UNPKG

6.58 kBJavaScriptView Raw
1// Copyright (c) Jupyter Development Team.
2// Distributed under the terms of the Modified BSD License.
3import { Signal } from '@lumino/signaling';
4import { h } from '@lumino/virtualdom';
5import { ContextMenu, Menu } from '@lumino/widgets';
6import { LabIconStyle } from '../../style';
7import { classes } from '../../utils';
8import { caretRightIcon, checkIcon } from '../iconimports';
9const submenuIcon = caretRightIcon.bindprops({
10 stylesheet: 'menuItem'
11});
12/**
13 * An object which implements a universal context menu.
14 * Tweaked to use inline svg icons
15 */
16export class ContextMenuSvg extends ContextMenu {
17 /**
18 * Construct a new context menu.
19 *
20 * @param options - The options for initializing the menu.
21 */
22 constructor(options) {
23 super(options);
24 this._isDisposed = false;
25 this._opened = new Signal(this);
26 // override the vanilla .menu
27 this.menu = new MenuSvg(options);
28 }
29 /**
30 * Test whether the context menu is disposed.
31 */
32 get isDisposed() {
33 return this._isDisposed;
34 }
35 /**
36 * A signal fired when the context menu is opened.
37 */
38 get opened() {
39 return this._opened;
40 }
41 /**
42 * Dispose of the resources held by the context menu.
43 */
44 dispose() {
45 if (this._isDisposed) {
46 return;
47 }
48 this._isDisposed = true;
49 this.menu.dispose();
50 Signal.disconnectSender(this);
51 }
52 /**
53 * Open the context menu in response to a `'contextmenu'` event.
54 *
55 * @param event - The `'contextmenu'` event of interest.
56 *
57 * @returns `true` if the menu was opened, or `false` if no items
58 * matched the event and the menu was not opened.
59 *
60 * #### Notes
61 * This method will populate the context menu with items which match
62 * the propagation path of the event, then open the menu at the mouse
63 * position indicated by the event.
64 */
65 open(event) {
66 if (this._isDisposed) {
67 return false;
68 }
69 const hasItems = super.open(event);
70 if (hasItems) {
71 this._opened.emit();
72 }
73 return hasItems;
74 }
75}
76/**
77 * a widget which displays items as a canonical menu.
78 * Tweaked to use inline svg icons
79 */
80export class MenuSvg extends Menu {
81 /**
82 * construct a new menu. Overrides the default renderer
83 *
84 * @param options - The options for initializing the tab bar.
85 */
86 constructor(options) {
87 options.renderer = options.renderer || MenuSvg.defaultRenderer;
88 super(options);
89 }
90 /**
91 * insert a menu item into the menu at the specified index. Replaces the
92 * default renderer for submenus
93 *
94 * @param index - The index at which to insert the item.
95 *
96 * @param options - The options for creating the menu item.
97 *
98 * @returns The menu item added to the menu.
99 *
100 * #### Notes
101 * The index will be clamped to the bounds of the items.
102 */
103 insertItem(index, options) {
104 if (options.submenu) {
105 MenuSvg.overrideDefaultRenderer(options.submenu);
106 }
107 return super.insertItem(index, options);
108 }
109}
110(function (MenuSvg) {
111 function overrideDefaultRenderer(menu) {
112 // override renderer, if needed
113 if (menu.renderer === Menu.defaultRenderer) {
114 // cast away readonly on menu.renderer
115 menu.renderer = MenuSvg.defaultRenderer;
116 }
117 // ensure correct renderer on any submenus that get added in the future
118 const originalInsertItem = menu.insertItem.bind(menu);
119 menu.insertItem = (index, options) => {
120 if (options.submenu) {
121 MenuSvg.overrideDefaultRenderer(options.submenu);
122 }
123 return originalInsertItem(index, options);
124 };
125 // recurse through submenus
126 for (const item of menu._items) {
127 if (item.submenu) {
128 overrideDefaultRenderer(item.submenu);
129 }
130 }
131 }
132 MenuSvg.overrideDefaultRenderer = overrideDefaultRenderer;
133 /**
134 * a modified implementation of the Menu Renderer
135 */
136 class Renderer extends Menu.Renderer {
137 /**
138 * Render the icon element for a menu item.
139 *
140 * @param data - The data to use for rendering the icon.
141 *
142 * @returns A virtual element representing the item icon.
143 */
144 renderIcon(data) {
145 const className = this.createIconClass(data);
146 if (data.item.isToggled) {
147 // check mark icon takes precedence
148 return h.div({ className }, checkIcon, data.item.iconLabel);
149 }
150 /* <DEPRECATED> */
151 if (typeof data.item.icon === 'string') {
152 return h.div({ className: classes(className, 'jp-Icon') }, data.item.iconLabel);
153 }
154 /* </DEPRECATED> */
155 // if data.item.icon is undefined, it will be ignored
156 return h.div({ className }, data.item.icon, data.item.iconLabel);
157 }
158 /**
159 * Create the class name for the menu item icon.
160 *
161 * @param data - The data to use for the class name.
162 *
163 * @returns The full class name for the item icon.
164 */
165 createIconClass(data) {
166 let name = 'lm-Menu-itemIcon';
167 /* <DEPRECATED> */
168 name += ' p-Menu-itemIcon';
169 /* </DEPRECATED> */
170 if (data.item.type === 'separator') {
171 return classes(data.item.iconClass, name);
172 }
173 else {
174 return classes(LabIconStyle.styleClass({ stylesheet: 'menuItem' }), data.item.iconClass, name);
175 }
176 }
177 /**
178 * Render the submenu icon element for a menu item.
179 *
180 * @param data - The data to use for rendering the submenu icon.
181 *
182 * @returns A virtual element representing the submenu icon.
183 */
184 renderSubmenu(data) {
185 const className = 'lm-Menu-itemSubmenuIcon' +
186 /* <DEPRECATED> */
187 ' p-Menu-itemSubmenuIcon';
188 /* </DEPRECATED> */
189 if (data.item.type === 'submenu') {
190 return h.div({ className }, submenuIcon);
191 }
192 else {
193 return h.div({ className });
194 }
195 }
196 }
197 MenuSvg.Renderer = Renderer;
198 MenuSvg.defaultRenderer = new Renderer();
199})(MenuSvg || (MenuSvg = {}));
200//# sourceMappingURL=menusvg.js.map
\No newline at end of file