c9-core/local/menus.js

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();