mirror of
https://github.com/atom/atom.git
synced 2026-01-22 13:28:01 -05:00
Honor item specificity while still preserving addition order
Rather than using order to specify item precedence, we now construct a set of menu items for each element traversing upward from the target. When merging items for a given element, we pass the specificity to the merge function, which uses it to decide whether or not to clobber existing items. When assembling the overall menu, we don’t ever clobber to ensure that items added for elements closer to the target always win over items matching further up the tree.
This commit is contained in:
@@ -68,6 +68,8 @@ describe "ContextMenuManager", ->
|
||||
'.grandchild.foo': [{label: 'A', command: 'b'}]
|
||||
disposable3 = contextMenu.add
|
||||
'.grandchild': [{label: 'A', command: 'c'}]
|
||||
disposable4 = contextMenu.add
|
||||
'.child': [{label: 'A', command: 'd'}]
|
||||
|
||||
expect(contextMenu.templateForElement(grandchild)).toEqual [{label: 'A', command: 'b'}]
|
||||
|
||||
@@ -77,6 +79,9 @@ describe "ContextMenuManager", ->
|
||||
disposable3.dispose()
|
||||
expect(contextMenu.templateForElement(grandchild)).toEqual [{label: 'A', command: 'a'}]
|
||||
|
||||
disposable1.dispose()
|
||||
expect(contextMenu.templateForElement(grandchild)).toEqual [{label: 'A', command: 'd'}]
|
||||
|
||||
it "allows multiple separators", ->
|
||||
contextMenu.add
|
||||
'.grandchild': [
|
||||
|
||||
@@ -10,7 +10,6 @@ Grim = require 'grim'
|
||||
MenuHelpers = require './menu-helpers'
|
||||
|
||||
SpecificityCache = {}
|
||||
SequenceCount = 0
|
||||
|
||||
# Extended: Provides a registry for commands that you'd like to appear in the
|
||||
# context menu.
|
||||
@@ -91,7 +90,7 @@ class ContextMenuManager
|
||||
addedItemSets = []
|
||||
|
||||
for selector, items of itemsBySelector
|
||||
itemSet = new ContextMenuItemSet(selector, items.slice())
|
||||
itemSet = new ContextMenuItemSet(selector, items)
|
||||
addedItemSets.push(itemSet)
|
||||
@itemSets.push(itemSet)
|
||||
|
||||
@@ -107,19 +106,21 @@ class ContextMenuManager
|
||||
currentTarget = event.target
|
||||
|
||||
while currentTarget?
|
||||
currentTargetItems = []
|
||||
matchingItemSets =
|
||||
@itemSets
|
||||
.filter (itemSet) -> currentTarget.webkitMatchesSelector(itemSet.selector)
|
||||
.sort (a, b) -> a.compare(b)
|
||||
@itemSets.filter (itemSet) -> currentTarget.webkitMatchesSelector(itemSet.selector)
|
||||
|
||||
for {items} in matchingItemSets
|
||||
for item in items
|
||||
for itemSet in matchingItemSets
|
||||
for item in itemSet.items
|
||||
continue if item.devMode and not @devMode
|
||||
item = Object.create(item)
|
||||
if typeof item.shouldDisplay is 'function'
|
||||
continue unless item.shouldDisplay(event)
|
||||
item.created?(event)
|
||||
MenuHelpers.merge(template, MenuHelpers.cloneMenuItem(item))
|
||||
MenuHelpers.merge(currentTargetItems, MenuHelpers.cloneMenuItem(item), itemSet.specificity)
|
||||
|
||||
for item in currentTargetItems
|
||||
MenuHelpers.merge(template, item, false)
|
||||
|
||||
currentTarget = currentTarget.parentElement
|
||||
|
||||
@@ -167,9 +168,3 @@ class ContextMenuManager
|
||||
class ContextMenuItemSet
|
||||
constructor: (@selector, @items) ->
|
||||
@specificity = (SpecificityCache[@selector] ?= specificity(@selector))
|
||||
@sequenceNumber = SequenceCount++
|
||||
|
||||
# more specific / recent item sets sort later, because we clobber existing menu items
|
||||
compare: (other) ->
|
||||
@specificity - other.specificity or
|
||||
@sequenceNumber - other.sequenceNumber
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
merge = (menu, item) ->
|
||||
ItemSpecificities = new WeakMap
|
||||
|
||||
merge = (menu, item, itemSpecificity=Infinity) ->
|
||||
ItemSpecificities.set(item, itemSpecificity) if itemSpecificity
|
||||
matchingItemIndex = findMatchingItemIndex(menu, item)
|
||||
matchingItem = menu[matchingItemIndex] unless matchingItemIndex is - 1
|
||||
|
||||
if matchingItem?
|
||||
if item.submenu?
|
||||
merge(matchingItem.submenu, submenuItem) for submenuItem in item.submenu
|
||||
else
|
||||
menu[matchingItemIndex] = item
|
||||
merge(matchingItem.submenu, submenuItem, itemSpecificity) for submenuItem in item.submenu
|
||||
else if itemSpecificity
|
||||
unless itemSpecificity < ItemSpecificities.get(matchingItem)
|
||||
menu[matchingItemIndex] = item
|
||||
else
|
||||
menu.push(item)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user