Add menu item order control (#12362)

Add four new optional properties to menus in Electron. The four properties are:
'before'
'after'
'beforeGroupContaining'
'afterGroupContaining'

'before/after' - provides a means for a single context menu item to declare its placement relative to another context menu item. These also imply that menu item in question should be placed in the same “group” as the item.

'beforeGroupContaining/afterGroupContaining - provides a means for a single menu item to declare the placement of its containing group, relative to the containing group of the specified item.
This commit is contained in:
Shelley Vohr 2018-05-05 09:37:29 -07:00 committed by GitHub
parent 118da36b52
commit 9c8952aef0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 665 additions and 206 deletions

View file

@ -1,6 +1,7 @@
'use strict'
const {TopLevelWindow, MenuItem, webContents} = require('electron')
const {sortMenuItems} = require('./menu-utils')
const EventEmitter = require('events').EventEmitter
const v8Util = process.atomBinding('v8_util')
const bindings = process.atomBinding('menu')
@ -160,18 +161,9 @@ Menu.buildFromTemplate = function (template) {
const menu = new Menu()
const filtered = removeExtraSeparators(template)
const sorted = sortTemplate(filtered)
const positioned = []
let idx = 0
// sort template by position
filtered.forEach(item => {
idx = (item.position) ? indexToInsertByPosition(positioned, item.position) : idx += 1
positioned.splice(idx, 0, item)
})
// add each item from positioned menu to application menu
positioned.forEach((item) => {
sorted.forEach((item) => {
if (typeof item !== 'object') {
throw new TypeError('Invalid template for MenuItem')
}
@ -183,6 +175,17 @@ Menu.buildFromTemplate = function (template) {
/* Helper Functions */
function sortTemplate (template) {
const sorted = sortMenuItems(template)
for (let id in sorted) {
const item = sorted[id]
if (Array.isArray(item.submenu)) {
item.submenu = sortTemplate(item.submenu)
}
}
return sorted
}
// Search between separators to find a radio menu item and return its group id
function generateGroupId (items, pos) {
if (pos > 0) {
@ -200,45 +203,6 @@ function generateGroupId (items, pos) {
return groupIdIndex
}
function indexOfItemById (items, id) {
const foundItem = items.find(item => item.id === id) || -1
return items.indexOf(foundItem)
}
function indexToInsertByPosition (items, position) {
if (!position) return items.length
const [query, id] = position.split('=') // parse query and id from position
const idx = indexOfItemById(items, id) // calculate initial index of item
// warn if query doesn't exist
if (idx === -1 && query !== 'endof') {
console.warn(`Item with id ${id} is not found`)
return items.length
}
// compute new index based on query
const queries = {
after: (index) => {
index += 1
return index
},
endof: (index) => {
if (index === -1) {
items.push({id, type: 'separator'})
index = items.length - 1
}
index += 1
while (index < items.length && items[index].type !== 'separator') index += 1
return index
}
}
// return new index if needed, or original indexOfItemById
return (query in queries) ? queries[query](idx) : idx
}
function removeExtraSeparators (items) {
// fold adjacent separators together
let ret = items.filter((e, idx, arr) => {