mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-09-20 07:28:08 +03:00
eb929cb7a2
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.
151 lines
5.3 KiB
CoffeeScript
151 lines
5.3 KiB
CoffeeScript
{$$} = require 'atom'
|
|
|
|
ContextMenuManager = require '../src/context-menu-manager'
|
|
|
|
describe "ContextMenuManager", ->
|
|
[contextMenu, parent, child, grandchild] = []
|
|
|
|
beforeEach ->
|
|
{resourcePath} = atom.getLoadSettings()
|
|
contextMenu = new ContextMenuManager({resourcePath})
|
|
|
|
parent = document.createElement("div")
|
|
child = document.createElement("div")
|
|
grandchild = document.createElement("div")
|
|
parent.classList.add('parent')
|
|
child.classList.add('child')
|
|
grandchild.classList.add('grandchild')
|
|
child.appendChild(grandchild)
|
|
parent.appendChild(child)
|
|
|
|
describe "::add(itemsBySelector)", ->
|
|
it "can add top-level menu items that can be removed with the returned disposable", ->
|
|
disposable = contextMenu.add
|
|
'.parent': [{label: 'A', command: 'a'}]
|
|
'.child': [{label: 'B', command: 'b'}]
|
|
'.grandchild': [{label: 'C', command: 'c'}]
|
|
|
|
expect(contextMenu.templateForElement(grandchild)).toEqual [
|
|
{label: 'C', command: 'c'}
|
|
{label: 'B', command: 'b'}
|
|
{label: 'A', command: 'a'}
|
|
]
|
|
|
|
disposable.dispose()
|
|
expect(contextMenu.templateForElement(grandchild)).toEqual []
|
|
|
|
it "can add submenu items to existing menus that can be removed with the returned disposable", ->
|
|
disposable1 = contextMenu.add
|
|
'.grandchild': [{label: 'A', submenu: [{label: 'B', command: 'b'}]}]
|
|
disposable2 = contextMenu.add
|
|
'.grandchild': [{label: 'A', submenu: [{label: 'C', command: 'c'}]}]
|
|
|
|
expect(contextMenu.templateForElement(grandchild)).toEqual [{
|
|
label: 'A',
|
|
submenu: [
|
|
{label: 'B', command: 'b'}
|
|
{label: 'C', command: 'c'}
|
|
]
|
|
}]
|
|
|
|
disposable2.dispose()
|
|
expect(contextMenu.templateForElement(grandchild)).toEqual [{
|
|
label: 'A',
|
|
submenu: [
|
|
{label: 'B', command: 'b'}
|
|
]
|
|
}]
|
|
|
|
disposable1.dispose()
|
|
expect(contextMenu.templateForElement(grandchild)).toEqual []
|
|
|
|
it "favors the most specific / recently added item in the case of a duplicate label", ->
|
|
grandchild.classList.add('foo')
|
|
|
|
disposable1 = contextMenu.add
|
|
'.grandchild': [{label: 'A', command: 'a'}]
|
|
disposable2 = contextMenu.add
|
|
'.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'}]
|
|
|
|
disposable2.dispose()
|
|
expect(contextMenu.templateForElement(grandchild)).toEqual [{label: 'A', command: 'c'}]
|
|
|
|
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': [
|
|
{label: 'A', command: 'a'},
|
|
{type: 'separator'},
|
|
{label: 'B', command: 'b'},
|
|
{type: 'separator'},
|
|
{label: 'C', command: 'c'}
|
|
]
|
|
|
|
expect(contextMenu.templateForElement(grandchild)).toEqual [
|
|
{label: 'A', command: 'a'},
|
|
{type: 'separator'},
|
|
{label: 'B', command: 'b'},
|
|
{type: 'separator'},
|
|
{label: 'C', command: 'c'}
|
|
]
|
|
|
|
it "excludes items marked for display in devMode unless in dev mode", ->
|
|
disposable1 = contextMenu.add
|
|
'.grandchild': [{label: 'A', command: 'a', devMode: true}, {label: 'B', command: 'b', devMode: false}]
|
|
|
|
expect(contextMenu.templateForElement(grandchild)).toEqual [{label: 'B', command: 'b'}]
|
|
|
|
contextMenu.devMode = true
|
|
expect(contextMenu.templateForElement(grandchild)).toEqual [{label: 'A', command: 'a'}, {label: 'B', command: 'b'}]
|
|
|
|
it "allows items to be associated with `created` hooks which are invoked on template construction with the item and event", ->
|
|
createdEvent = null
|
|
|
|
item = {
|
|
label: 'A',
|
|
command: 'a',
|
|
created: (event) ->
|
|
@command = 'b'
|
|
createdEvent = event
|
|
}
|
|
|
|
contextMenu.add('.grandchild': [item])
|
|
|
|
dispatchedEvent = {target: grandchild}
|
|
expect(contextMenu.templateForEvent(dispatchedEvent)).toEqual [{label: 'A', command: 'b'}]
|
|
expect(item.command).toBe 'a' # doesn't modify original item template
|
|
expect(createdEvent).toBe dispatchedEvent
|
|
|
|
it "allows items to be associated with `shouldDisplay` hooks which are invoked on construction to determine whether the item should be included", ->
|
|
shouldDisplayEvent = null
|
|
shouldDisplay = true
|
|
|
|
item = {
|
|
label: 'A',
|
|
command: 'a',
|
|
shouldDisplay: (event) ->
|
|
@foo = 'bar'
|
|
shouldDisplayEvent = event
|
|
shouldDisplay
|
|
}
|
|
contextMenu.add('.grandchild': [item])
|
|
|
|
dispatchedEvent = {target: grandchild}
|
|
expect(contextMenu.templateForEvent(dispatchedEvent)).toEqual [{label: 'A', command: 'a'}]
|
|
expect(item.foo).toBeUndefined() # doesn't modify original item template
|
|
expect(shouldDisplayEvent).toBe dispatchedEvent
|
|
|
|
shouldDisplay = false
|
|
expect(contextMenu.templateForEvent(dispatchedEvent)).toEqual []
|