Skip to content

Commit

Permalink
feat: allow Menu.buildFromTemplate() to accept MenuItems (backport: 5…
Browse files Browse the repository at this point in the history
…-0-x) (#16783)

* feat: allow Menu.buildFromTemplate to accept MenuItems

* add another spec

* fix linter error

* add submenu spec
  • Loading branch information
trop[bot] authored and codebytere committed Feb 11, 2019
1 parent b395a66 commit 14c3962
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 5 deletions.
5 changes: 2 additions & 3 deletions docs/api/menu.md
Expand Up @@ -52,15 +52,14 @@ for more information on macOS' native actions.

#### `Menu.buildFromTemplate(template)`

* `template` MenuItemConstructorOptions[]
* `template` (MenuItemConstructorOptions | MenuItem)[]

Returns `Menu`

Generally, the `template` is an array of `options` for constructing a
[MenuItem](menu-item.md). The usage can be referenced above.

You can also attach other fields to the element of the `template` and they
will become properties of the constructed menu items.
You can also attach other fields to the element of the `template` and they will become properties of the constructed menu items.

### Instance Methods

Expand Down
14 changes: 12 additions & 2 deletions lib/browser/api/menu.js
Expand Up @@ -168,7 +168,13 @@ Menu.buildFromTemplate = function (template) {
const sorted = sortTemplate(filtered)

const menu = new Menu()
sorted.forEach((item) => menu.append(new MenuItem(item)))
sorted.forEach(item => {
if (item instanceof MenuItem) {
menu.append(item)
} else {
menu.append(new MenuItem(item))
}
})

return menu
}
Expand All @@ -178,7 +184,11 @@ Menu.buildFromTemplate = function (template) {
// validate the template against having the wrong attribute
function areValidTemplateItems (template) {
return template.every(item =>
item != null && typeof item === 'object' && (item.hasOwnProperty('label') || item.hasOwnProperty('role') || item.type === 'separator'))
item != null &&
typeof item === 'object' &&
(item.hasOwnProperty('label') ||
item.hasOwnProperty('role') ||
item.type === 'separator'))
}

function sortTemplate (template) {
Expand Down
74 changes: 74 additions & 0 deletions spec/api-menu-spec.js
Expand Up @@ -21,6 +21,37 @@ describe('Menu module', () => {
expect(menu.items[0].extra).to.equal('field')
})

it('should be able to accept only MenuItems', () => {
const menu = Menu.buildFromTemplate([
new MenuItem({ label: 'one' }),
new MenuItem({ label: 'two' })
])
expect(menu.items[0].label).to.equal('one')
expect(menu.items[1].label).to.equal('two')
})

it('should be able to accept only MenuItems in a submenu', () => {
const menu = Menu.buildFromTemplate([
{
label: 'one',
submenu: [
new MenuItem({ label: 'two' })
]
}
])
expect(menu.items[0].label).to.equal('one')
expect(menu.items[0].submenu.items[0].label).to.equal('two')
})

it('should be able to accept MenuItems and plain objects', () => {
const menu = Menu.buildFromTemplate([
new MenuItem({ label: 'one' }),
{ label: 'two' }
])
expect(menu.items[0].label).to.equal('one')
expect(menu.items[1].label).to.equal('two')
})

it('does not modify the specified template', () => {
const template = [{ label: 'text', submenu: [{ label: 'sub' }] }]
const result = ipcRenderer.sendSync('eval', `const template = [{label: 'text', submenu: [{label: 'sub'}]}]\nrequire('electron').Menu.buildFromTemplate(template)\ntemplate`)
Expand Down Expand Up @@ -90,6 +121,21 @@ describe('Menu module', () => {
expect(sortMenuItems(items)).to.deep.equal(expected)
})

it('does a simple sort with MenuItems', () => {
const firstItem = new MenuItem({ id: '1', label: 'one' })
const secondItem = new MenuItem({
label: 'two',
id: '2',
afterGroupContaining: ['1']
})
const sep = new MenuItem({ type: 'separator' })

const items = [ secondItem, sep, firstItem ]
const expected = [ firstItem, sep, secondItem ]

expect(sortMenuItems(items)).to.deep.equal(expected)
})

it('resolves cycles by ignoring things that conflict', () => {
const items = [
{
Expand Down Expand Up @@ -571,6 +617,34 @@ describe('Menu module', () => {
expect(menu.items[3].label).to.equal('four')
expect(menu.items[4].label).to.equal('five')
})

it('should continue inserting MenuItems at next index when no specifier is present', () => {
const menu = Menu.buildFromTemplate([
new MenuItem({
id: '2',
label: 'two'
}), new MenuItem({
id: '3',
label: 'three'
}), new MenuItem({
id: '4',
label: 'four'
}), new MenuItem({
id: '5',
label: 'five'
}), new MenuItem({
id: '1',
label: 'one',
before: ['2']
})
])

expect(menu.items[0].label).to.equal('one')
expect(menu.items[1].label).to.equal('two')
expect(menu.items[2].label).to.equal('three')
expect(menu.items[3].label).to.equal('four')
expect(menu.items[4].label).to.equal('five')
})
})
})

Expand Down

0 comments on commit 14c3962

Please sign in to comment.