Merge pull request #354 from atom/automatic-group-id
Improve radio and checkbox menu items support
This commit is contained in:
commit
5b216ee0e6
13 changed files with 212 additions and 56 deletions
|
@ -44,7 +44,9 @@ v8::Handle<v8::Value> CallDelegate(v8::Handle<v8::Value> default_value,
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Menu::Menu() : model_(new ui::SimpleMenuModel(this)) {
|
Menu::Menu()
|
||||||
|
: model_(new ui::SimpleMenuModel(this)),
|
||||||
|
parent_(NULL) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Menu::~Menu() {
|
Menu::~Menu() {
|
||||||
|
@ -135,6 +137,12 @@ void Menu::ExecuteCommand(int command_id, int event_flags) {
|
||||||
command_id);
|
command_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Menu::MenuWillShow(ui::SimpleMenuModel* source) {
|
||||||
|
v8::Locker locker(node_isolate);
|
||||||
|
v8::HandleScope handle_scope(node_isolate);
|
||||||
|
CallDelegate(v8::False(), GetWrapper(node_isolate), "menuWillShow", -1);
|
||||||
|
}
|
||||||
|
|
||||||
void Menu::InsertItemAt(
|
void Menu::InsertItemAt(
|
||||||
int index, int command_id, const base::string16& label) {
|
int index, int command_id, const base::string16& label) {
|
||||||
model_->InsertItemAt(index, command_id, label);
|
model_->InsertItemAt(index, command_id, label);
|
||||||
|
@ -161,6 +169,7 @@ void Menu::InsertSubMenuAt(int index,
|
||||||
int command_id,
|
int command_id,
|
||||||
const base::string16& label,
|
const base::string16& label,
|
||||||
Menu* menu) {
|
Menu* menu) {
|
||||||
|
menu->parent_ = this;
|
||||||
model_->InsertSubMenuAt(index, command_id, label, menu->model_.get());
|
model_->InsertSubMenuAt(index, command_id, label, menu->model_.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,9 +233,12 @@ void Menu::BuildPrototype(v8::Isolate* isolate,
|
||||||
.SetMethod("isEnabledAt", &Menu::IsEnabledAt)
|
.SetMethod("isEnabledAt", &Menu::IsEnabledAt)
|
||||||
.SetMethod("isVisibleAt", &Menu::IsVisibleAt)
|
.SetMethod("isVisibleAt", &Menu::IsVisibleAt)
|
||||||
#if defined(OS_WIN) || defined(TOOLKIT_GTK)
|
#if defined(OS_WIN) || defined(TOOLKIT_GTK)
|
||||||
.SetMethod("attachToWindow", &Menu::AttachToWindow)
|
.SetMethod("_attachToWindow", &Menu::AttachToWindow)
|
||||||
#endif
|
#endif
|
||||||
.SetMethod("popup", &Menu::Popup);
|
#if defined(OS_WIN)
|
||||||
|
.SetMethod("_updateStates", &Menu::UpdateStates)
|
||||||
|
#endif
|
||||||
|
.SetMethod("_popup", &Menu::Popup);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace api
|
} // namespace api
|
||||||
|
|
|
@ -49,10 +49,12 @@ class Menu : public mate::Wrappable,
|
||||||
virtual string16 GetLabelForCommandId(int command_id) const OVERRIDE;
|
virtual string16 GetLabelForCommandId(int command_id) const OVERRIDE;
|
||||||
virtual string16 GetSublabelForCommandId(int command_id) const OVERRIDE;
|
virtual string16 GetSublabelForCommandId(int command_id) const OVERRIDE;
|
||||||
virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
|
virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
|
||||||
|
virtual void MenuWillShow(ui::SimpleMenuModel* source) OVERRIDE;
|
||||||
|
|
||||||
virtual void Popup(Window* window) = 0;
|
virtual void Popup(Window* window) = 0;
|
||||||
|
|
||||||
scoped_ptr<ui::SimpleMenuModel> model_;
|
scoped_ptr<ui::SimpleMenuModel> model_;
|
||||||
|
Menu* parent_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void InsertItemAt(int index, int command_id, const base::string16& label);
|
void InsertItemAt(int index, int command_id, const base::string16& label);
|
||||||
|
@ -79,8 +81,12 @@ class Menu : public mate::Wrappable,
|
||||||
bool IsEnabledAt(int index) const;
|
bool IsEnabledAt(int index) const;
|
||||||
bool IsVisibleAt(int index) const;
|
bool IsVisibleAt(int index) const;
|
||||||
|
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
virtual void UpdateStates() = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(OS_WIN) || defined(TOOLKIT_GTK)
|
#if defined(OS_WIN) || defined(TOOLKIT_GTK)
|
||||||
void AttachToWindow(Window* window);
|
virtual void AttachToWindow(Window* window) = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(Menu);
|
DISALLOW_COPY_AND_ASSIGN(Menu);
|
||||||
|
|
|
@ -37,7 +37,7 @@ void MenuGtk::Popup(Window* window) {
|
||||||
menu_gtk_->PopupAsContext(point, triggering_event_time);
|
menu_gtk_->PopupAsContext(point, triggering_event_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Menu::AttachToWindow(Window* window) {
|
void MenuGtk::AttachToWindow(Window* window) {
|
||||||
static_cast<NativeWindowGtk*>(window->window())->SetMenu(model_.get());
|
static_cast<NativeWindowGtk*>(window->window())->SetMenu(model_.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ class MenuGtk : public Menu,
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void Popup(Window* window) OVERRIDE;
|
virtual void Popup(Window* window) OVERRIDE;
|
||||||
|
virtual void AttachToWindow(Window* window) OVERRIDE;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
scoped_ptr<::MenuGtk> menu_gtk_;
|
scoped_ptr<::MenuGtk> menu_gtk_;
|
||||||
|
|
|
@ -15,17 +15,28 @@ namespace atom {
|
||||||
|
|
||||||
namespace api {
|
namespace api {
|
||||||
|
|
||||||
MenuWin::MenuWin() {
|
MenuWin::MenuWin() : menu_(NULL) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MenuWin::Popup(Window* window) {
|
void MenuWin::Popup(Window* window) {
|
||||||
gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
|
gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
|
||||||
menu_.reset(new atom::Menu2(model_.get()));
|
popup_menu_.reset(new atom::Menu2(model_.get()));
|
||||||
|
menu_ = popup_menu_.get();
|
||||||
menu_->RunContextMenuAt(cursor);
|
menu_->RunContextMenuAt(cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Menu::AttachToWindow(Window* window) {
|
void MenuWin::UpdateStates() {
|
||||||
static_cast<NativeWindowWin*>(window->window())->SetMenu(model_.get());
|
MenuWin* top = this;
|
||||||
|
while (top->parent_)
|
||||||
|
top = static_cast<MenuWin*>(top->parent_);
|
||||||
|
if (top->menu_)
|
||||||
|
top->menu_->UpdateStates();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MenuWin::AttachToWindow(Window* window) {
|
||||||
|
NativeWindowWin* nw = static_cast<NativeWindowWin*>(window->window());
|
||||||
|
nw->SetMenu(model_.get());
|
||||||
|
menu_ = nw->menu();
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
|
|
@ -19,9 +19,12 @@ class MenuWin : public Menu {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void Popup(Window* window) OVERRIDE;
|
virtual void Popup(Window* window) OVERRIDE;
|
||||||
|
virtual void UpdateStates() OVERRIDE;
|
||||||
|
virtual void AttachToWindow(Window* window) OVERRIDE;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
scoped_ptr<atom::Menu2> menu_;
|
atom::Menu2* menu_; // Weak ref, could be window menu or popup menu.
|
||||||
|
scoped_ptr<atom::Menu2> popup_menu_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(MenuWin);
|
DISALLOW_COPY_AND_ASSIGN(MenuWin);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
BrowserWindow = require 'browser-window'
|
BrowserWindow = require 'browser-window'
|
||||||
|
v8Util = process.atomBinding 'v8_util'
|
||||||
|
|
||||||
nextCommandId = 0
|
nextCommandId = 0
|
||||||
|
|
||||||
|
@ -8,28 +9,50 @@ class MenuItem
|
||||||
constructor: (options) ->
|
constructor: (options) ->
|
||||||
Menu = require 'menu'
|
Menu = require 'menu'
|
||||||
|
|
||||||
{click, @selector, @type, @label, @sublabel, @accelerator, @enabled, @visible, @checked, @groupId, @submenu} = options
|
{click, @selector, @type, @label, @sublabel, @accelerator, @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
|
||||||
|
|
||||||
@type = @type ? 'normal'
|
@overrideReadOnlyProperty 'type', 'normal'
|
||||||
@label = @label ? ''
|
@overrideReadOnlyProperty 'accelerator'
|
||||||
@sublabel = @sublabel ? ''
|
@overrideReadOnlyProperty 'submenu'
|
||||||
@accelerator = @accelerator ? null
|
@overrideProperty 'label', ''
|
||||||
@enabled = @enabled ? true
|
@overrideProperty 'sublabel', ''
|
||||||
@visible = @visible ? true
|
@overrideProperty 'enabled', true
|
||||||
@checked = @checked ? false
|
@overrideProperty 'visible', true
|
||||||
@groupId = @groupId ? null
|
@overrideProperty 'checked', false
|
||||||
@submenu = @submenu ? null
|
|
||||||
|
|
||||||
throw new Error('Unknown menu 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 = =>
|
||||||
|
# Manually flip the checked flags when clicked.
|
||||||
|
@checked = !@checked if @type in ['checkbox', 'radio']
|
||||||
|
|
||||||
if typeof click is 'function'
|
if typeof click is 'function'
|
||||||
click this, BrowserWindow.getFocusedWindow()
|
click this, BrowserWindow.getFocusedWindow()
|
||||||
else if typeof @selector is 'string'
|
else if typeof @selector is 'string'
|
||||||
Menu.sendActionToFirstResponder @selector
|
Menu.sendActionToFirstResponder @selector
|
||||||
|
|
||||||
|
overrideProperty: (name, defaultValue=null) ->
|
||||||
|
this[name] ?= defaultValue
|
||||||
|
|
||||||
|
# Update states when property is changed on Windows.
|
||||||
|
return unless process.platform is 'win32'
|
||||||
|
v8Util.setHiddenValue this, name, this[name]
|
||||||
|
Object.defineProperty this, name,
|
||||||
|
enumerable: true
|
||||||
|
get: => v8Util.getHiddenValue this, name
|
||||||
|
set: (val) =>
|
||||||
|
v8Util.setHiddenValue this, name, val
|
||||||
|
@menu?._updateStates()
|
||||||
|
|
||||||
|
overrideReadOnlyProperty: (name, defaultValue=null) ->
|
||||||
|
this[name] ?= defaultValue
|
||||||
|
Object.defineProperty this, name,
|
||||||
|
enumerable: true
|
||||||
|
writable: false
|
||||||
|
value: this[name]
|
||||||
|
|
||||||
module.exports = MenuItem
|
module.exports = MenuItem
|
||||||
|
|
|
@ -1,17 +1,34 @@
|
||||||
BrowserWindow = require 'browser-window'
|
BrowserWindow = require 'browser-window'
|
||||||
EventEmitter = require('events').EventEmitter
|
EventEmitter = require('events').EventEmitter
|
||||||
MenuItem = require 'menu-item'
|
MenuItem = require 'menu-item'
|
||||||
|
v8Util = process.atomBinding 'v8_util'
|
||||||
|
|
||||||
bindings = process.atomBinding 'menu'
|
bindings = process.atomBinding 'menu'
|
||||||
|
|
||||||
|
# Automatically generated radio menu item's group id.
|
||||||
|
nextGroupId = 0
|
||||||
|
|
||||||
|
# Search between seperators to find a radio menu item and return its group id,
|
||||||
|
# otherwise generate a group id.
|
||||||
|
generateGroupId = (items, pos) ->
|
||||||
|
if pos > 0
|
||||||
|
for i in [pos - 1..0]
|
||||||
|
item = items[i]
|
||||||
|
return item.groupId if item.type is 'radio'
|
||||||
|
break if item.type is 'separator'
|
||||||
|
else if pos < items.length
|
||||||
|
for i in [pos..items.length - 1]
|
||||||
|
item = items[i]
|
||||||
|
return item.groupId if item.type is 'radio'
|
||||||
|
break if item.type is 'separator'
|
||||||
|
++nextGroupId
|
||||||
|
|
||||||
Menu = bindings.Menu
|
Menu = bindings.Menu
|
||||||
Menu::__proto__ = EventEmitter.prototype
|
Menu::__proto__ = EventEmitter.prototype
|
||||||
|
|
||||||
popup = Menu::popup
|
|
||||||
Menu::popup = (window) ->
|
Menu::popup = (window) ->
|
||||||
throw new TypeError('Invalid window') unless window?.constructor is BrowserWindow
|
throw new TypeError('Invalid window') unless window?.constructor is BrowserWindow
|
||||||
|
@_popup window
|
||||||
popup.call this, window
|
|
||||||
|
|
||||||
Menu::append = (item) ->
|
Menu::append = (item) ->
|
||||||
@insert @getItemCount(), item
|
@insert @getItemCount(), item
|
||||||
|
@ -19,15 +36,7 @@ Menu::append = (item) ->
|
||||||
Menu::insert = (pos, item) ->
|
Menu::insert = (pos, item) ->
|
||||||
throw new TypeError('Invalid item') unless item?.constructor is MenuItem
|
throw new TypeError('Invalid item') unless item?.constructor is MenuItem
|
||||||
|
|
||||||
switch item.type
|
# Create delegate.
|
||||||
when 'normal' then @insertItem pos, item.commandId, item.label
|
|
||||||
when 'checkbox' then @insertCheckItem pos, item.commandId, item.label
|
|
||||||
when 'radio' then @insertRadioItem pos, item.commandId, item.label, item.groupId
|
|
||||||
when 'separator' then @insertSeparator pos
|
|
||||||
when 'submenu' then @insertSubMenu pos, item.commandId, item.label, item.submenu
|
|
||||||
|
|
||||||
@setSublabel pos, item.sublabel if item.sublabel?
|
|
||||||
|
|
||||||
unless @delegate?
|
unless @delegate?
|
||||||
@commandsMap = {}
|
@commandsMap = {}
|
||||||
@groupsMap = {}
|
@groupsMap = {}
|
||||||
|
@ -37,23 +46,59 @@ Menu::insert = (pos, item) ->
|
||||||
isCommandIdEnabled: (commandId) => @commandsMap[commandId]?.enabled
|
isCommandIdEnabled: (commandId) => @commandsMap[commandId]?.enabled
|
||||||
isCommandIdVisible: (commandId) => @commandsMap[commandId]?.visible
|
isCommandIdVisible: (commandId) => @commandsMap[commandId]?.visible
|
||||||
getAcceleratorForCommandId: (commandId) => @commandsMap[commandId]?.accelerator
|
getAcceleratorForCommandId: (commandId) => @commandsMap[commandId]?.accelerator
|
||||||
executeCommand: (commandId) =>
|
executeCommand: (commandId) => @commandsMap[commandId]?.click()
|
||||||
activeItem = @commandsMap[commandId]
|
menuWillShow: =>
|
||||||
if activeItem?
|
# Make sure radio groups have at least one menu item seleted.
|
||||||
switch activeItem.type
|
for id, group of @groupsMap
|
||||||
when 'checkbox'
|
checked = false
|
||||||
activeItem.checked = !activeItem.checked
|
for radioItem in group when radioItem.checked
|
||||||
|
checked = true
|
||||||
|
break
|
||||||
|
v8Util.setHiddenValue group[0], 'checked', true unless checked
|
||||||
|
|
||||||
|
switch item.type
|
||||||
|
when 'normal' then @insertItem pos, item.commandId, item.label
|
||||||
|
when 'checkbox' then @insertCheckItem pos, item.commandId, item.label
|
||||||
|
when 'separator' then @insertSeparator pos
|
||||||
|
when 'submenu' then @insertSubMenu pos, item.commandId, item.label, item.submenu
|
||||||
when 'radio'
|
when 'radio'
|
||||||
for item in @groupsMap[activeItem.groupId]
|
# Grouping radio menu items.
|
||||||
item.checked = false
|
item.overrideReadOnlyProperty 'groupId', generateGroupId(@items, pos)
|
||||||
activeItem.checked = true
|
@groupsMap[item.groupId] ?= []
|
||||||
activeItem.click()
|
@groupsMap[item.groupId].push item
|
||||||
|
|
||||||
|
# Setting a radio menu item should flip other items in the group.
|
||||||
|
v8Util.setHiddenValue item, 'checked', item.checked
|
||||||
|
Object.defineProperty item, 'checked',
|
||||||
|
enumerable: true
|
||||||
|
get: -> v8Util.getHiddenValue item, 'checked'
|
||||||
|
set: (val) =>
|
||||||
|
for otherItem in @groupsMap[item.groupId] when otherItem isnt item
|
||||||
|
v8Util.setHiddenValue otherItem, 'checked', false
|
||||||
|
v8Util.setHiddenValue item, 'checked', true
|
||||||
|
|
||||||
|
# Update states when clicked on Windows.
|
||||||
|
@_updateStates() if process.platform is 'win32'
|
||||||
|
|
||||||
|
@insertRadioItem pos, item.commandId, item.label, item.groupId
|
||||||
|
|
||||||
|
@setSublabel pos, item.sublabel if item.sublabel?
|
||||||
|
|
||||||
|
# Make menu accessable to items.
|
||||||
|
item.overrideReadOnlyProperty 'menu', this
|
||||||
|
|
||||||
|
# Remember the items.
|
||||||
@items.splice pos, 0, item
|
@items.splice pos, 0, item
|
||||||
@commandsMap[item.commandId] = item
|
@commandsMap[item.commandId] = item
|
||||||
|
|
||||||
if item.groupId?
|
Menu::attachToWindow = (window) ->
|
||||||
@groupsMap[item.groupId] ?= []
|
@_callMenuWillShow() if process.platform is 'win32'
|
||||||
@groupsMap[item.groupId].push item
|
@_attachToWindow window
|
||||||
|
|
||||||
|
# Force menuWillShow to be called
|
||||||
|
Menu::_callMenuWillShow = ->
|
||||||
|
@delegate?.menuWillShow()
|
||||||
|
item.submenu._callMenuWillShow() for item in @items when item.submenu?
|
||||||
|
|
||||||
applicationMenu = null
|
applicationMenu = null
|
||||||
Menu.setApplicationMenu = (menu) ->
|
Menu.setApplicationMenu = (menu) ->
|
||||||
|
@ -61,6 +106,7 @@ Menu.setApplicationMenu = (menu) ->
|
||||||
applicationMenu = menu # Keep a reference.
|
applicationMenu = menu # Keep a reference.
|
||||||
|
|
||||||
if process.platform is 'darwin'
|
if process.platform is 'darwin'
|
||||||
|
menu._callMenuWillShow()
|
||||||
bindings.setApplicationMenu menu
|
bindings.setApplicationMenu menu
|
||||||
else
|
else
|
||||||
windows = BrowserWindow.getAllWindows()
|
windows = BrowserWindow.getAllWindows()
|
||||||
|
|
|
@ -415,6 +415,7 @@ void NativeWindowWin::OnMenuCommand(int position, HMENU menu) {
|
||||||
|
|
||||||
void NativeWindowWin::SetMenu(ui::MenuModel* menu_model) {
|
void NativeWindowWin::SetMenu(ui::MenuModel* menu_model) {
|
||||||
menu_.reset(new atom::Menu2(menu_model, true));
|
menu_.reset(new atom::Menu2(menu_model, true));
|
||||||
|
menu_->UpdateStates();
|
||||||
::SetMenu(GetNativeWindow(), menu_->GetNativeMenu());
|
::SetMenu(GetNativeWindow(), menu_->GetNativeMenu());
|
||||||
RegisterAccelerators();
|
RegisterAccelerators();
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,7 @@ class NativeWindowWin : public NativeWindow,
|
||||||
void SetMenu(ui::MenuModel* menu_model);
|
void SetMenu(ui::MenuModel* menu_model);
|
||||||
|
|
||||||
views::Widget* window() const { return window_.get(); }
|
views::Widget* window() const { return window_.get(); }
|
||||||
|
atom::Menu2* menu() const { return menu_.get(); }
|
||||||
SkRegion* draggable_region() { return draggable_region_.get(); }
|
SkRegion* draggable_region() { return draggable_region_.get(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
* `enabled` Boolean
|
* `enabled` Boolean
|
||||||
* `visible` Boolean
|
* `visible` Boolean
|
||||||
* `checked` Boolean
|
* `checked` Boolean
|
||||||
* `groupId` Integer - Should be specified for `radio` type menu item
|
|
||||||
* `submenu` Menu - Should be specified for `submenu` type menu item, when
|
* `submenu` Menu - Should be specified for `submenu` type menu item, when
|
||||||
it's specified the `type: 'submenu'` can be omitted for the menu item
|
it's specified the `type: 'submenu'` can be omitted for the menu item
|
||||||
|
|
||||||
|
|
|
@ -35,3 +35,57 @@ describe 'menu module', ->
|
||||||
done()
|
done()
|
||||||
]
|
]
|
||||||
menu.delegate.executeCommand menu.items[0].commandId
|
menu.delegate.executeCommand menu.items[0].commandId
|
||||||
|
|
||||||
|
describe 'MenuItem with checked property', ->
|
||||||
|
it 'clicking an checkbox item should flip the checked property', ->
|
||||||
|
menu = Menu.buildFromTemplate [ label: 'text', type: 'checkbox' ]
|
||||||
|
assert.equal menu.items[0].checked, false
|
||||||
|
menu.delegate.executeCommand menu.items[0].commandId
|
||||||
|
assert.equal menu.items[0].checked, true
|
||||||
|
|
||||||
|
it 'clicking an radio item should always make checked property true', ->
|
||||||
|
menu = Menu.buildFromTemplate [ label: 'text', type: 'radio' ]
|
||||||
|
menu.delegate.executeCommand menu.items[0].commandId
|
||||||
|
assert.equal menu.items[0].checked, true
|
||||||
|
menu.delegate.executeCommand menu.items[0].commandId
|
||||||
|
assert.equal menu.items[0].checked, true
|
||||||
|
|
||||||
|
it 'at least have one item checked in each group', ->
|
||||||
|
template = []
|
||||||
|
template.push label: "#{i}", type: 'radio' for i in [0..10]
|
||||||
|
template.push type: 'separator'
|
||||||
|
template.push label: "#{i}", type: 'radio' for i in [12..20]
|
||||||
|
menu = Menu.buildFromTemplate template
|
||||||
|
menu.delegate.menuWillShow()
|
||||||
|
assert.equal menu.items[0].checked, true
|
||||||
|
assert.equal menu.items[12].checked, true
|
||||||
|
|
||||||
|
it 'should assign groupId automatically', ->
|
||||||
|
template = []
|
||||||
|
template.push label: "#{i}", type: 'radio' for i in [0..10]
|
||||||
|
template.push type: 'separator'
|
||||||
|
template.push label: "#{i}", type: 'radio' for i in [12..20]
|
||||||
|
menu = Menu.buildFromTemplate template
|
||||||
|
groupId = menu.items[0].groupId
|
||||||
|
assert.equal menu.items[i].groupId, groupId for i in [0..10]
|
||||||
|
assert.equal menu.items[i].groupId, groupId + 1 for i in [12..20]
|
||||||
|
|
||||||
|
it "setting 'checked' should flip other items' 'checked' property", ->
|
||||||
|
template = []
|
||||||
|
template.push label: "#{i}", type: 'radio' for i in [0..10]
|
||||||
|
template.push type: 'separator'
|
||||||
|
template.push label: "#{i}", type: 'radio' for i in [12..20]
|
||||||
|
menu = Menu.buildFromTemplate template
|
||||||
|
assert.equal menu.items[i].checked, false for i in [0..10]
|
||||||
|
menu.items[0].checked = true
|
||||||
|
assert.equal menu.items[0].checked, true
|
||||||
|
assert.equal menu.items[i].checked, false for i in [1..10]
|
||||||
|
menu.items[10].checked = true
|
||||||
|
assert.equal menu.items[10].checked, true
|
||||||
|
assert.equal menu.items[i].checked, false for i in [0..9]
|
||||||
|
assert.equal menu.items[i].checked, false for i in [12..20]
|
||||||
|
menu.items[12].checked = true
|
||||||
|
assert.equal menu.items[10].checked, true
|
||||||
|
assert.equal menu.items[i].checked, false for i in [0..9]
|
||||||
|
assert.equal menu.items[12].checked, true
|
||||||
|
assert.equal menu.items[i].checked, false for i in [13..20]
|
||||||
|
|
|
@ -32,10 +32,13 @@ ipc.on('echo', function(event, msg) {
|
||||||
event.returnValue = msg;
|
event.returnValue = msg;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (process.argv[1] == '--ci') {
|
||||||
|
process.removeAllListeners('uncaughtException');
|
||||||
process.on('uncaughtException', function(error) {
|
process.on('uncaughtException', function(error) {
|
||||||
console.log(error);
|
console.error(error, error.stack);
|
||||||
window.openDevTools();
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
app.on('window-all-closed', function() {
|
app.on('window-all-closed', function() {
|
||||||
app.quit();
|
app.quit();
|
||||||
|
@ -124,10 +127,6 @@ app.on('ready', function() {
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: 'Help',
|
|
||||||
submenu: [],
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
|
|
||||||
var menu = Menu.buildFromTemplate(template);
|
var menu = Menu.buildFromTemplate(template);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue