Add position attribute for menu items
This commit adds a position attribute for menu items defined in menu templates. When the final menu is built the position attribute is used to determine menu item positions in a similar design to how Eclipse positions menu items.
This commit is contained in:
parent
3ae604ca4e
commit
c8a3c14a8c
3 changed files with 160 additions and 2 deletions
|
@ -113,17 +113,64 @@ Menu.getApplicationMenu = -> applicationMenu
|
||||||
|
|
||||||
Menu.sendActionToFirstResponder = bindings.sendActionToFirstResponder
|
Menu.sendActionToFirstResponder = bindings.sendActionToFirstResponder
|
||||||
|
|
||||||
|
Menu._indexOfItemWithId = (insertedItems, id) ->
|
||||||
|
for each, index in insertedItems
|
||||||
|
if id is each.id
|
||||||
|
return index
|
||||||
|
-1
|
||||||
|
|
||||||
|
Menu._itemIndexForPosition = (insertedItems, position) ->
|
||||||
|
insertIndex = insertedItems.length
|
||||||
|
|
||||||
|
if position
|
||||||
|
[query, id] = position.split '='
|
||||||
|
switch query
|
||||||
|
when 'before'
|
||||||
|
insertIndex = Menu._indexOfItemWithId insertedItems, id
|
||||||
|
when 'after'
|
||||||
|
insertIndex = Menu._indexOfItemWithId insertedItems, id
|
||||||
|
unless insertIndex is -1
|
||||||
|
insertIndex++
|
||||||
|
when 'endof'
|
||||||
|
insertIndex = Menu._indexOfItemWithId insertedItems, id
|
||||||
|
if insertIndex is -1
|
||||||
|
separatorItem = id: id, type: 'separator'
|
||||||
|
insertIndex = insertedItems.length
|
||||||
|
insertedItems.push separatorItem
|
||||||
|
|
||||||
|
insertIndex++
|
||||||
|
item = insertedItems[insertIndex]
|
||||||
|
while (insertIndex < insertedItems.length) and item.type != 'separator'
|
||||||
|
insertIndex++
|
||||||
|
item = insertedItems[insertIndex]
|
||||||
|
|
||||||
|
if insertIndex is -1
|
||||||
|
console.warn "Could not position item at position #{position}"
|
||||||
|
insertIndex = insertedItems.length
|
||||||
|
|
||||||
|
insertIndex
|
||||||
|
|
||||||
Menu.buildFromTemplate = (template) ->
|
Menu.buildFromTemplate = (template) ->
|
||||||
throw new TypeError('Invalid template for Menu') unless Array.isArray template
|
throw new TypeError('Invalid template for Menu') unless Array.isArray template
|
||||||
|
|
||||||
menu = new Menu
|
positionedTemplate = []
|
||||||
|
insertIndex = 0
|
||||||
|
|
||||||
for item in template
|
for item in template
|
||||||
|
position = item.position
|
||||||
|
if position
|
||||||
|
insertIndex = Menu._itemIndexForPosition positionedTemplate, position
|
||||||
|
positionedTemplate.splice insertIndex, 0, item
|
||||||
|
insertIndex++
|
||||||
|
|
||||||
|
menu = new Menu
|
||||||
|
|
||||||
|
for item in positionedTemplate
|
||||||
throw new TypeError('Invalid template for MenuItem') unless typeof item is 'object'
|
throw new TypeError('Invalid template for MenuItem') unless typeof item is 'object'
|
||||||
|
|
||||||
item.submenu = Menu.buildFromTemplate item.submenu if item.submenu?
|
item.submenu = Menu.buildFromTemplate item.submenu if item.submenu?
|
||||||
menuItem = new MenuItem(item)
|
menuItem = new MenuItem(item)
|
||||||
menuItem[key] = value for key, value of item when not menuItem[key]?
|
menuItem[key] = value for key, value of item when not menuItem[key]?
|
||||||
|
|
||||||
menu.append menuItem
|
menu.append menuItem
|
||||||
|
|
||||||
menu
|
menu
|
||||||
|
|
|
@ -5,17 +5,54 @@
|
||||||
### new MenuItem(options)
|
### new MenuItem(options)
|
||||||
|
|
||||||
* `options` Object
|
* `options` Object
|
||||||
|
|
||||||
* `click` Function - Callback when the menu item is clicked
|
* `click` Function - Callback when the menu item is clicked
|
||||||
|
|
||||||
* `selector` String - Call the selector of first responder when clicked (OS
|
* `selector` String - Call the selector of first responder when clicked (OS
|
||||||
X only)
|
X only)
|
||||||
|
|
||||||
* `type` String - Can be `normal`, `separator`, `submenu`, `checkbox` or
|
* `type` String - Can be `normal`, `separator`, `submenu`, `checkbox` or
|
||||||
`radio`
|
`radio`
|
||||||
|
|
||||||
* `label` String
|
* `label` String
|
||||||
|
|
||||||
* `sublabel` String
|
* `sublabel` String
|
||||||
|
|
||||||
* `accelerator` [Accelerator](accelerator.md)
|
* `accelerator` [Accelerator](accelerator.md)
|
||||||
|
|
||||||
* `icon` [NativeImage](native-image.md)
|
* `icon` [NativeImage](native-image.md)
|
||||||
|
|
||||||
* `enabled` Boolean
|
* `enabled` Boolean
|
||||||
|
|
||||||
* `visible` Boolean
|
* `visible` Boolean
|
||||||
|
|
||||||
* `checked` Boolean
|
* `checked` Boolean
|
||||||
|
|
||||||
* `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
|
||||||
|
|
||||||
|
* `id` String - Unique within a single menu. If defined then it can be used
|
||||||
|
as a reference to this item by the position attribute.
|
||||||
|
|
||||||
|
* `position` String - This field allows fine-grained definition of the specific
|
||||||
|
location within a given menu.
|
||||||
|
|
||||||
|
It has the form "[placement]=[id]" where placement is one of `before`,
|
||||||
|
`after`, or `endof` and `id` is the id of an existing item in the menu.
|
||||||
|
|
||||||
|
- `before` - Inserts this item before the id referenced item. If the
|
||||||
|
referenced item doesn't exist the item will be inserted at the end of
|
||||||
|
the menu.
|
||||||
|
|
||||||
|
- `after` - Inserts this item after id referenced item. If the referenced
|
||||||
|
item doesn't exist the item will be inserted at the end of the menu.
|
||||||
|
|
||||||
|
- `endof` - Inserts this item at the end of the logical group containing
|
||||||
|
the id referenced item. (Groups are created by separator items). If
|
||||||
|
the referenced item doesn't exist a new separator group is created with
|
||||||
|
the given id and this item is inserted after that separator.
|
||||||
|
|
||||||
|
When an item is positioned following unpositioned items are inserted after
|
||||||
|
it, until a new item is positioned. So if you want to position a group of
|
||||||
|
menu items in the same location you only need to specify a position for
|
||||||
|
the first item.
|
|
@ -10,6 +10,80 @@ describe 'menu module', ->
|
||||||
menu = Menu.buildFromTemplate [label: 'text', extra: 'field']
|
menu = Menu.buildFromTemplate [label: 'text', extra: 'field']
|
||||||
assert.equal menu.items[0].extra, 'field'
|
assert.equal menu.items[0].extra, 'field'
|
||||||
|
|
||||||
|
describe 'Menu.buildFromTemplate should reorder based on item position specifiers', ->
|
||||||
|
it 'should position before existing item', ->
|
||||||
|
menu = Menu.buildFromTemplate [
|
||||||
|
{label: '2', id: '2'}
|
||||||
|
{label: '3', id: '3'}
|
||||||
|
{label: '1', id: '1', position: 'before=2'}
|
||||||
|
]
|
||||||
|
assert.equal menu.items[0].label, '1'
|
||||||
|
assert.equal menu.items[1].label, '2'
|
||||||
|
assert.equal menu.items[2].label, '3'
|
||||||
|
|
||||||
|
it 'should position after existing item', ->
|
||||||
|
menu = Menu.buildFromTemplate [
|
||||||
|
{label: '1', id: '1'}
|
||||||
|
{label: '3', id: '3'}
|
||||||
|
{label: '2', id: '2', position: 'after=1'}
|
||||||
|
]
|
||||||
|
assert.equal menu.items[0].label, '1'
|
||||||
|
assert.equal menu.items[1].label, '2'
|
||||||
|
assert.equal menu.items[2].label, '3'
|
||||||
|
|
||||||
|
it 'should position at endof existing separator groups', ->
|
||||||
|
menu = Menu.buildFromTemplate [
|
||||||
|
{type: 'separator', id: 'numbers'}
|
||||||
|
{type: 'separator', id: 'letters'}
|
||||||
|
{label: 'a', id: 'a', position: 'endof=letters'}
|
||||||
|
{label: '1', id: '1', position: 'endof=numbers'}
|
||||||
|
{label: 'b', id: 'b', position: 'endof=letters'}
|
||||||
|
{label: '2', id: '2', position: 'endof=numbers'}
|
||||||
|
{label: 'c', id: 'c', position: 'endof=letters'}
|
||||||
|
{label: '3', id: '3', position: 'endof=numbers'}
|
||||||
|
]
|
||||||
|
assert.equal menu.items[0].id, 'numbers'
|
||||||
|
assert.equal menu.items[1].label, '1'
|
||||||
|
assert.equal menu.items[2].label, '2'
|
||||||
|
assert.equal menu.items[3].label, '3'
|
||||||
|
assert.equal menu.items[4].id, 'letters'
|
||||||
|
assert.equal menu.items[5].label, 'a'
|
||||||
|
assert.equal menu.items[6].label, 'b'
|
||||||
|
assert.equal menu.items[7].label, 'c'
|
||||||
|
|
||||||
|
it 'should create separator group if endof does not reference existing separator group', ->
|
||||||
|
menu = Menu.buildFromTemplate [
|
||||||
|
{label: 'a', id: 'a', position: 'endof=letters'}
|
||||||
|
{label: '1', id: '1', position: 'endof=numbers'}
|
||||||
|
{label: 'b', id: 'b', position: 'endof=letters'}
|
||||||
|
{label: '2', id: '2', position: 'endof=numbers'}
|
||||||
|
{label: 'c', id: 'c', position: 'endof=letters'}
|
||||||
|
{label: '3', id: '3', position: 'endof=numbers'}
|
||||||
|
]
|
||||||
|
|
||||||
|
assert.equal menu.items[0].id, 'letters'
|
||||||
|
assert.equal menu.items[1].label, 'a'
|
||||||
|
assert.equal menu.items[2].label, 'b'
|
||||||
|
assert.equal menu.items[3].label, 'c'
|
||||||
|
assert.equal menu.items[4].id, 'numbers'
|
||||||
|
assert.equal menu.items[5].label, '1'
|
||||||
|
assert.equal menu.items[6].label, '2'
|
||||||
|
assert.equal menu.items[7].label, '3'
|
||||||
|
|
||||||
|
it 'should continue inserting items at next index when no specifier is present', ->
|
||||||
|
menu = Menu.buildFromTemplate [
|
||||||
|
{label: '4', id: '4'}
|
||||||
|
{label: '5', id: '5'}
|
||||||
|
{label: '1', id: '1', position: 'before=4'}
|
||||||
|
{label: '2', id: '2'}
|
||||||
|
{label: '3', id: '3'}
|
||||||
|
]
|
||||||
|
assert.equal menu.items[0].label, '1'
|
||||||
|
assert.equal menu.items[1].label, '2'
|
||||||
|
assert.equal menu.items[2].label, '3'
|
||||||
|
assert.equal menu.items[3].label, '4'
|
||||||
|
assert.equal menu.items[4].label, '5'
|
||||||
|
|
||||||
describe 'Menu.insert', ->
|
describe 'Menu.insert', ->
|
||||||
it 'should store item in @items by its index', ->
|
it 'should store item in @items by its index', ->
|
||||||
menu = Menu.buildFromTemplate [
|
menu = Menu.buildFromTemplate [
|
||||||
|
|
Loading…
Reference in a new issue