1 | // Copyright (c) Jupyter Development Team.
|
2 | // Distributed under the terms of the Modified BSD License.
|
3 | import { Signal } from '@lumino/signaling';
|
4 | import { h } from '@lumino/virtualdom';
|
5 | import { ContextMenu, Menu } from '@lumino/widgets';
|
6 | import { LabIconStyle } from '../../style';
|
7 | import { classes } from '../../utils';
|
8 | import { caretRightIcon, checkIcon } from '../iconimports';
|
9 | const 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 | */
|
16 | export 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 | */
|
80 | export 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 |