Merge pull request #2682 from atom/menu-item-role
Add "role" attribute for MenuItem
This commit is contained in:
commit
bfa33de792
13 changed files with 409 additions and 346 deletions
|
@ -107,6 +107,10 @@ void Menu::SetSublabel(int index, const base::string16& sublabel) {
|
||||||
model_->SetSublabel(index, sublabel);
|
model_->SetSublabel(index, sublabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Menu::SetRole(int index, const base::string16& role) {
|
||||||
|
model_->SetRole(index, role);
|
||||||
|
}
|
||||||
|
|
||||||
void Menu::Clear() {
|
void Menu::Clear() {
|
||||||
model_->Clear();
|
model_->Clear();
|
||||||
}
|
}
|
||||||
|
@ -154,6 +158,7 @@ void Menu::BuildPrototype(v8::Isolate* isolate,
|
||||||
.SetMethod("insertSubMenu", &Menu::InsertSubMenuAt)
|
.SetMethod("insertSubMenu", &Menu::InsertSubMenuAt)
|
||||||
.SetMethod("setIcon", &Menu::SetIcon)
|
.SetMethod("setIcon", &Menu::SetIcon)
|
||||||
.SetMethod("setSublabel", &Menu::SetSublabel)
|
.SetMethod("setSublabel", &Menu::SetSublabel)
|
||||||
|
.SetMethod("setRole", &Menu::SetRole)
|
||||||
.SetMethod("clear", &Menu::Clear)
|
.SetMethod("clear", &Menu::Clear)
|
||||||
.SetMethod("getIndexOfCommandId", &Menu::GetIndexOfCommandId)
|
.SetMethod("getIndexOfCommandId", &Menu::GetIndexOfCommandId)
|
||||||
.SetMethod("getItemCount", &Menu::GetItemCount)
|
.SetMethod("getItemCount", &Menu::GetItemCount)
|
||||||
|
|
|
@ -73,6 +73,7 @@ class Menu : public mate::Wrappable,
|
||||||
Menu* menu);
|
Menu* menu);
|
||||||
void SetIcon(int index, const gfx::Image& image);
|
void SetIcon(int index, const gfx::Image& image);
|
||||||
void SetSublabel(int index, const base::string16& sublabel);
|
void SetSublabel(int index, const base::string16& sublabel);
|
||||||
|
void SetRole(int index, const base::string16& role);
|
||||||
void Clear();
|
void Clear();
|
||||||
int GetIndexOfCommandId(int command_id);
|
int GetIndexOfCommandId(int command_id);
|
||||||
int GetItemCount() const;
|
int GetItemCount() const;
|
||||||
|
|
|
@ -62,6 +62,12 @@ BrowserWindow::loadUrl = -> @webContents.loadUrl.apply @webContents, arguments
|
||||||
BrowserWindow::send = -> @webContents.send.apply @webContents, arguments
|
BrowserWindow::send = -> @webContents.send.apply @webContents, arguments
|
||||||
|
|
||||||
# Be compatible with old API.
|
# Be compatible with old API.
|
||||||
|
BrowserWindow::undo = -> @webContents.undo()
|
||||||
|
BrowserWindow::redo = -> @webContents.redo()
|
||||||
|
BrowserWindow::cut = -> @webContents.cut()
|
||||||
|
BrowserWindow::copy = -> @webContents.copy()
|
||||||
|
BrowserWindow::paste = -> @webContents.paste()
|
||||||
|
BrowserWindow::selectAll = -> @webContents.selectAll()
|
||||||
BrowserWindow::restart = -> @webContents.reload()
|
BrowserWindow::restart = -> @webContents.reload()
|
||||||
BrowserWindow::getUrl = -> @webContents.getUrl()
|
BrowserWindow::getUrl = -> @webContents.getUrl()
|
||||||
BrowserWindow::reload = -> @webContents.reload.apply @webContents, arguments
|
BrowserWindow::reload = -> @webContents.reload.apply @webContents, arguments
|
||||||
|
|
|
@ -3,18 +3,30 @@ v8Util = process.atomBinding 'v8_util'
|
||||||
|
|
||||||
nextCommandId = 0
|
nextCommandId = 0
|
||||||
|
|
||||||
|
# Maps role to methods of webContents
|
||||||
|
rolesMap =
|
||||||
|
undo: 'undo'
|
||||||
|
redo: 'redo'
|
||||||
|
cut: 'cut'
|
||||||
|
copy: 'copy'
|
||||||
|
paste: 'paste'
|
||||||
|
selectall: 'selectAll'
|
||||||
|
minimize: 'minimize'
|
||||||
|
close: 'close'
|
||||||
|
|
||||||
class MenuItem
|
class MenuItem
|
||||||
@types = ['normal', 'separator', 'submenu', 'checkbox', 'radio']
|
@types = ['normal', 'separator', 'submenu', 'checkbox', 'radio']
|
||||||
|
|
||||||
constructor: (options) ->
|
constructor: (options) ->
|
||||||
Menu = require 'menu'
|
Menu = require 'menu'
|
||||||
|
|
||||||
{click, @selector, @type, @label, @sublabel, @accelerator, @icon, @enabled, @visible, @checked, @submenu} = options
|
{click, @selector, @type, @role, @label, @sublabel, @accelerator, @icon, @enabled, @visible, @checked, @submenu} = options
|
||||||
|
|
||||||
@type = 'submenu' if not @type? and @submenu?
|
@type = 'submenu' if not @type? and @submenu?
|
||||||
throw new Error('Invalid submenu') if @type is 'submenu' and @submenu?.constructor isnt Menu
|
throw new Error('Invalid submenu') if @type is 'submenu' and @submenu?.constructor isnt Menu
|
||||||
|
|
||||||
@overrideReadOnlyProperty 'type', 'normal'
|
@overrideReadOnlyProperty 'type', 'normal'
|
||||||
|
@overrideReadOnlyProperty 'role'
|
||||||
@overrideReadOnlyProperty 'accelerator'
|
@overrideReadOnlyProperty 'accelerator'
|
||||||
@overrideReadOnlyProperty 'icon'
|
@overrideReadOnlyProperty 'icon'
|
||||||
@overrideReadOnlyProperty 'submenu'
|
@overrideReadOnlyProperty 'submenu'
|
||||||
|
@ -27,12 +39,14 @@ class MenuItem
|
||||||
throw new Error("Unknown menu type #{@type}") if MenuItem.types.indexOf(@type) is -1
|
throw new Error("Unknown menu type #{@type}") if MenuItem.types.indexOf(@type) is -1
|
||||||
|
|
||||||
@commandId = ++nextCommandId
|
@commandId = ++nextCommandId
|
||||||
@click = =>
|
@click = (focusedWindow) =>
|
||||||
# Manually flip the checked flags when clicked.
|
# Manually flip the checked flags when clicked.
|
||||||
@checked = !@checked if @type in ['checkbox', 'radio']
|
@checked = !@checked if @type in ['checkbox', 'radio']
|
||||||
|
|
||||||
if typeof click is 'function'
|
if @role and rolesMap[@role] and process.platform isnt 'darwin'
|
||||||
click this, BrowserWindow.getFocusedWindow()
|
focusedWindow?[rolesMap[@role]]()
|
||||||
|
else if typeof click is 'function'
|
||||||
|
click this, focusedWindow
|
||||||
else if typeof @selector is 'string'
|
else if typeof @selector is 'string'
|
||||||
Menu.sendActionToFirstResponder @selector
|
Menu.sendActionToFirstResponder @selector
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,8 @@ Menu::_init = ->
|
||||||
isCommandIdVisible: (commandId) => @commandsMap[commandId]?.visible
|
isCommandIdVisible: (commandId) => @commandsMap[commandId]?.visible
|
||||||
getAcceleratorForCommandId: (commandId) => @commandsMap[commandId]?.accelerator
|
getAcceleratorForCommandId: (commandId) => @commandsMap[commandId]?.accelerator
|
||||||
getIconForCommandId: (commandId) => @commandsMap[commandId]?.icon
|
getIconForCommandId: (commandId) => @commandsMap[commandId]?.icon
|
||||||
executeCommand: (commandId) => @commandsMap[commandId]?.click()
|
executeCommand: (commandId) =>
|
||||||
|
@commandsMap[commandId]?.click BrowserWindow.getFocusedWindow()
|
||||||
menuWillShow: =>
|
menuWillShow: =>
|
||||||
# Make sure radio groups have at least one menu item seleted.
|
# Make sure radio groups have at least one menu item seleted.
|
||||||
for id, group of @groupsMap
|
for id, group of @groupsMap
|
||||||
|
@ -115,6 +116,7 @@ Menu::insert = (pos, item) ->
|
||||||
|
|
||||||
@setSublabel pos, item.sublabel if item.sublabel?
|
@setSublabel pos, item.sublabel if item.sublabel?
|
||||||
@setIcon pos, item.icon if item.icon?
|
@setIcon pos, item.icon if item.icon?
|
||||||
|
@setRole pos, item.role if item.role?
|
||||||
|
|
||||||
# Make menu accessable to items.
|
# Make menu accessable to items.
|
||||||
item.overrideReadOnlyProperty 'menu', this
|
item.overrideReadOnlyProperty 'menu', this
|
||||||
|
|
|
@ -36,21 +36,138 @@ app.once('ready', function() {
|
||||||
if (Menu.getApplicationMenu())
|
if (Menu.getApplicationMenu())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var template;
|
var template = [
|
||||||
if (process.platform == 'darwin') {
|
|
||||||
template = [
|
|
||||||
{
|
{
|
||||||
|
label: 'Edit',
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
label: 'Undo',
|
||||||
|
accelerator: 'CmdOrCtrl+Z',
|
||||||
|
role: 'undo'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Redo',
|
||||||
|
accelerator: 'Shift+CmdOrCtrl+Z',
|
||||||
|
role: 'redo'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'separator'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Cut',
|
||||||
|
accelerator: 'CmdOrCtrl+X',
|
||||||
|
role: 'cut'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Copy',
|
||||||
|
accelerator: 'CmdOrCtrl+C',
|
||||||
|
role: 'copy'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Paste',
|
||||||
|
accelerator: 'CmdOrCtrl+V',
|
||||||
|
role: 'paste'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Select All',
|
||||||
|
accelerator: 'CmdOrCtrl+A',
|
||||||
|
role: 'selectall'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'View',
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
label: 'Reload',
|
||||||
|
accelerator: 'CmdOrCtrl+R',
|
||||||
|
click: function(item, focusedWindow) {
|
||||||
|
if (focusedWindow)
|
||||||
|
focusedWindow.reload();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Toggle Full Screen',
|
||||||
|
accelerator: (function() {
|
||||||
|
if (process.platform == 'darwin')
|
||||||
|
return 'Ctrl+Command+F';
|
||||||
|
else
|
||||||
|
return 'F11';
|
||||||
|
})(),
|
||||||
|
click: function(item, focusedWindow) {
|
||||||
|
if (focusedWindow)
|
||||||
|
focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Toggle Developer Tools',
|
||||||
|
accelerator: (function() {
|
||||||
|
if (process.platform == 'darwin')
|
||||||
|
return 'Alt+Command+I';
|
||||||
|
else
|
||||||
|
return 'Ctrl+Shift+I';
|
||||||
|
})(),
|
||||||
|
click: function(item, focusedWindow) {
|
||||||
|
if (focusedWindow)
|
||||||
|
focusedWindow.toggleDevTools();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Window',
|
||||||
|
role: 'window',
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
label: 'Minimize',
|
||||||
|
accelerator: 'CmdOrCtrl+M',
|
||||||
|
role: 'minimize'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Close',
|
||||||
|
accelerator: 'CmdOrCtrl+W',
|
||||||
|
role: 'close'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Help',
|
||||||
|
role: 'help',
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
label: 'Learn More',
|
||||||
|
click: function() { require('shell').openExternal('http://electron.atom.io') }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Documentation',
|
||||||
|
click: function() { require('shell').openExternal('https://github.com/atom/electron/tree/master/docs#readme') }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Community Discussions',
|
||||||
|
click: function() { require('shell').openExternal('https://discuss.atom.io/c/electron') }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Search Issues',
|
||||||
|
click: function() { require('shell').openExternal('https://github.com/atom/electron/issues') }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
if (process.platform == 'darwin') {
|
||||||
|
template.unshift({
|
||||||
label: 'Electron',
|
label: 'Electron',
|
||||||
submenu: [
|
submenu: [
|
||||||
{
|
{
|
||||||
label: 'About Electron',
|
label: 'About Electron',
|
||||||
selector: 'orderFrontStandardAboutPanel:'
|
role: 'about'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'separator'
|
type: 'separator'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Services',
|
label: 'Services',
|
||||||
|
role: 'services',
|
||||||
submenu: []
|
submenu: []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -59,16 +176,16 @@ app.once('ready', function() {
|
||||||
{
|
{
|
||||||
label: 'Hide Electron',
|
label: 'Hide Electron',
|
||||||
accelerator: 'Command+H',
|
accelerator: 'Command+H',
|
||||||
selector: 'hide:'
|
role: 'hide'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Hide Others',
|
label: 'Hide Others',
|
||||||
accelerator: 'Command+Shift+H',
|
accelerator: 'Command+Shift+H',
|
||||||
selector: 'hideOtherApplications:'
|
role: 'hideothers:'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Show All',
|
label: 'Show All',
|
||||||
selector: 'unhideAllApplications:'
|
role: 'unhide:'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'separator'
|
type: 'separator'
|
||||||
|
@ -79,195 +196,16 @@ app.once('ready', function() {
|
||||||
click: function() { app.quit(); }
|
click: function() { app.quit(); }
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
});
|
||||||
{
|
template[3].submenu.push(
|
||||||
label: 'Edit',
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
label: 'Undo',
|
|
||||||
accelerator: 'Command+Z',
|
|
||||||
selector: 'undo:'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Redo',
|
|
||||||
accelerator: 'Shift+Command+Z',
|
|
||||||
selector: 'redo:'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'separator'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Cut',
|
|
||||||
accelerator: 'Command+X',
|
|
||||||
selector: 'cut:'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Copy',
|
|
||||||
accelerator: 'Command+C',
|
|
||||||
selector: 'copy:'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Paste',
|
|
||||||
accelerator: 'Command+V',
|
|
||||||
selector: 'paste:'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Select All',
|
|
||||||
accelerator: 'Command+A',
|
|
||||||
selector: 'selectAll:'
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'View',
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
label: 'Reload',
|
|
||||||
accelerator: 'Command+R',
|
|
||||||
click: function() {
|
|
||||||
var focusedWindow = BrowserWindow.getFocusedWindow();
|
|
||||||
if (focusedWindow)
|
|
||||||
focusedWindow.reload();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Toggle Full Screen',
|
|
||||||
accelerator: 'Ctrl+Command+F',
|
|
||||||
click: function() {
|
|
||||||
var focusedWindow = BrowserWindow.getFocusedWindow();
|
|
||||||
if (focusedWindow)
|
|
||||||
focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Toggle Developer Tools',
|
|
||||||
accelerator: 'Alt+Command+I',
|
|
||||||
click: function() {
|
|
||||||
var focusedWindow = BrowserWindow.getFocusedWindow();
|
|
||||||
if (focusedWindow)
|
|
||||||
focusedWindow.toggleDevTools();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Window',
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
label: 'Minimize',
|
|
||||||
accelerator: 'Command+M',
|
|
||||||
selector: 'performMiniaturize:'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Close',
|
|
||||||
accelerator: 'Command+W',
|
|
||||||
selector: 'performClose:'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
type: 'separator'
|
type: 'separator'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Bring All to Front',
|
label: 'Bring All to Front',
|
||||||
selector: 'arrangeInFront:'
|
role: 'front'
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Help',
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
label: 'Learn More',
|
|
||||||
click: function() { require('shell').openExternal('http://electron.atom.io') }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Documentation',
|
|
||||||
click: function() { require('shell').openExternal('https://github.com/atom/electron/tree/master/docs#readme') }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Community Discussions',
|
|
||||||
click: function() { require('shell').openExternal('https://discuss.atom.io/c/electron') }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Search Issues',
|
|
||||||
click: function() { require('shell').openExternal('https://github.com/atom/electron/issues') }
|
|
||||||
}
|
}
|
||||||
]
|
);
|
||||||
}
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
template = [
|
|
||||||
{
|
|
||||||
label: '&File',
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
label: '&Open',
|
|
||||||
accelerator: 'Ctrl+O',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '&Close',
|
|
||||||
accelerator: 'Ctrl+W',
|
|
||||||
click: function() {
|
|
||||||
var focusedWindow = BrowserWindow.getFocusedWindow();
|
|
||||||
if (focusedWindow)
|
|
||||||
focusedWindow.close();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '&View',
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
label: '&Reload',
|
|
||||||
accelerator: 'Ctrl+R',
|
|
||||||
click: function() {
|
|
||||||
var focusedWindow = BrowserWindow.getFocusedWindow();
|
|
||||||
if (focusedWindow)
|
|
||||||
focusedWindow.reload();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Toggle &Full Screen',
|
|
||||||
accelerator: 'F11',
|
|
||||||
click: function() {
|
|
||||||
var focusedWindow = BrowserWindow.getFocusedWindow();
|
|
||||||
if (focusedWindow)
|
|
||||||
focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Toggle &Developer Tools',
|
|
||||||
accelerator: 'Shift+Ctrl+I',
|
|
||||||
click: function() {
|
|
||||||
var focusedWindow = BrowserWindow.getFocusedWindow();
|
|
||||||
if (focusedWindow)
|
|
||||||
focusedWindow.toggleDevTools();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Help',
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
label: 'Learn More',
|
|
||||||
click: function() { require('shell').openExternal('http://electron.atom.io') }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Documentation',
|
|
||||||
click: function() { require('shell').openExternal('https://github.com/atom/electron/tree/master/docs#readme') }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Community Discussions',
|
|
||||||
click: function() { require('shell').openExternal('https://discuss.atom.io/c/electron') }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Search Issues',
|
|
||||||
click: function() { require('shell').openExternal('https://github.com/atom/electron/issues') }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var menu = Menu.buildFromTemplate(template);
|
var menu = Menu.buildFromTemplate(template);
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
#include "atom/browser/ui/atom_menu_model.h"
|
#include "atom/browser/ui/atom_menu_model.h"
|
||||||
|
|
||||||
|
#include "base/stl_util.h"
|
||||||
|
|
||||||
namespace atom {
|
namespace atom {
|
||||||
|
|
||||||
AtomMenuModel::AtomMenuModel(Delegate* delegate)
|
AtomMenuModel::AtomMenuModel(Delegate* delegate)
|
||||||
|
@ -14,6 +16,17 @@ AtomMenuModel::AtomMenuModel(Delegate* delegate)
|
||||||
AtomMenuModel::~AtomMenuModel() {
|
AtomMenuModel::~AtomMenuModel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AtomMenuModel::SetRole(int index, const base::string16& role) {
|
||||||
|
roles_[index] = role;
|
||||||
|
}
|
||||||
|
|
||||||
|
base::string16 AtomMenuModel::GetRoleAt(int index) {
|
||||||
|
if (ContainsKey(roles_, index))
|
||||||
|
return roles_[index];
|
||||||
|
else
|
||||||
|
return base::string16();
|
||||||
|
}
|
||||||
|
|
||||||
void AtomMenuModel::MenuClosed() {
|
void AtomMenuModel::MenuClosed() {
|
||||||
ui::SimpleMenuModel::MenuClosed();
|
ui::SimpleMenuModel::MenuClosed();
|
||||||
FOR_EACH_OBSERVER(Observer, observers_, MenuClosed());
|
FOR_EACH_OBSERVER(Observer, observers_, MenuClosed());
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#ifndef ATOM_BROWSER_UI_ATOM_MENU_MODEL_H_
|
#ifndef ATOM_BROWSER_UI_ATOM_MENU_MODEL_H_
|
||||||
#define ATOM_BROWSER_UI_ATOM_MENU_MODEL_H_
|
#define ATOM_BROWSER_UI_ATOM_MENU_MODEL_H_
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include "base/observer_list.h"
|
#include "base/observer_list.h"
|
||||||
#include "ui/base/models/simple_menu_model.h"
|
#include "ui/base/models/simple_menu_model.h"
|
||||||
|
|
||||||
|
@ -31,12 +33,16 @@ class AtomMenuModel : public ui::SimpleMenuModel {
|
||||||
void AddObserver(Observer* obs) { observers_.AddObserver(obs); }
|
void AddObserver(Observer* obs) { observers_.AddObserver(obs); }
|
||||||
void RemoveObserver(Observer* obs) { observers_.RemoveObserver(obs); }
|
void RemoveObserver(Observer* obs) { observers_.RemoveObserver(obs); }
|
||||||
|
|
||||||
|
void SetRole(int index, const base::string16& role);
|
||||||
|
base::string16 GetRoleAt(int index);
|
||||||
|
|
||||||
// ui::SimpleMenuModel:
|
// ui::SimpleMenuModel:
|
||||||
void MenuClosed() override;
|
void MenuClosed() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Delegate* delegate_; // weak ref.
|
Delegate* delegate_; // weak ref.
|
||||||
|
|
||||||
|
std::map<int, base::string16> roles_;
|
||||||
ObserverList<Observer> observers_;
|
ObserverList<Observer> observers_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(AtomMenuModel);
|
DISALLOW_COPY_AND_ASSIGN(AtomMenuModel);
|
||||||
|
|
|
@ -59,17 +59,4 @@ class MenuModel;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
// Exposed only for unit testing, do not call directly.
|
|
||||||
@interface AtomMenuController (PrivateExposedForTesting)
|
|
||||||
- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item;
|
|
||||||
@end
|
|
||||||
|
|
||||||
// Protected methods that subclassers can override.
|
|
||||||
@interface AtomMenuController (Protected)
|
|
||||||
- (void)addItemToMenu:(NSMenu*)menu
|
|
||||||
atIndex:(NSInteger)index
|
|
||||||
fromModel:(ui::MenuModel*)model;
|
|
||||||
- (NSMenu*)menuFromModel:(ui::MenuModel*)model;
|
|
||||||
@end
|
|
||||||
|
|
||||||
#endif // ATOM_BROWSER_UI_COCOA_ATOM_MENU_CONTROLLER_H_
|
#endif // ATOM_BROWSER_UI_COCOA_ATOM_MENU_CONTROLLER_H_
|
||||||
|
|
|
@ -8,16 +8,36 @@
|
||||||
#include "atom/browser/ui/atom_menu_model.h"
|
#include "atom/browser/ui/atom_menu_model.h"
|
||||||
#include "base/logging.h"
|
#include "base/logging.h"
|
||||||
#include "base/strings/sys_string_conversions.h"
|
#include "base/strings/sys_string_conversions.h"
|
||||||
|
#include "base/strings/utf_string_conversions.h"
|
||||||
#include "ui/base/accelerators/accelerator.h"
|
#include "ui/base/accelerators/accelerator.h"
|
||||||
#include "ui/base/accelerators/platform_accelerator_cocoa.h"
|
#include "ui/base/accelerators/platform_accelerator_cocoa.h"
|
||||||
#include "ui/base/l10n/l10n_util_mac.h"
|
#include "ui/base/l10n/l10n_util_mac.h"
|
||||||
#include "ui/events/cocoa/cocoa_event_utils.h"
|
#include "ui/events/cocoa/cocoa_event_utils.h"
|
||||||
#include "ui/gfx/image/image.h"
|
#include "ui/gfx/image/image.h"
|
||||||
|
|
||||||
@interface AtomMenuController (Private)
|
namespace {
|
||||||
- (void)addSeparatorToMenu:(NSMenu*)menu
|
|
||||||
atIndex:(int)index;
|
struct Role {
|
||||||
@end
|
SEL selector;
|
||||||
|
const char* role;
|
||||||
|
};
|
||||||
|
Role kRolesMap[] = {
|
||||||
|
{ @selector(orderFrontStandardAboutPanel:), "about" },
|
||||||
|
{ @selector(hide:), "hide" },
|
||||||
|
{ @selector(hideOtherApplications:), "hideothers" },
|
||||||
|
{ @selector(unhideAllApplications:), "unhide" },
|
||||||
|
{ @selector(arrangeInFront:), "front" },
|
||||||
|
{ @selector(undo:), "undo" },
|
||||||
|
{ @selector(redo:), "redo" },
|
||||||
|
{ @selector(cut:), "cut" },
|
||||||
|
{ @selector(copy:), "copy" },
|
||||||
|
{ @selector(paste:), "paste" },
|
||||||
|
{ @selector(selectAll:), "selectall" },
|
||||||
|
{ @selector(performMiniaturize:), "minimize" },
|
||||||
|
{ @selector(performClose:), "close" },
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
@implementation AtomMenuController
|
@implementation AtomMenuController
|
||||||
|
|
||||||
|
@ -101,7 +121,9 @@
|
||||||
// associated with the entry in the model identified by |modelIndex|.
|
// associated with the entry in the model identified by |modelIndex|.
|
||||||
- (void)addItemToMenu:(NSMenu*)menu
|
- (void)addItemToMenu:(NSMenu*)menu
|
||||||
atIndex:(NSInteger)index
|
atIndex:(NSInteger)index
|
||||||
fromModel:(ui::MenuModel*)model {
|
fromModel:(ui::MenuModel*)ui_model {
|
||||||
|
atom::AtomMenuModel* model = static_cast<atom::AtomMenuModel*>(ui_model);
|
||||||
|
|
||||||
base::string16 label16 = model->GetLabelAt(index);
|
base::string16 label16 = model->GetLabelAt(index);
|
||||||
NSString* label = l10n_util::FixUpWindowsStyleLabel(label16);
|
NSString* label = l10n_util::FixUpWindowsStyleLabel(label16);
|
||||||
base::scoped_nsobject<NSMenuItem> item(
|
base::scoped_nsobject<NSMenuItem> item(
|
||||||
|
@ -124,13 +146,13 @@
|
||||||
[submenu setTitle:[item title]];
|
[submenu setTitle:[item title]];
|
||||||
[item setSubmenu:submenu];
|
[item setSubmenu:submenu];
|
||||||
|
|
||||||
// Hack to set window and help menu.
|
// Set submenu's role.
|
||||||
if ([[item title] isEqualToString:@"Window"] && [submenu numberOfItems] > 0)
|
base::string16 role = model->GetRoleAt(index);
|
||||||
|
if (role == base::ASCIIToUTF16("window"))
|
||||||
[NSApp setWindowsMenu:submenu];
|
[NSApp setWindowsMenu:submenu];
|
||||||
else if ([[item title] isEqualToString:@"Help"])
|
else if (role == base::ASCIIToUTF16("help"))
|
||||||
[NSApp setHelpMenu:submenu];
|
[NSApp setHelpMenu:submenu];
|
||||||
if ([[item title] isEqualToString:@"Services"] &&
|
if (role == base::ASCIIToUTF16("services"))
|
||||||
[submenu numberOfItems] == 0)
|
|
||||||
[NSApp setServicesMenu:submenu];
|
[NSApp setServicesMenu:submenu];
|
||||||
} else {
|
} else {
|
||||||
// The MenuModel works on indexes so we can't just set the command id as the
|
// The MenuModel works on indexes so we can't just set the command id as the
|
||||||
|
@ -139,7 +161,6 @@
|
||||||
// model. Setting the target to |self| allows this class to participate
|
// model. Setting the target to |self| allows this class to participate
|
||||||
// in validation of the menu items.
|
// in validation of the menu items.
|
||||||
[item setTag:index];
|
[item setTag:index];
|
||||||
[item setTarget:self];
|
|
||||||
NSValue* modelObject = [NSValue valueWithPointer:model];
|
NSValue* modelObject = [NSValue valueWithPointer:model];
|
||||||
[item setRepresentedObject:modelObject]; // Retains |modelObject|.
|
[item setRepresentedObject:modelObject]; // Retains |modelObject|.
|
||||||
ui::Accelerator accelerator;
|
ui::Accelerator accelerator;
|
||||||
|
@ -153,6 +174,19 @@
|
||||||
platformAccelerator->modifier_mask()];
|
platformAccelerator->modifier_mask()];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set menu item's role.
|
||||||
|
base::string16 role = model->GetRoleAt(index);
|
||||||
|
if (role.empty()) {
|
||||||
|
[item setTarget:self];
|
||||||
|
} else {
|
||||||
|
for (const Role& pair : kRolesMap) {
|
||||||
|
if (role == base::ASCIIToUTF16(pair.role)) {
|
||||||
|
[item setAction:pair.selector];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
[menu insertItem:item atIndex:index];
|
[menu insertItem:item atIndex:index];
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,12 +48,13 @@ selected when you want to limit the user to a specific type. For example:
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The `extensions` array should contain extensions without wildcards or dots (e.g.
|
The `extensions` array should contain extensions without wildcards or dots (e.g.
|
||||||
`'png'` is good but `'.png'` and `'*.png'` are bad). To show all files, use the
|
`'png'` is good but `'.png'` and `'*.png'` are bad). To show all files, use the
|
||||||
`'*'` wildcard (no other wildcard is supported).
|
`'*'` wildcard (no other wildcard is supported).
|
||||||
|
|
||||||
If a `callback` is passed, the API call will be asynchronous and the result
|
If a `callback` is passed, the API call will be asynchronous and the result
|
||||||
wil be passed via `callback(filenames)`
|
will be passed via `callback(filenames)`
|
||||||
|
|
||||||
**Note:** On Windows and Linux an open dialog can not be both a file selector
|
**Note:** On Windows and Linux an open dialog can not be both a file selector
|
||||||
and a directory selector, so if you set `properties` to
|
and a directory selector, so if you set `properties` to
|
||||||
|
|
|
@ -12,9 +12,10 @@ Create a new `MenuItem` with the following method:
|
||||||
### new MenuItem(options)
|
### new MenuItem(options)
|
||||||
|
|
||||||
* `options` Object
|
* `options` Object
|
||||||
* `click` Function - Callback when the menu item is clicked
|
* `click` Function - Will be called with `click(menuItem, browserWindow)` when
|
||||||
* `selector` String - Call the selector of first responder when clicked (OS
|
the menu item is clicked
|
||||||
X only)
|
* `role` String - Define the action of the menu item, when specified the
|
||||||
|
`click` property will be ignored
|
||||||
* `type` String - Can be `normal`, `separator`, `submenu`, `checkbox` or
|
* `type` String - Can be `normal`, `separator`, `submenu`, `checkbox` or
|
||||||
`radio`
|
`radio`
|
||||||
* `label` String
|
* `label` String
|
||||||
|
@ -30,3 +31,29 @@ Create a new `MenuItem` with the following method:
|
||||||
as a reference to this item by the position attribute.
|
as a reference to this item by the position attribute.
|
||||||
* `position` String - This field allows fine-grained definition of the
|
* `position` String - This field allows fine-grained definition of the
|
||||||
specific location within a given menu.
|
specific location within a given menu.
|
||||||
|
|
||||||
|
When creating menu items, it is recommended to specify `role` instead of
|
||||||
|
manually implementing the behavior if there is matching action, so menu can have
|
||||||
|
best native experience.
|
||||||
|
|
||||||
|
The `role` property can have following values:
|
||||||
|
|
||||||
|
* `undo`
|
||||||
|
* `redo`
|
||||||
|
* `cut`
|
||||||
|
* `copy`
|
||||||
|
* `paste`
|
||||||
|
* `selectall`
|
||||||
|
* `minimize` - Minimize current window
|
||||||
|
* `close` - Close current window
|
||||||
|
|
||||||
|
On OS X `role` can also have following additional values:
|
||||||
|
|
||||||
|
* `about` - Map to the `orderFrontStandardAboutPanel` action
|
||||||
|
* `hide` - Map to the `hide` action
|
||||||
|
* `hideothers` - Map to the `hideOtherApplications` action
|
||||||
|
* `unhide` - Map to the `unhideAllApplications` action
|
||||||
|
* `front` - Map to the `arrangeInFront` action
|
||||||
|
* `window` - The submenu is a "Window" menu
|
||||||
|
* `help` - The submenu is a "Help" menu
|
||||||
|
* `services` - The submenu is a "Services" menu
|
||||||
|
|
197
docs/api/menu.md
197
docs/api/menu.md
|
@ -35,68 +35,20 @@ window.addEventListener('contextmenu', function (e) {
|
||||||
An example of creating the application menu in the render process with the
|
An example of creating the application menu in the render process with the
|
||||||
simple template API:
|
simple template API:
|
||||||
|
|
||||||
**Note to Window and Linux users** the `selector` member of each menu item is a
|
```javascript
|
||||||
Mac-only [Accelerator option](https://github.com/atom/electron/blob/master/docs/api/accelerator.md).
|
|
||||||
|
|
||||||
```html
|
|
||||||
<!-- index.html -->
|
|
||||||
<script>
|
|
||||||
var remote = require('remote');
|
|
||||||
var Menu = remote.require('menu');
|
|
||||||
var template = [
|
var template = [
|
||||||
{
|
|
||||||
label: 'Electron',
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
label: 'About Electron',
|
|
||||||
selector: 'orderFrontStandardAboutPanel:'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'separator'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Services',
|
|
||||||
submenu: []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'separator'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Hide Electron',
|
|
||||||
accelerator: 'CmdOrCtrl+H',
|
|
||||||
selector: 'hide:'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Hide Others',
|
|
||||||
accelerator: 'CmdOrCtrl+Shift+H',
|
|
||||||
selector: 'hideOtherApplications:'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Show All',
|
|
||||||
selector: 'unhideAllApplications:'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'separator'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Quit',
|
|
||||||
accelerator: 'CmdOrCtrl+Q',
|
|
||||||
selector: 'terminate:'
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: 'Edit',
|
label: 'Edit',
|
||||||
submenu: [
|
submenu: [
|
||||||
{
|
{
|
||||||
label: 'Undo',
|
label: 'Undo',
|
||||||
accelerator: 'CmdOrCtrl+Z',
|
accelerator: 'CmdOrCtrl+Z',
|
||||||
selector: 'undo:'
|
role: 'undo'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Redo',
|
label: 'Redo',
|
||||||
accelerator: 'Shift+CmdOrCtrl+Z',
|
accelerator: 'Shift+CmdOrCtrl+Z',
|
||||||
selector: 'redo:'
|
role: 'redo'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'separator'
|
type: 'separator'
|
||||||
|
@ -104,23 +56,23 @@ var template = [
|
||||||
{
|
{
|
||||||
label: 'Cut',
|
label: 'Cut',
|
||||||
accelerator: 'CmdOrCtrl+X',
|
accelerator: 'CmdOrCtrl+X',
|
||||||
selector: 'cut:'
|
role: 'cut'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Copy',
|
label: 'Copy',
|
||||||
accelerator: 'CmdOrCtrl+C',
|
accelerator: 'CmdOrCtrl+C',
|
||||||
selector: 'copy:'
|
role: 'copy'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Paste',
|
label: 'Paste',
|
||||||
accelerator: 'CmdOrCtrl+V',
|
accelerator: 'CmdOrCtrl+V',
|
||||||
selector: 'paste:'
|
role: 'paste'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Select All',
|
label: 'Select All',
|
||||||
accelerator: 'CmdOrCtrl+A',
|
accelerator: 'CmdOrCtrl+A',
|
||||||
selector: 'selectAll:'
|
role: 'selectall'
|
||||||
}
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -129,47 +81,125 @@ var template = [
|
||||||
{
|
{
|
||||||
label: 'Reload',
|
label: 'Reload',
|
||||||
accelerator: 'CmdOrCtrl+R',
|
accelerator: 'CmdOrCtrl+R',
|
||||||
click: function() { remote.getCurrentWindow().reload(); }
|
click: function(item, focusedWindow) {
|
||||||
|
if (focusedWindow)
|
||||||
|
focusedWindow.reload();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Toggle DevTools',
|
label: 'Toggle Full Screen',
|
||||||
accelerator: 'Alt+CmdOrCtrl+I',
|
accelerator: (function() {
|
||||||
click: function() { remote.getCurrentWindow().toggleDevTools(); }
|
if (process.platform == 'darwin')
|
||||||
|
return 'Ctrl+Command+F';
|
||||||
|
else
|
||||||
|
return 'F11';
|
||||||
|
})(),
|
||||||
|
click: function(item, focusedWindow) {
|
||||||
|
if (focusedWindow)
|
||||||
|
focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Toggle Developer Tools',
|
||||||
|
accelerator: (function() {
|
||||||
|
if (process.platform == 'darwin')
|
||||||
|
return 'Alt+Command+I';
|
||||||
|
else
|
||||||
|
return 'Ctrl+Shift+I';
|
||||||
|
})(),
|
||||||
|
click: function(item, focusedWindow) {
|
||||||
|
if (focusedWindow)
|
||||||
|
focusedWindow.toggleDevTools();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Window',
|
label: 'Window',
|
||||||
|
role: 'window',
|
||||||
submenu: [
|
submenu: [
|
||||||
{
|
{
|
||||||
label: 'Minimize',
|
label: 'Minimize',
|
||||||
accelerator: 'CmdOrCtrl+M',
|
accelerator: 'CmdOrCtrl+M',
|
||||||
selector: 'performMiniaturize:'
|
role: 'minimize'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Close',
|
label: 'Close',
|
||||||
accelerator: 'CmdOrCtrl+W',
|
accelerator: 'CmdOrCtrl+W',
|
||||||
selector: 'performClose:'
|
role: 'close'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Help',
|
||||||
|
role: 'help',
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
label: 'Learn More',
|
||||||
|
click: function() { require('shell').openExternal('http://electron.atom.io') }
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
if (process.platform == 'darwin') {
|
||||||
|
var name = require('app').getName();
|
||||||
|
template.unshift({
|
||||||
|
label: name,
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
label: 'About ' + name,
|
||||||
|
role: 'about'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'separator'
|
type: 'separator'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Bring All to Front',
|
label: 'Services',
|
||||||
selector: 'arrangeInFront:'
|
role: 'services',
|
||||||
}
|
submenu: []
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Help',
|
type: 'separator'
|
||||||
submenu: []
|
},
|
||||||
|
{
|
||||||
|
label: 'Hide ' + name,
|
||||||
|
accelerator: 'Command+H',
|
||||||
|
role: 'hide'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Hide Others',
|
||||||
|
accelerator: 'Command+Shift+H',
|
||||||
|
role: 'hideothers:'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Show All',
|
||||||
|
role: 'unhide:'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'separator'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Quit',
|
||||||
|
accelerator: 'Command+Q',
|
||||||
|
click: function() { app.quit(); }
|
||||||
|
},
|
||||||
|
]
|
||||||
|
});
|
||||||
|
// Window menu.
|
||||||
|
template[3].submenu.push(
|
||||||
|
{
|
||||||
|
type: 'separator'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Bring All to Front',
|
||||||
|
role: 'front'
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
];
|
|
||||||
|
|
||||||
menu = Menu.buildFromTemplate(template);
|
menu = Menu.buildFromTemplate(template);
|
||||||
|
|
||||||
Menu.setApplicationMenu(menu);
|
Menu.setApplicationMenu(menu);
|
||||||
</script>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Class: Menu
|
## Class: Menu
|
||||||
|
@ -242,29 +272,26 @@ Linux, here are some notes on making your app's menu more native-like.
|
||||||
### Standard Menus
|
### Standard Menus
|
||||||
|
|
||||||
On OS X there are many system defined standard menus, like the `Services` and
|
On OS X there are many system defined standard menus, like the `Services` and
|
||||||
`Windows` menus. To make your menu a standard menu, you can just set your menu's
|
`Windows` menus. To make your menu a standard menu, you should set your menu's
|
||||||
label to one of following and Electron will recognize them and make them
|
`role` to one of following and Electron will recognize them and make them
|
||||||
become standard menus:
|
become standard menus:
|
||||||
|
|
||||||
* `Window`
|
* `window`
|
||||||
* `Help`
|
* `help`
|
||||||
* `Services`
|
* `services`
|
||||||
|
|
||||||
### Standard Menu Item Actions
|
### Standard Menu Item Actions
|
||||||
|
|
||||||
OS X has provided standard actions for some menu items (which are called
|
OS X has provided standard actions for some menu items, like `About xxx`,
|
||||||
`selector`s), like `About xxx`, `Hide xxx`, and `Hide Others`. To set the action
|
`Hide xxx`, and `Hide Others`. To set the action of a menu item to a standard
|
||||||
of a menu item to a standard action, you can set the `selector` attribute of the
|
action, you should set the `role` attribute of the menu item.
|
||||||
menu item.
|
|
||||||
|
|
||||||
### Main Menu's Name
|
### Main Menu's Name
|
||||||
|
|
||||||
On OS X the label of application menu's first item is always your app's name,
|
On OS X the label of application menu's first item is always your app's name,
|
||||||
no matter what label you set. To change it you have to change your app's name
|
no matter what label you set. To change it you have to change your app's name
|
||||||
by modifying your app bundle's `Info.plist` file. See
|
by modifying your app bundle's `Info.plist` file. See [About Information
|
||||||
[About Information Property List Files](https://developer.apple.com/library/ios/documentation/general/Reference/InfoPlistKeyReference/Articles/AboutInformationPropertyListFiles.html)
|
Property List Files][AboutInformationPropertyListFiles] for more information.
|
||||||
for more information.
|
|
||||||
|
|
||||||
|
|
||||||
## Menu Item Position
|
## Menu Item Position
|
||||||
|
|
||||||
|
@ -339,3 +366,5 @@ Menu:
|
||||||
- 2
|
- 2
|
||||||
- 3
|
- 3
|
||||||
```
|
```
|
||||||
|
|
||||||
|
[AboutInformationPropertyListFiles]: https://developer.apple.com/library/ios/documentation/general/Reference/InfoPlistKeyReference/Articles/AboutInformationPropertyListFiles.html
|
||||||
|
|
Loading…
Reference in a new issue