kopia lustrzana https://github.com/c9/core
333 wiersze
10 KiB
JavaScript
333 wiersze
10 KiB
JavaScript
|
|
||
|
function MenuManager(){
|
||
|
var windowManager, connection, win, gui;
|
||
|
var nativeMenuBar;
|
||
|
|
||
|
// Lookup table for the menus
|
||
|
var menus = {};
|
||
|
var timers = {};
|
||
|
|
||
|
var TIMEOUT = 500;
|
||
|
|
||
|
function checkNativeItems(menu, name) {
|
||
|
var id = windowManager.activeWindowId;
|
||
|
if (id === 0) {
|
||
|
menu.items.forEach(function(item){
|
||
|
if (item.key != "q")
|
||
|
item.enabled = false;
|
||
|
});
|
||
|
gui.App.doneMenuShow();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Lets wait TIMEOUT ms before we force show the window
|
||
|
clearTimeout(timers[name]);
|
||
|
timers[name] = setTimeout(function(){
|
||
|
var menu = menus[name].submenu;
|
||
|
var nodes = menu.items.map(function(i){
|
||
|
return {
|
||
|
name: i.originalName,
|
||
|
disabled: i.originalName != "Cloud9/Quit Cloud9",
|
||
|
visible: true
|
||
|
}
|
||
|
});
|
||
|
updateMenu(name, nodes);
|
||
|
}, TIMEOUT);
|
||
|
|
||
|
// The window needs to send "showMenu" back - which calls updateMenu
|
||
|
connection.sendToWindow(id, "menuShow", { name: name });
|
||
|
}
|
||
|
|
||
|
function menuReady(name){
|
||
|
clearTimeout(timers[name]);
|
||
|
gui.App.doneMenuShow();
|
||
|
}
|
||
|
|
||
|
function updateMenu(name, nodes){
|
||
|
var menu = menus[name].submenu;
|
||
|
var item;
|
||
|
|
||
|
var found = {};
|
||
|
|
||
|
for (var n, i = nodes.length - 1; i >= 0; i--) {
|
||
|
n = nodes[i];
|
||
|
item = menus[n.name];
|
||
|
found[n.name] = true;
|
||
|
|
||
|
if (!item) {
|
||
|
if (n.submenu)
|
||
|
setSubMenu(n);
|
||
|
else
|
||
|
setMenuItem(n);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// Disabled
|
||
|
item.enabled = !n.disabled;
|
||
|
|
||
|
// This is for internal use
|
||
|
if (!n.caption)
|
||
|
continue;
|
||
|
|
||
|
// Toggle visibility
|
||
|
if (n.visible && menu.items.indexOf(item) == -1) {
|
||
|
nativeInsertByIndex(menu, item, n.index);
|
||
|
item.index = n.index;
|
||
|
}
|
||
|
else if (!n.visible && menu.items.indexOf(item) != -1) {
|
||
|
item.visible = false;
|
||
|
menu.remove(item);
|
||
|
}
|
||
|
|
||
|
// Don't update items that are not visible
|
||
|
if (!n.visible)
|
||
|
continue;
|
||
|
|
||
|
if (item.label != n.caption)
|
||
|
item.label = n.caption.replace(/\u2044/g, "/").trim();
|
||
|
|
||
|
// Update hotkey if needed
|
||
|
if (n.key != item.key || n.modifiers != item.modifiers) {
|
||
|
item.key = n.key;
|
||
|
item.modifiers = n.modifiers;
|
||
|
}
|
||
|
|
||
|
// Checkboxes and Radiobuttons
|
||
|
if (item.type == "checkbox")
|
||
|
item.checked = n.checked;
|
||
|
}
|
||
|
|
||
|
// Hide the menu items that are not found
|
||
|
var items = menu.items;
|
||
|
for (var i = items.length - 1; i >= 0; i--) {
|
||
|
if (!found[items[i].originalName]) {
|
||
|
items[i].visible = false;
|
||
|
menu.remove(items[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
menuReady(name);
|
||
|
}
|
||
|
|
||
|
function decorateMenu(menu, path) {
|
||
|
// Add show event
|
||
|
menu.on("show", checkNativeItems.bind(this, menu, path));
|
||
|
}
|
||
|
|
||
|
function nativeInsertByIndex(parent, item, index) {
|
||
|
item.$position = index;
|
||
|
|
||
|
var beforeNode, diff = 100000000, nodes = parent.items;
|
||
|
for (var i = 0, l = nodes.length; i < l; i++) {
|
||
|
var d = nodes[i].$position - index;
|
||
|
if (d > 0 && d < diff) {
|
||
|
beforeNode = i;
|
||
|
diff = d;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
parent.insert(item, isNaN(beforeNode) ? nodes.length : beforeNode);
|
||
|
|
||
|
item.visible = true;
|
||
|
|
||
|
return item;
|
||
|
}
|
||
|
|
||
|
function incrementIfExist(name, forceVisible) {
|
||
|
if (!menus[name]) return false;
|
||
|
var item = menus[name];
|
||
|
item.increment++;
|
||
|
|
||
|
if (forceVisible && !item.visible)
|
||
|
nativeInsertByIndex(findParent(name), item, forceVisible.index);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
function addItem(name, item) {
|
||
|
menus[name] = item;
|
||
|
item.increment = 1;
|
||
|
item.originalName = name;
|
||
|
}
|
||
|
|
||
|
function setRootMenu(e){
|
||
|
var item = nativeInsertByIndex(nativeMenuBar, new gui.MenuItem({
|
||
|
label: e.name,
|
||
|
submenu: new gui.Menu()
|
||
|
}), e.index);
|
||
|
|
||
|
decorateMenu(item.submenu, e.name);
|
||
|
|
||
|
addItem(e.name, item);
|
||
|
|
||
|
// Assign Menu Bar to Window
|
||
|
if (!win.menu)
|
||
|
win.menu = nativeMenuBar;
|
||
|
}
|
||
|
|
||
|
function setSubMenu(e){
|
||
|
var parent = findParent(e.name);
|
||
|
var item = nativeInsertByIndex(parent, new gui.MenuItem({
|
||
|
label: e.name.split("/").pop(),
|
||
|
submenu: new gui.Menu()
|
||
|
}), e.index);
|
||
|
|
||
|
decorateMenu(item.submenu, e.name);
|
||
|
|
||
|
addItem(e.name, item);
|
||
|
}
|
||
|
|
||
|
function setMenuItem(e){
|
||
|
var item;
|
||
|
var itemName = e.name.split("/").pop();
|
||
|
var parent = findParent(e.name);
|
||
|
|
||
|
if (itemName.charAt(0) == "~") {
|
||
|
item = new gui.MenuItem({ type: "separator" });
|
||
|
} else {
|
||
|
// Special Cases see https://github.com/rogerwang/node-webkit/compare/mac#diff-945bfbb0fd440b87cfe8ebf76f11c970R161
|
||
|
if (e.name.slice(0, 4) == "Edit") {
|
||
|
if (itemName == "Cut") {
|
||
|
e.selector = "cut:";
|
||
|
e.key = "x";
|
||
|
}
|
||
|
else if (itemName == "Copy") {
|
||
|
e.selector = "copy:";
|
||
|
e.key = "c";
|
||
|
}
|
||
|
else if (itemName == "Paste") {
|
||
|
e.selector = "paste:";
|
||
|
e.key = "v";
|
||
|
}
|
||
|
else if (itemName == "Select All") {
|
||
|
e.selector = "selectAll:";
|
||
|
e.key = "a";
|
||
|
}
|
||
|
else if (itemName == "Undo") {
|
||
|
e.selector = "undo:";
|
||
|
e.key = "z";
|
||
|
}
|
||
|
else if (itemName == "Redo") {
|
||
|
e.selector = "redo:";
|
||
|
e.key = "z";
|
||
|
e.modifiers = "cmd-shift";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var options = {
|
||
|
label: itemName.replace(/\u2044/g, "-"),
|
||
|
enabled: !e.disabled,
|
||
|
type: e.itemtype == "check"
|
||
|
|| e.itemtype == "radio" ? "checkbox" : "normal",
|
||
|
selector: e.selector,
|
||
|
key: e.key,
|
||
|
modifiers: e.modifiers,
|
||
|
click: function(){
|
||
|
var id = windowManager.activeWindowId;
|
||
|
if (id === undefined) return;
|
||
|
|
||
|
connection.sendToWindow(id, "menuClick", {
|
||
|
name: e.name
|
||
|
});
|
||
|
}
|
||
|
};
|
||
|
|
||
|
item = new gui.MenuItem(options);
|
||
|
item.index = e.index;
|
||
|
}
|
||
|
|
||
|
nativeInsertByIndex(parent, item, e.index);
|
||
|
|
||
|
addItem(e.name, item);
|
||
|
}
|
||
|
|
||
|
function removeItem(path) {
|
||
|
if (menus[path] && --menus[path].increment === 0) {
|
||
|
menus[path].menu.remove(menus[path]);
|
||
|
delete menus[path];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function findParent(path) {
|
||
|
var p = path.split("/"); p.pop();
|
||
|
var parent = menus[p.join("/")];
|
||
|
return parent.submenu;
|
||
|
}
|
||
|
|
||
|
this.init = function(wm) {
|
||
|
windowManager = wm;
|
||
|
|
||
|
windowManager.registerSharedModule("nativeMenuBar", function(windowManager, cn) {
|
||
|
win = windowManager.$allWindows.root;
|
||
|
gui = win.window.nwGui;
|
||
|
|
||
|
// Assign Connection
|
||
|
connection = cn;
|
||
|
|
||
|
// Create Menu Bar
|
||
|
nativeMenuBar = new gui.Menu({ type: "menubar" });
|
||
|
|
||
|
setRootMenu({name: "Cloud9", index: 50});
|
||
|
setRootMenu({name: "File", index: 100});
|
||
|
setRootMenu({name: "Edit", index: 200});
|
||
|
setRootMenu({name: "Find", index: 300});
|
||
|
setRootMenu({name: "View", index: 400});
|
||
|
setRootMenu({name: "Goto", index: 500});
|
||
|
setRootMenu({name: "Run", index: 600});
|
||
|
setRootMenu({name: "Tools", index: 700});
|
||
|
setRootMenu({name: "Window", index: 800});
|
||
|
setRootMenu({name: "Help", index: 900});
|
||
|
|
||
|
// Set Up Message Listeners
|
||
|
connection.on("setRoot", function(e) {
|
||
|
if (incrementIfExist(e.name)) return;
|
||
|
|
||
|
setRootMenu(e);
|
||
|
});
|
||
|
|
||
|
connection.on("setSubMenu", function(e) {
|
||
|
if (incrementIfExist(e.name)) return;
|
||
|
|
||
|
setSubMenu(e);
|
||
|
});
|
||
|
|
||
|
connection.on("setMenuItem", function(e) {
|
||
|
if (incrementIfExist(e.name, e)) return;
|
||
|
|
||
|
setMenuItem(e);
|
||
|
});
|
||
|
|
||
|
connection.on("remove", function(e) {
|
||
|
removeItem(e.name);
|
||
|
});
|
||
|
|
||
|
connection.on("showMenu", function(e) {
|
||
|
updateMenu(e.name, e.items);
|
||
|
});
|
||
|
|
||
|
connection.on("enableUndoRedo", function(e) {
|
||
|
var menu = menus["Edit"].submenu;
|
||
|
|
||
|
["Edit/Undo", "Edit/Redo"].forEach(function(path){
|
||
|
var item = menus[path];
|
||
|
if (item && menu.items.indexOf(item) == -1)
|
||
|
nativeInsertByIndex(menu, item, item.index);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
connection.on("builtin", function(e) {
|
||
|
if (!win.hasBuiltIn) {
|
||
|
while (nativeMenuBar.items.length) {
|
||
|
nativeMenuBar.remove(nativeMenuBar.items[0]);
|
||
|
}
|
||
|
|
||
|
nativeMenuBar.createMacBuiltin("Cloud9");
|
||
|
win.menu = nativeMenuBar;
|
||
|
win.hasBuiltIn = true;
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
};
|
||
|
}
|
||
|
|
||
|
module.exports = new MenuManager();
|