From bbeb0b5919a49908107150aec5e8cd15ee6014ef Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 29 Sep 2014 10:34:50 -0600 Subject: [PATCH] Return disposables from MenuManager which can be used to remove menus --- spec/menu-manager-spec.coffee | 37 +++++++++++++++++++++++++++++++++++ src/menu-manager.coffee | 30 ++++++++++++++++++++++++---- 2 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 spec/menu-manager-spec.coffee diff --git a/spec/menu-manager-spec.coffee b/spec/menu-manager-spec.coffee new file mode 100644 index 000000000..a018d3f84 --- /dev/null +++ b/spec/menu-manager-spec.coffee @@ -0,0 +1,37 @@ +describe "MenuManager", -> + describe "::add(items)", -> + it "can add new menus that can be removed with the returned disposable", -> + originalItemCount = atom.menu.template.length + disposable = atom.menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}] + expect(atom.menu.template[originalItemCount]).toEqual {label: "A", submenu: [{label: "B", command: "b"}]} + disposable.dispose() + expect(atom.menu.template.length).toBe originalItemCount + + it "can submenu items to existing menus that can be removed with the returned disposable", -> + originalItemCount = atom.menu.template.length + disposable1 = atom.menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}] + disposable2 = atom.menu.add [{label: "A", submenu: [{label: "C", submenu: [{label: "D", command: 'd'}]}]}] + disposable3 = atom.menu.add [{label: "A", submenu: [{label: "C", submenu: [{label: "E", command: 'e'}]}]}] + + expect(atom.menu.template[originalItemCount]).toEqual { + label: "A", + submenu: [ + {label: "B", command: "b"}, + {label: "C", submenu: [{label: 'D', command: 'd'}, {label: 'E', command: 'e'}]} + ] + } + + disposable3.dispose() + expect(atom.menu.template[originalItemCount]).toEqual { + label: "A", + submenu: [ + {label: "B", command: "b"}, + {label: "C", submenu: [{label: 'D', command: 'd'}]} + ] + } + + disposable2.dispose() + expect(atom.menu.template[originalItemCount]).toEqual {label: "A", submenu: [{label: "B", command: "b"}]} + + disposable1.dispose() + expect(atom.menu.template.length).toBe originalItemCount diff --git a/src/menu-manager.coffee b/src/menu-manager.coffee index 89462ec7a..f03b4ce73 100644 --- a/src/menu-manager.coffee +++ b/src/menu-manager.coffee @@ -4,6 +4,7 @@ _ = require 'underscore-plus' ipc = require 'ipc' CSON = require 'season' fs = require 'fs-plus' +{Disposable} = require 'event-kit' # Extended: Provides a registry for menu items that you'd like to appear in the # application menu. @@ -37,7 +38,11 @@ class MenuManager add: (items) -> @merge(@template, item) for item in items @update() - undefined + new Disposable => @remove(items) + + remove: (items) -> + @unmerge(@template, item) for item in items + @update() # Should the binding for the given selector be included in the menu # commands. @@ -96,11 +101,28 @@ class MenuManager # appended to the bottom of existing menus where possible. merge: (menu, item) -> item = _.deepClone(item) + matchingItem = @findMatchingItem(menu, item) - if item.submenu? and match = _.find(menu, ({label, submenu}) => submenu? and label and @normalizeLabel(label) is @normalizeLabel(item.label)) - @merge(match.submenu, i) for i in item.submenu + if matchingItem? and item.submenu? + @merge(matchingItem.submenu, submenuItem) for submenuItem in item.submenu else - menu.push(item) unless _.find(menu, ({label}) => label and @normalizeLabel(label) is @normalizeLabel(item.label)) + menu.push(item) + + unmerge: (menu, item) -> + if matchingItem = @findMatchingItem(menu, item) + if item.submenu? + @unmerge(matchingItem.submenu, submenuItem) for submenuItem in item.submenu + + unless matchingItem.submenu?.length > 0 + menu.splice(menu.indexOf(matchingItem), 1) + + # find an existing menu item matching the given item + findMatchingItem: (menu, {label, submenu}) -> + debugger unless menu? + for item in menu + if @normalizeLabel(item.label) is @normalizeLabel(label) and item.submenu? is submenu? + return item + null # OSX can't handle displaying accelerators for multiple keystrokes. # If they are sent across, it will stop processing accelerators for the rest