mirror of
https://github.com/atom/atom.git
synced 2026-01-26 07:19:06 -05:00
133 lines
3.1 KiB
JavaScript
133 lines
3.1 KiB
JavaScript
const _ = require('underscore-plus')
|
|
|
|
const ItemSpecificities = new WeakMap()
|
|
|
|
// Add an item to a menu, ensuring separators are not duplicated.
|
|
function addItemToMenu (item, menu) {
|
|
const lastMenuItem = _.last(menu)
|
|
const lastMenuItemIsSpearator = lastMenuItem && lastMenuItem.type === 'separator'
|
|
if (!(item.type === 'separator' && lastMenuItemIsSpearator)) {
|
|
menu.push(item)
|
|
}
|
|
}
|
|
|
|
function merge (menu, item, itemSpecificity = Infinity) {
|
|
item = cloneMenuItem(item)
|
|
ItemSpecificities.set(item, itemSpecificity)
|
|
const matchingItemIndex = findMatchingItemIndex(menu, item)
|
|
|
|
if (matchingItemIndex === -1) {
|
|
addItemToMenu(item, menu)
|
|
return
|
|
}
|
|
|
|
const matchingItem = menu[matchingItemIndex]
|
|
if (item.submenu != null) {
|
|
for (let submenuItem of item.submenu) {
|
|
merge(matchingItem.submenu, submenuItem, itemSpecificity)
|
|
}
|
|
} else if (itemSpecificity && itemSpecificity >= ItemSpecificities.get(matchingItem)) {
|
|
menu[matchingItemIndex] = item
|
|
}
|
|
}
|
|
|
|
function unmerge (menu, item) {
|
|
const matchingItemIndex = findMatchingItemIndex(menu, item)
|
|
if (matchingItemIndex === -1) {
|
|
return
|
|
}
|
|
|
|
const matchingItem = menu[matchingItemIndex]
|
|
if (item.submenu != null) {
|
|
for (let submenuItem of item.submenu) {
|
|
unmerge(matchingItem.submenu, submenuItem)
|
|
}
|
|
}
|
|
|
|
if (matchingItem.submenu == null || matchingItem.submenu.length === 0) {
|
|
menu.splice(matchingItemIndex, 1)
|
|
}
|
|
}
|
|
|
|
function findMatchingItemIndex (menu, { type, label, submenu }) {
|
|
if (type === 'separator') {
|
|
return -1
|
|
}
|
|
for (let index = 0; index < menu.length; index++) {
|
|
const item = menu[index]
|
|
if (
|
|
normalizeLabel(item.label) === normalizeLabel(label) &&
|
|
(item.submenu != null) === (submenu != null)
|
|
) {
|
|
return index
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
function normalizeLabel (label) {
|
|
if (label == null) {
|
|
return
|
|
}
|
|
return process.platform === 'darwin' ? label : label.replace(/&/g, '')
|
|
}
|
|
|
|
function cloneMenuItem (item) {
|
|
item = _.pick(
|
|
item,
|
|
'type',
|
|
'label',
|
|
'enabled',
|
|
'visible',
|
|
'command',
|
|
'submenu',
|
|
'commandDetail',
|
|
'role',
|
|
'accelerator',
|
|
'before',
|
|
'after',
|
|
'beforeGroupContaining',
|
|
'afterGroupContaining'
|
|
)
|
|
if (item.submenu != null) {
|
|
item.submenu = item.submenu.map(submenuItem => cloneMenuItem(submenuItem))
|
|
}
|
|
return item
|
|
}
|
|
|
|
// Determine the Electron accelerator for a given Atom keystroke.
|
|
//
|
|
// keystroke - The keystroke.
|
|
//
|
|
// Returns a String containing the keystroke in a format that can be interpreted
|
|
// by Electron to provide nice icons where available.
|
|
function acceleratorForKeystroke (keystroke) {
|
|
if (!keystroke) {
|
|
return null
|
|
}
|
|
let modifiers = keystroke.split(/-(?=.)/)
|
|
const key = modifiers
|
|
.pop()
|
|
.toUpperCase()
|
|
.replace('+', 'Plus')
|
|
|
|
modifiers = modifiers.map(modifier =>
|
|
modifier
|
|
.replace(/shift/gi, 'Shift')
|
|
.replace(/cmd/gi, 'Command')
|
|
.replace(/ctrl/gi, 'Ctrl')
|
|
.replace(/alt/gi, 'Alt')
|
|
)
|
|
|
|
const keys = [...modifiers, key]
|
|
return keys.join('+')
|
|
}
|
|
|
|
module.exports = {
|
|
merge,
|
|
unmerge,
|
|
normalizeLabel,
|
|
cloneMenuItem,
|
|
acceleratorForKeystroke
|
|
}
|