UNPKG

8.34 kBJavaScriptView Raw
1// Copyright (c) Jupyter Development Team.
2// Distributed under the terms of the Modified BSD License.
3/* global WeakRef */
4import { ArrayExt } from '@lumino/algorithm';
5import { DisposableDelegate } from '@lumino/disposable';
6import { Signal } from '@lumino/signaling';
7import { Menu } from '@lumino/widgets';
8/**
9 * Namespace for JupyterLabMenu interfaces
10 */
11export var IRankedMenu;
12(function (IRankedMenu) {
13 /**
14 * Default menu item rank
15 */
16 IRankedMenu.DEFAULT_RANK = 100;
17})(IRankedMenu || (IRankedMenu = {}));
18/**
19 * An extensible menu for JupyterLab application menus.
20 */
21export class RankedMenu extends Menu {
22 /**
23 * Construct a new menu.
24 *
25 * @param options - Options for the lumino menu.
26 */
27 constructor(options) {
28 var _a;
29 super(options);
30 this._ranks = [];
31 this._rank = options.rank;
32 this._includeSeparators = (_a = options.includeSeparators) !== null && _a !== void 0 ? _a : true;
33 }
34 /**
35 * Menu rank.
36 */
37 get rank() {
38 return this._rank;
39 }
40 /**
41 * Add a group of menu items specific to a particular
42 * plugin.
43 *
44 * The rank can be set for all items in the group using the
45 * function argument or per item.
46 *
47 * @param items - the list of menu items to add.
48 * @param rank - the default rank in the menu in which to insert the group.
49 * @returns Disposable of the group
50 */
51 addGroup(items, rank) {
52 if (items.length === 0) {
53 return new DisposableDelegate(() => void 0);
54 }
55 const defaultRank = rank !== null && rank !== void 0 ? rank : IRankedMenu.DEFAULT_RANK;
56 const sortedItems = items
57 .map(item => {
58 var _a;
59 return { ...item, rank: (_a = item.rank) !== null && _a !== void 0 ? _a : defaultRank };
60 })
61 .sort((a, b) => a.rank - b.rank);
62 // Insert the plugin group into the menu.
63 let insertIndex = this._ranks.findIndex(rank => sortedItems[0].rank < rank);
64 if (insertIndex < 0) {
65 insertIndex = this._ranks.length; // Insert at the end of the menu
66 }
67 // Keep an array of the menu items that have been created.
68 const added = [];
69 // Insert a separator before the group.
70 // Lumino takes care of superfluous leading,
71 // trailing, and duplicate separators.
72 if (this._includeSeparators) {
73 added.push(this.insertItem(insertIndex++, { type: 'separator', rank: defaultRank }));
74 }
75 // Insert the group.
76 added.push(...sortedItems.map(item => {
77 return this.insertItem(insertIndex++, item);
78 }));
79 // Insert a separator after the group.
80 if (this._includeSeparators) {
81 added.push(this.insertItem(insertIndex++, { type: 'separator', rank: defaultRank }));
82 }
83 return new DisposableDelegate(() => {
84 added.forEach(i => i.dispose());
85 });
86 }
87 /**
88 * Add a menu item to the end of the menu.
89 *
90 * @param options - The options for creating the menu item.
91 *
92 * @returns The menu item added to the menu.
93 */
94 addItem(options) {
95 let insertIndex = -1;
96 if (options.rank) {
97 insertIndex = this._ranks.findIndex(rank => options.rank < rank);
98 }
99 if (insertIndex < 0) {
100 insertIndex = this._ranks.length; // Insert at the end of the menu
101 }
102 return this.insertItem(insertIndex, options);
103 }
104 /**
105 * Remove all menu items from the menu.
106 */
107 clearItems() {
108 this._ranks.length = 0;
109 super.clearItems();
110 }
111 /**
112 * Dispose of the resources held by the menu.
113 */
114 dispose() {
115 this._ranks.length = 0;
116 super.dispose();
117 }
118 /**
119 * Get the rank of the item at index.
120 *
121 * @param index Item index.
122 * @returns Rank of the item.
123 */
124 getRankAt(index) {
125 return this._ranks[index];
126 }
127 /**
128 * Insert a menu item into the menu at the specified index.
129 *
130 * @param index - The index at which to insert the item.
131 *
132 * @param options - The options for creating the menu item.
133 *
134 * @returns The menu item added to the menu.
135 *
136 * #### Notes
137 * The index will be clamped to the bounds of the items.
138 */
139 insertItem(index, options) {
140 var _a, _b;
141 const clampedIndex = Math.max(0, Math.min(index, this._ranks.length));
142 ArrayExt.insert(this._ranks, clampedIndex, (_a = options.rank) !== null && _a !== void 0 ? _a : Math.max(IRankedMenu.DEFAULT_RANK, (_b = this._ranks[this._ranks.length - 1]) !== null && _b !== void 0 ? _b : IRankedMenu.DEFAULT_RANK));
143 const item = super.insertItem(clampedIndex, options);
144 return new DisposableMenuItem(item, this);
145 }
146 /**
147 * Remove the item at a given index from the menu.
148 *
149 * @param index - The index of the item to remove.
150 *
151 * #### Notes
152 * This is a no-op if the index is out of range.
153 */
154 removeItemAt(index) {
155 ArrayExt.removeAt(this._ranks, index);
156 super.removeItemAt(index);
157 }
158}
159/**
160 * Disposable Menu Item
161 */
162class DisposableMenuItem {
163 /**
164 * Create a disposable menu item from an item and the menu it belongs to
165 *
166 * @param item Menu item
167 * @param menu Menu
168 */
169 constructor(item, menu) {
170 this._item = new WeakRef(item);
171 this._menu = menu;
172 // dispose this item if the parent menu is disposed
173 const dispose = (menu) => {
174 menu.disposed.disconnect(dispose, this);
175 this.dispose();
176 };
177 this._menu.disposed.connect(dispose, this);
178 }
179 /**
180 * Whether the menu item is disposed or not.
181 */
182 get isDisposed() {
183 return this._isDisposed;
184 }
185 /**
186 * The type of the menu item.
187 */
188 get type() {
189 return this._item.deref().type;
190 }
191 /**
192 * The command to execute when the item is triggered.
193 */
194 get command() {
195 return this._item.deref().command;
196 }
197 /**
198 * The arguments for the command.
199 */
200 get args() {
201 return this._item.deref().args;
202 }
203 /**
204 * The submenu for a `'submenu'` type item.
205 */
206 get submenu() {
207 return this._item.deref().submenu;
208 }
209 /**
210 * The display label for the menu item.
211 */
212 get label() {
213 return this._item.deref().label;
214 }
215 /**
216 * The mnemonic index for the menu item.
217 */
218 get mnemonic() {
219 return this._item.deref().mnemonic;
220 }
221 /**
222 * The icon renderer for the menu item.
223 */
224 get icon() {
225 return this._item.deref().icon;
226 }
227 /**
228 * The icon class for the menu item.
229 */
230 get iconClass() {
231 return this._item.deref().iconClass;
232 }
233 /**
234 * The icon label for the menu item.
235 */
236 get iconLabel() {
237 return this._item.deref().iconLabel;
238 }
239 /**
240 * The display caption for the menu item.
241 */
242 get caption() {
243 return this._item.deref().caption;
244 }
245 /**
246 * The extra class name for the menu item.
247 */
248 get className() {
249 return this._item.deref().className;
250 }
251 /**
252 * The dataset for the menu item.
253 */
254 get dataset() {
255 return this._item.deref().dataset;
256 }
257 /**
258 * Whether the menu item is enabled.
259 */
260 get isEnabled() {
261 return this._item.deref().isEnabled;
262 }
263 /**
264 * Whether the menu item is toggled.
265 */
266 get isToggled() {
267 return this._item.deref().isToggled;
268 }
269 /**
270 * Whether the menu item is visible.
271 */
272 get isVisible() {
273 return this._item.deref().isVisible;
274 }
275 /**
276 * The key binding for the menu item.
277 */
278 get keyBinding() {
279 return this._item.deref().keyBinding;
280 }
281 /**
282 * Dispose the menu item by removing it from its menu.
283 */
284 dispose() {
285 if (this._isDisposed) {
286 return;
287 }
288 this._isDisposed = true;
289 const item = this._item.deref();
290 if (item && !this._menu.isDisposed) {
291 this._menu.removeItem(item);
292 }
293 Signal.clearData(this);
294 }
295}
296//# sourceMappingURL=menu.js.map
\No newline at end of file