1 |
|
2 |
|
3 | import { Button } from '@jupyter/react-components';
|
4 | import { addJupyterLabThemeChangeListener, jpButton, jpToolbar, provideJupyterDesignSystem } from '@jupyter/web-components';
|
5 | import { nullTranslator } from '@jupyterlab/translation';
|
6 | import { find, map, some } from '@lumino/algorithm';
|
7 | import { CommandRegistry } from '@lumino/commands';
|
8 | import { MessageLoop } from '@lumino/messaging';
|
9 | import { AttachedProperty } from '@lumino/properties';
|
10 | import { PanelLayout, Widget } from '@lumino/widgets';
|
11 | import { Throttler } from '@lumino/polling';
|
12 | import * as React from 'react';
|
13 | import { ellipsesIcon, LabIcon } from '../icon';
|
14 | import { classes } from '../utils';
|
15 | import { ReactWidget, UseSignal } from './vdom';
|
16 | provideJupyterDesignSystem().register([jpButton(), jpToolbar()]);
|
17 | addJupyterLabThemeChangeListener();
|
18 |
|
19 |
|
20 |
|
21 | const TOOLBAR_CLASS = 'jp-Toolbar';
|
22 |
|
23 |
|
24 |
|
25 | const TOOLBAR_ITEM_CLASS = 'jp-Toolbar-item';
|
26 |
|
27 |
|
28 |
|
29 | const TOOLBAR_OPENER_NAME = 'toolbar-popup-opener';
|
30 |
|
31 |
|
32 |
|
33 | const TOOLBAR_SPACER_CLASS = 'jp-Toolbar-spacer';
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 | class ToolbarLayout extends PanelLayout {
|
43 | constructor() {
|
44 | super(...arguments);
|
45 | this._dirty = false;
|
46 | }
|
47 | |
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 | onFitRequest(msg) {
|
54 | super.onFitRequest(msg);
|
55 | if (this.parent.isAttached) {
|
56 |
|
57 |
|
58 | if (some(this.widgets, w => !w.isHidden)) {
|
59 | this.parent.node.style.minHeight = 'var(--jp-private-toolbar-height)';
|
60 | this.parent.removeClass('jp-Toolbar-micro');
|
61 | }
|
62 | else {
|
63 | this.parent.node.style.minHeight = '';
|
64 | this.parent.addClass('jp-Toolbar-micro');
|
65 | }
|
66 | }
|
67 |
|
68 | this._dirty = true;
|
69 |
|
70 |
|
71 | if (this.parent.parent) {
|
72 | MessageLoop.sendMessage(this.parent.parent, Widget.Msg.FitRequest);
|
73 | }
|
74 |
|
75 |
|
76 | if (this._dirty) {
|
77 | MessageLoop.sendMessage(this.parent, Widget.Msg.UpdateRequest);
|
78 | }
|
79 | }
|
80 | |
81 |
|
82 |
|
83 | onUpdateRequest(msg) {
|
84 | super.onUpdateRequest(msg);
|
85 | if (this.parent.isVisible) {
|
86 | this._dirty = false;
|
87 | }
|
88 | }
|
89 | |
90 |
|
91 |
|
92 | onChildShown(msg) {
|
93 | super.onChildShown(msg);
|
94 |
|
95 | this.parent.fit();
|
96 | }
|
97 | |
98 |
|
99 |
|
100 | onChildHidden(msg) {
|
101 | super.onChildHidden(msg);
|
102 |
|
103 | this.parent.fit();
|
104 | }
|
105 | |
106 |
|
107 |
|
108 | onBeforeAttach(msg) {
|
109 | super.onBeforeAttach(msg);
|
110 |
|
111 | this.parent.fit();
|
112 | }
|
113 | |
114 |
|
115 |
|
116 |
|
117 |
|
118 |
|
119 |
|
120 |
|
121 |
|
122 |
|
123 | attachWidget(index, widget) {
|
124 | super.attachWidget(index, widget);
|
125 |
|
126 | this.parent.fit();
|
127 | }
|
128 | |
129 |
|
130 |
|
131 |
|
132 |
|
133 |
|
134 |
|
135 |
|
136 |
|
137 |
|
138 | detachWidget(index, widget) {
|
139 | super.detachWidget(index, widget);
|
140 |
|
141 | this.parent.fit();
|
142 | }
|
143 | }
|
144 |
|
145 |
|
146 |
|
147 | export class Toolbar extends Widget {
|
148 | |
149 |
|
150 |
|
151 | constructor(options = {}) {
|
152 | var _a;
|
153 | super({ node: document.createElement('jp-toolbar') });
|
154 | this.addClass(TOOLBAR_CLASS);
|
155 | this.layout = (_a = options.layout) !== null && _a !== void 0 ? _a : new ToolbarLayout();
|
156 | }
|
157 | |
158 |
|
159 |
|
160 |
|
161 |
|
162 | names() {
|
163 | const layout = this.layout;
|
164 | return map(layout.widgets, widget => {
|
165 | return Private.nameProperty.get(widget);
|
166 | });
|
167 | }
|
168 | |
169 |
|
170 |
|
171 |
|
172 |
|
173 |
|
174 |
|
175 |
|
176 |
|
177 |
|
178 |
|
179 |
|
180 |
|
181 |
|
182 |
|
183 | addItem(name, widget) {
|
184 | const layout = this.layout;
|
185 | return this.insertItem(layout.widgets.length, name, widget);
|
186 | }
|
187 | |
188 |
|
189 |
|
190 |
|
191 |
|
192 |
|
193 |
|
194 |
|
195 |
|
196 |
|
197 |
|
198 |
|
199 |
|
200 |
|
201 |
|
202 |
|
203 | insertItem(index, name, widget) {
|
204 | const existing = find(this.names(), value => value === name);
|
205 | if (existing) {
|
206 | return false;
|
207 | }
|
208 | widget.addClass(TOOLBAR_ITEM_CLASS);
|
209 | const layout = this.layout;
|
210 | const j = Math.max(0, Math.min(index, layout.widgets.length));
|
211 | layout.insertWidget(j, widget);
|
212 | Private.nameProperty.set(widget, name);
|
213 | return true;
|
214 | }
|
215 | |
216 |
|
217 |
|
218 |
|
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 |
|
225 |
|
226 |
|
227 |
|
228 |
|
229 |
|
230 |
|
231 | insertAfter(at, name, widget) {
|
232 | return this.insertRelative(at, 1, name, widget);
|
233 | }
|
234 | |
235 |
|
236 |
|
237 |
|
238 |
|
239 |
|
240 |
|
241 |
|
242 |
|
243 |
|
244 |
|
245 |
|
246 |
|
247 |
|
248 |
|
249 |
|
250 | insertBefore(at, name, widget) {
|
251 | return this.insertRelative(at, 0, name, widget);
|
252 | }
|
253 | |
254 |
|
255 |
|
256 | insertRelative(at, offset, name, widget) {
|
257 | const nameWithIndex = map(this.names(), (name, i) => {
|
258 | return { name: name, index: i };
|
259 | });
|
260 | const target = find(nameWithIndex, x => x.name === at);
|
261 | if (target) {
|
262 | return this.insertItem(target.index + offset, name, widget);
|
263 | }
|
264 | return false;
|
265 | }
|
266 | |
267 |
|
268 |
|
269 |
|
270 |
|
271 |
|
272 |
|
273 |
|
274 |
|
275 |
|
276 | handleEvent(event) {
|
277 | switch (event.type) {
|
278 | case 'click':
|
279 | this.handleClick(event);
|
280 | break;
|
281 | default:
|
282 | break;
|
283 | }
|
284 | }
|
285 | |
286 |
|
287 |
|
288 | handleClick(event) {
|
289 |
|
290 | event.stopPropagation();
|
291 |
|
292 |
|
293 | if (event.target instanceof HTMLLabelElement) {
|
294 | const forId = event.target.getAttribute('for');
|
295 | if (forId && this.node.querySelector(`#${forId}`)) {
|
296 | return;
|
297 | }
|
298 | }
|
299 |
|
300 | if (this.node.contains(document.activeElement)) {
|
301 | return;
|
302 | }
|
303 |
|
304 | if (this.parent) {
|
305 | this.parent.activate();
|
306 | }
|
307 | }
|
308 | |
309 |
|
310 |
|
311 | onAfterAttach(msg) {
|
312 | this.node.addEventListener('click', this);
|
313 | }
|
314 | |
315 |
|
316 |
|
317 | onBeforeDetach(msg) {
|
318 | this.node.removeEventListener('click', this);
|
319 | }
|
320 | }
|
321 |
|
322 |
|
323 |
|
324 | export class ReactiveToolbar extends Toolbar {
|
325 | |
326 |
|
327 |
|
328 | constructor() {
|
329 | super();
|
330 | this.popupOpener = new ToolbarPopupOpener();
|
331 | this._widgetWidths = new Map();
|
332 | this._widgetPositions = new Map();
|
333 | this._zoomChanged = true;
|
334 | this.insertItem(0, TOOLBAR_OPENER_NAME, this.popupOpener);
|
335 | this.popupOpener.hide();
|
336 | this._resizer = new Throttler(async (callTwice = false) => {
|
337 | await this._onResize(callTwice);
|
338 | }, 500);
|
339 | }
|
340 | |
341 |
|
342 |
|
343 | dispose() {
|
344 | if (this.isDisposed) {
|
345 | return;
|
346 | }
|
347 | if (this._resizer) {
|
348 | this._resizer.dispose();
|
349 | }
|
350 | super.dispose();
|
351 | }
|
352 | |
353 |
|
354 |
|
355 |
|
356 |
|
357 |
|
358 |
|
359 |
|
360 |
|
361 |
|
362 |
|
363 |
|
364 |
|
365 |
|
366 |
|
367 |
|
368 |
|
369 | insertAfter(at, name, widget) {
|
370 | if (at === TOOLBAR_OPENER_NAME) {
|
371 | return false;
|
372 | }
|
373 | return super.insertAfter(at, name, widget);
|
374 | }
|
375 | |
376 |
|
377 |
|
378 | insertRelative(at, offset, name, widget) {
|
379 | const targetPosition = this._widgetPositions.get(at);
|
380 | const position = (targetPosition !== null && targetPosition !== void 0 ? targetPosition : 0) + offset;
|
381 | return this.insertItem(position, name, widget);
|
382 | }
|
383 | |
384 |
|
385 |
|
386 |
|
387 |
|
388 |
|
389 |
|
390 |
|
391 |
|
392 |
|
393 |
|
394 |
|
395 |
|
396 |
|
397 |
|
398 |
|
399 | insertItem(index, name, widget) {
|
400 | var _a;
|
401 | let status;
|
402 | if (widget instanceof ToolbarPopupOpener) {
|
403 | status = super.insertItem(index, name, widget);
|
404 | }
|
405 | else {
|
406 | const j = Math.max(0, Math.min(index, this.layout.widgets.length - 1));
|
407 | status = super.insertItem(j, name, widget);
|
408 | }
|
409 |
|
410 | if (name !== TOOLBAR_OPENER_NAME &&
|
411 | this._widgetPositions.get(name) !== index) {
|
412 |
|
413 | const currentPosition = (_a = this._widgetPositions.get(name)) !== null && _a !== void 0 ? _a : this._widgetPositions.size;
|
414 |
|
415 | this._widgetPositions.forEach((value, key) => {
|
416 | if (key !== TOOLBAR_OPENER_NAME) {
|
417 | if (value >= index && value < currentPosition) {
|
418 | this._widgetPositions.set(key, value + 1);
|
419 | }
|
420 | else if (value <= index && value > currentPosition) {
|
421 | this._widgetPositions.set(key, value - 1);
|
422 | }
|
423 | }
|
424 | });
|
425 |
|
426 | this._widgetPositions.set(name, index);
|
427 |
|
428 |
|
429 | if (this.isVisible) {
|
430 | void this._resizer.invoke();
|
431 | }
|
432 | }
|
433 | return status;
|
434 | }
|
435 | |
436 |
|
437 |
|
438 |
|
439 |
|
440 | onAfterShow(msg) {
|
441 | void this._resizer.invoke(true);
|
442 | }
|
443 | |
444 |
|
445 |
|
446 |
|
447 |
|
448 | onBeforeHide(msg) {
|
449 | this.popupOpener.hidePopup();
|
450 | super.onBeforeHide(msg);
|
451 | }
|
452 | onResize(msg) {
|
453 | super.onResize(msg);
|
454 |
|
455 | const zoom = Math.round((window.outerWidth / window.innerWidth) * 100);
|
456 | if (zoom !== this._zoom) {
|
457 | this._zoomChanged = true;
|
458 | this._zoom = zoom;
|
459 | }
|
460 | if (msg.width > 0 && this._resizer) {
|
461 | void this._resizer.invoke();
|
462 | }
|
463 | }
|
464 | |
465 |
|
466 |
|
467 |
|
468 |
|
469 |
|
470 |
|
471 |
|
472 |
|
473 |
|
474 |
|
475 |
|
476 | async _onResize(callTwice = false) {
|
477 | if (!(this.parent && this.parent.isAttached)) {
|
478 | return;
|
479 | }
|
480 | const toolbarWidth = this.node.clientWidth;
|
481 | const opener = this.popupOpener;
|
482 | const openerWidth = 32;
|
483 |
|
484 | const toolbarPadding = 2 + 5;
|
485 | let width = opener.isHidden ? toolbarPadding : toolbarPadding + openerWidth;
|
486 | this._getWidgetsToRemove(width, toolbarWidth, openerWidth)
|
487 | .then(values => {
|
488 | var _a, _b;
|
489 | let { width, widgetsToRemove } = values;
|
490 | while (widgetsToRemove.length > 0) {
|
491 |
|
492 |
|
493 |
|
494 | const widget = widgetsToRemove.pop();
|
495 | const name = Private.nameProperty.get(widget);
|
496 | width -= this._widgetWidths.get(name) || 0;
|
497 | const position = (_a = this._widgetPositions.get(name)) !== null && _a !== void 0 ? _a : 0;
|
498 |
|
499 |
|
500 | let openerFirstIndex = this._widgetPositions.size;
|
501 | const openerFirst = opener.widgetAt(0);
|
502 | if (openerFirst) {
|
503 | const openerFirstName = Private.nameProperty.get(openerFirst);
|
504 | openerFirstIndex =
|
505 | (_b = this._widgetPositions.get(openerFirstName)) !== null && _b !== void 0 ? _b : openerFirstIndex;
|
506 | }
|
507 |
|
508 | const index = position - openerFirstIndex;
|
509 | opener.insertWidget(index, widget);
|
510 | }
|
511 | if (opener.widgetCount() > 0) {
|
512 | const widgetsToAdd = [];
|
513 | let index = 0;
|
514 | const widgetCount = opener.widgetCount();
|
515 | while (index < widgetCount) {
|
516 | let widget = opener.widgetAt(index);
|
517 | if (widget) {
|
518 | width += this._getWidgetWidth(widget);
|
519 | if (widgetCount - widgetsToAdd.length === 1) {
|
520 | width -= openerWidth;
|
521 | }
|
522 | }
|
523 | else {
|
524 | break;
|
525 | }
|
526 | if (width < toolbarWidth) {
|
527 | widgetsToAdd.push(widget);
|
528 | }
|
529 | else {
|
530 | break;
|
531 | }
|
532 | index++;
|
533 | }
|
534 | while (widgetsToAdd.length > 0) {
|
535 |
|
536 | const widget = widgetsToAdd.shift();
|
537 | const name = Private.nameProperty.get(widget);
|
538 | if (this._widgetPositions.has(name)) {
|
539 | this.insertItem(this._widgetPositions.get(name), name, widget);
|
540 | }
|
541 | else {
|
542 | this.addItem(name, widget);
|
543 | }
|
544 | }
|
545 | }
|
546 | if (opener.widgetCount() > 0) {
|
547 | opener.updatePopup();
|
548 | opener.show();
|
549 | }
|
550 | else {
|
551 | opener.hide();
|
552 | }
|
553 | if (callTwice) {
|
554 | void this._onResize();
|
555 | }
|
556 | })
|
557 | .catch(msg => {
|
558 | console.error('Error while computing the ReactiveToolbar', msg);
|
559 | });
|
560 | }
|
561 | async _getWidgetsToRemove(width, toolbarWidth, openerWidth) {
|
562 | var _a;
|
563 | const opener = this.popupOpener;
|
564 | const layout = this.layout;
|
565 | const toIndex = layout.widgets.length - 1;
|
566 | const widgetsToRemove = [];
|
567 | let index = 0;
|
568 | while (index < toIndex) {
|
569 | const widget = layout.widgets[index];
|
570 | const name = Private.nameProperty.get(widget);
|
571 |
|
572 |
|
573 |
|
574 | let widgetWidth;
|
575 | if (this._zoomChanged) {
|
576 | widgetWidth = await this._saveWidgetWidth(name, widget);
|
577 | }
|
578 | else {
|
579 |
|
580 |
|
581 | widgetWidth =
|
582 | this._getWidgetWidth(widget) ||
|
583 | (await this._saveWidgetWidth(name, widget));
|
584 | }
|
585 | width += widgetWidth;
|
586 | if (widgetsToRemove.length === 0 &&
|
587 | opener.isHidden &&
|
588 | width + openerWidth > toolbarWidth) {
|
589 | width += openerWidth;
|
590 | }
|
591 |
|
592 |
|
593 |
|
594 |
|
595 | if (width > toolbarWidth ||
|
596 | ((_a = this._widgetPositions.get(name)) !== null && _a !== void 0 ? _a : 0) > index) {
|
597 | widgetsToRemove.push(widget);
|
598 | }
|
599 | index++;
|
600 | }
|
601 | this._zoomChanged = false;
|
602 | return {
|
603 | width: width,
|
604 | widgetsToRemove: widgetsToRemove
|
605 | };
|
606 | }
|
607 | async _saveWidgetWidth(name, widget) {
|
608 | if (widget instanceof ReactWidget) {
|
609 | await widget.renderPromise;
|
610 | }
|
611 | const widgetWidth = widget.hasClass(TOOLBAR_SPACER_CLASS)
|
612 | ? 2
|
613 | : widget.node.clientWidth;
|
614 | this._widgetWidths.set(name, widgetWidth);
|
615 | return widgetWidth;
|
616 | }
|
617 | _getWidgetWidth(widget) {
|
618 | const widgetName = Private.nameProperty.get(widget);
|
619 | return this._widgetWidths.get(widgetName) || 0;
|
620 | }
|
621 | }
|
622 |
|
623 |
|
624 |
|
625 | (function (Toolbar) {
|
626 | |
627 |
|
628 |
|
629 |
|
630 |
|
631 |
|
632 |
|
633 | function createSpacerItem() {
|
634 | return new Private.Spacer();
|
635 | }
|
636 | Toolbar.createSpacerItem = createSpacerItem;
|
637 | })(Toolbar || (Toolbar = {}));
|
638 |
|
639 |
|
640 |
|
641 |
|
642 |
|
643 | export function ToolbarButtonComponent(props) {
|
644 | var _a, _b;
|
645 | const actualOnClick = (_a = props.actualOnClick) !== null && _a !== void 0 ? _a : false;
|
646 |
|
647 |
|
648 |
|
649 |
|
650 | const handleMouseDown = actualOnClick
|
651 | ? undefined
|
652 | : (event) => {
|
653 | var _a;
|
654 |
|
655 | if (event.button === 0) {
|
656 | event.preventDefault();
|
657 | (_a = props.onClick) === null || _a === void 0 ? void 0 : _a.call(props);
|
658 | }
|
659 | };
|
660 | const handleClick = actualOnClick
|
661 | ? (event) => {
|
662 | var _a;
|
663 | if (event.button === 0) {
|
664 | (_a = props.onClick) === null || _a === void 0 ? void 0 : _a.call(props);
|
665 | }
|
666 | }
|
667 | : undefined;
|
668 | const handleKeyDown = (event) => {
|
669 | var _a;
|
670 | const { key } = event;
|
671 | if (key === 'Enter' || key === ' ') {
|
672 | (_a = props.onClick) === null || _a === void 0 ? void 0 : _a.call(props);
|
673 | }
|
674 | };
|
675 | const getTooltip = () => {
|
676 | if (props.enabled === false && props.disabledTooltip) {
|
677 | return props.disabledTooltip;
|
678 | }
|
679 | else if (props.pressed && props.pressedTooltip) {
|
680 | return props.pressedTooltip;
|
681 | }
|
682 | else {
|
683 | return props.tooltip || props.iconLabel;
|
684 | }
|
685 | };
|
686 | return (React.createElement(Button, { appearance: "stealth", className: props.className
|
687 | ? props.className + ' jp-ToolbarButtonComponent'
|
688 | : 'jp-ToolbarButtonComponent', "aria-pressed": props.pressed, "aria-disabled": props.enabled === false, ...props.dataset, disabled: props.enabled === false, onClick: handleClick, onMouseDown: handleMouseDown, onKeyDown: handleKeyDown, title: getTooltip(), minimal: true },
|
689 | (props.icon || props.iconClass) && (React.createElement(LabIcon.resolveReact, { icon: props.pressed ? (_b = props.pressedIcon) !== null && _b !== void 0 ? _b : props.icon : props.icon, iconClass:
|
690 |
|
691 | classes(props.iconClass, 'jp-Icon'), tag: null })),
|
692 | props.label && (React.createElement("span", { className: "jp-ToolbarButtonComponent-label" }, props.label))));
|
693 | }
|
694 |
|
695 |
|
696 |
|
697 |
|
698 | export function addToolbarButtonClass(w) {
|
699 | w.addClass('jp-ToolbarButton');
|
700 | return w;
|
701 | }
|
702 |
|
703 |
|
704 |
|
705 | export class ToolbarButton extends ReactWidget {
|
706 | |
707 |
|
708 |
|
709 |
|
710 | constructor(props = {}) {
|
711 | var _a, _b;
|
712 | super();
|
713 | this.props = props;
|
714 | addToolbarButtonClass(this);
|
715 | this._enabled = (_a = props.enabled) !== null && _a !== void 0 ? _a : true;
|
716 | this._pressed = this._enabled && ((_b = props.pressed) !== null && _b !== void 0 ? _b : false);
|
717 | this._onClick = props.onClick;
|
718 | }
|
719 | |
720 |
|
721 |
|
722 |
|
723 | set pressed(value) {
|
724 | if (this.enabled && value !== this._pressed) {
|
725 | this._pressed = value;
|
726 | this.update();
|
727 | }
|
728 | }
|
729 | |
730 |
|
731 |
|
732 | get pressed() {
|
733 | return this._pressed;
|
734 | }
|
735 | |
736 |
|
737 |
|
738 |
|
739 | set enabled(value) {
|
740 | if (value != this._enabled) {
|
741 | this._enabled = value;
|
742 | if (!this._enabled) {
|
743 | this._pressed = false;
|
744 | }
|
745 | this.update();
|
746 | }
|
747 | }
|
748 | |
749 |
|
750 |
|
751 | get enabled() {
|
752 | return this._enabled;
|
753 | }
|
754 | |
755 |
|
756 |
|
757 |
|
758 | set onClick(value) {
|
759 | if (value !== this._onClick) {
|
760 | this._onClick = value;
|
761 | this.update();
|
762 | }
|
763 | }
|
764 | |
765 |
|
766 |
|
767 | get onClick() {
|
768 | return this._onClick;
|
769 | }
|
770 | render() {
|
771 | return (React.createElement(ToolbarButtonComponent, { ...this.props, pressed: this.pressed, enabled: this.enabled, onClick: this.onClick }));
|
772 | }
|
773 | }
|
774 |
|
775 |
|
776 |
|
777 |
|
778 |
|
779 |
|
780 | export function CommandToolbarButtonComponent(props) {
|
781 | return (React.createElement(UseSignal, { signal: props.commands.commandChanged, shouldUpdate: (sender, args) => (args.id === props.id && args.type === 'changed') ||
|
782 | args.type === 'many-changed' }, () => props.commands.listCommands().includes(props.id) ? (React.createElement(ToolbarButtonComponent, { ...Private.propsFromCommand(props) })) : null));
|
783 | }
|
784 |
|
785 |
|
786 |
|
787 |
|
788 | export function addCommandToolbarButtonClass(w) {
|
789 | w.addClass('jp-CommandToolbarButton');
|
790 | return w;
|
791 | }
|
792 |
|
793 |
|
794 |
|
795 | export class CommandToolbarButton extends ReactWidget {
|
796 | |
797 |
|
798 |
|
799 |
|
800 | constructor(props) {
|
801 | super();
|
802 | this.props = props;
|
803 | const { commands, id, args } = props;
|
804 | addCommandToolbarButtonClass(this);
|
805 | this.setCommandAttributes(commands, id, args);
|
806 | commands.commandChanged.connect((_, change) => {
|
807 | if (change.id === props.id) {
|
808 | this.setCommandAttributes(commands, id, args);
|
809 | }
|
810 | }, this);
|
811 | }
|
812 | setCommandAttributes(commands, id, args) {
|
813 | if (commands.isToggled(id, args)) {
|
814 | this.addClass('lm-mod-toggled');
|
815 | }
|
816 | else {
|
817 | this.removeClass('lm-mod-toggled');
|
818 | }
|
819 | if (commands.isVisible(id, args)) {
|
820 | this.removeClass('lm-mod-hidden');
|
821 | }
|
822 | else {
|
823 | this.addClass('lm-mod-hidden');
|
824 | }
|
825 | if (commands.isEnabled(id, args)) {
|
826 | if ('disabled' in this.node) {
|
827 | this.node.disabled = false;
|
828 | }
|
829 | }
|
830 | else {
|
831 | if ('disabled' in this.node) {
|
832 | this.node.disabled = true;
|
833 | }
|
834 | }
|
835 | }
|
836 | render() {
|
837 | return React.createElement(CommandToolbarButtonComponent, { ...this.props });
|
838 | }
|
839 | }
|
840 |
|
841 |
|
842 |
|
843 |
|
844 |
|
845 | class ToolbarPopup extends Widget {
|
846 | |
847 |
|
848 |
|
849 | constructor() {
|
850 | super({ node: document.createElement('jp-toolbar') });
|
851 | this.width = 0;
|
852 | this.addClass('jp-Toolbar');
|
853 | this.addClass('jp-Toolbar-responsive-popup');
|
854 | this.layout = new PanelLayout();
|
855 | Widget.attach(this, document.body);
|
856 | this.hide();
|
857 | }
|
858 | |
859 |
|
860 |
|
861 |
|
862 |
|
863 |
|
864 |
|
865 | updateWidth(width) {
|
866 | if (width > 0) {
|
867 | this.width = width;
|
868 | this.node.style.width = `${width}px`;
|
869 | }
|
870 | }
|
871 | |
872 |
|
873 |
|
874 |
|
875 |
|
876 |
|
877 | alignTo(widget) {
|
878 | const { height: widgetHeight, width: widgetWidth, x: widgetX, y: widgetY } = widget.node.getBoundingClientRect();
|
879 | const width = this.width;
|
880 | this.node.style.left = `${widgetX + widgetWidth - width + 1}px`;
|
881 | this.node.style.top = `${widgetY + widgetHeight + 1}px`;
|
882 | }
|
883 | |
884 |
|
885 |
|
886 |
|
887 |
|
888 | insertWidget(index, widget) {
|
889 | this.layout.insertWidget(index, widget);
|
890 | }
|
891 | |
892 |
|
893 |
|
894 | widgetCount() {
|
895 | return this.layout.widgets.length;
|
896 | }
|
897 | |
898 |
|
899 |
|
900 |
|
901 | widgetAt(index) {
|
902 | return this.layout.widgets[index];
|
903 | }
|
904 | }
|
905 |
|
906 |
|
907 |
|
908 |
|
909 |
|
910 | class ToolbarPopupOpener extends ToolbarButton {
|
911 | |
912 |
|
913 |
|
914 | constructor(props = {}) {
|
915 | const trans = (props.translator || nullTranslator).load('jupyterlab');
|
916 | super({
|
917 | icon: ellipsesIcon,
|
918 | onClick: () => {
|
919 | this.handleClick();
|
920 | },
|
921 | tooltip: trans.__('More commands')
|
922 | });
|
923 | this.addClass('jp-Toolbar-responsive-opener');
|
924 | this.popup = new ToolbarPopup();
|
925 | }
|
926 | |
927 |
|
928 |
|
929 |
|
930 | addWidget(widget) {
|
931 | this.popup.insertWidget(0, widget);
|
932 | }
|
933 | |
934 |
|
935 |
|
936 |
|
937 | insertWidget(index, widget) {
|
938 | this.popup.insertWidget(index, widget);
|
939 | }
|
940 | |
941 |
|
942 |
|
943 |
|
944 |
|
945 |
|
946 |
|
947 |
|
948 | dispose() {
|
949 | if (this.isDisposed) {
|
950 | return;
|
951 | }
|
952 | this.popup.dispose();
|
953 | super.dispose();
|
954 | }
|
955 | |
956 |
|
957 |
|
958 | hide() {
|
959 | super.hide();
|
960 | this.hidePopup();
|
961 | }
|
962 | |
963 |
|
964 |
|
965 | hidePopup() {
|
966 | this.popup.hide();
|
967 | }
|
968 | |
969 |
|
970 |
|
971 |
|
972 | updatePopup() {
|
973 | this.popup.updateWidth(this.parent.node.clientWidth);
|
974 | this.popup.alignTo(this.parent);
|
975 | }
|
976 | |
977 |
|
978 |
|
979 |
|
980 | widgetAt(index) {
|
981 | return this.popup.widgetAt(index);
|
982 | }
|
983 | |
984 |
|
985 |
|
986 |
|
987 |
|
988 | widgetCount() {
|
989 | return this.popup.widgetCount();
|
990 | }
|
991 | handleClick() {
|
992 | this.updatePopup();
|
993 | this.popup.setHidden(!this.popup.isHidden);
|
994 | }
|
995 | }
|
996 |
|
997 |
|
998 |
|
999 | var Private;
|
1000 | (function (Private) {
|
1001 | function propsFromCommand(options) {
|
1002 | var _a, _b;
|
1003 | const { commands, id, args } = options;
|
1004 | const iconClass = commands.iconClass(id, args);
|
1005 | const iconLabel = commands.iconLabel(id, args);
|
1006 | const icon = (_a = options.icon) !== null && _a !== void 0 ? _a : commands.icon(id, args);
|
1007 | const label = commands.label(id, args);
|
1008 | let className = commands.className(id, args);
|
1009 |
|
1010 | let pressed;
|
1011 | if (commands.isToggleable(id, args)) {
|
1012 | pressed = commands.isToggled(id, args);
|
1013 | if (pressed) {
|
1014 | className += ' lm-mod-toggled';
|
1015 | }
|
1016 | }
|
1017 | if (!commands.isVisible(id, args)) {
|
1018 | className += ' lm-mod-hidden';
|
1019 | }
|
1020 | const labelOverride = typeof options.label === 'function'
|
1021 | ? options.label(args !== null && args !== void 0 ? args : {})
|
1022 | : options.label;
|
1023 | let tooltip = commands.caption(id, args) || labelOverride || label || iconLabel;
|
1024 |
|
1025 | const binding = commands.keyBindings.find(b => b.command === id);
|
1026 | if (binding) {
|
1027 | const ks = binding.keys.map(CommandRegistry.formatKeystroke).join(', ');
|
1028 | tooltip = `${tooltip} (${ks})`;
|
1029 | }
|
1030 | const onClick = () => {
|
1031 | void commands.execute(id, args);
|
1032 | };
|
1033 | const enabled = commands.isEnabled(id, args);
|
1034 | return {
|
1035 | className,
|
1036 | dataset: { 'data-command': options.id },
|
1037 | icon,
|
1038 | iconClass,
|
1039 | tooltip: (_b = options.caption) !== null && _b !== void 0 ? _b : tooltip,
|
1040 | onClick,
|
1041 | enabled,
|
1042 | label: labelOverride !== null && labelOverride !== void 0 ? labelOverride : label,
|
1043 | pressed
|
1044 | };
|
1045 | }
|
1046 | Private.propsFromCommand = propsFromCommand;
|
1047 | |
1048 |
|
1049 |
|
1050 | Private.nameProperty = new AttachedProperty({
|
1051 | name: 'name',
|
1052 | create: () => ''
|
1053 | });
|
1054 | |
1055 |
|
1056 |
|
1057 | class Spacer extends Widget {
|
1058 | |
1059 |
|
1060 |
|
1061 | constructor() {
|
1062 | super();
|
1063 | this.addClass(TOOLBAR_SPACER_CLASS);
|
1064 | }
|
1065 | }
|
1066 | Private.Spacer = Spacer;
|
1067 | })(Private || (Private = {}));
|
1068 |
|
\ | No newline at end of file |