UNPKG

570 kBJavaScriptView Raw
1import { empty, each, iter, ArrayExt, StringExt, chain, once, map, ChainIterator, reduce, find, toArray, filter, max } from '@lumino/algorithm';
2import { ElementExt, Selector, Platform } from '@lumino/domutils';
3import { MessageLoop, Message, ConflatableMessage } from '@lumino/messaging';
4import { AttachedProperty } from '@lumino/properties';
5import { Signal } from '@lumino/signaling';
6import { Drag } from '@lumino/dragdrop';
7import { JSONExt, MimeData } from '@lumino/coreutils';
8import { CommandRegistry } from '@lumino/commands';
9import { VirtualDOM, h } from '@lumino/virtualdom';
10import { DisposableDelegate } from '@lumino/disposable';
11import { getKeyboardLayout } from '@lumino/keyboard';
12
13/*! *****************************************************************************
14Copyright (c) Microsoft Corporation.
15
16Permission to use, copy, modify, and/or distribute this software for any
17purpose with or without fee is hereby granted.
18
19THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
20REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
21AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
22INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
23LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
24OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
25PERFORMANCE OF THIS SOFTWARE.
26***************************************************************************** */
27/* global Reflect, Promise */
28
29var extendStatics = function(d, b) {
30 extendStatics = Object.setPrototypeOf ||
31 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
32 function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
33 return extendStatics(d, b);
34};
35
36function __extends(d, b) {
37 if (typeof b !== "function" && b !== null)
38 throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
39 extendStatics(d, b);
40 function __() { this.constructor = d; }
41 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
42}
43
44var __assign = function() {
45 __assign = Object.assign || function __assign(t) {
46 for (var s, i = 1, n = arguments.length; i < n; i++) {
47 s = arguments[i];
48 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
49 }
50 return t;
51 };
52 return __assign.apply(this, arguments);
53};
54
55function __rest(s, e) {
56 var t = {};
57 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
58 t[p] = s[p];
59 if (s != null && typeof Object.getOwnPropertySymbols === "function")
60 for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
61 if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
62 t[p[i]] = s[p[i]];
63 }
64 return t;
65}
66
67// Copyright (c) Jupyter Development Team.
68// Distributed under the terms of the Modified BSD License.
69/*-----------------------------------------------------------------------------
70| Copyright (c) 2014-2017, PhosphorJS Contributors
71|
72| Distributed under the terms of the BSD 3-Clause License.
73|
74| The full license is in the file LICENSE, distributed with this software.
75|----------------------------------------------------------------------------*/
76/**
77 * A sizer object for use with the box engine layout functions.
78 *
79 * #### Notes
80 * A box sizer holds the geometry information for an object along an
81 * arbitrary layout orientation.
82 *
83 * For best performance, this class should be treated as a raw data
84 * struct. It should not typically be subclassed.
85 */
86var BoxSizer = /** @class */ (function () {
87 function BoxSizer() {
88 /**
89 * The preferred size for the sizer.
90 *
91 * #### Notes
92 * The sizer will be given this initial size subject to its size
93 * bounds. The sizer will not deviate from this size unless such
94 * deviation is required to fit into the available layout space.
95 *
96 * There is no limit to this value, but it will be clamped to the
97 * bounds defined by [[minSize]] and [[maxSize]].
98 *
99 * The default value is `0`.
100 */
101 this.sizeHint = 0;
102 /**
103 * The minimum size of the sizer.
104 *
105 * #### Notes
106 * The sizer will never be sized less than this value, even if
107 * it means the sizer will overflow the available layout space.
108 *
109 * It is assumed that this value lies in the range `[0, Infinity)`
110 * and that it is `<=` to [[maxSize]]. Failure to adhere to this
111 * constraint will yield undefined results.
112 *
113 * The default value is `0`.
114 */
115 this.minSize = 0;
116 /**
117 * The maximum size of the sizer.
118 *
119 * #### Notes
120 * The sizer will never be sized greater than this value, even if
121 * it means the sizer will underflow the available layout space.
122 *
123 * It is assumed that this value lies in the range `[0, Infinity]`
124 * and that it is `>=` to [[minSize]]. Failure to adhere to this
125 * constraint will yield undefined results.
126 *
127 * The default value is `Infinity`.
128 */
129 this.maxSize = Infinity;
130 /**
131 * The stretch factor for the sizer.
132 *
133 * #### Notes
134 * This controls how much the sizer stretches relative to its sibling
135 * sizers when layout space is distributed. A stretch factor of zero
136 * is special and will cause the sizer to only be resized after all
137 * other sizers with a stretch factor greater than zero have been
138 * resized to their limits.
139 *
140 * It is assumed that this value is an integer that lies in the range
141 * `[0, Infinity)`. Failure to adhere to this constraint will yield
142 * undefined results.
143 *
144 * The default value is `1`.
145 */
146 this.stretch = 1;
147 /**
148 * The computed size of the sizer.
149 *
150 * #### Notes
151 * This value is the output of a call to [[boxCalc]]. It represents
152 * the computed size for the object along the layout orientation,
153 * and will always lie in the range `[minSize, maxSize]`.
154 *
155 * This value is output only.
156 *
157 * Changing this value will have no effect.
158 */
159 this.size = 0;
160 /**
161 * An internal storage property for the layout algorithm.
162 *
163 * #### Notes
164 * This value is used as temporary storage by the layout algorithm.
165 *
166 * Changing this value will have no effect.
167 */
168 this.done = false;
169 }
170 return BoxSizer;
171}());
172/**
173 * The namespace for the box engine layout functions.
174 */
175var BoxEngine;
176(function (BoxEngine) {
177 /**
178 * Calculate the optimal layout sizes for a sequence of box sizers.
179 *
180 * This distributes the available layout space among the box sizers
181 * according to the following algorithm:
182 *
183 * 1. Initialize the sizers's size to its size hint and compute the
184 * sums for each of size hint, min size, and max size.
185 *
186 * 2. If the total size hint equals the available space, return.
187 *
188 * 3. If the available space is less than the total min size, set all
189 * sizers to their min size and return.
190 *
191 * 4. If the available space is greater than the total max size, set
192 * all sizers to their max size and return.
193 *
194 * 5. If the layout space is less than the total size hint, distribute
195 * the negative delta as follows:
196 *
197 * a. Shrink each sizer with a stretch factor greater than zero by
198 * an amount proportional to the negative space and the sum of
199 * stretch factors. If the sizer reaches its min size, remove
200 * it and its stretch factor from the computation.
201 *
202 * b. If after adjusting all stretch sizers there remains negative
203 * space, distribute the space equally among the sizers with a
204 * stretch factor of zero. If a sizer reaches its min size,
205 * remove it from the computation.
206 *
207 * 6. If the layout space is greater than the total size hint,
208 * distribute the positive delta as follows:
209 *
210 * a. Expand each sizer with a stretch factor greater than zero by
211 * an amount proportional to the postive space and the sum of
212 * stretch factors. If the sizer reaches its max size, remove
213 * it and its stretch factor from the computation.
214 *
215 * b. If after adjusting all stretch sizers there remains positive
216 * space, distribute the space equally among the sizers with a
217 * stretch factor of zero. If a sizer reaches its max size,
218 * remove it from the computation.
219 *
220 * 7. return
221 *
222 * @param sizers - The sizers for a particular layout line.
223 *
224 * @param space - The available layout space for the sizers.
225 *
226 * @returns The delta between the provided available space and the
227 * actual consumed space. This value will be zero if the sizers
228 * can be adjusted to fit, negative if the available space is too
229 * small, and positive if the available space is too large.
230 *
231 * #### Notes
232 * The [[size]] of each sizer is updated with the computed size.
233 *
234 * This function can be called at any time to recompute the layout for
235 * an existing sequence of sizers. The previously computed results will
236 * have no effect on the new output. It is therefore not necessary to
237 * create new sizer objects on each resize event.
238 */
239 function calc(sizers, space) {
240 // Bail early if there is nothing to do.
241 var count = sizers.length;
242 if (count === 0) {
243 return space;
244 }
245 // Setup the size and stretch counters.
246 var totalMin = 0;
247 var totalMax = 0;
248 var totalSize = 0;
249 var totalStretch = 0;
250 var stretchCount = 0;
251 // Setup the sizers and compute the totals.
252 for (var i = 0; i < count; ++i) {
253 var sizer = sizers[i];
254 var min = sizer.minSize;
255 var max = sizer.maxSize;
256 var hint = sizer.sizeHint;
257 sizer.done = false;
258 sizer.size = Math.max(min, Math.min(hint, max));
259 totalSize += sizer.size;
260 totalMin += min;
261 totalMax += max;
262 if (sizer.stretch > 0) {
263 totalStretch += sizer.stretch;
264 stretchCount++;
265 }
266 }
267 // If the space is equal to the total size, return early.
268 if (space === totalSize) {
269 return 0;
270 }
271 // If the space is less than the total min, minimize each sizer.
272 if (space <= totalMin) {
273 for (var i = 0; i < count; ++i) {
274 var sizer = sizers[i];
275 sizer.size = sizer.minSize;
276 }
277 return space - totalMin;
278 }
279 // If the space is greater than the total max, maximize each sizer.
280 if (space >= totalMax) {
281 for (var i = 0; i < count; ++i) {
282 var sizer = sizers[i];
283 sizer.size = sizer.maxSize;
284 }
285 return space - totalMax;
286 }
287 // The loops below perform sub-pixel precision sizing. A near zero
288 // value is used for compares instead of zero to ensure that the
289 // loop terminates when the subdivided space is reasonably small.
290 var nearZero = 0.01;
291 // A counter which is decremented each time a sizer is resized to
292 // its limit. This ensures the loops terminate even if there is
293 // space remaining to distribute.
294 var notDoneCount = count;
295 // Distribute negative delta space.
296 if (space < totalSize) {
297 // Shrink each stretchable sizer by an amount proportional to its
298 // stretch factor. If a sizer reaches its min size it's marked as
299 // done. The loop progresses in phases where each sizer is given
300 // a chance to consume its fair share for the pass, regardless of
301 // whether a sizer before it reached its limit. This continues
302 // until the stretchable sizers or the free space is exhausted.
303 var freeSpace = totalSize - space;
304 while (stretchCount > 0 && freeSpace > nearZero) {
305 var distSpace = freeSpace;
306 var distStretch = totalStretch;
307 for (var i = 0; i < count; ++i) {
308 var sizer = sizers[i];
309 if (sizer.done || sizer.stretch === 0) {
310 continue;
311 }
312 var amt = (sizer.stretch * distSpace) / distStretch;
313 if (sizer.size - amt <= sizer.minSize) {
314 freeSpace -= sizer.size - sizer.minSize;
315 totalStretch -= sizer.stretch;
316 sizer.size = sizer.minSize;
317 sizer.done = true;
318 notDoneCount--;
319 stretchCount--;
320 }
321 else {
322 freeSpace -= amt;
323 sizer.size -= amt;
324 }
325 }
326 }
327 // Distribute any remaining space evenly among the non-stretchable
328 // sizers. This progresses in phases in the same manner as above.
329 while (notDoneCount > 0 && freeSpace > nearZero) {
330 var amt = freeSpace / notDoneCount;
331 for (var i = 0; i < count; ++i) {
332 var sizer = sizers[i];
333 if (sizer.done) {
334 continue;
335 }
336 if (sizer.size - amt <= sizer.minSize) {
337 freeSpace -= sizer.size - sizer.minSize;
338 sizer.size = sizer.minSize;
339 sizer.done = true;
340 notDoneCount--;
341 }
342 else {
343 freeSpace -= amt;
344 sizer.size -= amt;
345 }
346 }
347 }
348 }
349 // Distribute positive delta space.
350 else {
351 // Expand each stretchable sizer by an amount proportional to its
352 // stretch factor. If a sizer reaches its max size it's marked as
353 // done. The loop progresses in phases where each sizer is given
354 // a chance to consume its fair share for the pass, regardless of
355 // whether a sizer before it reached its limit. This continues
356 // until the stretchable sizers or the free space is exhausted.
357 var freeSpace = space - totalSize;
358 while (stretchCount > 0 && freeSpace > nearZero) {
359 var distSpace = freeSpace;
360 var distStretch = totalStretch;
361 for (var i = 0; i < count; ++i) {
362 var sizer = sizers[i];
363 if (sizer.done || sizer.stretch === 0) {
364 continue;
365 }
366 var amt = (sizer.stretch * distSpace) / distStretch;
367 if (sizer.size + amt >= sizer.maxSize) {
368 freeSpace -= sizer.maxSize - sizer.size;
369 totalStretch -= sizer.stretch;
370 sizer.size = sizer.maxSize;
371 sizer.done = true;
372 notDoneCount--;
373 stretchCount--;
374 }
375 else {
376 freeSpace -= amt;
377 sizer.size += amt;
378 }
379 }
380 }
381 // Distribute any remaining space evenly among the non-stretchable
382 // sizers. This progresses in phases in the same manner as above.
383 while (notDoneCount > 0 && freeSpace > nearZero) {
384 var amt = freeSpace / notDoneCount;
385 for (var i = 0; i < count; ++i) {
386 var sizer = sizers[i];
387 if (sizer.done) {
388 continue;
389 }
390 if (sizer.size + amt >= sizer.maxSize) {
391 freeSpace -= sizer.maxSize - sizer.size;
392 sizer.size = sizer.maxSize;
393 sizer.done = true;
394 notDoneCount--;
395 }
396 else {
397 freeSpace -= amt;
398 sizer.size += amt;
399 }
400 }
401 }
402 }
403 // Indicate that the consumed space equals the available space.
404 return 0;
405 }
406 BoxEngine.calc = calc;
407 /**
408 * Adjust a sizer by a delta and update its neighbors accordingly.
409 *
410 * @param sizers - The sizers which should be adjusted.
411 *
412 * @param index - The index of the sizer to grow.
413 *
414 * @param delta - The amount to adjust the sizer, positive or negative.
415 *
416 * #### Notes
417 * This will adjust the indicated sizer by the specified amount, along
418 * with the sizes of the appropriate neighbors, subject to the limits
419 * specified by each of the sizers.
420 *
421 * This is useful when implementing box layouts where the boundaries
422 * between the sizers are interactively adjustable by the user.
423 */
424 function adjust(sizers, index, delta) {
425 // Bail early when there is nothing to do.
426 if (sizers.length === 0 || delta === 0) {
427 return;
428 }
429 // Dispatch to the proper implementation.
430 if (delta > 0) {
431 growSizer(sizers, index, delta);
432 }
433 else {
434 shrinkSizer(sizers, index, -delta);
435 }
436 }
437 BoxEngine.adjust = adjust;
438 /**
439 * Grow a sizer by a positive delta and adjust neighbors.
440 */
441 function growSizer(sizers, index, delta) {
442 // Compute how much the items to the left can expand.
443 var growLimit = 0;
444 for (var i = 0; i <= index; ++i) {
445 var sizer = sizers[i];
446 growLimit += sizer.maxSize - sizer.size;
447 }
448 // Compute how much the items to the right can shrink.
449 var shrinkLimit = 0;
450 for (var i = index + 1, n = sizers.length; i < n; ++i) {
451 var sizer = sizers[i];
452 shrinkLimit += sizer.size - sizer.minSize;
453 }
454 // Clamp the delta adjustment to the limits.
455 delta = Math.min(delta, growLimit, shrinkLimit);
456 // Grow the sizers to the left by the delta.
457 var grow = delta;
458 for (var i = index; i >= 0 && grow > 0; --i) {
459 var sizer = sizers[i];
460 var limit = sizer.maxSize - sizer.size;
461 if (limit >= grow) {
462 sizer.sizeHint = sizer.size + grow;
463 grow = 0;
464 }
465 else {
466 sizer.sizeHint = sizer.size + limit;
467 grow -= limit;
468 }
469 }
470 // Shrink the sizers to the right by the delta.
471 var shrink = delta;
472 for (var i = index + 1, n = sizers.length; i < n && shrink > 0; ++i) {
473 var sizer = sizers[i];
474 var limit = sizer.size - sizer.minSize;
475 if (limit >= shrink) {
476 sizer.sizeHint = sizer.size - shrink;
477 shrink = 0;
478 }
479 else {
480 sizer.sizeHint = sizer.size - limit;
481 shrink -= limit;
482 }
483 }
484 }
485 /**
486 * Shrink a sizer by a positive delta and adjust neighbors.
487 */
488 function shrinkSizer(sizers, index, delta) {
489 // Compute how much the items to the right can expand.
490 var growLimit = 0;
491 for (var i = index + 1, n = sizers.length; i < n; ++i) {
492 var sizer = sizers[i];
493 growLimit += sizer.maxSize - sizer.size;
494 }
495 // Compute how much the items to the left can shrink.
496 var shrinkLimit = 0;
497 for (var i = 0; i <= index; ++i) {
498 var sizer = sizers[i];
499 shrinkLimit += sizer.size - sizer.minSize;
500 }
501 // Clamp the delta adjustment to the limits.
502 delta = Math.min(delta, growLimit, shrinkLimit);
503 // Grow the sizers to the right by the delta.
504 var grow = delta;
505 for (var i = index + 1, n = sizers.length; i < n && grow > 0; ++i) {
506 var sizer = sizers[i];
507 var limit = sizer.maxSize - sizer.size;
508 if (limit >= grow) {
509 sizer.sizeHint = sizer.size + grow;
510 grow = 0;
511 }
512 else {
513 sizer.sizeHint = sizer.size + limit;
514 grow -= limit;
515 }
516 }
517 // Shrink the sizers to the left by the delta.
518 var shrink = delta;
519 for (var i = index; i >= 0 && shrink > 0; --i) {
520 var sizer = sizers[i];
521 var limit = sizer.size - sizer.minSize;
522 if (limit >= shrink) {
523 sizer.sizeHint = sizer.size - shrink;
524 shrink = 0;
525 }
526 else {
527 sizer.sizeHint = sizer.size - limit;
528 shrink -= limit;
529 }
530 }
531 }
532})(BoxEngine || (BoxEngine = {}));
533
534// Copyright (c) Jupyter Development Team.
535/**
536 * An object which holds data related to an object's title.
537 *
538 * #### Notes
539 * A title object is intended to hold the data necessary to display a
540 * header for a particular object. A common example is the `TabPanel`,
541 * which uses the widget title to populate the tab for a child widget.
542 */
543var Title = /** @class */ (function () {
544 /**
545 * Construct a new title.
546 *
547 * @param options - The options for initializing the title.
548 */
549 function Title(options) {
550 this._label = '';
551 this._caption = '';
552 this._mnemonic = -1;
553 this._iconClass = '';
554 this._iconLabel = '';
555 this._className = '';
556 this._closable = false;
557 this._changed = new Signal(this);
558 this.owner = options.owner;
559 if (options.label !== undefined) {
560 this._label = options.label;
561 }
562 if (options.mnemonic !== undefined) {
563 this._mnemonic = options.mnemonic;
564 }
565 if (options.icon !== undefined) {
566 /* <DEPRECATED> */
567 if (typeof options.icon === 'string') {
568 // when ._icon is null, the .icon getter will alias .iconClass
569 this._icon = null;
570 this._iconClass = options.icon;
571 }
572 else {
573 /* </DEPRECATED> */
574 this._icon = options.icon;
575 /* <DEPRECATED> */
576 }
577 /* </DEPRECATED> */
578 }
579 else {
580 /* <DEPRECATED> */
581 // if unset, default to aliasing .iconClass
582 this._icon = null;
583 }
584 /* </DEPRECATED> */
585 if (options.iconClass !== undefined) {
586 this._iconClass = options.iconClass;
587 }
588 if (options.iconLabel !== undefined) {
589 this._iconLabel = options.iconLabel;
590 }
591 if (options.iconRenderer !== undefined) {
592 this._icon = options.iconRenderer;
593 }
594 if (options.caption !== undefined) {
595 this._caption = options.caption;
596 }
597 if (options.className !== undefined) {
598 this._className = options.className;
599 }
600 if (options.closable !== undefined) {
601 this._closable = options.closable;
602 }
603 this._dataset = options.dataset || {};
604 }
605 Object.defineProperty(Title.prototype, "changed", {
606 /**
607 * A signal emitted when the state of the title changes.
608 */
609 get: function () {
610 return this._changed;
611 },
612 enumerable: true,
613 configurable: true
614 });
615 Object.defineProperty(Title.prototype, "label", {
616 /**
617 * Get the label for the title.
618 *
619 * #### Notes
620 * The default value is an empty string.
621 */
622 get: function () {
623 return this._label;
624 },
625 /**
626 * Set the label for the title.
627 */
628 set: function (value) {
629 if (this._label === value) {
630 return;
631 }
632 this._label = value;
633 this._changed.emit(undefined);
634 },
635 enumerable: true,
636 configurable: true
637 });
638 Object.defineProperty(Title.prototype, "mnemonic", {
639 /**
640 * Get the mnemonic index for the title.
641 *
642 * #### Notes
643 * The default value is `-1`.
644 */
645 get: function () {
646 return this._mnemonic;
647 },
648 /**
649 * Set the mnemonic index for the title.
650 */
651 set: function (value) {
652 if (this._mnemonic === value) {
653 return;
654 }
655 this._mnemonic = value;
656 this._changed.emit(undefined);
657 },
658 enumerable: true,
659 configurable: true
660 });
661 Object.defineProperty(Title.prototype, "icon", {
662 /**
663 * Get the icon renderer for the title.
664 *
665 * #### Notes
666 * The default value is undefined.
667 *
668 * DEPRECATED: if set to a string value, the .icon field will function as
669 * an alias for the .iconClass field, for backwards compatibility
670 */
671 get: function () {
672 /* <DEPRECATED> */
673 if (this._icon === null) {
674 // only alias .iconClass if ._icon has been explicitly nulled
675 return this.iconClass;
676 }
677 /* </DEPRECATED> */
678 return this._icon;
679 },
680 /**
681 * Set the icon renderer for the title.
682 *
683 * #### Notes
684 * A renderer is an object that supplies a render and unrender function.
685 *
686 * DEPRECATED: if set to a string value, the .icon field will function as
687 * an alias for the .iconClass field, for backwards compatibility
688 */
689 set: function (value /* </DEPRECATED> */) {
690 /* <DEPRECATED> */
691 if (typeof value === 'string') {
692 // when ._icon is null, the .icon getter will alias .iconClass
693 this._icon = null;
694 this.iconClass = value;
695 }
696 else {
697 /* </DEPRECATED> */
698 if (this._icon === value) {
699 return;
700 }
701 this._icon = value;
702 this._changed.emit(undefined);
703 /* <DEPRECATED> */
704 }
705 /* </DEPRECATED> */
706 },
707 enumerable: true,
708 configurable: true
709 });
710 Object.defineProperty(Title.prototype, "iconClass", {
711 /**
712 * Get the icon class name for the title.
713 *
714 * #### Notes
715 * The default value is an empty string.
716 */
717 get: function () {
718 return this._iconClass;
719 },
720 /**
721 * Set the icon class name for the title.
722 *
723 * #### Notes
724 * Multiple class names can be separated with whitespace.
725 */
726 set: function (value) {
727 if (this._iconClass === value) {
728 return;
729 }
730 this._iconClass = value;
731 this._changed.emit(undefined);
732 },
733 enumerable: true,
734 configurable: true
735 });
736 Object.defineProperty(Title.prototype, "iconLabel", {
737 /**
738 * Get the icon label for the title.
739 *
740 * #### Notes
741 * The default value is an empty string.
742 */
743 get: function () {
744 return this._iconLabel;
745 },
746 /**
747 * Set the icon label for the title.
748 *
749 * #### Notes
750 * Multiple class names can be separated with whitespace.
751 */
752 set: function (value) {
753 if (this._iconLabel === value) {
754 return;
755 }
756 this._iconLabel = value;
757 this._changed.emit(undefined);
758 },
759 enumerable: true,
760 configurable: true
761 });
762 Object.defineProperty(Title.prototype, "iconRenderer", {
763 /**
764 * @deprecated Use `icon` instead.
765 */
766 get: function () {
767 return this._icon || undefined;
768 },
769 /**
770 * @deprecated Use `icon` instead.
771 */
772 set: function (value) {
773 this.icon = value;
774 },
775 enumerable: true,
776 configurable: true
777 });
778 Object.defineProperty(Title.prototype, "caption", {
779 /**
780 * Get the caption for the title.
781 *
782 * #### Notes
783 * The default value is an empty string.
784 */
785 get: function () {
786 return this._caption;
787 },
788 /**
789 * Set the caption for the title.
790 */
791 set: function (value) {
792 if (this._caption === value) {
793 return;
794 }
795 this._caption = value;
796 this._changed.emit(undefined);
797 },
798 enumerable: true,
799 configurable: true
800 });
801 Object.defineProperty(Title.prototype, "className", {
802 /**
803 * Get the extra class name for the title.
804 *
805 * #### Notes
806 * The default value is an empty string.
807 */
808 get: function () {
809 return this._className;
810 },
811 /**
812 * Set the extra class name for the title.
813 *
814 * #### Notes
815 * Multiple class names can be separated with whitespace.
816 */
817 set: function (value) {
818 if (this._className === value) {
819 return;
820 }
821 this._className = value;
822 this._changed.emit(undefined);
823 },
824 enumerable: true,
825 configurable: true
826 });
827 Object.defineProperty(Title.prototype, "closable", {
828 /**
829 * Get the closable state for the title.
830 *
831 * #### Notes
832 * The default value is `false`.
833 */
834 get: function () {
835 return this._closable;
836 },
837 /**
838 * Set the closable state for the title.
839 *
840 * #### Notes
841 * This controls the presence of a close icon when applicable.
842 */
843 set: function (value) {
844 if (this._closable === value) {
845 return;
846 }
847 this._closable = value;
848 this._changed.emit(undefined);
849 },
850 enumerable: true,
851 configurable: true
852 });
853 Object.defineProperty(Title.prototype, "dataset", {
854 /**
855 * Get the dataset for the title.
856 *
857 * #### Notes
858 * The default value is an empty dataset.
859 */
860 get: function () {
861 return this._dataset;
862 },
863 /**
864 * Set the dataset for the title.
865 *
866 * #### Notes
867 * This controls the data attributes when applicable.
868 */
869 set: function (value) {
870 if (this._dataset === value) {
871 return;
872 }
873 this._dataset = value;
874 this._changed.emit(undefined);
875 },
876 enumerable: true,
877 configurable: true
878 });
879 return Title;
880}());
881
882/**
883 * The base class of the lumino widget hierarchy.
884 *
885 * #### Notes
886 * This class will typically be subclassed in order to create a useful
887 * widget. However, it can be used directly to host externally created
888 * content.
889 */
890var Widget = /** @class */ (function () {
891 /**
892 * Construct a new widget.
893 *
894 * @param options - The options for initializing the widget.
895 */
896 function Widget(options) {
897 if (options === void 0) { options = {}; }
898 this._flags = 0;
899 this._layout = null;
900 this._parent = null;
901 this._disposed = new Signal(this);
902 this._hiddenMode = Widget.HiddenMode.Display;
903 this.node = Private$j.createNode(options);
904 this.addClass('lm-Widget');
905 /* <DEPRECATED> */
906 this.addClass('p-Widget');
907 /* </DEPRECATED> */
908 }
909 /**
910 * Dispose of the widget and its descendant widgets.
911 *
912 * #### Notes
913 * It is unsafe to use the widget after it has been disposed.
914 *
915 * All calls made to this method after the first are a no-op.
916 */
917 Widget.prototype.dispose = function () {
918 // Do nothing if the widget is already disposed.
919 if (this.isDisposed) {
920 return;
921 }
922 // Set the disposed flag and emit the disposed signal.
923 this.setFlag(Widget.Flag.IsDisposed);
924 this._disposed.emit(undefined);
925 // Remove or detach the widget if necessary.
926 if (this.parent) {
927 this.parent = null;
928 }
929 else if (this.isAttached) {
930 Widget.detach(this);
931 }
932 // Dispose of the widget layout.
933 if (this._layout) {
934 this._layout.dispose();
935 this._layout = null;
936 }
937 // Clear the extra data associated with the widget.
938 Signal.clearData(this);
939 MessageLoop.clearData(this);
940 AttachedProperty.clearData(this);
941 };
942 Object.defineProperty(Widget.prototype, "disposed", {
943 /**
944 * A signal emitted when the widget is disposed.
945 */
946 get: function () {
947 return this._disposed;
948 },
949 enumerable: true,
950 configurable: true
951 });
952 Object.defineProperty(Widget.prototype, "isDisposed", {
953 /**
954 * Test whether the widget has been disposed.
955 */
956 get: function () {
957 return this.testFlag(Widget.Flag.IsDisposed);
958 },
959 enumerable: true,
960 configurable: true
961 });
962 Object.defineProperty(Widget.prototype, "isAttached", {
963 /**
964 * Test whether the widget's node is attached to the DOM.
965 */
966 get: function () {
967 return this.testFlag(Widget.Flag.IsAttached);
968 },
969 enumerable: true,
970 configurable: true
971 });
972 Object.defineProperty(Widget.prototype, "isHidden", {
973 /**
974 * Test whether the widget is explicitly hidden.
975 */
976 get: function () {
977 return this.testFlag(Widget.Flag.IsHidden);
978 },
979 enumerable: true,
980 configurable: true
981 });
982 Object.defineProperty(Widget.prototype, "isVisible", {
983 /**
984 * Test whether the widget is visible.
985 *
986 * #### Notes
987 * A widget is visible when it is attached to the DOM, is not
988 * explicitly hidden, and has no explicitly hidden ancestors.
989 */
990 get: function () {
991 return this.testFlag(Widget.Flag.IsVisible);
992 },
993 enumerable: true,
994 configurable: true
995 });
996 Object.defineProperty(Widget.prototype, "title", {
997 /**
998 * The title object for the widget.
999 *
1000 * #### Notes
1001 * The title object is used by some container widgets when displaying
1002 * the widget alongside some title, such as a tab panel or side bar.
1003 *
1004 * Since not all widgets will use the title, it is created on demand.
1005 *
1006 * The `owner` property of the title is set to this widget.
1007 */
1008 get: function () {
1009 return Private$j.titleProperty.get(this);
1010 },
1011 enumerable: true,
1012 configurable: true
1013 });
1014 Object.defineProperty(Widget.prototype, "id", {
1015 /**
1016 * Get the id of the widget's DOM node.
1017 */
1018 get: function () {
1019 return this.node.id;
1020 },
1021 /**
1022 * Set the id of the widget's DOM node.
1023 */
1024 set: function (value) {
1025 this.node.id = value;
1026 },
1027 enumerable: true,
1028 configurable: true
1029 });
1030 Object.defineProperty(Widget.prototype, "dataset", {
1031 /**
1032 * The dataset for the widget's DOM node.
1033 */
1034 get: function () {
1035 return this.node.dataset;
1036 },
1037 enumerable: true,
1038 configurable: true
1039 });
1040 Object.defineProperty(Widget.prototype, "hiddenMode", {
1041 /**
1042 * Get the method for hiding the widget.
1043 */
1044 get: function () {
1045 return this._hiddenMode;
1046 },
1047 /**
1048 * Set the method for hiding the widget.
1049 */
1050 set: function (value) {
1051 if (this._hiddenMode === value) {
1052 return;
1053 }
1054 this._hiddenMode = value;
1055 switch (value) {
1056 case Widget.HiddenMode.Display:
1057 this.node.style.willChange = 'auto';
1058 break;
1059 case Widget.HiddenMode.Scale:
1060 this.node.style.willChange = 'transform';
1061 break;
1062 }
1063 if (this.isHidden) {
1064 if (value === Widget.HiddenMode.Display) {
1065 this.addClass('lm-mod-hidden');
1066 /* <DEPRECATED> */
1067 this.addClass('p-mod-hidden');
1068 /* </DEPRECATED> */
1069 this.node.style.transform = '';
1070 }
1071 else {
1072 this.node.style.transform = 'scale(0)';
1073 this.removeClass('lm-mod-hidden');
1074 /* <DEPRECATED> */
1075 this.removeClass('p-mod-hidden');
1076 /* </DEPRECATED> */
1077 }
1078 }
1079 },
1080 enumerable: true,
1081 configurable: true
1082 });
1083 Object.defineProperty(Widget.prototype, "parent", {
1084 /**
1085 * Get the parent of the widget.
1086 */
1087 get: function () {
1088 return this._parent;
1089 },
1090 /**
1091 * Set the parent of the widget.
1092 *
1093 * #### Notes
1094 * Children are typically added to a widget by using a layout, which
1095 * means user code will not normally set the parent widget directly.
1096 *
1097 * The widget will be automatically removed from its old parent.
1098 *
1099 * This is a no-op if there is no effective parent change.
1100 */
1101 set: function (value) {
1102 if (this._parent === value) {
1103 return;
1104 }
1105 if (value && this.contains(value)) {
1106 throw new Error('Invalid parent widget.');
1107 }
1108 if (this._parent && !this._parent.isDisposed) {
1109 var msg = new Widget.ChildMessage('child-removed', this);
1110 MessageLoop.sendMessage(this._parent, msg);
1111 }
1112 this._parent = value;
1113 if (this._parent && !this._parent.isDisposed) {
1114 var msg = new Widget.ChildMessage('child-added', this);
1115 MessageLoop.sendMessage(this._parent, msg);
1116 }
1117 if (!this.isDisposed) {
1118 MessageLoop.sendMessage(this, Widget.Msg.ParentChanged);
1119 }
1120 },
1121 enumerable: true,
1122 configurable: true
1123 });
1124 Object.defineProperty(Widget.prototype, "layout", {
1125 /**
1126 * Get the layout for the widget.
1127 */
1128 get: function () {
1129 return this._layout;
1130 },
1131 /**
1132 * Set the layout for the widget.
1133 *
1134 * #### Notes
1135 * The layout is single-use only. It cannot be changed after the
1136 * first assignment.
1137 *
1138 * The layout is disposed automatically when the widget is disposed.
1139 */
1140 set: function (value) {
1141 if (this._layout === value) {
1142 return;
1143 }
1144 if (this.testFlag(Widget.Flag.DisallowLayout)) {
1145 throw new Error('Cannot set widget layout.');
1146 }
1147 if (this._layout) {
1148 throw new Error('Cannot change widget layout.');
1149 }
1150 if (value.parent) {
1151 throw new Error('Cannot change layout parent.');
1152 }
1153 this._layout = value;
1154 value.parent = this;
1155 },
1156 enumerable: true,
1157 configurable: true
1158 });
1159 /**
1160 * Create an iterator over the widget's children.
1161 *
1162 * @returns A new iterator over the children of the widget.
1163 *
1164 * #### Notes
1165 * The widget must have a populated layout in order to have children.
1166 *
1167 * If a layout is not installed, the returned iterator will be empty.
1168 */
1169 Widget.prototype.children = function () {
1170 return this._layout ? this._layout.iter() : empty();
1171 };
1172 /**
1173 * Test whether a widget is a descendant of this widget.
1174 *
1175 * @param widget - The descendant widget of interest.
1176 *
1177 * @returns `true` if the widget is a descendant, `false` otherwise.
1178 */
1179 Widget.prototype.contains = function (widget) {
1180 for (var value = widget; value; value = value._parent) {
1181 if (value === this) {
1182 return true;
1183 }
1184 }
1185 return false;
1186 };
1187 /**
1188 * Test whether the widget's DOM node has the given class name.
1189 *
1190 * @param name - The class name of interest.
1191 *
1192 * @returns `true` if the node has the class, `false` otherwise.
1193 */
1194 Widget.prototype.hasClass = function (name) {
1195 return this.node.classList.contains(name);
1196 };
1197 /**
1198 * Add a class name to the widget's DOM node.
1199 *
1200 * @param name - The class name to add to the node.
1201 *
1202 * #### Notes
1203 * If the class name is already added to the node, this is a no-op.
1204 *
1205 * The class name must not contain whitespace.
1206 */
1207 Widget.prototype.addClass = function (name) {
1208 this.node.classList.add(name);
1209 };
1210 /**
1211 * Remove a class name from the widget's DOM node.
1212 *
1213 * @param name - The class name to remove from the node.
1214 *
1215 * #### Notes
1216 * If the class name is not yet added to the node, this is a no-op.
1217 *
1218 * The class name must not contain whitespace.
1219 */
1220 Widget.prototype.removeClass = function (name) {
1221 this.node.classList.remove(name);
1222 };
1223 /**
1224 * Toggle a class name on the widget's DOM node.
1225 *
1226 * @param name - The class name to toggle on the node.
1227 *
1228 * @param force - Whether to force add the class (`true`) or force
1229 * remove the class (`false`). If not provided, the presence of
1230 * the class will be toggled from its current state.
1231 *
1232 * @returns `true` if the class is now present, `false` otherwise.
1233 *
1234 * #### Notes
1235 * The class name must not contain whitespace.
1236 */
1237 Widget.prototype.toggleClass = function (name, force) {
1238 if (force === true) {
1239 this.node.classList.add(name);
1240 return true;
1241 }
1242 if (force === false) {
1243 this.node.classList.remove(name);
1244 return false;
1245 }
1246 return this.node.classList.toggle(name);
1247 };
1248 /**
1249 * Post an `'update-request'` message to the widget.
1250 *
1251 * #### Notes
1252 * This is a simple convenience method for posting the message.
1253 */
1254 Widget.prototype.update = function () {
1255 MessageLoop.postMessage(this, Widget.Msg.UpdateRequest);
1256 };
1257 /**
1258 * Post a `'fit-request'` message to the widget.
1259 *
1260 * #### Notes
1261 * This is a simple convenience method for posting the message.
1262 */
1263 Widget.prototype.fit = function () {
1264 MessageLoop.postMessage(this, Widget.Msg.FitRequest);
1265 };
1266 /**
1267 * Post an `'activate-request'` message to the widget.
1268 *
1269 * #### Notes
1270 * This is a simple convenience method for posting the message.
1271 */
1272 Widget.prototype.activate = function () {
1273 MessageLoop.postMessage(this, Widget.Msg.ActivateRequest);
1274 };
1275 /**
1276 * Send a `'close-request'` message to the widget.
1277 *
1278 * #### Notes
1279 * This is a simple convenience method for sending the message.
1280 */
1281 Widget.prototype.close = function () {
1282 MessageLoop.sendMessage(this, Widget.Msg.CloseRequest);
1283 };
1284 /**
1285 * Show the widget and make it visible to its parent widget.
1286 *
1287 * #### Notes
1288 * This causes the [[isHidden]] property to be `false`.
1289 *
1290 * If the widget is not explicitly hidden, this is a no-op.
1291 */
1292 Widget.prototype.show = function () {
1293 if (!this.testFlag(Widget.Flag.IsHidden)) {
1294 return;
1295 }
1296 if (this.isAttached && (!this.parent || this.parent.isVisible)) {
1297 MessageLoop.sendMessage(this, Widget.Msg.BeforeShow);
1298 }
1299 this.clearFlag(Widget.Flag.IsHidden);
1300 this.node.removeAttribute('aria-hidden');
1301 if (this.hiddenMode === Widget.HiddenMode.Display) {
1302 this.removeClass('lm-mod-hidden');
1303 /* <DEPRECATED> */
1304 this.removeClass('p-mod-hidden');
1305 /* </DEPRECATED> */
1306 }
1307 else {
1308 this.node.style.transform = '';
1309 }
1310 if (this.isAttached && (!this.parent || this.parent.isVisible)) {
1311 MessageLoop.sendMessage(this, Widget.Msg.AfterShow);
1312 }
1313 if (this.parent) {
1314 var msg = new Widget.ChildMessage('child-shown', this);
1315 MessageLoop.sendMessage(this.parent, msg);
1316 }
1317 };
1318 /**
1319 * Hide the widget and make it hidden to its parent widget.
1320 *
1321 * #### Notes
1322 * This causes the [[isHidden]] property to be `true`.
1323 *
1324 * If the widget is explicitly hidden, this is a no-op.
1325 */
1326 Widget.prototype.hide = function () {
1327 if (this.testFlag(Widget.Flag.IsHidden)) {
1328 return;
1329 }
1330 if (this.isAttached && (!this.parent || this.parent.isVisible)) {
1331 MessageLoop.sendMessage(this, Widget.Msg.BeforeHide);
1332 }
1333 this.setFlag(Widget.Flag.IsHidden);
1334 this.node.setAttribute('aria-hidden', 'true');
1335 if (this.hiddenMode === Widget.HiddenMode.Display) {
1336 this.addClass('lm-mod-hidden');
1337 /* <DEPRECATED> */
1338 this.addClass('p-mod-hidden');
1339 /* </DEPRECATED> */
1340 }
1341 else {
1342 this.node.style.transform = 'scale(0)';
1343 }
1344 if (this.isAttached && (!this.parent || this.parent.isVisible)) {
1345 MessageLoop.sendMessage(this, Widget.Msg.AfterHide);
1346 }
1347 if (this.parent) {
1348 var msg = new Widget.ChildMessage('child-hidden', this);
1349 MessageLoop.sendMessage(this.parent, msg);
1350 }
1351 };
1352 /**
1353 * Show or hide the widget according to a boolean value.
1354 *
1355 * @param hidden - `true` to hide the widget, or `false` to show it.
1356 *
1357 * #### Notes
1358 * This is a convenience method for `hide()` and `show()`.
1359 */
1360 Widget.prototype.setHidden = function (hidden) {
1361 if (hidden) {
1362 this.hide();
1363 }
1364 else {
1365 this.show();
1366 }
1367 };
1368 /**
1369 * Test whether the given widget flag is set.
1370 *
1371 * #### Notes
1372 * This will not typically be called directly by user code.
1373 */
1374 Widget.prototype.testFlag = function (flag) {
1375 return (this._flags & flag) !== 0;
1376 };
1377 /**
1378 * Set the given widget flag.
1379 *
1380 * #### Notes
1381 * This will not typically be called directly by user code.
1382 */
1383 Widget.prototype.setFlag = function (flag) {
1384 this._flags |= flag;
1385 };
1386 /**
1387 * Clear the given widget flag.
1388 *
1389 * #### Notes
1390 * This will not typically be called directly by user code.
1391 */
1392 Widget.prototype.clearFlag = function (flag) {
1393 this._flags &= ~flag;
1394 };
1395 /**
1396 * Process a message sent to the widget.
1397 *
1398 * @param msg - The message sent to the widget.
1399 *
1400 * #### Notes
1401 * Subclasses may reimplement this method as needed.
1402 */
1403 Widget.prototype.processMessage = function (msg) {
1404 switch (msg.type) {
1405 case 'resize':
1406 this.notifyLayout(msg);
1407 this.onResize(msg);
1408 break;
1409 case 'update-request':
1410 this.notifyLayout(msg);
1411 this.onUpdateRequest(msg);
1412 break;
1413 case 'fit-request':
1414 this.notifyLayout(msg);
1415 this.onFitRequest(msg);
1416 break;
1417 case 'before-show':
1418 this.notifyLayout(msg);
1419 this.onBeforeShow(msg);
1420 break;
1421 case 'after-show':
1422 this.setFlag(Widget.Flag.IsVisible);
1423 this.notifyLayout(msg);
1424 this.onAfterShow(msg);
1425 break;
1426 case 'before-hide':
1427 this.notifyLayout(msg);
1428 this.onBeforeHide(msg);
1429 break;
1430 case 'after-hide':
1431 this.clearFlag(Widget.Flag.IsVisible);
1432 this.notifyLayout(msg);
1433 this.onAfterHide(msg);
1434 break;
1435 case 'before-attach':
1436 this.notifyLayout(msg);
1437 this.onBeforeAttach(msg);
1438 break;
1439 case 'after-attach':
1440 if (!this.isHidden && (!this.parent || this.parent.isVisible)) {
1441 this.setFlag(Widget.Flag.IsVisible);
1442 }
1443 this.setFlag(Widget.Flag.IsAttached);
1444 this.notifyLayout(msg);
1445 this.onAfterAttach(msg);
1446 break;
1447 case 'before-detach':
1448 this.notifyLayout(msg);
1449 this.onBeforeDetach(msg);
1450 break;
1451 case 'after-detach':
1452 this.clearFlag(Widget.Flag.IsVisible);
1453 this.clearFlag(Widget.Flag.IsAttached);
1454 this.notifyLayout(msg);
1455 this.onAfterDetach(msg);
1456 break;
1457 case 'activate-request':
1458 this.notifyLayout(msg);
1459 this.onActivateRequest(msg);
1460 break;
1461 case 'close-request':
1462 this.notifyLayout(msg);
1463 this.onCloseRequest(msg);
1464 break;
1465 case 'child-added':
1466 this.notifyLayout(msg);
1467 this.onChildAdded(msg);
1468 break;
1469 case 'child-removed':
1470 this.notifyLayout(msg);
1471 this.onChildRemoved(msg);
1472 break;
1473 default:
1474 this.notifyLayout(msg);
1475 break;
1476 }
1477 };
1478 /**
1479 * Invoke the message processing routine of the widget's layout.
1480 *
1481 * @param msg - The message to dispatch to the layout.
1482 *
1483 * #### Notes
1484 * This is a no-op if the widget does not have a layout.
1485 *
1486 * This will not typically be called directly by user code.
1487 */
1488 Widget.prototype.notifyLayout = function (msg) {
1489 if (this._layout) {
1490 this._layout.processParentMessage(msg);
1491 }
1492 };
1493 /**
1494 * A message handler invoked on a `'close-request'` message.
1495 *
1496 * #### Notes
1497 * The default implementation unparents or detaches the widget.
1498 */
1499 Widget.prototype.onCloseRequest = function (msg) {
1500 if (this.parent) {
1501 this.parent = null;
1502 }
1503 else if (this.isAttached) {
1504 Widget.detach(this);
1505 }
1506 };
1507 /**
1508 * A message handler invoked on a `'resize'` message.
1509 *
1510 * #### Notes
1511 * The default implementation of this handler is a no-op.
1512 */
1513 Widget.prototype.onResize = function (msg) { };
1514 /**
1515 * A message handler invoked on an `'update-request'` message.
1516 *
1517 * #### Notes
1518 * The default implementation of this handler is a no-op.
1519 */
1520 Widget.prototype.onUpdateRequest = function (msg) { };
1521 /**
1522 * A message handler invoked on a `'fit-request'` message.
1523 *
1524 * #### Notes
1525 * The default implementation of this handler is a no-op.
1526 */
1527 Widget.prototype.onFitRequest = function (msg) { };
1528 /**
1529 * A message handler invoked on an `'activate-request'` message.
1530 *
1531 * #### Notes
1532 * The default implementation of this handler is a no-op.
1533 */
1534 Widget.prototype.onActivateRequest = function (msg) { };
1535 /**
1536 * A message handler invoked on a `'before-show'` message.
1537 *
1538 * #### Notes
1539 * The default implementation of this handler is a no-op.
1540 */
1541 Widget.prototype.onBeforeShow = function (msg) { };
1542 /**
1543 * A message handler invoked on an `'after-show'` message.
1544 *
1545 * #### Notes
1546 * The default implementation of this handler is a no-op.
1547 */
1548 Widget.prototype.onAfterShow = function (msg) { };
1549 /**
1550 * A message handler invoked on a `'before-hide'` message.
1551 *
1552 * #### Notes
1553 * The default implementation of this handler is a no-op.
1554 */
1555 Widget.prototype.onBeforeHide = function (msg) { };
1556 /**
1557 * A message handler invoked on an `'after-hide'` message.
1558 *
1559 * #### Notes
1560 * The default implementation of this handler is a no-op.
1561 */
1562 Widget.prototype.onAfterHide = function (msg) { };
1563 /**
1564 * A message handler invoked on a `'before-attach'` message.
1565 *
1566 * #### Notes
1567 * The default implementation of this handler is a no-op.
1568 */
1569 Widget.prototype.onBeforeAttach = function (msg) { };
1570 /**
1571 * A message handler invoked on an `'after-attach'` message.
1572 *
1573 * #### Notes
1574 * The default implementation of this handler is a no-op.
1575 */
1576 Widget.prototype.onAfterAttach = function (msg) { };
1577 /**
1578 * A message handler invoked on a `'before-detach'` message.
1579 *
1580 * #### Notes
1581 * The default implementation of this handler is a no-op.
1582 */
1583 Widget.prototype.onBeforeDetach = function (msg) { };
1584 /**
1585 * A message handler invoked on an `'after-detach'` message.
1586 *
1587 * #### Notes
1588 * The default implementation of this handler is a no-op.
1589 */
1590 Widget.prototype.onAfterDetach = function (msg) { };
1591 /**
1592 * A message handler invoked on a `'child-added'` message.
1593 *
1594 * #### Notes
1595 * The default implementation of this handler is a no-op.
1596 */
1597 Widget.prototype.onChildAdded = function (msg) { };
1598 /**
1599 * A message handler invoked on a `'child-removed'` message.
1600 *
1601 * #### Notes
1602 * The default implementation of this handler is a no-op.
1603 */
1604 Widget.prototype.onChildRemoved = function (msg) { };
1605 return Widget;
1606}());
1607/**
1608 * The namespace for the `Widget` class statics.
1609 */
1610(function (Widget) {
1611 (function (HiddenMode) {
1612 /**
1613 * Set a `lm-mod-hidden` CSS class to hide the widget using `display:none`
1614 * CSS from the standard Lumino CSS.
1615 */
1616 HiddenMode[HiddenMode["Display"] = 0] = "Display";
1617 /**
1618 * Hide the widget by setting the `transform` to `'scale(0)'`.
1619 */
1620 HiddenMode[HiddenMode["Scale"] = 1] = "Scale";
1621 })(Widget.HiddenMode || (Widget.HiddenMode = {}));
1622 (function (Flag) {
1623 /**
1624 * The widget has been disposed.
1625 */
1626 Flag[Flag["IsDisposed"] = 1] = "IsDisposed";
1627 /**
1628 * The widget is attached to the DOM.
1629 */
1630 Flag[Flag["IsAttached"] = 2] = "IsAttached";
1631 /**
1632 * The widget is hidden.
1633 */
1634 Flag[Flag["IsHidden"] = 4] = "IsHidden";
1635 /**
1636 * The widget is visible.
1637 */
1638 Flag[Flag["IsVisible"] = 8] = "IsVisible";
1639 /**
1640 * A layout cannot be set on the widget.
1641 */
1642 Flag[Flag["DisallowLayout"] = 16] = "DisallowLayout";
1643 })(Widget.Flag || (Widget.Flag = {}));
1644 (function (Msg) {
1645 /**
1646 * A singleton `'before-show'` message.
1647 *
1648 * #### Notes
1649 * This message is sent to a widget before it becomes visible.
1650 *
1651 * This message is **not** sent when the widget is being attached.
1652 */
1653 Msg.BeforeShow = new Message('before-show');
1654 /**
1655 * A singleton `'after-show'` message.
1656 *
1657 * #### Notes
1658 * This message is sent to a widget after it becomes visible.
1659 *
1660 * This message is **not** sent when the widget is being attached.
1661 */
1662 Msg.AfterShow = new Message('after-show');
1663 /**
1664 * A singleton `'before-hide'` message.
1665 *
1666 * #### Notes
1667 * This message is sent to a widget before it becomes not-visible.
1668 *
1669 * This message is **not** sent when the widget is being detached.
1670 */
1671 Msg.BeforeHide = new Message('before-hide');
1672 /**
1673 * A singleton `'after-hide'` message.
1674 *
1675 * #### Notes
1676 * This message is sent to a widget after it becomes not-visible.
1677 *
1678 * This message is **not** sent when the widget is being detached.
1679 */
1680 Msg.AfterHide = new Message('after-hide');
1681 /**
1682 * A singleton `'before-attach'` message.
1683 *
1684 * #### Notes
1685 * This message is sent to a widget before it is attached.
1686 */
1687 Msg.BeforeAttach = new Message('before-attach');
1688 /**
1689 * A singleton `'after-attach'` message.
1690 *
1691 * #### Notes
1692 * This message is sent to a widget after it is attached.
1693 */
1694 Msg.AfterAttach = new Message('after-attach');
1695 /**
1696 * A singleton `'before-detach'` message.
1697 *
1698 * #### Notes
1699 * This message is sent to a widget before it is detached.
1700 */
1701 Msg.BeforeDetach = new Message('before-detach');
1702 /**
1703 * A singleton `'after-detach'` message.
1704 *
1705 * #### Notes
1706 * This message is sent to a widget after it is detached.
1707 */
1708 Msg.AfterDetach = new Message('after-detach');
1709 /**
1710 * A singleton `'parent-changed'` message.
1711 *
1712 * #### Notes
1713 * This message is sent to a widget when its parent has changed.
1714 */
1715 Msg.ParentChanged = new Message('parent-changed');
1716 /**
1717 * A singleton conflatable `'update-request'` message.
1718 *
1719 * #### Notes
1720 * This message can be dispatched to supporting widgets in order to
1721 * update their content based on the current widget state. Not all
1722 * widgets will respond to messages of this type.
1723 *
1724 * For widgets with a layout, this message will inform the layout to
1725 * update the position and size of its child widgets.
1726 */
1727 Msg.UpdateRequest = new ConflatableMessage('update-request');
1728 /**
1729 * A singleton conflatable `'fit-request'` message.
1730 *
1731 * #### Notes
1732 * For widgets with a layout, this message will inform the layout to
1733 * recalculate its size constraints to fit the space requirements of
1734 * its child widgets, and to update their position and size. Not all
1735 * layouts will respond to messages of this type.
1736 */
1737 Msg.FitRequest = new ConflatableMessage('fit-request');
1738 /**
1739 * A singleton conflatable `'activate-request'` message.
1740 *
1741 * #### Notes
1742 * This message should be dispatched to a widget when it should
1743 * perform the actions necessary to activate the widget, which
1744 * may include focusing its node or descendant node.
1745 */
1746 Msg.ActivateRequest = new ConflatableMessage('activate-request');
1747 /**
1748 * A singleton conflatable `'close-request'` message.
1749 *
1750 * #### Notes
1751 * This message should be dispatched to a widget when it should close
1752 * and remove itself from the widget hierarchy.
1753 */
1754 Msg.CloseRequest = new ConflatableMessage('close-request');
1755 })(Widget.Msg || (Widget.Msg = {}));
1756 /**
1757 * A message class for child related messages.
1758 */
1759 var ChildMessage = /** @class */ (function (_super) {
1760 __extends(ChildMessage, _super);
1761 /**
1762 * Construct a new child message.
1763 *
1764 * @param type - The message type.
1765 *
1766 * @param child - The child widget for the message.
1767 */
1768 function ChildMessage(type, child) {
1769 var _this = _super.call(this, type) || this;
1770 _this.child = child;
1771 return _this;
1772 }
1773 return ChildMessage;
1774 }(Message));
1775 Widget.ChildMessage = ChildMessage;
1776 /**
1777 * A message class for `'resize'` messages.
1778 */
1779 var ResizeMessage = /** @class */ (function (_super) {
1780 __extends(ResizeMessage, _super);
1781 /**
1782 * Construct a new resize message.
1783 *
1784 * @param width - The **offset width** of the widget, or `-1` if
1785 * the width is not known.
1786 *
1787 * @param height - The **offset height** of the widget, or `-1` if
1788 * the height is not known.
1789 */
1790 function ResizeMessage(width, height) {
1791 var _this = _super.call(this, 'resize') || this;
1792 _this.width = width;
1793 _this.height = height;
1794 return _this;
1795 }
1796 return ResizeMessage;
1797 }(Message));
1798 Widget.ResizeMessage = ResizeMessage;
1799 /**
1800 * The namespace for the `ResizeMessage` class statics.
1801 */
1802 (function (ResizeMessage) {
1803 /**
1804 * A singleton `'resize'` message with an unknown size.
1805 */
1806 ResizeMessage.UnknownSize = new ResizeMessage(-1, -1);
1807 })(ResizeMessage = Widget.ResizeMessage || (Widget.ResizeMessage = {}));
1808 /**
1809 * Attach a widget to a host DOM node.
1810 *
1811 * @param widget - The widget of interest.
1812 *
1813 * @param host - The DOM node to use as the widget's host.
1814 *
1815 * @param ref - The child of `host` to use as the reference element.
1816 * If this is provided, the widget will be inserted before this
1817 * node in the host. The default is `null`, which will cause the
1818 * widget to be added as the last child of the host.
1819 *
1820 * #### Notes
1821 * This will throw an error if the widget is not a root widget, if
1822 * the widget is already attached, or if the host is not attached
1823 * to the DOM.
1824 */
1825 function attach(widget, host, ref) {
1826 if (ref === void 0) { ref = null; }
1827 if (widget.parent) {
1828 throw new Error('Cannot attach a child widget.');
1829 }
1830 if (widget.isAttached || widget.node.isConnected) {
1831 throw new Error('Widget is already attached.');
1832 }
1833 if (!host.isConnected) {
1834 throw new Error('Host is not attached.');
1835 }
1836 MessageLoop.sendMessage(widget, Widget.Msg.BeforeAttach);
1837 host.insertBefore(widget.node, ref);
1838 MessageLoop.sendMessage(widget, Widget.Msg.AfterAttach);
1839 }
1840 Widget.attach = attach;
1841 /**
1842 * Detach the widget from its host DOM node.
1843 *
1844 * @param widget - The widget of interest.
1845 *
1846 * #### Notes
1847 * This will throw an error if the widget is not a root widget,
1848 * or if the widget is not attached to the DOM.
1849 */
1850 function detach(widget) {
1851 if (widget.parent) {
1852 throw new Error('Cannot detach a child widget.');
1853 }
1854 if (!widget.isAttached || !widget.node.isConnected) {
1855 throw new Error('Widget is not attached.');
1856 }
1857 MessageLoop.sendMessage(widget, Widget.Msg.BeforeDetach);
1858 widget.node.parentNode.removeChild(widget.node);
1859 MessageLoop.sendMessage(widget, Widget.Msg.AfterDetach);
1860 }
1861 Widget.detach = detach;
1862})(Widget || (Widget = {}));
1863/**
1864 * The namespace for the module implementation details.
1865 */
1866var Private$j;
1867(function (Private) {
1868 /**
1869 * An attached property for the widget title object.
1870 */
1871 Private.titleProperty = new AttachedProperty({
1872 name: 'title',
1873 create: function (owner) { return new Title({ owner: owner }); }
1874 });
1875 /**
1876 * Create a DOM node for the given widget options.
1877 */
1878 function createNode(options) {
1879 return options.node || document.createElement(options.tag || 'div');
1880 }
1881 Private.createNode = createNode;
1882})(Private$j || (Private$j = {}));
1883
1884/* eslint-disable @typescript-eslint/no-empty-function */
1885/**
1886 * An abstract base class for creating lumino layouts.
1887 *
1888 * #### Notes
1889 * A layout is used to add widgets to a parent and to arrange those
1890 * widgets within the parent's DOM node.
1891 *
1892 * This class implements the base functionality which is required of
1893 * nearly all layouts. It must be subclassed in order to be useful.
1894 *
1895 * Notably, this class does not define a uniform interface for adding
1896 * widgets to the layout. A subclass should define that API in a way
1897 * which is meaningful for its intended use.
1898 */
1899var Layout = /** @class */ (function () {
1900 /**
1901 * Construct a new layout.
1902 *
1903 * @param options - The options for initializing the layout.
1904 */
1905 function Layout(options) {
1906 if (options === void 0) { options = {}; }
1907 this._disposed = false;
1908 this._parent = null;
1909 this._fitPolicy = options.fitPolicy || 'set-min-size';
1910 }
1911 /**
1912 * Dispose of the resources held by the layout.
1913 *
1914 * #### Notes
1915 * This should be reimplemented to clear and dispose of the widgets.
1916 *
1917 * All reimplementations should call the superclass method.
1918 *
1919 * This method is called automatically when the parent is disposed.
1920 */
1921 Layout.prototype.dispose = function () {
1922 this._parent = null;
1923 this._disposed = true;
1924 Signal.clearData(this);
1925 AttachedProperty.clearData(this);
1926 };
1927 Object.defineProperty(Layout.prototype, "isDisposed", {
1928 /**
1929 * Test whether the layout is disposed.
1930 */
1931 get: function () {
1932 return this._disposed;
1933 },
1934 enumerable: true,
1935 configurable: true
1936 });
1937 Object.defineProperty(Layout.prototype, "parent", {
1938 /**
1939 * Get the parent widget of the layout.
1940 */
1941 get: function () {
1942 return this._parent;
1943 },
1944 /**
1945 * Set the parent widget of the layout.
1946 *
1947 * #### Notes
1948 * This is set automatically when installing the layout on the parent
1949 * widget. The parent widget should not be set directly by user code.
1950 */
1951 set: function (value) {
1952 if (this._parent === value) {
1953 return;
1954 }
1955 if (this._parent) {
1956 throw new Error('Cannot change parent widget.');
1957 }
1958 if (value.layout !== this) {
1959 throw new Error('Invalid parent widget.');
1960 }
1961 this._parent = value;
1962 this.init();
1963 },
1964 enumerable: true,
1965 configurable: true
1966 });
1967 Object.defineProperty(Layout.prototype, "fitPolicy", {
1968 /**
1969 * Get the fit policy for the layout.
1970 *
1971 * #### Notes
1972 * The fit policy controls the computed size constraints which are
1973 * applied to the parent widget by the layout.
1974 *
1975 * Some layout implementations may ignore the fit policy.
1976 */
1977 get: function () {
1978 return this._fitPolicy;
1979 },
1980 /**
1981 * Set the fit policy for the layout.
1982 *
1983 * #### Notes
1984 * The fit policy controls the computed size constraints which are
1985 * applied to the parent widget by the layout.
1986 *
1987 * Some layout implementations may ignore the fit policy.
1988 *
1989 * Changing the fit policy will clear the current size constraint
1990 * for the parent widget and then re-fit the parent.
1991 */
1992 set: function (value) {
1993 // Bail if the policy does not change
1994 if (this._fitPolicy === value) {
1995 return;
1996 }
1997 // Update the internal policy.
1998 this._fitPolicy = value;
1999 // Clear the size constraints and schedule a fit of the parent.
2000 if (this._parent) {
2001 var style = this._parent.node.style;
2002 style.minWidth = '';
2003 style.minHeight = '';
2004 style.maxWidth = '';
2005 style.maxHeight = '';
2006 this._parent.fit();
2007 }
2008 },
2009 enumerable: true,
2010 configurable: true
2011 });
2012 /**
2013 * Process a message sent to the parent widget.
2014 *
2015 * @param msg - The message sent to the parent widget.
2016 *
2017 * #### Notes
2018 * This method is called by the parent widget to process a message.
2019 *
2020 * Subclasses may reimplement this method as needed.
2021 */
2022 Layout.prototype.processParentMessage = function (msg) {
2023 switch (msg.type) {
2024 case 'resize':
2025 this.onResize(msg);
2026 break;
2027 case 'update-request':
2028 this.onUpdateRequest(msg);
2029 break;
2030 case 'fit-request':
2031 this.onFitRequest(msg);
2032 break;
2033 case 'before-show':
2034 this.onBeforeShow(msg);
2035 break;
2036 case 'after-show':
2037 this.onAfterShow(msg);
2038 break;
2039 case 'before-hide':
2040 this.onBeforeHide(msg);
2041 break;
2042 case 'after-hide':
2043 this.onAfterHide(msg);
2044 break;
2045 case 'before-attach':
2046 this.onBeforeAttach(msg);
2047 break;
2048 case 'after-attach':
2049 this.onAfterAttach(msg);
2050 break;
2051 case 'before-detach':
2052 this.onBeforeDetach(msg);
2053 break;
2054 case 'after-detach':
2055 this.onAfterDetach(msg);
2056 break;
2057 case 'child-removed':
2058 this.onChildRemoved(msg);
2059 break;
2060 case 'child-shown':
2061 this.onChildShown(msg);
2062 break;
2063 case 'child-hidden':
2064 this.onChildHidden(msg);
2065 break;
2066 }
2067 };
2068 /**
2069 * Perform layout initialization which requires the parent widget.
2070 *
2071 * #### Notes
2072 * This method is invoked immediately after the layout is installed
2073 * on the parent widget.
2074 *
2075 * The default implementation reparents all of the widgets to the
2076 * layout parent widget.
2077 *
2078 * Subclasses should reimplement this method and attach the child
2079 * widget nodes to the parent widget's node.
2080 */
2081 Layout.prototype.init = function () {
2082 var _this = this;
2083 each(this, function (widget) {
2084 widget.parent = _this.parent;
2085 });
2086 };
2087 /**
2088 * A message handler invoked on a `'resize'` message.
2089 *
2090 * #### Notes
2091 * The layout should ensure that its widgets are resized according
2092 * to the specified layout space, and that they are sent a `'resize'`
2093 * message if appropriate.
2094 *
2095 * The default implementation of this method sends an `UnknownSize`
2096 * resize message to all widgets.
2097 *
2098 * This may be reimplemented by subclasses as needed.
2099 */
2100 Layout.prototype.onResize = function (msg) {
2101 each(this, function (widget) {
2102 MessageLoop.sendMessage(widget, Widget.ResizeMessage.UnknownSize);
2103 });
2104 };
2105 /**
2106 * A message handler invoked on an `'update-request'` message.
2107 *
2108 * #### Notes
2109 * The layout should ensure that its widgets are resized according
2110 * to the available layout space, and that they are sent a `'resize'`
2111 * message if appropriate.
2112 *
2113 * The default implementation of this method sends an `UnknownSize`
2114 * resize message to all widgets.
2115 *
2116 * This may be reimplemented by subclasses as needed.
2117 */
2118 Layout.prototype.onUpdateRequest = function (msg) {
2119 each(this, function (widget) {
2120 MessageLoop.sendMessage(widget, Widget.ResizeMessage.UnknownSize);
2121 });
2122 };
2123 /**
2124 * A message handler invoked on a `'before-attach'` message.
2125 *
2126 * #### Notes
2127 * The default implementation of this method forwards the message
2128 * to all widgets. It assumes all widget nodes are attached to the
2129 * parent widget node.
2130 *
2131 * This may be reimplemented by subclasses as needed.
2132 */
2133 Layout.prototype.onBeforeAttach = function (msg) {
2134 each(this, function (widget) {
2135 MessageLoop.sendMessage(widget, msg);
2136 });
2137 };
2138 /**
2139 * A message handler invoked on an `'after-attach'` message.
2140 *
2141 * #### Notes
2142 * The default implementation of this method forwards the message
2143 * to all widgets. It assumes all widget nodes are attached to the
2144 * parent widget node.
2145 *
2146 * This may be reimplemented by subclasses as needed.
2147 */
2148 Layout.prototype.onAfterAttach = function (msg) {
2149 each(this, function (widget) {
2150 MessageLoop.sendMessage(widget, msg);
2151 });
2152 };
2153 /**
2154 * A message handler invoked on a `'before-detach'` message.
2155 *
2156 * #### Notes
2157 * The default implementation of this method forwards the message
2158 * to all widgets. It assumes all widget nodes are attached to the
2159 * parent widget node.
2160 *
2161 * This may be reimplemented by subclasses as needed.
2162 */
2163 Layout.prototype.onBeforeDetach = function (msg) {
2164 each(this, function (widget) {
2165 MessageLoop.sendMessage(widget, msg);
2166 });
2167 };
2168 /**
2169 * A message handler invoked on an `'after-detach'` message.
2170 *
2171 * #### Notes
2172 * The default implementation of this method forwards the message
2173 * to all widgets. It assumes all widget nodes are attached to the
2174 * parent widget node.
2175 *
2176 * This may be reimplemented by subclasses as needed.
2177 */
2178 Layout.prototype.onAfterDetach = function (msg) {
2179 each(this, function (widget) {
2180 MessageLoop.sendMessage(widget, msg);
2181 });
2182 };
2183 /**
2184 * A message handler invoked on a `'before-show'` message.
2185 *
2186 * #### Notes
2187 * The default implementation of this method forwards the message to
2188 * all non-hidden widgets. It assumes all widget nodes are attached
2189 * to the parent widget node.
2190 *
2191 * This may be reimplemented by subclasses as needed.
2192 */
2193 Layout.prototype.onBeforeShow = function (msg) {
2194 each(this, function (widget) {
2195 if (!widget.isHidden) {
2196 MessageLoop.sendMessage(widget, msg);
2197 }
2198 });
2199 };
2200 /**
2201 * A message handler invoked on an `'after-show'` message.
2202 *
2203 * #### Notes
2204 * The default implementation of this method forwards the message to
2205 * all non-hidden widgets. It assumes all widget nodes are attached
2206 * to the parent widget node.
2207 *
2208 * This may be reimplemented by subclasses as needed.
2209 */
2210 Layout.prototype.onAfterShow = function (msg) {
2211 each(this, function (widget) {
2212 if (!widget.isHidden) {
2213 MessageLoop.sendMessage(widget, msg);
2214 }
2215 });
2216 };
2217 /**
2218 * A message handler invoked on a `'before-hide'` message.
2219 *
2220 * #### Notes
2221 * The default implementation of this method forwards the message to
2222 * all non-hidden widgets. It assumes all widget nodes are attached
2223 * to the parent widget node.
2224 *
2225 * This may be reimplemented by subclasses as needed.
2226 */
2227 Layout.prototype.onBeforeHide = function (msg) {
2228 each(this, function (widget) {
2229 if (!widget.isHidden) {
2230 MessageLoop.sendMessage(widget, msg);
2231 }
2232 });
2233 };
2234 /**
2235 * A message handler invoked on an `'after-hide'` message.
2236 *
2237 * #### Notes
2238 * The default implementation of this method forwards the message to
2239 * all non-hidden widgets. It assumes all widget nodes are attached
2240 * to the parent widget node.
2241 *
2242 * This may be reimplemented by subclasses as needed.
2243 */
2244 Layout.prototype.onAfterHide = function (msg) {
2245 each(this, function (widget) {
2246 if (!widget.isHidden) {
2247 MessageLoop.sendMessage(widget, msg);
2248 }
2249 });
2250 };
2251 /**
2252 * A message handler invoked on a `'child-removed'` message.
2253 *
2254 * #### Notes
2255 * This will remove the child widget from the layout.
2256 *
2257 * Subclasses should **not** typically reimplement this method.
2258 */
2259 Layout.prototype.onChildRemoved = function (msg) {
2260 this.removeWidget(msg.child);
2261 };
2262 /**
2263 * A message handler invoked on a `'fit-request'` message.
2264 *
2265 * #### Notes
2266 * The default implementation of this handler is a no-op.
2267 */
2268 Layout.prototype.onFitRequest = function (msg) { };
2269 /**
2270 * A message handler invoked on a `'child-shown'` message.
2271 *
2272 * #### Notes
2273 * The default implementation of this handler is a no-op.
2274 */
2275 Layout.prototype.onChildShown = function (msg) { };
2276 /**
2277 * A message handler invoked on a `'child-hidden'` message.
2278 *
2279 * #### Notes
2280 * The default implementation of this handler is a no-op.
2281 */
2282 Layout.prototype.onChildHidden = function (msg) { };
2283 return Layout;
2284}());
2285/**
2286 * The namespace for the `Layout` class statics.
2287 */
2288(function (Layout) {
2289 /**
2290 * Get the horizontal alignment for a widget.
2291 *
2292 * @param widget - The widget of interest.
2293 *
2294 * @returns The horizontal alignment for the widget.
2295 *
2296 * #### Notes
2297 * If the layout width allocated to a widget is larger than its max
2298 * width, the horizontal alignment controls how the widget is placed
2299 * within the extra horizontal space.
2300 *
2301 * If the allocated width is less than the widget's max width, the
2302 * horizontal alignment has no effect.
2303 *
2304 * Some layout implementations may ignore horizontal alignment.
2305 */
2306 function getHorizontalAlignment(widget) {
2307 return Private$i.horizontalAlignmentProperty.get(widget);
2308 }
2309 Layout.getHorizontalAlignment = getHorizontalAlignment;
2310 /**
2311 * Set the horizontal alignment for a widget.
2312 *
2313 * @param widget - The widget of interest.
2314 *
2315 * @param value - The value for the horizontal alignment.
2316 *
2317 * #### Notes
2318 * If the layout width allocated to a widget is larger than its max
2319 * width, the horizontal alignment controls how the widget is placed
2320 * within the extra horizontal space.
2321 *
2322 * If the allocated width is less than the widget's max width, the
2323 * horizontal alignment has no effect.
2324 *
2325 * Some layout implementations may ignore horizontal alignment.
2326 *
2327 * Changing the horizontal alignment will post an `update-request`
2328 * message to widget's parent, provided the parent has a layout
2329 * installed.
2330 */
2331 function setHorizontalAlignment(widget, value) {
2332 Private$i.horizontalAlignmentProperty.set(widget, value);
2333 }
2334 Layout.setHorizontalAlignment = setHorizontalAlignment;
2335 /**
2336 * Get the vertical alignment for a widget.
2337 *
2338 * @param widget - The widget of interest.
2339 *
2340 * @returns The vertical alignment for the widget.
2341 *
2342 * #### Notes
2343 * If the layout height allocated to a widget is larger than its max
2344 * height, the vertical alignment controls how the widget is placed
2345 * within the extra vertical space.
2346 *
2347 * If the allocated height is less than the widget's max height, the
2348 * vertical alignment has no effect.
2349 *
2350 * Some layout implementations may ignore vertical alignment.
2351 */
2352 function getVerticalAlignment(widget) {
2353 return Private$i.verticalAlignmentProperty.get(widget);
2354 }
2355 Layout.getVerticalAlignment = getVerticalAlignment;
2356 /**
2357 * Set the vertical alignment for a widget.
2358 *
2359 * @param widget - The widget of interest.
2360 *
2361 * @param value - The value for the vertical alignment.
2362 *
2363 * #### Notes
2364 * If the layout height allocated to a widget is larger than its max
2365 * height, the vertical alignment controls how the widget is placed
2366 * within the extra vertical space.
2367 *
2368 * If the allocated height is less than the widget's max height, the
2369 * vertical alignment has no effect.
2370 *
2371 * Some layout implementations may ignore vertical alignment.
2372 *
2373 * Changing the horizontal alignment will post an `update-request`
2374 * message to widget's parent, provided the parent has a layout
2375 * installed.
2376 */
2377 function setVerticalAlignment(widget, value) {
2378 Private$i.verticalAlignmentProperty.set(widget, value);
2379 }
2380 Layout.setVerticalAlignment = setVerticalAlignment;
2381})(Layout || (Layout = {}));
2382/**
2383 * An object which assists in the absolute layout of widgets.
2384 *
2385 * #### Notes
2386 * This class is useful when implementing a layout which arranges its
2387 * widgets using absolute positioning.
2388 *
2389 * This class is used by nearly all of the built-in lumino layouts.
2390 */
2391var LayoutItem = /** @class */ (function () {
2392 /**
2393 * Construct a new layout item.
2394 *
2395 * @param widget - The widget to be managed by the item.
2396 *
2397 * #### Notes
2398 * The widget will be set to absolute positioning.
2399 */
2400 function LayoutItem(widget) {
2401 this._top = NaN;
2402 this._left = NaN;
2403 this._width = NaN;
2404 this._height = NaN;
2405 this._minWidth = 0;
2406 this._minHeight = 0;
2407 this._maxWidth = Infinity;
2408 this._maxHeight = Infinity;
2409 this._disposed = false;
2410 this.widget = widget;
2411 this.widget.node.style.position = 'absolute';
2412 }
2413 /**
2414 * Dispose of the the layout item.
2415 *
2416 * #### Notes
2417 * This will reset the positioning of the widget.
2418 */
2419 LayoutItem.prototype.dispose = function () {
2420 // Do nothing if the item is already disposed.
2421 if (this._disposed) {
2422 return;
2423 }
2424 // Mark the item as disposed.
2425 this._disposed = true;
2426 // Reset the widget style.
2427 var style = this.widget.node.style;
2428 style.position = '';
2429 style.top = '';
2430 style.left = '';
2431 style.width = '';
2432 style.height = '';
2433 };
2434 Object.defineProperty(LayoutItem.prototype, "minWidth", {
2435 /**
2436 * The computed minimum width of the widget.
2437 *
2438 * #### Notes
2439 * This value can be updated by calling the `fit` method.
2440 */
2441 get: function () {
2442 return this._minWidth;
2443 },
2444 enumerable: true,
2445 configurable: true
2446 });
2447 Object.defineProperty(LayoutItem.prototype, "minHeight", {
2448 /**
2449 * The computed minimum height of the widget.
2450 *
2451 * #### Notes
2452 * This value can be updated by calling the `fit` method.
2453 */
2454 get: function () {
2455 return this._minHeight;
2456 },
2457 enumerable: true,
2458 configurable: true
2459 });
2460 Object.defineProperty(LayoutItem.prototype, "maxWidth", {
2461 /**
2462 * The computed maximum width of the widget.
2463 *
2464 * #### Notes
2465 * This value can be updated by calling the `fit` method.
2466 */
2467 get: function () {
2468 return this._maxWidth;
2469 },
2470 enumerable: true,
2471 configurable: true
2472 });
2473 Object.defineProperty(LayoutItem.prototype, "maxHeight", {
2474 /**
2475 * The computed maximum height of the widget.
2476 *
2477 * #### Notes
2478 * This value can be updated by calling the `fit` method.
2479 */
2480 get: function () {
2481 return this._maxHeight;
2482 },
2483 enumerable: true,
2484 configurable: true
2485 });
2486 Object.defineProperty(LayoutItem.prototype, "isDisposed", {
2487 /**
2488 * Whether the layout item is disposed.
2489 */
2490 get: function () {
2491 return this._disposed;
2492 },
2493 enumerable: true,
2494 configurable: true
2495 });
2496 Object.defineProperty(LayoutItem.prototype, "isHidden", {
2497 /**
2498 * Whether the managed widget is hidden.
2499 */
2500 get: function () {
2501 return this.widget.isHidden;
2502 },
2503 enumerable: true,
2504 configurable: true
2505 });
2506 Object.defineProperty(LayoutItem.prototype, "isVisible", {
2507 /**
2508 * Whether the managed widget is visible.
2509 */
2510 get: function () {
2511 return this.widget.isVisible;
2512 },
2513 enumerable: true,
2514 configurable: true
2515 });
2516 Object.defineProperty(LayoutItem.prototype, "isAttached", {
2517 /**
2518 * Whether the managed widget is attached.
2519 */
2520 get: function () {
2521 return this.widget.isAttached;
2522 },
2523 enumerable: true,
2524 configurable: true
2525 });
2526 /**
2527 * Update the computed size limits of the managed widget.
2528 */
2529 LayoutItem.prototype.fit = function () {
2530 var limits = ElementExt.sizeLimits(this.widget.node);
2531 this._minWidth = limits.minWidth;
2532 this._minHeight = limits.minHeight;
2533 this._maxWidth = limits.maxWidth;
2534 this._maxHeight = limits.maxHeight;
2535 };
2536 /**
2537 * Update the position and size of the managed widget.
2538 *
2539 * @param left - The left edge position of the layout box.
2540 *
2541 * @param top - The top edge position of the layout box.
2542 *
2543 * @param width - The width of the layout box.
2544 *
2545 * @param height - The height of the layout box.
2546 */
2547 LayoutItem.prototype.update = function (left, top, width, height) {
2548 // Clamp the size to the computed size limits.
2549 var clampW = Math.max(this._minWidth, Math.min(width, this._maxWidth));
2550 var clampH = Math.max(this._minHeight, Math.min(height, this._maxHeight));
2551 // Adjust the left edge for the horizontal alignment, if needed.
2552 if (clampW < width) {
2553 switch (Layout.getHorizontalAlignment(this.widget)) {
2554 case 'left':
2555 break;
2556 case 'center':
2557 left += (width - clampW) / 2;
2558 break;
2559 case 'right':
2560 left += width - clampW;
2561 break;
2562 default:
2563 throw 'unreachable';
2564 }
2565 }
2566 // Adjust the top edge for the vertical alignment, if needed.
2567 if (clampH < height) {
2568 switch (Layout.getVerticalAlignment(this.widget)) {
2569 case 'top':
2570 break;
2571 case 'center':
2572 top += (height - clampH) / 2;
2573 break;
2574 case 'bottom':
2575 top += height - clampH;
2576 break;
2577 default:
2578 throw 'unreachable';
2579 }
2580 }
2581 // Set up the resize variables.
2582 var resized = false;
2583 var style = this.widget.node.style;
2584 // Update the top edge of the widget if needed.
2585 if (this._top !== top) {
2586 this._top = top;
2587 style.top = top + "px";
2588 }
2589 // Update the left edge of the widget if needed.
2590 if (this._left !== left) {
2591 this._left = left;
2592 style.left = left + "px";
2593 }
2594 // Update the width of the widget if needed.
2595 if (this._width !== clampW) {
2596 resized = true;
2597 this._width = clampW;
2598 style.width = clampW + "px";
2599 }
2600 // Update the height of the widget if needed.
2601 if (this._height !== clampH) {
2602 resized = true;
2603 this._height = clampH;
2604 style.height = clampH + "px";
2605 }
2606 // Send a resize message to the widget if needed.
2607 if (resized) {
2608 var msg = new Widget.ResizeMessage(clampW, clampH);
2609 MessageLoop.sendMessage(this.widget, msg);
2610 }
2611 };
2612 return LayoutItem;
2613}());
2614/**
2615 * The namespace for the module implementation details.
2616 */
2617var Private$i;
2618(function (Private) {
2619 /**
2620 * The attached property for a widget horizontal alignment.
2621 */
2622 Private.horizontalAlignmentProperty = new AttachedProperty({
2623 name: 'horizontalAlignment',
2624 create: function () { return 'center'; },
2625 changed: onAlignmentChanged
2626 });
2627 /**
2628 * The attached property for a widget vertical alignment.
2629 */
2630 Private.verticalAlignmentProperty = new AttachedProperty({
2631 name: 'verticalAlignment',
2632 create: function () { return 'top'; },
2633 changed: onAlignmentChanged
2634 });
2635 /**
2636 * The change handler for the attached alignment properties.
2637 */
2638 function onAlignmentChanged(child) {
2639 if (child.parent && child.parent.layout) {
2640 child.parent.update();
2641 }
2642 }
2643})(Private$i || (Private$i = {}));
2644
2645/**
2646 * A concrete layout implementation suitable for many use cases.
2647 *
2648 * #### Notes
2649 * This class is suitable as a base class for implementing a variety of
2650 * layouts, but can also be used directly with standard CSS to layout a
2651 * collection of widgets.
2652 */
2653var PanelLayout = /** @class */ (function (_super) {
2654 __extends(PanelLayout, _super);
2655 function PanelLayout() {
2656 var _this = _super !== null && _super.apply(this, arguments) || this;
2657 _this._widgets = [];
2658 return _this;
2659 }
2660 /**
2661 * Dispose of the resources held by the layout.
2662 *
2663 * #### Notes
2664 * This will clear and dispose all widgets in the layout.
2665 *
2666 * All reimplementations should call the superclass method.
2667 *
2668 * This method is called automatically when the parent is disposed.
2669 */
2670 PanelLayout.prototype.dispose = function () {
2671 while (this._widgets.length > 0) {
2672 this._widgets.pop().dispose();
2673 }
2674 _super.prototype.dispose.call(this);
2675 };
2676 Object.defineProperty(PanelLayout.prototype, "widgets", {
2677 /**
2678 * A read-only array of the widgets in the layout.
2679 */
2680 get: function () {
2681 return this._widgets;
2682 },
2683 enumerable: true,
2684 configurable: true
2685 });
2686 /**
2687 * Create an iterator over the widgets in the layout.
2688 *
2689 * @returns A new iterator over the widgets in the layout.
2690 */
2691 PanelLayout.prototype.iter = function () {
2692 return iter(this._widgets);
2693 };
2694 /**
2695 * Add a widget to the end of the layout.
2696 *
2697 * @param widget - The widget to add to the layout.
2698 *
2699 * #### Notes
2700 * If the widget is already contained in the layout, it will be moved.
2701 */
2702 PanelLayout.prototype.addWidget = function (widget) {
2703 this.insertWidget(this._widgets.length, widget);
2704 };
2705 /**
2706 * Insert a widget into the layout at the specified index.
2707 *
2708 * @param index - The index at which to insert the widget.
2709 *
2710 * @param widget - The widget to insert into the layout.
2711 *
2712 * #### Notes
2713 * The index will be clamped to the bounds of the widgets.
2714 *
2715 * If the widget is already added to the layout, it will be moved.
2716 *
2717 * #### Undefined Behavior
2718 * An `index` which is non-integral.
2719 */
2720 PanelLayout.prototype.insertWidget = function (index, widget) {
2721 // Remove the widget from its current parent. This is a no-op
2722 // if the widget's parent is already the layout parent widget.
2723 widget.parent = this.parent;
2724 // Look up the current index of the widget.
2725 var i = this._widgets.indexOf(widget);
2726 // Clamp the insert index to the array bounds.
2727 var j = Math.max(0, Math.min(index, this._widgets.length));
2728 // If the widget is not in the array, insert it.
2729 if (i === -1) {
2730 // Insert the widget into the array.
2731 ArrayExt.insert(this._widgets, j, widget);
2732 // If the layout is parented, attach the widget to the DOM.
2733 if (this.parent) {
2734 this.attachWidget(j, widget);
2735 }
2736 // There is nothing more to do.
2737 return;
2738 }
2739 // Otherwise, the widget exists in the array and should be moved.
2740 // Adjust the index if the location is at the end of the array.
2741 if (j === this._widgets.length) {
2742 j--;
2743 }
2744 // Bail if there is no effective move.
2745 if (i === j) {
2746 return;
2747 }
2748 // Move the widget to the new location.
2749 ArrayExt.move(this._widgets, i, j);
2750 // If the layout is parented, move the widget in the DOM.
2751 if (this.parent) {
2752 this.moveWidget(i, j, widget);
2753 }
2754 };
2755 /**
2756 * Remove a widget from the layout.
2757 *
2758 * @param widget - The widget to remove from the layout.
2759 *
2760 * #### Notes
2761 * A widget is automatically removed from the layout when its `parent`
2762 * is set to `null`. This method should only be invoked directly when
2763 * removing a widget from a layout which has yet to be installed on a
2764 * parent widget.
2765 *
2766 * This method does *not* modify the widget's `parent`.
2767 */
2768 PanelLayout.prototype.removeWidget = function (widget) {
2769 this.removeWidgetAt(this._widgets.indexOf(widget));
2770 };
2771 /**
2772 * Remove the widget at a given index from the layout.
2773 *
2774 * @param index - The index of the widget to remove.
2775 *
2776 * #### Notes
2777 * A widget is automatically removed from the layout when its `parent`
2778 * is set to `null`. This method should only be invoked directly when
2779 * removing a widget from a layout which has yet to be installed on a
2780 * parent widget.
2781 *
2782 * This method does *not* modify the widget's `parent`.
2783 *
2784 * #### Undefined Behavior
2785 * An `index` which is non-integral.
2786 */
2787 PanelLayout.prototype.removeWidgetAt = function (index) {
2788 // Remove the widget from the array.
2789 var widget = ArrayExt.removeAt(this._widgets, index);
2790 // If the layout is parented, detach the widget from the DOM.
2791 if (widget && this.parent) {
2792 this.detachWidget(index, widget);
2793 }
2794 };
2795 /**
2796 * Perform layout initialization which requires the parent widget.
2797 */
2798 PanelLayout.prototype.init = function () {
2799 var _this = this;
2800 _super.prototype.init.call(this);
2801 each(this, function (widget, index) {
2802 _this.attachWidget(index, widget);
2803 });
2804 };
2805 /**
2806 * Attach a widget to the parent's DOM node.
2807 *
2808 * @param index - The current index of the widget in the layout.
2809 *
2810 * @param widget - The widget to attach to the parent.
2811 *
2812 * #### Notes
2813 * This method is called automatically by the panel layout at the
2814 * appropriate time. It should not be called directly by user code.
2815 *
2816 * The default implementation adds the widgets's node to the parent's
2817 * node at the proper location, and sends the appropriate attach
2818 * messages to the widget if the parent is attached to the DOM.
2819 *
2820 * Subclasses may reimplement this method to control how the widget's
2821 * node is added to the parent's node.
2822 */
2823 PanelLayout.prototype.attachWidget = function (index, widget) {
2824 // Look up the next sibling reference node.
2825 var ref = this.parent.node.children[index];
2826 // Send a `'before-attach'` message if the parent is attached.
2827 if (this.parent.isAttached) {
2828 MessageLoop.sendMessage(widget, Widget.Msg.BeforeAttach);
2829 }
2830 // Insert the widget's node before the sibling.
2831 this.parent.node.insertBefore(widget.node, ref);
2832 // Send an `'after-attach'` message if the parent is attached.
2833 if (this.parent.isAttached) {
2834 MessageLoop.sendMessage(widget, Widget.Msg.AfterAttach);
2835 }
2836 };
2837 /**
2838 * Move a widget in the parent's DOM node.
2839 *
2840 * @param fromIndex - The previous index of the widget in the layout.
2841 *
2842 * @param toIndex - The current index of the widget in the layout.
2843 *
2844 * @param widget - The widget to move in the parent.
2845 *
2846 * #### Notes
2847 * This method is called automatically by the panel layout at the
2848 * appropriate time. It should not be called directly by user code.
2849 *
2850 * The default implementation moves the widget's node to the proper
2851 * location in the parent's node and sends the appropriate attach and
2852 * detach messages to the widget if the parent is attached to the DOM.
2853 *
2854 * Subclasses may reimplement this method to control how the widget's
2855 * node is moved in the parent's node.
2856 */
2857 PanelLayout.prototype.moveWidget = function (fromIndex, toIndex, widget) {
2858 // Send a `'before-detach'` message if the parent is attached.
2859 if (this.parent.isAttached) {
2860 MessageLoop.sendMessage(widget, Widget.Msg.BeforeDetach);
2861 }
2862 // Remove the widget's node from the parent.
2863 this.parent.node.removeChild(widget.node);
2864 // Send an `'after-detach'` and message if the parent is attached.
2865 if (this.parent.isAttached) {
2866 MessageLoop.sendMessage(widget, Widget.Msg.AfterDetach);
2867 }
2868 // Look up the next sibling reference node.
2869 var ref = this.parent.node.children[toIndex];
2870 // Send a `'before-attach'` message if the parent is attached.
2871 if (this.parent.isAttached) {
2872 MessageLoop.sendMessage(widget, Widget.Msg.BeforeAttach);
2873 }
2874 // Insert the widget's node before the sibling.
2875 this.parent.node.insertBefore(widget.node, ref);
2876 // Send an `'after-attach'` message if the parent is attached.
2877 if (this.parent.isAttached) {
2878 MessageLoop.sendMessage(widget, Widget.Msg.AfterAttach);
2879 }
2880 };
2881 /**
2882 * Detach a widget from the parent's DOM node.
2883 *
2884 * @param index - The previous index of the widget in the layout.
2885 *
2886 * @param widget - The widget to detach from the parent.
2887 *
2888 * #### Notes
2889 * This method is called automatically by the panel layout at the
2890 * appropriate time. It should not be called directly by user code.
2891 *
2892 * The default implementation removes the widget's node from the
2893 * parent's node, and sends the appropriate detach messages to the
2894 * widget if the parent is attached to the DOM.
2895 *
2896 * Subclasses may reimplement this method to control how the widget's
2897 * node is removed from the parent's node.
2898 */
2899 PanelLayout.prototype.detachWidget = function (index, widget) {
2900 // Send a `'before-detach'` message if the parent is attached.
2901 if (this.parent.isAttached) {
2902 MessageLoop.sendMessage(widget, Widget.Msg.BeforeDetach);
2903 }
2904 // Remove the widget's node from the parent.
2905 this.parent.node.removeChild(widget.node);
2906 // Send an `'after-detach'` message if the parent is attached.
2907 if (this.parent.isAttached) {
2908 MessageLoop.sendMessage(widget, Widget.Msg.AfterDetach);
2909 }
2910 };
2911 return PanelLayout;
2912}(Layout));
2913
2914var Utils;
2915(function (Utils) {
2916 /**
2917 * Clamp a dimension value to an integer >= 0.
2918 */
2919 function clampDimension(value) {
2920 return Math.max(0, Math.floor(value));
2921 }
2922 Utils.clampDimension = clampDimension;
2923})(Utils || (Utils = {}));
2924var Utils$1 = Utils;
2925
2926/**
2927 * A layout which arranges its widgets into resizable sections.
2928 */
2929var SplitLayout = /** @class */ (function (_super) {
2930 __extends(SplitLayout, _super);
2931 /**
2932 * Construct a new split layout.
2933 *
2934 * @param options - The options for initializing the layout.
2935 */
2936 function SplitLayout(options) {
2937 var _this = _super.call(this) || this;
2938 _this.widgetOffset = 0;
2939 _this._fixed = 0;
2940 _this._spacing = 4;
2941 _this._dirty = false;
2942 _this._hasNormedSizes = false;
2943 _this._sizers = [];
2944 _this._items = [];
2945 _this._handles = [];
2946 _this._box = null;
2947 _this._alignment = 'start';
2948 _this._orientation = 'horizontal';
2949 _this.renderer = options.renderer;
2950 if (options.orientation !== undefined) {
2951 _this._orientation = options.orientation;
2952 }
2953 if (options.alignment !== undefined) {
2954 _this._alignment = options.alignment;
2955 }
2956 if (options.spacing !== undefined) {
2957 _this._spacing = Utils.clampDimension(options.spacing);
2958 }
2959 return _this;
2960 }
2961 /**
2962 * Dispose of the resources held by the layout.
2963 */
2964 SplitLayout.prototype.dispose = function () {
2965 // Dispose of the layout items.
2966 each(this._items, function (item) {
2967 item.dispose();
2968 });
2969 // Clear the layout state.
2970 this._box = null;
2971 this._items.length = 0;
2972 this._sizers.length = 0;
2973 this._handles.length = 0;
2974 // Dispose of the rest of the layout.
2975 _super.prototype.dispose.call(this);
2976 };
2977 Object.defineProperty(SplitLayout.prototype, "orientation", {
2978 /**
2979 * Get the layout orientation for the split layout.
2980 */
2981 get: function () {
2982 return this._orientation;
2983 },
2984 /**
2985 * Set the layout orientation for the split layout.
2986 */
2987 set: function (value) {
2988 if (this._orientation === value) {
2989 return;
2990 }
2991 this._orientation = value;
2992 if (!this.parent) {
2993 return;
2994 }
2995 this.parent.dataset['orientation'] = value;
2996 this.parent.fit();
2997 },
2998 enumerable: true,
2999 configurable: true
3000 });
3001 Object.defineProperty(SplitLayout.prototype, "alignment", {
3002 /**
3003 * Get the content alignment for the split layout.
3004 *
3005 * #### Notes
3006 * This is the alignment of the widgets in the layout direction.
3007 *
3008 * The alignment has no effect if the widgets can expand to fill the
3009 * entire split layout.
3010 */
3011 get: function () {
3012 return this._alignment;
3013 },
3014 /**
3015 * Set the content alignment for the split layout.
3016 *
3017 * #### Notes
3018 * This is the alignment of the widgets in the layout direction.
3019 *
3020 * The alignment has no effect if the widgets can expand to fill the
3021 * entire split layout.
3022 */
3023 set: function (value) {
3024 if (this._alignment === value) {
3025 return;
3026 }
3027 this._alignment = value;
3028 if (!this.parent) {
3029 return;
3030 }
3031 this.parent.dataset['alignment'] = value;
3032 this.parent.update();
3033 },
3034 enumerable: true,
3035 configurable: true
3036 });
3037 Object.defineProperty(SplitLayout.prototype, "spacing", {
3038 /**
3039 * Get the inter-element spacing for the split layout.
3040 */
3041 get: function () {
3042 return this._spacing;
3043 },
3044 /**
3045 * Set the inter-element spacing for the split layout.
3046 */
3047 set: function (value) {
3048 value = Utils.clampDimension(value);
3049 if (this._spacing === value) {
3050 return;
3051 }
3052 this._spacing = value;
3053 if (!this.parent) {
3054 return;
3055 }
3056 this.parent.fit();
3057 },
3058 enumerable: true,
3059 configurable: true
3060 });
3061 Object.defineProperty(SplitLayout.prototype, "handles", {
3062 /**
3063 * A read-only array of the split handles in the layout.
3064 */
3065 get: function () {
3066 return this._handles;
3067 },
3068 enumerable: true,
3069 configurable: true
3070 });
3071 /**
3072 * Get the relative sizes of the widgets in the layout.
3073 *
3074 * @returns A new array of the relative sizes of the widgets.
3075 *
3076 * #### Notes
3077 * The returned sizes reflect the sizes of the widgets normalized
3078 * relative to their siblings.
3079 *
3080 * This method **does not** measure the DOM nodes.
3081 */
3082 SplitLayout.prototype.relativeSizes = function () {
3083 return Private$h.normalize(this._sizers.map(function (sizer) { return sizer.size; }));
3084 };
3085 /**
3086 * Set the relative sizes for the widgets in the layout.
3087 *
3088 * @param sizes - The relative sizes for the widgets in the panel.
3089 *
3090 * #### Notes
3091 * Extra values are ignored, too few will yield an undefined layout.
3092 *
3093 * The actual geometry of the DOM nodes is updated asynchronously.
3094 */
3095 SplitLayout.prototype.setRelativeSizes = function (sizes) {
3096 // Copy the sizes and pad with zeros as needed.
3097 var n = this._sizers.length;
3098 var temp = sizes.slice(0, n);
3099 while (temp.length < n) {
3100 temp.push(0);
3101 }
3102 // Normalize the padded sizes.
3103 var normed = Private$h.normalize(temp);
3104 // Apply the normalized sizes to the sizers.
3105 for (var i = 0; i < n; ++i) {
3106 var sizer = this._sizers[i];
3107 sizer.sizeHint = normed[i];
3108 sizer.size = normed[i];
3109 }
3110 // Set the flag indicating the sizes are normalized.
3111 this._hasNormedSizes = true;
3112 // Trigger an update of the parent widget.
3113 if (this.parent) {
3114 this.parent.update();
3115 }
3116 };
3117 /**
3118 * Move the offset position of a split handle.
3119 *
3120 * @param index - The index of the handle of the interest.
3121 *
3122 * @param position - The desired offset position of the handle.
3123 *
3124 * #### Notes
3125 * The position is relative to the offset parent.
3126 *
3127 * This will move the handle as close as possible to the desired
3128 * position. The sibling widgets will be adjusted as necessary.
3129 */
3130 SplitLayout.prototype.moveHandle = function (index, position) {
3131 // Bail if the index is invalid or the handle is hidden.
3132 var handle = this._handles[index];
3133 if (!handle || handle.classList.contains('lm-mod-hidden')) {
3134 return;
3135 }
3136 // Compute the desired delta movement for the handle.
3137 var delta;
3138 if (this._orientation === 'horizontal') {
3139 delta = position - handle.offsetLeft;
3140 }
3141 else {
3142 delta = position - handle.offsetTop;
3143 }
3144 // Bail if there is no handle movement.
3145 if (delta === 0) {
3146 return;
3147 }
3148 // Prevent widget resizing unless needed.
3149 for (var _i = 0, _a = this._sizers; _i < _a.length; _i++) {
3150 var sizer = _a[_i];
3151 if (sizer.size > 0) {
3152 sizer.sizeHint = sizer.size;
3153 }
3154 }
3155 // Adjust the sizers to reflect the handle movement.
3156 BoxEngine.adjust(this._sizers, index, delta);
3157 // Update the layout of the widgets.
3158 if (this.parent) {
3159 this.parent.update();
3160 }
3161 };
3162 /**
3163 * Perform layout initialization which requires the parent widget.
3164 */
3165 SplitLayout.prototype.init = function () {
3166 this.parent.dataset['orientation'] = this.orientation;
3167 this.parent.dataset['alignment'] = this.alignment;
3168 _super.prototype.init.call(this);
3169 };
3170 /**
3171 * Attach a widget to the parent's DOM node.
3172 *
3173 * @param index - The current index of the widget in the layout.
3174 *
3175 * @param widget - The widget to attach to the parent.
3176 *
3177 * #### Notes
3178 * This is a reimplementation of the superclass method.
3179 */
3180 SplitLayout.prototype.attachWidget = function (index, widget) {
3181 // Create the item, handle, and sizer for the new widget.
3182 var item = new LayoutItem(widget);
3183 var handle = Private$h.createHandle(this.renderer);
3184 var average = Private$h.averageSize(this._sizers);
3185 var sizer = Private$h.createSizer(average);
3186 // Insert the item, handle, and sizer into the internal arrays.
3187 ArrayExt.insert(this._items, index, item);
3188 ArrayExt.insert(this._sizers, index, sizer);
3189 ArrayExt.insert(this._handles, index, handle);
3190 // Send a `'before-attach'` message if the parent is attached.
3191 if (this.parent.isAttached) {
3192 MessageLoop.sendMessage(widget, Widget.Msg.BeforeAttach);
3193 }
3194 // Add the widget and handle nodes to the parent.
3195 this.parent.node.appendChild(widget.node);
3196 this.parent.node.appendChild(handle);
3197 // Send an `'after-attach'` message if the parent is attached.
3198 if (this.parent.isAttached) {
3199 MessageLoop.sendMessage(widget, Widget.Msg.AfterAttach);
3200 }
3201 // Post a fit request for the parent widget.
3202 this.parent.fit();
3203 };
3204 /**
3205 * Move a widget in the parent's DOM node.
3206 *
3207 * @param fromIndex - The previous index of the widget in the layout.
3208 *
3209 * @param toIndex - The current index of the widget in the layout.
3210 *
3211 * @param widget - The widget to move in the parent.
3212 *
3213 * #### Notes
3214 * This is a reimplementation of the superclass method.
3215 */
3216 SplitLayout.prototype.moveWidget = function (fromIndex, toIndex, widget) {
3217 // Move the item, sizer, and handle for the widget.
3218 ArrayExt.move(this._items, fromIndex, toIndex);
3219 ArrayExt.move(this._sizers, fromIndex, toIndex);
3220 ArrayExt.move(this._handles, fromIndex, toIndex);
3221 // Post a fit request to the parent to show/hide last handle.
3222 this.parent.fit();
3223 };
3224 /**
3225 * Detach a widget from the parent's DOM node.
3226 *
3227 * @param index - The previous index of the widget in the layout.
3228 *
3229 * @param widget - The widget to detach from the parent.
3230 *
3231 * #### Notes
3232 * This is a reimplementation of the superclass method.
3233 */
3234 SplitLayout.prototype.detachWidget = function (index, widget) {
3235 // Remove the item, handle, and sizer for the widget.
3236 var item = ArrayExt.removeAt(this._items, index);
3237 var handle = ArrayExt.removeAt(this._handles, index);
3238 ArrayExt.removeAt(this._sizers, index);
3239 // Send a `'before-detach'` message if the parent is attached.
3240 if (this.parent.isAttached) {
3241 MessageLoop.sendMessage(widget, Widget.Msg.BeforeDetach);
3242 }
3243 // Remove the widget and handle nodes from the parent.
3244 this.parent.node.removeChild(widget.node);
3245 this.parent.node.removeChild(handle);
3246 // Send an `'after-detach'` message if the parent is attached.
3247 if (this.parent.isAttached) {
3248 MessageLoop.sendMessage(widget, Widget.Msg.AfterDetach);
3249 }
3250 // Dispose of the layout item.
3251 item.dispose();
3252 // Post a fit request for the parent widget.
3253 this.parent.fit();
3254 };
3255 /**
3256 * A message handler invoked on a `'before-show'` message.
3257 */
3258 SplitLayout.prototype.onBeforeShow = function (msg) {
3259 _super.prototype.onBeforeShow.call(this, msg);
3260 this.parent.update();
3261 };
3262 /**
3263 * A message handler invoked on a `'before-attach'` message.
3264 */
3265 SplitLayout.prototype.onBeforeAttach = function (msg) {
3266 _super.prototype.onBeforeAttach.call(this, msg);
3267 this.parent.fit();
3268 };
3269 /**
3270 * A message handler invoked on a `'child-shown'` message.
3271 */
3272 SplitLayout.prototype.onChildShown = function (msg) {
3273 this.parent.fit();
3274 };
3275 /**
3276 * A message handler invoked on a `'child-hidden'` message.
3277 */
3278 SplitLayout.prototype.onChildHidden = function (msg) {
3279 this.parent.fit();
3280 };
3281 /**
3282 * A message handler invoked on a `'resize'` message.
3283 */
3284 SplitLayout.prototype.onResize = function (msg) {
3285 if (this.parent.isVisible) {
3286 this._update(msg.width, msg.height);
3287 }
3288 };
3289 /**
3290 * A message handler invoked on an `'update-request'` message.
3291 */
3292 SplitLayout.prototype.onUpdateRequest = function (msg) {
3293 if (this.parent.isVisible) {
3294 this._update(-1, -1);
3295 }
3296 };
3297 /**
3298 * A message handler invoked on a `'fit-request'` message.
3299 */
3300 SplitLayout.prototype.onFitRequest = function (msg) {
3301 if (this.parent.isAttached) {
3302 this._fit();
3303 }
3304 };
3305 /**
3306 * Update the item position.
3307 *
3308 * @param i Item index
3309 * @param isHorizontal Whether the layout is horizontal or not
3310 * @param left Left position in pixels
3311 * @param top Top position in pixels
3312 * @param height Item height
3313 * @param width Item width
3314 * @param size Item size
3315 */
3316 SplitLayout.prototype.updateItemPosition = function (i, isHorizontal, left, top, height, width, size) {
3317 var item = this._items[i];
3318 if (item.isHidden) {
3319 return;
3320 }
3321 // Fetch the style for the handle.
3322 var handleStyle = this._handles[i].style;
3323 // Update the widget and handle, and advance the relevant edge.
3324 if (isHorizontal) {
3325 left += this.widgetOffset;
3326 item.update(left, top, size, height);
3327 left += size;
3328 handleStyle.top = top + "px";
3329 handleStyle.left = left + "px";
3330 handleStyle.width = this._spacing + "px";
3331 handleStyle.height = height + "px";
3332 }
3333 else {
3334 top += this.widgetOffset;
3335 item.update(left, top, width, size);
3336 top += size;
3337 handleStyle.top = top + "px";
3338 handleStyle.left = left + "px";
3339 handleStyle.width = width + "px";
3340 handleStyle.height = this._spacing + "px";
3341 }
3342 };
3343 /**
3344 * Fit the layout to the total size required by the widgets.
3345 */
3346 SplitLayout.prototype._fit = function () {
3347 // Update the handles and track the visible widget count.
3348 var nVisible = 0;
3349 var lastHandleIndex = -1;
3350 for (var i = 0, n = this._items.length; i < n; ++i) {
3351 if (this._items[i].isHidden) {
3352 this._handles[i].classList.add('lm-mod-hidden');
3353 /* <DEPRECATED> */
3354 this._handles[i].classList.add('p-mod-hidden');
3355 /* </DEPRECATED> */
3356 }
3357 else {
3358 this._handles[i].classList.remove('lm-mod-hidden');
3359 /* <DEPRECATED> */
3360 this._handles[i].classList.remove('p-mod-hidden');
3361 /* </DEPRECATED> */
3362 lastHandleIndex = i;
3363 nVisible++;
3364 }
3365 }
3366 // Hide the handle for the last visible widget.
3367 if (lastHandleIndex !== -1) {
3368 this._handles[lastHandleIndex].classList.add('lm-mod-hidden');
3369 /* <DEPRECATED> */
3370 this._handles[lastHandleIndex].classList.add('p-mod-hidden');
3371 /* </DEPRECATED> */
3372 }
3373 // Update the fixed space for the visible items.
3374 this._fixed =
3375 this._spacing * Math.max(0, nVisible - 1) +
3376 this.widgetOffset * this._items.length;
3377 // Setup the computed minimum size.
3378 var horz = this._orientation === 'horizontal';
3379 var minW = horz ? this._fixed : 0;
3380 var minH = horz ? 0 : this._fixed;
3381 // Update the sizers and computed size limits.
3382 for (var i = 0, n = this._items.length; i < n; ++i) {
3383 // Fetch the item and corresponding box sizer.
3384 var item = this._items[i];
3385 var sizer = this._sizers[i];
3386 // Prevent resizing unless necessary.
3387 if (sizer.size > 0) {
3388 sizer.sizeHint = sizer.size;
3389 }
3390 // If the item is hidden, it should consume zero size.
3391 if (item.isHidden) {
3392 sizer.minSize = 0;
3393 sizer.maxSize = 0;
3394 continue;
3395 }
3396 // Update the size limits for the item.
3397 item.fit();
3398 // Update the stretch factor.
3399 sizer.stretch = SplitLayout.getStretch(item.widget);
3400 // Update the sizer limits and computed min size.
3401 if (horz) {
3402 sizer.minSize = item.minWidth;
3403 sizer.maxSize = item.maxWidth;
3404 minW += item.minWidth;
3405 minH = Math.max(minH, item.minHeight);
3406 }
3407 else {
3408 sizer.minSize = item.minHeight;
3409 sizer.maxSize = item.maxHeight;
3410 minH += item.minHeight;
3411 minW = Math.max(minW, item.minWidth);
3412 }
3413 }
3414 // Update the box sizing and add it to the computed min size.
3415 var box = (this._box = ElementExt.boxSizing(this.parent.node));
3416 minW += box.horizontalSum;
3417 minH += box.verticalSum;
3418 // Update the parent's min size constraints.
3419 var style = this.parent.node.style;
3420 style.minWidth = minW + "px";
3421 style.minHeight = minH + "px";
3422 // Set the dirty flag to ensure only a single update occurs.
3423 this._dirty = true;
3424 // Notify the ancestor that it should fit immediately. This may
3425 // cause a resize of the parent, fulfilling the required update.
3426 if (this.parent.parent) {
3427 MessageLoop.sendMessage(this.parent.parent, Widget.Msg.FitRequest);
3428 }
3429 // If the dirty flag is still set, the parent was not resized.
3430 // Trigger the required update on the parent widget immediately.
3431 if (this._dirty) {
3432 MessageLoop.sendMessage(this.parent, Widget.Msg.UpdateRequest);
3433 }
3434 };
3435 /**
3436 * Update the layout position and size of the widgets.
3437 *
3438 * The parent offset dimensions should be `-1` if unknown.
3439 */
3440 SplitLayout.prototype._update = function (offsetWidth, offsetHeight) {
3441 // Clear the dirty flag to indicate the update occurred.
3442 this._dirty = false;
3443 // Compute the visible item count.
3444 var nVisible = 0;
3445 for (var i = 0, n = this._items.length; i < n; ++i) {
3446 nVisible += +!this._items[i].isHidden;
3447 }
3448 // Bail early if there are no visible items to layout.
3449 if (nVisible === 0 && this.widgetOffset === 0) {
3450 return;
3451 }
3452 // Measure the parent if the offset dimensions are unknown.
3453 if (offsetWidth < 0) {
3454 offsetWidth = this.parent.node.offsetWidth;
3455 }
3456 if (offsetHeight < 0) {
3457 offsetHeight = this.parent.node.offsetHeight;
3458 }
3459 // Ensure the parent box sizing data is computed.
3460 if (!this._box) {
3461 this._box = ElementExt.boxSizing(this.parent.node);
3462 }
3463 // Compute the actual layout bounds adjusted for border and padding.
3464 var top = this._box.paddingTop;
3465 var left = this._box.paddingLeft;
3466 var width = offsetWidth - this._box.horizontalSum;
3467 var height = offsetHeight - this._box.verticalSum;
3468 // Set up the variables for justification and alignment offset.
3469 var extra = 0;
3470 var offset = 0;
3471 var horz = this._orientation === 'horizontal';
3472 if (nVisible > 0) {
3473 // Compute the adjusted layout space.
3474 var space = void 0;
3475 if (horz) {
3476 // left += this.widgetOffset;
3477 space = Math.max(0, width - this._fixed);
3478 }
3479 else {
3480 // top += this.widgetOffset;
3481 space = Math.max(0, height - this._fixed);
3482 }
3483 // Scale the size hints if they are normalized.
3484 if (this._hasNormedSizes) {
3485 for (var _i = 0, _a = this._sizers; _i < _a.length; _i++) {
3486 var sizer = _a[_i];
3487 sizer.sizeHint *= space;
3488 }
3489 this._hasNormedSizes = false;
3490 }
3491 // Distribute the layout space to the box sizers.
3492 var delta = BoxEngine.calc(this._sizers, space);
3493 // Account for alignment if there is extra layout space.
3494 if (delta > 0) {
3495 switch (this._alignment) {
3496 case 'start':
3497 break;
3498 case 'center':
3499 extra = 0;
3500 offset = delta / 2;
3501 break;
3502 case 'end':
3503 extra = 0;
3504 offset = delta;
3505 break;
3506 case 'justify':
3507 extra = delta / nVisible;
3508 offset = 0;
3509 break;
3510 default:
3511 throw 'unreachable';
3512 }
3513 }
3514 }
3515 // Layout the items using the computed box sizes.
3516 for (var i = 0, n = this._items.length; i < n; ++i) {
3517 // Fetch the item.
3518 var item = this._items[i];
3519 // Fetch the computed size for the widget.
3520 var size = item.isHidden ? 0 : this._sizers[i].size + extra;
3521 this.updateItemPosition(i, horz, horz ? left + offset : left, horz ? top : top + offset, height, width, size);
3522 var fullOffset = this.widgetOffset +
3523 (this._handles[i].classList.contains('lm-mod-hidden')
3524 ? 0
3525 : this._spacing);
3526 if (horz) {
3527 left += size + fullOffset;
3528 }
3529 else {
3530 top += size + fullOffset;
3531 }
3532 }
3533 };
3534 return SplitLayout;
3535}(PanelLayout));
3536/**
3537 * The namespace for the `SplitLayout` class statics.
3538 */
3539(function (SplitLayout) {
3540 /**
3541 * Get the split layout stretch factor for the given widget.
3542 *
3543 * @param widget - The widget of interest.
3544 *
3545 * @returns The split layout stretch factor for the widget.
3546 */
3547 function getStretch(widget) {
3548 return Private$h.stretchProperty.get(widget);
3549 }
3550 SplitLayout.getStretch = getStretch;
3551 /**
3552 * Set the split layout stretch factor for the given widget.
3553 *
3554 * @param widget - The widget of interest.
3555 *
3556 * @param value - The value for the stretch factor.
3557 */
3558 function setStretch(widget, value) {
3559 Private$h.stretchProperty.set(widget, value);
3560 }
3561 SplitLayout.setStretch = setStretch;
3562})(SplitLayout || (SplitLayout = {}));
3563/**
3564 * The namespace for the module implementation details.
3565 */
3566var Private$h;
3567(function (Private) {
3568 /**
3569 * The property descriptor for a widget stretch factor.
3570 */
3571 Private.stretchProperty = new AttachedProperty({
3572 name: 'stretch',
3573 create: function () { return 0; },
3574 coerce: function (owner, value) { return Math.max(0, Math.floor(value)); },
3575 changed: onChildSizingChanged
3576 });
3577 /**
3578 * Create a new box sizer with the given size hint.
3579 */
3580 function createSizer(size) {
3581 var sizer = new BoxSizer();
3582 sizer.sizeHint = Math.floor(size);
3583 return sizer;
3584 }
3585 Private.createSizer = createSizer;
3586 /**
3587 * Create a new split handle node using the given renderer.
3588 */
3589 function createHandle(renderer) {
3590 var handle = renderer.createHandle();
3591 handle.style.position = 'absolute';
3592 return handle;
3593 }
3594 Private.createHandle = createHandle;
3595 /**
3596 * Compute the average size of an array of box sizers.
3597 */
3598 function averageSize(sizers) {
3599 return sizers.reduce(function (v, s) { return v + s.size; }, 0) / sizers.length || 0;
3600 }
3601 Private.averageSize = averageSize;
3602 /**
3603 * Normalize an array of values.
3604 */
3605 function normalize(values) {
3606 var n = values.length;
3607 if (n === 0) {
3608 return [];
3609 }
3610 var sum = values.reduce(function (a, b) { return a + Math.abs(b); }, 0);
3611 return sum === 0 ? values.map(function (v) { return 1 / n; }) : values.map(function (v) { return v / sum; });
3612 }
3613 Private.normalize = normalize;
3614 /**
3615 * The change handler for the attached sizing properties.
3616 */
3617 function onChildSizingChanged(child) {
3618 if (child.parent && child.parent.layout instanceof SplitLayout) {
3619 child.parent.fit();
3620 }
3621 }
3622})(Private$h || (Private$h = {}));
3623
3624/**
3625 * A layout which arranges its widgets into collapsible resizable sections.
3626 */
3627var AccordionLayout = /** @class */ (function (_super) {
3628 __extends(AccordionLayout, _super);
3629 /**
3630 * Construct a new accordion layout.
3631 *
3632 * @param options - The options for initializing the layout.
3633 *
3634 * #### Notes
3635 * The default orientation will be vertical.
3636 *
3637 * Titles must be rotated for horizontal accordion panel using CSS: see accordionpanel.css
3638 */
3639 function AccordionLayout(options) {
3640 var _this = _super.call(this, __assign(__assign({}, options), { orientation: options.orientation || 'vertical' })) || this;
3641 _this._titles = [];
3642 _this.titleSpace = options.titleSpace || 22;
3643 return _this;
3644 }
3645 Object.defineProperty(AccordionLayout.prototype, "titleSpace", {
3646 /**
3647 * The section title height or width depending on the orientation.
3648 */
3649 get: function () {
3650 return this.widgetOffset;
3651 },
3652 set: function (value) {
3653 value = Utils$1.clampDimension(value);
3654 if (this.widgetOffset === value) {
3655 return;
3656 }
3657 this.widgetOffset = value;
3658 if (!this.parent) {
3659 return;
3660 }
3661 this.parent.fit();
3662 },
3663 enumerable: true,
3664 configurable: true
3665 });
3666 Object.defineProperty(AccordionLayout.prototype, "titles", {
3667 /**
3668 * A read-only array of the section titles in the panel.
3669 */
3670 get: function () {
3671 return this._titles;
3672 },
3673 enumerable: true,
3674 configurable: true
3675 });
3676 /**
3677 * Dispose of the resources held by the layout.
3678 */
3679 AccordionLayout.prototype.dispose = function () {
3680 if (this.isDisposed) {
3681 return;
3682 }
3683 // Clear the layout state.
3684 this._titles.length = 0;
3685 // Dispose of the rest of the layout.
3686 _super.prototype.dispose.call(this);
3687 };
3688 AccordionLayout.prototype.updateTitle = function (index, widget) {
3689 var oldTitle = this._titles[index];
3690 var expanded = oldTitle.classList.contains('lm-mod-expanded');
3691 var newTitle = Private$g.createTitle(this.renderer, widget.title, expanded);
3692 this._titles[index] = newTitle;
3693 // Add the title node to the parent before the widget.
3694 this.parent.node.replaceChild(newTitle, oldTitle);
3695 };
3696 /**
3697 * Attach a widget to the parent's DOM node.
3698 *
3699 * @param index - The current index of the widget in the layout.
3700 *
3701 * @param widget - The widget to attach to the parent.
3702 */
3703 AccordionLayout.prototype.attachWidget = function (index, widget) {
3704 var title = Private$g.createTitle(this.renderer, widget.title);
3705 ArrayExt.insert(this._titles, index, title);
3706 // Add the title node to the parent before the widget.
3707 this.parent.node.appendChild(title);
3708 widget.node.setAttribute('role', 'region');
3709 widget.node.setAttribute('aria-labelledby', title.id);
3710 _super.prototype.attachWidget.call(this, index, widget);
3711 };
3712 /**
3713 * Move a widget in the parent's DOM node.
3714 *
3715 * @param fromIndex - The previous index of the widget in the layout.
3716 *
3717 * @param toIndex - The current index of the widget in the layout.
3718 *
3719 * @param widget - The widget to move in the parent.
3720 */
3721 AccordionLayout.prototype.moveWidget = function (fromIndex, toIndex, widget) {
3722 ArrayExt.move(this._titles, fromIndex, toIndex);
3723 _super.prototype.moveWidget.call(this, fromIndex, toIndex, widget);
3724 };
3725 /**
3726 * Detach a widget from the parent's DOM node.
3727 *
3728 * @param index - The previous index of the widget in the layout.
3729 *
3730 * @param widget - The widget to detach from the parent.
3731 *
3732 * #### Notes
3733 * This is a reimplementation of the superclass method.
3734 */
3735 AccordionLayout.prototype.detachWidget = function (index, widget) {
3736 var title = ArrayExt.removeAt(this._titles, index);
3737 this.parent.node.removeChild(title);
3738 _super.prototype.detachWidget.call(this, index, widget);
3739 };
3740 /**
3741 * Update the item position.
3742 *
3743 * @param i Item index
3744 * @param isHorizontal Whether the layout is horizontal or not
3745 * @param left Left position in pixels
3746 * @param top Top position in pixels
3747 * @param height Item height
3748 * @param width Item width
3749 * @param size Item size
3750 */
3751 AccordionLayout.prototype.updateItemPosition = function (i, isHorizontal, left, top, height, width, size) {
3752 var titleStyle = this._titles[i].style;
3753 // Titles must be rotated for horizontal accordion panel using CSS: see accordionpanel.css
3754 titleStyle.top = top + "px";
3755 titleStyle.left = left + "px";
3756 titleStyle.height = this.widgetOffset + "px";
3757 if (isHorizontal) {
3758 titleStyle.width = height + "px";
3759 }
3760 else {
3761 titleStyle.width = width + "px";
3762 }
3763 _super.prototype.updateItemPosition.call(this, i, isHorizontal, left, top, height, width, size);
3764 };
3765 return AccordionLayout;
3766}(SplitLayout));
3767var Private$g;
3768(function (Private) {
3769 /**
3770 * Create the title HTML element.
3771 *
3772 * @param renderer Accordion renderer
3773 * @param data Widget title
3774 * @returns Title HTML element
3775 */
3776 function createTitle(renderer, data, expanded) {
3777 if (expanded === void 0) { expanded = true; }
3778 var title = renderer.createSectionTitle(data);
3779 title.style.position = 'absolute';
3780 title.setAttribute('aria-label', data.label + " Section");
3781 title.setAttribute('aria-expanded', expanded ? 'true' : 'false');
3782 title.setAttribute('aria-controls', data.owner.id);
3783 if (expanded) {
3784 title.classList.add('lm-mod-expanded');
3785 }
3786 return title;
3787 }
3788 Private.createTitle = createTitle;
3789})(Private$g || (Private$g = {}));
3790
3791/**
3792 * A simple and convenient panel widget class.
3793 *
3794 * #### Notes
3795 * This class is suitable as a base class for implementing a variety of
3796 * convenience panel widgets, but can also be used directly with CSS to
3797 * arrange a collection of widgets.
3798 *
3799 * This class provides a convenience wrapper around a [[PanelLayout]].
3800 */
3801var Panel = /** @class */ (function (_super) {
3802 __extends(Panel, _super);
3803 /**
3804 * Construct a new panel.
3805 *
3806 * @param options - The options for initializing the panel.
3807 */
3808 function Panel(options) {
3809 if (options === void 0) { options = {}; }
3810 var _this = _super.call(this) || this;
3811 _this.addClass('lm-Panel');
3812 /* <DEPRECATED> */
3813 _this.addClass('p-Panel');
3814 /* </DEPRECATED> */
3815 _this.layout = Private$f.createLayout(options);
3816 return _this;
3817 }
3818 Object.defineProperty(Panel.prototype, "widgets", {
3819 /**
3820 * A read-only array of the widgets in the panel.
3821 */
3822 get: function () {
3823 return this.layout.widgets;
3824 },
3825 enumerable: true,
3826 configurable: true
3827 });
3828 /**
3829 * Add a widget to the end of the panel.
3830 *
3831 * @param widget - The widget to add to the panel.
3832 *
3833 * #### Notes
3834 * If the widget is already contained in the panel, it will be moved.
3835 */
3836 Panel.prototype.addWidget = function (widget) {
3837 this.layout.addWidget(widget);
3838 };
3839 /**
3840 * Insert a widget at the specified index.
3841 *
3842 * @param index - The index at which to insert the widget.
3843 *
3844 * @param widget - The widget to insert into to the panel.
3845 *
3846 * #### Notes
3847 * If the widget is already contained in the panel, it will be moved.
3848 */
3849 Panel.prototype.insertWidget = function (index, widget) {
3850 this.layout.insertWidget(index, widget);
3851 };
3852 return Panel;
3853}(Widget));
3854/**
3855 * The namespace for the module implementation details.
3856 */
3857var Private$f;
3858(function (Private) {
3859 /**
3860 * Create a panel layout for the given panel options.
3861 */
3862 function createLayout(options) {
3863 return options.layout || new PanelLayout();
3864 }
3865 Private.createLayout = createLayout;
3866})(Private$f || (Private$f = {}));
3867
3868/**
3869 * A panel which arranges its widgets into resizable sections.
3870 *
3871 * #### Notes
3872 * This class provides a convenience wrapper around a [[SplitLayout]].
3873 */
3874var SplitPanel = /** @class */ (function (_super) {
3875 __extends(SplitPanel, _super);
3876 /**
3877 * Construct a new split panel.
3878 *
3879 * @param options - The options for initializing the split panel.
3880 */
3881 function SplitPanel(options) {
3882 if (options === void 0) { options = {}; }
3883 var _this = _super.call(this, { layout: Private$e.createLayout(options) }) || this;
3884 _this._handleMoved = new Signal(_this);
3885 _this._pressData = null;
3886 _this.addClass('lm-SplitPanel');
3887 /* <DEPRECATED> */
3888 _this.addClass('p-SplitPanel');
3889 return _this;
3890 /* </DEPRECATED> */
3891 }
3892 /**
3893 * Dispose of the resources held by the panel.
3894 */
3895 SplitPanel.prototype.dispose = function () {
3896 this._releaseMouse();
3897 _super.prototype.dispose.call(this);
3898 };
3899 Object.defineProperty(SplitPanel.prototype, "orientation", {
3900 /**
3901 * Get the layout orientation for the split panel.
3902 */
3903 get: function () {
3904 return this.layout.orientation;
3905 },
3906 /**
3907 * Set the layout orientation for the split panel.
3908 */
3909 set: function (value) {
3910 this.layout.orientation = value;
3911 },
3912 enumerable: true,
3913 configurable: true
3914 });
3915 Object.defineProperty(SplitPanel.prototype, "alignment", {
3916 /**
3917 * Get the content alignment for the split panel.
3918 *
3919 * #### Notes
3920 * This is the alignment of the widgets in the layout direction.
3921 *
3922 * The alignment has no effect if the widgets can expand to fill the
3923 * entire split panel.
3924 */
3925 get: function () {
3926 return this.layout.alignment;
3927 },
3928 /**
3929 * Set the content alignment for the split panel.
3930 *
3931 * #### Notes
3932 * This is the alignment of the widgets in the layout direction.
3933 *
3934 * The alignment has no effect if the widgets can expand to fill the
3935 * entire split panel.
3936 */
3937 set: function (value) {
3938 this.layout.alignment = value;
3939 },
3940 enumerable: true,
3941 configurable: true
3942 });
3943 Object.defineProperty(SplitPanel.prototype, "spacing", {
3944 /**
3945 * Get the inter-element spacing for the split panel.
3946 */
3947 get: function () {
3948 return this.layout.spacing;
3949 },
3950 /**
3951 * Set the inter-element spacing for the split panel.
3952 */
3953 set: function (value) {
3954 this.layout.spacing = value;
3955 },
3956 enumerable: true,
3957 configurable: true
3958 });
3959 Object.defineProperty(SplitPanel.prototype, "renderer", {
3960 /**
3961 * The renderer used by the split panel.
3962 */
3963 get: function () {
3964 return this.layout.renderer;
3965 },
3966 enumerable: true,
3967 configurable: true
3968 });
3969 Object.defineProperty(SplitPanel.prototype, "handleMoved", {
3970 /**
3971 * A signal emitted when a split handle has moved.
3972 */
3973 get: function () {
3974 return this._handleMoved;
3975 },
3976 enumerable: true,
3977 configurable: true
3978 });
3979 Object.defineProperty(SplitPanel.prototype, "handles", {
3980 /**
3981 * A read-only array of the split handles in the panel.
3982 */
3983 get: function () {
3984 return this.layout.handles;
3985 },
3986 enumerable: true,
3987 configurable: true
3988 });
3989 /**
3990 * Get the relative sizes of the widgets in the panel.
3991 *
3992 * @returns A new array of the relative sizes of the widgets.
3993 *
3994 * #### Notes
3995 * The returned sizes reflect the sizes of the widgets normalized
3996 * relative to their siblings.
3997 *
3998 * This method **does not** measure the DOM nodes.
3999 */
4000 SplitPanel.prototype.relativeSizes = function () {
4001 return this.layout.relativeSizes();
4002 };
4003 /**
4004 * Set the relative sizes for the widgets in the panel.
4005 *
4006 * @param sizes - The relative sizes for the widgets in the panel.
4007 *
4008 * #### Notes
4009 * Extra values are ignored, too few will yield an undefined layout.
4010 *
4011 * The actual geometry of the DOM nodes is updated asynchronously.
4012 */
4013 SplitPanel.prototype.setRelativeSizes = function (sizes) {
4014 this.layout.setRelativeSizes(sizes);
4015 };
4016 /**
4017 * Handle the DOM events for the split panel.
4018 *
4019 * @param event - The DOM event sent to the panel.
4020 *
4021 * #### Notes
4022 * This method implements the DOM `EventListener` interface and is
4023 * called in response to events on the panel's DOM node. It should
4024 * not be called directly by user code.
4025 */
4026 SplitPanel.prototype.handleEvent = function (event) {
4027 switch (event.type) {
4028 case 'mousedown':
4029 this._evtMouseDown(event);
4030 break;
4031 case 'mousemove':
4032 this._evtMouseMove(event);
4033 break;
4034 case 'mouseup':
4035 this._evtMouseUp(event);
4036 break;
4037 case 'pointerdown':
4038 this._evtMouseDown(event);
4039 break;
4040 case 'pointermove':
4041 this._evtMouseMove(event);
4042 break;
4043 case 'pointerup':
4044 this._evtMouseUp(event);
4045 break;
4046 case 'keydown':
4047 this._evtKeyDown(event);
4048 break;
4049 case 'contextmenu':
4050 event.preventDefault();
4051 event.stopPropagation();
4052 break;
4053 }
4054 };
4055 /**
4056 * A message handler invoked on a `'before-attach'` message.
4057 */
4058 SplitPanel.prototype.onBeforeAttach = function (msg) {
4059 this.node.addEventListener('mousedown', this);
4060 this.node.addEventListener('pointerdown', this);
4061 };
4062 /**
4063 * A message handler invoked on an `'after-detach'` message.
4064 */
4065 SplitPanel.prototype.onAfterDetach = function (msg) {
4066 this.node.removeEventListener('mousedown', this);
4067 this.node.removeEventListener('pointerdown', this);
4068 this._releaseMouse();
4069 };
4070 /**
4071 * A message handler invoked on a `'child-added'` message.
4072 */
4073 SplitPanel.prototype.onChildAdded = function (msg) {
4074 msg.child.addClass('lm-SplitPanel-child');
4075 /* <DEPRECATED> */
4076 msg.child.addClass('p-SplitPanel-child');
4077 /* </DEPRECATED> */
4078 this._releaseMouse();
4079 };
4080 /**
4081 * A message handler invoked on a `'child-removed'` message.
4082 */
4083 SplitPanel.prototype.onChildRemoved = function (msg) {
4084 msg.child.removeClass('lm-SplitPanel-child');
4085 /* <DEPRECATED> */
4086 msg.child.removeClass('p-SplitPanel-child');
4087 /* </DEPRECATED> */
4088 this._releaseMouse();
4089 };
4090 /**
4091 * Handle the `'keydown'` event for the split panel.
4092 */
4093 SplitPanel.prototype._evtKeyDown = function (event) {
4094 // Stop input events during drag.
4095 if (this._pressData) {
4096 event.preventDefault();
4097 event.stopPropagation();
4098 }
4099 // Release the mouse if `Escape` is pressed.
4100 if (event.keyCode === 27) {
4101 this._releaseMouse();
4102 }
4103 };
4104 /**
4105 * Handle the `'mousedown'` event for the split panel.
4106 */
4107 SplitPanel.prototype._evtMouseDown = function (event) {
4108 // Do nothing if the left mouse button is not pressed.
4109 if (event.button !== 0) {
4110 return;
4111 }
4112 // Find the handle which contains the mouse target, if any.
4113 var layout = this.layout;
4114 var index = ArrayExt.findFirstIndex(layout.handles, function (handle) {
4115 return handle.contains(event.target);
4116 });
4117 // Bail early if the mouse press was not on a handle.
4118 if (index === -1) {
4119 return;
4120 }
4121 // Stop the event when a split handle is pressed.
4122 event.preventDefault();
4123 event.stopPropagation();
4124 // Add the extra document listeners.
4125 document.addEventListener('mouseup', this, true);
4126 document.addEventListener('mousemove', this, true);
4127 document.addEventListener('pointerup', this, true);
4128 document.addEventListener('pointermove', this, true);
4129 document.addEventListener('keydown', this, true);
4130 document.addEventListener('contextmenu', this, true);
4131 // Compute the offset delta for the handle press.
4132 var delta;
4133 var handle = layout.handles[index];
4134 var rect = handle.getBoundingClientRect();
4135 if (layout.orientation === 'horizontal') {
4136 delta = event.clientX - rect.left;
4137 }
4138 else {
4139 delta = event.clientY - rect.top;
4140 }
4141 // Override the cursor and store the press data.
4142 var style = window.getComputedStyle(handle);
4143 var override = Drag.overrideCursor(style.cursor);
4144 this._pressData = { index: index, delta: delta, override: override };
4145 };
4146 /**
4147 * Handle the `'mousemove'` event for the split panel.
4148 */
4149 SplitPanel.prototype._evtMouseMove = function (event) {
4150 // Stop the event when dragging a split handle.
4151 event.preventDefault();
4152 event.stopPropagation();
4153 // Compute the desired offset position for the handle.
4154 var pos;
4155 var layout = this.layout;
4156 var rect = this.node.getBoundingClientRect();
4157 if (layout.orientation === 'horizontal') {
4158 pos = event.clientX - rect.left - this._pressData.delta;
4159 }
4160 else {
4161 pos = event.clientY - rect.top - this._pressData.delta;
4162 }
4163 // Move the handle as close to the desired position as possible.
4164 layout.moveHandle(this._pressData.index, pos);
4165 };
4166 /**
4167 * Handle the `'mouseup'` event for the split panel.
4168 */
4169 SplitPanel.prototype._evtMouseUp = function (event) {
4170 // Do nothing if the left mouse button is not released.
4171 if (event.button !== 0) {
4172 return;
4173 }
4174 // Stop the event when releasing a handle.
4175 event.preventDefault();
4176 event.stopPropagation();
4177 // Finalize the mouse release.
4178 this._releaseMouse();
4179 };
4180 /**
4181 * Release the mouse grab for the split panel.
4182 */
4183 SplitPanel.prototype._releaseMouse = function () {
4184 // Bail early if no drag is in progress.
4185 if (!this._pressData) {
4186 return;
4187 }
4188 // Clear the override cursor.
4189 this._pressData.override.dispose();
4190 this._pressData = null;
4191 // Emit the handle moved signal.
4192 this._handleMoved.emit();
4193 // Remove the extra document listeners.
4194 document.removeEventListener('mouseup', this, true);
4195 document.removeEventListener('mousemove', this, true);
4196 document.removeEventListener('keydown', this, true);
4197 document.removeEventListener('pointerup', this, true);
4198 document.removeEventListener('pointermove', this, true);
4199 document.removeEventListener('contextmenu', this, true);
4200 };
4201 return SplitPanel;
4202}(Panel));
4203/**
4204 * The namespace for the `SplitPanel` class statics.
4205 */
4206(function (SplitPanel) {
4207 /**
4208 * The default implementation of `IRenderer`.
4209 */
4210 var Renderer = /** @class */ (function () {
4211 function Renderer() {
4212 }
4213 /**
4214 * Create a new handle for use with a split panel.
4215 *
4216 * @returns A new handle element for a split panel.
4217 */
4218 Renderer.prototype.createHandle = function () {
4219 var handle = document.createElement('div');
4220 handle.className = 'lm-SplitPanel-handle';
4221 /* <DEPRECATED> */
4222 handle.classList.add('p-SplitPanel-handle');
4223 /* </DEPRECATED> */
4224 return handle;
4225 };
4226 return Renderer;
4227 }());
4228 SplitPanel.Renderer = Renderer;
4229 /**
4230 * The default `Renderer` instance.
4231 */
4232 SplitPanel.defaultRenderer = new Renderer();
4233 /**
4234 * Get the split panel stretch factor for the given widget.
4235 *
4236 * @param widget - The widget of interest.
4237 *
4238 * @returns The split panel stretch factor for the widget.
4239 */
4240 function getStretch(widget) {
4241 return SplitLayout.getStretch(widget);
4242 }
4243 SplitPanel.getStretch = getStretch;
4244 /**
4245 * Set the split panel stretch factor for the given widget.
4246 *
4247 * @param widget - The widget of interest.
4248 *
4249 * @param value - The value for the stretch factor.
4250 */
4251 function setStretch(widget, value) {
4252 SplitLayout.setStretch(widget, value);
4253 }
4254 SplitPanel.setStretch = setStretch;
4255})(SplitPanel || (SplitPanel = {}));
4256/**
4257 * The namespace for the module implementation details.
4258 */
4259var Private$e;
4260(function (Private) {
4261 /**
4262 * Create a split layout for the given panel options.
4263 */
4264 function createLayout(options) {
4265 return (options.layout ||
4266 new SplitLayout({
4267 renderer: options.renderer || SplitPanel.defaultRenderer,
4268 orientation: options.orientation,
4269 alignment: options.alignment,
4270 spacing: options.spacing
4271 }));
4272 }
4273 Private.createLayout = createLayout;
4274})(Private$e || (Private$e = {}));
4275
4276// Copyright (c) Jupyter Development Team.
4277/**
4278 * A panel which arranges its widgets into resizable sections separated by a title widget.
4279 *
4280 * #### Notes
4281 * This class provides a convenience wrapper around [[AccordionLayout]].
4282 */
4283var AccordionPanel = /** @class */ (function (_super) {
4284 __extends(AccordionPanel, _super);
4285 /**
4286 * Construct a new accordion panel.
4287 *
4288 * @param options - The options for initializing the accordion panel.
4289 */
4290 function AccordionPanel(options) {
4291 if (options === void 0) { options = {}; }
4292 var _this = _super.call(this, __assign(__assign({}, options), { layout: Private$d.createLayout(options) })) || this;
4293 _this.addClass('lm-AccordionPanel');
4294 return _this;
4295 }
4296 Object.defineProperty(AccordionPanel.prototype, "renderer", {
4297 /**
4298 * The renderer used by the accordion panel.
4299 */
4300 get: function () {
4301 return this.layout.renderer;
4302 },
4303 enumerable: true,
4304 configurable: true
4305 });
4306 Object.defineProperty(AccordionPanel.prototype, "titleSpace", {
4307 /**
4308 * The section title space.
4309 *
4310 * This is the height if the panel is vertical and the width if it is
4311 * horizontal.
4312 */
4313 get: function () {
4314 return this.layout.titleSpace;
4315 },
4316 set: function (value) {
4317 this.layout.titleSpace = value;
4318 },
4319 enumerable: true,
4320 configurable: true
4321 });
4322 Object.defineProperty(AccordionPanel.prototype, "titles", {
4323 /**
4324 * A read-only array of the section titles in the panel.
4325 */
4326 get: function () {
4327 return this.layout.titles;
4328 },
4329 enumerable: true,
4330 configurable: true
4331 });
4332 /**
4333 * Add a widget to the end of the panel.
4334 *
4335 * @param widget - The widget to add to the panel.
4336 *
4337 * #### Notes
4338 * If the widget is already contained in the panel, it will be moved.
4339 */
4340 AccordionPanel.prototype.addWidget = function (widget) {
4341 _super.prototype.addWidget.call(this, widget);
4342 widget.title.changed.connect(this._onTitleChanged, this);
4343 };
4344 /**
4345 * Insert a widget at the specified index.
4346 *
4347 * @param index - The index at which to insert the widget.
4348 *
4349 * @param widget - The widget to insert into to the panel.
4350 *
4351 * #### Notes
4352 * If the widget is already contained in the panel, it will be moved.
4353 */
4354 AccordionPanel.prototype.insertWidget = function (index, widget) {
4355 _super.prototype.insertWidget.call(this, index, widget);
4356 widget.title.changed.connect(this._onTitleChanged, this);
4357 };
4358 /**
4359 * Handle the DOM events for the accordion panel.
4360 *
4361 * @param event - The DOM event sent to the panel.
4362 *
4363 * #### Notes
4364 * This method implements the DOM `EventListener` interface and is
4365 * called in response to events on the panel's DOM node. It should
4366 * not be called directly by user code.
4367 */
4368 AccordionPanel.prototype.handleEvent = function (event) {
4369 _super.prototype.handleEvent.call(this, event);
4370 switch (event.type) {
4371 case 'click':
4372 this._evtClick(event);
4373 break;
4374 case 'keydown':
4375 this._eventKeyDown(event);
4376 break;
4377 }
4378 };
4379 /**
4380 * A message handler invoked on a `'before-attach'` message.
4381 */
4382 AccordionPanel.prototype.onBeforeAttach = function (msg) {
4383 this.node.addEventListener('click', this);
4384 this.node.addEventListener('keydown', this);
4385 _super.prototype.onBeforeAttach.call(this, msg);
4386 };
4387 /**
4388 * A message handler invoked on an `'after-detach'` message.
4389 */
4390 AccordionPanel.prototype.onAfterDetach = function (msg) {
4391 _super.prototype.onAfterDetach.call(this, msg);
4392 this.node.removeEventListener('click', this);
4393 this.node.removeEventListener('keydown', this);
4394 };
4395 /**
4396 * Handle the `changed` signal of a title object.
4397 */
4398 AccordionPanel.prototype._onTitleChanged = function (sender) {
4399 var index = ArrayExt.findFirstIndex(this.widgets, function (widget) {
4400 return widget.contains(sender.owner);
4401 });
4402 if (index >= 0) {
4403 this.layout.updateTitle(index, sender.owner);
4404 this.update();
4405 }
4406 };
4407 /**
4408 * Handle the `'click'` event for the accordion panel
4409 */
4410 AccordionPanel.prototype._evtClick = function (event) {
4411 var target = event.target;
4412 if (target) {
4413 var index = ArrayExt.findFirstIndex(this.titles, function (title) {
4414 return title.contains(target);
4415 });
4416 if (index >= 0) {
4417 event.preventDefault();
4418 event.stopPropagation();
4419 var title = this.titles[index];
4420 var widget = this.layout.widgets[index];
4421 if (widget.isHidden) {
4422 title.classList.add('lm-mod-expanded');
4423 title.setAttribute('aria-expanded', 'true');
4424 widget.show();
4425 }
4426 else {
4427 title.classList.remove('lm-mod-expanded');
4428 title.setAttribute('aria-expanded', 'false');
4429 widget.hide();
4430 }
4431 }
4432 }
4433 };
4434 /**
4435 * Handle the `'keydown'` event for the accordion panel.
4436 */
4437 AccordionPanel.prototype._eventKeyDown = function (event) {
4438 if (event.defaultPrevented) {
4439 return;
4440 }
4441 var target = event.target;
4442 var handled = false;
4443 if (target) {
4444 var index = ArrayExt.findFirstIndex(this.titles, function (title) {
4445 return title.contains(target);
4446 });
4447 if (index >= 0) {
4448 var keyCode = event.keyCode.toString();
4449 // If Space or Enter is pressed on title, emulate click event
4450 if (event.key.match(/Space|Enter/) || keyCode.match(/13|32/)) {
4451 target.click();
4452 handled = true;
4453 }
4454 else if (this.orientation === 'horizontal'
4455 ? event.key.match(/ArrowLeft|ArrowRight/) || keyCode.match(/37|39/)
4456 : event.key.match(/ArrowUp|ArrowDown/) || keyCode.match(/38|40/)) {
4457 // If Up or Down (for vertical) / Left or Right (for horizontal) is pressed on title, loop on titles
4458 var direction = event.key.match(/ArrowLeft|ArrowUp/) || keyCode.match(/37|38/)
4459 ? -1
4460 : 1;
4461 var length_1 = this.titles.length;
4462 var newIndex = (index + length_1 + direction) % length_1;
4463 this.titles[newIndex].focus();
4464 handled = true;
4465 }
4466 else if (event.key === 'End' || keyCode === '35') {
4467 // If End is pressed on title, focus on the last title
4468 this.titles[this.titles.length - 1].focus();
4469 handled = true;
4470 }
4471 else if (event.key === 'Home' || keyCode === '36') {
4472 // If Home is pressed on title, focus on the first title
4473 this.titles[0].focus();
4474 handled = true;
4475 }
4476 }
4477 if (handled) {
4478 event.preventDefault();
4479 }
4480 }
4481 };
4482 return AccordionPanel;
4483}(SplitPanel));
4484/**
4485 * The namespace for the `AccordionPanel` class statics.
4486 */
4487(function (AccordionPanel) {
4488 /**
4489 * The default implementation of `IRenderer`.
4490 */
4491 var Renderer = /** @class */ (function (_super) {
4492 __extends(Renderer, _super);
4493 function Renderer() {
4494 var _this = _super !== null && _super.apply(this, arguments) || this;
4495 /**
4496 * A selector which matches any title node in the accordion.
4497 */
4498 _this.titleClassName = 'lm-AccordionPanel-title';
4499 _this._titleID = 0;
4500 _this._titleKeys = new WeakMap();
4501 return _this;
4502 }
4503 /**
4504 * Render the collapse indicator for a section title.
4505 *
4506 * @param data - The data to use for rendering the section title.
4507 *
4508 * @returns A element representing the collapse indicator.
4509 */
4510 Renderer.prototype.createCollapseIcon = function (data) {
4511 return document.createElement('span');
4512 };
4513 /**
4514 * Render the element for a section title.
4515 *
4516 * @param data - The data to use for rendering the section title.
4517 *
4518 * @returns A element representing the section title.
4519 */
4520 Renderer.prototype.createSectionTitle = function (data) {
4521 var handle = document.createElement('h3');
4522 handle.setAttribute('role', 'button');
4523 handle.setAttribute('tabindex', '0');
4524 handle.id = this.createTitleKey(data);
4525 handle.className = this.titleClassName;
4526 handle.title = data.caption;
4527 for (var aData in data.dataset) {
4528 handle.dataset[aData] = data.dataset[aData];
4529 }
4530 var collapser = handle.appendChild(this.createCollapseIcon(data));
4531 collapser.className = 'lm-AccordionPanel-titleCollapser';
4532 var label = handle.appendChild(document.createElement('span'));
4533 label.className = 'lm-AccordionPanel-titleLabel';
4534 label.textContent = data.label;
4535 return handle;
4536 };
4537 /**
4538 * Create a unique render key for the title.
4539 *
4540 * @param data - The data to use for the title.
4541 *
4542 * @returns The unique render key for the title.
4543 *
4544 * #### Notes
4545 * This method caches the key against the section title the first time
4546 * the key is generated.
4547 */
4548 Renderer.prototype.createTitleKey = function (data) {
4549 var key = this._titleKeys.get(data);
4550 if (key === undefined) {
4551 key = "title-key-" + this._titleID++;
4552 this._titleKeys.set(data, key);
4553 }
4554 return key;
4555 };
4556 return Renderer;
4557 }(SplitPanel.Renderer));
4558 AccordionPanel.Renderer = Renderer;
4559 /**
4560 * The default `Renderer` instance.
4561 */
4562 AccordionPanel.defaultRenderer = new Renderer();
4563})(AccordionPanel || (AccordionPanel = {}));
4564var Private$d;
4565(function (Private) {
4566 /**
4567 * Create an accordion layout for the given panel options.
4568 *
4569 * @param options Panel options
4570 * @returns Panel layout
4571 */
4572 function createLayout(options) {
4573 return (options.layout ||
4574 new AccordionLayout({
4575 renderer: options.renderer || AccordionPanel.defaultRenderer,
4576 orientation: options.orientation,
4577 alignment: options.alignment,
4578 spacing: options.spacing,
4579 titleSpace: options.titleSpace
4580 }));
4581 }
4582 Private.createLayout = createLayout;
4583})(Private$d || (Private$d = {}));
4584
4585/**
4586 * A layout which arranges its widgets in a single row or column.
4587 */
4588var BoxLayout = /** @class */ (function (_super) {
4589 __extends(BoxLayout, _super);
4590 /**
4591 * Construct a new box layout.
4592 *
4593 * @param options - The options for initializing the layout.
4594 */
4595 function BoxLayout(options) {
4596 if (options === void 0) { options = {}; }
4597 var _this = _super.call(this) || this;
4598 _this._fixed = 0;
4599 _this._spacing = 4;
4600 _this._dirty = false;
4601 _this._sizers = [];
4602 _this._items = [];
4603 _this._box = null;
4604 _this._alignment = 'start';
4605 _this._direction = 'top-to-bottom';
4606 if (options.direction !== undefined) {
4607 _this._direction = options.direction;
4608 }
4609 if (options.alignment !== undefined) {
4610 _this._alignment = options.alignment;
4611 }
4612 if (options.spacing !== undefined) {
4613 _this._spacing = Utils$1.clampDimension(options.spacing);
4614 }
4615 return _this;
4616 }
4617 /**
4618 * Dispose of the resources held by the layout.
4619 */
4620 BoxLayout.prototype.dispose = function () {
4621 // Dispose of the layout items.
4622 each(this._items, function (item) {
4623 item.dispose();
4624 });
4625 // Clear the layout state.
4626 this._box = null;
4627 this._items.length = 0;
4628 this._sizers.length = 0;
4629 // Dispose of the rest of the layout.
4630 _super.prototype.dispose.call(this);
4631 };
4632 Object.defineProperty(BoxLayout.prototype, "direction", {
4633 /**
4634 * Get the layout direction for the box layout.
4635 */
4636 get: function () {
4637 return this._direction;
4638 },
4639 /**
4640 * Set the layout direction for the box layout.
4641 */
4642 set: function (value) {
4643 if (this._direction === value) {
4644 return;
4645 }
4646 this._direction = value;
4647 if (!this.parent) {
4648 return;
4649 }
4650 this.parent.dataset['direction'] = value;
4651 this.parent.fit();
4652 },
4653 enumerable: true,
4654 configurable: true
4655 });
4656 Object.defineProperty(BoxLayout.prototype, "alignment", {
4657 /**
4658 * Get the content alignment for the box layout.
4659 *
4660 * #### Notes
4661 * This is the alignment of the widgets in the layout direction.
4662 *
4663 * The alignment has no effect if the widgets can expand to fill the
4664 * entire box layout.
4665 */
4666 get: function () {
4667 return this._alignment;
4668 },
4669 /**
4670 * Set the content alignment for the box layout.
4671 *
4672 * #### Notes
4673 * This is the alignment of the widgets in the layout direction.
4674 *
4675 * The alignment has no effect if the widgets can expand to fill the
4676 * entire box layout.
4677 */
4678 set: function (value) {
4679 if (this._alignment === value) {
4680 return;
4681 }
4682 this._alignment = value;
4683 if (!this.parent) {
4684 return;
4685 }
4686 this.parent.dataset['alignment'] = value;
4687 this.parent.update();
4688 },
4689 enumerable: true,
4690 configurable: true
4691 });
4692 Object.defineProperty(BoxLayout.prototype, "spacing", {
4693 /**
4694 * Get the inter-element spacing for the box layout.
4695 */
4696 get: function () {
4697 return this._spacing;
4698 },
4699 /**
4700 * Set the inter-element spacing for the box layout.
4701 */
4702 set: function (value) {
4703 value = Utils$1.clampDimension(value);
4704 if (this._spacing === value) {
4705 return;
4706 }
4707 this._spacing = value;
4708 if (!this.parent) {
4709 return;
4710 }
4711 this.parent.fit();
4712 },
4713 enumerable: true,
4714 configurable: true
4715 });
4716 /**
4717 * Perform layout initialization which requires the parent widget.
4718 */
4719 BoxLayout.prototype.init = function () {
4720 this.parent.dataset['direction'] = this.direction;
4721 this.parent.dataset['alignment'] = this.alignment;
4722 _super.prototype.init.call(this);
4723 };
4724 /**
4725 * Attach a widget to the parent's DOM node.
4726 *
4727 * @param index - The current index of the widget in the layout.
4728 *
4729 * @param widget - The widget to attach to the parent.
4730 *
4731 * #### Notes
4732 * This is a reimplementation of the superclass method.
4733 */
4734 BoxLayout.prototype.attachWidget = function (index, widget) {
4735 // Create and add a new layout item for the widget.
4736 ArrayExt.insert(this._items, index, new LayoutItem(widget));
4737 // Create and add a new sizer for the widget.
4738 ArrayExt.insert(this._sizers, index, new BoxSizer());
4739 // Send a `'before-attach'` message if the parent is attached.
4740 if (this.parent.isAttached) {
4741 MessageLoop.sendMessage(widget, Widget.Msg.BeforeAttach);
4742 }
4743 // Add the widget's node to the parent.
4744 this.parent.node.appendChild(widget.node);
4745 // Send an `'after-attach'` message if the parent is attached.
4746 if (this.parent.isAttached) {
4747 MessageLoop.sendMessage(widget, Widget.Msg.AfterAttach);
4748 }
4749 // Post a fit request for the parent widget.
4750 this.parent.fit();
4751 };
4752 /**
4753 * Move a widget in the parent's DOM node.
4754 *
4755 * @param fromIndex - The previous index of the widget in the layout.
4756 *
4757 * @param toIndex - The current index of the widget in the layout.
4758 *
4759 * @param widget - The widget to move in the parent.
4760 *
4761 * #### Notes
4762 * This is a reimplementation of the superclass method.
4763 */
4764 BoxLayout.prototype.moveWidget = function (fromIndex, toIndex, widget) {
4765 // Move the layout item for the widget.
4766 ArrayExt.move(this._items, fromIndex, toIndex);
4767 // Move the sizer for the widget.
4768 ArrayExt.move(this._sizers, fromIndex, toIndex);
4769 // Post an update request for the parent widget.
4770 this.parent.update();
4771 };
4772 /**
4773 * Detach a widget from the parent's DOM node.
4774 *
4775 * @param index - The previous index of the widget in the layout.
4776 *
4777 * @param widget - The widget to detach from the parent.
4778 *
4779 * #### Notes
4780 * This is a reimplementation of the superclass method.
4781 */
4782 BoxLayout.prototype.detachWidget = function (index, widget) {
4783 // Remove the layout item for the widget.
4784 var item = ArrayExt.removeAt(this._items, index);
4785 // Remove the sizer for the widget.
4786 ArrayExt.removeAt(this._sizers, index);
4787 // Send a `'before-detach'` message if the parent is attached.
4788 if (this.parent.isAttached) {
4789 MessageLoop.sendMessage(widget, Widget.Msg.BeforeDetach);
4790 }
4791 // Remove the widget's node from the parent.
4792 this.parent.node.removeChild(widget.node);
4793 // Send an `'after-detach'` message if the parent is attached.
4794 if (this.parent.isAttached) {
4795 MessageLoop.sendMessage(widget, Widget.Msg.AfterDetach);
4796 }
4797 // Dispose of the layout item.
4798 item.dispose();
4799 // Post a fit request for the parent widget.
4800 this.parent.fit();
4801 };
4802 /**
4803 * A message handler invoked on a `'before-show'` message.
4804 */
4805 BoxLayout.prototype.onBeforeShow = function (msg) {
4806 _super.prototype.onBeforeShow.call(this, msg);
4807 this.parent.update();
4808 };
4809 /**
4810 * A message handler invoked on a `'before-attach'` message.
4811 */
4812 BoxLayout.prototype.onBeforeAttach = function (msg) {
4813 _super.prototype.onBeforeAttach.call(this, msg);
4814 this.parent.fit();
4815 };
4816 /**
4817 * A message handler invoked on a `'child-shown'` message.
4818 */
4819 BoxLayout.prototype.onChildShown = function (msg) {
4820 this.parent.fit();
4821 };
4822 /**
4823 * A message handler invoked on a `'child-hidden'` message.
4824 */
4825 BoxLayout.prototype.onChildHidden = function (msg) {
4826 this.parent.fit();
4827 };
4828 /**
4829 * A message handler invoked on a `'resize'` message.
4830 */
4831 BoxLayout.prototype.onResize = function (msg) {
4832 if (this.parent.isVisible) {
4833 this._update(msg.width, msg.height);
4834 }
4835 };
4836 /**
4837 * A message handler invoked on an `'update-request'` message.
4838 */
4839 BoxLayout.prototype.onUpdateRequest = function (msg) {
4840 if (this.parent.isVisible) {
4841 this._update(-1, -1);
4842 }
4843 };
4844 /**
4845 * A message handler invoked on a `'fit-request'` message.
4846 */
4847 BoxLayout.prototype.onFitRequest = function (msg) {
4848 if (this.parent.isAttached) {
4849 this._fit();
4850 }
4851 };
4852 /**
4853 * Fit the layout to the total size required by the widgets.
4854 */
4855 BoxLayout.prototype._fit = function () {
4856 // Compute the visible item count.
4857 var nVisible = 0;
4858 for (var i = 0, n = this._items.length; i < n; ++i) {
4859 nVisible += +!this._items[i].isHidden;
4860 }
4861 // Update the fixed space for the visible items.
4862 this._fixed = this._spacing * Math.max(0, nVisible - 1);
4863 // Setup the computed minimum size.
4864 var horz = Private$c.isHorizontal(this._direction);
4865 var minW = horz ? this._fixed : 0;
4866 var minH = horz ? 0 : this._fixed;
4867 // Update the sizers and computed minimum size.
4868 for (var i = 0, n = this._items.length; i < n; ++i) {
4869 // Fetch the item and corresponding box sizer.
4870 var item = this._items[i];
4871 var sizer = this._sizers[i];
4872 // If the item is hidden, it should consume zero size.
4873 if (item.isHidden) {
4874 sizer.minSize = 0;
4875 sizer.maxSize = 0;
4876 continue;
4877 }
4878 // Update the size limits for the item.
4879 item.fit();
4880 // Update the size basis and stretch factor.
4881 sizer.sizeHint = BoxLayout.getSizeBasis(item.widget);
4882 sizer.stretch = BoxLayout.getStretch(item.widget);
4883 // Update the sizer limits and computed min size.
4884 if (horz) {
4885 sizer.minSize = item.minWidth;
4886 sizer.maxSize = item.maxWidth;
4887 minW += item.minWidth;
4888 minH = Math.max(minH, item.minHeight);
4889 }
4890 else {
4891 sizer.minSize = item.minHeight;
4892 sizer.maxSize = item.maxHeight;
4893 minH += item.minHeight;
4894 minW = Math.max(minW, item.minWidth);
4895 }
4896 }
4897 // Update the box sizing and add it to the computed min size.
4898 var box = (this._box = ElementExt.boxSizing(this.parent.node));
4899 minW += box.horizontalSum;
4900 minH += box.verticalSum;
4901 // Update the parent's min size constraints.
4902 var style = this.parent.node.style;
4903 style.minWidth = minW + "px";
4904 style.minHeight = minH + "px";
4905 // Set the dirty flag to ensure only a single update occurs.
4906 this._dirty = true;
4907 // Notify the ancestor that it should fit immediately. This may
4908 // cause a resize of the parent, fulfilling the required update.
4909 if (this.parent.parent) {
4910 MessageLoop.sendMessage(this.parent.parent, Widget.Msg.FitRequest);
4911 }
4912 // If the dirty flag is still set, the parent was not resized.
4913 // Trigger the required update on the parent widget immediately.
4914 if (this._dirty) {
4915 MessageLoop.sendMessage(this.parent, Widget.Msg.UpdateRequest);
4916 }
4917 };
4918 /**
4919 * Update the layout position and size of the widgets.
4920 *
4921 * The parent offset dimensions should be `-1` if unknown.
4922 */
4923 BoxLayout.prototype._update = function (offsetWidth, offsetHeight) {
4924 // Clear the dirty flag to indicate the update occurred.
4925 this._dirty = false;
4926 // Compute the visible item count.
4927 var nVisible = 0;
4928 for (var i = 0, n = this._items.length; i < n; ++i) {
4929 nVisible += +!this._items[i].isHidden;
4930 }
4931 // Bail early if there are no visible items to layout.
4932 if (nVisible === 0) {
4933 return;
4934 }
4935 // Measure the parent if the offset dimensions are unknown.
4936 if (offsetWidth < 0) {
4937 offsetWidth = this.parent.node.offsetWidth;
4938 }
4939 if (offsetHeight < 0) {
4940 offsetHeight = this.parent.node.offsetHeight;
4941 }
4942 // Ensure the parent box sizing data is computed.
4943 if (!this._box) {
4944 this._box = ElementExt.boxSizing(this.parent.node);
4945 }
4946 // Compute the layout area adjusted for border and padding.
4947 var top = this._box.paddingTop;
4948 var left = this._box.paddingLeft;
4949 var width = offsetWidth - this._box.horizontalSum;
4950 var height = offsetHeight - this._box.verticalSum;
4951 // Distribute the layout space and adjust the start position.
4952 var delta;
4953 switch (this._direction) {
4954 case 'left-to-right':
4955 delta = BoxEngine.calc(this._sizers, Math.max(0, width - this._fixed));
4956 break;
4957 case 'top-to-bottom':
4958 delta = BoxEngine.calc(this._sizers, Math.max(0, height - this._fixed));
4959 break;
4960 case 'right-to-left':
4961 delta = BoxEngine.calc(this._sizers, Math.max(0, width - this._fixed));
4962 left += width;
4963 break;
4964 case 'bottom-to-top':
4965 delta = BoxEngine.calc(this._sizers, Math.max(0, height - this._fixed));
4966 top += height;
4967 break;
4968 default:
4969 throw 'unreachable';
4970 }
4971 // Setup the variables for justification and alignment offset.
4972 var extra = 0;
4973 var offset = 0;
4974 // Account for alignment if there is extra layout space.
4975 if (delta > 0) {
4976 switch (this._alignment) {
4977 case 'start':
4978 break;
4979 case 'center':
4980 extra = 0;
4981 offset = delta / 2;
4982 break;
4983 case 'end':
4984 extra = 0;
4985 offset = delta;
4986 break;
4987 case 'justify':
4988 extra = delta / nVisible;
4989 offset = 0;
4990 break;
4991 default:
4992 throw 'unreachable';
4993 }
4994 }
4995 // Layout the items using the computed box sizes.
4996 for (var i = 0, n = this._items.length; i < n; ++i) {
4997 // Fetch the item.
4998 var item = this._items[i];
4999 // Ignore hidden items.
5000 if (item.isHidden) {
5001 continue;
5002 }
5003 // Fetch the computed size for the widget.
5004 var size = this._sizers[i].size;
5005 // Update the widget geometry and advance the relevant edge.
5006 switch (this._direction) {
5007 case 'left-to-right':
5008 item.update(left + offset, top, size + extra, height);
5009 left += size + extra + this._spacing;
5010 break;
5011 case 'top-to-bottom':
5012 item.update(left, top + offset, width, size + extra);
5013 top += size + extra + this._spacing;
5014 break;
5015 case 'right-to-left':
5016 item.update(left - offset - size - extra, top, size + extra, height);
5017 left -= size + extra + this._spacing;
5018 break;
5019 case 'bottom-to-top':
5020 item.update(left, top - offset - size - extra, width, size + extra);
5021 top -= size + extra + this._spacing;
5022 break;
5023 default:
5024 throw 'unreachable';
5025 }
5026 }
5027 };
5028 return BoxLayout;
5029}(PanelLayout));
5030/**
5031 * The namespace for the `BoxLayout` class statics.
5032 */
5033(function (BoxLayout) {
5034 /**
5035 * Get the box layout stretch factor for the given widget.
5036 *
5037 * @param widget - The widget of interest.
5038 *
5039 * @returns The box layout stretch factor for the widget.
5040 */
5041 function getStretch(widget) {
5042 return Private$c.stretchProperty.get(widget);
5043 }
5044 BoxLayout.getStretch = getStretch;
5045 /**
5046 * Set the box layout stretch factor for the given widget.
5047 *
5048 * @param widget - The widget of interest.
5049 *
5050 * @param value - The value for the stretch factor.
5051 */
5052 function setStretch(widget, value) {
5053 Private$c.stretchProperty.set(widget, value);
5054 }
5055 BoxLayout.setStretch = setStretch;
5056 /**
5057 * Get the box layout size basis for the given widget.
5058 *
5059 * @param widget - The widget of interest.
5060 *
5061 * @returns The box layout size basis for the widget.
5062 */
5063 function getSizeBasis(widget) {
5064 return Private$c.sizeBasisProperty.get(widget);
5065 }
5066 BoxLayout.getSizeBasis = getSizeBasis;
5067 /**
5068 * Set the box layout size basis for the given widget.
5069 *
5070 * @param widget - The widget of interest.
5071 *
5072 * @param value - The value for the size basis.
5073 */
5074 function setSizeBasis(widget, value) {
5075 Private$c.sizeBasisProperty.set(widget, value);
5076 }
5077 BoxLayout.setSizeBasis = setSizeBasis;
5078})(BoxLayout || (BoxLayout = {}));
5079/**
5080 * The namespace for the module implementation details.
5081 */
5082var Private$c;
5083(function (Private) {
5084 /**
5085 * The property descriptor for a widget stretch factor.
5086 */
5087 Private.stretchProperty = new AttachedProperty({
5088 name: 'stretch',
5089 create: function () { return 0; },
5090 coerce: function (owner, value) { return Math.max(0, Math.floor(value)); },
5091 changed: onChildSizingChanged
5092 });
5093 /**
5094 * The property descriptor for a widget size basis.
5095 */
5096 Private.sizeBasisProperty = new AttachedProperty({
5097 name: 'sizeBasis',
5098 create: function () { return 0; },
5099 coerce: function (owner, value) { return Math.max(0, Math.floor(value)); },
5100 changed: onChildSizingChanged
5101 });
5102 /**
5103 * Test whether a direction has horizontal orientation.
5104 */
5105 function isHorizontal(dir) {
5106 return dir === 'left-to-right' || dir === 'right-to-left';
5107 }
5108 Private.isHorizontal = isHorizontal;
5109 /**
5110 * Clamp a spacing value to an integer >= 0.
5111 */
5112 function clampSpacing(value) {
5113 return Math.max(0, Math.floor(value));
5114 }
5115 Private.clampSpacing = clampSpacing;
5116 /**
5117 * The change handler for the attached sizing properties.
5118 */
5119 function onChildSizingChanged(child) {
5120 if (child.parent && child.parent.layout instanceof BoxLayout) {
5121 child.parent.fit();
5122 }
5123 }
5124})(Private$c || (Private$c = {}));
5125
5126/**
5127 * A panel which arranges its widgets in a single row or column.
5128 *
5129 * #### Notes
5130 * This class provides a convenience wrapper around a [[BoxLayout]].
5131 */
5132var BoxPanel = /** @class */ (function (_super) {
5133 __extends(BoxPanel, _super);
5134 /**
5135 * Construct a new box panel.
5136 *
5137 * @param options - The options for initializing the box panel.
5138 */
5139 function BoxPanel(options) {
5140 if (options === void 0) { options = {}; }
5141 var _this = _super.call(this, { layout: Private$b.createLayout(options) }) || this;
5142 _this.addClass('lm-BoxPanel');
5143 /* <DEPRECATED> */
5144 _this.addClass('p-BoxPanel');
5145 return _this;
5146 /* </DEPRECATED> */
5147 }
5148 Object.defineProperty(BoxPanel.prototype, "direction", {
5149 /**
5150 * Get the layout direction for the box panel.
5151 */
5152 get: function () {
5153 return this.layout.direction;
5154 },
5155 /**
5156 * Set the layout direction for the box panel.
5157 */
5158 set: function (value) {
5159 this.layout.direction = value;
5160 },
5161 enumerable: true,
5162 configurable: true
5163 });
5164 Object.defineProperty(BoxPanel.prototype, "alignment", {
5165 /**
5166 * Get the content alignment for the box panel.
5167 *
5168 * #### Notes
5169 * This is the alignment of the widgets in the layout direction.
5170 *
5171 * The alignment has no effect if the widgets can expand to fill the
5172 * entire box layout.
5173 */
5174 get: function () {
5175 return this.layout.alignment;
5176 },
5177 /**
5178 * Set the content alignment for the box panel.
5179 *
5180 * #### Notes
5181 * This is the alignment of the widgets in the layout direction.
5182 *
5183 * The alignment has no effect if the widgets can expand to fill the
5184 * entire box layout.
5185 */
5186 set: function (value) {
5187 this.layout.alignment = value;
5188 },
5189 enumerable: true,
5190 configurable: true
5191 });
5192 Object.defineProperty(BoxPanel.prototype, "spacing", {
5193 /**
5194 * Get the inter-element spacing for the box panel.
5195 */
5196 get: function () {
5197 return this.layout.spacing;
5198 },
5199 /**
5200 * Set the inter-element spacing for the box panel.
5201 */
5202 set: function (value) {
5203 this.layout.spacing = value;
5204 },
5205 enumerable: true,
5206 configurable: true
5207 });
5208 /**
5209 * A message handler invoked on a `'child-added'` message.
5210 */
5211 BoxPanel.prototype.onChildAdded = function (msg) {
5212 msg.child.addClass('lm-BoxPanel-child');
5213 /* <DEPRECATED> */
5214 msg.child.addClass('p-BoxPanel-child');
5215 /* </DEPRECATED> */
5216 };
5217 /**
5218 * A message handler invoked on a `'child-removed'` message.
5219 */
5220 BoxPanel.prototype.onChildRemoved = function (msg) {
5221 msg.child.removeClass('lm-BoxPanel-child');
5222 /* <DEPRECATED> */
5223 msg.child.removeClass('p-BoxPanel-child');
5224 /* </DEPRECATED> */
5225 };
5226 return BoxPanel;
5227}(Panel));
5228/**
5229 * The namespace for the `BoxPanel` class statics.
5230 */
5231(function (BoxPanel) {
5232 /**
5233 * Get the box panel stretch factor for the given widget.
5234 *
5235 * @param widget - The widget of interest.
5236 *
5237 * @returns The box panel stretch factor for the widget.
5238 */
5239 function getStretch(widget) {
5240 return BoxLayout.getStretch(widget);
5241 }
5242 BoxPanel.getStretch = getStretch;
5243 /**
5244 * Set the box panel stretch factor for the given widget.
5245 *
5246 * @param widget - The widget of interest.
5247 *
5248 * @param value - The value for the stretch factor.
5249 */
5250 function setStretch(widget, value) {
5251 BoxLayout.setStretch(widget, value);
5252 }
5253 BoxPanel.setStretch = setStretch;
5254 /**
5255 * Get the box panel size basis for the given widget.
5256 *
5257 * @param widget - The widget of interest.
5258 *
5259 * @returns The box panel size basis for the widget.
5260 */
5261 function getSizeBasis(widget) {
5262 return BoxLayout.getSizeBasis(widget);
5263 }
5264 BoxPanel.getSizeBasis = getSizeBasis;
5265 /**
5266 * Set the box panel size basis for the given widget.
5267 *
5268 * @param widget - The widget of interest.
5269 *
5270 * @param value - The value for the size basis.
5271 */
5272 function setSizeBasis(widget, value) {
5273 BoxLayout.setSizeBasis(widget, value);
5274 }
5275 BoxPanel.setSizeBasis = setSizeBasis;
5276})(BoxPanel || (BoxPanel = {}));
5277/**
5278 * The namespace for the module implementation details.
5279 */
5280var Private$b;
5281(function (Private) {
5282 /**
5283 * Create a box layout for the given panel options.
5284 */
5285 function createLayout(options) {
5286 return options.layout || new BoxLayout(options);
5287 }
5288 Private.createLayout = createLayout;
5289})(Private$b || (Private$b = {}));
5290
5291/**
5292 * A widget which displays command items as a searchable palette.
5293 */
5294var CommandPalette = /** @class */ (function (_super) {
5295 __extends(CommandPalette, _super);
5296 /**
5297 * Construct a new command palette.
5298 *
5299 * @param options - The options for initializing the palette.
5300 */
5301 function CommandPalette(options) {
5302 var _this = _super.call(this, { node: Private$a.createNode() }) || this;
5303 _this._activeIndex = -1;
5304 _this._items = [];
5305 _this._results = null;
5306 _this.addClass('lm-CommandPalette');
5307 /* <DEPRECATED> */
5308 _this.addClass('p-CommandPalette');
5309 /* </DEPRECATED> */
5310 _this.setFlag(Widget.Flag.DisallowLayout);
5311 _this.commands = options.commands;
5312 _this.renderer = options.renderer || CommandPalette.defaultRenderer;
5313 _this.commands.commandChanged.connect(_this._onGenericChange, _this);
5314 _this.commands.keyBindingChanged.connect(_this._onGenericChange, _this);
5315 return _this;
5316 }
5317 /**
5318 * Dispose of the resources held by the widget.
5319 */
5320 CommandPalette.prototype.dispose = function () {
5321 this._items.length = 0;
5322 this._results = null;
5323 _super.prototype.dispose.call(this);
5324 };
5325 Object.defineProperty(CommandPalette.prototype, "searchNode", {
5326 /**
5327 * The command palette search node.
5328 *
5329 * #### Notes
5330 * This is the node which contains the search-related elements.
5331 */
5332 get: function () {
5333 return this.node.getElementsByClassName('lm-CommandPalette-search')[0];
5334 },
5335 enumerable: true,
5336 configurable: true
5337 });
5338 Object.defineProperty(CommandPalette.prototype, "inputNode", {
5339 /**
5340 * The command palette input node.
5341 *
5342 * #### Notes
5343 * This is the actual input node for the search area.
5344 */
5345 get: function () {
5346 return this.node.getElementsByClassName('lm-CommandPalette-input')[0];
5347 },
5348 enumerable: true,
5349 configurable: true
5350 });
5351 Object.defineProperty(CommandPalette.prototype, "contentNode", {
5352 /**
5353 * The command palette content node.
5354 *
5355 * #### Notes
5356 * This is the node which holds the command item nodes.
5357 *
5358 * Modifying this node directly can lead to undefined behavior.
5359 */
5360 get: function () {
5361 return this.node.getElementsByClassName('lm-CommandPalette-content')[0];
5362 },
5363 enumerable: true,
5364 configurable: true
5365 });
5366 Object.defineProperty(CommandPalette.prototype, "items", {
5367 /**
5368 * A read-only array of the command items in the palette.
5369 */
5370 get: function () {
5371 return this._items;
5372 },
5373 enumerable: true,
5374 configurable: true
5375 });
5376 /**
5377 * Add a command item to the command palette.
5378 *
5379 * @param options - The options for creating the command item.
5380 *
5381 * @returns The command item added to the palette.
5382 */
5383 CommandPalette.prototype.addItem = function (options) {
5384 // Create a new command item for the options.
5385 var item = Private$a.createItem(this.commands, options);
5386 // Add the item to the array.
5387 this._items.push(item);
5388 // Refresh the search results.
5389 this.refresh();
5390 // Return the item added to the palette.
5391 return item;
5392 };
5393 /**
5394 * Adds command items to the command palette.
5395 *
5396 * @param items - An array of options for creating each command item.
5397 *
5398 * @returns The command items added to the palette.
5399 */
5400 CommandPalette.prototype.addItems = function (items) {
5401 var _this = this;
5402 var newItems = items.map(function (item) { return Private$a.createItem(_this.commands, item); });
5403 newItems.forEach(function (item) { return _this._items.push(item); });
5404 this.refresh();
5405 return newItems;
5406 };
5407 /**
5408 * Remove an item from the command palette.
5409 *
5410 * @param item - The item to remove from the palette.
5411 *
5412 * #### Notes
5413 * This is a no-op if the item is not in the palette.
5414 */
5415 CommandPalette.prototype.removeItem = function (item) {
5416 this.removeItemAt(this._items.indexOf(item));
5417 };
5418 /**
5419 * Remove the item at a given index from the command palette.
5420 *
5421 * @param index - The index of the item to remove.
5422 *
5423 * #### Notes
5424 * This is a no-op if the index is out of range.
5425 */
5426 CommandPalette.prototype.removeItemAt = function (index) {
5427 // Remove the item from the array.
5428 var item = ArrayExt.removeAt(this._items, index);
5429 // Bail if the index is out of range.
5430 if (!item) {
5431 return;
5432 }
5433 // Refresh the search results.
5434 this.refresh();
5435 };
5436 /**
5437 * Remove all items from the command palette.
5438 */
5439 CommandPalette.prototype.clearItems = function () {
5440 // Bail if there is nothing to remove.
5441 if (this._items.length === 0) {
5442 return;
5443 }
5444 // Clear the array of items.
5445 this._items.length = 0;
5446 // Refresh the search results.
5447 this.refresh();
5448 };
5449 /**
5450 * Clear the search results and schedule an update.
5451 *
5452 * #### Notes
5453 * This should be called whenever the search results of the palette
5454 * should be updated.
5455 *
5456 * This is typically called automatically by the palette as needed,
5457 * but can be called manually if the input text is programatically
5458 * changed.
5459 *
5460 * The rendered results are updated asynchronously.
5461 */
5462 CommandPalette.prototype.refresh = function () {
5463 this._results = null;
5464 if (this.inputNode.value !== '') {
5465 var clear = this.node.getElementsByClassName('lm-close-icon')[0];
5466 clear.style.display = 'inherit';
5467 }
5468 else {
5469 var clear = this.node.getElementsByClassName('lm-close-icon')[0];
5470 clear.style.display = 'none';
5471 }
5472 this.update();
5473 };
5474 /**
5475 * Handle the DOM events for the command palette.
5476 *
5477 * @param event - The DOM event sent to the command palette.
5478 *
5479 * #### Notes
5480 * This method implements the DOM `EventListener` interface and is
5481 * called in response to events on the command palette's DOM node.
5482 * It should not be called directly by user code.
5483 */
5484 CommandPalette.prototype.handleEvent = function (event) {
5485 switch (event.type) {
5486 case 'click':
5487 this._evtClick(event);
5488 break;
5489 case 'keydown':
5490 this._evtKeyDown(event);
5491 break;
5492 case 'input':
5493 this.refresh();
5494 break;
5495 case 'focus':
5496 case 'blur':
5497 this._toggleFocused();
5498 break;
5499 }
5500 };
5501 /**
5502 * A message handler invoked on a `'before-attach'` message.
5503 */
5504 CommandPalette.prototype.onBeforeAttach = function (msg) {
5505 this.node.addEventListener('click', this);
5506 this.node.addEventListener('keydown', this);
5507 this.node.addEventListener('input', this);
5508 this.node.addEventListener('focus', this, true);
5509 this.node.addEventListener('blur', this, true);
5510 };
5511 /**
5512 * A message handler invoked on an `'after-detach'` message.
5513 */
5514 CommandPalette.prototype.onAfterDetach = function (msg) {
5515 this.node.removeEventListener('click', this);
5516 this.node.removeEventListener('keydown', this);
5517 this.node.removeEventListener('input', this);
5518 this.node.removeEventListener('focus', this, true);
5519 this.node.removeEventListener('blur', this, true);
5520 };
5521 /**
5522 * A message handler invoked on an `'activate-request'` message.
5523 */
5524 CommandPalette.prototype.onActivateRequest = function (msg) {
5525 if (this.isAttached) {
5526 var input = this.inputNode;
5527 input.focus();
5528 input.select();
5529 }
5530 };
5531 /**
5532 * A message handler invoked on an `'update-request'` message.
5533 */
5534 CommandPalette.prototype.onUpdateRequest = function (msg) {
5535 // Fetch the current query text and content node.
5536 var query = this.inputNode.value;
5537 var contentNode = this.contentNode;
5538 // Ensure the search results are generated.
5539 var results = this._results;
5540 if (!results) {
5541 // Generate and store the new search results.
5542 results = this._results = Private$a.search(this._items, query);
5543 // Reset the active index.
5544 this._activeIndex = query
5545 ? ArrayExt.findFirstIndex(results, Private$a.canActivate)
5546 : -1;
5547 }
5548 // If there is no query and no results, clear the content.
5549 if (!query && results.length === 0) {
5550 VirtualDOM.render(null, contentNode);
5551 return;
5552 }
5553 // If the is a query but no results, render the empty message.
5554 if (query && results.length === 0) {
5555 var content_1 = this.renderer.renderEmptyMessage({ query: query });
5556 VirtualDOM.render(content_1, contentNode);
5557 return;
5558 }
5559 // Create the render content for the search results.
5560 var renderer = this.renderer;
5561 var activeIndex = this._activeIndex;
5562 var content = new Array(results.length);
5563 for (var i = 0, n = results.length; i < n; ++i) {
5564 var result = results[i];
5565 if (result.type === 'header') {
5566 var indices = result.indices;
5567 var category = result.category;
5568 content[i] = renderer.renderHeader({ category: category, indices: indices });
5569 }
5570 else {
5571 var item = result.item;
5572 var indices = result.indices;
5573 var active = i === activeIndex;
5574 content[i] = renderer.renderItem({ item: item, indices: indices, active: active });
5575 }
5576 }
5577 // Render the search result content.
5578 VirtualDOM.render(content, contentNode);
5579 // Adjust the scroll position as needed.
5580 if (activeIndex < 0 || activeIndex >= results.length) {
5581 contentNode.scrollTop = 0;
5582 }
5583 else {
5584 var element = contentNode.children[activeIndex];
5585 ElementExt.scrollIntoViewIfNeeded(contentNode, element);
5586 }
5587 };
5588 /**
5589 * Handle the `'click'` event for the command palette.
5590 */
5591 CommandPalette.prototype._evtClick = function (event) {
5592 // Bail if the click is not the left button.
5593 if (event.button !== 0) {
5594 return;
5595 }
5596 // Clear input if the target is clear button
5597 if (event.target.classList.contains('lm-close-icon')) {
5598 this.inputNode.value = '';
5599 this.refresh();
5600 return;
5601 }
5602 // Find the index of the item which was clicked.
5603 var index = ArrayExt.findFirstIndex(this.contentNode.children, function (node) {
5604 return node.contains(event.target);
5605 });
5606 // Bail if the click was not on an item.
5607 if (index === -1) {
5608 return;
5609 }
5610 // Kill the event when a content item is clicked.
5611 event.preventDefault();
5612 event.stopPropagation();
5613 // Execute the item if possible.
5614 this._execute(index);
5615 };
5616 /**
5617 * Handle the `'keydown'` event for the command palette.
5618 */
5619 CommandPalette.prototype._evtKeyDown = function (event) {
5620 if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {
5621 return;
5622 }
5623 switch (event.keyCode) {
5624 case 13: // Enter
5625 event.preventDefault();
5626 event.stopPropagation();
5627 this._execute(this._activeIndex);
5628 break;
5629 case 38: // Up Arrow
5630 event.preventDefault();
5631 event.stopPropagation();
5632 this._activatePreviousItem();
5633 break;
5634 case 40: // Down Arrow
5635 event.preventDefault();
5636 event.stopPropagation();
5637 this._activateNextItem();
5638 break;
5639 }
5640 };
5641 /**
5642 * Activate the next enabled command item.
5643 */
5644 CommandPalette.prototype._activateNextItem = function () {
5645 // Bail if there are no search results.
5646 if (!this._results || this._results.length === 0) {
5647 return;
5648 }
5649 // Find the next enabled item index.
5650 var ai = this._activeIndex;
5651 var n = this._results.length;
5652 var start = ai < n - 1 ? ai + 1 : 0;
5653 var stop = start === 0 ? n - 1 : start - 1;
5654 this._activeIndex = ArrayExt.findFirstIndex(this._results, Private$a.canActivate, start, stop);
5655 // Schedule an update of the items.
5656 this.update();
5657 };
5658 /**
5659 * Activate the previous enabled command item.
5660 */
5661 CommandPalette.prototype._activatePreviousItem = function () {
5662 // Bail if there are no search results.
5663 if (!this._results || this._results.length === 0) {
5664 return;
5665 }
5666 // Find the previous enabled item index.
5667 var ai = this._activeIndex;
5668 var n = this._results.length;
5669 var start = ai <= 0 ? n - 1 : ai - 1;
5670 var stop = start === n - 1 ? 0 : start + 1;
5671 this._activeIndex = ArrayExt.findLastIndex(this._results, Private$a.canActivate, start, stop);
5672 // Schedule an update of the items.
5673 this.update();
5674 };
5675 /**
5676 * Execute the command item at the given index, if possible.
5677 */
5678 CommandPalette.prototype._execute = function (index) {
5679 // Bail if there are no search results.
5680 if (!this._results) {
5681 return;
5682 }
5683 // Bail if the index is out of range.
5684 var part = this._results[index];
5685 if (!part) {
5686 return;
5687 }
5688 // Update the search text if the item is a header.
5689 if (part.type === 'header') {
5690 var input = this.inputNode;
5691 input.value = part.category.toLowerCase() + " ";
5692 input.focus();
5693 this.refresh();
5694 return;
5695 }
5696 // Bail if item is not enabled.
5697 if (!part.item.isEnabled) {
5698 return;
5699 }
5700 // Execute the item.
5701 this.commands.execute(part.item.command, part.item.args);
5702 // Clear the query text.
5703 this.inputNode.value = '';
5704 // Refresh the search results.
5705 this.refresh();
5706 };
5707 /**
5708 * Toggle the focused modifier based on the input node focus state.
5709 */
5710 CommandPalette.prototype._toggleFocused = function () {
5711 var focused = document.activeElement === this.inputNode;
5712 this.toggleClass('lm-mod-focused', focused);
5713 /* <DEPRECATED> */
5714 this.toggleClass('p-mod-focused', focused);
5715 /* </DEPRECATED> */
5716 };
5717 /**
5718 * A signal handler for generic command changes.
5719 */
5720 CommandPalette.prototype._onGenericChange = function () {
5721 this.refresh();
5722 };
5723 return CommandPalette;
5724}(Widget));
5725/**
5726 * The namespace for the `CommandPalette` class statics.
5727 */
5728(function (CommandPalette) {
5729 /**
5730 * The default implementation of `IRenderer`.
5731 */
5732 var Renderer = /** @class */ (function () {
5733 function Renderer() {
5734 }
5735 /**
5736 * Render the virtual element for a command palette header.
5737 *
5738 * @param data - The data to use for rendering the header.
5739 *
5740 * @returns A virtual element representing the header.
5741 */
5742 Renderer.prototype.renderHeader = function (data) {
5743 var content = this.formatHeader(data);
5744 return h.li({
5745 className: 'lm-CommandPalette-header' +
5746 /* <DEPRECATED> */
5747 ' p-CommandPalette-header'
5748 /* </DEPRECATED> */
5749 }, content);
5750 };
5751 /**
5752 * Render the virtual element for a command palette item.
5753 *
5754 * @param data - The data to use for rendering the item.
5755 *
5756 * @returns A virtual element representing the item.
5757 */
5758 Renderer.prototype.renderItem = function (data) {
5759 var className = this.createItemClass(data);
5760 var dataset = this.createItemDataset(data);
5761 if (data.item.isToggleable) {
5762 return h.li({
5763 className: className,
5764 dataset: dataset,
5765 role: 'checkbox',
5766 'aria-checked': "" + data.item.isToggled
5767 }, this.renderItemIcon(data), this.renderItemContent(data), this.renderItemShortcut(data));
5768 }
5769 return h.li({
5770 className: className,
5771 dataset: dataset
5772 }, this.renderItemIcon(data), this.renderItemContent(data), this.renderItemShortcut(data));
5773 };
5774 /**
5775 * Render the empty results message for a command palette.
5776 *
5777 * @param data - The data to use for rendering the message.
5778 *
5779 * @returns A virtual element representing the message.
5780 */
5781 Renderer.prototype.renderEmptyMessage = function (data) {
5782 var content = this.formatEmptyMessage(data);
5783 return h.li({
5784 className: 'lm-CommandPalette-emptyMessage' +
5785 /* <DEPRECATED> */
5786 ' p-CommandPalette-emptyMessage'
5787 /* </DEPRECATED> */
5788 }, content);
5789 };
5790 /**
5791 * Render the icon for a command palette item.
5792 *
5793 * @param data - The data to use for rendering the icon.
5794 *
5795 * @returns A virtual element representing the icon.
5796 */
5797 Renderer.prototype.renderItemIcon = function (data) {
5798 var className = this.createIconClass(data);
5799 /* <DEPRECATED> */
5800 if (typeof data.item.icon === 'string') {
5801 return h.div({ className: className }, data.item.iconLabel);
5802 }
5803 /* </DEPRECATED> */
5804 // if data.item.icon is undefined, it will be ignored
5805 return h.div({ className: className }, data.item.icon, data.item.iconLabel);
5806 };
5807 /**
5808 * Render the content for a command palette item.
5809 *
5810 * @param data - The data to use for rendering the content.
5811 *
5812 * @returns A virtual element representing the content.
5813 */
5814 Renderer.prototype.renderItemContent = function (data) {
5815 return h.div({
5816 className: 'lm-CommandPalette-itemContent' +
5817 /* <DEPRECATED> */
5818 ' p-CommandPalette-itemContent'
5819 /* </DEPRECATED> */
5820 }, this.renderItemLabel(data), this.renderItemCaption(data));
5821 };
5822 /**
5823 * Render the label for a command palette item.
5824 *
5825 * @param data - The data to use for rendering the label.
5826 *
5827 * @returns A virtual element representing the label.
5828 */
5829 Renderer.prototype.renderItemLabel = function (data) {
5830 var content = this.formatItemLabel(data);
5831 return h.div({
5832 className: 'lm-CommandPalette-itemLabel' +
5833 /* <DEPRECATED> */
5834 ' p-CommandPalette-itemLabel'
5835 /* </DEPRECATED> */
5836 }, content);
5837 };
5838 /**
5839 * Render the caption for a command palette item.
5840 *
5841 * @param data - The data to use for rendering the caption.
5842 *
5843 * @returns A virtual element representing the caption.
5844 */
5845 Renderer.prototype.renderItemCaption = function (data) {
5846 var content = this.formatItemCaption(data);
5847 return h.div({
5848 className: 'lm-CommandPalette-itemCaption' +
5849 /* <DEPRECATED> */
5850 ' p-CommandPalette-itemCaption'
5851 /* </DEPRECATED> */
5852 }, content);
5853 };
5854 /**
5855 * Render the shortcut for a command palette item.
5856 *
5857 * @param data - The data to use for rendering the shortcut.
5858 *
5859 * @returns A virtual element representing the shortcut.
5860 */
5861 Renderer.prototype.renderItemShortcut = function (data) {
5862 var content = this.formatItemShortcut(data);
5863 return h.div({
5864 className: 'lm-CommandPalette-itemShortcut' +
5865 /* <DEPRECATED> */
5866 ' p-CommandPalette-itemShortcut'
5867 /* </DEPRECATED> */
5868 }, content);
5869 };
5870 /**
5871 * Create the class name for the command palette item.
5872 *
5873 * @param data - The data to use for the class name.
5874 *
5875 * @returns The full class name for the command palette item.
5876 */
5877 Renderer.prototype.createItemClass = function (data) {
5878 // Set up the initial class name.
5879 var name = 'lm-CommandPalette-item';
5880 /* <DEPRECATED> */
5881 name += ' p-CommandPalette-item';
5882 /* </DEPRECATED> */
5883 // Add the boolean state classes.
5884 if (!data.item.isEnabled) {
5885 name += ' lm-mod-disabled';
5886 /* <DEPRECATED> */
5887 name += ' p-mod-disabled';
5888 /* </DEPRECATED> */
5889 }
5890 if (data.item.isToggled) {
5891 name += ' lm-mod-toggled';
5892 /* <DEPRECATED> */
5893 name += ' p-mod-toggled';
5894 /* </DEPRECATED> */
5895 }
5896 if (data.active) {
5897 name += ' lm-mod-active';
5898 /* <DEPRECATED> */
5899 name += ' p-mod-active';
5900 /* </DEPRECATED> */
5901 }
5902 // Add the extra class.
5903 var extra = data.item.className;
5904 if (extra) {
5905 name += " " + extra;
5906 }
5907 // Return the complete class name.
5908 return name;
5909 };
5910 /**
5911 * Create the dataset for the command palette item.
5912 *
5913 * @param data - The data to use for creating the dataset.
5914 *
5915 * @returns The dataset for the command palette item.
5916 */
5917 Renderer.prototype.createItemDataset = function (data) {
5918 return __assign(__assign({}, data.item.dataset), { command: data.item.command });
5919 };
5920 /**
5921 * Create the class name for the command item icon.
5922 *
5923 * @param data - The data to use for the class name.
5924 *
5925 * @returns The full class name for the item icon.
5926 */
5927 Renderer.prototype.createIconClass = function (data) {
5928 var name = 'lm-CommandPalette-itemIcon';
5929 /* <DEPRECATED> */
5930 name += ' p-CommandPalette-itemIcon';
5931 /* </DEPRECATED> */
5932 var extra = data.item.iconClass;
5933 return extra ? name + " " + extra : name;
5934 };
5935 /**
5936 * Create the render content for the header node.
5937 *
5938 * @param data - The data to use for the header content.
5939 *
5940 * @returns The content to add to the header node.
5941 */
5942 Renderer.prototype.formatHeader = function (data) {
5943 if (!data.indices || data.indices.length === 0) {
5944 return data.category;
5945 }
5946 return StringExt.highlight(data.category, data.indices, h.mark);
5947 };
5948 /**
5949 * Create the render content for the empty message node.
5950 *
5951 * @param data - The data to use for the empty message content.
5952 *
5953 * @returns The content to add to the empty message node.
5954 */
5955 Renderer.prototype.formatEmptyMessage = function (data) {
5956 return "No commands found that match '" + data.query + "'";
5957 };
5958 /**
5959 * Create the render content for the item shortcut node.
5960 *
5961 * @param data - The data to use for the shortcut content.
5962 *
5963 * @returns The content to add to the shortcut node.
5964 */
5965 Renderer.prototype.formatItemShortcut = function (data) {
5966 var kb = data.item.keyBinding;
5967 return kb
5968 ? kb.keys.map(CommandRegistry.formatKeystroke).join(', ')
5969 : null;
5970 };
5971 /**
5972 * Create the render content for the item label node.
5973 *
5974 * @param data - The data to use for the label content.
5975 *
5976 * @returns The content to add to the label node.
5977 */
5978 Renderer.prototype.formatItemLabel = function (data) {
5979 if (!data.indices || data.indices.length === 0) {
5980 return data.item.label;
5981 }
5982 return StringExt.highlight(data.item.label, data.indices, h.mark);
5983 };
5984 /**
5985 * Create the render content for the item caption node.
5986 *
5987 * @param data - The data to use for the caption content.
5988 *
5989 * @returns The content to add to the caption node.
5990 */
5991 Renderer.prototype.formatItemCaption = function (data) {
5992 return data.item.caption;
5993 };
5994 return Renderer;
5995 }());
5996 CommandPalette.Renderer = Renderer;
5997 /**
5998 * The default `Renderer` instance.
5999 */
6000 CommandPalette.defaultRenderer = new Renderer();
6001})(CommandPalette || (CommandPalette = {}));
6002/**
6003 * The namespace for the module implementation details.
6004 */
6005var Private$a;
6006(function (Private) {
6007 /**
6008 * Create the DOM node for a command palette.
6009 */
6010 function createNode() {
6011 var node = document.createElement('div');
6012 var search = document.createElement('div');
6013 var wrapper = document.createElement('div');
6014 var input = document.createElement('input');
6015 var content = document.createElement('ul');
6016 var clear = document.createElement('button');
6017 search.className = 'lm-CommandPalette-search';
6018 wrapper.className = 'lm-CommandPalette-wrapper';
6019 input.className = 'lm-CommandPalette-input';
6020 clear.className = 'lm-close-icon';
6021 content.className = 'lm-CommandPalette-content';
6022 /* <DEPRECATED> */
6023 search.classList.add('p-CommandPalette-search');
6024 wrapper.classList.add('p-CommandPalette-wrapper');
6025 input.classList.add('p-CommandPalette-input');
6026 content.classList.add('p-CommandPalette-content');
6027 /* </DEPRECATED> */
6028 input.spellcheck = false;
6029 wrapper.appendChild(input);
6030 wrapper.appendChild(clear);
6031 search.appendChild(wrapper);
6032 node.appendChild(search);
6033 node.appendChild(content);
6034 return node;
6035 }
6036 Private.createNode = createNode;
6037 /**
6038 * Create a new command item from a command registry and options.
6039 */
6040 function createItem(commands, options) {
6041 return new CommandItem(commands, options);
6042 }
6043 Private.createItem = createItem;
6044 /**
6045 * Search an array of command items for fuzzy matches.
6046 */
6047 function search(items, query) {
6048 // Fuzzy match the items for the query.
6049 var scores = matchItems(items, query);
6050 // Sort the items based on their score.
6051 scores.sort(scoreCmp);
6052 // Create the results for the search.
6053 return createResults(scores);
6054 }
6055 Private.search = search;
6056 /**
6057 * Test whether a result item can be activated.
6058 */
6059 function canActivate(result) {
6060 return result.type === 'item' && result.item.isEnabled;
6061 }
6062 Private.canActivate = canActivate;
6063 /**
6064 * Normalize a category for a command item.
6065 */
6066 function normalizeCategory(category) {
6067 return category.trim().replace(/\s+/g, ' ');
6068 }
6069 /**
6070 * Normalize the query text for a fuzzy search.
6071 */
6072 function normalizeQuery(text) {
6073 return text.replace(/\s+/g, '').toLowerCase();
6074 }
6075 /**
6076 * Perform a fuzzy match on an array of command items.
6077 */
6078 function matchItems(items, query) {
6079 // Normalize the query text to lower case with no whitespace.
6080 query = normalizeQuery(query);
6081 // Create the array to hold the scores.
6082 var scores = [];
6083 // Iterate over the items and match against the query.
6084 for (var i = 0, n = items.length; i < n; ++i) {
6085 // Ignore items which are not visible.
6086 var item = items[i];
6087 if (!item.isVisible) {
6088 continue;
6089 }
6090 // If the query is empty, all items are matched by default.
6091 if (!query) {
6092 scores.push({
6093 matchType: 3 /* Default */,
6094 categoryIndices: null,
6095 labelIndices: null,
6096 score: 0,
6097 item: item
6098 });
6099 continue;
6100 }
6101 // Run the fuzzy search for the item and query.
6102 var score = fuzzySearch(item, query);
6103 // Ignore the item if it is not a match.
6104 if (!score) {
6105 continue;
6106 }
6107 // Penalize disabled items.
6108 // TODO - push disabled items all the way down in sort cmp?
6109 if (!item.isEnabled) {
6110 score.score += 1000;
6111 }
6112 // Add the score to the results.
6113 scores.push(score);
6114 }
6115 // Return the final array of scores.
6116 return scores;
6117 }
6118 /**
6119 * Perform a fuzzy search on a single command item.
6120 */
6121 function fuzzySearch(item, query) {
6122 // Create the source text to be searched.
6123 var category = item.category.toLowerCase();
6124 var label = item.label.toLowerCase();
6125 var source = category + " " + label;
6126 // Set up the match score and indices array.
6127 var score = Infinity;
6128 var indices = null;
6129 // The regex for search word boundaries
6130 var rgx = /\b\w/g;
6131 // Search the source by word boundary.
6132 // eslint-disable-next-line no-constant-condition
6133 while (true) {
6134 // Find the next word boundary in the source.
6135 var rgxMatch = rgx.exec(source);
6136 // Break if there is no more source context.
6137 if (!rgxMatch) {
6138 break;
6139 }
6140 // Run the string match on the relevant substring.
6141 var match = StringExt.matchSumOfDeltas(source, query, rgxMatch.index);
6142 // Break if there is no match.
6143 if (!match) {
6144 break;
6145 }
6146 // Update the match if the score is better.
6147 if (match && match.score <= score) {
6148 score = match.score;
6149 indices = match.indices;
6150 }
6151 }
6152 // Bail if there was no match.
6153 if (!indices || score === Infinity) {
6154 return null;
6155 }
6156 // Compute the pivot index between category and label text.
6157 var pivot = category.length + 1;
6158 // Find the slice index to separate matched indices.
6159 var j = ArrayExt.lowerBound(indices, pivot, function (a, b) { return a - b; });
6160 // Extract the matched category and label indices.
6161 var categoryIndices = indices.slice(0, j);
6162 var labelIndices = indices.slice(j);
6163 // Adjust the label indices for the pivot offset.
6164 for (var i = 0, n = labelIndices.length; i < n; ++i) {
6165 labelIndices[i] -= pivot;
6166 }
6167 // Handle a pure label match.
6168 if (categoryIndices.length === 0) {
6169 return {
6170 matchType: 0 /* Label */,
6171 categoryIndices: null,
6172 labelIndices: labelIndices,
6173 score: score,
6174 item: item
6175 };
6176 }
6177 // Handle a pure category match.
6178 if (labelIndices.length === 0) {
6179 return {
6180 matchType: 1 /* Category */,
6181 categoryIndices: categoryIndices,
6182 labelIndices: null,
6183 score: score,
6184 item: item
6185 };
6186 }
6187 // Handle a split match.
6188 return {
6189 matchType: 2 /* Split */,
6190 categoryIndices: categoryIndices,
6191 labelIndices: labelIndices,
6192 score: score,
6193 item: item
6194 };
6195 }
6196 /**
6197 * A sort comparison function for a match score.
6198 */
6199 function scoreCmp(a, b) {
6200 // First compare based on the match type
6201 var m1 = a.matchType - b.matchType;
6202 if (m1 !== 0) {
6203 return m1;
6204 }
6205 // Otherwise, compare based on the match score.
6206 var d1 = a.score - b.score;
6207 if (d1 !== 0) {
6208 return d1;
6209 }
6210 // Find the match index based on the match type.
6211 var i1 = 0;
6212 var i2 = 0;
6213 switch (a.matchType) {
6214 case 0 /* Label */:
6215 i1 = a.labelIndices[0];
6216 i2 = b.labelIndices[0];
6217 break;
6218 case 1 /* Category */:
6219 case 2 /* Split */:
6220 i1 = a.categoryIndices[0];
6221 i2 = b.categoryIndices[0];
6222 break;
6223 }
6224 // Compare based on the match index.
6225 if (i1 !== i2) {
6226 return i1 - i2;
6227 }
6228 // Otherwise, compare by category.
6229 var d2 = a.item.category.localeCompare(b.item.category);
6230 if (d2 !== 0) {
6231 return d2;
6232 }
6233 // Otherwise, compare by rank.
6234 var r1 = a.item.rank;
6235 var r2 = b.item.rank;
6236 if (r1 !== r2) {
6237 return r1 < r2 ? -1 : 1; // Infinity safe
6238 }
6239 // Finally, compare by label.
6240 return a.item.label.localeCompare(b.item.label);
6241 }
6242 /**
6243 * Create the results from an array of sorted scores.
6244 */
6245 function createResults(scores) {
6246 // Set up an array to track which scores have been visited.
6247 var visited = new Array(scores.length);
6248 ArrayExt.fill(visited, false);
6249 // Set up the search results array.
6250 var results = [];
6251 // Iterate over each score in the array.
6252 for (var i = 0, n = scores.length; i < n; ++i) {
6253 // Ignore a score which has already been processed.
6254 if (visited[i]) {
6255 continue;
6256 }
6257 // Extract the current item and indices.
6258 var _a = scores[i], item = _a.item, categoryIndices = _a.categoryIndices;
6259 // Extract the category for the current item.
6260 var category = item.category;
6261 // Add the header result for the category.
6262 results.push({ type: 'header', category: category, indices: categoryIndices });
6263 // Find the rest of the scores with the same category.
6264 for (var j = i; j < n; ++j) {
6265 // Ignore a score which has already been processed.
6266 if (visited[j]) {
6267 continue;
6268 }
6269 // Extract the data for the current score.
6270 var _b = scores[j], item_1 = _b.item, labelIndices = _b.labelIndices;
6271 // Ignore an item with a different category.
6272 if (item_1.category !== category) {
6273 continue;
6274 }
6275 // Create the item result for the score.
6276 results.push({ type: 'item', item: item_1, indices: labelIndices });
6277 // Mark the score as processed.
6278 visited[j] = true;
6279 }
6280 }
6281 // Return the final results.
6282 return results;
6283 }
6284 /**
6285 * A concrete implementation of `CommandPalette.IItem`.
6286 */
6287 var CommandItem = /** @class */ (function () {
6288 /**
6289 * Construct a new command item.
6290 */
6291 function CommandItem(commands, options) {
6292 this._commands = commands;
6293 this.category = normalizeCategory(options.category);
6294 this.command = options.command;
6295 this.args = options.args || JSONExt.emptyObject;
6296 this.rank = options.rank !== undefined ? options.rank : Infinity;
6297 }
6298 Object.defineProperty(CommandItem.prototype, "label", {
6299 /**
6300 * The display label for the command item.
6301 */
6302 get: function () {
6303 return this._commands.label(this.command, this.args);
6304 },
6305 enumerable: true,
6306 configurable: true
6307 });
6308 Object.defineProperty(CommandItem.prototype, "icon", {
6309 /**
6310 * The icon renderer for the command item.
6311 */
6312 get: function () {
6313 return this._commands.icon(this.command, this.args);
6314 },
6315 enumerable: true,
6316 configurable: true
6317 });
6318 Object.defineProperty(CommandItem.prototype, "iconClass", {
6319 /**
6320 * The icon class for the command item.
6321 */
6322 get: function () {
6323 return this._commands.iconClass(this.command, this.args);
6324 },
6325 enumerable: true,
6326 configurable: true
6327 });
6328 Object.defineProperty(CommandItem.prototype, "iconLabel", {
6329 /**
6330 * The icon label for the command item.
6331 */
6332 get: function () {
6333 return this._commands.iconLabel(this.command, this.args);
6334 },
6335 enumerable: true,
6336 configurable: true
6337 });
6338 Object.defineProperty(CommandItem.prototype, "caption", {
6339 /**
6340 * The display caption for the command item.
6341 */
6342 get: function () {
6343 return this._commands.caption(this.command, this.args);
6344 },
6345 enumerable: true,
6346 configurable: true
6347 });
6348 Object.defineProperty(CommandItem.prototype, "className", {
6349 /**
6350 * The extra class name for the command item.
6351 */
6352 get: function () {
6353 return this._commands.className(this.command, this.args);
6354 },
6355 enumerable: true,
6356 configurable: true
6357 });
6358 Object.defineProperty(CommandItem.prototype, "dataset", {
6359 /**
6360 * The dataset for the command item.
6361 */
6362 get: function () {
6363 return this._commands.dataset(this.command, this.args);
6364 },
6365 enumerable: true,
6366 configurable: true
6367 });
6368 Object.defineProperty(CommandItem.prototype, "isEnabled", {
6369 /**
6370 * Whether the command item is enabled.
6371 */
6372 get: function () {
6373 return this._commands.isEnabled(this.command, this.args);
6374 },
6375 enumerable: true,
6376 configurable: true
6377 });
6378 Object.defineProperty(CommandItem.prototype, "isToggled", {
6379 /**
6380 * Whether the command item is toggled.
6381 */
6382 get: function () {
6383 return this._commands.isToggled(this.command, this.args);
6384 },
6385 enumerable: true,
6386 configurable: true
6387 });
6388 Object.defineProperty(CommandItem.prototype, "isToggleable", {
6389 /**
6390 * Whether the command item is toggleable.
6391 */
6392 get: function () {
6393 return this._commands.isToggleable(this.command, this.args);
6394 },
6395 enumerable: true,
6396 configurable: true
6397 });
6398 Object.defineProperty(CommandItem.prototype, "isVisible", {
6399 /**
6400 * Whether the command item is visible.
6401 */
6402 get: function () {
6403 return this._commands.isVisible(this.command, this.args);
6404 },
6405 enumerable: true,
6406 configurable: true
6407 });
6408 Object.defineProperty(CommandItem.prototype, "keyBinding", {
6409 /**
6410 * The key binding for the command item.
6411 */
6412 get: function () {
6413 var _a = this, command = _a.command, args = _a.args;
6414 return (ArrayExt.findLastValue(this._commands.keyBindings, function (kb) {
6415 return kb.command === command && JSONExt.deepEqual(kb.args, args);
6416 }) || null);
6417 },
6418 enumerable: true,
6419 configurable: true
6420 });
6421 return CommandItem;
6422 }());
6423})(Private$a || (Private$a = {}));
6424
6425/**
6426 * A widget which displays items as a canonical menu.
6427 */
6428var Menu = /** @class */ (function (_super) {
6429 __extends(Menu, _super);
6430 /**
6431 * Construct a new menu.
6432 *
6433 * @param options - The options for initializing the menu.
6434 */
6435 function Menu(options) {
6436 var _this = _super.call(this, { node: Private$9.createNode() }) || this;
6437 _this._childIndex = -1;
6438 _this._activeIndex = -1;
6439 _this._openTimerID = 0;
6440 _this._closeTimerID = 0;
6441 _this._items = [];
6442 _this._childMenu = null;
6443 _this._parentMenu = null;
6444 _this._aboutToClose = new Signal(_this);
6445 _this._menuRequested = new Signal(_this);
6446 _this.addClass('lm-Menu');
6447 /* <DEPRECATED> */
6448 _this.addClass('p-Menu');
6449 /* </DEPRECATED> */
6450 _this.setFlag(Widget.Flag.DisallowLayout);
6451 _this.commands = options.commands;
6452 _this.renderer = options.renderer || Menu.defaultRenderer;
6453 return _this;
6454 }
6455 /**
6456 * Dispose of the resources held by the menu.
6457 */
6458 Menu.prototype.dispose = function () {
6459 this.close();
6460 this._items.length = 0;
6461 _super.prototype.dispose.call(this);
6462 };
6463 Object.defineProperty(Menu.prototype, "aboutToClose", {
6464 /**
6465 * A signal emitted just before the menu is closed.
6466 *
6467 * #### Notes
6468 * This signal is emitted when the menu receives a `'close-request'`
6469 * message, just before it removes itself from the DOM.
6470 *
6471 * This signal is not emitted if the menu is already detached from
6472 * the DOM when it receives the `'close-request'` message.
6473 */
6474 get: function () {
6475 return this._aboutToClose;
6476 },
6477 enumerable: true,
6478 configurable: true
6479 });
6480 Object.defineProperty(Menu.prototype, "menuRequested", {
6481 /**
6482 * A signal emitted when a new menu is requested by the user.
6483 *
6484 * #### Notes
6485 * This signal is emitted whenever the user presses the right or left
6486 * arrow keys, and a submenu cannot be opened or closed in response.
6487 *
6488 * This signal is useful when implementing menu bars in order to open
6489 * the next or previous menu in response to a user key press.
6490 *
6491 * This signal is only emitted for the root menu in a hierarchy.
6492 */
6493 get: function () {
6494 return this._menuRequested;
6495 },
6496 enumerable: true,
6497 configurable: true
6498 });
6499 Object.defineProperty(Menu.prototype, "parentMenu", {
6500 /**
6501 * The parent menu of the menu.
6502 *
6503 * #### Notes
6504 * This is `null` unless the menu is an open submenu.
6505 */
6506 get: function () {
6507 return this._parentMenu;
6508 },
6509 enumerable: true,
6510 configurable: true
6511 });
6512 Object.defineProperty(Menu.prototype, "childMenu", {
6513 /**
6514 * The child menu of the menu.
6515 *
6516 * #### Notes
6517 * This is `null` unless the menu has an open submenu.
6518 */
6519 get: function () {
6520 return this._childMenu;
6521 },
6522 enumerable: true,
6523 configurable: true
6524 });
6525 Object.defineProperty(Menu.prototype, "rootMenu", {
6526 /**
6527 * The root menu of the menu hierarchy.
6528 */
6529 get: function () {
6530 // eslint-disable-next-line @typescript-eslint/no-this-alias
6531 var menu = this;
6532 while (menu._parentMenu) {
6533 menu = menu._parentMenu;
6534 }
6535 return menu;
6536 },
6537 enumerable: true,
6538 configurable: true
6539 });
6540 Object.defineProperty(Menu.prototype, "leafMenu", {
6541 /**
6542 * The leaf menu of the menu hierarchy.
6543 */
6544 get: function () {
6545 // eslint-disable-next-line @typescript-eslint/no-this-alias
6546 var menu = this;
6547 while (menu._childMenu) {
6548 menu = menu._childMenu;
6549 }
6550 return menu;
6551 },
6552 enumerable: true,
6553 configurable: true
6554 });
6555 Object.defineProperty(Menu.prototype, "contentNode", {
6556 /**
6557 * The menu content node.
6558 *
6559 * #### Notes
6560 * This is the node which holds the menu item nodes.
6561 *
6562 * Modifying this node directly can lead to undefined behavior.
6563 */
6564 get: function () {
6565 return this.node.getElementsByClassName('lm-Menu-content')[0];
6566 },
6567 enumerable: true,
6568 configurable: true
6569 });
6570 Object.defineProperty(Menu.prototype, "activeItem", {
6571 /**
6572 * Get the currently active menu item.
6573 */
6574 get: function () {
6575 return this._items[this._activeIndex] || null;
6576 },
6577 /**
6578 * Set the currently active menu item.
6579 *
6580 * #### Notes
6581 * If the item cannot be activated, the item will be set to `null`.
6582 */
6583 set: function (value) {
6584 this.activeIndex = value ? this._items.indexOf(value) : -1;
6585 },
6586 enumerable: true,
6587 configurable: true
6588 });
6589 Object.defineProperty(Menu.prototype, "activeIndex", {
6590 /**
6591 * Get the index of the currently active menu item.
6592 *
6593 * #### Notes
6594 * This will be `-1` if no menu item is active.
6595 */
6596 get: function () {
6597 return this._activeIndex;
6598 },
6599 /**
6600 * Set the index of the currently active menu item.
6601 *
6602 * #### Notes
6603 * If the item cannot be activated, the index will be set to `-1`.
6604 */
6605 set: function (value) {
6606 // Adjust the value for an out of range index.
6607 if (value < 0 || value >= this._items.length) {
6608 value = -1;
6609 }
6610 // Ensure the item can be activated.
6611 if (value !== -1 && !Private$9.canActivate(this._items[value])) {
6612 value = -1;
6613 }
6614 // Bail if the index will not change.
6615 if (this._activeIndex === value) {
6616 return;
6617 }
6618 // Update the active index.
6619 this._activeIndex = value;
6620 // Make active element in focus
6621 if (this._activeIndex >= 0 &&
6622 this.contentNode.childNodes[this._activeIndex]) {
6623 this.contentNode.childNodes[this._activeIndex].focus();
6624 }
6625 // schedule an update of the items.
6626 this.update();
6627 },
6628 enumerable: true,
6629 configurable: true
6630 });
6631 Object.defineProperty(Menu.prototype, "items", {
6632 /**
6633 * A read-only array of the menu items in the menu.
6634 */
6635 get: function () {
6636 return this._items;
6637 },
6638 enumerable: true,
6639 configurable: true
6640 });
6641 /**
6642 * Activate the next selectable item in the menu.
6643 *
6644 * #### Notes
6645 * If no item is selectable, the index will be set to `-1`.
6646 */
6647 Menu.prototype.activateNextItem = function () {
6648 var n = this._items.length;
6649 var ai = this._activeIndex;
6650 var start = ai < n - 1 ? ai + 1 : 0;
6651 var stop = start === 0 ? n - 1 : start - 1;
6652 this.activeIndex = ArrayExt.findFirstIndex(this._items, Private$9.canActivate, start, stop);
6653 };
6654 /**
6655 * Activate the previous selectable item in the menu.
6656 *
6657 * #### Notes
6658 * If no item is selectable, the index will be set to `-1`.
6659 */
6660 Menu.prototype.activatePreviousItem = function () {
6661 var n = this._items.length;
6662 var ai = this._activeIndex;
6663 var start = ai <= 0 ? n - 1 : ai - 1;
6664 var stop = start === n - 1 ? 0 : start + 1;
6665 this.activeIndex = ArrayExt.findLastIndex(this._items, Private$9.canActivate, start, stop);
6666 };
6667 /**
6668 * Trigger the active menu item.
6669 *
6670 * #### Notes
6671 * If the active item is a submenu, it will be opened and the first
6672 * item will be activated.
6673 *
6674 * If the active item is a command, the command will be executed.
6675 *
6676 * If the menu is not attached, this is a no-op.
6677 *
6678 * If there is no active item, this is a no-op.
6679 */
6680 Menu.prototype.triggerActiveItem = function () {
6681 // Bail if the menu is not attached.
6682 if (!this.isAttached) {
6683 return;
6684 }
6685 // Bail if there is no active item.
6686 var item = this.activeItem;
6687 if (!item) {
6688 return;
6689 }
6690 // Cancel the pending timers.
6691 this._cancelOpenTimer();
6692 this._cancelCloseTimer();
6693 // If the item is a submenu, open it.
6694 if (item.type === 'submenu') {
6695 this._openChildMenu(true);
6696 return;
6697 }
6698 // Close the root menu before executing the command.
6699 this.rootMenu.close();
6700 // Execute the command for the item.
6701 var command = item.command, args = item.args;
6702 if (this.commands.isEnabled(command, args)) {
6703 this.commands.execute(command, args);
6704 }
6705 else {
6706 console.log("Command '" + command + "' is disabled.");
6707 }
6708 };
6709 /**
6710 * Add a menu item to the end of the menu.
6711 *
6712 * @param options - The options for creating the menu item.
6713 *
6714 * @returns The menu item added to the menu.
6715 */
6716 Menu.prototype.addItem = function (options) {
6717 return this.insertItem(this._items.length, options);
6718 };
6719 /**
6720 * Insert a menu item into the menu at the specified index.
6721 *
6722 * @param index - The index at which to insert the item.
6723 *
6724 * @param options - The options for creating the menu item.
6725 *
6726 * @returns The menu item added to the menu.
6727 *
6728 * #### Notes
6729 * The index will be clamped to the bounds of the items.
6730 */
6731 Menu.prototype.insertItem = function (index, options) {
6732 // Close the menu if it's attached.
6733 if (this.isAttached) {
6734 this.close();
6735 }
6736 // Reset the active index.
6737 this.activeIndex = -1;
6738 // Clamp the insert index to the array bounds.
6739 var i = Math.max(0, Math.min(index, this._items.length));
6740 // Create the item for the options.
6741 var item = Private$9.createItem(this, options);
6742 // Insert the item into the array.
6743 ArrayExt.insert(this._items, i, item);
6744 // Schedule an update of the items.
6745 this.update();
6746 // Return the item added to the menu.
6747 return item;
6748 };
6749 /**
6750 * Remove an item from the menu.
6751 *
6752 * @param item - The item to remove from the menu.
6753 *
6754 * #### Notes
6755 * This is a no-op if the item is not in the menu.
6756 */
6757 Menu.prototype.removeItem = function (item) {
6758 this.removeItemAt(this._items.indexOf(item));
6759 };
6760 /**
6761 * Remove the item at a given index from the menu.
6762 *
6763 * @param index - The index of the item to remove.
6764 *
6765 * #### Notes
6766 * This is a no-op if the index is out of range.
6767 */
6768 Menu.prototype.removeItemAt = function (index) {
6769 // Close the menu if it's attached.
6770 if (this.isAttached) {
6771 this.close();
6772 }
6773 // Reset the active index.
6774 this.activeIndex = -1;
6775 // Remove the item from the array.
6776 var item = ArrayExt.removeAt(this._items, index);
6777 // Bail if the index is out of range.
6778 if (!item) {
6779 return;
6780 }
6781 // Schedule an update of the items.
6782 this.update();
6783 };
6784 /**
6785 * Remove all menu items from the menu.
6786 */
6787 Menu.prototype.clearItems = function () {
6788 // Close the menu if it's attached.
6789 if (this.isAttached) {
6790 this.close();
6791 }
6792 // Reset the active index.
6793 this.activeIndex = -1;
6794 // Bail if there is nothing to remove.
6795 if (this._items.length === 0) {
6796 return;
6797 }
6798 // Clear the items.
6799 this._items.length = 0;
6800 // Schedule an update of the items.
6801 this.update();
6802 };
6803 /**
6804 * Open the menu at the specified location.
6805 *
6806 * @param x - The client X coordinate of the menu location.
6807 *
6808 * @param y - The client Y coordinate of the menu location.
6809 *
6810 * @param options - The additional options for opening the menu.
6811 *
6812 * #### Notes
6813 * The menu will be opened at the given location unless it will not
6814 * fully fit on the screen. If it will not fit, it will be adjusted
6815 * to fit naturally on the screen.
6816 *
6817 * This is a no-op if the menu is already attached to the DOM.
6818 */
6819 Menu.prototype.open = function (x, y, options) {
6820 if (options === void 0) { options = {}; }
6821 // Bail early if the menu is already attached.
6822 if (this.isAttached) {
6823 return;
6824 }
6825 // Extract the position options.
6826 var forceX = options.forceX || false;
6827 var forceY = options.forceY || false;
6828 // Open the menu as a root menu.
6829 Private$9.openRootMenu(this, x, y, forceX, forceY);
6830 // Activate the menu to accept keyboard input.
6831 this.activate();
6832 };
6833 /**
6834 * Handle the DOM events for the menu.
6835 *
6836 * @param event - The DOM event sent to the menu.
6837 *
6838 * #### Notes
6839 * This method implements the DOM `EventListener` interface and is
6840 * called in response to events on the menu's DOM nodes. It should
6841 * not be called directly by user code.
6842 */
6843 Menu.prototype.handleEvent = function (event) {
6844 switch (event.type) {
6845 case 'keydown':
6846 this._evtKeyDown(event);
6847 break;
6848 case 'mouseup':
6849 this._evtMouseUp(event);
6850 break;
6851 case 'mousemove':
6852 this._evtMouseMove(event);
6853 break;
6854 case 'mouseenter':
6855 this._evtMouseEnter(event);
6856 break;
6857 case 'mouseleave':
6858 this._evtMouseLeave(event);
6859 break;
6860 case 'mousedown':
6861 this._evtMouseDown(event);
6862 break;
6863 case 'contextmenu':
6864 event.preventDefault();
6865 event.stopPropagation();
6866 break;
6867 }
6868 };
6869 /**
6870 * A message handler invoked on a `'before-attach'` message.
6871 */
6872 Menu.prototype.onBeforeAttach = function (msg) {
6873 this.node.addEventListener('keydown', this);
6874 this.node.addEventListener('mouseup', this);
6875 this.node.addEventListener('mousemove', this);
6876 this.node.addEventListener('mouseenter', this);
6877 this.node.addEventListener('mouseleave', this);
6878 this.node.addEventListener('contextmenu', this);
6879 document.addEventListener('mousedown', this, true);
6880 };
6881 /**
6882 * A message handler invoked on an `'after-detach'` message.
6883 */
6884 Menu.prototype.onAfterDetach = function (msg) {
6885 this.node.removeEventListener('keydown', this);
6886 this.node.removeEventListener('mouseup', this);
6887 this.node.removeEventListener('mousemove', this);
6888 this.node.removeEventListener('mouseenter', this);
6889 this.node.removeEventListener('mouseleave', this);
6890 this.node.removeEventListener('contextmenu', this);
6891 document.removeEventListener('mousedown', this, true);
6892 };
6893 /**
6894 * A message handler invoked on an `'activate-request'` message.
6895 */
6896 Menu.prototype.onActivateRequest = function (msg) {
6897 if (this.isAttached) {
6898 this.node.focus();
6899 }
6900 };
6901 /**
6902 * A message handler invoked on an `'update-request'` message.
6903 */
6904 Menu.prototype.onUpdateRequest = function (msg) {
6905 var _this = this;
6906 var items = this._items;
6907 var renderer = this.renderer;
6908 var activeIndex = this._activeIndex;
6909 var collapsedFlags = Private$9.computeCollapsed(items);
6910 var content = new Array(items.length);
6911 var _loop_1 = function (i, n) {
6912 var item = items[i];
6913 var active = i === activeIndex;
6914 var collapsed = collapsedFlags[i];
6915 content[i] = renderer.renderItem({
6916 item: item,
6917 active: active,
6918 collapsed: collapsed,
6919 onfocus: function () {
6920 _this.activeIndex = i;
6921 }
6922 });
6923 };
6924 for (var i = 0, n = items.length; i < n; ++i) {
6925 _loop_1(i);
6926 }
6927 VirtualDOM.render(content, this.contentNode);
6928 };
6929 /**
6930 * A message handler invoked on a `'close-request'` message.
6931 */
6932 Menu.prototype.onCloseRequest = function (msg) {
6933 // Cancel the pending timers.
6934 this._cancelOpenTimer();
6935 this._cancelCloseTimer();
6936 // Reset the active index.
6937 this.activeIndex = -1;
6938 // Close any open child menu.
6939 var childMenu = this._childMenu;
6940 if (childMenu) {
6941 this._childIndex = -1;
6942 this._childMenu = null;
6943 childMenu._parentMenu = null;
6944 childMenu.close();
6945 }
6946 // Remove this menu from its parent and activate the parent.
6947 var parentMenu = this._parentMenu;
6948 if (parentMenu) {
6949 this._parentMenu = null;
6950 parentMenu._childIndex = -1;
6951 parentMenu._childMenu = null;
6952 parentMenu.activate();
6953 }
6954 // Emit the `aboutToClose` signal if the menu is attached.
6955 if (this.isAttached) {
6956 this._aboutToClose.emit(undefined);
6957 }
6958 // Finish closing the menu.
6959 _super.prototype.onCloseRequest.call(this, msg);
6960 };
6961 /**
6962 * Handle the `'keydown'` event for the menu.
6963 *
6964 * #### Notes
6965 * This listener is attached to the menu node.
6966 */
6967 Menu.prototype._evtKeyDown = function (event) {
6968 // A menu handles all keydown events.
6969 event.preventDefault();
6970 event.stopPropagation();
6971 // Fetch the key code for the event.
6972 var kc = event.keyCode;
6973 // Enter
6974 if (kc === 13) {
6975 this.triggerActiveItem();
6976 return;
6977 }
6978 // Escape
6979 if (kc === 27) {
6980 this.close();
6981 return;
6982 }
6983 // Left Arrow
6984 if (kc === 37) {
6985 if (this._parentMenu) {
6986 this.close();
6987 }
6988 else {
6989 this._menuRequested.emit('previous');
6990 }
6991 return;
6992 }
6993 // Up Arrow
6994 if (kc === 38) {
6995 this.activatePreviousItem();
6996 return;
6997 }
6998 // Right Arrow
6999 if (kc === 39) {
7000 var item = this.activeItem;
7001 if (item && item.type === 'submenu') {
7002 this.triggerActiveItem();
7003 }
7004 else {
7005 this.rootMenu._menuRequested.emit('next');
7006 }
7007 return;
7008 }
7009 // Down Arrow
7010 if (kc === 40) {
7011 this.activateNextItem();
7012 return;
7013 }
7014 // Get the pressed key character.
7015 var key = getKeyboardLayout().keyForKeydownEvent(event);
7016 // Bail if the key is not valid.
7017 if (!key) {
7018 return;
7019 }
7020 // Search for the next best matching mnemonic item.
7021 var start = this._activeIndex + 1;
7022 var result = Private$9.findMnemonic(this._items, key, start);
7023 // Handle the requested mnemonic based on the search results.
7024 // If exactly one mnemonic is matched, that item is triggered.
7025 // Otherwise, the next mnemonic is activated if available,
7026 // followed by the auto mnemonic if available.
7027 if (result.index !== -1 && !result.multiple) {
7028 this.activeIndex = result.index;
7029 this.triggerActiveItem();
7030 }
7031 else if (result.index !== -1) {
7032 this.activeIndex = result.index;
7033 }
7034 else if (result.auto !== -1) {
7035 this.activeIndex = result.auto;
7036 }
7037 };
7038 /**
7039 * Handle the `'mouseup'` event for the menu.
7040 *
7041 * #### Notes
7042 * This listener is attached to the menu node.
7043 */
7044 Menu.prototype._evtMouseUp = function (event) {
7045 if (event.button !== 0) {
7046 return;
7047 }
7048 event.preventDefault();
7049 event.stopPropagation();
7050 this.triggerActiveItem();
7051 };
7052 /**
7053 * Handle the `'mousemove'` event for the menu.
7054 *
7055 * #### Notes
7056 * This listener is attached to the menu node.
7057 */
7058 Menu.prototype._evtMouseMove = function (event) {
7059 // Hit test the item nodes for the item under the mouse.
7060 var index = ArrayExt.findFirstIndex(this.contentNode.children, function (node) {
7061 return ElementExt.hitTest(node, event.clientX, event.clientY);
7062 });
7063 // Bail early if the mouse is already over the active index.
7064 if (index === this._activeIndex) {
7065 return;
7066 }
7067 // Update and coerce the active index.
7068 this.activeIndex = index;
7069 index = this.activeIndex;
7070 // If the index is the current child index, cancel the timers.
7071 if (index === this._childIndex) {
7072 this._cancelOpenTimer();
7073 this._cancelCloseTimer();
7074 return;
7075 }
7076 // If a child menu is currently open, start the close timer.
7077 if (this._childIndex !== -1) {
7078 this._startCloseTimer();
7079 }
7080 // Cancel the open timer to give a full delay for opening.
7081 this._cancelOpenTimer();
7082 // Bail if the active item is not a valid submenu item.
7083 var item = this.activeItem;
7084 if (!item || item.type !== 'submenu' || !item.submenu) {
7085 return;
7086 }
7087 // Start the open timer to open the active item submenu.
7088 this._startOpenTimer();
7089 };
7090 /**
7091 * Handle the `'mouseenter'` event for the menu.
7092 *
7093 * #### Notes
7094 * This listener is attached to the menu node.
7095 */
7096 Menu.prototype._evtMouseEnter = function (event) {
7097 // Synchronize the active ancestor items.
7098 for (var menu = this._parentMenu; menu; menu = menu._parentMenu) {
7099 menu._cancelOpenTimer();
7100 menu._cancelCloseTimer();
7101 menu.activeIndex = menu._childIndex;
7102 }
7103 };
7104 /**
7105 * Handle the `'mouseleave'` event for the menu.
7106 *
7107 * #### Notes
7108 * This listener is attached to the menu node.
7109 */
7110 Menu.prototype._evtMouseLeave = function (event) {
7111 // Cancel any pending submenu opening.
7112 this._cancelOpenTimer();
7113 // If there is no open child menu, just reset the active index.
7114 if (!this._childMenu) {
7115 this.activeIndex = -1;
7116 return;
7117 }
7118 // If the mouse is over the child menu, cancel the close timer.
7119 var clientX = event.clientX, clientY = event.clientY;
7120 if (ElementExt.hitTest(this._childMenu.node, clientX, clientY)) {
7121 this._cancelCloseTimer();
7122 return;
7123 }
7124 // Otherwise, reset the active index and start the close timer.
7125 this.activeIndex = -1;
7126 this._startCloseTimer();
7127 };
7128 /**
7129 * Handle the `'mousedown'` event for the menu.
7130 *
7131 * #### Notes
7132 * This listener is attached to the document node.
7133 */
7134 Menu.prototype._evtMouseDown = function (event) {
7135 // Bail if the menu is not a root menu.
7136 if (this._parentMenu) {
7137 return;
7138 }
7139 // The mouse button which is pressed is irrelevant. If the press
7140 // is not on a menu, the entire hierarchy is closed and the event
7141 // is allowed to propagate. This allows other code to act on the
7142 // event, such as focusing the clicked element.
7143 if (Private$9.hitTestMenus(this, event.clientX, event.clientY)) {
7144 event.preventDefault();
7145 event.stopPropagation();
7146 }
7147 else {
7148 this.close();
7149 }
7150 };
7151 /**
7152 * Open the child menu at the active index immediately.
7153 *
7154 * If a different child menu is already open, it will be closed,
7155 * even if the active item is not a valid submenu.
7156 */
7157 Menu.prototype._openChildMenu = function (activateFirst) {
7158 if (activateFirst === void 0) { activateFirst = false; }
7159 // If the item is not a valid submenu, close the child menu.
7160 var item = this.activeItem;
7161 if (!item || item.type !== 'submenu' || !item.submenu) {
7162 this._closeChildMenu();
7163 return;
7164 }
7165 // Do nothing if the child menu will not change.
7166 var submenu = item.submenu;
7167 if (submenu === this._childMenu) {
7168 return;
7169 }
7170 // Ensure the current child menu is closed.
7171 this._closeChildMenu();
7172 // Update the private child state.
7173 this._childMenu = submenu;
7174 this._childIndex = this._activeIndex;
7175 // Set the parent menu reference for the child.
7176 submenu._parentMenu = this;
7177 // Ensure the menu is updated and lookup the item node.
7178 MessageLoop.sendMessage(this, Widget.Msg.UpdateRequest);
7179 var itemNode = this.contentNode.children[this._activeIndex];
7180 // Open the submenu at the active node.
7181 Private$9.openSubmenu(submenu, itemNode);
7182 // Activate the first item if desired.
7183 if (activateFirst) {
7184 submenu.activeIndex = -1;
7185 submenu.activateNextItem();
7186 }
7187 // Activate the child menu.
7188 submenu.activate();
7189 };
7190 /**
7191 * Close the child menu immediately.
7192 *
7193 * This is a no-op if a child menu is not open.
7194 */
7195 Menu.prototype._closeChildMenu = function () {
7196 if (this._childMenu) {
7197 this._childMenu.close();
7198 }
7199 };
7200 /**
7201 * Start the open timer, unless it is already pending.
7202 */
7203 Menu.prototype._startOpenTimer = function () {
7204 var _this = this;
7205 if (this._openTimerID === 0) {
7206 this._openTimerID = window.setTimeout(function () {
7207 _this._openTimerID = 0;
7208 _this._openChildMenu();
7209 }, Private$9.TIMER_DELAY);
7210 }
7211 };
7212 /**
7213 * Start the close timer, unless it is already pending.
7214 */
7215 Menu.prototype._startCloseTimer = function () {
7216 var _this = this;
7217 if (this._closeTimerID === 0) {
7218 this._closeTimerID = window.setTimeout(function () {
7219 _this._closeTimerID = 0;
7220 _this._closeChildMenu();
7221 }, Private$9.TIMER_DELAY);
7222 }
7223 };
7224 /**
7225 * Cancel the open timer, if the timer is pending.
7226 */
7227 Menu.prototype._cancelOpenTimer = function () {
7228 if (this._openTimerID !== 0) {
7229 clearTimeout(this._openTimerID);
7230 this._openTimerID = 0;
7231 }
7232 };
7233 /**
7234 * Cancel the close timer, if the timer is pending.
7235 */
7236 Menu.prototype._cancelCloseTimer = function () {
7237 if (this._closeTimerID !== 0) {
7238 clearTimeout(this._closeTimerID);
7239 this._closeTimerID = 0;
7240 }
7241 };
7242 return Menu;
7243}(Widget));
7244/**
7245 * The namespace for the `Menu` class statics.
7246 */
7247(function (Menu) {
7248 /**
7249 * The default implementation of `IRenderer`.
7250 *
7251 * #### Notes
7252 * Subclasses are free to reimplement rendering methods as needed.
7253 */
7254 var Renderer = /** @class */ (function () {
7255 function Renderer() {
7256 }
7257 /**
7258 * Render the virtual element for a menu item.
7259 *
7260 * @param data - The data to use for rendering the item.
7261 *
7262 * @returns A virtual element representing the item.
7263 */
7264 Renderer.prototype.renderItem = function (data) {
7265 var className = this.createItemClass(data);
7266 var dataset = this.createItemDataset(data);
7267 var aria = this.createItemARIA(data);
7268 return h.li(__assign({ className: className,
7269 dataset: dataset, tabindex: '0', onfocus: data.onfocus }, aria), this.renderIcon(data), this.renderLabel(data), this.renderShortcut(data), this.renderSubmenu(data));
7270 };
7271 /**
7272 * Render the icon element for a menu item.
7273 *
7274 * @param data - The data to use for rendering the icon.
7275 *
7276 * @returns A virtual element representing the item icon.
7277 */
7278 Renderer.prototype.renderIcon = function (data) {
7279 var className = this.createIconClass(data);
7280 /* <DEPRECATED> */
7281 if (typeof data.item.icon === 'string') {
7282 return h.div({ className: className }, data.item.iconLabel);
7283 }
7284 /* </DEPRECATED> */
7285 // if data.item.icon is undefined, it will be ignored
7286 return h.div({ className: className }, data.item.icon, data.item.iconLabel);
7287 };
7288 /**
7289 * Render the label element for a menu item.
7290 *
7291 * @param data - The data to use for rendering the label.
7292 *
7293 * @returns A virtual element representing the item label.
7294 */
7295 Renderer.prototype.renderLabel = function (data) {
7296 var content = this.formatLabel(data);
7297 return h.div({
7298 className: 'lm-Menu-itemLabel' +
7299 /* <DEPRECATED> */
7300 ' p-Menu-itemLabel'
7301 /* </DEPRECATED> */
7302 }, content);
7303 };
7304 /**
7305 * Render the shortcut element for a menu item.
7306 *
7307 * @param data - The data to use for rendering the shortcut.
7308 *
7309 * @returns A virtual element representing the item shortcut.
7310 */
7311 Renderer.prototype.renderShortcut = function (data) {
7312 var content = this.formatShortcut(data);
7313 return h.div({
7314 className: 'lm-Menu-itemShortcut' +
7315 /* <DEPRECATED> */
7316 ' p-Menu-itemShortcut'
7317 /* </DEPRECATED> */
7318 }, content);
7319 };
7320 /**
7321 * Render the submenu icon element for a menu item.
7322 *
7323 * @param data - The data to use for rendering the submenu icon.
7324 *
7325 * @returns A virtual element representing the submenu icon.
7326 */
7327 Renderer.prototype.renderSubmenu = function (data) {
7328 return h.div({
7329 className: 'lm-Menu-itemSubmenuIcon' +
7330 /* <DEPRECATED> */
7331 ' p-Menu-itemSubmenuIcon'
7332 /* </DEPRECATED> */
7333 });
7334 };
7335 /**
7336 * Create the class name for the menu item.
7337 *
7338 * @param data - The data to use for the class name.
7339 *
7340 * @returns The full class name for the menu item.
7341 */
7342 Renderer.prototype.createItemClass = function (data) {
7343 // Setup the initial class name.
7344 var name = 'lm-Menu-item';
7345 /* <DEPRECATED> */
7346 name += ' p-Menu-item';
7347 /* </DEPRECATED> */
7348 // Add the boolean state classes.
7349 if (!data.item.isEnabled) {
7350 name += ' lm-mod-disabled';
7351 /* <DEPRECATED> */
7352 name += ' p-mod-disabled';
7353 /* </DEPRECATED> */
7354 }
7355 if (data.item.isToggled) {
7356 name += ' lm-mod-toggled';
7357 /* <DEPRECATED> */
7358 name += ' p-mod-toggled';
7359 /* </DEPRECATED> */
7360 }
7361 if (!data.item.isVisible) {
7362 name += ' lm-mod-hidden';
7363 /* <DEPRECATED> */
7364 name += ' p-mod-hidden';
7365 /* </DEPRECATED> */
7366 }
7367 if (data.active) {
7368 name += ' lm-mod-active';
7369 /* <DEPRECATED> */
7370 name += ' p-mod-active';
7371 /* </DEPRECATED> */
7372 }
7373 if (data.collapsed) {
7374 name += ' lm-mod-collapsed';
7375 /* <DEPRECATED> */
7376 name += ' p-mod-collapsed';
7377 /* </DEPRECATED> */
7378 }
7379 // Add the extra class.
7380 var extra = data.item.className;
7381 if (extra) {
7382 name += " " + extra;
7383 }
7384 // Return the complete class name.
7385 return name;
7386 };
7387 /**
7388 * Create the dataset for the menu item.
7389 *
7390 * @param data - The data to use for creating the dataset.
7391 *
7392 * @returns The dataset for the menu item.
7393 */
7394 Renderer.prototype.createItemDataset = function (data) {
7395 var result;
7396 var _a = data.item, type = _a.type, command = _a.command, dataset = _a.dataset;
7397 if (type === 'command') {
7398 result = __assign(__assign({}, dataset), { type: type, command: command });
7399 }
7400 else {
7401 result = __assign(__assign({}, dataset), { type: type });
7402 }
7403 return result;
7404 };
7405 /**
7406 * Create the class name for the menu item icon.
7407 *
7408 * @param data - The data to use for the class name.
7409 *
7410 * @returns The full class name for the item icon.
7411 */
7412 Renderer.prototype.createIconClass = function (data) {
7413 var name = 'lm-Menu-itemIcon';
7414 /* <DEPRECATED> */
7415 name += ' p-Menu-itemIcon';
7416 /* </DEPRECATED> */
7417 var extra = data.item.iconClass;
7418 return extra ? name + " " + extra : name;
7419 };
7420 /**
7421 * Create the aria attributes for menu item.
7422 *
7423 * @param data - The data to use for the aria attributes.
7424 *
7425 * @returns The aria attributes object for the item.
7426 */
7427 Renderer.prototype.createItemARIA = function (data) {
7428 var aria = {};
7429 switch (data.item.type) {
7430 case 'separator':
7431 aria.role = 'presentation';
7432 break;
7433 case 'submenu':
7434 aria['aria-haspopup'] = 'true';
7435 if (!data.item.isEnabled) {
7436 aria['aria-disabled'] = 'true';
7437 }
7438 break;
7439 default:
7440 if (!data.item.isEnabled) {
7441 aria['aria-disabled'] = 'true';
7442 }
7443 aria.role = 'menuitem';
7444 }
7445 return aria;
7446 };
7447 /**
7448 * Create the render content for the label node.
7449 *
7450 * @param data - The data to use for the label content.
7451 *
7452 * @returns The content to add to the label node.
7453 */
7454 Renderer.prototype.formatLabel = function (data) {
7455 // Fetch the label text and mnemonic index.
7456 var _a = data.item, label = _a.label, mnemonic = _a.mnemonic;
7457 // If the index is out of range, do not modify the label.
7458 if (mnemonic < 0 || mnemonic >= label.length) {
7459 return label;
7460 }
7461 // Split the label into parts.
7462 var prefix = label.slice(0, mnemonic);
7463 var suffix = label.slice(mnemonic + 1);
7464 var char = label[mnemonic];
7465 // Wrap the mnemonic character in a span.
7466 var span = h.span({
7467 className: 'lm-Menu-itemMnemonic' +
7468 /* <DEPRECATED> */
7469 ' p-Menu-itemMnemonic'
7470 /* </DEPRECATED> */
7471 }, char);
7472 // Return the content parts.
7473 return [prefix, span, suffix];
7474 };
7475 /**
7476 * Create the render content for the shortcut node.
7477 *
7478 * @param data - The data to use for the shortcut content.
7479 *
7480 * @returns The content to add to the shortcut node.
7481 */
7482 Renderer.prototype.formatShortcut = function (data) {
7483 var kb = data.item.keyBinding;
7484 return kb
7485 ? kb.keys.map(CommandRegistry.formatKeystroke).join(', ')
7486 : null;
7487 };
7488 return Renderer;
7489 }());
7490 Menu.Renderer = Renderer;
7491 /**
7492 * The default `Renderer` instance.
7493 */
7494 Menu.defaultRenderer = new Renderer();
7495})(Menu || (Menu = {}));
7496/**
7497 * The namespace for the module implementation details.
7498 */
7499var Private$9;
7500(function (Private) {
7501 /**
7502 * The ms delay for opening and closing a submenu.
7503 */
7504 Private.TIMER_DELAY = 300;
7505 /**
7506 * The horizontal pixel overlap for an open submenu.
7507 */
7508 Private.SUBMENU_OVERLAP = 3;
7509 /**
7510 * Create the DOM node for a menu.
7511 */
7512 function createNode() {
7513 var node = document.createElement('div');
7514 var content = document.createElement('ul');
7515 content.className = 'lm-Menu-content';
7516 /* <DEPRECATED> */
7517 content.classList.add('p-Menu-content');
7518 /* </DEPRECATED> */
7519 node.appendChild(content);
7520 content.setAttribute('role', 'menu');
7521 node.tabIndex = 0;
7522 return node;
7523 }
7524 Private.createNode = createNode;
7525 /**
7526 * Test whether a menu item can be activated.
7527 */
7528 function canActivate(item) {
7529 return item.type !== 'separator' && item.isEnabled && item.isVisible;
7530 }
7531 Private.canActivate = canActivate;
7532 /**
7533 * Create a new menu item for an owner menu.
7534 */
7535 function createItem(owner, options) {
7536 return new MenuItem(owner.commands, options);
7537 }
7538 Private.createItem = createItem;
7539 /**
7540 * Hit test a menu hierarchy starting at the given root.
7541 */
7542 function hitTestMenus(menu, x, y) {
7543 for (var temp = menu; temp; temp = temp.childMenu) {
7544 if (ElementExt.hitTest(temp.node, x, y)) {
7545 return true;
7546 }
7547 }
7548 return false;
7549 }
7550 Private.hitTestMenus = hitTestMenus;
7551 /**
7552 * Compute which extra separator items should be collapsed.
7553 */
7554 function computeCollapsed(items) {
7555 // Allocate the return array and fill it with `false`.
7556 var result = new Array(items.length);
7557 ArrayExt.fill(result, false);
7558 // Collapse the leading separators.
7559 var k1 = 0;
7560 var n = items.length;
7561 for (; k1 < n; ++k1) {
7562 var item = items[k1];
7563 if (!item.isVisible) {
7564 continue;
7565 }
7566 if (item.type !== 'separator') {
7567 break;
7568 }
7569 result[k1] = true;
7570 }
7571 // Hide the trailing separators.
7572 var k2 = n - 1;
7573 for (; k2 >= 0; --k2) {
7574 var item = items[k2];
7575 if (!item.isVisible) {
7576 continue;
7577 }
7578 if (item.type !== 'separator') {
7579 break;
7580 }
7581 result[k2] = true;
7582 }
7583 // Hide the remaining consecutive separators.
7584 var hide = false;
7585 while (++k1 < k2) {
7586 var item = items[k1];
7587 if (!item.isVisible) {
7588 continue;
7589 }
7590 if (item.type !== 'separator') {
7591 hide = false;
7592 }
7593 else if (hide) {
7594 result[k1] = true;
7595 }
7596 else {
7597 hide = true;
7598 }
7599 }
7600 // Return the resulting flags.
7601 return result;
7602 }
7603 Private.computeCollapsed = computeCollapsed;
7604 /**
7605 * Open a menu as a root menu at the target location.
7606 */
7607 function openRootMenu(menu, x, y, forceX, forceY) {
7608 // Ensure the menu is updated before attaching and measuring.
7609 MessageLoop.sendMessage(menu, Widget.Msg.UpdateRequest);
7610 // Get the current position and size of the main viewport.
7611 var px = window.pageXOffset;
7612 var py = window.pageYOffset;
7613 var cw = document.documentElement.clientWidth;
7614 var ch = document.documentElement.clientHeight;
7615 // Compute the maximum allowed height for the menu.
7616 var maxHeight = ch - (forceY ? y : 0);
7617 // Fetch common variables.
7618 var node = menu.node;
7619 var style = node.style;
7620 // Clear the menu geometry and prepare it for measuring.
7621 style.top = '';
7622 style.left = '';
7623 style.width = '';
7624 style.height = '';
7625 style.visibility = 'hidden';
7626 style.maxHeight = maxHeight + "px";
7627 // Attach the menu to the document.
7628 Widget.attach(menu, document.body);
7629 // Measure the size of the menu.
7630 var _a = node.getBoundingClientRect(), width = _a.width, height = _a.height;
7631 // Adjust the X position of the menu to fit on-screen.
7632 if (!forceX && x + width > px + cw) {
7633 x = px + cw - width;
7634 }
7635 // Adjust the Y position of the menu to fit on-screen.
7636 if (!forceY && y + height > py + ch) {
7637 if (y > py + ch) {
7638 y = py + ch - height;
7639 }
7640 else {
7641 y = y - height;
7642 }
7643 }
7644 // Update the position of the menu to the computed position.
7645 style.top = Math.max(0, y) + "px";
7646 style.left = Math.max(0, x) + "px";
7647 // Finally, make the menu visible on the screen.
7648 style.visibility = '';
7649 }
7650 Private.openRootMenu = openRootMenu;
7651 /**
7652 * Open a menu as a submenu using an item node for positioning.
7653 */
7654 function openSubmenu(submenu, itemNode) {
7655 // Ensure the menu is updated before opening.
7656 MessageLoop.sendMessage(submenu, Widget.Msg.UpdateRequest);
7657 // Get the current position and size of the main viewport.
7658 var px = window.pageXOffset;
7659 var py = window.pageYOffset;
7660 var cw = document.documentElement.clientWidth;
7661 var ch = document.documentElement.clientHeight;
7662 // Compute the maximum allowed height for the menu.
7663 var maxHeight = ch;
7664 // Fetch common variables.
7665 var node = submenu.node;
7666 var style = node.style;
7667 // Clear the menu geometry and prepare it for measuring.
7668 style.top = '';
7669 style.left = '';
7670 style.width = '';
7671 style.height = '';
7672 style.visibility = 'hidden';
7673 style.maxHeight = maxHeight + "px";
7674 // Attach the menu to the document.
7675 Widget.attach(submenu, document.body);
7676 // Measure the size of the menu.
7677 var _a = node.getBoundingClientRect(), width = _a.width, height = _a.height;
7678 // Compute the box sizing for the menu.
7679 var box = ElementExt.boxSizing(submenu.node);
7680 // Get the bounding rect for the target item node.
7681 var itemRect = itemNode.getBoundingClientRect();
7682 // Compute the target X position.
7683 var x = itemRect.right - Private.SUBMENU_OVERLAP;
7684 // Adjust the X position to fit on the screen.
7685 if (x + width > px + cw) {
7686 x = itemRect.left + Private.SUBMENU_OVERLAP - width;
7687 }
7688 // Compute the target Y position.
7689 var y = itemRect.top - box.borderTop - box.paddingTop;
7690 // Adjust the Y position to fit on the screen.
7691 if (y + height > py + ch) {
7692 y = itemRect.bottom + box.borderBottom + box.paddingBottom - height;
7693 }
7694 // Update the position of the menu to the computed position.
7695 style.top = Math.max(0, y) + "px";
7696 style.left = Math.max(0, x) + "px";
7697 // Finally, make the menu visible on the screen.
7698 style.visibility = '';
7699 }
7700 Private.openSubmenu = openSubmenu;
7701 /**
7702 * Find the best matching mnemonic item.
7703 *
7704 * The search starts at the given index and wraps around.
7705 */
7706 function findMnemonic(items, key, start) {
7707 // Setup the result variables.
7708 var index = -1;
7709 var auto = -1;
7710 var multiple = false;
7711 // Normalize the key to upper case.
7712 var upperKey = key.toUpperCase();
7713 // Search the items from the given start index.
7714 for (var i = 0, n = items.length; i < n; ++i) {
7715 // Compute the wrapped index.
7716 var k = (i + start) % n;
7717 // Lookup the item
7718 var item = items[k];
7719 // Ignore items which cannot be activated.
7720 if (!canActivate(item)) {
7721 continue;
7722 }
7723 // Ignore items with an empty label.
7724 var label = item.label;
7725 if (label.length === 0) {
7726 continue;
7727 }
7728 // Lookup the mnemonic index for the label.
7729 var mn = item.mnemonic;
7730 // Handle a valid mnemonic index.
7731 if (mn >= 0 && mn < label.length) {
7732 if (label[mn].toUpperCase() === upperKey) {
7733 if (index === -1) {
7734 index = k;
7735 }
7736 else {
7737 multiple = true;
7738 }
7739 }
7740 continue;
7741 }
7742 // Finally, handle the auto index if possible.
7743 if (auto === -1 && label[0].toUpperCase() === upperKey) {
7744 auto = k;
7745 }
7746 }
7747 // Return the search results.
7748 return { index: index, multiple: multiple, auto: auto };
7749 }
7750 Private.findMnemonic = findMnemonic;
7751 /**
7752 * A concrete implementation of `Menu.IItem`.
7753 */
7754 var MenuItem = /** @class */ (function () {
7755 /**
7756 * Construct a new menu item.
7757 */
7758 function MenuItem(commands, options) {
7759 this._commands = commands;
7760 this.type = options.type || 'command';
7761 this.command = options.command || '';
7762 this.args = options.args || JSONExt.emptyObject;
7763 this.submenu = options.submenu || null;
7764 }
7765 Object.defineProperty(MenuItem.prototype, "label", {
7766 /**
7767 * The display label for the menu item.
7768 */
7769 get: function () {
7770 if (this.type === 'command') {
7771 return this._commands.label(this.command, this.args);
7772 }
7773 if (this.type === 'submenu' && this.submenu) {
7774 return this.submenu.title.label;
7775 }
7776 return '';
7777 },
7778 enumerable: true,
7779 configurable: true
7780 });
7781 Object.defineProperty(MenuItem.prototype, "mnemonic", {
7782 /**
7783 * The mnemonic index for the menu item.
7784 */
7785 get: function () {
7786 if (this.type === 'command') {
7787 return this._commands.mnemonic(this.command, this.args);
7788 }
7789 if (this.type === 'submenu' && this.submenu) {
7790 return this.submenu.title.mnemonic;
7791 }
7792 return -1;
7793 },
7794 enumerable: true,
7795 configurable: true
7796 });
7797 Object.defineProperty(MenuItem.prototype, "icon", {
7798 /**
7799 * The icon renderer for the menu item.
7800 */
7801 get: function () {
7802 if (this.type === 'command') {
7803 return this._commands.icon(this.command, this.args);
7804 }
7805 if (this.type === 'submenu' && this.submenu) {
7806 return this.submenu.title.icon;
7807 }
7808 /* <DEPRECATED> */
7809 // alias to icon class if not otherwise defined
7810 return this.iconClass;
7811 /* </DEPRECATED> */
7812 /* <FUTURE>
7813 return undefined;
7814 </FUTURE> */
7815 },
7816 enumerable: true,
7817 configurable: true
7818 });
7819 Object.defineProperty(MenuItem.prototype, "iconClass", {
7820 /**
7821 * The icon class for the menu item.
7822 */
7823 get: function () {
7824 if (this.type === 'command') {
7825 return this._commands.iconClass(this.command, this.args);
7826 }
7827 if (this.type === 'submenu' && this.submenu) {
7828 return this.submenu.title.iconClass;
7829 }
7830 return '';
7831 },
7832 enumerable: true,
7833 configurable: true
7834 });
7835 Object.defineProperty(MenuItem.prototype, "iconLabel", {
7836 /**
7837 * The icon label for the menu item.
7838 */
7839 get: function () {
7840 if (this.type === 'command') {
7841 return this._commands.iconLabel(this.command, this.args);
7842 }
7843 if (this.type === 'submenu' && this.submenu) {
7844 return this.submenu.title.iconLabel;
7845 }
7846 return '';
7847 },
7848 enumerable: true,
7849 configurable: true
7850 });
7851 Object.defineProperty(MenuItem.prototype, "caption", {
7852 /**
7853 * The display caption for the menu item.
7854 */
7855 get: function () {
7856 if (this.type === 'command') {
7857 return this._commands.caption(this.command, this.args);
7858 }
7859 if (this.type === 'submenu' && this.submenu) {
7860 return this.submenu.title.caption;
7861 }
7862 return '';
7863 },
7864 enumerable: true,
7865 configurable: true
7866 });
7867 Object.defineProperty(MenuItem.prototype, "className", {
7868 /**
7869 * The extra class name for the menu item.
7870 */
7871 get: function () {
7872 if (this.type === 'command') {
7873 return this._commands.className(this.command, this.args);
7874 }
7875 if (this.type === 'submenu' && this.submenu) {
7876 return this.submenu.title.className;
7877 }
7878 return '';
7879 },
7880 enumerable: true,
7881 configurable: true
7882 });
7883 Object.defineProperty(MenuItem.prototype, "dataset", {
7884 /**
7885 * The dataset for the menu item.
7886 */
7887 get: function () {
7888 if (this.type === 'command') {
7889 return this._commands.dataset(this.command, this.args);
7890 }
7891 if (this.type === 'submenu' && this.submenu) {
7892 return this.submenu.title.dataset;
7893 }
7894 return {};
7895 },
7896 enumerable: true,
7897 configurable: true
7898 });
7899 Object.defineProperty(MenuItem.prototype, "isEnabled", {
7900 /**
7901 * Whether the menu item is enabled.
7902 */
7903 get: function () {
7904 if (this.type === 'command') {
7905 return this._commands.isEnabled(this.command, this.args);
7906 }
7907 if (this.type === 'submenu') {
7908 return this.submenu !== null;
7909 }
7910 return true;
7911 },
7912 enumerable: true,
7913 configurable: true
7914 });
7915 Object.defineProperty(MenuItem.prototype, "isToggled", {
7916 /**
7917 * Whether the menu item is toggled.
7918 */
7919 get: function () {
7920 if (this.type === 'command') {
7921 return this._commands.isToggled(this.command, this.args);
7922 }
7923 return false;
7924 },
7925 enumerable: true,
7926 configurable: true
7927 });
7928 Object.defineProperty(MenuItem.prototype, "isVisible", {
7929 /**
7930 * Whether the menu item is visible.
7931 */
7932 get: function () {
7933 if (this.type === 'command') {
7934 return this._commands.isVisible(this.command, this.args);
7935 }
7936 if (this.type === 'submenu') {
7937 return this.submenu !== null;
7938 }
7939 return true;
7940 },
7941 enumerable: true,
7942 configurable: true
7943 });
7944 Object.defineProperty(MenuItem.prototype, "keyBinding", {
7945 /**
7946 * The key binding for the menu item.
7947 */
7948 get: function () {
7949 if (this.type === 'command') {
7950 var _a = this, command_1 = _a.command, args_1 = _a.args;
7951 return (ArrayExt.findLastValue(this._commands.keyBindings, function (kb) {
7952 return kb.command === command_1 && JSONExt.deepEqual(kb.args, args_1);
7953 }) || null);
7954 }
7955 return null;
7956 },
7957 enumerable: true,
7958 configurable: true
7959 });
7960 return MenuItem;
7961 }());
7962})(Private$9 || (Private$9 = {}));
7963
7964/**
7965 * An object which implements a universal context menu.
7966 *
7967 * #### Notes
7968 * The items shown in the context menu are determined by CSS selector
7969 * matching against the DOM hierarchy at the site of the mouse click.
7970 * This is similar in concept to how keyboard shortcuts are matched
7971 * in the command registry.
7972 */
7973var ContextMenu = /** @class */ (function () {
7974 /**
7975 * Construct a new context menu.
7976 *
7977 * @param options - The options for initializing the menu.
7978 */
7979 function ContextMenu(options) {
7980 this._groupByTarget = true;
7981 this._idTick = 0;
7982 this._items = [];
7983 this._sortBySelector = true;
7984 var groupByTarget = options.groupByTarget, sortBySelector = options.sortBySelector, others = __rest(options, ["groupByTarget", "sortBySelector"]);
7985 this.menu = new Menu(others);
7986 this._groupByTarget = groupByTarget !== false;
7987 this._sortBySelector = sortBySelector !== false;
7988 }
7989 /**
7990 * Add an item to the context menu.
7991 *
7992 * @param options - The options for creating the item.
7993 *
7994 * @returns A disposable which will remove the item from the menu.
7995 */
7996 ContextMenu.prototype.addItem = function (options) {
7997 var _this = this;
7998 // Create an item from the given options.
7999 var item = Private$8.createItem(options, this._idTick++);
8000 // Add the item to the internal array.
8001 this._items.push(item);
8002 // Return a disposable which will remove the item.
8003 return new DisposableDelegate(function () {
8004 ArrayExt.removeFirstOf(_this._items, item);
8005 });
8006 };
8007 /**
8008 * Open the context menu in response to a `'contextmenu'` event.
8009 *
8010 * @param event - The `'contextmenu'` event of interest.
8011 *
8012 * @returns `true` if the menu was opened, or `false` if no items
8013 * matched the event and the menu was not opened.
8014 *
8015 * #### Notes
8016 * This method will populate the context menu with items which match
8017 * the propagation path of the event, then open the menu at the mouse
8018 * position indicated by the event.
8019 */
8020 ContextMenu.prototype.open = function (event) {
8021 var _this = this;
8022 // Clear the current contents of the context menu.
8023 this.menu.clearItems();
8024 // Bail early if there are no items to match.
8025 if (this._items.length === 0) {
8026 return false;
8027 }
8028 // Find the matching items for the event.
8029 var items = Private$8.matchItems(this._items, event, this._groupByTarget, this._sortBySelector);
8030 // Bail if there are no matching items.
8031 if (!items || items.length === 0) {
8032 return false;
8033 }
8034 // Add the filtered items to the menu.
8035 each(items, function (item) {
8036 _this.menu.addItem(item);
8037 });
8038 // Open the context menu at the current mouse position.
8039 this.menu.open(event.clientX, event.clientY);
8040 // Indicate success.
8041 return true;
8042 };
8043 return ContextMenu;
8044}());
8045/**
8046 * The namespace for the module implementation details.
8047 */
8048var Private$8;
8049(function (Private) {
8050 /**
8051 * Create a normalized context menu item from an options object.
8052 */
8053 function createItem(options, id) {
8054 var selector = validateSelector(options.selector);
8055 var rank = options.rank !== undefined ? options.rank : Infinity;
8056 return __assign(__assign({}, options), { selector: selector, rank: rank, id: id });
8057 }
8058 Private.createItem = createItem;
8059 /**
8060 * Find the items which match a context menu event.
8061 *
8062 * The results are sorted by DOM level, specificity, and rank.
8063 */
8064 function matchItems(items, event, groupByTarget, sortBySelector) {
8065 // Look up the target of the event.
8066 var target = event.target;
8067 // Bail if there is no target.
8068 if (!target) {
8069 return null;
8070 }
8071 // Look up the current target of the event.
8072 var currentTarget = event.currentTarget;
8073 // Bail if there is no current target.
8074 if (!currentTarget) {
8075 return null;
8076 }
8077 // There are some third party libraries that cause the `target` to
8078 // be detached from the DOM before lumino can process the event.
8079 // If that happens, search for a new target node by point. If that
8080 // node is still dangling, bail.
8081 if (!currentTarget.contains(target)) {
8082 target = document.elementFromPoint(event.clientX, event.clientY);
8083 if (!target || !currentTarget.contains(target)) {
8084 return null;
8085 }
8086 }
8087 // Set up the result array.
8088 var result = [];
8089 // Copy the items array to allow in-place modification.
8090 var availableItems = items.slice();
8091 // Walk up the DOM hierarchy searching for matches.
8092 while (target !== null) {
8093 // Set up the match array for this DOM level.
8094 var matches = [];
8095 // Search the remaining items for matches.
8096 for (var i = 0, n = availableItems.length; i < n; ++i) {
8097 // Fetch the item.
8098 var item = availableItems[i];
8099 // Skip items which are already consumed.
8100 if (!item) {
8101 continue;
8102 }
8103 // Skip items which do not match the element.
8104 if (!Selector.matches(target, item.selector)) {
8105 continue;
8106 }
8107 // Add the matched item to the result for this DOM level.
8108 matches.push(item);
8109 // Mark the item as consumed.
8110 availableItems[i] = null;
8111 }
8112 // Sort the matches for this level and add them to the results.
8113 if (matches.length !== 0) {
8114 if (groupByTarget) {
8115 matches.sort(sortBySelector ? itemCmp : itemCmpRank);
8116 }
8117 result.push.apply(result, matches);
8118 }
8119 // Stop searching at the limits of the DOM range.
8120 if (target === currentTarget) {
8121 break;
8122 }
8123 // Step to the parent DOM level.
8124 target = target.parentElement;
8125 }
8126 if (!groupByTarget) {
8127 result.sort(sortBySelector ? itemCmp : itemCmpRank);
8128 }
8129 // Return the matched and sorted results.
8130 return result;
8131 }
8132 Private.matchItems = matchItems;
8133 /**
8134 * Validate the selector for a menu item.
8135 *
8136 * This returns the validated selector, or throws if the selector is
8137 * invalid or contains commas.
8138 */
8139 function validateSelector(selector) {
8140 if (selector.indexOf(',') !== -1) {
8141 throw new Error("Selector cannot contain commas: " + selector);
8142 }
8143 if (!Selector.isValid(selector)) {
8144 throw new Error("Invalid selector: " + selector);
8145 }
8146 return selector;
8147 }
8148 /**
8149 * A sort comparison function for a context menu item by ranks.
8150 */
8151 function itemCmpRank(a, b) {
8152 // Sort based on rank.
8153 var r1 = a.rank;
8154 var r2 = b.rank;
8155 if (r1 !== r2) {
8156 return r1 < r2 ? -1 : 1; // Infinity-safe
8157 }
8158 // When all else fails, sort by item id.
8159 return a.id - b.id;
8160 }
8161 /**
8162 * A sort comparison function for a context menu item by selectors and ranks.
8163 */
8164 function itemCmp(a, b) {
8165 // Sort first based on selector specificity.
8166 var s1 = Selector.calculateSpecificity(a.selector);
8167 var s2 = Selector.calculateSpecificity(b.selector);
8168 if (s1 !== s2) {
8169 return s2 - s1;
8170 }
8171 // If specificities are equal
8172 return itemCmpRank(a, b);
8173 }
8174})(Private$8 || (Private$8 = {}));
8175
8176/**
8177 * A widget which displays titles as a single row or column of tabs.
8178 *
8179 * #### Notes
8180 * If CSS transforms are used to rotate nodes for vertically oriented
8181 * text, then tab dragging will not work correctly. The `tabsMovable`
8182 * property should be set to `false` when rotating nodes from CSS.
8183 */
8184var TabBar = /** @class */ (function (_super) {
8185 __extends(TabBar, _super);
8186 /**
8187 * Construct a new tab bar.
8188 *
8189 * @param options - The options for initializing the tab bar.
8190 */
8191 function TabBar(options) {
8192 if (options === void 0) { options = {}; }
8193 var _this = _super.call(this, { node: Private$7.createNode() }) || this;
8194 _this._currentIndex = -1;
8195 _this._titles = [];
8196 _this._titlesEditable = false;
8197 _this._previousTitle = null;
8198 _this._dragData = null;
8199 _this._addButtonEnabled = false;
8200 _this._tabMoved = new Signal(_this);
8201 _this._currentChanged = new Signal(_this);
8202 _this._addRequested = new Signal(_this);
8203 _this._tabCloseRequested = new Signal(_this);
8204 _this._tabDetachRequested = new Signal(_this);
8205 _this._tabActivateRequested = new Signal(_this);
8206 _this.addClass('lm-TabBar');
8207 /* <DEPRECATED> */
8208 _this.addClass('p-TabBar');
8209 /* </DEPRECATED> */
8210 _this.contentNode.setAttribute('role', 'tablist');
8211 _this.setFlag(Widget.Flag.DisallowLayout);
8212 _this._document = options.document || document;
8213 _this.tabsMovable = options.tabsMovable || false;
8214 _this.titlesEditable = options.titlesEditable || false;
8215 _this.allowDeselect = options.allowDeselect || false;
8216 _this.addButtonEnabled = options.addButtonEnabled || false;
8217 _this.insertBehavior = options.insertBehavior || 'select-tab-if-needed';
8218 _this.name = options.name || '';
8219 _this.orientation = options.orientation || 'horizontal';
8220 _this.removeBehavior = options.removeBehavior || 'select-tab-after';
8221 _this.renderer = options.renderer || TabBar.defaultRenderer;
8222 return _this;
8223 }
8224 /**
8225 * Dispose of the resources held by the widget.
8226 */
8227 TabBar.prototype.dispose = function () {
8228 this._releaseMouse();
8229 this._titles.length = 0;
8230 this._previousTitle = null;
8231 _super.prototype.dispose.call(this);
8232 };
8233 Object.defineProperty(TabBar.prototype, "currentChanged", {
8234 /**
8235 * A signal emitted when the current tab is changed.
8236 *
8237 * #### Notes
8238 * This signal is emitted when the currently selected tab is changed
8239 * either through user or programmatic interaction.
8240 *
8241 * Notably, this signal is not emitted when the index of the current
8242 * tab changes due to tabs being inserted, removed, or moved. It is
8243 * only emitted when the actual current tab node is changed.
8244 */
8245 get: function () {
8246 return this._currentChanged;
8247 },
8248 enumerable: true,
8249 configurable: true
8250 });
8251 Object.defineProperty(TabBar.prototype, "tabMoved", {
8252 /**
8253 * A signal emitted when a tab is moved by the user.
8254 *
8255 * #### Notes
8256 * This signal is emitted when a tab is moved by user interaction.
8257 *
8258 * This signal is not emitted when a tab is moved programmatically.
8259 */
8260 get: function () {
8261 return this._tabMoved;
8262 },
8263 enumerable: true,
8264 configurable: true
8265 });
8266 Object.defineProperty(TabBar.prototype, "tabActivateRequested", {
8267 /**
8268 * A signal emitted when a tab is clicked by the user.
8269 *
8270 * #### Notes
8271 * If the clicked tab is not the current tab, the clicked tab will be
8272 * made current and the `currentChanged` signal will be emitted first.
8273 *
8274 * This signal is emitted even if the clicked tab is the current tab.
8275 */
8276 get: function () {
8277 return this._tabActivateRequested;
8278 },
8279 enumerable: true,
8280 configurable: true
8281 });
8282 Object.defineProperty(TabBar.prototype, "addRequested", {
8283 /**
8284 * A signal emitted when the tab bar add button is clicked.
8285 */
8286 get: function () {
8287 return this._addRequested;
8288 },
8289 enumerable: true,
8290 configurable: true
8291 });
8292 Object.defineProperty(TabBar.prototype, "tabCloseRequested", {
8293 /**
8294 * A signal emitted when a tab close icon is clicked.
8295 *
8296 * #### Notes
8297 * This signal is not emitted unless the tab title is `closable`.
8298 */
8299 get: function () {
8300 return this._tabCloseRequested;
8301 },
8302 enumerable: true,
8303 configurable: true
8304 });
8305 Object.defineProperty(TabBar.prototype, "tabDetachRequested", {
8306 /**
8307 * A signal emitted when a tab is dragged beyond the detach threshold.
8308 *
8309 * #### Notes
8310 * This signal is emitted when the user drags a tab with the mouse,
8311 * and mouse is dragged beyond the detach threshold.
8312 *
8313 * The consumer of the signal should call `releaseMouse` and remove
8314 * the tab in order to complete the detach.
8315 *
8316 * This signal is only emitted once per drag cycle.
8317 */
8318 get: function () {
8319 return this._tabDetachRequested;
8320 },
8321 enumerable: true,
8322 configurable: true
8323 });
8324 Object.defineProperty(TabBar.prototype, "document", {
8325 /**
8326 * The document to use with the tab bar.
8327 *
8328 * The default is the global `document` instance.
8329 */
8330 get: function () {
8331 return this._document;
8332 },
8333 enumerable: true,
8334 configurable: true
8335 });
8336 Object.defineProperty(TabBar.prototype, "titlesEditable", {
8337 /**
8338 * Whether the titles can be user-edited.
8339 *
8340 */
8341 get: function () {
8342 return this._titlesEditable;
8343 },
8344 /**
8345 * Set whether titles can be user edited.
8346 *
8347 */
8348 set: function (value) {
8349 this._titlesEditable = value;
8350 },
8351 enumerable: true,
8352 configurable: true
8353 });
8354 Object.defineProperty(TabBar.prototype, "currentTitle", {
8355 /**
8356 * Get the currently selected title.
8357 *
8358 * #### Notes
8359 * This will be `null` if no tab is selected.
8360 */
8361 get: function () {
8362 return this._titles[this._currentIndex] || null;
8363 },
8364 /**
8365 * Set the currently selected title.
8366 *
8367 * #### Notes
8368 * If the title does not exist, the title will be set to `null`.
8369 */
8370 set: function (value) {
8371 this.currentIndex = value ? this._titles.indexOf(value) : -1;
8372 },
8373 enumerable: true,
8374 configurable: true
8375 });
8376 Object.defineProperty(TabBar.prototype, "currentIndex", {
8377 /**
8378 * Get the index of the currently selected tab.
8379 *
8380 * #### Notes
8381 * This will be `-1` if no tab is selected.
8382 */
8383 get: function () {
8384 return this._currentIndex;
8385 },
8386 /**
8387 * Set the index of the currently selected tab.
8388 *
8389 * #### Notes
8390 * If the value is out of range, the index will be set to `-1`.
8391 */
8392 set: function (value) {
8393 // Adjust for an out of range index.
8394 if (value < 0 || value >= this._titles.length) {
8395 value = -1;
8396 }
8397 // Bail early if the index will not change.
8398 if (this._currentIndex === value) {
8399 return;
8400 }
8401 // Look up the previous index and title.
8402 var pi = this._currentIndex;
8403 var pt = this._titles[pi] || null;
8404 // Look up the current index and title.
8405 var ci = value;
8406 var ct = this._titles[ci] || null;
8407 // Update the current index and previous title.
8408 this._currentIndex = ci;
8409 this._previousTitle = pt;
8410 // Schedule an update of the tabs.
8411 this.update();
8412 // Emit the current changed signal.
8413 this._currentChanged.emit({
8414 previousIndex: pi,
8415 previousTitle: pt,
8416 currentIndex: ci,
8417 currentTitle: ct
8418 });
8419 },
8420 enumerable: true,
8421 configurable: true
8422 });
8423 Object.defineProperty(TabBar.prototype, "name", {
8424 /**
8425 * Get the name of the tab bar.
8426 */
8427 get: function () {
8428 return this._name;
8429 },
8430 /**
8431 * Set the name of the tab bar.
8432 */
8433 set: function (value) {
8434 this._name = value;
8435 if (value) {
8436 this.contentNode.setAttribute('aria-label', value);
8437 }
8438 else {
8439 this.contentNode.removeAttribute('aria-label');
8440 }
8441 },
8442 enumerable: true,
8443 configurable: true
8444 });
8445 Object.defineProperty(TabBar.prototype, "orientation", {
8446 /**
8447 * Get the orientation of the tab bar.
8448 *
8449 * #### Notes
8450 * This controls whether the tabs are arranged in a row or column.
8451 */
8452 get: function () {
8453 return this._orientation;
8454 },
8455 /**
8456 * Set the orientation of the tab bar.
8457 *
8458 * #### Notes
8459 * This controls whether the tabs are arranged in a row or column.
8460 */
8461 set: function (value) {
8462 // Do nothing if the orientation does not change.
8463 if (this._orientation === value) {
8464 return;
8465 }
8466 // Release the mouse before making any changes.
8467 this._releaseMouse();
8468 // Toggle the orientation values.
8469 this._orientation = value;
8470 this.dataset['orientation'] = value;
8471 this.contentNode.setAttribute('aria-orientation', value);
8472 },
8473 enumerable: true,
8474 configurable: true
8475 });
8476 Object.defineProperty(TabBar.prototype, "addButtonEnabled", {
8477 /**
8478 * Whether the add button is enabled.
8479 */
8480 get: function () {
8481 return this._addButtonEnabled;
8482 },
8483 /**
8484 * Set whether the add button is enabled.
8485 */
8486 set: function (value) {
8487 // Do nothing if the value does not change.
8488 if (this._addButtonEnabled === value) {
8489 return;
8490 }
8491 this._addButtonEnabled = value;
8492 if (value) {
8493 this.addButtonNode.classList.remove('lm-mod-hidden');
8494 }
8495 else {
8496 this.addButtonNode.classList.add('lm-mod-hidden');
8497 }
8498 },
8499 enumerable: true,
8500 configurable: true
8501 });
8502 Object.defineProperty(TabBar.prototype, "titles", {
8503 /**
8504 * A read-only array of the titles in the tab bar.
8505 */
8506 get: function () {
8507 return this._titles;
8508 },
8509 enumerable: true,
8510 configurable: true
8511 });
8512 Object.defineProperty(TabBar.prototype, "contentNode", {
8513 /**
8514 * The tab bar content node.
8515 *
8516 * #### Notes
8517 * This is the node which holds the tab nodes.
8518 *
8519 * Modifying this node directly can lead to undefined behavior.
8520 */
8521 get: function () {
8522 return this.node.getElementsByClassName('lm-TabBar-content')[0];
8523 },
8524 enumerable: true,
8525 configurable: true
8526 });
8527 Object.defineProperty(TabBar.prototype, "addButtonNode", {
8528 /**
8529 * The tab bar add button node.
8530 *
8531 * #### Notes
8532 * This is the node which holds the add button.
8533 *
8534 * Modifying this node directly can lead to undefined behavior.
8535 */
8536 get: function () {
8537 return this.node.getElementsByClassName('lm-TabBar-addButton')[0];
8538 },
8539 enumerable: true,
8540 configurable: true
8541 });
8542 /**
8543 * Add a tab to the end of the tab bar.
8544 *
8545 * @param value - The title which holds the data for the tab,
8546 * or an options object to convert to a title.
8547 *
8548 * @returns The title object added to the tab bar.
8549 *
8550 * #### Notes
8551 * If the title is already added to the tab bar, it will be moved.
8552 */
8553 TabBar.prototype.addTab = function (value) {
8554 return this.insertTab(this._titles.length, value);
8555 };
8556 /**
8557 * Insert a tab into the tab bar at the specified index.
8558 *
8559 * @param index - The index at which to insert the tab.
8560 *
8561 * @param value - The title which holds the data for the tab,
8562 * or an options object to convert to a title.
8563 *
8564 * @returns The title object added to the tab bar.
8565 *
8566 * #### Notes
8567 * The index will be clamped to the bounds of the tabs.
8568 *
8569 * If the title is already added to the tab bar, it will be moved.
8570 */
8571 TabBar.prototype.insertTab = function (index, value) {
8572 // Release the mouse before making any changes.
8573 this._releaseMouse();
8574 // Coerce the value to a title.
8575 var title = Private$7.asTitle(value);
8576 // Look up the index of the title.
8577 var i = this._titles.indexOf(title);
8578 // Clamp the insert index to the array bounds.
8579 var j = Math.max(0, Math.min(index, this._titles.length));
8580 // If the title is not in the array, insert it.
8581 if (i === -1) {
8582 // Insert the title into the array.
8583 ArrayExt.insert(this._titles, j, title);
8584 // Connect to the title changed signal.
8585 title.changed.connect(this._onTitleChanged, this);
8586 // Schedule an update of the tabs.
8587 this.update();
8588 // Adjust the current index for the insert.
8589 this._adjustCurrentForInsert(j, title);
8590 // Return the title added to the tab bar.
8591 return title;
8592 }
8593 // Otherwise, the title exists in the array and should be moved.
8594 // Adjust the index if the location is at the end of the array.
8595 if (j === this._titles.length) {
8596 j--;
8597 }
8598 // Bail if there is no effective move.
8599 if (i === j) {
8600 return title;
8601 }
8602 // Move the title to the new location.
8603 ArrayExt.move(this._titles, i, j);
8604 // Schedule an update of the tabs.
8605 this.update();
8606 // Adjust the current index for the move.
8607 this._adjustCurrentForMove(i, j);
8608 // Return the title added to the tab bar.
8609 return title;
8610 };
8611 /**
8612 * Remove a tab from the tab bar.
8613 *
8614 * @param title - The title for the tab to remove.
8615 *
8616 * #### Notes
8617 * This is a no-op if the title is not in the tab bar.
8618 */
8619 TabBar.prototype.removeTab = function (title) {
8620 this.removeTabAt(this._titles.indexOf(title));
8621 };
8622 /**
8623 * Remove the tab at a given index from the tab bar.
8624 *
8625 * @param index - The index of the tab to remove.
8626 *
8627 * #### Notes
8628 * This is a no-op if the index is out of range.
8629 */
8630 TabBar.prototype.removeTabAt = function (index) {
8631 // Release the mouse before making any changes.
8632 this._releaseMouse();
8633 // Remove the title from the array.
8634 var title = ArrayExt.removeAt(this._titles, index);
8635 // Bail if the index is out of range.
8636 if (!title) {
8637 return;
8638 }
8639 // Disconnect from the title changed signal.
8640 title.changed.disconnect(this._onTitleChanged, this);
8641 // Clear the previous title if it's being removed.
8642 if (title === this._previousTitle) {
8643 this._previousTitle = null;
8644 }
8645 // Schedule an update of the tabs.
8646 this.update();
8647 // Adjust the current index for the remove.
8648 this._adjustCurrentForRemove(index, title);
8649 };
8650 /**
8651 * Remove all tabs from the tab bar.
8652 */
8653 TabBar.prototype.clearTabs = function () {
8654 // Bail if there is nothing to remove.
8655 if (this._titles.length === 0) {
8656 return;
8657 }
8658 // Release the mouse before making any changes.
8659 this._releaseMouse();
8660 // Disconnect from the title changed signals.
8661 for (var _i = 0, _a = this._titles; _i < _a.length; _i++) {
8662 var title = _a[_i];
8663 title.changed.disconnect(this._onTitleChanged, this);
8664 }
8665 // Get the current index and title.
8666 var pi = this.currentIndex;
8667 var pt = this.currentTitle;
8668 // Reset the current index and previous title.
8669 this._currentIndex = -1;
8670 this._previousTitle = null;
8671 // Clear the title array.
8672 this._titles.length = 0;
8673 // Schedule an update of the tabs.
8674 this.update();
8675 // If no tab was selected, there's nothing else to do.
8676 if (pi === -1) {
8677 return;
8678 }
8679 // Emit the current changed signal.
8680 this._currentChanged.emit({
8681 previousIndex: pi,
8682 previousTitle: pt,
8683 currentIndex: -1,
8684 currentTitle: null
8685 });
8686 };
8687 /**
8688 * Release the mouse and restore the non-dragged tab positions.
8689 *
8690 * #### Notes
8691 * This will cause the tab bar to stop handling mouse events and to
8692 * restore the tabs to their non-dragged positions.
8693 */
8694 TabBar.prototype.releaseMouse = function () {
8695 this._releaseMouse();
8696 };
8697 /**
8698 * Handle the DOM events for the tab bar.
8699 *
8700 * @param event - The DOM event sent to the tab bar.
8701 *
8702 * #### Notes
8703 * This method implements the DOM `EventListener` interface and is
8704 * called in response to events on the tab bar's DOM node.
8705 *
8706 * This should not be called directly by user code.
8707 */
8708 TabBar.prototype.handleEvent = function (event) {
8709 switch (event.type) {
8710 case 'mousedown': // <DEPRECATED>
8711 this._evtMouseDown(event);
8712 break;
8713 case 'mousemove': // <DEPRECATED>
8714 this._evtMouseMove(event);
8715 break;
8716 case 'mouseup': // <DEPRECATED>
8717 this._evtMouseUp(event);
8718 break;
8719 case 'pointerdown':
8720 this._evtMouseDown(event);
8721 break;
8722 case 'pointermove':
8723 this._evtMouseMove(event);
8724 break;
8725 case 'pointerup':
8726 this._evtMouseUp(event);
8727 break;
8728 case 'dblclick':
8729 this._evtDblClick(event);
8730 break;
8731 case 'keydown':
8732 this._evtKeyDown(event);
8733 break;
8734 case 'contextmenu':
8735 event.preventDefault();
8736 event.stopPropagation();
8737 break;
8738 }
8739 };
8740 /**
8741 * A message handler invoked on a `'before-attach'` message.
8742 */
8743 TabBar.prototype.onBeforeAttach = function (msg) {
8744 this.node.addEventListener('mousedown', this); // <DEPRECATED>
8745 this.node.addEventListener('pointerdown', this);
8746 this.node.addEventListener('dblclick', this);
8747 };
8748 /**
8749 * A message handler invoked on an `'after-detach'` message.
8750 */
8751 TabBar.prototype.onAfterDetach = function (msg) {
8752 this.node.removeEventListener('mousedown', this); // <DEPRECATED>
8753 this.node.removeEventListener('pointerdown', this);
8754 this.node.removeEventListener('dblclick', this);
8755 this._releaseMouse();
8756 };
8757 /**
8758 * A message handler invoked on an `'update-request'` message.
8759 */
8760 TabBar.prototype.onUpdateRequest = function (msg) {
8761 var titles = this._titles;
8762 var renderer = this.renderer;
8763 var currentTitle = this.currentTitle;
8764 var content = new Array(titles.length);
8765 for (var i = 0, n = titles.length; i < n; ++i) {
8766 var title = titles[i];
8767 var current = title === currentTitle;
8768 var zIndex = current ? n : n - i - 1;
8769 content[i] = renderer.renderTab({ title: title, current: current, zIndex: zIndex });
8770 }
8771 VirtualDOM.render(content, this.contentNode);
8772 };
8773 /**
8774 * Handle the `'dblclick'` event for the tab bar.
8775 */
8776 TabBar.prototype._evtDblClick = function (event) {
8777 // Do nothing if titles are not editable
8778 if (!this.titlesEditable) {
8779 return;
8780 }
8781 var tabs = this.contentNode.children;
8782 // Find the index of the released tab.
8783 var index = ArrayExt.findFirstIndex(tabs, function (tab) {
8784 return ElementExt.hitTest(tab, event.clientX, event.clientY);
8785 });
8786 // Do nothing if the press is not on a tab.
8787 if (index === -1) {
8788 return;
8789 }
8790 var title = this.titles[index];
8791 var label = tabs[index].querySelector('.lm-TabBar-tabLabel');
8792 if (label && label.contains(event.target)) {
8793 var value = title.label || '';
8794 // Clear the label element
8795 var oldValue_1 = label.innerHTML;
8796 label.innerHTML = '';
8797 var input_1 = document.createElement('input');
8798 input_1.classList.add('lm-TabBar-tabInput');
8799 input_1.value = value;
8800 label.appendChild(input_1);
8801 var onblur_1 = function () {
8802 input_1.removeEventListener('blur', onblur_1);
8803 label.innerHTML = oldValue_1;
8804 };
8805 input_1.addEventListener('dblclick', function (event) {
8806 return event.stopPropagation();
8807 });
8808 input_1.addEventListener('blur', onblur_1);
8809 input_1.addEventListener('keydown', function (event) {
8810 if (event.key === 'Enter') {
8811 if (input_1.value !== '') {
8812 title.label = title.caption = input_1.value;
8813 }
8814 onblur_1();
8815 }
8816 else if (event.key === 'Escape') {
8817 onblur_1();
8818 }
8819 });
8820 input_1.select();
8821 input_1.focus();
8822 if (label.children.length > 0) {
8823 label.children[0].focus();
8824 }
8825 }
8826 };
8827 /**
8828 * Handle the `'keydown'` event for the tab bar.
8829 */
8830 TabBar.prototype._evtKeyDown = function (event) {
8831 // Stop all input events during drag.
8832 event.preventDefault();
8833 event.stopPropagation();
8834 // Release the mouse if `Escape` is pressed.
8835 if (event.keyCode === 27) {
8836 this._releaseMouse();
8837 }
8838 };
8839 /**
8840 * Handle the `'mousedown'` event for the tab bar.
8841 */
8842 TabBar.prototype._evtMouseDown = function (event) {
8843 // Do nothing if it's not a left or middle mouse press.
8844 if (event.button !== 0 && event.button !== 1) {
8845 return;
8846 }
8847 // Do nothing if a drag is in progress.
8848 if (this._dragData) {
8849 return;
8850 }
8851 // Check if the add button was clicked.
8852 var addButtonClicked = this.addButtonEnabled &&
8853 this.addButtonNode.contains(event.target);
8854 // Lookup the tab nodes.
8855 var tabs = this.contentNode.children;
8856 // Find the index of the pressed tab.
8857 var index = ArrayExt.findFirstIndex(tabs, function (tab) {
8858 return ElementExt.hitTest(tab, event.clientX, event.clientY);
8859 });
8860 // Do nothing if the press is not on a tab or the add button.
8861 if (index === -1 && !addButtonClicked) {
8862 return;
8863 }
8864 // Pressing on a tab stops the event propagation.
8865 event.preventDefault();
8866 event.stopPropagation();
8867 // Initialize the non-measured parts of the drag data.
8868 this._dragData = {
8869 tab: tabs[index],
8870 index: index,
8871 pressX: event.clientX,
8872 pressY: event.clientY,
8873 tabPos: -1,
8874 tabSize: -1,
8875 tabPressPos: -1,
8876 targetIndex: -1,
8877 tabLayout: null,
8878 contentRect: null,
8879 override: null,
8880 dragActive: false,
8881 dragAborted: false,
8882 detachRequested: false
8883 };
8884 // Add the document mouse up listener.
8885 this.document.addEventListener('mouseup', this, true); // <DEPRECATED>
8886 this.document.addEventListener('pointerup', this, true);
8887 // Do nothing else if the middle button or add button is clicked.
8888 if (event.button === 1 || addButtonClicked) {
8889 return;
8890 }
8891 // Do nothing else if the close icon is clicked.
8892 var icon = tabs[index].querySelector(this.renderer.closeIconSelector);
8893 if (icon && icon.contains(event.target)) {
8894 return;
8895 }
8896 // Add the extra listeners if the tabs are movable.
8897 if (this.tabsMovable) {
8898 this.document.addEventListener('mousemove', this, true); // <DEPRECATED>
8899 this.document.addEventListener('pointermove', this, true);
8900 this.document.addEventListener('keydown', this, true);
8901 this.document.addEventListener('contextmenu', this, true);
8902 }
8903 // Update the current index as appropriate.
8904 if (this.allowDeselect && this.currentIndex === index) {
8905 this.currentIndex = -1;
8906 }
8907 else {
8908 this.currentIndex = index;
8909 }
8910 // Do nothing else if there is no current tab.
8911 if (this.currentIndex === -1) {
8912 return;
8913 }
8914 // Emit the tab activate request signal.
8915 this._tabActivateRequested.emit({
8916 index: this.currentIndex,
8917 title: this.currentTitle
8918 });
8919 };
8920 /**
8921 * Handle the `'mousemove'` event for the tab bar.
8922 */
8923 TabBar.prototype._evtMouseMove = function (event) {
8924 // Do nothing if no drag is in progress.
8925 var data = this._dragData;
8926 if (!data) {
8927 return;
8928 }
8929 // Suppress the event during a drag.
8930 event.preventDefault();
8931 event.stopPropagation();
8932 // Lookup the tab nodes.
8933 var tabs = this.contentNode.children;
8934 // Bail early if the drag threshold has not been met.
8935 if (!data.dragActive && !Private$7.dragExceeded(data, event)) {
8936 return;
8937 }
8938 // Activate the drag if necessary.
8939 if (!data.dragActive) {
8940 // Fill in the rest of the drag data measurements.
8941 var tabRect = data.tab.getBoundingClientRect();
8942 if (this._orientation === 'horizontal') {
8943 data.tabPos = data.tab.offsetLeft;
8944 data.tabSize = tabRect.width;
8945 data.tabPressPos = data.pressX - tabRect.left;
8946 }
8947 else {
8948 data.tabPos = data.tab.offsetTop;
8949 data.tabSize = tabRect.height;
8950 data.tabPressPos = data.pressY - tabRect.top;
8951 }
8952 data.tabLayout = Private$7.snapTabLayout(tabs, this._orientation);
8953 data.contentRect = this.contentNode.getBoundingClientRect();
8954 data.override = Drag.overrideCursor('default');
8955 // Add the dragging style classes.
8956 data.tab.classList.add('lm-mod-dragging');
8957 this.addClass('lm-mod-dragging');
8958 /* <DEPRECATED> */
8959 data.tab.classList.add('p-mod-dragging');
8960 this.addClass('p-mod-dragging');
8961 /* </DEPRECATED> */
8962 // Mark the drag as active.
8963 data.dragActive = true;
8964 }
8965 // Emit the detach requested signal if the threshold is exceeded.
8966 if (!data.detachRequested && Private$7.detachExceeded(data, event)) {
8967 // Only emit the signal once per drag cycle.
8968 data.detachRequested = true;
8969 // Setup the arguments for the signal.
8970 var index = data.index;
8971 var clientX = event.clientX;
8972 var clientY = event.clientY;
8973 var tab = tabs[index];
8974 var title = this._titles[index];
8975 // Emit the tab detach requested signal.
8976 this._tabDetachRequested.emit({ index: index, title: title, tab: tab, clientX: clientX, clientY: clientY });
8977 // Bail if the signal handler aborted the drag.
8978 if (data.dragAborted) {
8979 return;
8980 }
8981 }
8982 // Update the positions of the tabs.
8983 Private$7.layoutTabs(tabs, data, event, this._orientation);
8984 };
8985 /**
8986 * Handle the `'mouseup'` event for the document.
8987 */
8988 TabBar.prototype._evtMouseUp = function (event) {
8989 var _this = this;
8990 // Do nothing if it's not a left or middle mouse release.
8991 if (event.button !== 0 && event.button !== 1) {
8992 return;
8993 }
8994 // Do nothing if no drag is in progress.
8995 var data = this._dragData;
8996 if (!data) {
8997 return;
8998 }
8999 // Stop the event propagation.
9000 event.preventDefault();
9001 event.stopPropagation();
9002 // Remove the extra mouse event listeners.
9003 this.document.removeEventListener('mousemove', this, true); // <DEPRECATED>
9004 this.document.removeEventListener('mouseup', this, true); // <DEPRECATED>
9005 this.document.removeEventListener('pointermove', this, true);
9006 this.document.removeEventListener('pointerup', this, true);
9007 this.document.removeEventListener('keydown', this, true);
9008 this.document.removeEventListener('contextmenu', this, true);
9009 // Handle a release when the drag is not active.
9010 if (!data.dragActive) {
9011 // Clear the drag data.
9012 this._dragData = null;
9013 // Handle clicking the add button.
9014 var addButtonClicked = this.addButtonEnabled &&
9015 this.addButtonNode.contains(event.target);
9016 if (addButtonClicked) {
9017 this._addRequested.emit(undefined);
9018 return;
9019 }
9020 // Lookup the tab nodes.
9021 var tabs = this.contentNode.children;
9022 // Find the index of the released tab.
9023 var index = ArrayExt.findFirstIndex(tabs, function (tab) {
9024 return ElementExt.hitTest(tab, event.clientX, event.clientY);
9025 });
9026 // Do nothing if the release is not on the original pressed tab.
9027 if (index !== data.index) {
9028 return;
9029 }
9030 // Ignore the release if the title is not closable.
9031 var title = this._titles[index];
9032 if (!title.closable) {
9033 return;
9034 }
9035 // Emit the close requested signal if the middle button is released.
9036 if (event.button === 1) {
9037 this._tabCloseRequested.emit({ index: index, title: title });
9038 return;
9039 }
9040 // Emit the close requested signal if the close icon was released.
9041 var icon = tabs[index].querySelector(this.renderer.closeIconSelector);
9042 if (icon && icon.contains(event.target)) {
9043 this._tabCloseRequested.emit({ index: index, title: title });
9044 return;
9045 }
9046 // Otherwise, there is nothing left to do.
9047 return;
9048 }
9049 // Do nothing if the left button is not released.
9050 if (event.button !== 0) {
9051 return;
9052 }
9053 // Position the tab at its final resting position.
9054 Private$7.finalizeTabPosition(data, this._orientation);
9055 // Remove the dragging class from the tab so it can be transitioned.
9056 data.tab.classList.remove('lm-mod-dragging');
9057 /* <DEPRECATED> */
9058 data.tab.classList.remove('p-mod-dragging');
9059 /* </DEPRECATED> */
9060 // Parse the transition duration for releasing the tab.
9061 var duration = Private$7.parseTransitionDuration(data.tab);
9062 // Complete the release on a timer to allow the tab to transition.
9063 setTimeout(function () {
9064 // Do nothing if the drag has been aborted.
9065 if (data.dragAborted) {
9066 return;
9067 }
9068 // Clear the drag data reference.
9069 _this._dragData = null;
9070 // Reset the positions of the tabs.
9071 Private$7.resetTabPositions(_this.contentNode.children, _this._orientation);
9072 // Clear the cursor grab.
9073 data.override.dispose();
9074 // Remove the remaining dragging style.
9075 _this.removeClass('lm-mod-dragging');
9076 /* <DEPRECATED> */
9077 _this.removeClass('p-mod-dragging');
9078 /* </DEPRECATED> */
9079 // If the tab was not moved, there is nothing else to do.
9080 var i = data.index;
9081 var j = data.targetIndex;
9082 if (j === -1 || i === j) {
9083 return;
9084 }
9085 // Move the title to the new locations.
9086 ArrayExt.move(_this._titles, i, j);
9087 // Adjust the current index for the move.
9088 _this._adjustCurrentForMove(i, j);
9089 // Emit the tab moved signal.
9090 _this._tabMoved.emit({
9091 fromIndex: i,
9092 toIndex: j,
9093 title: _this._titles[j]
9094 });
9095 // Update the tabs immediately to prevent flicker.
9096 MessageLoop.sendMessage(_this, Widget.Msg.UpdateRequest);
9097 }, duration);
9098 };
9099 /**
9100 * Release the mouse and restore the non-dragged tab positions.
9101 */
9102 TabBar.prototype._releaseMouse = function () {
9103 // Do nothing if no drag is in progress.
9104 var data = this._dragData;
9105 if (!data) {
9106 return;
9107 }
9108 // Clear the drag data reference.
9109 this._dragData = null;
9110 // Remove the extra mouse listeners.
9111 this.document.removeEventListener('mousemove', this, true); // <DEPRECATED>
9112 this.document.removeEventListener('mouseup', this, true); // <DEPRECATED>
9113 this.document.removeEventListener('pointermove', this, true);
9114 this.document.removeEventListener('pointerup', this, true);
9115 this.document.removeEventListener('keydown', this, true);
9116 this.document.removeEventListener('contextmenu', this, true);
9117 // Indicate the drag has been aborted. This allows the mouse
9118 // event handlers to return early when the drag is canceled.
9119 data.dragAborted = true;
9120 // If the drag is not active, there's nothing more to do.
9121 if (!data.dragActive) {
9122 return;
9123 }
9124 // Reset the tabs to their non-dragged positions.
9125 Private$7.resetTabPositions(this.contentNode.children, this._orientation);
9126 // Clear the cursor override.
9127 data.override.dispose();
9128 // Clear the dragging style classes.
9129 data.tab.classList.remove('lm-mod-dragging');
9130 this.removeClass('lm-mod-dragging');
9131 /* <DEPRECATED> */
9132 data.tab.classList.remove('p-mod-dragging');
9133 this.removeClass('p-mod-dragging');
9134 /* </DEPRECATED> */
9135 };
9136 /**
9137 * Adjust the current index for a tab insert operation.
9138 *
9139 * This method accounts for the tab bar's insertion behavior when
9140 * adjusting the current index and emitting the changed signal.
9141 */
9142 TabBar.prototype._adjustCurrentForInsert = function (i, title) {
9143 // Lookup commonly used variables.
9144 var ct = this.currentTitle;
9145 var ci = this._currentIndex;
9146 var bh = this.insertBehavior;
9147 // TODO: do we need to do an update to update the aria-selected attribute?
9148 // Handle the behavior where the new tab is always selected,
9149 // or the behavior where the new tab is selected if needed.
9150 if (bh === 'select-tab' || (bh === 'select-tab-if-needed' && ci === -1)) {
9151 this._currentIndex = i;
9152 this._previousTitle = ct;
9153 this._currentChanged.emit({
9154 previousIndex: ci,
9155 previousTitle: ct,
9156 currentIndex: i,
9157 currentTitle: title
9158 });
9159 return;
9160 }
9161 // Otherwise, silently adjust the current index if needed.
9162 if (ci >= i) {
9163 this._currentIndex++;
9164 }
9165 };
9166 /**
9167 * Adjust the current index for a tab move operation.
9168 *
9169 * This method will not cause the actual current tab to change.
9170 * It silently adjusts the index to account for the given move.
9171 */
9172 TabBar.prototype._adjustCurrentForMove = function (i, j) {
9173 if (this._currentIndex === i) {
9174 this._currentIndex = j;
9175 }
9176 else if (this._currentIndex < i && this._currentIndex >= j) {
9177 this._currentIndex++;
9178 }
9179 else if (this._currentIndex > i && this._currentIndex <= j) {
9180 this._currentIndex--;
9181 }
9182 };
9183 /**
9184 * Adjust the current index for a tab remove operation.
9185 *
9186 * This method accounts for the tab bar's remove behavior when
9187 * adjusting the current index and emitting the changed signal.
9188 */
9189 TabBar.prototype._adjustCurrentForRemove = function (i, title) {
9190 // Lookup commonly used variables.
9191 var ci = this._currentIndex;
9192 var bh = this.removeBehavior;
9193 // Silently adjust the index if the current tab is not removed.
9194 if (ci !== i) {
9195 if (ci > i) {
9196 this._currentIndex--;
9197 }
9198 return;
9199 }
9200 // TODO: do we need to do an update to adjust the aria-selected value?
9201 // No tab gets selected if the tab bar is empty.
9202 if (this._titles.length === 0) {
9203 this._currentIndex = -1;
9204 this._currentChanged.emit({
9205 previousIndex: i,
9206 previousTitle: title,
9207 currentIndex: -1,
9208 currentTitle: null
9209 });
9210 return;
9211 }
9212 // Handle behavior where the next sibling tab is selected.
9213 if (bh === 'select-tab-after') {
9214 this._currentIndex = Math.min(i, this._titles.length - 1);
9215 this._currentChanged.emit({
9216 previousIndex: i,
9217 previousTitle: title,
9218 currentIndex: this._currentIndex,
9219 currentTitle: this.currentTitle
9220 });
9221 return;
9222 }
9223 // Handle behavior where the previous sibling tab is selected.
9224 if (bh === 'select-tab-before') {
9225 this._currentIndex = Math.max(0, i - 1);
9226 this._currentChanged.emit({
9227 previousIndex: i,
9228 previousTitle: title,
9229 currentIndex: this._currentIndex,
9230 currentTitle: this.currentTitle
9231 });
9232 return;
9233 }
9234 // Handle behavior where the previous history tab is selected.
9235 if (bh === 'select-previous-tab') {
9236 if (this._previousTitle) {
9237 this._currentIndex = this._titles.indexOf(this._previousTitle);
9238 this._previousTitle = null;
9239 }
9240 else {
9241 this._currentIndex = Math.min(i, this._titles.length - 1);
9242 }
9243 this._currentChanged.emit({
9244 previousIndex: i,
9245 previousTitle: title,
9246 currentIndex: this._currentIndex,
9247 currentTitle: this.currentTitle
9248 });
9249 return;
9250 }
9251 // Otherwise, no tab gets selected.
9252 this._currentIndex = -1;
9253 this._currentChanged.emit({
9254 previousIndex: i,
9255 previousTitle: title,
9256 currentIndex: -1,
9257 currentTitle: null
9258 });
9259 };
9260 /**
9261 * Handle the `changed` signal of a title object.
9262 */
9263 TabBar.prototype._onTitleChanged = function (sender) {
9264 this.update();
9265 };
9266 return TabBar;
9267}(Widget));
9268/**
9269 * The namespace for the `TabBar` class statics.
9270 */
9271(function (TabBar) {
9272 /**
9273 * The default implementation of `IRenderer`.
9274 *
9275 * #### Notes
9276 * Subclasses are free to reimplement rendering methods as needed.
9277 */
9278 var Renderer = /** @class */ (function () {
9279 function Renderer() {
9280 /**
9281 * A selector which matches the close icon node in a tab.
9282 */
9283 this.closeIconSelector = '.lm-TabBar-tabCloseIcon';
9284 this._tabID = 0;
9285 this._tabKeys = new WeakMap();
9286 }
9287 /**
9288 * Render the virtual element for a tab.
9289 *
9290 * @param data - The data to use for rendering the tab.
9291 *
9292 * @returns A virtual element representing the tab.
9293 */
9294 Renderer.prototype.renderTab = function (data) {
9295 var title = data.title.caption;
9296 var key = this.createTabKey(data);
9297 var id = key;
9298 var style = this.createTabStyle(data);
9299 var className = this.createTabClass(data);
9300 var dataset = this.createTabDataset(data);
9301 var aria = this.createTabARIA(data);
9302 if (data.title.closable) {
9303 return h.li(__assign({ id: id, key: key, className: className, title: title, style: style, dataset: dataset }, aria), this.renderIcon(data), this.renderLabel(data), this.renderCloseIcon(data));
9304 }
9305 else {
9306 return h.li(__assign({ id: id, key: key, className: className, title: title, style: style, dataset: dataset }, aria), this.renderIcon(data), this.renderLabel(data));
9307 }
9308 };
9309 /**
9310 * Render the icon element for a tab.
9311 *
9312 * @param data - The data to use for rendering the tab.
9313 *
9314 * @returns A virtual element representing the tab icon.
9315 */
9316 Renderer.prototype.renderIcon = function (data) {
9317 var title = data.title;
9318 var className = this.createIconClass(data);
9319 /* <DEPRECATED> */
9320 if (typeof title.icon === 'string') {
9321 return h.div({ className: className }, title.iconLabel);
9322 }
9323 /* </DEPRECATED> */
9324 // if title.icon is undefined, it will be ignored
9325 return h.div({ className: className }, title.icon, title.iconLabel);
9326 };
9327 /**
9328 * Render the label element for a tab.
9329 *
9330 * @param data - The data to use for rendering the tab.
9331 *
9332 * @returns A virtual element representing the tab label.
9333 */
9334 Renderer.prototype.renderLabel = function (data) {
9335 return h.div({
9336 className: 'lm-TabBar-tabLabel' +
9337 /* <DEPRECATED> */
9338 ' p-TabBar-tabLabel'
9339 /* </DEPRECATED> */
9340 }, data.title.label);
9341 };
9342 /**
9343 * Render the close icon element for a tab.
9344 *
9345 * @param data - The data to use for rendering the tab.
9346 *
9347 * @returns A virtual element representing the tab close icon.
9348 */
9349 Renderer.prototype.renderCloseIcon = function (data) {
9350 return h.div({
9351 className: 'lm-TabBar-tabCloseIcon' +
9352 /* <DEPRECATED> */
9353 ' p-TabBar-tabCloseIcon'
9354 /* </DEPRECATED> */
9355 });
9356 };
9357 /**
9358 * Create a unique render key for the tab.
9359 *
9360 * @param data - The data to use for the tab.
9361 *
9362 * @returns The unique render key for the tab.
9363 *
9364 * #### Notes
9365 * This method caches the key against the tab title the first time
9366 * the key is generated. This enables efficient rendering of moved
9367 * tabs and avoids subtle hover style artifacts.
9368 */
9369 Renderer.prototype.createTabKey = function (data) {
9370 var key = this._tabKeys.get(data.title);
9371 if (key === undefined) {
9372 key = "tab-key-" + this._tabID++;
9373 this._tabKeys.set(data.title, key);
9374 }
9375 return key;
9376 };
9377 /**
9378 * Create the inline style object for a tab.
9379 *
9380 * @param data - The data to use for the tab.
9381 *
9382 * @returns The inline style data for the tab.
9383 */
9384 Renderer.prototype.createTabStyle = function (data) {
9385 return { zIndex: "" + data.zIndex };
9386 };
9387 /**
9388 * Create the class name for the tab.
9389 *
9390 * @param data - The data to use for the tab.
9391 *
9392 * @returns The full class name for the tab.
9393 */
9394 Renderer.prototype.createTabClass = function (data) {
9395 var name = 'lm-TabBar-tab';
9396 /* <DEPRECATED> */
9397 name += ' p-TabBar-tab';
9398 /* </DEPRECATED> */
9399 if (data.title.className) {
9400 name += " " + data.title.className;
9401 }
9402 if (data.title.closable) {
9403 name += ' lm-mod-closable';
9404 /* <DEPRECATED> */
9405 name += ' p-mod-closable';
9406 /* </DEPRECATED> */
9407 }
9408 if (data.current) {
9409 name += ' lm-mod-current';
9410 /* <DEPRECATED> */
9411 name += ' p-mod-current';
9412 /* </DEPRECATED> */
9413 }
9414 return name;
9415 };
9416 /**
9417 * Create the dataset for a tab.
9418 *
9419 * @param data - The data to use for the tab.
9420 *
9421 * @returns The dataset for the tab.
9422 */
9423 Renderer.prototype.createTabDataset = function (data) {
9424 return data.title.dataset;
9425 };
9426 /**
9427 * Create the ARIA attributes for a tab.
9428 *
9429 * @param data - The data to use for the tab.
9430 *
9431 * @returns The ARIA attributes for the tab.
9432 */
9433 Renderer.prototype.createTabARIA = function (data) {
9434 return { role: 'tab', 'aria-selected': data.current.toString() };
9435 };
9436 /**
9437 * Create the class name for the tab icon.
9438 *
9439 * @param data - The data to use for the tab.
9440 *
9441 * @returns The full class name for the tab icon.
9442 */
9443 Renderer.prototype.createIconClass = function (data) {
9444 var name = 'lm-TabBar-tabIcon';
9445 /* <DEPRECATED> */
9446 name += ' p-TabBar-tabIcon';
9447 /* </DEPRECATED> */
9448 var extra = data.title.iconClass;
9449 return extra ? name + " " + extra : name;
9450 };
9451 return Renderer;
9452 }());
9453 TabBar.Renderer = Renderer;
9454 /**
9455 * The default `Renderer` instance.
9456 */
9457 TabBar.defaultRenderer = new Renderer();
9458 /**
9459 * A selector which matches the add button node in the tab bar.
9460 */
9461 TabBar.addButtonSelector = '.lm-TabBar-addButton';
9462})(TabBar || (TabBar = {}));
9463/**
9464 * The namespace for the module implementation details.
9465 */
9466var Private$7;
9467(function (Private) {
9468 /**
9469 * The start drag distance threshold.
9470 */
9471 Private.DRAG_THRESHOLD = 5;
9472 /**
9473 * The detach distance threshold.
9474 */
9475 Private.DETACH_THRESHOLD = 20;
9476 /**
9477 * Create the DOM node for a tab bar.
9478 */
9479 function createNode() {
9480 var node = document.createElement('div');
9481 var content = document.createElement('ul');
9482 content.setAttribute('role', 'tablist');
9483 content.className = 'lm-TabBar-content';
9484 /* <DEPRECATED> */
9485 content.classList.add('p-TabBar-content');
9486 /* </DEPRECATED> */
9487 node.appendChild(content);
9488 var add = document.createElement('div');
9489 add.className = 'lm-TabBar-addButton lm-mod-hidden';
9490 node.appendChild(add);
9491 return node;
9492 }
9493 Private.createNode = createNode;
9494 /**
9495 * Coerce a title or options into a real title.
9496 */
9497 function asTitle(value) {
9498 return value instanceof Title ? value : new Title(value);
9499 }
9500 Private.asTitle = asTitle;
9501 /**
9502 * Parse the transition duration for a tab node.
9503 */
9504 function parseTransitionDuration(tab) {
9505 var style = window.getComputedStyle(tab);
9506 return 1000 * (parseFloat(style.transitionDuration) || 0);
9507 }
9508 Private.parseTransitionDuration = parseTransitionDuration;
9509 /**
9510 * Get a snapshot of the current tab layout values.
9511 */
9512 function snapTabLayout(tabs, orientation) {
9513 var layout = new Array(tabs.length);
9514 for (var i = 0, n = tabs.length; i < n; ++i) {
9515 var node = tabs[i];
9516 var style = window.getComputedStyle(node);
9517 if (orientation === 'horizontal') {
9518 layout[i] = {
9519 pos: node.offsetLeft,
9520 size: node.offsetWidth,
9521 margin: parseFloat(style.marginLeft) || 0
9522 };
9523 }
9524 else {
9525 layout[i] = {
9526 pos: node.offsetTop,
9527 size: node.offsetHeight,
9528 margin: parseFloat(style.marginTop) || 0
9529 };
9530 }
9531 }
9532 return layout;
9533 }
9534 Private.snapTabLayout = snapTabLayout;
9535 /**
9536 * Test if the event exceeds the drag threshold.
9537 */
9538 function dragExceeded(data, event) {
9539 var dx = Math.abs(event.clientX - data.pressX);
9540 var dy = Math.abs(event.clientY - data.pressY);
9541 return dx >= Private.DRAG_THRESHOLD || dy >= Private.DRAG_THRESHOLD;
9542 }
9543 Private.dragExceeded = dragExceeded;
9544 /**
9545 * Test if the event exceeds the drag detach threshold.
9546 */
9547 function detachExceeded(data, event) {
9548 var rect = data.contentRect;
9549 return (event.clientX < rect.left - Private.DETACH_THRESHOLD ||
9550 event.clientX >= rect.right + Private.DETACH_THRESHOLD ||
9551 event.clientY < rect.top - Private.DETACH_THRESHOLD ||
9552 event.clientY >= rect.bottom + Private.DETACH_THRESHOLD);
9553 }
9554 Private.detachExceeded = detachExceeded;
9555 /**
9556 * Update the relative tab positions and computed target index.
9557 */
9558 function layoutTabs(tabs, data, event, orientation) {
9559 // Compute the orientation-sensitive values.
9560 var pressPos;
9561 var localPos;
9562 var clientPos;
9563 var clientSize;
9564 if (orientation === 'horizontal') {
9565 pressPos = data.pressX;
9566 localPos = event.clientX - data.contentRect.left;
9567 clientPos = event.clientX;
9568 clientSize = data.contentRect.width;
9569 }
9570 else {
9571 pressPos = data.pressY;
9572 localPos = event.clientY - data.contentRect.top;
9573 clientPos = event.clientY;
9574 clientSize = data.contentRect.height;
9575 }
9576 // Compute the target data.
9577 var targetIndex = data.index;
9578 var targetPos = localPos - data.tabPressPos;
9579 var targetEnd = targetPos + data.tabSize;
9580 // Update the relative tab positions.
9581 for (var i = 0, n = tabs.length; i < n; ++i) {
9582 var pxPos = void 0;
9583 var layout = data.tabLayout[i];
9584 var threshold = layout.pos + (layout.size >> 1);
9585 if (i < data.index && targetPos < threshold) {
9586 pxPos = data.tabSize + data.tabLayout[i + 1].margin + "px";
9587 targetIndex = Math.min(targetIndex, i);
9588 }
9589 else if (i > data.index && targetEnd > threshold) {
9590 pxPos = -data.tabSize - layout.margin + "px";
9591 targetIndex = Math.max(targetIndex, i);
9592 }
9593 else if (i === data.index) {
9594 var ideal = clientPos - pressPos;
9595 var limit = clientSize - (data.tabPos + data.tabSize);
9596 pxPos = Math.max(-data.tabPos, Math.min(ideal, limit)) + "px";
9597 }
9598 else {
9599 pxPos = '';
9600 }
9601 if (orientation === 'horizontal') {
9602 tabs[i].style.left = pxPos;
9603 }
9604 else {
9605 tabs[i].style.top = pxPos;
9606 }
9607 }
9608 // Update the computed target index.
9609 data.targetIndex = targetIndex;
9610 }
9611 Private.layoutTabs = layoutTabs;
9612 /**
9613 * Position the drag tab at its final resting relative position.
9614 */
9615 function finalizeTabPosition(data, orientation) {
9616 // Compute the orientation-sensitive client size.
9617 var clientSize;
9618 if (orientation === 'horizontal') {
9619 clientSize = data.contentRect.width;
9620 }
9621 else {
9622 clientSize = data.contentRect.height;
9623 }
9624 // Compute the ideal final tab position.
9625 var ideal;
9626 if (data.targetIndex === data.index) {
9627 ideal = 0;
9628 }
9629 else if (data.targetIndex > data.index) {
9630 var tgt = data.tabLayout[data.targetIndex];
9631 ideal = tgt.pos + tgt.size - data.tabSize - data.tabPos;
9632 }
9633 else {
9634 var tgt = data.tabLayout[data.targetIndex];
9635 ideal = tgt.pos - data.tabPos;
9636 }
9637 // Compute the tab position limit.
9638 var limit = clientSize - (data.tabPos + data.tabSize);
9639 var final = Math.max(-data.tabPos, Math.min(ideal, limit));
9640 // Set the final orientation-sensitive position.
9641 if (orientation === 'horizontal') {
9642 data.tab.style.left = final + "px";
9643 }
9644 else {
9645 data.tab.style.top = final + "px";
9646 }
9647 }
9648 Private.finalizeTabPosition = finalizeTabPosition;
9649 /**
9650 * Reset the relative positions of the given tabs.
9651 */
9652 function resetTabPositions(tabs, orientation) {
9653 each(tabs, function (tab) {
9654 if (orientation === 'horizontal') {
9655 tab.style.left = '';
9656 }
9657 else {
9658 tab.style.top = '';
9659 }
9660 });
9661 }
9662 Private.resetTabPositions = resetTabPositions;
9663})(Private$7 || (Private$7 = {}));
9664
9665/**
9666 * A layout which provides a flexible docking arrangement.
9667 *
9668 * #### Notes
9669 * The consumer of this layout is responsible for handling all signals
9670 * from the generated tab bars and managing the visibility of widgets
9671 * and tab bars as needed.
9672 */
9673var DockLayout = /** @class */ (function (_super) {
9674 __extends(DockLayout, _super);
9675 /**
9676 * Construct a new dock layout.
9677 *
9678 * @param options - The options for initializing the layout.
9679 */
9680 function DockLayout(options) {
9681 var _this = _super.call(this) || this;
9682 _this._spacing = 4;
9683 _this._dirty = false;
9684 _this._root = null;
9685 _this._box = null;
9686 _this._items = new Map();
9687 _this.renderer = options.renderer;
9688 if (options.spacing !== undefined) {
9689 _this._spacing = Utils$1.clampDimension(options.spacing);
9690 }
9691 _this._document = options.document || document;
9692 _this._hiddenMode =
9693 options.hiddenMode !== undefined
9694 ? options.hiddenMode
9695 : Widget.HiddenMode.Display;
9696 return _this;
9697 }
9698 /**
9699 * Dispose of the resources held by the layout.
9700 *
9701 * #### Notes
9702 * This will clear and dispose all widgets in the layout.
9703 */
9704 DockLayout.prototype.dispose = function () {
9705 // Get an iterator over the widgets in the layout.
9706 var widgets = this.iter();
9707 // Dispose of the layout items.
9708 this._items.forEach(function (item) {
9709 item.dispose();
9710 });
9711 // Clear the layout state before disposing the widgets.
9712 this._box = null;
9713 this._root = null;
9714 this._items.clear();
9715 // Dispose of the widgets contained in the old layout root.
9716 each(widgets, function (widget) {
9717 widget.dispose();
9718 });
9719 // Dispose of the base class.
9720 _super.prototype.dispose.call(this);
9721 };
9722 Object.defineProperty(DockLayout.prototype, "hiddenMode", {
9723 /**
9724 * The method for hiding child widgets.
9725 *
9726 * #### Notes
9727 * If there is only one child widget, `Display` hiding mode will be used
9728 * regardless of this setting.
9729 */
9730 get: function () {
9731 return this._hiddenMode;
9732 },
9733 set: function (v) {
9734 var _this = this;
9735 if (this._hiddenMode === v) {
9736 return;
9737 }
9738 this._hiddenMode = v;
9739 each(this.tabBars(), function (bar) {
9740 if (bar.titles.length > 1) {
9741 bar.titles.forEach(function (title) {
9742 title.owner.hiddenMode = _this._hiddenMode;
9743 });
9744 }
9745 });
9746 },
9747 enumerable: true,
9748 configurable: true
9749 });
9750 Object.defineProperty(DockLayout.prototype, "spacing", {
9751 /**
9752 * Get the inter-element spacing for the dock layout.
9753 */
9754 get: function () {
9755 return this._spacing;
9756 },
9757 /**
9758 * Set the inter-element spacing for the dock layout.
9759 */
9760 set: function (value) {
9761 value = Utils$1.clampDimension(value);
9762 if (this._spacing === value) {
9763 return;
9764 }
9765 this._spacing = value;
9766 if (!this.parent) {
9767 return;
9768 }
9769 this.parent.fit();
9770 },
9771 enumerable: true,
9772 configurable: true
9773 });
9774 Object.defineProperty(DockLayout.prototype, "isEmpty", {
9775 /**
9776 * Whether the dock layout is empty.
9777 */
9778 get: function () {
9779 return this._root === null;
9780 },
9781 enumerable: true,
9782 configurable: true
9783 });
9784 /**
9785 * Create an iterator over all widgets in the layout.
9786 *
9787 * @returns A new iterator over the widgets in the layout.
9788 *
9789 * #### Notes
9790 * This iterator includes the generated tab bars.
9791 */
9792 DockLayout.prototype.iter = function () {
9793 return this._root ? this._root.iterAllWidgets() : empty();
9794 };
9795 /**
9796 * Create an iterator over the user widgets in the layout.
9797 *
9798 * @returns A new iterator over the user widgets in the layout.
9799 *
9800 * #### Notes
9801 * This iterator does not include the generated tab bars.
9802 */
9803 DockLayout.prototype.widgets = function () {
9804 return this._root ? this._root.iterUserWidgets() : empty();
9805 };
9806 /**
9807 * Create an iterator over the selected widgets in the layout.
9808 *
9809 * @returns A new iterator over the selected user widgets.
9810 *
9811 * #### Notes
9812 * This iterator yields the widgets corresponding to the current tab
9813 * of each tab bar in the layout.
9814 */
9815 DockLayout.prototype.selectedWidgets = function () {
9816 return this._root ? this._root.iterSelectedWidgets() : empty();
9817 };
9818 /**
9819 * Create an iterator over the tab bars in the layout.
9820 *
9821 * @returns A new iterator over the tab bars in the layout.
9822 *
9823 * #### Notes
9824 * This iterator does not include the user widgets.
9825 */
9826 DockLayout.prototype.tabBars = function () {
9827 return this._root ? this._root.iterTabBars() : empty();
9828 };
9829 /**
9830 * Create an iterator over the handles in the layout.
9831 *
9832 * @returns A new iterator over the handles in the layout.
9833 */
9834 DockLayout.prototype.handles = function () {
9835 return this._root ? this._root.iterHandles() : empty();
9836 };
9837 /**
9838 * Move a handle to the given offset position.
9839 *
9840 * @param handle - The handle to move.
9841 *
9842 * @param offsetX - The desired offset X position of the handle.
9843 *
9844 * @param offsetY - The desired offset Y position of the handle.
9845 *
9846 * #### Notes
9847 * If the given handle is not contained in the layout, this is no-op.
9848 *
9849 * The handle will be moved as close as possible to the desired
9850 * position without violating any of the layout constraints.
9851 *
9852 * Only one of the coordinates is used depending on the orientation
9853 * of the handle. This method accepts both coordinates to make it
9854 * easy to invoke from a mouse move event without needing to know
9855 * the handle orientation.
9856 */
9857 DockLayout.prototype.moveHandle = function (handle, offsetX, offsetY) {
9858 // Bail early if there is no root or if the handle is hidden.
9859 var hidden = handle.classList.contains('lm-mod-hidden');
9860 /* <DEPRECATED> */
9861 hidden = hidden || handle.classList.contains('p-mod-hidden');
9862 /* </DEPRECATED> */
9863 if (!this._root || hidden) {
9864 return;
9865 }
9866 // Lookup the split node for the handle.
9867 var data = this._root.findSplitNode(handle);
9868 if (!data) {
9869 return;
9870 }
9871 // Compute the desired delta movement for the handle.
9872 var delta;
9873 if (data.node.orientation === 'horizontal') {
9874 delta = offsetX - handle.offsetLeft;
9875 }
9876 else {
9877 delta = offsetY - handle.offsetTop;
9878 }
9879 // Bail if there is no handle movement.
9880 if (delta === 0) {
9881 return;
9882 }
9883 // Prevent sibling resizing unless needed.
9884 data.node.holdSizes();
9885 // Adjust the sizers to reflect the handle movement.
9886 BoxEngine.adjust(data.node.sizers, data.index, delta);
9887 // Update the layout of the widgets.
9888 if (this.parent) {
9889 this.parent.update();
9890 }
9891 };
9892 /**
9893 * Save the current configuration of the dock layout.
9894 *
9895 * @returns A new config object for the current layout state.
9896 *
9897 * #### Notes
9898 * The return value can be provided to the `restoreLayout` method
9899 * in order to restore the layout to its current configuration.
9900 */
9901 DockLayout.prototype.saveLayout = function () {
9902 // Bail early if there is no root.
9903 if (!this._root) {
9904 return { main: null };
9905 }
9906 // Hold the current sizes in the layout tree.
9907 this._root.holdAllSizes();
9908 // Return the layout config.
9909 return { main: this._root.createConfig() };
9910 };
9911 /**
9912 * Restore the layout to a previously saved configuration.
9913 *
9914 * @param config - The layout configuration to restore.
9915 *
9916 * #### Notes
9917 * Widgets which currently belong to the layout but which are not
9918 * contained in the config will be unparented.
9919 */
9920 DockLayout.prototype.restoreLayout = function (config) {
9921 var _this = this;
9922 // Create the widget set for validating the config.
9923 var widgetSet = new Set();
9924 // Normalize the main area config and collect the widgets.
9925 var mainConfig;
9926 if (config.main) {
9927 mainConfig = Private$6.normalizeAreaConfig(config.main, widgetSet);
9928 }
9929 else {
9930 mainConfig = null;
9931 }
9932 // Create iterators over the old content.
9933 var oldWidgets = this.widgets();
9934 var oldTabBars = this.tabBars();
9935 var oldHandles = this.handles();
9936 // Clear the root before removing the old content.
9937 this._root = null;
9938 // Unparent the old widgets which are not in the new config.
9939 each(oldWidgets, function (widget) {
9940 if (!widgetSet.has(widget)) {
9941 widget.parent = null;
9942 }
9943 });
9944 // Dispose of the old tab bars.
9945 each(oldTabBars, function (tabBar) {
9946 tabBar.dispose();
9947 });
9948 // Remove the old handles.
9949 each(oldHandles, function (handle) {
9950 if (handle.parentNode) {
9951 handle.parentNode.removeChild(handle);
9952 }
9953 });
9954 // Reparent the new widgets to the current parent.
9955 widgetSet.forEach(function (widget) {
9956 widget.parent = _this.parent;
9957 });
9958 // Create the root node for the new config.
9959 if (mainConfig) {
9960 this._root = Private$6.realizeAreaConfig(mainConfig, {
9961 // Ignoring optional `document` argument as we must reuse `this._document`
9962 createTabBar: function (document) {
9963 return _this._createTabBar();
9964 },
9965 createHandle: function () { return _this._createHandle(); }
9966 }, this._document);
9967 }
9968 else {
9969 this._root = null;
9970 }
9971 // If there is no parent, there is nothing more to do.
9972 if (!this.parent) {
9973 return;
9974 }
9975 // Attach the new widgets to the parent.
9976 widgetSet.forEach(function (widget) {
9977 _this.attachWidget(widget);
9978 });
9979 // Post a fit request to the parent.
9980 this.parent.fit();
9981 };
9982 /**
9983 * Add a widget to the dock layout.
9984 *
9985 * @param widget - The widget to add to the dock layout.
9986 *
9987 * @param options - The additional options for adding the widget.
9988 *
9989 * #### Notes
9990 * The widget will be moved if it is already contained in the layout.
9991 *
9992 * An error will be thrown if the reference widget is invalid.
9993 */
9994 DockLayout.prototype.addWidget = function (widget, options) {
9995 if (options === void 0) { options = {}; }
9996 // Parse the options.
9997 var ref = options.ref || null;
9998 var mode = options.mode || 'tab-after';
9999 // Find the tab node which holds the reference widget.
10000 var refNode = null;
10001 if (this._root && ref) {
10002 refNode = this._root.findTabNode(ref);
10003 }
10004 // Throw an error if the reference widget is invalid.
10005 if (ref && !refNode) {
10006 throw new Error('Reference widget is not in the layout.');
10007 }
10008 // Reparent the widget to the current layout parent.
10009 widget.parent = this.parent;
10010 // Insert the widget according to the insert mode.
10011 switch (mode) {
10012 case 'tab-after':
10013 this._insertTab(widget, ref, refNode, true);
10014 break;
10015 case 'tab-before':
10016 this._insertTab(widget, ref, refNode, false);
10017 break;
10018 case 'split-top':
10019 this._insertSplit(widget, ref, refNode, 'vertical', false);
10020 break;
10021 case 'split-left':
10022 this._insertSplit(widget, ref, refNode, 'horizontal', false);
10023 break;
10024 case 'split-right':
10025 this._insertSplit(widget, ref, refNode, 'horizontal', true);
10026 break;
10027 case 'split-bottom':
10028 this._insertSplit(widget, ref, refNode, 'vertical', true);
10029 break;
10030 }
10031 // Do nothing else if there is no parent widget.
10032 if (!this.parent) {
10033 return;
10034 }
10035 // Ensure the widget is attached to the parent widget.
10036 this.attachWidget(widget);
10037 // Post a fit request for the parent widget.
10038 this.parent.fit();
10039 };
10040 /**
10041 * Remove a widget from the layout.
10042 *
10043 * @param widget - The widget to remove from the layout.
10044 *
10045 * #### Notes
10046 * A widget is automatically removed from the layout when its `parent`
10047 * is set to `null`. This method should only be invoked directly when
10048 * removing a widget from a layout which has yet to be installed on a
10049 * parent widget.
10050 *
10051 * This method does *not* modify the widget's `parent`.
10052 */
10053 DockLayout.prototype.removeWidget = function (widget) {
10054 // Remove the widget from its current layout location.
10055 this._removeWidget(widget);
10056 // Do nothing else if there is no parent widget.
10057 if (!this.parent) {
10058 return;
10059 }
10060 // Detach the widget from the parent widget.
10061 this.detachWidget(widget);
10062 // Post a fit request for the parent widget.
10063 this.parent.fit();
10064 };
10065 /**
10066 * Find the tab area which contains the given client position.
10067 *
10068 * @param clientX - The client X position of interest.
10069 *
10070 * @param clientY - The client Y position of interest.
10071 *
10072 * @returns The geometry of the tab area at the given position, or
10073 * `null` if there is no tab area at the given position.
10074 */
10075 DockLayout.prototype.hitTestTabAreas = function (clientX, clientY) {
10076 // Bail early if hit testing cannot produce valid results.
10077 if (!this._root || !this.parent || !this.parent.isVisible) {
10078 return null;
10079 }
10080 // Ensure the parent box sizing data is computed.
10081 if (!this._box) {
10082 this._box = ElementExt.boxSizing(this.parent.node);
10083 }
10084 // Convert from client to local coordinates.
10085 var rect = this.parent.node.getBoundingClientRect();
10086 var x = clientX - rect.left - this._box.borderLeft;
10087 var y = clientY - rect.top - this._box.borderTop;
10088 // Find the tab layout node at the local position.
10089 var tabNode = this._root.hitTestTabNodes(x, y);
10090 // Bail if a tab layout node was not found.
10091 if (!tabNode) {
10092 return null;
10093 }
10094 // Extract the data from the tab node.
10095 var tabBar = tabNode.tabBar, top = tabNode.top, left = tabNode.left, width = tabNode.width, height = tabNode.height;
10096 // Compute the right and bottom edges of the tab area.
10097 var borderWidth = this._box.borderLeft + this._box.borderRight;
10098 var borderHeight = this._box.borderTop + this._box.borderBottom;
10099 var right = rect.width - borderWidth - (left + width);
10100 var bottom = rect.height - borderHeight - (top + height);
10101 // Return the hit test results.
10102 return { tabBar: tabBar, x: x, y: y, top: top, left: left, right: right, bottom: bottom, width: width, height: height };
10103 };
10104 /**
10105 * Perform layout initialization which requires the parent widget.
10106 */
10107 DockLayout.prototype.init = function () {
10108 var _this = this;
10109 // Perform superclass initialization.
10110 _super.prototype.init.call(this);
10111 // Attach each widget to the parent.
10112 each(this, function (widget) {
10113 _this.attachWidget(widget);
10114 });
10115 // Attach each handle to the parent.
10116 each(this.handles(), function (handle) {
10117 _this.parent.node.appendChild(handle);
10118 });
10119 // Post a fit request for the parent widget.
10120 this.parent.fit();
10121 };
10122 /**
10123 * Attach the widget to the layout parent widget.
10124 *
10125 * @param widget - The widget to attach to the parent.
10126 *
10127 * #### Notes
10128 * This is a no-op if the widget is already attached.
10129 */
10130 DockLayout.prototype.attachWidget = function (widget) {
10131 // Do nothing if the widget is already attached.
10132 if (this.parent.node === widget.node.parentNode) {
10133 return;
10134 }
10135 // Create the layout item for the widget.
10136 this._items.set(widget, new LayoutItem(widget));
10137 // Send a `'before-attach'` message if the parent is attached.
10138 if (this.parent.isAttached) {
10139 MessageLoop.sendMessage(widget, Widget.Msg.BeforeAttach);
10140 }
10141 // Add the widget's node to the parent.
10142 this.parent.node.appendChild(widget.node);
10143 // Send an `'after-attach'` message if the parent is attached.
10144 if (this.parent.isAttached) {
10145 MessageLoop.sendMessage(widget, Widget.Msg.AfterAttach);
10146 }
10147 };
10148 /**
10149 * Detach the widget from the layout parent widget.
10150 *
10151 * @param widget - The widget to detach from the parent.
10152 *
10153 * #### Notes
10154 * This is a no-op if the widget is not attached.
10155 */
10156 DockLayout.prototype.detachWidget = function (widget) {
10157 // Do nothing if the widget is not attached.
10158 if (this.parent.node !== widget.node.parentNode) {
10159 return;
10160 }
10161 // Send a `'before-detach'` message if the parent is attached.
10162 if (this.parent.isAttached) {
10163 MessageLoop.sendMessage(widget, Widget.Msg.BeforeDetach);
10164 }
10165 // Remove the widget's node from the parent.
10166 this.parent.node.removeChild(widget.node);
10167 // Send an `'after-detach'` message if the parent is attached.
10168 if (this.parent.isAttached) {
10169 MessageLoop.sendMessage(widget, Widget.Msg.AfterDetach);
10170 }
10171 // Delete the layout item for the widget.
10172 var item = this._items.get(widget);
10173 if (item) {
10174 this._items.delete(widget);
10175 item.dispose();
10176 }
10177 };
10178 /**
10179 * A message handler invoked on a `'before-show'` message.
10180 */
10181 DockLayout.prototype.onBeforeShow = function (msg) {
10182 _super.prototype.onBeforeShow.call(this, msg);
10183 this.parent.update();
10184 };
10185 /**
10186 * A message handler invoked on a `'before-attach'` message.
10187 */
10188 DockLayout.prototype.onBeforeAttach = function (msg) {
10189 _super.prototype.onBeforeAttach.call(this, msg);
10190 this.parent.fit();
10191 };
10192 /**
10193 * A message handler invoked on a `'child-shown'` message.
10194 */
10195 DockLayout.prototype.onChildShown = function (msg) {
10196 this.parent.fit();
10197 };
10198 /**
10199 * A message handler invoked on a `'child-hidden'` message.
10200 */
10201 DockLayout.prototype.onChildHidden = function (msg) {
10202 this.parent.fit();
10203 };
10204 /**
10205 * A message handler invoked on a `'resize'` message.
10206 */
10207 DockLayout.prototype.onResize = function (msg) {
10208 if (this.parent.isVisible) {
10209 this._update(msg.width, msg.height);
10210 }
10211 };
10212 /**
10213 * A message handler invoked on an `'update-request'` message.
10214 */
10215 DockLayout.prototype.onUpdateRequest = function (msg) {
10216 if (this.parent.isVisible) {
10217 this._update(-1, -1);
10218 }
10219 };
10220 /**
10221 * A message handler invoked on a `'fit-request'` message.
10222 */
10223 DockLayout.prototype.onFitRequest = function (msg) {
10224 if (this.parent.isAttached) {
10225 this._fit();
10226 }
10227 };
10228 /**
10229 * Remove the specified widget from the layout structure.
10230 *
10231 * #### Notes
10232 * This is a no-op if the widget is not in the layout tree.
10233 *
10234 * This does not detach the widget from the parent node.
10235 */
10236 DockLayout.prototype._removeWidget = function (widget) {
10237 // Bail early if there is no layout root.
10238 if (!this._root) {
10239 return;
10240 }
10241 // Find the tab node which contains the given widget.
10242 var tabNode = this._root.findTabNode(widget);
10243 // Bail early if the tab node is not found.
10244 if (!tabNode) {
10245 return;
10246 }
10247 Private$6.removeAria(widget);
10248 // If there are multiple tabs, just remove the widget's tab.
10249 if (tabNode.tabBar.titles.length > 1) {
10250 tabNode.tabBar.removeTab(widget.title);
10251 if (this._hiddenMode === Widget.HiddenMode.Scale &&
10252 tabNode.tabBar.titles.length == 1) {
10253 var existingWidget = tabNode.tabBar.titles[0].owner;
10254 existingWidget.hiddenMode = Widget.HiddenMode.Display;
10255 }
10256 return;
10257 }
10258 // Otherwise, the tab node needs to be removed...
10259 // Dispose the tab bar.
10260 tabNode.tabBar.dispose();
10261 // Handle the case where the tab node is the root.
10262 if (this._root === tabNode) {
10263 this._root = null;
10264 return;
10265 }
10266 // Otherwise, remove the tab node from its parent...
10267 // Prevent widget resizing unless needed.
10268 this._root.holdAllSizes();
10269 // Clear the parent reference on the tab node.
10270 var splitNode = tabNode.parent;
10271 tabNode.parent = null;
10272 // Remove the tab node from its parent split node.
10273 var i = ArrayExt.removeFirstOf(splitNode.children, tabNode);
10274 var handle = ArrayExt.removeAt(splitNode.handles, i);
10275 ArrayExt.removeAt(splitNode.sizers, i);
10276 // Remove the handle from its parent DOM node.
10277 if (handle.parentNode) {
10278 handle.parentNode.removeChild(handle);
10279 }
10280 // If there are multiple children, just update the handles.
10281 if (splitNode.children.length > 1) {
10282 splitNode.syncHandles();
10283 return;
10284 }
10285 // Otherwise, the split node also needs to be removed...
10286 // Clear the parent reference on the split node.
10287 var maybeParent = splitNode.parent;
10288 splitNode.parent = null;
10289 // Lookup the remaining child node and handle.
10290 var childNode = splitNode.children[0];
10291 var childHandle = splitNode.handles[0];
10292 // Clear the split node data.
10293 splitNode.children.length = 0;
10294 splitNode.handles.length = 0;
10295 splitNode.sizers.length = 0;
10296 // Remove the child handle from its parent node.
10297 if (childHandle.parentNode) {
10298 childHandle.parentNode.removeChild(childHandle);
10299 }
10300 // Handle the case where the split node is the root.
10301 if (this._root === splitNode) {
10302 childNode.parent = null;
10303 this._root = childNode;
10304 return;
10305 }
10306 // Otherwise, move the child node to the parent node...
10307 var parentNode = maybeParent;
10308 // Lookup the index of the split node.
10309 var j = parentNode.children.indexOf(splitNode);
10310 // Handle the case where the child node is a tab node.
10311 if (childNode instanceof Private$6.TabLayoutNode) {
10312 childNode.parent = parentNode;
10313 parentNode.children[j] = childNode;
10314 return;
10315 }
10316 // Remove the split data from the parent.
10317 var splitHandle = ArrayExt.removeAt(parentNode.handles, j);
10318 ArrayExt.removeAt(parentNode.children, j);
10319 ArrayExt.removeAt(parentNode.sizers, j);
10320 // Remove the handle from its parent node.
10321 if (splitHandle.parentNode) {
10322 splitHandle.parentNode.removeChild(splitHandle);
10323 }
10324 // The child node and the split parent node will have the same
10325 // orientation. Merge the grand-children with the parent node.
10326 for (var i_1 = 0, n = childNode.children.length; i_1 < n; ++i_1) {
10327 var gChild = childNode.children[i_1];
10328 var gHandle = childNode.handles[i_1];
10329 var gSizer = childNode.sizers[i_1];
10330 ArrayExt.insert(parentNode.children, j + i_1, gChild);
10331 ArrayExt.insert(parentNode.handles, j + i_1, gHandle);
10332 ArrayExt.insert(parentNode.sizers, j + i_1, gSizer);
10333 gChild.parent = parentNode;
10334 }
10335 // Clear the child node.
10336 childNode.children.length = 0;
10337 childNode.handles.length = 0;
10338 childNode.sizers.length = 0;
10339 childNode.parent = null;
10340 // Sync the handles on the parent node.
10341 parentNode.syncHandles();
10342 };
10343 /**
10344 * Insert a widget next to an existing tab.
10345 *
10346 * #### Notes
10347 * This does not attach the widget to the parent widget.
10348 */
10349 DockLayout.prototype._insertTab = function (widget, ref, refNode, after) {
10350 // Do nothing if the tab is inserted next to itself.
10351 if (widget === ref) {
10352 return;
10353 }
10354 // Create the root if it does not exist.
10355 if (!this._root) {
10356 var tabNode = new Private$6.TabLayoutNode(this._createTabBar());
10357 tabNode.tabBar.addTab(widget.title);
10358 this._root = tabNode;
10359 Private$6.addAria(widget, tabNode.tabBar);
10360 return;
10361 }
10362 // Use the first tab node as the ref node if needed.
10363 if (!refNode) {
10364 refNode = this._root.findFirstTabNode();
10365 }
10366 // If the widget is not contained in the ref node, ensure it is
10367 // removed from the layout and hidden before being added again.
10368 if (refNode.tabBar.titles.indexOf(widget.title) === -1) {
10369 this._removeWidget(widget);
10370 widget.hide();
10371 }
10372 // Lookup the target index for inserting the tab.
10373 var index;
10374 if (ref) {
10375 index = refNode.tabBar.titles.indexOf(ref.title);
10376 }
10377 else {
10378 index = refNode.tabBar.currentIndex;
10379 }
10380 // Using transform create an additional layer in the pixel pipeline
10381 // to limit the number of layer, it is set only if there is more than one widget.
10382 if (this._hiddenMode === Widget.HiddenMode.Scale &&
10383 refNode.tabBar.titles.length > 0) {
10384 if (refNode.tabBar.titles.length == 1) {
10385 var existingWidget = refNode.tabBar.titles[0].owner;
10386 existingWidget.hiddenMode = Widget.HiddenMode.Scale;
10387 }
10388 widget.hiddenMode = Widget.HiddenMode.Scale;
10389 }
10390 else {
10391 widget.hiddenMode = Widget.HiddenMode.Display;
10392 }
10393 // Insert the widget's tab relative to the target index.
10394 refNode.tabBar.insertTab(index + (after ? 1 : 0), widget.title);
10395 Private$6.addAria(widget, refNode.tabBar);
10396 };
10397 /**
10398 * Insert a widget as a new split area.
10399 *
10400 * #### Notes
10401 * This does not attach the widget to the parent widget.
10402 */
10403 DockLayout.prototype._insertSplit = function (widget, ref, refNode, orientation, after) {
10404 // Do nothing if there is no effective split.
10405 if (widget === ref && refNode && refNode.tabBar.titles.length === 1) {
10406 return;
10407 }
10408 // Ensure the widget is removed from the current layout.
10409 this._removeWidget(widget);
10410 // Create the tab layout node to hold the widget.
10411 var tabNode = new Private$6.TabLayoutNode(this._createTabBar());
10412 tabNode.tabBar.addTab(widget.title);
10413 Private$6.addAria(widget, tabNode.tabBar);
10414 // Set the root if it does not exist.
10415 if (!this._root) {
10416 this._root = tabNode;
10417 return;
10418 }
10419 // If the ref node parent is null, split the root.
10420 if (!refNode || !refNode.parent) {
10421 // Ensure the root is split with the correct orientation.
10422 var root = this._splitRoot(orientation);
10423 // Determine the insert index for the new tab node.
10424 var i_2 = after ? root.children.length : 0;
10425 // Normalize the split node.
10426 root.normalizeSizes();
10427 // Create the sizer for new tab node.
10428 var sizer = Private$6.createSizer(refNode ? 1 : Private$6.GOLDEN_RATIO);
10429 // Insert the tab node sized to the golden ratio.
10430 ArrayExt.insert(root.children, i_2, tabNode);
10431 ArrayExt.insert(root.sizers, i_2, sizer);
10432 ArrayExt.insert(root.handles, i_2, this._createHandle());
10433 tabNode.parent = root;
10434 // Re-normalize the split node to maintain the ratios.
10435 root.normalizeSizes();
10436 // Finally, synchronize the visibility of the handles.
10437 root.syncHandles();
10438 return;
10439 }
10440 // Lookup the split node for the ref widget.
10441 var splitNode = refNode.parent;
10442 // If the split node already had the correct orientation,
10443 // the widget can be inserted into the split node directly.
10444 if (splitNode.orientation === orientation) {
10445 // Find the index of the ref node.
10446 var i_3 = splitNode.children.indexOf(refNode);
10447 // Normalize the split node.
10448 splitNode.normalizeSizes();
10449 // Consume half the space for the insert location.
10450 var s = (splitNode.sizers[i_3].sizeHint /= 2);
10451 // Insert the tab node sized to the other half.
10452 var j_1 = i_3 + (after ? 1 : 0);
10453 ArrayExt.insert(splitNode.children, j_1, tabNode);
10454 ArrayExt.insert(splitNode.sizers, j_1, Private$6.createSizer(s));
10455 ArrayExt.insert(splitNode.handles, j_1, this._createHandle());
10456 tabNode.parent = splitNode;
10457 // Finally, synchronize the visibility of the handles.
10458 splitNode.syncHandles();
10459 return;
10460 }
10461 // Remove the ref node from the split node.
10462 var i = ArrayExt.removeFirstOf(splitNode.children, refNode);
10463 // Create a new normalized split node for the children.
10464 var childNode = new Private$6.SplitLayoutNode(orientation);
10465 childNode.normalized = true;
10466 // Add the ref node sized to half the space.
10467 childNode.children.push(refNode);
10468 childNode.sizers.push(Private$6.createSizer(0.5));
10469 childNode.handles.push(this._createHandle());
10470 refNode.parent = childNode;
10471 // Add the tab node sized to the other half.
10472 var j = after ? 1 : 0;
10473 ArrayExt.insert(childNode.children, j, tabNode);
10474 ArrayExt.insert(childNode.sizers, j, Private$6.createSizer(0.5));
10475 ArrayExt.insert(childNode.handles, j, this._createHandle());
10476 tabNode.parent = childNode;
10477 // Synchronize the visibility of the handles.
10478 childNode.syncHandles();
10479 // Finally, add the new child node to the original split node.
10480 ArrayExt.insert(splitNode.children, i, childNode);
10481 childNode.parent = splitNode;
10482 };
10483 /**
10484 * Ensure the root is a split node with the given orientation.
10485 */
10486 DockLayout.prototype._splitRoot = function (orientation) {
10487 // Bail early if the root already meets the requirements.
10488 var oldRoot = this._root;
10489 if (oldRoot instanceof Private$6.SplitLayoutNode) {
10490 if (oldRoot.orientation === orientation) {
10491 return oldRoot;
10492 }
10493 }
10494 // Create a new root node with the specified orientation.
10495 var newRoot = (this._root = new Private$6.SplitLayoutNode(orientation));
10496 // Add the old root to the new root.
10497 if (oldRoot) {
10498 newRoot.children.push(oldRoot);
10499 newRoot.sizers.push(Private$6.createSizer(0));
10500 newRoot.handles.push(this._createHandle());
10501 oldRoot.parent = newRoot;
10502 }
10503 // Return the new root as a convenience.
10504 return newRoot;
10505 };
10506 /**
10507 * Fit the layout to the total size required by the widgets.
10508 */
10509 DockLayout.prototype._fit = function () {
10510 // Set up the computed minimum size.
10511 var minW = 0;
10512 var minH = 0;
10513 // Update the size limits for the layout tree.
10514 if (this._root) {
10515 var limits = this._root.fit(this._spacing, this._items);
10516 minW = limits.minWidth;
10517 minH = limits.minHeight;
10518 }
10519 // Update the box sizing and add it to the computed min size.
10520 var box = (this._box = ElementExt.boxSizing(this.parent.node));
10521 minW += box.horizontalSum;
10522 minH += box.verticalSum;
10523 // Update the parent's min size constraints.
10524 var style = this.parent.node.style;
10525 style.minWidth = minW + "px";
10526 style.minHeight = minH + "px";
10527 // Set the dirty flag to ensure only a single update occurs.
10528 this._dirty = true;
10529 // Notify the ancestor that it should fit immediately. This may
10530 // cause a resize of the parent, fulfilling the required update.
10531 if (this.parent.parent) {
10532 MessageLoop.sendMessage(this.parent.parent, Widget.Msg.FitRequest);
10533 }
10534 // If the dirty flag is still set, the parent was not resized.
10535 // Trigger the required update on the parent widget immediately.
10536 if (this._dirty) {
10537 MessageLoop.sendMessage(this.parent, Widget.Msg.UpdateRequest);
10538 }
10539 };
10540 /**
10541 * Update the layout position and size of the widgets.
10542 *
10543 * The parent offset dimensions should be `-1` if unknown.
10544 */
10545 DockLayout.prototype._update = function (offsetWidth, offsetHeight) {
10546 // Clear the dirty flag to indicate the update occurred.
10547 this._dirty = false;
10548 // Bail early if there is no root layout node.
10549 if (!this._root) {
10550 return;
10551 }
10552 // Measure the parent if the offset dimensions are unknown.
10553 if (offsetWidth < 0) {
10554 offsetWidth = this.parent.node.offsetWidth;
10555 }
10556 if (offsetHeight < 0) {
10557 offsetHeight = this.parent.node.offsetHeight;
10558 }
10559 // Ensure the parent box sizing data is computed.
10560 if (!this._box) {
10561 this._box = ElementExt.boxSizing(this.parent.node);
10562 }
10563 // Compute the actual layout bounds adjusted for border and padding.
10564 var x = this._box.paddingTop;
10565 var y = this._box.paddingLeft;
10566 var width = offsetWidth - this._box.horizontalSum;
10567 var height = offsetHeight - this._box.verticalSum;
10568 // Update the geometry of the layout tree.
10569 this._root.update(x, y, width, height, this._spacing, this._items);
10570 };
10571 /**
10572 * Create a new tab bar for use by the dock layout.
10573 *
10574 * #### Notes
10575 * The tab bar will be attached to the parent if it exists.
10576 */
10577 DockLayout.prototype._createTabBar = function () {
10578 // Create the tab bar using the renderer.
10579 var tabBar = this.renderer.createTabBar(this._document);
10580 // Enforce necessary tab bar behavior.
10581 tabBar.orientation = 'horizontal';
10582 // Reparent and attach the tab bar to the parent if possible.
10583 if (this.parent) {
10584 tabBar.parent = this.parent;
10585 this.attachWidget(tabBar);
10586 }
10587 // Return the initialized tab bar.
10588 return tabBar;
10589 };
10590 /**
10591 * Create a new handle for the dock layout.
10592 *
10593 * #### Notes
10594 * The handle will be attached to the parent if it exists.
10595 */
10596 DockLayout.prototype._createHandle = function () {
10597 // Create the handle using the renderer.
10598 var handle = this.renderer.createHandle();
10599 // Initialize the handle layout behavior.
10600 var style = handle.style;
10601 style.position = 'absolute';
10602 style.top = '0';
10603 style.left = '0';
10604 style.width = '0';
10605 style.height = '0';
10606 // Attach the handle to the parent if it exists.
10607 if (this.parent) {
10608 this.parent.node.appendChild(handle);
10609 }
10610 // Return the initialized handle.
10611 return handle;
10612 };
10613 return DockLayout;
10614}(Layout));
10615/**
10616 * The namespace for the module implementation details.
10617 */
10618var Private$6;
10619(function (Private) {
10620 /**
10621 * A fraction used for sizing root panels; ~= `1 / golden_ratio`.
10622 */
10623 Private.GOLDEN_RATIO = 0.618;
10624 /**
10625 * Create a box sizer with an initial size hint.
10626 */
10627 function createSizer(hint) {
10628 var sizer = new BoxSizer();
10629 sizer.sizeHint = hint;
10630 sizer.size = hint;
10631 return sizer;
10632 }
10633 Private.createSizer = createSizer;
10634 /**
10635 * Normalize an area config object and collect the visited widgets.
10636 */
10637 function normalizeAreaConfig(config, widgetSet) {
10638 var result;
10639 if (config.type === 'tab-area') {
10640 result = normalizeTabAreaConfig(config, widgetSet);
10641 }
10642 else {
10643 result = normalizeSplitAreaConfig(config, widgetSet);
10644 }
10645 return result;
10646 }
10647 Private.normalizeAreaConfig = normalizeAreaConfig;
10648 /**
10649 * Convert a normalized area config into a layout tree.
10650 */
10651 function realizeAreaConfig(config, renderer, document) {
10652 var node;
10653 if (config.type === 'tab-area') {
10654 node = realizeTabAreaConfig(config, renderer, document);
10655 }
10656 else {
10657 node = realizeSplitAreaConfig(config, renderer, document);
10658 }
10659 return node;
10660 }
10661 Private.realizeAreaConfig = realizeAreaConfig;
10662 /**
10663 * A layout node which holds the data for a tabbed area.
10664 */
10665 var TabLayoutNode = /** @class */ (function () {
10666 /**
10667 * Construct a new tab layout node.
10668 *
10669 * @param tabBar - The tab bar to use for the layout node.
10670 */
10671 function TabLayoutNode(tabBar) {
10672 /**
10673 * The parent of the layout node.
10674 */
10675 this.parent = null;
10676 this._top = 0;
10677 this._left = 0;
10678 this._width = 0;
10679 this._height = 0;
10680 var tabSizer = new BoxSizer();
10681 var widgetSizer = new BoxSizer();
10682 tabSizer.stretch = 0;
10683 widgetSizer.stretch = 1;
10684 this.tabBar = tabBar;
10685 this.sizers = [tabSizer, widgetSizer];
10686 }
10687 Object.defineProperty(TabLayoutNode.prototype, "top", {
10688 /**
10689 * The most recent value for the `top` edge of the layout box.
10690 */
10691 get: function () {
10692 return this._top;
10693 },
10694 enumerable: true,
10695 configurable: true
10696 });
10697 Object.defineProperty(TabLayoutNode.prototype, "left", {
10698 /**
10699 * The most recent value for the `left` edge of the layout box.
10700 */
10701 get: function () {
10702 return this._left;
10703 },
10704 enumerable: true,
10705 configurable: true
10706 });
10707 Object.defineProperty(TabLayoutNode.prototype, "width", {
10708 /**
10709 * The most recent value for the `width` of the layout box.
10710 */
10711 get: function () {
10712 return this._width;
10713 },
10714 enumerable: true,
10715 configurable: true
10716 });
10717 Object.defineProperty(TabLayoutNode.prototype, "height", {
10718 /**
10719 * The most recent value for the `height` of the layout box.
10720 */
10721 get: function () {
10722 return this._height;
10723 },
10724 enumerable: true,
10725 configurable: true
10726 });
10727 /**
10728 * Create an iterator for all widgets in the layout tree.
10729 */
10730 TabLayoutNode.prototype.iterAllWidgets = function () {
10731 return chain(once(this.tabBar), this.iterUserWidgets());
10732 };
10733 /**
10734 * Create an iterator for the user widgets in the layout tree.
10735 */
10736 TabLayoutNode.prototype.iterUserWidgets = function () {
10737 return map(this.tabBar.titles, function (title) { return title.owner; });
10738 };
10739 /**
10740 * Create an iterator for the selected widgets in the layout tree.
10741 */
10742 TabLayoutNode.prototype.iterSelectedWidgets = function () {
10743 var title = this.tabBar.currentTitle;
10744 return title ? once(title.owner) : empty();
10745 };
10746 /**
10747 * Create an iterator for the tab bars in the layout tree.
10748 */
10749 TabLayoutNode.prototype.iterTabBars = function () {
10750 return once(this.tabBar);
10751 };
10752 /**
10753 * Create an iterator for the handles in the layout tree.
10754 */
10755 TabLayoutNode.prototype.iterHandles = function () {
10756 return empty();
10757 };
10758 /**
10759 * Find the tab layout node which contains the given widget.
10760 */
10761 TabLayoutNode.prototype.findTabNode = function (widget) {
10762 return this.tabBar.titles.indexOf(widget.title) !== -1 ? this : null;
10763 };
10764 /**
10765 * Find the split layout node which contains the given handle.
10766 */
10767 TabLayoutNode.prototype.findSplitNode = function (handle) {
10768 return null;
10769 };
10770 /**
10771 * Find the first tab layout node in a layout tree.
10772 */
10773 TabLayoutNode.prototype.findFirstTabNode = function () {
10774 return this;
10775 };
10776 /**
10777 * Find the tab layout node which contains the local point.
10778 */
10779 TabLayoutNode.prototype.hitTestTabNodes = function (x, y) {
10780 if (x < this._left || x >= this._left + this._width) {
10781 return null;
10782 }
10783 if (y < this._top || y >= this._top + this._height) {
10784 return null;
10785 }
10786 return this;
10787 };
10788 /**
10789 * Create a configuration object for the layout tree.
10790 */
10791 TabLayoutNode.prototype.createConfig = function () {
10792 var widgets = this.tabBar.titles.map(function (title) { return title.owner; });
10793 var currentIndex = this.tabBar.currentIndex;
10794 return { type: 'tab-area', widgets: widgets, currentIndex: currentIndex };
10795 };
10796 /**
10797 * Recursively hold all of the sizes in the layout tree.
10798 *
10799 * This ignores the sizers of tab layout nodes.
10800 */
10801 TabLayoutNode.prototype.holdAllSizes = function () {
10802 return;
10803 };
10804 /**
10805 * Fit the layout tree.
10806 */
10807 TabLayoutNode.prototype.fit = function (spacing, items) {
10808 // Set up the limit variables.
10809 var minWidth = 0;
10810 var minHeight = 0;
10811 var maxWidth = Infinity;
10812 var maxHeight = Infinity;
10813 // Lookup the tab bar layout item.
10814 var tabBarItem = items.get(this.tabBar);
10815 // Lookup the widget layout item.
10816 var current = this.tabBar.currentTitle;
10817 var widgetItem = current ? items.get(current.owner) : undefined;
10818 // Lookup the tab bar and widget sizers.
10819 var _a = this.sizers, tabBarSizer = _a[0], widgetSizer = _a[1];
10820 // Update the tab bar limits.
10821 if (tabBarItem) {
10822 tabBarItem.fit();
10823 }
10824 // Update the widget limits.
10825 if (widgetItem) {
10826 widgetItem.fit();
10827 }
10828 // Update the results and sizer for the tab bar.
10829 if (tabBarItem && !tabBarItem.isHidden) {
10830 minWidth = Math.max(minWidth, tabBarItem.minWidth);
10831 minHeight += tabBarItem.minHeight;
10832 tabBarSizer.minSize = tabBarItem.minHeight;
10833 tabBarSizer.maxSize = tabBarItem.maxHeight;
10834 }
10835 else {
10836 tabBarSizer.minSize = 0;
10837 tabBarSizer.maxSize = 0;
10838 }
10839 // Update the results and sizer for the current widget.
10840 if (widgetItem && !widgetItem.isHidden) {
10841 minWidth = Math.max(minWidth, widgetItem.minWidth);
10842 minHeight += widgetItem.minHeight;
10843 widgetSizer.minSize = widgetItem.minHeight;
10844 widgetSizer.maxSize = Infinity;
10845 }
10846 else {
10847 widgetSizer.minSize = 0;
10848 widgetSizer.maxSize = Infinity;
10849 }
10850 // Return the computed size limits for the layout node.
10851 return { minWidth: minWidth, minHeight: minHeight, maxWidth: maxWidth, maxHeight: maxHeight };
10852 };
10853 /**
10854 * Update the layout tree.
10855 */
10856 TabLayoutNode.prototype.update = function (left, top, width, height, spacing, items) {
10857 // Update the layout box values.
10858 this._top = top;
10859 this._left = left;
10860 this._width = width;
10861 this._height = height;
10862 // Lookup the tab bar layout item.
10863 var tabBarItem = items.get(this.tabBar);
10864 // Lookup the widget layout item.
10865 var current = this.tabBar.currentTitle;
10866 var widgetItem = current ? items.get(current.owner) : undefined;
10867 // Distribute the layout space to the sizers.
10868 BoxEngine.calc(this.sizers, height);
10869 // Update the tab bar item using the computed size.
10870 if (tabBarItem && !tabBarItem.isHidden) {
10871 var size = this.sizers[0].size;
10872 tabBarItem.update(left, top, width, size);
10873 top += size;
10874 }
10875 // Layout the widget using the computed size.
10876 if (widgetItem && !widgetItem.isHidden) {
10877 var size = this.sizers[1].size;
10878 widgetItem.update(left, top, width, size);
10879 }
10880 };
10881 return TabLayoutNode;
10882 }());
10883 Private.TabLayoutNode = TabLayoutNode;
10884 /**
10885 * A layout node which holds the data for a split area.
10886 */
10887 var SplitLayoutNode = /** @class */ (function () {
10888 /**
10889 * Construct a new split layout node.
10890 *
10891 * @param orientation - The orientation of the node.
10892 */
10893 function SplitLayoutNode(orientation) {
10894 /**
10895 * The parent of the layout node.
10896 */
10897 this.parent = null;
10898 /**
10899 * Whether the sizers have been normalized.
10900 */
10901 this.normalized = false;
10902 /**
10903 * The child nodes for the split node.
10904 */
10905 this.children = [];
10906 /**
10907 * The box sizers for the layout children.
10908 */
10909 this.sizers = [];
10910 /**
10911 * The handles for the layout children.
10912 */
10913 this.handles = [];
10914 this.orientation = orientation;
10915 }
10916 /**
10917 * Create an iterator for all widgets in the layout tree.
10918 */
10919 SplitLayoutNode.prototype.iterAllWidgets = function () {
10920 var children = map(this.children, function (child) { return child.iterAllWidgets(); });
10921 return new ChainIterator(children);
10922 };
10923 /**
10924 * Create an iterator for the user widgets in the layout tree.
10925 */
10926 SplitLayoutNode.prototype.iterUserWidgets = function () {
10927 var children = map(this.children, function (child) { return child.iterUserWidgets(); });
10928 return new ChainIterator(children);
10929 };
10930 /**
10931 * Create an iterator for the selected widgets in the layout tree.
10932 */
10933 SplitLayoutNode.prototype.iterSelectedWidgets = function () {
10934 var children = map(this.children, function (child) { return child.iterSelectedWidgets(); });
10935 return new ChainIterator(children);
10936 };
10937 /**
10938 * Create an iterator for the tab bars in the layout tree.
10939 */
10940 SplitLayoutNode.prototype.iterTabBars = function () {
10941 var children = map(this.children, function (child) { return child.iterTabBars(); });
10942 return new ChainIterator(children);
10943 };
10944 /**
10945 * Create an iterator for the handles in the layout tree.
10946 */
10947 SplitLayoutNode.prototype.iterHandles = function () {
10948 var children = map(this.children, function (child) { return child.iterHandles(); });
10949 return chain(this.handles, new ChainIterator(children));
10950 };
10951 /**
10952 * Find the tab layout node which contains the given widget.
10953 */
10954 SplitLayoutNode.prototype.findTabNode = function (widget) {
10955 for (var i = 0, n = this.children.length; i < n; ++i) {
10956 var result = this.children[i].findTabNode(widget);
10957 if (result) {
10958 return result;
10959 }
10960 }
10961 return null;
10962 };
10963 /**
10964 * Find the split layout node which contains the given handle.
10965 */
10966 SplitLayoutNode.prototype.findSplitNode = function (handle) {
10967 var index = this.handles.indexOf(handle);
10968 if (index !== -1) {
10969 return { index: index, node: this };
10970 }
10971 for (var i = 0, n = this.children.length; i < n; ++i) {
10972 var result = this.children[i].findSplitNode(handle);
10973 if (result) {
10974 return result;
10975 }
10976 }
10977 return null;
10978 };
10979 /**
10980 * Find the first tab layout node in a layout tree.
10981 */
10982 SplitLayoutNode.prototype.findFirstTabNode = function () {
10983 if (this.children.length === 0) {
10984 return null;
10985 }
10986 return this.children[0].findFirstTabNode();
10987 };
10988 /**
10989 * Find the tab layout node which contains the local point.
10990 */
10991 SplitLayoutNode.prototype.hitTestTabNodes = function (x, y) {
10992 for (var i = 0, n = this.children.length; i < n; ++i) {
10993 var result = this.children[i].hitTestTabNodes(x, y);
10994 if (result) {
10995 return result;
10996 }
10997 }
10998 return null;
10999 };
11000 /**
11001 * Create a configuration object for the layout tree.
11002 */
11003 SplitLayoutNode.prototype.createConfig = function () {
11004 var orientation = this.orientation;
11005 var sizes = this.createNormalizedSizes();
11006 var children = this.children.map(function (child) { return child.createConfig(); });
11007 return { type: 'split-area', orientation: orientation, children: children, sizes: sizes };
11008 };
11009 /**
11010 * Sync the visibility and orientation of the handles.
11011 */
11012 SplitLayoutNode.prototype.syncHandles = function () {
11013 var _this = this;
11014 each(this.handles, function (handle, i) {
11015 handle.setAttribute('data-orientation', _this.orientation);
11016 if (i === _this.handles.length - 1) {
11017 handle.classList.add('lm-mod-hidden');
11018 /* <DEPRECATED> */
11019 handle.classList.add('p-mod-hidden');
11020 /* </DEPRECATED> */
11021 }
11022 else {
11023 handle.classList.remove('lm-mod-hidden');
11024 /* <DEPRECATED> */
11025 handle.classList.remove('p-mod-hidden');
11026 /* </DEPRECATED> */
11027 }
11028 });
11029 };
11030 /**
11031 * Hold the current sizes of the box sizers.
11032 *
11033 * This sets the size hint of each sizer to its current size.
11034 */
11035 SplitLayoutNode.prototype.holdSizes = function () {
11036 each(this.sizers, function (sizer) {
11037 sizer.sizeHint = sizer.size;
11038 });
11039 };
11040 /**
11041 * Recursively hold all of the sizes in the layout tree.
11042 *
11043 * This ignores the sizers of tab layout nodes.
11044 */
11045 SplitLayoutNode.prototype.holdAllSizes = function () {
11046 each(this.children, function (child) { return child.holdAllSizes(); });
11047 this.holdSizes();
11048 };
11049 /**
11050 * Normalize the sizes of the split layout node.
11051 */
11052 SplitLayoutNode.prototype.normalizeSizes = function () {
11053 // Bail early if the sizers are empty.
11054 var n = this.sizers.length;
11055 if (n === 0) {
11056 return;
11057 }
11058 // Hold the current sizes of the sizers.
11059 this.holdSizes();
11060 // Compute the sum of the sizes.
11061 var sum = reduce(this.sizers, function (v, sizer) { return v + sizer.sizeHint; }, 0);
11062 // Normalize the sizes based on the sum.
11063 if (sum === 0) {
11064 each(this.sizers, function (sizer) {
11065 sizer.size = sizer.sizeHint = 1 / n;
11066 });
11067 }
11068 else {
11069 each(this.sizers, function (sizer) {
11070 sizer.size = sizer.sizeHint /= sum;
11071 });
11072 }
11073 // Mark the sizes as normalized.
11074 this.normalized = true;
11075 };
11076 /**
11077 * Snap the normalized sizes of the split layout node.
11078 */
11079 SplitLayoutNode.prototype.createNormalizedSizes = function () {
11080 // Bail early if the sizers are empty.
11081 var n = this.sizers.length;
11082 if (n === 0) {
11083 return [];
11084 }
11085 // Grab the current sizes of the sizers.
11086 var sizes = this.sizers.map(function (sizer) { return sizer.size; });
11087 // Compute the sum of the sizes.
11088 var sum = reduce(sizes, function (v, size) { return v + size; }, 0);
11089 // Normalize the sizes based on the sum.
11090 if (sum === 0) {
11091 each(sizes, function (size, i) {
11092 sizes[i] = 1 / n;
11093 });
11094 }
11095 else {
11096 each(sizes, function (size, i) {
11097 sizes[i] = size / sum;
11098 });
11099 }
11100 // Return the normalized sizes.
11101 return sizes;
11102 };
11103 /**
11104 * Fit the layout tree.
11105 */
11106 SplitLayoutNode.prototype.fit = function (spacing, items) {
11107 // Compute the required fixed space.
11108 var horizontal = this.orientation === 'horizontal';
11109 var fixed = Math.max(0, this.children.length - 1) * spacing;
11110 // Set up the limit variables.
11111 var minWidth = horizontal ? fixed : 0;
11112 var minHeight = horizontal ? 0 : fixed;
11113 var maxWidth = Infinity;
11114 var maxHeight = Infinity;
11115 // Fit the children and update the limits.
11116 for (var i = 0, n = this.children.length; i < n; ++i) {
11117 var limits = this.children[i].fit(spacing, items);
11118 if (horizontal) {
11119 minHeight = Math.max(minHeight, limits.minHeight);
11120 minWidth += limits.minWidth;
11121 this.sizers[i].minSize = limits.minWidth;
11122 }
11123 else {
11124 minWidth = Math.max(minWidth, limits.minWidth);
11125 minHeight += limits.minHeight;
11126 this.sizers[i].minSize = limits.minHeight;
11127 }
11128 }
11129 // Return the computed limits for the layout node.
11130 return { minWidth: minWidth, minHeight: minHeight, maxWidth: maxWidth, maxHeight: maxHeight };
11131 };
11132 /**
11133 * Update the layout tree.
11134 */
11135 SplitLayoutNode.prototype.update = function (left, top, width, height, spacing, items) {
11136 // Compute the available layout space.
11137 var horizontal = this.orientation === 'horizontal';
11138 var fixed = Math.max(0, this.children.length - 1) * spacing;
11139 var space = Math.max(0, (horizontal ? width : height) - fixed);
11140 // De-normalize the sizes if needed.
11141 if (this.normalized) {
11142 each(this.sizers, function (sizer) {
11143 sizer.sizeHint *= space;
11144 });
11145 this.normalized = false;
11146 }
11147 // Distribute the layout space to the sizers.
11148 BoxEngine.calc(this.sizers, space);
11149 // Update the geometry of the child nodes and handles.
11150 for (var i = 0, n = this.children.length; i < n; ++i) {
11151 var child = this.children[i];
11152 var size = this.sizers[i].size;
11153 var handleStyle = this.handles[i].style;
11154 if (horizontal) {
11155 child.update(left, top, size, height, spacing, items);
11156 left += size;
11157 handleStyle.top = top + "px";
11158 handleStyle.left = left + "px";
11159 handleStyle.width = spacing + "px";
11160 handleStyle.height = height + "px";
11161 left += spacing;
11162 }
11163 else {
11164 child.update(left, top, width, size, spacing, items);
11165 top += size;
11166 handleStyle.top = top + "px";
11167 handleStyle.left = left + "px";
11168 handleStyle.width = width + "px";
11169 handleStyle.height = spacing + "px";
11170 top += spacing;
11171 }
11172 }
11173 };
11174 return SplitLayoutNode;
11175 }());
11176 Private.SplitLayoutNode = SplitLayoutNode;
11177 function addAria(widget, tabBar) {
11178 widget.node.setAttribute('role', 'tabpanel');
11179 var renderer = tabBar.renderer;
11180 if (renderer instanceof TabBar.Renderer) {
11181 var tabId = renderer.createTabKey({
11182 title: widget.title,
11183 current: false,
11184 zIndex: 0
11185 });
11186 widget.node.setAttribute('aria-labelledby', tabId);
11187 }
11188 }
11189 Private.addAria = addAria;
11190 function removeAria(widget) {
11191 widget.node.removeAttribute('role');
11192 widget.node.removeAttribute('aria-labelledby');
11193 }
11194 Private.removeAria = removeAria;
11195 /**
11196 * Normalize a tab area config and collect the visited widgets.
11197 */
11198 function normalizeTabAreaConfig(config, widgetSet) {
11199 // Bail early if there is no content.
11200 if (config.widgets.length === 0) {
11201 return null;
11202 }
11203 // Setup the filtered widgets array.
11204 var widgets = [];
11205 // Filter the config for unique widgets.
11206 each(config.widgets, function (widget) {
11207 if (!widgetSet.has(widget)) {
11208 widgetSet.add(widget);
11209 widgets.push(widget);
11210 }
11211 });
11212 // Bail if there are no effective widgets.
11213 if (widgets.length === 0) {
11214 return null;
11215 }
11216 // Normalize the current index.
11217 var index = config.currentIndex;
11218 if (index !== -1 && (index < 0 || index >= widgets.length)) {
11219 index = 0;
11220 }
11221 // Return a normalized config object.
11222 return { type: 'tab-area', widgets: widgets, currentIndex: index };
11223 }
11224 /**
11225 * Normalize a split area config and collect the visited widgets.
11226 */
11227 function normalizeSplitAreaConfig(config, widgetSet) {
11228 // Set up the result variables.
11229 var orientation = config.orientation;
11230 var children = [];
11231 var sizes = [];
11232 // Normalize the config children.
11233 for (var i = 0, n = config.children.length; i < n; ++i) {
11234 // Normalize the child config.
11235 var child = normalizeAreaConfig(config.children[i], widgetSet);
11236 // Ignore an empty child.
11237 if (!child) {
11238 continue;
11239 }
11240 // Add the child or hoist its content as appropriate.
11241 if (child.type === 'tab-area' || child.orientation !== orientation) {
11242 children.push(child);
11243 sizes.push(Math.abs(config.sizes[i] || 0));
11244 }
11245 else {
11246 children.push.apply(children, child.children);
11247 sizes.push.apply(sizes, child.sizes);
11248 }
11249 }
11250 // Bail if there are no effective children.
11251 if (children.length === 0) {
11252 return null;
11253 }
11254 // If there is only one effective child, return that child.
11255 if (children.length === 1) {
11256 return children[0];
11257 }
11258 // Return a normalized config object.
11259 return { type: 'split-area', orientation: orientation, children: children, sizes: sizes };
11260 }
11261 /**
11262 * Convert a normalized tab area config into a layout tree.
11263 */
11264 function realizeTabAreaConfig(config, renderer, document) {
11265 // Create the tab bar for the layout node.
11266 var tabBar = renderer.createTabBar(document);
11267 // Hide each widget and add it to the tab bar.
11268 each(config.widgets, function (widget) {
11269 widget.hide();
11270 tabBar.addTab(widget.title);
11271 Private.addAria(widget, tabBar);
11272 });
11273 // Set the current index of the tab bar.
11274 tabBar.currentIndex = config.currentIndex;
11275 // Return the new tab layout node.
11276 return new TabLayoutNode(tabBar);
11277 }
11278 /**
11279 * Convert a normalized split area config into a layout tree.
11280 */
11281 function realizeSplitAreaConfig(config, renderer, document) {
11282 // Create the split layout node.
11283 var node = new SplitLayoutNode(config.orientation);
11284 // Add each child to the layout node.
11285 each(config.children, function (child, i) {
11286 // Create the child data for the layout node.
11287 var childNode = realizeAreaConfig(child, renderer, document);
11288 var sizer = createSizer(config.sizes[i]);
11289 var handle = renderer.createHandle();
11290 // Add the child data to the layout node.
11291 node.children.push(childNode);
11292 node.handles.push(handle);
11293 node.sizers.push(sizer);
11294 // Update the parent for the child node.
11295 childNode.parent = node;
11296 });
11297 // Synchronize the handle state for the layout node.
11298 node.syncHandles();
11299 // Normalize the sizes for the layout node.
11300 node.normalizeSizes();
11301 // Return the new layout node.
11302 return node;
11303 }
11304})(Private$6 || (Private$6 = {}));
11305
11306/**
11307 * A widget which provides a flexible docking area for widgets.
11308 */
11309var DockPanel = /** @class */ (function (_super) {
11310 __extends(DockPanel, _super);
11311 /**
11312 * Construct a new dock panel.
11313 *
11314 * @param options - The options for initializing the panel.
11315 */
11316 function DockPanel(options) {
11317 if (options === void 0) { options = {}; }
11318 var _this = _super.call(this) || this;
11319 _this._drag = null;
11320 _this._tabsMovable = true;
11321 _this._tabsConstrained = false;
11322 _this._addButtonEnabled = false;
11323 _this._pressData = null;
11324 _this._layoutModified = new Signal(_this);
11325 _this._addRequested = new Signal(_this);
11326 _this.addClass('lm-DockPanel');
11327 /* <DEPRECATED> */
11328 _this.addClass('p-DockPanel');
11329 /* </DEPRECATED> */
11330 _this._document = options.document || document;
11331 _this._mode = options.mode || 'multiple-document';
11332 _this._renderer = options.renderer || DockPanel.defaultRenderer;
11333 _this._edges = options.edges || Private$5.DEFAULT_EDGES;
11334 if (options.tabsMovable !== undefined) {
11335 _this._tabsMovable = options.tabsMovable;
11336 }
11337 if (options.tabsConstrained !== undefined) {
11338 _this._tabsConstrained = options.tabsConstrained;
11339 }
11340 if (options.addButtonEnabled !== undefined) {
11341 _this._addButtonEnabled = options.addButtonEnabled;
11342 }
11343 // Toggle the CSS mode attribute.
11344 _this.dataset['mode'] = _this._mode;
11345 // Create the delegate renderer for the layout.
11346 var renderer = {
11347 createTabBar: function () { return _this._createTabBar(); },
11348 createHandle: function () { return _this._createHandle(); }
11349 };
11350 // Set up the dock layout for the panel.
11351 _this.layout = new DockLayout({
11352 document: _this._document,
11353 renderer: renderer,
11354 spacing: options.spacing,
11355 hiddenMode: options.hiddenMode
11356 });
11357 // Set up the overlay drop indicator.
11358 _this.overlay = options.overlay || new DockPanel.Overlay();
11359 _this.node.appendChild(_this.overlay.node);
11360 return _this;
11361 }
11362 /**
11363 * Dispose of the resources held by the panel.
11364 */
11365 DockPanel.prototype.dispose = function () {
11366 // Ensure the mouse is released.
11367 this._releaseMouse();
11368 // Hide the overlay.
11369 this.overlay.hide(0);
11370 // Cancel a drag if one is in progress.
11371 if (this._drag) {
11372 this._drag.dispose();
11373 }
11374 // Dispose of the base class.
11375 _super.prototype.dispose.call(this);
11376 };
11377 Object.defineProperty(DockPanel.prototype, "hiddenMode", {
11378 /**
11379 * The method for hiding widgets.
11380 */
11381 get: function () {
11382 return this.layout.hiddenMode;
11383 },
11384 /**
11385 * Set the method for hiding widgets.
11386 */
11387 set: function (v) {
11388 this.layout.hiddenMode = v;
11389 },
11390 enumerable: true,
11391 configurable: true
11392 });
11393 Object.defineProperty(DockPanel.prototype, "layoutModified", {
11394 /**
11395 * A signal emitted when the layout configuration is modified.
11396 *
11397 * #### Notes
11398 * This signal is emitted whenever the current layout configuration
11399 * may have changed.
11400 *
11401 * This signal is emitted asynchronously in a collapsed fashion, so
11402 * that multiple synchronous modifications results in only a single
11403 * emit of the signal.
11404 */
11405 get: function () {
11406 return this._layoutModified;
11407 },
11408 enumerable: true,
11409 configurable: true
11410 });
11411 Object.defineProperty(DockPanel.prototype, "addRequested", {
11412 /**
11413 * A signal emitted when the add button on a tab bar is clicked.
11414 *
11415 */
11416 get: function () {
11417 return this._addRequested;
11418 },
11419 enumerable: true,
11420 configurable: true
11421 });
11422 Object.defineProperty(DockPanel.prototype, "renderer", {
11423 /**
11424 * The renderer used by the dock panel.
11425 */
11426 get: function () {
11427 return this.layout.renderer;
11428 },
11429 enumerable: true,
11430 configurable: true
11431 });
11432 Object.defineProperty(DockPanel.prototype, "spacing", {
11433 /**
11434 * Get the spacing between the widgets.
11435 */
11436 get: function () {
11437 return this.layout.spacing;
11438 },
11439 /**
11440 * Set the spacing between the widgets.
11441 */
11442 set: function (value) {
11443 this.layout.spacing = value;
11444 },
11445 enumerable: true,
11446 configurable: true
11447 });
11448 Object.defineProperty(DockPanel.prototype, "mode", {
11449 /**
11450 * Get the mode for the dock panel.
11451 */
11452 get: function () {
11453 return this._mode;
11454 },
11455 /**
11456 * Set the mode for the dock panel.
11457 *
11458 * #### Notes
11459 * Changing the mode is a destructive operation with respect to the
11460 * panel's layout configuration. If layout state must be preserved,
11461 * save the current layout config before changing the mode.
11462 */
11463 set: function (value) {
11464 // Bail early if the mode does not change.
11465 if (this._mode === value) {
11466 return;
11467 }
11468 // Update the internal mode.
11469 this._mode = value;
11470 // Toggle the CSS mode attribute.
11471 this.dataset['mode'] = value;
11472 // Get the layout for the panel.
11473 var layout = this.layout;
11474 // Configure the layout for the specified mode.
11475 switch (value) {
11476 case 'multiple-document':
11477 each(layout.tabBars(), function (tabBar) {
11478 tabBar.show();
11479 });
11480 break;
11481 case 'single-document':
11482 layout.restoreLayout(Private$5.createSingleDocumentConfig(this));
11483 break;
11484 default:
11485 throw 'unreachable';
11486 }
11487 // Schedule an emit of the layout modified signal.
11488 MessageLoop.postMessage(this, Private$5.LayoutModified);
11489 },
11490 enumerable: true,
11491 configurable: true
11492 });
11493 Object.defineProperty(DockPanel.prototype, "tabsMovable", {
11494 /**
11495 * Whether the tabs can be dragged / moved at runtime.
11496 */
11497 get: function () {
11498 return this._tabsMovable;
11499 },
11500 /**
11501 * Enable / Disable draggable / movable tabs.
11502 */
11503 set: function (value) {
11504 this._tabsMovable = value;
11505 each(this.tabBars(), function (tabbar) {
11506 tabbar.tabsMovable = value;
11507 });
11508 },
11509 enumerable: true,
11510 configurable: true
11511 });
11512 Object.defineProperty(DockPanel.prototype, "tabsConstrained", {
11513 /**
11514 * Whether the tabs are constrained to their source dock panel
11515 */
11516 get: function () {
11517 return this._tabsConstrained;
11518 },
11519 /**
11520 * Constrain/Allow tabs to be dragged outside of this dock panel
11521 */
11522 set: function (value) {
11523 this._tabsConstrained = value;
11524 },
11525 enumerable: true,
11526 configurable: true
11527 });
11528 Object.defineProperty(DockPanel.prototype, "addButtonEnabled", {
11529 /**
11530 * Whether the add buttons for each tab bar are enabled.
11531 */
11532 get: function () {
11533 return this._addButtonEnabled;
11534 },
11535 /**
11536 * Set whether the add buttons for each tab bar are enabled.
11537 */
11538 set: function (value) {
11539 this._addButtonEnabled = value;
11540 each(this.tabBars(), function (tabbar) {
11541 tabbar.addButtonEnabled = value;
11542 });
11543 },
11544 enumerable: true,
11545 configurable: true
11546 });
11547 Object.defineProperty(DockPanel.prototype, "isEmpty", {
11548 /**
11549 * Whether the dock panel is empty.
11550 */
11551 get: function () {
11552 return this.layout.isEmpty;
11553 },
11554 enumerable: true,
11555 configurable: true
11556 });
11557 /**
11558 * Create an iterator over the user widgets in the panel.
11559 *
11560 * @returns A new iterator over the user widgets in the panel.
11561 *
11562 * #### Notes
11563 * This iterator does not include the generated tab bars.
11564 */
11565 DockPanel.prototype.widgets = function () {
11566 return this.layout.widgets();
11567 };
11568 /**
11569 * Create an iterator over the selected widgets in the panel.
11570 *
11571 * @returns A new iterator over the selected user widgets.
11572 *
11573 * #### Notes
11574 * This iterator yields the widgets corresponding to the current tab
11575 * of each tab bar in the panel.
11576 */
11577 DockPanel.prototype.selectedWidgets = function () {
11578 return this.layout.selectedWidgets();
11579 };
11580 /**
11581 * Create an iterator over the tab bars in the panel.
11582 *
11583 * @returns A new iterator over the tab bars in the panel.
11584 *
11585 * #### Notes
11586 * This iterator does not include the user widgets.
11587 */
11588 DockPanel.prototype.tabBars = function () {
11589 return this.layout.tabBars();
11590 };
11591 /**
11592 * Create an iterator over the handles in the panel.
11593 *
11594 * @returns A new iterator over the handles in the panel.
11595 */
11596 DockPanel.prototype.handles = function () {
11597 return this.layout.handles();
11598 };
11599 /**
11600 * Select a specific widget in the dock panel.
11601 *
11602 * @param widget - The widget of interest.
11603 *
11604 * #### Notes
11605 * This will make the widget the current widget in its tab area.
11606 */
11607 DockPanel.prototype.selectWidget = function (widget) {
11608 // Find the tab bar which contains the widget.
11609 var tabBar = find(this.tabBars(), function (bar) {
11610 return bar.titles.indexOf(widget.title) !== -1;
11611 });
11612 // Throw an error if no tab bar is found.
11613 if (!tabBar) {
11614 throw new Error('Widget is not contained in the dock panel.');
11615 }
11616 // Ensure the widget is the current widget.
11617 tabBar.currentTitle = widget.title;
11618 };
11619 /**
11620 * Activate a specified widget in the dock panel.
11621 *
11622 * @param widget - The widget of interest.
11623 *
11624 * #### Notes
11625 * This will select and activate the given widget.
11626 */
11627 DockPanel.prototype.activateWidget = function (widget) {
11628 this.selectWidget(widget);
11629 widget.activate();
11630 };
11631 /**
11632 * Save the current layout configuration of the dock panel.
11633 *
11634 * @returns A new config object for the current layout state.
11635 *
11636 * #### Notes
11637 * The return value can be provided to the `restoreLayout` method
11638 * in order to restore the layout to its current configuration.
11639 */
11640 DockPanel.prototype.saveLayout = function () {
11641 return this.layout.saveLayout();
11642 };
11643 /**
11644 * Restore the layout to a previously saved configuration.
11645 *
11646 * @param config - The layout configuration to restore.
11647 *
11648 * #### Notes
11649 * Widgets which currently belong to the layout but which are not
11650 * contained in the config will be unparented.
11651 *
11652 * The dock panel automatically reverts to `'multiple-document'`
11653 * mode when a layout config is restored.
11654 */
11655 DockPanel.prototype.restoreLayout = function (config) {
11656 // Reset the mode.
11657 this._mode = 'multiple-document';
11658 // Restore the layout.
11659 this.layout.restoreLayout(config);
11660 // Flush the message loop on IE and Edge to prevent flicker.
11661 if (Platform.IS_EDGE || Platform.IS_IE) {
11662 MessageLoop.flush();
11663 }
11664 // Schedule an emit of the layout modified signal.
11665 MessageLoop.postMessage(this, Private$5.LayoutModified);
11666 };
11667 /**
11668 * Add a widget to the dock panel.
11669 *
11670 * @param widget - The widget to add to the dock panel.
11671 *
11672 * @param options - The additional options for adding the widget.
11673 *
11674 * #### Notes
11675 * If the panel is in single document mode, the options are ignored
11676 * and the widget is always added as tab in the hidden tab bar.
11677 */
11678 DockPanel.prototype.addWidget = function (widget, options) {
11679 if (options === void 0) { options = {}; }
11680 // Add the widget to the layout.
11681 if (this._mode === 'single-document') {
11682 this.layout.addWidget(widget);
11683 }
11684 else {
11685 this.layout.addWidget(widget, options);
11686 }
11687 // Schedule an emit of the layout modified signal.
11688 MessageLoop.postMessage(this, Private$5.LayoutModified);
11689 };
11690 /**
11691 * Process a message sent to the widget.
11692 *
11693 * @param msg - The message sent to the widget.
11694 */
11695 DockPanel.prototype.processMessage = function (msg) {
11696 if (msg.type === 'layout-modified') {
11697 this._layoutModified.emit(undefined);
11698 }
11699 else {
11700 _super.prototype.processMessage.call(this, msg);
11701 }
11702 };
11703 /**
11704 * Handle the DOM events for the dock panel.
11705 *
11706 * @param event - The DOM event sent to the panel.
11707 *
11708 * #### Notes
11709 * This method implements the DOM `EventListener` interface and is
11710 * called in response to events on the panel's DOM node. It should
11711 * not be called directly by user code.
11712 */
11713 DockPanel.prototype.handleEvent = function (event) {
11714 switch (event.type) {
11715 case 'lm-dragenter':
11716 this._evtDragEnter(event);
11717 break;
11718 case 'lm-dragleave':
11719 this._evtDragLeave(event);
11720 break;
11721 case 'lm-dragover':
11722 this._evtDragOver(event);
11723 break;
11724 case 'lm-drop':
11725 this._evtDrop(event);
11726 break;
11727 case 'mousedown': // <DEPRECATED>
11728 this._evtMouseDown(event);
11729 break;
11730 case 'mousemove': // <DEPRECATED>
11731 this._evtMouseMove(event);
11732 break;
11733 case 'mouseup': // <DEPRECATED>
11734 this._evtMouseUp(event);
11735 break;
11736 case 'pointerdown':
11737 this._evtMouseDown(event);
11738 break;
11739 case 'pointermove':
11740 this._evtMouseMove(event);
11741 break;
11742 case 'pointerup':
11743 this._evtMouseUp(event);
11744 break;
11745 case 'keydown':
11746 this._evtKeyDown(event);
11747 break;
11748 case 'contextmenu':
11749 event.preventDefault();
11750 event.stopPropagation();
11751 break;
11752 }
11753 };
11754 /**
11755 * A message handler invoked on a `'before-attach'` message.
11756 */
11757 DockPanel.prototype.onBeforeAttach = function (msg) {
11758 this.node.addEventListener('lm-dragenter', this);
11759 this.node.addEventListener('lm-dragleave', this);
11760 this.node.addEventListener('lm-dragover', this);
11761 this.node.addEventListener('lm-drop', this);
11762 this.node.addEventListener('mousedown', this); // <DEPRECATED>
11763 this.node.addEventListener('pointerdown', this);
11764 };
11765 /**
11766 * A message handler invoked on an `'after-detach'` message.
11767 */
11768 DockPanel.prototype.onAfterDetach = function (msg) {
11769 this.node.removeEventListener('lm-dragenter', this);
11770 this.node.removeEventListener('lm-dragleave', this);
11771 this.node.removeEventListener('lm-dragover', this);
11772 this.node.removeEventListener('lm-drop', this);
11773 this.node.removeEventListener('mousedown', this); // <DEPRECATED>
11774 this.node.removeEventListener('pointerdown', this);
11775 this._releaseMouse();
11776 };
11777 /**
11778 * A message handler invoked on a `'child-added'` message.
11779 */
11780 DockPanel.prototype.onChildAdded = function (msg) {
11781 // Ignore the generated tab bars.
11782 if (Private$5.isGeneratedTabBarProperty.get(msg.child)) {
11783 return;
11784 }
11785 // Add the widget class to the child.
11786 msg.child.addClass('lm-DockPanel-widget');
11787 /* <DEPRECATED> */
11788 msg.child.addClass('p-DockPanel-widget');
11789 /* </DEPRECATED> */
11790 };
11791 /**
11792 * A message handler invoked on a `'child-removed'` message.
11793 */
11794 DockPanel.prototype.onChildRemoved = function (msg) {
11795 // Ignore the generated tab bars.
11796 if (Private$5.isGeneratedTabBarProperty.get(msg.child)) {
11797 return;
11798 }
11799 // Remove the widget class from the child.
11800 msg.child.removeClass('lm-DockPanel-widget');
11801 /* <DEPRECATED> */
11802 msg.child.removeClass('p-DockPanel-widget');
11803 /* </DEPRECATED> */
11804 // Schedule an emit of the layout modified signal.
11805 MessageLoop.postMessage(this, Private$5.LayoutModified);
11806 };
11807 /**
11808 * Handle the `'lm-dragenter'` event for the dock panel.
11809 */
11810 DockPanel.prototype._evtDragEnter = function (event) {
11811 // If the factory mime type is present, mark the event as
11812 // handled in order to get the rest of the drag events.
11813 if (event.mimeData.hasData('application/vnd.lumino.widget-factory')) {
11814 event.preventDefault();
11815 event.stopPropagation();
11816 }
11817 };
11818 /**
11819 * Handle the `'lm-dragleave'` event for the dock panel.
11820 */
11821 DockPanel.prototype._evtDragLeave = function (event) {
11822 // Mark the event as handled.
11823 event.preventDefault();
11824 event.stopPropagation();
11825 // The new target might be a descendant, so we might still handle the drop.
11826 // Hide asynchronously so that if a lm-dragover event bubbles up to us, the
11827 // hide is cancelled by the lm-dragover handler's show overlay logic.
11828 this.overlay.hide(1);
11829 };
11830 /**
11831 * Handle the `'lm-dragover'` event for the dock panel.
11832 */
11833 DockPanel.prototype._evtDragOver = function (event) {
11834 // Mark the event as handled.
11835 event.preventDefault();
11836 event.stopPropagation();
11837 // Show the drop indicator overlay and update the drop
11838 // action based on the drop target zone under the mouse.
11839 if ((this._tabsConstrained && event.source !== this) ||
11840 this._showOverlay(event.clientX, event.clientY) === 'invalid') {
11841 event.dropAction = 'none';
11842 }
11843 else {
11844 event.dropAction = event.proposedAction;
11845 }
11846 };
11847 /**
11848 * Handle the `'lm-drop'` event for the dock panel.
11849 */
11850 DockPanel.prototype._evtDrop = function (event) {
11851 // Mark the event as handled.
11852 event.preventDefault();
11853 event.stopPropagation();
11854 // Hide the drop indicator overlay.
11855 this.overlay.hide(0);
11856 // Bail if the proposed action is to do nothing.
11857 if (event.proposedAction === 'none') {
11858 event.dropAction = 'none';
11859 return;
11860 }
11861 // Find the drop target under the mouse.
11862 var clientX = event.clientX, clientY = event.clientY;
11863 var _a = Private$5.findDropTarget(this, clientX, clientY, this._edges), zone = _a.zone, target = _a.target;
11864 // Bail if the drop zone is invalid.
11865 if (zone === 'invalid') {
11866 event.dropAction = 'none';
11867 return;
11868 }
11869 // Bail if the factory mime type has invalid data.
11870 var mimeData = event.mimeData;
11871 var factory = mimeData.getData('application/vnd.lumino.widget-factory');
11872 if (typeof factory !== 'function') {
11873 event.dropAction = 'none';
11874 return;
11875 }
11876 // Bail if the factory does not produce a widget.
11877 var widget = factory();
11878 if (!(widget instanceof Widget)) {
11879 event.dropAction = 'none';
11880 return;
11881 }
11882 // Bail if the widget is an ancestor of the dock panel.
11883 if (widget.contains(this)) {
11884 event.dropAction = 'none';
11885 return;
11886 }
11887 // Find the reference widget for the drop target.
11888 var ref = target ? Private$5.getDropRef(target.tabBar) : null;
11889 // Add the widget according to the indicated drop zone.
11890 switch (zone) {
11891 case 'root-all':
11892 this.addWidget(widget);
11893 break;
11894 case 'root-top':
11895 this.addWidget(widget, { mode: 'split-top' });
11896 break;
11897 case 'root-left':
11898 this.addWidget(widget, { mode: 'split-left' });
11899 break;
11900 case 'root-right':
11901 this.addWidget(widget, { mode: 'split-right' });
11902 break;
11903 case 'root-bottom':
11904 this.addWidget(widget, { mode: 'split-bottom' });
11905 break;
11906 case 'widget-all':
11907 this.addWidget(widget, { mode: 'tab-after', ref: ref });
11908 break;
11909 case 'widget-top':
11910 this.addWidget(widget, { mode: 'split-top', ref: ref });
11911 break;
11912 case 'widget-left':
11913 this.addWidget(widget, { mode: 'split-left', ref: ref });
11914 break;
11915 case 'widget-right':
11916 this.addWidget(widget, { mode: 'split-right', ref: ref });
11917 break;
11918 case 'widget-bottom':
11919 this.addWidget(widget, { mode: 'split-bottom', ref: ref });
11920 break;
11921 case 'widget-tab':
11922 this.addWidget(widget, { mode: 'tab-after', ref: ref });
11923 break;
11924 default:
11925 throw 'unreachable';
11926 }
11927 // Accept the proposed drop action.
11928 event.dropAction = event.proposedAction;
11929 // Activate the dropped widget.
11930 this.activateWidget(widget);
11931 };
11932 /**
11933 * Handle the `'keydown'` event for the dock panel.
11934 */
11935 DockPanel.prototype._evtKeyDown = function (event) {
11936 // Stop input events during drag.
11937 event.preventDefault();
11938 event.stopPropagation();
11939 // Release the mouse if `Escape` is pressed.
11940 if (event.keyCode === 27) {
11941 // Finalize the mouse release.
11942 this._releaseMouse();
11943 // Schedule an emit of the layout modified signal.
11944 MessageLoop.postMessage(this, Private$5.LayoutModified);
11945 }
11946 };
11947 /**
11948 * Handle the `'mousedown'` event for the dock panel.
11949 */
11950 DockPanel.prototype._evtMouseDown = function (event) {
11951 // Do nothing if the left mouse button is not pressed.
11952 if (event.button !== 0) {
11953 return;
11954 }
11955 // Find the handle which contains the mouse target, if any.
11956 var layout = this.layout;
11957 var target = event.target;
11958 var handle = find(layout.handles(), function (handle) { return handle.contains(target); });
11959 if (!handle) {
11960 return;
11961 }
11962 // Stop the event when a handle is pressed.
11963 event.preventDefault();
11964 event.stopPropagation();
11965 // Add the extra document listeners.
11966 this._document.addEventListener('keydown', this, true);
11967 this._document.addEventListener('mouseup', this, true); // <DEPRECATED>
11968 this._document.addEventListener('mousemove', this, true); // <DEPRECATED>
11969 this._document.addEventListener('pointerup', this, true);
11970 this._document.addEventListener('pointermove', this, true);
11971 this._document.addEventListener('contextmenu', this, true);
11972 // Compute the offset deltas for the handle press.
11973 var rect = handle.getBoundingClientRect();
11974 var deltaX = event.clientX - rect.left;
11975 var deltaY = event.clientY - rect.top;
11976 // Override the cursor and store the press data.
11977 var style = window.getComputedStyle(handle);
11978 var override = Drag.overrideCursor(style.cursor, this._document);
11979 this._pressData = { handle: handle, deltaX: deltaX, deltaY: deltaY, override: override };
11980 };
11981 /**
11982 * Handle the `'mousemove'` event for the dock panel.
11983 */
11984 DockPanel.prototype._evtMouseMove = function (event) {
11985 // Bail early if no drag is in progress.
11986 if (!this._pressData) {
11987 return;
11988 }
11989 // Stop the event when dragging a handle.
11990 event.preventDefault();
11991 event.stopPropagation();
11992 // Compute the desired offset position for the handle.
11993 var rect = this.node.getBoundingClientRect();
11994 var xPos = event.clientX - rect.left - this._pressData.deltaX;
11995 var yPos = event.clientY - rect.top - this._pressData.deltaY;
11996 // Set the handle as close to the desired position as possible.
11997 var layout = this.layout;
11998 layout.moveHandle(this._pressData.handle, xPos, yPos);
11999 };
12000 /**
12001 * Handle the `'mouseup'` event for the dock panel.
12002 */
12003 DockPanel.prototype._evtMouseUp = function (event) {
12004 // Do nothing if the left mouse button is not released.
12005 if (event.button !== 0) {
12006 return;
12007 }
12008 // Stop the event when releasing a handle.
12009 event.preventDefault();
12010 event.stopPropagation();
12011 // Finalize the mouse release.
12012 this._releaseMouse();
12013 // Schedule an emit of the layout modified signal.
12014 MessageLoop.postMessage(this, Private$5.LayoutModified);
12015 };
12016 /**
12017 * Release the mouse grab for the dock panel.
12018 */
12019 DockPanel.prototype._releaseMouse = function () {
12020 // Bail early if no drag is in progress.
12021 if (!this._pressData) {
12022 return;
12023 }
12024 // Clear the override cursor.
12025 this._pressData.override.dispose();
12026 this._pressData = null;
12027 // Remove the extra document listeners.
12028 this._document.removeEventListener('keydown', this, true);
12029 this._document.removeEventListener('mouseup', this, true); // <DEPRECATED>
12030 this._document.removeEventListener('mousemove', this, true); // <DEPRECATED>
12031 this._document.removeEventListener('pointerup', this, true);
12032 this._document.removeEventListener('pointermove', this, true);
12033 this._document.removeEventListener('contextmenu', this, true);
12034 };
12035 /**
12036 * Show the overlay indicator at the given client position.
12037 *
12038 * Returns the drop zone at the specified client position.
12039 *
12040 * #### Notes
12041 * If the position is not over a valid zone, the overlay is hidden.
12042 */
12043 DockPanel.prototype._showOverlay = function (clientX, clientY) {
12044 // Find the dock target for the given client position.
12045 var _a = Private$5.findDropTarget(this, clientX, clientY, this._edges), zone = _a.zone, target = _a.target;
12046 // If the drop zone is invalid, hide the overlay and bail.
12047 if (zone === 'invalid') {
12048 this.overlay.hide(100);
12049 return zone;
12050 }
12051 // Setup the variables needed to compute the overlay geometry.
12052 var top;
12053 var left;
12054 var right;
12055 var bottom;
12056 var box = ElementExt.boxSizing(this.node); // TODO cache this?
12057 var rect = this.node.getBoundingClientRect();
12058 // Compute the overlay geometry based on the dock zone.
12059 switch (zone) {
12060 case 'root-all':
12061 top = box.paddingTop;
12062 left = box.paddingLeft;
12063 right = box.paddingRight;
12064 bottom = box.paddingBottom;
12065 break;
12066 case 'root-top':
12067 top = box.paddingTop;
12068 left = box.paddingLeft;
12069 right = box.paddingRight;
12070 bottom = rect.height * Private$5.GOLDEN_RATIO;
12071 break;
12072 case 'root-left':
12073 top = box.paddingTop;
12074 left = box.paddingLeft;
12075 right = rect.width * Private$5.GOLDEN_RATIO;
12076 bottom = box.paddingBottom;
12077 break;
12078 case 'root-right':
12079 top = box.paddingTop;
12080 left = rect.width * Private$5.GOLDEN_RATIO;
12081 right = box.paddingRight;
12082 bottom = box.paddingBottom;
12083 break;
12084 case 'root-bottom':
12085 top = rect.height * Private$5.GOLDEN_RATIO;
12086 left = box.paddingLeft;
12087 right = box.paddingRight;
12088 bottom = box.paddingBottom;
12089 break;
12090 case 'widget-all':
12091 top = target.top;
12092 left = target.left;
12093 right = target.right;
12094 bottom = target.bottom;
12095 break;
12096 case 'widget-top':
12097 top = target.top;
12098 left = target.left;
12099 right = target.right;
12100 bottom = target.bottom + target.height / 2;
12101 break;
12102 case 'widget-left':
12103 top = target.top;
12104 left = target.left;
12105 right = target.right + target.width / 2;
12106 bottom = target.bottom;
12107 break;
12108 case 'widget-right':
12109 top = target.top;
12110 left = target.left + target.width / 2;
12111 right = target.right;
12112 bottom = target.bottom;
12113 break;
12114 case 'widget-bottom':
12115 top = target.top + target.height / 2;
12116 left = target.left;
12117 right = target.right;
12118 bottom = target.bottom;
12119 break;
12120 case 'widget-tab':
12121 var tabHeight = target.tabBar.node.getBoundingClientRect().height;
12122 top = target.top;
12123 left = target.left;
12124 right = target.right;
12125 bottom = target.bottom + target.height - tabHeight;
12126 break;
12127 default:
12128 throw 'unreachable';
12129 }
12130 // Show the overlay with the computed geometry.
12131 this.overlay.show({ top: top, left: left, right: right, bottom: bottom });
12132 // Finally, return the computed drop zone.
12133 return zone;
12134 };
12135 /**
12136 * Create a new tab bar for use by the panel.
12137 */
12138 DockPanel.prototype._createTabBar = function () {
12139 // Create the tab bar.
12140 var tabBar = this._renderer.createTabBar(this._document);
12141 // Set the generated tab bar property for the tab bar.
12142 Private$5.isGeneratedTabBarProperty.set(tabBar, true);
12143 // Hide the tab bar when in single document mode.
12144 if (this._mode === 'single-document') {
12145 tabBar.hide();
12146 }
12147 // Enforce necessary tab bar behavior.
12148 // TODO do we really want to enforce *all* of these?
12149 tabBar.tabsMovable = this._tabsMovable;
12150 tabBar.allowDeselect = false;
12151 tabBar.addButtonEnabled = this._addButtonEnabled;
12152 tabBar.removeBehavior = 'select-previous-tab';
12153 tabBar.insertBehavior = 'select-tab-if-needed';
12154 // Connect the signal handlers for the tab bar.
12155 tabBar.tabMoved.connect(this._onTabMoved, this);
12156 tabBar.currentChanged.connect(this._onCurrentChanged, this);
12157 tabBar.tabCloseRequested.connect(this._onTabCloseRequested, this);
12158 tabBar.tabDetachRequested.connect(this._onTabDetachRequested, this);
12159 tabBar.tabActivateRequested.connect(this._onTabActivateRequested, this);
12160 tabBar.addRequested.connect(this._onTabAddRequested, this);
12161 // Return the initialized tab bar.
12162 return tabBar;
12163 };
12164 /**
12165 * Create a new handle for use by the panel.
12166 */
12167 DockPanel.prototype._createHandle = function () {
12168 return this._renderer.createHandle();
12169 };
12170 /**
12171 * Handle the `tabMoved` signal from a tab bar.
12172 */
12173 DockPanel.prototype._onTabMoved = function () {
12174 MessageLoop.postMessage(this, Private$5.LayoutModified);
12175 };
12176 /**
12177 * Handle the `currentChanged` signal from a tab bar.
12178 */
12179 DockPanel.prototype._onCurrentChanged = function (sender, args) {
12180 // Extract the previous and current title from the args.
12181 var previousTitle = args.previousTitle, currentTitle = args.currentTitle;
12182 // Hide the previous widget.
12183 if (previousTitle) {
12184 previousTitle.owner.hide();
12185 }
12186 // Show the current widget.
12187 if (currentTitle) {
12188 currentTitle.owner.show();
12189 }
12190 // Flush the message loop on IE and Edge to prevent flicker.
12191 if (Platform.IS_EDGE || Platform.IS_IE) {
12192 MessageLoop.flush();
12193 }
12194 // Schedule an emit of the layout modified signal.
12195 MessageLoop.postMessage(this, Private$5.LayoutModified);
12196 };
12197 /**
12198 * Handle the `addRequested` signal from a tab bar.
12199 */
12200 DockPanel.prototype._onTabAddRequested = function (sender) {
12201 this._addRequested.emit(sender);
12202 };
12203 /**
12204 * Handle the `tabActivateRequested` signal from a tab bar.
12205 */
12206 DockPanel.prototype._onTabActivateRequested = function (sender, args) {
12207 args.title.owner.activate();
12208 };
12209 /**
12210 * Handle the `tabCloseRequested` signal from a tab bar.
12211 */
12212 DockPanel.prototype._onTabCloseRequested = function (sender, args) {
12213 args.title.owner.close();
12214 };
12215 /**
12216 * Handle the `tabDetachRequested` signal from a tab bar.
12217 */
12218 DockPanel.prototype._onTabDetachRequested = function (sender, args) {
12219 var _this = this;
12220 // Do nothing if a drag is already in progress.
12221 if (this._drag) {
12222 return;
12223 }
12224 // Release the tab bar's hold on the mouse.
12225 sender.releaseMouse();
12226 // Extract the data from the args.
12227 var title = args.title, tab = args.tab, clientX = args.clientX, clientY = args.clientY;
12228 // Setup the mime data for the drag operation.
12229 var mimeData = new MimeData();
12230 var factory = function () { return title.owner; };
12231 mimeData.setData('application/vnd.lumino.widget-factory', factory);
12232 // Create the drag image for the drag operation.
12233 var dragImage = tab.cloneNode(true);
12234 // Create the drag object to manage the drag-drop operation.
12235 this._drag = new Drag({
12236 document: this._document,
12237 mimeData: mimeData,
12238 dragImage: dragImage,
12239 proposedAction: 'move',
12240 supportedActions: 'move',
12241 source: this
12242 });
12243 // Hide the tab node in the original tab.
12244 tab.classList.add('lm-mod-hidden');
12245 /* <DEPRECATED> */
12246 tab.classList.add('p-mod-hidden'); // Create the cleanup callback.
12247 /* </DEPRECATED> */ var cleanup = function () {
12248 _this._drag = null;
12249 tab.classList.remove('lm-mod-hidden');
12250 /* <DEPRECATED> */
12251 tab.classList.remove('p-mod-hidden');
12252 /* </DEPRECATED> */
12253 };
12254 // Start the drag operation and cleanup when done.
12255 this._drag.start(clientX, clientY).then(cleanup);
12256 };
12257 return DockPanel;
12258}(Widget));
12259/**
12260 * The namespace for the `DockPanel` class statics.
12261 */
12262(function (DockPanel) {
12263 /**
12264 * A concrete implementation of `IOverlay`.
12265 *
12266 * This is the default overlay implementation for a dock panel.
12267 */
12268 var Overlay = /** @class */ (function () {
12269 /**
12270 * Construct a new overlay.
12271 */
12272 function Overlay() {
12273 this._timer = -1;
12274 this._hidden = true;
12275 this.node = document.createElement('div');
12276 this.node.classList.add('lm-DockPanel-overlay');
12277 this.node.classList.add('lm-mod-hidden');
12278 /* <DEPRECATED> */
12279 this.node.classList.add('p-DockPanel-overlay');
12280 this.node.classList.add('p-mod-hidden');
12281 /* </DEPRECATED> */ this.node.style.position = 'absolute';
12282 }
12283 /**
12284 * Show the overlay using the given overlay geometry.
12285 *
12286 * @param geo - The desired geometry for the overlay.
12287 */
12288 Overlay.prototype.show = function (geo) {
12289 // Update the position of the overlay.
12290 var style = this.node.style;
12291 style.top = geo.top + "px";
12292 style.left = geo.left + "px";
12293 style.right = geo.right + "px";
12294 style.bottom = geo.bottom + "px";
12295 // Clear any pending hide timer.
12296 clearTimeout(this._timer);
12297 this._timer = -1;
12298 // If the overlay is already visible, we're done.
12299 if (!this._hidden) {
12300 return;
12301 }
12302 // Clear the hidden flag.
12303 this._hidden = false;
12304 // Finally, show the overlay.
12305 this.node.classList.remove('lm-mod-hidden');
12306 /* <DEPRECATED> */
12307 this.node.classList.remove('p-mod-hidden');
12308 /* </DEPRECATED> */
12309 };
12310 /**
12311 * Hide the overlay node.
12312 *
12313 * @param delay - The delay (in ms) before hiding the overlay.
12314 * A delay value <= 0 will hide the overlay immediately.
12315 */
12316 Overlay.prototype.hide = function (delay) {
12317 var _this = this;
12318 // Do nothing if the overlay is already hidden.
12319 if (this._hidden) {
12320 return;
12321 }
12322 // Hide immediately if the delay is <= 0.
12323 if (delay <= 0) {
12324 clearTimeout(this._timer);
12325 this._timer = -1;
12326 this._hidden = true;
12327 this.node.classList.add('lm-mod-hidden');
12328 /* <DEPRECATED> */
12329 this.node.classList.add('p-mod-hidden');
12330 /* </DEPRECATED> */ return;
12331 }
12332 // Do nothing if a hide is already pending.
12333 if (this._timer !== -1) {
12334 return;
12335 }
12336 // Otherwise setup the hide timer.
12337 this._timer = window.setTimeout(function () {
12338 _this._timer = -1;
12339 _this._hidden = true;
12340 _this.node.classList.add('lm-mod-hidden');
12341 /* <DEPRECATED> */
12342 _this.node.classList.add('p-mod-hidden');
12343 /* </DEPRECATED> */
12344 }, delay);
12345 };
12346 return Overlay;
12347 }());
12348 DockPanel.Overlay = Overlay;
12349 /**
12350 * The default implementation of `IRenderer`.
12351 */
12352 var Renderer = /** @class */ (function () {
12353 function Renderer() {
12354 }
12355 /**
12356 * Create a new tab bar for use with a dock panel.
12357 *
12358 * @returns A new tab bar for a dock panel.
12359 */
12360 Renderer.prototype.createTabBar = function (document) {
12361 var bar = new TabBar({ document: document });
12362 bar.addClass('lm-DockPanel-tabBar');
12363 /* <DEPRECATED> */
12364 bar.addClass('p-DockPanel-tabBar');
12365 /* </DEPRECATED> */
12366 return bar;
12367 };
12368 /**
12369 * Create a new handle node for use with a dock panel.
12370 *
12371 * @returns A new handle node for a dock panel.
12372 */
12373 Renderer.prototype.createHandle = function () {
12374 var handle = document.createElement('div');
12375 handle.className = 'lm-DockPanel-handle';
12376 /* <DEPRECATED> */
12377 handle.classList.add('p-DockPanel-handle');
12378 /* </DEPRECATED> */ return handle;
12379 };
12380 return Renderer;
12381 }());
12382 DockPanel.Renderer = Renderer;
12383 /**
12384 * The default `Renderer` instance.
12385 */
12386 DockPanel.defaultRenderer = new Renderer();
12387})(DockPanel || (DockPanel = {}));
12388/**
12389 * The namespace for the module implementation details.
12390 */
12391var Private$5;
12392(function (Private) {
12393 /**
12394 * A fraction used for sizing root panels; ~= `1 / golden_ratio`.
12395 */
12396 Private.GOLDEN_RATIO = 0.618;
12397 /**
12398 * The default sizes for the edge drop zones, in pixels.
12399 */
12400 Private.DEFAULT_EDGES = {
12401 /**
12402 * The size of the top edge dock zone for the root panel, in pixels.
12403 * This is different from the others to distinguish between the top
12404 * tab bar and the top root zone.
12405 */
12406 top: 12,
12407 /**
12408 * The size of the edge dock zone for the root panel, in pixels.
12409 */
12410 right: 40,
12411 /**
12412 * The size of the edge dock zone for the root panel, in pixels.
12413 */
12414 bottom: 40,
12415 /**
12416 * The size of the edge dock zone for the root panel, in pixels.
12417 */
12418 left: 40
12419 };
12420 /**
12421 * A singleton `'layout-modified'` conflatable message.
12422 */
12423 Private.LayoutModified = new ConflatableMessage('layout-modified');
12424 /**
12425 * An attached property used to track generated tab bars.
12426 */
12427 Private.isGeneratedTabBarProperty = new AttachedProperty({
12428 name: 'isGeneratedTabBar',
12429 create: function () { return false; }
12430 });
12431 /**
12432 * Create a single document config for the widgets in a dock panel.
12433 */
12434 function createSingleDocumentConfig(panel) {
12435 // Return an empty config if the panel is empty.
12436 if (panel.isEmpty) {
12437 return { main: null };
12438 }
12439 // Get a flat array of the widgets in the panel.
12440 var widgets = toArray(panel.widgets());
12441 // Get the first selected widget in the panel.
12442 var selected = panel.selectedWidgets().next();
12443 // Compute the current index for the new config.
12444 var currentIndex = selected ? widgets.indexOf(selected) : -1;
12445 // Return the single document config.
12446 return { main: { type: 'tab-area', widgets: widgets, currentIndex: currentIndex } };
12447 }
12448 Private.createSingleDocumentConfig = createSingleDocumentConfig;
12449 /**
12450 * Find the drop target at the given client position.
12451 */
12452 function findDropTarget(panel, clientX, clientY, edges) {
12453 // Bail if the mouse is not over the dock panel.
12454 if (!ElementExt.hitTest(panel.node, clientX, clientY)) {
12455 return { zone: 'invalid', target: null };
12456 }
12457 // Look up the layout for the panel.
12458 var layout = panel.layout;
12459 // If the layout is empty, indicate the entire root drop zone.
12460 if (layout.isEmpty) {
12461 return { zone: 'root-all', target: null };
12462 }
12463 // Test the edge zones when in multiple document mode.
12464 if (panel.mode === 'multiple-document') {
12465 // Get the client rect for the dock panel.
12466 var panelRect = panel.node.getBoundingClientRect();
12467 // Compute the distance to each edge of the panel.
12468 var pl = clientX - panelRect.left + 1;
12469 var pt = clientY - panelRect.top + 1;
12470 var pr = panelRect.right - clientX;
12471 var pb = panelRect.bottom - clientY;
12472 // Find the minimum distance to an edge.
12473 var pd = Math.min(pt, pr, pb, pl);
12474 // Return a root zone if the mouse is within an edge.
12475 switch (pd) {
12476 case pt:
12477 if (pt < edges.top) {
12478 return { zone: 'root-top', target: null };
12479 }
12480 break;
12481 case pr:
12482 if (pr < edges.right) {
12483 return { zone: 'root-right', target: null };
12484 }
12485 break;
12486 case pb:
12487 if (pb < edges.bottom) {
12488 return { zone: 'root-bottom', target: null };
12489 }
12490 break;
12491 case pl:
12492 if (pl < edges.left) {
12493 return { zone: 'root-left', target: null };
12494 }
12495 break;
12496 default:
12497 throw 'unreachable';
12498 }
12499 }
12500 // Hit test the dock layout at the given client position.
12501 var target = layout.hitTestTabAreas(clientX, clientY);
12502 // Bail if no target area was found.
12503 if (!target) {
12504 return { zone: 'invalid', target: null };
12505 }
12506 // Return the whole tab area when in single document mode.
12507 if (panel.mode === 'single-document') {
12508 return { zone: 'widget-all', target: target };
12509 }
12510 // Compute the distance to each edge of the tab area.
12511 var al = target.x - target.left + 1;
12512 var at = target.y - target.top + 1;
12513 var ar = target.left + target.width - target.x;
12514 var ab = target.top + target.height - target.y;
12515 var tabHeight = target.tabBar.node.getBoundingClientRect().height;
12516 if (at < tabHeight) {
12517 return { zone: 'widget-tab', target: target };
12518 }
12519 // Get the X and Y edge sizes for the area.
12520 var rx = Math.round(target.width / 3);
12521 var ry = Math.round(target.height / 3);
12522 // If the mouse is not within an edge, indicate the entire area.
12523 if (al > rx && ar > rx && at > ry && ab > ry) {
12524 return { zone: 'widget-all', target: target };
12525 }
12526 // Scale the distances by the slenderness ratio.
12527 al /= rx;
12528 at /= ry;
12529 ar /= rx;
12530 ab /= ry;
12531 // Find the minimum distance to the area edge.
12532 var ad = Math.min(al, at, ar, ab);
12533 // Find the widget zone for the area edge.
12534 var zone;
12535 switch (ad) {
12536 case al:
12537 zone = 'widget-left';
12538 break;
12539 case at:
12540 zone = 'widget-top';
12541 break;
12542 case ar:
12543 zone = 'widget-right';
12544 break;
12545 case ab:
12546 zone = 'widget-bottom';
12547 break;
12548 default:
12549 throw 'unreachable';
12550 }
12551 // Return the final drop target.
12552 return { zone: zone, target: target };
12553 }
12554 Private.findDropTarget = findDropTarget;
12555 /**
12556 * Get the drop reference widget for a tab bar.
12557 */
12558 function getDropRef(tabBar) {
12559 if (tabBar.titles.length === 0) {
12560 return null;
12561 }
12562 if (tabBar.currentTitle) {
12563 return tabBar.currentTitle.owner;
12564 }
12565 return tabBar.titles[tabBar.titles.length - 1].owner;
12566 }
12567 Private.getDropRef = getDropRef;
12568})(Private$5 || (Private$5 = {}));
12569
12570// Copyright (c) Jupyter Development Team.
12571/**
12572 * A class which tracks focus among a set of widgets.
12573 *
12574 * This class is useful when code needs to keep track of the most
12575 * recently focused widget(s) among a set of related widgets.
12576 */
12577var FocusTracker = /** @class */ (function () {
12578 function FocusTracker() {
12579 this._counter = 0;
12580 this._widgets = [];
12581 this._activeWidget = null;
12582 this._currentWidget = null;
12583 this._numbers = new Map();
12584 this._nodes = new Map();
12585 this._activeChanged = new Signal(this);
12586 this._currentChanged = new Signal(this);
12587 }
12588 /**
12589 * Dispose of the resources held by the tracker.
12590 */
12591 FocusTracker.prototype.dispose = function () {
12592 var _this = this;
12593 // Do nothing if the tracker is already disposed.
12594 if (this._counter < 0) {
12595 return;
12596 }
12597 // Mark the tracker as disposed.
12598 this._counter = -1;
12599 // Clear the connections for the tracker.
12600 Signal.clearData(this);
12601 // Remove all event listeners.
12602 each(this._widgets, function (w) {
12603 w.node.removeEventListener('focus', _this, true);
12604 w.node.removeEventListener('blur', _this, true);
12605 });
12606 // Clear the internal data structures.
12607 this._activeWidget = null;
12608 this._currentWidget = null;
12609 this._nodes.clear();
12610 this._numbers.clear();
12611 this._widgets.length = 0;
12612 };
12613 Object.defineProperty(FocusTracker.prototype, "currentChanged", {
12614 /**
12615 * A signal emitted when the current widget has changed.
12616 */
12617 get: function () {
12618 return this._currentChanged;
12619 },
12620 enumerable: true,
12621 configurable: true
12622 });
12623 Object.defineProperty(FocusTracker.prototype, "activeChanged", {
12624 /**
12625 * A signal emitted when the active widget has changed.
12626 */
12627 get: function () {
12628 return this._activeChanged;
12629 },
12630 enumerable: true,
12631 configurable: true
12632 });
12633 Object.defineProperty(FocusTracker.prototype, "isDisposed", {
12634 /**
12635 * A flag indicating whether the tracker is disposed.
12636 */
12637 get: function () {
12638 return this._counter < 0;
12639 },
12640 enumerable: true,
12641 configurable: true
12642 });
12643 Object.defineProperty(FocusTracker.prototype, "currentWidget", {
12644 /**
12645 * The current widget in the tracker.
12646 *
12647 * #### Notes
12648 * The current widget is the widget among the tracked widgets which
12649 * has the *descendant node* which has most recently been focused.
12650 *
12651 * The current widget will not be updated if the node loses focus. It
12652 * will only be updated when a different tracked widget gains focus.
12653 *
12654 * If the current widget is removed from the tracker, the previous
12655 * current widget will be restored.
12656 *
12657 * This behavior is intended to follow a user's conceptual model of
12658 * a semantically "current" widget, where the "last thing of type X"
12659 * to be interacted with is the "current instance of X", regardless
12660 * of whether that instance still has focus.
12661 */
12662 get: function () {
12663 return this._currentWidget;
12664 },
12665 enumerable: true,
12666 configurable: true
12667 });
12668 Object.defineProperty(FocusTracker.prototype, "activeWidget", {
12669 /**
12670 * The active widget in the tracker.
12671 *
12672 * #### Notes
12673 * The active widget is the widget among the tracked widgets which
12674 * has the *descendant node* which is currently focused.
12675 */
12676 get: function () {
12677 return this._activeWidget;
12678 },
12679 enumerable: true,
12680 configurable: true
12681 });
12682 Object.defineProperty(FocusTracker.prototype, "widgets", {
12683 /**
12684 * A read only array of the widgets being tracked.
12685 */
12686 get: function () {
12687 return this._widgets;
12688 },
12689 enumerable: true,
12690 configurable: true
12691 });
12692 /**
12693 * Get the focus number for a particular widget in the tracker.
12694 *
12695 * @param widget - The widget of interest.
12696 *
12697 * @returns The focus number for the given widget, or `-1` if the
12698 * widget has not had focus since being added to the tracker, or
12699 * is not contained by the tracker.
12700 *
12701 * #### Notes
12702 * The focus number indicates the relative order in which the widgets
12703 * have gained focus. A widget with a larger number has gained focus
12704 * more recently than a widget with a smaller number.
12705 *
12706 * The `currentWidget` will always have the largest focus number.
12707 *
12708 * All widgets start with a focus number of `-1`, which indicates that
12709 * the widget has not been focused since being added to the tracker.
12710 */
12711 FocusTracker.prototype.focusNumber = function (widget) {
12712 var n = this._numbers.get(widget);
12713 return n === undefined ? -1 : n;
12714 };
12715 /**
12716 * Test whether the focus tracker contains a given widget.
12717 *
12718 * @param widget - The widget of interest.
12719 *
12720 * @returns `true` if the widget is tracked, `false` otherwise.
12721 */
12722 FocusTracker.prototype.has = function (widget) {
12723 return this._numbers.has(widget);
12724 };
12725 /**
12726 * Add a widget to the focus tracker.
12727 *
12728 * @param widget - The widget of interest.
12729 *
12730 * #### Notes
12731 * A widget will be automatically removed from the tracker if it
12732 * is disposed after being added.
12733 *
12734 * If the widget is already tracked, this is a no-op.
12735 */
12736 FocusTracker.prototype.add = function (widget) {
12737 // Do nothing if the widget is already tracked.
12738 if (this._numbers.has(widget)) {
12739 return;
12740 }
12741 // Test whether the widget has focus.
12742 var focused = widget.node.contains(document.activeElement);
12743 // Set up the initial focus number.
12744 var n = focused ? this._counter++ : -1;
12745 // Add the widget to the internal data structures.
12746 this._widgets.push(widget);
12747 this._numbers.set(widget, n);
12748 this._nodes.set(widget.node, widget);
12749 // Set up the event listeners. The capturing phase must be used
12750 // since the 'focus' and 'blur' events don't bubble and Firefox
12751 // doesn't support the 'focusin' or 'focusout' events.
12752 widget.node.addEventListener('focus', this, true);
12753 widget.node.addEventListener('blur', this, true);
12754 // Connect the disposed signal handler.
12755 widget.disposed.connect(this._onWidgetDisposed, this);
12756 // Set the current and active widgets if needed.
12757 if (focused) {
12758 this._setWidgets(widget, widget);
12759 }
12760 };
12761 /**
12762 * Remove a widget from the focus tracker.
12763 *
12764 * #### Notes
12765 * If the widget is the `currentWidget`, the previous current widget
12766 * will become the new `currentWidget`.
12767 *
12768 * A widget will be automatically removed from the tracker if it
12769 * is disposed after being added.
12770 *
12771 * If the widget is not tracked, this is a no-op.
12772 */
12773 FocusTracker.prototype.remove = function (widget) {
12774 var _this = this;
12775 // Bail early if the widget is not tracked.
12776 if (!this._numbers.has(widget)) {
12777 return;
12778 }
12779 // Disconnect the disposed signal handler.
12780 widget.disposed.disconnect(this._onWidgetDisposed, this);
12781 // Remove the event listeners.
12782 widget.node.removeEventListener('focus', this, true);
12783 widget.node.removeEventListener('blur', this, true);
12784 // Remove the widget from the internal data structures.
12785 ArrayExt.removeFirstOf(this._widgets, widget);
12786 this._nodes.delete(widget.node);
12787 this._numbers.delete(widget);
12788 // Bail early if the widget is not the current widget.
12789 if (this._currentWidget !== widget) {
12790 return;
12791 }
12792 // Filter the widgets for those which have had focus.
12793 var valid = filter(this._widgets, function (w) { return _this._numbers.get(w) !== -1; });
12794 // Get the valid widget with the max focus number.
12795 var previous = max(valid, function (first, second) {
12796 var a = _this._numbers.get(first);
12797 var b = _this._numbers.get(second);
12798 return a - b;
12799 }) || null;
12800 // Set the current and active widgets.
12801 this._setWidgets(previous, null);
12802 };
12803 /**
12804 * Handle the DOM events for the focus tracker.
12805 *
12806 * @param event - The DOM event sent to the panel.
12807 *
12808 * #### Notes
12809 * This method implements the DOM `EventListener` interface and is
12810 * called in response to events on the tracked nodes. It should
12811 * not be called directly by user code.
12812 */
12813 FocusTracker.prototype.handleEvent = function (event) {
12814 switch (event.type) {
12815 case 'focus':
12816 this._evtFocus(event);
12817 break;
12818 case 'blur':
12819 this._evtBlur(event);
12820 break;
12821 }
12822 };
12823 /**
12824 * Set the current and active widgets for the tracker.
12825 */
12826 FocusTracker.prototype._setWidgets = function (current, active) {
12827 // Swap the current widget.
12828 var oldCurrent = this._currentWidget;
12829 this._currentWidget = current;
12830 // Swap the active widget.
12831 var oldActive = this._activeWidget;
12832 this._activeWidget = active;
12833 // Emit the `currentChanged` signal if needed.
12834 if (oldCurrent !== current) {
12835 this._currentChanged.emit({ oldValue: oldCurrent, newValue: current });
12836 }
12837 // Emit the `activeChanged` signal if needed.
12838 if (oldActive !== active) {
12839 this._activeChanged.emit({ oldValue: oldActive, newValue: active });
12840 }
12841 };
12842 /**
12843 * Handle the `'focus'` event for a tracked widget.
12844 */
12845 FocusTracker.prototype._evtFocus = function (event) {
12846 // Find the widget which gained focus, which is known to exist.
12847 var widget = this._nodes.get(event.currentTarget);
12848 // Update the focus number if necessary.
12849 if (widget !== this._currentWidget) {
12850 this._numbers.set(widget, this._counter++);
12851 }
12852 // Set the current and active widgets.
12853 this._setWidgets(widget, widget);
12854 };
12855 /**
12856 * Handle the `'blur'` event for a tracked widget.
12857 */
12858 FocusTracker.prototype._evtBlur = function (event) {
12859 // Find the widget which lost focus, which is known to exist.
12860 var widget = this._nodes.get(event.currentTarget);
12861 // Get the node which being focused after this blur.
12862 var focusTarget = event.relatedTarget;
12863 // If no other node is being focused, clear the active widget.
12864 if (!focusTarget) {
12865 this._setWidgets(this._currentWidget, null);
12866 return;
12867 }
12868 // Bail if the focus widget is not changing.
12869 if (widget.node.contains(focusTarget)) {
12870 return;
12871 }
12872 // If no tracked widget is being focused, clear the active widget.
12873 if (!find(this._widgets, function (w) { return w.node.contains(focusTarget); })) {
12874 this._setWidgets(this._currentWidget, null);
12875 return;
12876 }
12877 };
12878 /**
12879 * Handle the `disposed` signal for a tracked widget.
12880 */
12881 FocusTracker.prototype._onWidgetDisposed = function (sender) {
12882 this.remove(sender);
12883 };
12884 return FocusTracker;
12885}());
12886
12887/**
12888 * A layout which arranges its widgets in a grid.
12889 */
12890var GridLayout = /** @class */ (function (_super) {
12891 __extends(GridLayout, _super);
12892 /**
12893 * Construct a new grid layout.
12894 *
12895 * @param options - The options for initializing the layout.
12896 */
12897 function GridLayout(options) {
12898 if (options === void 0) { options = {}; }
12899 var _this = _super.call(this, options) || this;
12900 _this._dirty = false;
12901 _this._rowSpacing = 4;
12902 _this._columnSpacing = 4;
12903 _this._items = [];
12904 _this._rowStarts = [];
12905 _this._columnStarts = [];
12906 _this._rowSizers = [new BoxSizer()];
12907 _this._columnSizers = [new BoxSizer()];
12908 _this._box = null;
12909 if (options.rowCount !== undefined) {
12910 Private$4.reallocSizers(_this._rowSizers, options.rowCount);
12911 }
12912 if (options.columnCount !== undefined) {
12913 Private$4.reallocSizers(_this._columnSizers, options.columnCount);
12914 }
12915 if (options.rowSpacing !== undefined) {
12916 _this._rowSpacing = Private$4.clampValue(options.rowSpacing);
12917 }
12918 if (options.columnSpacing !== undefined) {
12919 _this._columnSpacing = Private$4.clampValue(options.columnSpacing);
12920 }
12921 return _this;
12922 }
12923 /**
12924 * Dispose of the resources held by the layout.
12925 */
12926 GridLayout.prototype.dispose = function () {
12927 // Dispose of the widgets and layout items.
12928 each(this._items, function (item) {
12929 var widget = item.widget;
12930 item.dispose();
12931 widget.dispose();
12932 });
12933 // Clear the layout state.
12934 this._box = null;
12935 this._items.length = 0;
12936 this._rowStarts.length = 0;
12937 this._rowSizers.length = 0;
12938 this._columnStarts.length = 0;
12939 this._columnSizers.length = 0;
12940 // Dispose of the rest of the layout.
12941 _super.prototype.dispose.call(this);
12942 };
12943 Object.defineProperty(GridLayout.prototype, "rowCount", {
12944 /**
12945 * Get the number of rows in the layout.
12946 */
12947 get: function () {
12948 return this._rowSizers.length;
12949 },
12950 /**
12951 * Set the number of rows in the layout.
12952 *
12953 * #### Notes
12954 * The minimum row count is `1`.
12955 */
12956 set: function (value) {
12957 // Do nothing if the row count does not change.
12958 if (value === this.rowCount) {
12959 return;
12960 }
12961 // Reallocate the row sizers.
12962 Private$4.reallocSizers(this._rowSizers, value);
12963 // Schedule a fit of the parent.
12964 if (this.parent) {
12965 this.parent.fit();
12966 }
12967 },
12968 enumerable: true,
12969 configurable: true
12970 });
12971 Object.defineProperty(GridLayout.prototype, "columnCount", {
12972 /**
12973 * Get the number of columns in the layout.
12974 */
12975 get: function () {
12976 return this._columnSizers.length;
12977 },
12978 /**
12979 * Set the number of columns in the layout.
12980 *
12981 * #### Notes
12982 * The minimum column count is `1`.
12983 */
12984 set: function (value) {
12985 // Do nothing if the column count does not change.
12986 if (value === this.columnCount) {
12987 return;
12988 }
12989 // Reallocate the column sizers.
12990 Private$4.reallocSizers(this._columnSizers, value);
12991 // Schedule a fit of the parent.
12992 if (this.parent) {
12993 this.parent.fit();
12994 }
12995 },
12996 enumerable: true,
12997 configurable: true
12998 });
12999 Object.defineProperty(GridLayout.prototype, "rowSpacing", {
13000 /**
13001 * Get the row spacing for the layout.
13002 */
13003 get: function () {
13004 return this._rowSpacing;
13005 },
13006 /**
13007 * Set the row spacing for the layout.
13008 */
13009 set: function (value) {
13010 // Clamp the spacing to the allowed range.
13011 value = Private$4.clampValue(value);
13012 // Bail if the spacing does not change
13013 if (this._rowSpacing === value) {
13014 return;
13015 }
13016 // Update the internal spacing.
13017 this._rowSpacing = value;
13018 // Schedule a fit of the parent.
13019 if (this.parent) {
13020 this.parent.fit();
13021 }
13022 },
13023 enumerable: true,
13024 configurable: true
13025 });
13026 Object.defineProperty(GridLayout.prototype, "columnSpacing", {
13027 /**
13028 * Get the column spacing for the layout.
13029 */
13030 get: function () {
13031 return this._columnSpacing;
13032 },
13033 /**
13034 * Set the col spacing for the layout.
13035 */
13036 set: function (value) {
13037 // Clamp the spacing to the allowed range.
13038 value = Private$4.clampValue(value);
13039 // Bail if the spacing does not change
13040 if (this._columnSpacing === value) {
13041 return;
13042 }
13043 // Update the internal spacing.
13044 this._columnSpacing = value;
13045 // Schedule a fit of the parent.
13046 if (this.parent) {
13047 this.parent.fit();
13048 }
13049 },
13050 enumerable: true,
13051 configurable: true
13052 });
13053 /**
13054 * Get the stretch factor for a specific row.
13055 *
13056 * @param index - The row index of interest.
13057 *
13058 * @returns The stretch factor for the row.
13059 *
13060 * #### Notes
13061 * This returns `-1` if the index is out of range.
13062 */
13063 GridLayout.prototype.rowStretch = function (index) {
13064 var sizer = this._rowSizers[index];
13065 return sizer ? sizer.stretch : -1;
13066 };
13067 /**
13068 * Set the stretch factor for a specific row.
13069 *
13070 * @param index - The row index of interest.
13071 *
13072 * @param value - The stretch factor for the row.
13073 *
13074 * #### Notes
13075 * This is a no-op if the index is out of range.
13076 */
13077 GridLayout.prototype.setRowStretch = function (index, value) {
13078 // Look up the row sizer.
13079 var sizer = this._rowSizers[index];
13080 // Bail if the index is out of range.
13081 if (!sizer) {
13082 return;
13083 }
13084 // Clamp the value to the allowed range.
13085 value = Private$4.clampValue(value);
13086 // Bail if the stretch does not change.
13087 if (sizer.stretch === value) {
13088 return;
13089 }
13090 // Update the sizer stretch.
13091 sizer.stretch = value;
13092 // Schedule an update of the parent.
13093 if (this.parent) {
13094 this.parent.update();
13095 }
13096 };
13097 /**
13098 * Get the stretch factor for a specific column.
13099 *
13100 * @param index - The column index of interest.
13101 *
13102 * @returns The stretch factor for the column.
13103 *
13104 * #### Notes
13105 * This returns `-1` if the index is out of range.
13106 */
13107 GridLayout.prototype.columnStretch = function (index) {
13108 var sizer = this._columnSizers[index];
13109 return sizer ? sizer.stretch : -1;
13110 };
13111 /**
13112 * Set the stretch factor for a specific column.
13113 *
13114 * @param index - The column index of interest.
13115 *
13116 * @param value - The stretch factor for the column.
13117 *
13118 * #### Notes
13119 * This is a no-op if the index is out of range.
13120 */
13121 GridLayout.prototype.setColumnStretch = function (index, value) {
13122 // Look up the column sizer.
13123 var sizer = this._columnSizers[index];
13124 // Bail if the index is out of range.
13125 if (!sizer) {
13126 return;
13127 }
13128 // Clamp the value to the allowed range.
13129 value = Private$4.clampValue(value);
13130 // Bail if the stretch does not change.
13131 if (sizer.stretch === value) {
13132 return;
13133 }
13134 // Update the sizer stretch.
13135 sizer.stretch = value;
13136 // Schedule an update of the parent.
13137 if (this.parent) {
13138 this.parent.update();
13139 }
13140 };
13141 /**
13142 * Create an iterator over the widgets in the layout.
13143 *
13144 * @returns A new iterator over the widgets in the layout.
13145 */
13146 GridLayout.prototype.iter = function () {
13147 return map(this._items, function (item) { return item.widget; });
13148 };
13149 /**
13150 * Add a widget to the grid layout.
13151 *
13152 * @param widget - The widget to add to the layout.
13153 *
13154 * #### Notes
13155 * If the widget is already contained in the layout, this is no-op.
13156 */
13157 GridLayout.prototype.addWidget = function (widget) {
13158 // Look up the index for the widget.
13159 var i = ArrayExt.findFirstIndex(this._items, function (it) { return it.widget === widget; });
13160 // Bail if the widget is already in the layout.
13161 if (i !== -1) {
13162 return;
13163 }
13164 // Add the widget to the layout.
13165 this._items.push(new LayoutItem(widget));
13166 // Attach the widget to the parent.
13167 if (this.parent) {
13168 this.attachWidget(widget);
13169 }
13170 };
13171 /**
13172 * Remove a widget from the grid layout.
13173 *
13174 * @param widget - The widget to remove from the layout.
13175 *
13176 * #### Notes
13177 * A widget is automatically removed from the layout when its `parent`
13178 * is set to `null`. This method should only be invoked directly when
13179 * removing a widget from a layout which has yet to be installed on a
13180 * parent widget.
13181 *
13182 * This method does *not* modify the widget's `parent`.
13183 */
13184 GridLayout.prototype.removeWidget = function (widget) {
13185 // Look up the index for the widget.
13186 var i = ArrayExt.findFirstIndex(this._items, function (it) { return it.widget === widget; });
13187 // Bail if the widget is not in the layout.
13188 if (i === -1) {
13189 return;
13190 }
13191 // Remove the widget from the layout.
13192 var item = ArrayExt.removeAt(this._items, i);
13193 // Detach the widget from the parent.
13194 if (this.parent) {
13195 this.detachWidget(widget);
13196 }
13197 // Dispose the layout item.
13198 item.dispose();
13199 };
13200 /**
13201 * Perform layout initialization which requires the parent widget.
13202 */
13203 GridLayout.prototype.init = function () {
13204 var _this = this;
13205 _super.prototype.init.call(this);
13206 each(this, function (widget) {
13207 _this.attachWidget(widget);
13208 });
13209 };
13210 /**
13211 * Attach a widget to the parent's DOM node.
13212 *
13213 * @param widget - The widget to attach to the parent.
13214 */
13215 GridLayout.prototype.attachWidget = function (widget) {
13216 // Send a `'before-attach'` message if the parent is attached.
13217 if (this.parent.isAttached) {
13218 MessageLoop.sendMessage(widget, Widget.Msg.BeforeAttach);
13219 }
13220 // Add the widget's node to the parent.
13221 this.parent.node.appendChild(widget.node);
13222 // Send an `'after-attach'` message if the parent is attached.
13223 if (this.parent.isAttached) {
13224 MessageLoop.sendMessage(widget, Widget.Msg.AfterAttach);
13225 }
13226 // Post a fit request for the parent widget.
13227 this.parent.fit();
13228 };
13229 /**
13230 * Detach a widget from the parent's DOM node.
13231 *
13232 * @param widget - The widget to detach from the parent.
13233 */
13234 GridLayout.prototype.detachWidget = function (widget) {
13235 // Send a `'before-detach'` message if the parent is attached.
13236 if (this.parent.isAttached) {
13237 MessageLoop.sendMessage(widget, Widget.Msg.BeforeDetach);
13238 }
13239 // Remove the widget's node from the parent.
13240 this.parent.node.removeChild(widget.node);
13241 // Send an `'after-detach'` message if the parent is attached.
13242 if (this.parent.isAttached) {
13243 MessageLoop.sendMessage(widget, Widget.Msg.AfterDetach);
13244 }
13245 // Post a fit request for the parent widget.
13246 this.parent.fit();
13247 };
13248 /**
13249 * A message handler invoked on a `'before-show'` message.
13250 */
13251 GridLayout.prototype.onBeforeShow = function (msg) {
13252 _super.prototype.onBeforeShow.call(this, msg);
13253 this.parent.update();
13254 };
13255 /**
13256 * A message handler invoked on a `'before-attach'` message.
13257 */
13258 GridLayout.prototype.onBeforeAttach = function (msg) {
13259 _super.prototype.onBeforeAttach.call(this, msg);
13260 this.parent.fit();
13261 };
13262 /**
13263 * A message handler invoked on a `'child-shown'` message.
13264 */
13265 GridLayout.prototype.onChildShown = function (msg) {
13266 this.parent.fit();
13267 };
13268 /**
13269 * A message handler invoked on a `'child-hidden'` message.
13270 */
13271 GridLayout.prototype.onChildHidden = function (msg) {
13272 this.parent.fit();
13273 };
13274 /**
13275 * A message handler invoked on a `'resize'` message.
13276 */
13277 GridLayout.prototype.onResize = function (msg) {
13278 if (this.parent.isVisible) {
13279 this._update(msg.width, msg.height);
13280 }
13281 };
13282 /**
13283 * A message handler invoked on an `'update-request'` message.
13284 */
13285 GridLayout.prototype.onUpdateRequest = function (msg) {
13286 if (this.parent.isVisible) {
13287 this._update(-1, -1);
13288 }
13289 };
13290 /**
13291 * A message handler invoked on a `'fit-request'` message.
13292 */
13293 GridLayout.prototype.onFitRequest = function (msg) {
13294 if (this.parent.isAttached) {
13295 this._fit();
13296 }
13297 };
13298 /**
13299 * Fit the layout to the total size required by the widgets.
13300 */
13301 GridLayout.prototype._fit = function () {
13302 // Reset the min sizes of the sizers.
13303 for (var i = 0, n = this.rowCount; i < n; ++i) {
13304 this._rowSizers[i].minSize = 0;
13305 }
13306 for (var i = 0, n = this.columnCount; i < n; ++i) {
13307 this._columnSizers[i].minSize = 0;
13308 }
13309 // Filter for the visible layout items.
13310 var items = this._items.filter(function (it) { return !it.isHidden; });
13311 // Fit the layout items.
13312 for (var i = 0, n = items.length; i < n; ++i) {
13313 items[i].fit();
13314 }
13315 // Get the max row and column index.
13316 var maxRow = this.rowCount - 1;
13317 var maxCol = this.columnCount - 1;
13318 // Sort the items by row span.
13319 items.sort(Private$4.rowSpanCmp);
13320 // Update the min sizes of the row sizers.
13321 for (var i = 0, n = items.length; i < n; ++i) {
13322 // Fetch the item.
13323 var item = items[i];
13324 // Get the row bounds for the item.
13325 var config = GridLayout.getCellConfig(item.widget);
13326 var r1 = Math.min(config.row, maxRow);
13327 var r2 = Math.min(config.row + config.rowSpan - 1, maxRow);
13328 // Distribute the minimum height to the sizers as needed.
13329 Private$4.distributeMin(this._rowSizers, r1, r2, item.minHeight);
13330 }
13331 // Sort the items by column span.
13332 items.sort(Private$4.columnSpanCmp);
13333 // Update the min sizes of the column sizers.
13334 for (var i = 0, n = items.length; i < n; ++i) {
13335 // Fetch the item.
13336 var item = items[i];
13337 // Get the column bounds for the item.
13338 var config = GridLayout.getCellConfig(item.widget);
13339 var c1 = Math.min(config.column, maxCol);
13340 var c2 = Math.min(config.column + config.columnSpan - 1, maxCol);
13341 // Distribute the minimum width to the sizers as needed.
13342 Private$4.distributeMin(this._columnSizers, c1, c2, item.minWidth);
13343 }
13344 // If no size constraint is needed, just update the parent.
13345 if (this.fitPolicy === 'set-no-constraint') {
13346 MessageLoop.sendMessage(this.parent, Widget.Msg.UpdateRequest);
13347 return;
13348 }
13349 // Set up the computed min size.
13350 var minH = maxRow * this._rowSpacing;
13351 var minW = maxCol * this._columnSpacing;
13352 // Add the sizer minimums to the computed min size.
13353 for (var i = 0, n = this.rowCount; i < n; ++i) {
13354 minH += this._rowSizers[i].minSize;
13355 }
13356 for (var i = 0, n = this.columnCount; i < n; ++i) {
13357 minW += this._columnSizers[i].minSize;
13358 }
13359 // Update the box sizing and add it to the computed min size.
13360 var box = (this._box = ElementExt.boxSizing(this.parent.node));
13361 minW += box.horizontalSum;
13362 minH += box.verticalSum;
13363 // Update the parent's min size constraints.
13364 var style = this.parent.node.style;
13365 style.minWidth = minW + "px";
13366 style.minHeight = minH + "px";
13367 // Set the dirty flag to ensure only a single update occurs.
13368 this._dirty = true;
13369 // Notify the ancestor that it should fit immediately. This may
13370 // cause a resize of the parent, fulfilling the required update.
13371 if (this.parent.parent) {
13372 MessageLoop.sendMessage(this.parent.parent, Widget.Msg.FitRequest);
13373 }
13374 // If the dirty flag is still set, the parent was not resized.
13375 // Trigger the required update on the parent widget immediately.
13376 if (this._dirty) {
13377 MessageLoop.sendMessage(this.parent, Widget.Msg.UpdateRequest);
13378 }
13379 };
13380 /**
13381 * Update the layout position and size of the widgets.
13382 *
13383 * The parent offset dimensions should be `-1` if unknown.
13384 */
13385 GridLayout.prototype._update = function (offsetWidth, offsetHeight) {
13386 // Clear the dirty flag to indicate the update occurred.
13387 this._dirty = false;
13388 // Measure the parent if the offset dimensions are unknown.
13389 if (offsetWidth < 0) {
13390 offsetWidth = this.parent.node.offsetWidth;
13391 }
13392 if (offsetHeight < 0) {
13393 offsetHeight = this.parent.node.offsetHeight;
13394 }
13395 // Ensure the parent box sizing data is computed.
13396 if (!this._box) {
13397 this._box = ElementExt.boxSizing(this.parent.node);
13398 }
13399 // Compute the layout area adjusted for border and padding.
13400 var top = this._box.paddingTop;
13401 var left = this._box.paddingLeft;
13402 var width = offsetWidth - this._box.horizontalSum;
13403 var height = offsetHeight - this._box.verticalSum;
13404 // Get the max row and column index.
13405 var maxRow = this.rowCount - 1;
13406 var maxCol = this.columnCount - 1;
13407 // Compute the total fixed row and column space.
13408 var fixedRowSpace = maxRow * this._rowSpacing;
13409 var fixedColSpace = maxCol * this._columnSpacing;
13410 // Distribute the available space to the box sizers.
13411 BoxEngine.calc(this._rowSizers, Math.max(0, height - fixedRowSpace));
13412 BoxEngine.calc(this._columnSizers, Math.max(0, width - fixedColSpace));
13413 // Update the row start positions.
13414 for (var i = 0, pos = top, n = this.rowCount; i < n; ++i) {
13415 this._rowStarts[i] = pos;
13416 pos += this._rowSizers[i].size + this._rowSpacing;
13417 }
13418 // Update the column start positions.
13419 for (var i = 0, pos = left, n = this.columnCount; i < n; ++i) {
13420 this._columnStarts[i] = pos;
13421 pos += this._columnSizers[i].size + this._columnSpacing;
13422 }
13423 // Update the geometry of the layout items.
13424 for (var i = 0, n = this._items.length; i < n; ++i) {
13425 // Fetch the item.
13426 var item = this._items[i];
13427 // Ignore hidden items.
13428 if (item.isHidden) {
13429 continue;
13430 }
13431 // Fetch the cell bounds for the widget.
13432 var config = GridLayout.getCellConfig(item.widget);
13433 var r1 = Math.min(config.row, maxRow);
13434 var c1 = Math.min(config.column, maxCol);
13435 var r2 = Math.min(config.row + config.rowSpan - 1, maxRow);
13436 var c2 = Math.min(config.column + config.columnSpan - 1, maxCol);
13437 // Compute the cell geometry.
13438 var x = this._columnStarts[c1];
13439 var y = this._rowStarts[r1];
13440 var w = this._columnStarts[c2] + this._columnSizers[c2].size - x;
13441 var h = this._rowStarts[r2] + this._rowSizers[r2].size - y;
13442 // Update the geometry of the layout item.
13443 item.update(x, y, w, h);
13444 }
13445 };
13446 return GridLayout;
13447}(Layout));
13448/**
13449 * The namespace for the `GridLayout` class statics.
13450 */
13451(function (GridLayout) {
13452 /**
13453 * Get the cell config for the given widget.
13454 *
13455 * @param widget - The widget of interest.
13456 *
13457 * @returns The cell config for the widget.
13458 */
13459 function getCellConfig(widget) {
13460 return Private$4.cellConfigProperty.get(widget);
13461 }
13462 GridLayout.getCellConfig = getCellConfig;
13463 /**
13464 * Set the cell config for the given widget.
13465 *
13466 * @param widget - The widget of interest.
13467 *
13468 * @param value - The value for the cell config.
13469 */
13470 function setCellConfig(widget, value) {
13471 Private$4.cellConfigProperty.set(widget, Private$4.normalizeConfig(value));
13472 }
13473 GridLayout.setCellConfig = setCellConfig;
13474})(GridLayout || (GridLayout = {}));
13475/**
13476 * The namespace for the module implementation details.
13477 */
13478var Private$4;
13479(function (Private) {
13480 /**
13481 * The property descriptor for the widget cell config.
13482 */
13483 Private.cellConfigProperty = new AttachedProperty({
13484 name: 'cellConfig',
13485 create: function () { return ({ row: 0, column: 0, rowSpan: 1, columnSpan: 1 }); },
13486 changed: onChildCellConfigChanged
13487 });
13488 /**
13489 * Normalize a partial cell config object.
13490 */
13491 function normalizeConfig(config) {
13492 var row = Math.max(0, Math.floor(config.row || 0));
13493 var column = Math.max(0, Math.floor(config.column || 0));
13494 var rowSpan = Math.max(1, Math.floor(config.rowSpan || 0));
13495 var columnSpan = Math.max(1, Math.floor(config.columnSpan || 0));
13496 return { row: row, column: column, rowSpan: rowSpan, columnSpan: columnSpan };
13497 }
13498 Private.normalizeConfig = normalizeConfig;
13499 /**
13500 * Clamp a value to an integer >= 0.
13501 */
13502 function clampValue(value) {
13503 return Math.max(0, Math.floor(value));
13504 }
13505 Private.clampValue = clampValue;
13506 /**
13507 * A sort comparison function for row spans.
13508 */
13509 function rowSpanCmp(a, b) {
13510 var c1 = Private.cellConfigProperty.get(a.widget);
13511 var c2 = Private.cellConfigProperty.get(b.widget);
13512 return c1.rowSpan - c2.rowSpan;
13513 }
13514 Private.rowSpanCmp = rowSpanCmp;
13515 /**
13516 * A sort comparison function for column spans.
13517 */
13518 function columnSpanCmp(a, b) {
13519 var c1 = Private.cellConfigProperty.get(a.widget);
13520 var c2 = Private.cellConfigProperty.get(b.widget);
13521 return c1.columnSpan - c2.columnSpan;
13522 }
13523 Private.columnSpanCmp = columnSpanCmp;
13524 /**
13525 * Reallocate the box sizers for the given grid dimensions.
13526 */
13527 function reallocSizers(sizers, count) {
13528 // Coerce the count to the valid range.
13529 count = Math.max(1, Math.floor(count));
13530 // Add the missing sizers.
13531 while (sizers.length < count) {
13532 sizers.push(new BoxSizer());
13533 }
13534 // Remove the extra sizers.
13535 if (sizers.length > count) {
13536 sizers.length = count;
13537 }
13538 }
13539 Private.reallocSizers = reallocSizers;
13540 /**
13541 * Distribute a min size constraint across a range of sizers.
13542 */
13543 function distributeMin(sizers, i1, i2, minSize) {
13544 // Sanity check the indices.
13545 if (i2 < i1) {
13546 return;
13547 }
13548 // Handle the simple case of no cell span.
13549 if (i1 === i2) {
13550 var sizer = sizers[i1];
13551 sizer.minSize = Math.max(sizer.minSize, minSize);
13552 return;
13553 }
13554 // Compute the total current min size of the span.
13555 var totalMin = 0;
13556 for (var i = i1; i <= i2; ++i) {
13557 totalMin += sizers[i].minSize;
13558 }
13559 // Do nothing if the total is greater than the required.
13560 if (totalMin >= minSize) {
13561 return;
13562 }
13563 // Compute the portion of the space to allocate to each sizer.
13564 var portion = (minSize - totalMin) / (i2 - i1 + 1);
13565 // Add the portion to each sizer.
13566 for (var i = i1; i <= i2; ++i) {
13567 sizers[i].minSize += portion;
13568 }
13569 }
13570 Private.distributeMin = distributeMin;
13571 /**
13572 * The change handler for the child cell config property.
13573 */
13574 function onChildCellConfigChanged(child) {
13575 if (child.parent && child.parent.layout instanceof GridLayout) {
13576 child.parent.fit();
13577 }
13578 }
13579})(Private$4 || (Private$4 = {}));
13580
13581/**
13582 * A widget which displays menus as a canonical menu bar.
13583 */
13584var MenuBar = /** @class */ (function (_super) {
13585 __extends(MenuBar, _super);
13586 /**
13587 * Construct a new menu bar.
13588 *
13589 * @param options - The options for initializing the menu bar.
13590 */
13591 function MenuBar(options) {
13592 if (options === void 0) { options = {}; }
13593 var _this = _super.call(this, { node: Private$3.createNode() }) || this;
13594 _this._activeIndex = -1;
13595 _this._menus = [];
13596 _this._childMenu = null;
13597 _this.addClass('lm-MenuBar');
13598 /* <DEPRECATED> */
13599 _this.addClass('p-MenuBar');
13600 /* </DEPRECATED> */
13601 _this.setFlag(Widget.Flag.DisallowLayout);
13602 _this.renderer = options.renderer || MenuBar.defaultRenderer;
13603 _this._forceItemsPosition = options.forceItemsPosition || {
13604 forceX: true,
13605 forceY: true
13606 };
13607 return _this;
13608 }
13609 /**
13610 * Dispose of the resources held by the widget.
13611 */
13612 MenuBar.prototype.dispose = function () {
13613 this._closeChildMenu();
13614 this._menus.length = 0;
13615 _super.prototype.dispose.call(this);
13616 };
13617 Object.defineProperty(MenuBar.prototype, "childMenu", {
13618 /**
13619 * The child menu of the menu bar.
13620 *
13621 * #### Notes
13622 * This will be `null` if the menu bar does not have an open menu.
13623 */
13624 get: function () {
13625 return this._childMenu;
13626 },
13627 enumerable: true,
13628 configurable: true
13629 });
13630 Object.defineProperty(MenuBar.prototype, "contentNode", {
13631 /**
13632 * Get the menu bar content node.
13633 *
13634 * #### Notes
13635 * This is the node which holds the menu title nodes.
13636 *
13637 * Modifying this node directly can lead to undefined behavior.
13638 */
13639 get: function () {
13640 return this.node.getElementsByClassName('lm-MenuBar-content')[0];
13641 },
13642 enumerable: true,
13643 configurable: true
13644 });
13645 Object.defineProperty(MenuBar.prototype, "activeMenu", {
13646 /**
13647 * Get the currently active menu.
13648 */
13649 get: function () {
13650 return this._menus[this._activeIndex] || null;
13651 },
13652 /**
13653 * Set the currently active menu.
13654 *
13655 * #### Notes
13656 * If the menu does not exist, the menu will be set to `null`.
13657 */
13658 set: function (value) {
13659 this.activeIndex = value ? this._menus.indexOf(value) : -1;
13660 },
13661 enumerable: true,
13662 configurable: true
13663 });
13664 Object.defineProperty(MenuBar.prototype, "activeIndex", {
13665 /**
13666 * Get the index of the currently active menu.
13667 *
13668 * #### Notes
13669 * This will be `-1` if no menu is active.
13670 */
13671 get: function () {
13672 return this._activeIndex;
13673 },
13674 /**
13675 * Set the index of the currently active menu.
13676 *
13677 * #### Notes
13678 * If the menu cannot be activated, the index will be set to `-1`.
13679 */
13680 set: function (value) {
13681 // Adjust the value for an out of range index.
13682 if (value < 0 || value >= this._menus.length) {
13683 value = -1;
13684 }
13685 // Bail early if the index will not change.
13686 if (this._activeIndex === value) {
13687 return;
13688 }
13689 // Update the active index.
13690 this._activeIndex = value;
13691 // Update focus to new active index
13692 if (this._activeIndex >= 0 &&
13693 this.contentNode.childNodes[this._activeIndex]) {
13694 this.contentNode.childNodes[this._activeIndex].focus();
13695 }
13696 // Schedule an update of the items.
13697 this.update();
13698 },
13699 enumerable: true,
13700 configurable: true
13701 });
13702 Object.defineProperty(MenuBar.prototype, "menus", {
13703 /**
13704 * A read-only array of the menus in the menu bar.
13705 */
13706 get: function () {
13707 return this._menus;
13708 },
13709 enumerable: true,
13710 configurable: true
13711 });
13712 /**
13713 * Open the active menu and activate its first menu item.
13714 *
13715 * #### Notes
13716 * If there is no active menu, this is a no-op.
13717 */
13718 MenuBar.prototype.openActiveMenu = function () {
13719 // Bail early if there is no active item.
13720 if (this._activeIndex === -1) {
13721 return;
13722 }
13723 // Open the child menu.
13724 this._openChildMenu();
13725 // Activate the first item in the child menu.
13726 if (this._childMenu) {
13727 this._childMenu.activeIndex = -1;
13728 this._childMenu.activateNextItem();
13729 }
13730 };
13731 /**
13732 * Add a menu to the end of the menu bar.
13733 *
13734 * @param menu - The menu to add to the menu bar.
13735 *
13736 * #### Notes
13737 * If the menu is already added to the menu bar, it will be moved.
13738 */
13739 MenuBar.prototype.addMenu = function (menu) {
13740 this.insertMenu(this._menus.length, menu);
13741 };
13742 /**
13743 * Insert a menu into the menu bar at the specified index.
13744 *
13745 * @param index - The index at which to insert the menu.
13746 *
13747 * @param menu - The menu to insert into the menu bar.
13748 *
13749 * #### Notes
13750 * The index will be clamped to the bounds of the menus.
13751 *
13752 * If the menu is already added to the menu bar, it will be moved.
13753 */
13754 MenuBar.prototype.insertMenu = function (index, menu) {
13755 // Close the child menu before making changes.
13756 this._closeChildMenu();
13757 // Look up the index of the menu.
13758 var i = this._menus.indexOf(menu);
13759 // Clamp the insert index to the array bounds.
13760 var j = Math.max(0, Math.min(index, this._menus.length));
13761 // If the menu is not in the array, insert it.
13762 if (i === -1) {
13763 // Insert the menu into the array.
13764 ArrayExt.insert(this._menus, j, menu);
13765 // Add the styling class to the menu.
13766 menu.addClass('lm-MenuBar-menu');
13767 /* <DEPRECATED> */
13768 menu.addClass('p-MenuBar-menu');
13769 /* </DEPRECATED> */
13770 // Connect to the menu signals.
13771 menu.aboutToClose.connect(this._onMenuAboutToClose, this);
13772 menu.menuRequested.connect(this._onMenuMenuRequested, this);
13773 menu.title.changed.connect(this._onTitleChanged, this);
13774 // Schedule an update of the items.
13775 this.update();
13776 // There is nothing more to do.
13777 return;
13778 }
13779 // Otherwise, the menu exists in the array and should be moved.
13780 // Adjust the index if the location is at the end of the array.
13781 if (j === this._menus.length) {
13782 j--;
13783 }
13784 // Bail if there is no effective move.
13785 if (i === j) {
13786 return;
13787 }
13788 // Move the menu to the new locations.
13789 ArrayExt.move(this._menus, i, j);
13790 // Schedule an update of the items.
13791 this.update();
13792 };
13793 /**
13794 * Remove a menu from the menu bar.
13795 *
13796 * @param menu - The menu to remove from the menu bar.
13797 *
13798 * #### Notes
13799 * This is a no-op if the menu is not in the menu bar.
13800 */
13801 MenuBar.prototype.removeMenu = function (menu) {
13802 this.removeMenuAt(this._menus.indexOf(menu));
13803 };
13804 /**
13805 * Remove the menu at a given index from the menu bar.
13806 *
13807 * @param index - The index of the menu to remove.
13808 *
13809 * #### Notes
13810 * This is a no-op if the index is out of range.
13811 */
13812 MenuBar.prototype.removeMenuAt = function (index) {
13813 // Close the child menu before making changes.
13814 this._closeChildMenu();
13815 // Remove the menu from the array.
13816 var menu = ArrayExt.removeAt(this._menus, index);
13817 // Bail if the index is out of range.
13818 if (!menu) {
13819 return;
13820 }
13821 // Disconnect from the menu signals.
13822 menu.aboutToClose.disconnect(this._onMenuAboutToClose, this);
13823 menu.menuRequested.disconnect(this._onMenuMenuRequested, this);
13824 menu.title.changed.disconnect(this._onTitleChanged, this);
13825 // Remove the styling class from the menu.
13826 menu.removeClass('lm-MenuBar-menu');
13827 /* <DEPRECATED> */
13828 menu.removeClass('p-MenuBar-menu');
13829 /* </DEPRECATED> */
13830 // Schedule an update of the items.
13831 this.update();
13832 };
13833 /**
13834 * Remove all menus from the menu bar.
13835 */
13836 MenuBar.prototype.clearMenus = function () {
13837 // Bail if there is nothing to remove.
13838 if (this._menus.length === 0) {
13839 return;
13840 }
13841 // Close the child menu before making changes.
13842 this._closeChildMenu();
13843 // Disconnect from the menu signals and remove the styling class.
13844 for (var _i = 0, _a = this._menus; _i < _a.length; _i++) {
13845 var menu = _a[_i];
13846 menu.aboutToClose.disconnect(this._onMenuAboutToClose, this);
13847 menu.menuRequested.disconnect(this._onMenuMenuRequested, this);
13848 menu.title.changed.disconnect(this._onTitleChanged, this);
13849 menu.removeClass('lm-MenuBar-menu');
13850 /* <DEPRECATED> */
13851 menu.removeClass('p-MenuBar-menu');
13852 /* </DEPRECATED> */
13853 }
13854 // Clear the menus array.
13855 this._menus.length = 0;
13856 // Schedule an update of the items.
13857 this.update();
13858 };
13859 /**
13860 * Handle the DOM events for the menu bar.
13861 *
13862 * @param event - The DOM event sent to the menu bar.
13863 *
13864 * #### Notes
13865 * This method implements the DOM `EventListener` interface and is
13866 * called in response to events on the menu bar's DOM nodes. It
13867 * should not be called directly by user code.
13868 */
13869 MenuBar.prototype.handleEvent = function (event) {
13870 switch (event.type) {
13871 case 'keydown':
13872 this._evtKeyDown(event);
13873 break;
13874 case 'mousedown':
13875 this._evtMouseDown(event);
13876 break;
13877 case 'mousemove':
13878 this._evtMouseMove(event);
13879 break;
13880 case 'mouseleave':
13881 this._evtMouseLeave(event);
13882 break;
13883 case 'contextmenu':
13884 event.preventDefault();
13885 event.stopPropagation();
13886 break;
13887 }
13888 };
13889 /**
13890 * A message handler invoked on a `'before-attach'` message.
13891 */
13892 MenuBar.prototype.onBeforeAttach = function (msg) {
13893 this.node.addEventListener('keydown', this);
13894 this.node.addEventListener('mousedown', this);
13895 this.node.addEventListener('mousemove', this);
13896 this.node.addEventListener('mouseleave', this);
13897 this.node.addEventListener('contextmenu', this);
13898 };
13899 /**
13900 * A message handler invoked on an `'after-detach'` message.
13901 */
13902 MenuBar.prototype.onAfterDetach = function (msg) {
13903 this.node.removeEventListener('keydown', this);
13904 this.node.removeEventListener('mousedown', this);
13905 this.node.removeEventListener('mousemove', this);
13906 this.node.removeEventListener('mouseleave', this);
13907 this.node.removeEventListener('contextmenu', this);
13908 this._closeChildMenu();
13909 };
13910 /**
13911 * A message handler invoked on an `'activate-request'` message.
13912 */
13913 MenuBar.prototype.onActivateRequest = function (msg) {
13914 if (this.isAttached) {
13915 this.node.focus();
13916 }
13917 };
13918 /**
13919 * A message handler invoked on an `'update-request'` message.
13920 */
13921 MenuBar.prototype.onUpdateRequest = function (msg) {
13922 var _this = this;
13923 var menus = this._menus;
13924 var renderer = this.renderer;
13925 var activeIndex = this._activeIndex;
13926 var content = new Array(menus.length);
13927 var _loop_1 = function (i, n) {
13928 var title = menus[i].title;
13929 var active = i === activeIndex;
13930 if (active && menus[i].items.length == 0) {
13931 active = false;
13932 }
13933 content[i] = renderer.renderItem({
13934 title: title,
13935 active: active,
13936 onfocus: function () {
13937 _this.activeIndex = i;
13938 }
13939 });
13940 };
13941 for (var i = 0, n = menus.length; i < n; ++i) {
13942 _loop_1(i);
13943 }
13944 VirtualDOM.render(content, this.contentNode);
13945 };
13946 /**
13947 * Handle the `'keydown'` event for the menu bar.
13948 */
13949 MenuBar.prototype._evtKeyDown = function (event) {
13950 // A menu bar handles all keydown events.
13951 event.preventDefault();
13952 event.stopPropagation();
13953 // Fetch the key code for the event.
13954 var kc = event.keyCode;
13955 // Enter, Up Arrow, Down Arrow
13956 if (kc === 13 || kc === 38 || kc === 40) {
13957 this.openActiveMenu();
13958 return;
13959 }
13960 // Escape
13961 if (kc === 27) {
13962 this._closeChildMenu();
13963 this.activeIndex = -1;
13964 this.node.blur();
13965 return;
13966 }
13967 // Left Arrow
13968 if (kc === 37) {
13969 var i = this._activeIndex;
13970 var n = this._menus.length;
13971 this.activeIndex = i === 0 ? n - 1 : i - 1;
13972 return;
13973 }
13974 // Right Arrow
13975 if (kc === 39) {
13976 var i = this._activeIndex;
13977 var n = this._menus.length;
13978 this.activeIndex = i === n - 1 ? 0 : i + 1;
13979 return;
13980 }
13981 // Get the pressed key character.
13982 var key = getKeyboardLayout().keyForKeydownEvent(event);
13983 // Bail if the key is not valid.
13984 if (!key) {
13985 return;
13986 }
13987 // Search for the next best matching mnemonic item.
13988 var start = this._activeIndex + 1;
13989 var result = Private$3.findMnemonic(this._menus, key, start);
13990 // Handle the requested mnemonic based on the search results.
13991 // If exactly one mnemonic is matched, that menu is opened.
13992 // Otherwise, the next mnemonic is activated if available,
13993 // followed by the auto mnemonic if available.
13994 if (result.index !== -1 && !result.multiple) {
13995 this.activeIndex = result.index;
13996 this.openActiveMenu();
13997 }
13998 else if (result.index !== -1) {
13999 this.activeIndex = result.index;
14000 }
14001 else if (result.auto !== -1) {
14002 this.activeIndex = result.auto;
14003 }
14004 };
14005 /**
14006 * Handle the `'mousedown'` event for the menu bar.
14007 */
14008 MenuBar.prototype._evtMouseDown = function (event) {
14009 // Bail if the mouse press was not on the menu bar. This can occur
14010 // when the document listener is installed for an active menu bar.
14011 if (!ElementExt.hitTest(this.node, event.clientX, event.clientY)) {
14012 return;
14013 }
14014 // Stop the propagation of the event. Immediate propagation is
14015 // also stopped so that an open menu does not handle the event.
14016 event.preventDefault();
14017 event.stopPropagation();
14018 event.stopImmediatePropagation();
14019 // Check if the mouse is over one of the menu items.
14020 var index = ArrayExt.findFirstIndex(this.contentNode.children, function (node) {
14021 return ElementExt.hitTest(node, event.clientX, event.clientY);
14022 });
14023 // If the press was not on an item, close the child menu.
14024 if (index === -1) {
14025 this._closeChildMenu();
14026 return;
14027 }
14028 // If the press was not the left mouse button, do nothing further.
14029 if (event.button !== 0) {
14030 return;
14031 }
14032 // Otherwise, toggle the open state of the child menu.
14033 if (this._childMenu) {
14034 this._closeChildMenu();
14035 this.activeIndex = index;
14036 }
14037 else {
14038 this.activeIndex = index;
14039 this._openChildMenu();
14040 }
14041 };
14042 /**
14043 * Handle the `'mousemove'` event for the menu bar.
14044 */
14045 MenuBar.prototype._evtMouseMove = function (event) {
14046 // Check if the mouse is over one of the menu items.
14047 var index = ArrayExt.findFirstIndex(this.contentNode.children, function (node) {
14048 return ElementExt.hitTest(node, event.clientX, event.clientY);
14049 });
14050 // Bail early if the active index will not change.
14051 if (index === this._activeIndex) {
14052 return;
14053 }
14054 // Bail early if a child menu is open and the mouse is not over
14055 // an item. This allows the child menu to be kept open when the
14056 // mouse is over the empty part of the menu bar.
14057 if (index === -1 && this._childMenu) {
14058 return;
14059 }
14060 // Update the active index to the hovered item.
14061 this.activeIndex = index;
14062 // Open the new menu if a menu is already open.
14063 if (this._childMenu) {
14064 this._openChildMenu();
14065 }
14066 };
14067 /**
14068 * Handle the `'mouseleave'` event for the menu bar.
14069 */
14070 MenuBar.prototype._evtMouseLeave = function (event) {
14071 // Reset the active index if there is no open menu.
14072 if (!this._childMenu) {
14073 this.activeIndex = -1;
14074 }
14075 };
14076 /**
14077 * Open the child menu at the active index immediately.
14078 *
14079 * If a different child menu is already open, it will be closed,
14080 * even if there is no active menu.
14081 */
14082 MenuBar.prototype._openChildMenu = function () {
14083 // If there is no active menu, close the current menu.
14084 var newMenu = this.activeMenu;
14085 if (!newMenu) {
14086 this._closeChildMenu();
14087 return;
14088 }
14089 // Bail if there is no effective menu change.
14090 var oldMenu = this._childMenu;
14091 if (oldMenu === newMenu) {
14092 return;
14093 }
14094 // Swap the internal menu reference.
14095 this._childMenu = newMenu;
14096 // Close the current menu, or setup for the new menu.
14097 if (oldMenu) {
14098 oldMenu.close();
14099 }
14100 else {
14101 this.addClass('lm-mod-active');
14102 /* <DEPRECATED> */
14103 this.addClass('p-mod-active');
14104 /* </DEPRECATED> */
14105 document.addEventListener('mousedown', this, true);
14106 }
14107 // Ensure the menu bar is updated and look up the item node.
14108 MessageLoop.sendMessage(this, Widget.Msg.UpdateRequest);
14109 var itemNode = this.contentNode.children[this._activeIndex];
14110 // Get the positioning data for the new menu.
14111 var _a = itemNode.getBoundingClientRect(), left = _a.left, bottom = _a.bottom;
14112 // Open the new menu at the computed location.
14113 if (newMenu.items.length > 0) {
14114 newMenu.open(left, bottom, this._forceItemsPosition);
14115 }
14116 };
14117 /**
14118 * Close the child menu immediately.
14119 *
14120 * This is a no-op if a child menu is not open.
14121 */
14122 MenuBar.prototype._closeChildMenu = function () {
14123 // Bail if no child menu is open.
14124 if (!this._childMenu) {
14125 return;
14126 }
14127 // Remove the active class from the menu bar.
14128 this.removeClass('lm-mod-active');
14129 /* <DEPRECATED> */
14130 this.removeClass('p-mod-active');
14131 /* </DEPRECATED> */
14132 // Remove the document listeners.
14133 document.removeEventListener('mousedown', this, true);
14134 // Clear the internal menu reference.
14135 var menu = this._childMenu;
14136 this._childMenu = null;
14137 // Close the menu.
14138 menu.close();
14139 // Reset the active index.
14140 this.activeIndex = -1;
14141 };
14142 /**
14143 * Handle the `aboutToClose` signal of a menu.
14144 */
14145 MenuBar.prototype._onMenuAboutToClose = function (sender) {
14146 // Bail if the sender is not the child menu.
14147 if (sender !== this._childMenu) {
14148 return;
14149 }
14150 // Remove the active class from the menu bar.
14151 this.removeClass('lm-mod-active');
14152 /* <DEPRECATED> */
14153 this.removeClass('p-mod-active');
14154 /* </DEPRECATED> */
14155 // Remove the document listeners.
14156 document.removeEventListener('mousedown', this, true);
14157 // Clear the internal menu reference.
14158 this._childMenu = null;
14159 // Reset the active index.
14160 this.activeIndex = -1;
14161 };
14162 /**
14163 * Handle the `menuRequested` signal of a child menu.
14164 */
14165 MenuBar.prototype._onMenuMenuRequested = function (sender, args) {
14166 // Bail if the sender is not the child menu.
14167 if (sender !== this._childMenu) {
14168 return;
14169 }
14170 // Look up the active index and menu count.
14171 var i = this._activeIndex;
14172 var n = this._menus.length;
14173 // Active the next requested index.
14174 switch (args) {
14175 case 'next':
14176 this.activeIndex = i === n - 1 ? 0 : i + 1;
14177 break;
14178 case 'previous':
14179 this.activeIndex = i === 0 ? n - 1 : i - 1;
14180 break;
14181 }
14182 // Open the active menu.
14183 this.openActiveMenu();
14184 };
14185 /**
14186 * Handle the `changed` signal of a title object.
14187 */
14188 MenuBar.prototype._onTitleChanged = function () {
14189 this.update();
14190 };
14191 return MenuBar;
14192}(Widget));
14193/**
14194 * The namespace for the `MenuBar` class statics.
14195 */
14196(function (MenuBar) {
14197 /**
14198 * The default implementation of `IRenderer`.
14199 *
14200 * #### Notes
14201 * Subclasses are free to reimplement rendering methods as needed.
14202 */
14203 var Renderer = /** @class */ (function () {
14204 function Renderer() {
14205 }
14206 /**
14207 * Render the virtual element for a menu bar item.
14208 *
14209 * @param data - The data to use for rendering the item.
14210 *
14211 * @returns A virtual element representing the item.
14212 */
14213 Renderer.prototype.renderItem = function (data) {
14214 var className = this.createItemClass(data);
14215 var dataset = this.createItemDataset(data);
14216 var aria = this.createItemARIA(data);
14217 return h.li(__assign({ className: className, dataset: dataset, tabindex: '0', onfocus: data.onfocus }, aria), this.renderIcon(data), this.renderLabel(data));
14218 };
14219 /**
14220 * Render the icon element for a menu bar item.
14221 *
14222 * @param data - The data to use for rendering the icon.
14223 *
14224 * @returns A virtual element representing the item icon.
14225 */
14226 Renderer.prototype.renderIcon = function (data) {
14227 var className = this.createIconClass(data);
14228 /* <DEPRECATED> */
14229 if (typeof data.title.icon === 'string') {
14230 return h.div({ className: className }, data.title.iconLabel);
14231 }
14232 /* </DEPRECATED> */
14233 // if data.title.icon is undefined, it will be ignored
14234 return h.div({ className: className }, data.title.icon, data.title.iconLabel);
14235 };
14236 /**
14237 * Render the label element for a menu item.
14238 *
14239 * @param data - The data to use for rendering the label.
14240 *
14241 * @returns A virtual element representing the item label.
14242 */
14243 Renderer.prototype.renderLabel = function (data) {
14244 var content = this.formatLabel(data);
14245 return h.div({
14246 className: 'lm-MenuBar-itemLabel' +
14247 /* <DEPRECATED> */
14248 ' p-MenuBar-itemLabel'
14249 /* </DEPRECATED> */
14250 }, content);
14251 };
14252 /**
14253 * Create the class name for the menu bar item.
14254 *
14255 * @param data - The data to use for the class name.
14256 *
14257 * @returns The full class name for the menu item.
14258 */
14259 Renderer.prototype.createItemClass = function (data) {
14260 var name = 'lm-MenuBar-item';
14261 /* <DEPRECATED> */
14262 name += ' p-MenuBar-item';
14263 /* </DEPRECATED> */
14264 if (data.title.className) {
14265 name += " " + data.title.className;
14266 }
14267 if (data.active) {
14268 name += ' lm-mod-active';
14269 /* <DEPRECATED> */
14270 name += ' p-mod-active';
14271 /* </DEPRECATED> */
14272 }
14273 return name;
14274 };
14275 /**
14276 * Create the dataset for a menu bar item.
14277 *
14278 * @param data - The data to use for the item.
14279 *
14280 * @returns The dataset for the menu bar item.
14281 */
14282 Renderer.prototype.createItemDataset = function (data) {
14283 return data.title.dataset;
14284 };
14285 /**
14286 * Create the aria attributes for menu bar item.
14287 *
14288 * @param data - The data to use for the aria attributes.
14289 *
14290 * @returns The aria attributes object for the item.
14291 */
14292 Renderer.prototype.createItemARIA = function (data) {
14293 return { role: 'menuitem', 'aria-haspopup': 'true' };
14294 };
14295 /**
14296 * Create the class name for the menu bar item icon.
14297 *
14298 * @param data - The data to use for the class name.
14299 *
14300 * @returns The full class name for the item icon.
14301 */
14302 Renderer.prototype.createIconClass = function (data) {
14303 var name = 'lm-MenuBar-itemIcon';
14304 /* <DEPRECATED> */
14305 name += ' p-MenuBar-itemIcon';
14306 /* </DEPRECATED> */
14307 var extra = data.title.iconClass;
14308 return extra ? name + " " + extra : name;
14309 };
14310 /**
14311 * Create the render content for the label node.
14312 *
14313 * @param data - The data to use for the label content.
14314 *
14315 * @returns The content to add to the label node.
14316 */
14317 Renderer.prototype.formatLabel = function (data) {
14318 // Fetch the label text and mnemonic index.
14319 var _a = data.title, label = _a.label, mnemonic = _a.mnemonic;
14320 // If the index is out of range, do not modify the label.
14321 if (mnemonic < 0 || mnemonic >= label.length) {
14322 return label;
14323 }
14324 // Split the label into parts.
14325 var prefix = label.slice(0, mnemonic);
14326 var suffix = label.slice(mnemonic + 1);
14327 var char = label[mnemonic];
14328 // Wrap the mnemonic character in a span.
14329 var span = h.span({
14330 className: 'lm-MenuBar-itemMnemonic' +
14331 /* <DEPRECATED> */
14332 ' p-MenuBar-itemMnemonic'
14333 /* </DEPRECATED> */
14334 }, char);
14335 // Return the content parts.
14336 return [prefix, span, suffix];
14337 };
14338 return Renderer;
14339 }());
14340 MenuBar.Renderer = Renderer;
14341 /**
14342 * The default `Renderer` instance.
14343 */
14344 MenuBar.defaultRenderer = new Renderer();
14345})(MenuBar || (MenuBar = {}));
14346/**
14347 * The namespace for the module implementation details.
14348 */
14349var Private$3;
14350(function (Private) {
14351 /**
14352 * Create the DOM node for a menu bar.
14353 */
14354 function createNode() {
14355 var node = document.createElement('div');
14356 var content = document.createElement('ul');
14357 content.className = 'lm-MenuBar-content';
14358 /* <DEPRECATED> */
14359 content.classList.add('p-MenuBar-content');
14360 /* </DEPRECATED> */
14361 node.appendChild(content);
14362 content.setAttribute('role', 'menubar');
14363 node.tabIndex = 0;
14364 content.tabIndex = 0;
14365 return node;
14366 }
14367 Private.createNode = createNode;
14368 /**
14369 * Find the best matching mnemonic item.
14370 *
14371 * The search starts at the given index and wraps around.
14372 */
14373 function findMnemonic(menus, key, start) {
14374 // Setup the result variables.
14375 var index = -1;
14376 var auto = -1;
14377 var multiple = false;
14378 // Normalize the key to upper case.
14379 var upperKey = key.toUpperCase();
14380 // Search the items from the given start index.
14381 for (var i = 0, n = menus.length; i < n; ++i) {
14382 // Compute the wrapped index.
14383 var k = (i + start) % n;
14384 // Look up the menu title.
14385 var title = menus[k].title;
14386 // Ignore titles with an empty label.
14387 if (title.label.length === 0) {
14388 continue;
14389 }
14390 // Look up the mnemonic index for the label.
14391 var mn = title.mnemonic;
14392 // Handle a valid mnemonic index.
14393 if (mn >= 0 && mn < title.label.length) {
14394 if (title.label[mn].toUpperCase() === upperKey) {
14395 if (index === -1) {
14396 index = k;
14397 }
14398 else {
14399 multiple = true;
14400 }
14401 }
14402 continue;
14403 }
14404 // Finally, handle the auto index if possible.
14405 if (auto === -1 && title.label[0].toUpperCase() === upperKey) {
14406 auto = k;
14407 }
14408 }
14409 // Return the search results.
14410 return { index: index, multiple: multiple, auto: auto };
14411 }
14412 Private.findMnemonic = findMnemonic;
14413})(Private$3 || (Private$3 = {}));
14414
14415/**
14416 * A widget which implements a canonical scroll bar.
14417 */
14418var ScrollBar = /** @class */ (function (_super) {
14419 __extends(ScrollBar, _super);
14420 /**
14421 * Construct a new scroll bar.
14422 *
14423 * @param options - The options for initializing the scroll bar.
14424 */
14425 function ScrollBar(options) {
14426 if (options === void 0) { options = {}; }
14427 var _this = _super.call(this, { node: Private$2.createNode() }) || this;
14428 /**
14429 * A timeout callback for repeating the mouse press.
14430 */
14431 _this._onRepeat = function () {
14432 // Clear the repeat timer id.
14433 _this._repeatTimer = -1;
14434 // Bail if the mouse has been released.
14435 if (!_this._pressData) {
14436 return;
14437 }
14438 // Look up the part that was pressed.
14439 var part = _this._pressData.part;
14440 // Bail if the thumb was pressed.
14441 if (part === 'thumb') {
14442 return;
14443 }
14444 // Schedule the timer for another repeat.
14445 _this._repeatTimer = window.setTimeout(_this._onRepeat, 20);
14446 // Get the current mouse position.
14447 var mouseX = _this._pressData.mouseX;
14448 var mouseY = _this._pressData.mouseY;
14449 // Handle a decrement button repeat.
14450 if (part === 'decrement') {
14451 // Bail if the mouse is not over the button.
14452 if (!ElementExt.hitTest(_this.decrementNode, mouseX, mouseY)) {
14453 return;
14454 }
14455 // Emit the step requested signal.
14456 _this._stepRequested.emit('decrement');
14457 // Finished.
14458 return;
14459 }
14460 // Handle an increment button repeat.
14461 if (part === 'increment') {
14462 // Bail if the mouse is not over the button.
14463 if (!ElementExt.hitTest(_this.incrementNode, mouseX, mouseY)) {
14464 return;
14465 }
14466 // Emit the step requested signal.
14467 _this._stepRequested.emit('increment');
14468 // Finished.
14469 return;
14470 }
14471 // Handle a track repeat.
14472 if (part === 'track') {
14473 // Bail if the mouse is not over the track.
14474 if (!ElementExt.hitTest(_this.trackNode, mouseX, mouseY)) {
14475 return;
14476 }
14477 // Fetch the thumb node.
14478 var thumbNode = _this.thumbNode;
14479 // Bail if the mouse is over the thumb.
14480 if (ElementExt.hitTest(thumbNode, mouseX, mouseY)) {
14481 return;
14482 }
14483 // Fetch the client rect for the thumb.
14484 var thumbRect = thumbNode.getBoundingClientRect();
14485 // Determine the direction for the page request.
14486 var dir = void 0;
14487 if (_this._orientation === 'horizontal') {
14488 dir = mouseX < thumbRect.left ? 'decrement' : 'increment';
14489 }
14490 else {
14491 dir = mouseY < thumbRect.top ? 'decrement' : 'increment';
14492 }
14493 // Emit the page requested signal.
14494 _this._pageRequested.emit(dir);
14495 // Finished.
14496 return;
14497 }
14498 };
14499 _this._value = 0;
14500 _this._page = 10;
14501 _this._maximum = 100;
14502 _this._repeatTimer = -1;
14503 _this._pressData = null;
14504 _this._thumbMoved = new Signal(_this);
14505 _this._stepRequested = new Signal(_this);
14506 _this._pageRequested = new Signal(_this);
14507 _this.addClass('lm-ScrollBar');
14508 /* <DEPRECATED> */
14509 _this.addClass('p-ScrollBar');
14510 /* </DEPRECATED> */
14511 _this.setFlag(Widget.Flag.DisallowLayout);
14512 // Set the orientation.
14513 _this._orientation = options.orientation || 'vertical';
14514 _this.dataset['orientation'] = _this._orientation;
14515 // Parse the rest of the options.
14516 if (options.maximum !== undefined) {
14517 _this._maximum = Math.max(0, options.maximum);
14518 }
14519 if (options.page !== undefined) {
14520 _this._page = Math.max(0, options.page);
14521 }
14522 if (options.value !== undefined) {
14523 _this._value = Math.max(0, Math.min(options.value, _this._maximum));
14524 }
14525 return _this;
14526 }
14527 Object.defineProperty(ScrollBar.prototype, "thumbMoved", {
14528 /**
14529 * A signal emitted when the user moves the scroll thumb.
14530 *
14531 * #### Notes
14532 * The payload is the current value of the scroll bar.
14533 */
14534 get: function () {
14535 return this._thumbMoved;
14536 },
14537 enumerable: true,
14538 configurable: true
14539 });
14540 Object.defineProperty(ScrollBar.prototype, "stepRequested", {
14541 /**
14542 * A signal emitted when the user clicks a step button.
14543 *
14544 * #### Notes
14545 * The payload is whether a decrease or increase is requested.
14546 */
14547 get: function () {
14548 return this._stepRequested;
14549 },
14550 enumerable: true,
14551 configurable: true
14552 });
14553 Object.defineProperty(ScrollBar.prototype, "pageRequested", {
14554 /**
14555 * A signal emitted when the user clicks the scroll track.
14556 *
14557 * #### Notes
14558 * The payload is whether a decrease or increase is requested.
14559 */
14560 get: function () {
14561 return this._pageRequested;
14562 },
14563 enumerable: true,
14564 configurable: true
14565 });
14566 Object.defineProperty(ScrollBar.prototype, "orientation", {
14567 /**
14568 * Get the orientation of the scroll bar.
14569 */
14570 get: function () {
14571 return this._orientation;
14572 },
14573 /**
14574 * Set the orientation of the scroll bar.
14575 */
14576 set: function (value) {
14577 // Do nothing if the orientation does not change.
14578 if (this._orientation === value) {
14579 return;
14580 }
14581 // Release the mouse before making changes.
14582 this._releaseMouse();
14583 // Update the internal orientation.
14584 this._orientation = value;
14585 this.dataset['orientation'] = value;
14586 // Schedule an update the scroll bar.
14587 this.update();
14588 },
14589 enumerable: true,
14590 configurable: true
14591 });
14592 Object.defineProperty(ScrollBar.prototype, "value", {
14593 /**
14594 * Get the current value of the scroll bar.
14595 */
14596 get: function () {
14597 return this._value;
14598 },
14599 /**
14600 * Set the current value of the scroll bar.
14601 *
14602 * #### Notes
14603 * The value will be clamped to the range `[0, maximum]`.
14604 */
14605 set: function (value) {
14606 // Clamp the value to the allowable range.
14607 value = Math.max(0, Math.min(value, this._maximum));
14608 // Do nothing if the value does not change.
14609 if (this._value === value) {
14610 return;
14611 }
14612 // Update the internal value.
14613 this._value = value;
14614 // Schedule an update the scroll bar.
14615 this.update();
14616 },
14617 enumerable: true,
14618 configurable: true
14619 });
14620 Object.defineProperty(ScrollBar.prototype, "page", {
14621 /**
14622 * Get the page size of the scroll bar.
14623 *
14624 * #### Notes
14625 * The page size is the amount of visible content in the scrolled
14626 * region, expressed in data units. It determines the size of the
14627 * scroll bar thumb.
14628 */
14629 get: function () {
14630 return this._page;
14631 },
14632 /**
14633 * Set the page size of the scroll bar.
14634 *
14635 * #### Notes
14636 * The page size will be clamped to the range `[0, Infinity]`.
14637 */
14638 set: function (value) {
14639 // Clamp the page size to the allowable range.
14640 value = Math.max(0, value);
14641 // Do nothing if the value does not change.
14642 if (this._page === value) {
14643 return;
14644 }
14645 // Update the internal page size.
14646 this._page = value;
14647 // Schedule an update the scroll bar.
14648 this.update();
14649 },
14650 enumerable: true,
14651 configurable: true
14652 });
14653 Object.defineProperty(ScrollBar.prototype, "maximum", {
14654 /**
14655 * Get the maximum value of the scroll bar.
14656 */
14657 get: function () {
14658 return this._maximum;
14659 },
14660 /**
14661 * Set the maximum value of the scroll bar.
14662 *
14663 * #### Notes
14664 * The max size will be clamped to the range `[0, Infinity]`.
14665 */
14666 set: function (value) {
14667 // Clamp the value to the allowable range.
14668 value = Math.max(0, value);
14669 // Do nothing if the value does not change.
14670 if (this._maximum === value) {
14671 return;
14672 }
14673 // Update the internal values.
14674 this._maximum = value;
14675 // Clamp the current value to the new range.
14676 this._value = Math.min(this._value, value);
14677 // Schedule an update the scroll bar.
14678 this.update();
14679 },
14680 enumerable: true,
14681 configurable: true
14682 });
14683 Object.defineProperty(ScrollBar.prototype, "decrementNode", {
14684 /**
14685 * The scroll bar decrement button node.
14686 *
14687 * #### Notes
14688 * Modifying this node directly can lead to undefined behavior.
14689 */
14690 get: function () {
14691 return this.node.getElementsByClassName('lm-ScrollBar-button')[0];
14692 },
14693 enumerable: true,
14694 configurable: true
14695 });
14696 Object.defineProperty(ScrollBar.prototype, "incrementNode", {
14697 /**
14698 * The scroll bar increment button node.
14699 *
14700 * #### Notes
14701 * Modifying this node directly can lead to undefined behavior.
14702 */
14703 get: function () {
14704 return this.node.getElementsByClassName('lm-ScrollBar-button')[1];
14705 },
14706 enumerable: true,
14707 configurable: true
14708 });
14709 Object.defineProperty(ScrollBar.prototype, "trackNode", {
14710 /**
14711 * The scroll bar track node.
14712 *
14713 * #### Notes
14714 * Modifying this node directly can lead to undefined behavior.
14715 */
14716 get: function () {
14717 return this.node.getElementsByClassName('lm-ScrollBar-track')[0];
14718 },
14719 enumerable: true,
14720 configurable: true
14721 });
14722 Object.defineProperty(ScrollBar.prototype, "thumbNode", {
14723 /**
14724 * The scroll bar thumb node.
14725 *
14726 * #### Notes
14727 * Modifying this node directly can lead to undefined behavior.
14728 */
14729 get: function () {
14730 return this.node.getElementsByClassName('lm-ScrollBar-thumb')[0];
14731 },
14732 enumerable: true,
14733 configurable: true
14734 });
14735 /**
14736 * Handle the DOM events for the scroll bar.
14737 *
14738 * @param event - The DOM event sent to the scroll bar.
14739 *
14740 * #### Notes
14741 * This method implements the DOM `EventListener` interface and is
14742 * called in response to events on the scroll bar's DOM node.
14743 *
14744 * This should not be called directly by user code.
14745 */
14746 ScrollBar.prototype.handleEvent = function (event) {
14747 switch (event.type) {
14748 case 'mousedown':
14749 this._evtMouseDown(event);
14750 break;
14751 case 'mousemove':
14752 this._evtMouseMove(event);
14753 break;
14754 case 'mouseup':
14755 this._evtMouseUp(event);
14756 break;
14757 case 'keydown':
14758 this._evtKeyDown(event);
14759 break;
14760 case 'contextmenu':
14761 event.preventDefault();
14762 event.stopPropagation();
14763 break;
14764 }
14765 };
14766 /**
14767 * A method invoked on a 'before-attach' message.
14768 */
14769 ScrollBar.prototype.onBeforeAttach = function (msg) {
14770 this.node.addEventListener('mousedown', this);
14771 this.update();
14772 };
14773 /**
14774 * A method invoked on an 'after-detach' message.
14775 */
14776 ScrollBar.prototype.onAfterDetach = function (msg) {
14777 this.node.removeEventListener('mousedown', this);
14778 this._releaseMouse();
14779 };
14780 /**
14781 * A method invoked on an 'update-request' message.
14782 */
14783 ScrollBar.prototype.onUpdateRequest = function (msg) {
14784 // Convert the value and page into percentages.
14785 var value = (this._value * 100) / this._maximum;
14786 var page = (this._page * 100) / (this._page + this._maximum);
14787 // Clamp the value and page to the relevant range.
14788 value = Math.max(0, Math.min(value, 100));
14789 page = Math.max(0, Math.min(page, 100));
14790 // Fetch the thumb style.
14791 var thumbStyle = this.thumbNode.style;
14792 // Update the thumb style for the current orientation.
14793 if (this._orientation === 'horizontal') {
14794 thumbStyle.top = '';
14795 thumbStyle.height = '';
14796 thumbStyle.left = value + "%";
14797 thumbStyle.width = page + "%";
14798 thumbStyle.transform = "translate(" + -value + "%, 0%)";
14799 }
14800 else {
14801 thumbStyle.left = '';
14802 thumbStyle.width = '';
14803 thumbStyle.top = value + "%";
14804 thumbStyle.height = page + "%";
14805 thumbStyle.transform = "translate(0%, " + -value + "%)";
14806 }
14807 };
14808 /**
14809 * Handle the `'keydown'` event for the scroll bar.
14810 */
14811 ScrollBar.prototype._evtKeyDown = function (event) {
14812 // Stop all input events during drag.
14813 event.preventDefault();
14814 event.stopPropagation();
14815 // Ignore anything except the `Escape` key.
14816 if (event.keyCode !== 27) {
14817 return;
14818 }
14819 // Fetch the previous scroll value.
14820 var value = this._pressData ? this._pressData.value : -1;
14821 // Release the mouse.
14822 this._releaseMouse();
14823 // Restore the old scroll value if possible.
14824 if (value !== -1) {
14825 this._moveThumb(value);
14826 }
14827 };
14828 /**
14829 * Handle the `'mousedown'` event for the scroll bar.
14830 */
14831 ScrollBar.prototype._evtMouseDown = function (event) {
14832 // Do nothing if it's not a left mouse press.
14833 if (event.button !== 0) {
14834 return;
14835 }
14836 // Send an activate request to the scroll bar. This can be
14837 // used by message hooks to activate something relevant.
14838 this.activate();
14839 // Do nothing if the mouse is already captured.
14840 if (this._pressData) {
14841 return;
14842 }
14843 // Find the pressed scroll bar part.
14844 var part = Private$2.findPart(this, event.target);
14845 // Do nothing if the part is not of interest.
14846 if (!part) {
14847 return;
14848 }
14849 // Stop the event propagation.
14850 event.preventDefault();
14851 event.stopPropagation();
14852 // Override the mouse cursor.
14853 var override = Drag.overrideCursor('default');
14854 // Set up the press data.
14855 this._pressData = {
14856 part: part,
14857 override: override,
14858 delta: -1,
14859 value: -1,
14860 mouseX: event.clientX,
14861 mouseY: event.clientY
14862 };
14863 // Add the extra event listeners.
14864 document.addEventListener('mousemove', this, true);
14865 document.addEventListener('mouseup', this, true);
14866 document.addEventListener('keydown', this, true);
14867 document.addEventListener('contextmenu', this, true);
14868 // Handle a thumb press.
14869 if (part === 'thumb') {
14870 // Fetch the thumb node.
14871 var thumbNode = this.thumbNode;
14872 // Fetch the client rect for the thumb.
14873 var thumbRect = thumbNode.getBoundingClientRect();
14874 // Update the press data delta for the current orientation.
14875 if (this._orientation === 'horizontal') {
14876 this._pressData.delta = event.clientX - thumbRect.left;
14877 }
14878 else {
14879 this._pressData.delta = event.clientY - thumbRect.top;
14880 }
14881 // Add the active class to the thumb node.
14882 thumbNode.classList.add('lm-mod-active');
14883 /* <DEPRECATED> */
14884 thumbNode.classList.add('p-mod-active');
14885 /* </DEPRECATED> */
14886 // Store the current value in the press data.
14887 this._pressData.value = this._value;
14888 // Finished.
14889 return;
14890 }
14891 // Handle a track press.
14892 if (part === 'track') {
14893 // Fetch the client rect for the thumb.
14894 var thumbRect = this.thumbNode.getBoundingClientRect();
14895 // Determine the direction for the page request.
14896 var dir = void 0;
14897 if (this._orientation === 'horizontal') {
14898 dir = event.clientX < thumbRect.left ? 'decrement' : 'increment';
14899 }
14900 else {
14901 dir = event.clientY < thumbRect.top ? 'decrement' : 'increment';
14902 }
14903 // Start the repeat timer.
14904 this._repeatTimer = window.setTimeout(this._onRepeat, 350);
14905 // Emit the page requested signal.
14906 this._pageRequested.emit(dir);
14907 // Finished.
14908 return;
14909 }
14910 // Handle a decrement button press.
14911 if (part === 'decrement') {
14912 // Add the active class to the decrement node.
14913 this.decrementNode.classList.add('lm-mod-active');
14914 /* <DEPRECATED> */
14915 this.decrementNode.classList.add('p-mod-active');
14916 /* </DEPRECATED> */
14917 // Start the repeat timer.
14918 this._repeatTimer = window.setTimeout(this._onRepeat, 350);
14919 // Emit the step requested signal.
14920 this._stepRequested.emit('decrement');
14921 // Finished.
14922 return;
14923 }
14924 // Handle an increment button press.
14925 if (part === 'increment') {
14926 // Add the active class to the increment node.
14927 this.incrementNode.classList.add('lm-mod-active');
14928 /* <DEPRECATED> */
14929 this.incrementNode.classList.add('p-mod-active');
14930 /* </DEPRECATED> */
14931 // Start the repeat timer.
14932 this._repeatTimer = window.setTimeout(this._onRepeat, 350);
14933 // Emit the step requested signal.
14934 this._stepRequested.emit('increment');
14935 // Finished.
14936 return;
14937 }
14938 };
14939 /**
14940 * Handle the `'mousemove'` event for the scroll bar.
14941 */
14942 ScrollBar.prototype._evtMouseMove = function (event) {
14943 // Do nothing if no drag is in progress.
14944 if (!this._pressData) {
14945 return;
14946 }
14947 // Stop the event propagation.
14948 event.preventDefault();
14949 event.stopPropagation();
14950 // Update the mouse position.
14951 this._pressData.mouseX = event.clientX;
14952 this._pressData.mouseY = event.clientY;
14953 // Bail if the thumb is not being dragged.
14954 if (this._pressData.part !== 'thumb') {
14955 return;
14956 }
14957 // Get the client rect for the thumb and track.
14958 var thumbRect = this.thumbNode.getBoundingClientRect();
14959 var trackRect = this.trackNode.getBoundingClientRect();
14960 // Fetch the scroll geometry based on the orientation.
14961 var trackPos;
14962 var trackSpan;
14963 if (this._orientation === 'horizontal') {
14964 trackPos = event.clientX - trackRect.left - this._pressData.delta;
14965 trackSpan = trackRect.width - thumbRect.width;
14966 }
14967 else {
14968 trackPos = event.clientY - trackRect.top - this._pressData.delta;
14969 trackSpan = trackRect.height - thumbRect.height;
14970 }
14971 // Compute the desired value from the scroll geometry.
14972 var value = trackSpan === 0 ? 0 : (trackPos * this._maximum) / trackSpan;
14973 // Move the thumb to the computed value.
14974 this._moveThumb(value);
14975 };
14976 /**
14977 * Handle the `'mouseup'` event for the scroll bar.
14978 */
14979 ScrollBar.prototype._evtMouseUp = function (event) {
14980 // Do nothing if it's not a left mouse release.
14981 if (event.button !== 0) {
14982 return;
14983 }
14984 // Stop the event propagation.
14985 event.preventDefault();
14986 event.stopPropagation();
14987 // Release the mouse.
14988 this._releaseMouse();
14989 };
14990 /**
14991 * Release the mouse and restore the node states.
14992 */
14993 ScrollBar.prototype._releaseMouse = function () {
14994 // Bail if there is no press data.
14995 if (!this._pressData) {
14996 return;
14997 }
14998 // Clear the repeat timer.
14999 clearTimeout(this._repeatTimer);
15000 this._repeatTimer = -1;
15001 // Clear the press data.
15002 this._pressData.override.dispose();
15003 this._pressData = null;
15004 // Remove the extra event listeners.
15005 document.removeEventListener('mousemove', this, true);
15006 document.removeEventListener('mouseup', this, true);
15007 document.removeEventListener('keydown', this, true);
15008 document.removeEventListener('contextmenu', this, true);
15009 // Remove the active classes from the nodes.
15010 this.thumbNode.classList.remove('lm-mod-active');
15011 this.decrementNode.classList.remove('lm-mod-active');
15012 this.incrementNode.classList.remove('lm-mod-active');
15013 /* <DEPRECATED> */
15014 this.thumbNode.classList.remove('p-mod-active');
15015 this.decrementNode.classList.remove('p-mod-active');
15016 this.incrementNode.classList.remove('p-mod-active');
15017 /* </DEPRECATED> */
15018 };
15019 /**
15020 * Move the thumb to the specified position.
15021 */
15022 ScrollBar.prototype._moveThumb = function (value) {
15023 // Clamp the value to the allowed range.
15024 value = Math.max(0, Math.min(value, this._maximum));
15025 // Bail if the value does not change.
15026 if (this._value === value) {
15027 return;
15028 }
15029 // Update the internal value.
15030 this._value = value;
15031 // Schedule an update of the scroll bar.
15032 this.update();
15033 // Emit the thumb moved signal.
15034 this._thumbMoved.emit(value);
15035 };
15036 return ScrollBar;
15037}(Widget));
15038/**
15039 * The namespace for the module implementation details.
15040 */
15041var Private$2;
15042(function (Private) {
15043 /**
15044 * Create the DOM node for a scroll bar.
15045 */
15046 function createNode() {
15047 var node = document.createElement('div');
15048 var decrement = document.createElement('div');
15049 var increment = document.createElement('div');
15050 var track = document.createElement('div');
15051 var thumb = document.createElement('div');
15052 decrement.className = 'lm-ScrollBar-button';
15053 increment.className = 'lm-ScrollBar-button';
15054 decrement.dataset['action'] = 'decrement';
15055 increment.dataset['action'] = 'increment';
15056 track.className = 'lm-ScrollBar-track';
15057 thumb.className = 'lm-ScrollBar-thumb';
15058 /* <DEPRECATED> */
15059 decrement.classList.add('p-ScrollBar-button');
15060 increment.classList.add('p-ScrollBar-button');
15061 track.classList.add('p-ScrollBar-track');
15062 thumb.classList.add('p-ScrollBar-thumb');
15063 /* </DEPRECATED> */
15064 track.appendChild(thumb);
15065 node.appendChild(decrement);
15066 node.appendChild(track);
15067 node.appendChild(increment);
15068 return node;
15069 }
15070 Private.createNode = createNode;
15071 /**
15072 * Find the scroll bar part which contains the given target.
15073 */
15074 function findPart(scrollBar, target) {
15075 // Test the thumb.
15076 if (scrollBar.thumbNode.contains(target)) {
15077 return 'thumb';
15078 }
15079 // Test the track.
15080 if (scrollBar.trackNode.contains(target)) {
15081 return 'track';
15082 }
15083 // Test the decrement button.
15084 if (scrollBar.decrementNode.contains(target)) {
15085 return 'decrement';
15086 }
15087 // Test the increment button.
15088 if (scrollBar.incrementNode.contains(target)) {
15089 return 'increment';
15090 }
15091 // Indicate no match.
15092 return null;
15093 }
15094 Private.findPart = findPart;
15095})(Private$2 || (Private$2 = {}));
15096
15097/**
15098 * A concrete layout implementation which holds a single widget.
15099 *
15100 * #### Notes
15101 * This class is useful for creating simple container widgets which
15102 * hold a single child. The child should be positioned with CSS.
15103 */
15104var SingletonLayout = /** @class */ (function (_super) {
15105 __extends(SingletonLayout, _super);
15106 function SingletonLayout() {
15107 var _this = _super !== null && _super.apply(this, arguments) || this;
15108 _this._widget = null;
15109 return _this;
15110 }
15111 /**
15112 * Dispose of the resources held by the layout.
15113 */
15114 SingletonLayout.prototype.dispose = function () {
15115 if (this._widget) {
15116 var widget = this._widget;
15117 this._widget = null;
15118 widget.dispose();
15119 }
15120 _super.prototype.dispose.call(this);
15121 };
15122 Object.defineProperty(SingletonLayout.prototype, "widget", {
15123 /**
15124 * Get the child widget for the layout.
15125 */
15126 get: function () {
15127 return this._widget;
15128 },
15129 /**
15130 * Set the child widget for the layout.
15131 *
15132 * #### Notes
15133 * Setting the child widget will cause the old child widget to be
15134 * automatically disposed. If that is not desired, set the parent
15135 * of the old child to `null` before assigning a new child.
15136 */
15137 set: function (widget) {
15138 // Remove the widget from its current parent. This is a no-op
15139 // if the widget's parent is already the layout parent widget.
15140 if (widget) {
15141 widget.parent = this.parent;
15142 }
15143 // Bail early if the widget does not change.
15144 if (this._widget === widget) {
15145 return;
15146 }
15147 // Dispose of the old child widget.
15148 if (this._widget) {
15149 this._widget.dispose();
15150 }
15151 // Update the internal widget.
15152 this._widget = widget;
15153 // Attach the new child widget if needed.
15154 if (this.parent && widget) {
15155 this.attachWidget(widget);
15156 }
15157 },
15158 enumerable: true,
15159 configurable: true
15160 });
15161 /**
15162 * Create an iterator over the widgets in the layout.
15163 *
15164 * @returns A new iterator over the widgets in the layout.
15165 */
15166 SingletonLayout.prototype.iter = function () {
15167 return this._widget ? once(this._widget) : empty();
15168 };
15169 /**
15170 * Remove a widget from the layout.
15171 *
15172 * @param widget - The widget to remove from the layout.
15173 *
15174 * #### Notes
15175 * A widget is automatically removed from the layout when its `parent`
15176 * is set to `null`. This method should only be invoked directly when
15177 * removing a widget from a layout which has yet to be installed on a
15178 * parent widget.
15179 *
15180 * This method does *not* modify the widget's `parent`.
15181 */
15182 SingletonLayout.prototype.removeWidget = function (widget) {
15183 // Bail early if the widget does not exist in the layout.
15184 if (this._widget !== widget) {
15185 return;
15186 }
15187 // Clear the internal widget.
15188 this._widget = null;
15189 // If the layout is parented, detach the widget from the DOM.
15190 if (this.parent) {
15191 this.detachWidget(widget);
15192 }
15193 };
15194 /**
15195 * Perform layout initialization which requires the parent widget.
15196 */
15197 SingletonLayout.prototype.init = function () {
15198 var _this = this;
15199 _super.prototype.init.call(this);
15200 each(this, function (widget) {
15201 _this.attachWidget(widget);
15202 });
15203 };
15204 /**
15205 * Attach a widget to the parent's DOM node.
15206 *
15207 * @param index - The current index of the widget in the layout.
15208 *
15209 * @param widget - The widget to attach to the parent.
15210 *
15211 * #### Notes
15212 * This method is called automatically by the single layout at the
15213 * appropriate time. It should not be called directly by user code.
15214 *
15215 * The default implementation adds the widgets's node to the parent's
15216 * node at the proper location, and sends the appropriate attach
15217 * messages to the widget if the parent is attached to the DOM.
15218 *
15219 * Subclasses may reimplement this method to control how the widget's
15220 * node is added to the parent's node.
15221 */
15222 SingletonLayout.prototype.attachWidget = function (widget) {
15223 // Send a `'before-attach'` message if the parent is attached.
15224 if (this.parent.isAttached) {
15225 MessageLoop.sendMessage(widget, Widget.Msg.BeforeAttach);
15226 }
15227 // Add the widget's node to the parent.
15228 this.parent.node.appendChild(widget.node);
15229 // Send an `'after-attach'` message if the parent is attached.
15230 if (this.parent.isAttached) {
15231 MessageLoop.sendMessage(widget, Widget.Msg.AfterAttach);
15232 }
15233 };
15234 /**
15235 * Detach a widget from the parent's DOM node.
15236 *
15237 * @param widget - The widget to detach from the parent.
15238 *
15239 * #### Notes
15240 * This method is called automatically by the single layout at the
15241 * appropriate time. It should not be called directly by user code.
15242 *
15243 * The default implementation removes the widget's node from the
15244 * parent's node, and sends the appropriate detach messages to the
15245 * widget if the parent is attached to the DOM.
15246 *
15247 * Subclasses may reimplement this method to control how the widget's
15248 * node is removed from the parent's node.
15249 */
15250 SingletonLayout.prototype.detachWidget = function (widget) {
15251 // Send a `'before-detach'` message if the parent is attached.
15252 if (this.parent.isAttached) {
15253 MessageLoop.sendMessage(widget, Widget.Msg.BeforeDetach);
15254 }
15255 // Remove the widget's node from the parent.
15256 this.parent.node.removeChild(widget.node);
15257 // Send an `'after-detach'` message if the parent is attached.
15258 if (this.parent.isAttached) {
15259 MessageLoop.sendMessage(widget, Widget.Msg.AfterDetach);
15260 }
15261 };
15262 return SingletonLayout;
15263}(Layout));
15264
15265/**
15266 * A layout where visible widgets are stacked atop one another.
15267 *
15268 * #### Notes
15269 * The Z-order of the visible widgets follows their layout order.
15270 */
15271var StackedLayout = /** @class */ (function (_super) {
15272 __extends(StackedLayout, _super);
15273 function StackedLayout(options) {
15274 if (options === void 0) { options = {}; }
15275 var _this = _super.call(this, options) || this;
15276 _this._dirty = false;
15277 _this._items = [];
15278 _this._box = null;
15279 _this._hiddenMode =
15280 options.hiddenMode !== undefined
15281 ? options.hiddenMode
15282 : Widget.HiddenMode.Display;
15283 return _this;
15284 }
15285 Object.defineProperty(StackedLayout.prototype, "hiddenMode", {
15286 /**
15287 * The method for hiding widgets.
15288 *
15289 * #### Notes
15290 * If there is only one child widget, `Display` hiding mode will be used
15291 * regardless of this setting.
15292 */
15293 get: function () {
15294 return this._hiddenMode;
15295 },
15296 /**
15297 * Set the method for hiding widgets.
15298 *
15299 * #### Notes
15300 * If there is only one child widget, `Display` hiding mode will be used
15301 * regardless of this setting.
15302 */
15303 set: function (v) {
15304 var _this = this;
15305 if (this._hiddenMode === v) {
15306 return;
15307 }
15308 this._hiddenMode = v;
15309 if (this.widgets.length > 1) {
15310 this.widgets.forEach(function (w) {
15311 w.hiddenMode = _this._hiddenMode;
15312 });
15313 }
15314 },
15315 enumerable: true,
15316 configurable: true
15317 });
15318 /**
15319 * Dispose of the resources held by the layout.
15320 */
15321 StackedLayout.prototype.dispose = function () {
15322 // Dispose of the layout items.
15323 each(this._items, function (item) {
15324 item.dispose();
15325 });
15326 // Clear the layout state.
15327 this._box = null;
15328 this._items.length = 0;
15329 // Dispose of the rest of the layout.
15330 _super.prototype.dispose.call(this);
15331 };
15332 /**
15333 * Attach a widget to the parent's DOM node.
15334 *
15335 * @param index - The current index of the widget in the layout.
15336 *
15337 * @param widget - The widget to attach to the parent.
15338 *
15339 * #### Notes
15340 * This is a reimplementation of the superclass method.
15341 */
15342 StackedLayout.prototype.attachWidget = function (index, widget) {
15343 // Using transform create an additional layer in the pixel pipeline
15344 // to limit the number of layer, it is set only if there is more than one widget.
15345 if (this._hiddenMode === Widget.HiddenMode.Scale &&
15346 this._items.length > 0) {
15347 if (this._items.length === 1) {
15348 this.widgets[0].hiddenMode = Widget.HiddenMode.Scale;
15349 }
15350 widget.hiddenMode = Widget.HiddenMode.Scale;
15351 }
15352 else {
15353 widget.hiddenMode = Widget.HiddenMode.Display;
15354 }
15355 // Create and add a new layout item for the widget.
15356 ArrayExt.insert(this._items, index, new LayoutItem(widget));
15357 // Send a `'before-attach'` message if the parent is attached.
15358 if (this.parent.isAttached) {
15359 MessageLoop.sendMessage(widget, Widget.Msg.BeforeAttach);
15360 }
15361 // Add the widget's node to the parent.
15362 this.parent.node.appendChild(widget.node);
15363 // Send an `'after-attach'` message if the parent is attached.
15364 if (this.parent.isAttached) {
15365 MessageLoop.sendMessage(widget, Widget.Msg.AfterAttach);
15366 }
15367 // Post a fit request for the parent widget.
15368 this.parent.fit();
15369 };
15370 /**
15371 * Move a widget in the parent's DOM node.
15372 *
15373 * @param fromIndex - The previous index of the widget in the layout.
15374 *
15375 * @param toIndex - The current index of the widget in the layout.
15376 *
15377 * @param widget - The widget to move in the parent.
15378 *
15379 * #### Notes
15380 * This is a reimplementation of the superclass method.
15381 */
15382 StackedLayout.prototype.moveWidget = function (fromIndex, toIndex, widget) {
15383 // Move the layout item for the widget.
15384 ArrayExt.move(this._items, fromIndex, toIndex);
15385 // Post an update request for the parent widget.
15386 this.parent.update();
15387 };
15388 /**
15389 * Detach a widget from the parent's DOM node.
15390 *
15391 * @param index - The previous index of the widget in the layout.
15392 *
15393 * @param widget - The widget to detach from the parent.
15394 *
15395 * #### Notes
15396 * This is a reimplementation of the superclass method.
15397 */
15398 StackedLayout.prototype.detachWidget = function (index, widget) {
15399 // Remove the layout item for the widget.
15400 var item = ArrayExt.removeAt(this._items, index);
15401 // Send a `'before-detach'` message if the parent is attached.
15402 if (this.parent.isAttached) {
15403 MessageLoop.sendMessage(widget, Widget.Msg.BeforeDetach);
15404 }
15405 // Remove the widget's node from the parent.
15406 this.parent.node.removeChild(widget.node);
15407 // Send an `'after-detach'` message if the parent is attached.
15408 if (this.parent.isAttached) {
15409 MessageLoop.sendMessage(widget, Widget.Msg.AfterDetach);
15410 }
15411 // Reset the z-index for the widget.
15412 item.widget.node.style.zIndex = '';
15413 // Reset the hidden mode for the widget.
15414 if (this._hiddenMode === Widget.HiddenMode.Scale) {
15415 widget.hiddenMode = Widget.HiddenMode.Display;
15416 // Reset the hidden mode for the first widget if necessary.
15417 if (this._items.length === 1) {
15418 this._items[0].widget.hiddenMode = Widget.HiddenMode.Display;
15419 }
15420 }
15421 // Dispose of the layout item.
15422 item.dispose();
15423 // Post a fit request for the parent widget.
15424 this.parent.fit();
15425 };
15426 /**
15427 * A message handler invoked on a `'before-show'` message.
15428 */
15429 StackedLayout.prototype.onBeforeShow = function (msg) {
15430 _super.prototype.onBeforeShow.call(this, msg);
15431 this.parent.update();
15432 };
15433 /**
15434 * A message handler invoked on a `'before-attach'` message.
15435 */
15436 StackedLayout.prototype.onBeforeAttach = function (msg) {
15437 _super.prototype.onBeforeAttach.call(this, msg);
15438 this.parent.fit();
15439 };
15440 /**
15441 * A message handler invoked on a `'child-shown'` message.
15442 */
15443 StackedLayout.prototype.onChildShown = function (msg) {
15444 this.parent.fit();
15445 };
15446 /**
15447 * A message handler invoked on a `'child-hidden'` message.
15448 */
15449 StackedLayout.prototype.onChildHidden = function (msg) {
15450 this.parent.fit();
15451 };
15452 /**
15453 * A message handler invoked on a `'resize'` message.
15454 */
15455 StackedLayout.prototype.onResize = function (msg) {
15456 if (this.parent.isVisible) {
15457 this._update(msg.width, msg.height);
15458 }
15459 };
15460 /**
15461 * A message handler invoked on an `'update-request'` message.
15462 */
15463 StackedLayout.prototype.onUpdateRequest = function (msg) {
15464 if (this.parent.isVisible) {
15465 this._update(-1, -1);
15466 }
15467 };
15468 /**
15469 * A message handler invoked on a `'fit-request'` message.
15470 */
15471 StackedLayout.prototype.onFitRequest = function (msg) {
15472 if (this.parent.isAttached) {
15473 this._fit();
15474 }
15475 };
15476 /**
15477 * Fit the layout to the total size required by the widgets.
15478 */
15479 StackedLayout.prototype._fit = function () {
15480 // Set up the computed minimum size.
15481 var minW = 0;
15482 var minH = 0;
15483 // Update the computed minimum size.
15484 for (var i = 0, n = this._items.length; i < n; ++i) {
15485 // Fetch the item.
15486 var item = this._items[i];
15487 // Ignore hidden items.
15488 if (item.isHidden) {
15489 continue;
15490 }
15491 // Update the size limits for the item.
15492 item.fit();
15493 // Update the computed minimum size.
15494 minW = Math.max(minW, item.minWidth);
15495 minH = Math.max(minH, item.minHeight);
15496 }
15497 // Update the box sizing and add it to the computed min size.
15498 var box = (this._box = ElementExt.boxSizing(this.parent.node));
15499 minW += box.horizontalSum;
15500 minH += box.verticalSum;
15501 // Update the parent's min size constraints.
15502 var style = this.parent.node.style;
15503 style.minWidth = minW + "px";
15504 style.minHeight = minH + "px";
15505 // Set the dirty flag to ensure only a single update occurs.
15506 this._dirty = true;
15507 // Notify the ancestor that it should fit immediately. This may
15508 // cause a resize of the parent, fulfilling the required update.
15509 if (this.parent.parent) {
15510 MessageLoop.sendMessage(this.parent.parent, Widget.Msg.FitRequest);
15511 }
15512 // If the dirty flag is still set, the parent was not resized.
15513 // Trigger the required update on the parent widget immediately.
15514 if (this._dirty) {
15515 MessageLoop.sendMessage(this.parent, Widget.Msg.UpdateRequest);
15516 }
15517 };
15518 /**
15519 * Update the layout position and size of the widgets.
15520 *
15521 * The parent offset dimensions should be `-1` if unknown.
15522 */
15523 StackedLayout.prototype._update = function (offsetWidth, offsetHeight) {
15524 // Clear the dirty flag to indicate the update occurred.
15525 this._dirty = false;
15526 // Compute the visible item count.
15527 var nVisible = 0;
15528 for (var i = 0, n = this._items.length; i < n; ++i) {
15529 nVisible += +!this._items[i].isHidden;
15530 }
15531 // Bail early if there are no visible items to layout.
15532 if (nVisible === 0) {
15533 return;
15534 }
15535 // Measure the parent if the offset dimensions are unknown.
15536 if (offsetWidth < 0) {
15537 offsetWidth = this.parent.node.offsetWidth;
15538 }
15539 if (offsetHeight < 0) {
15540 offsetHeight = this.parent.node.offsetHeight;
15541 }
15542 // Ensure the parent box sizing data is computed.
15543 if (!this._box) {
15544 this._box = ElementExt.boxSizing(this.parent.node);
15545 }
15546 // Compute the actual layout bounds adjusted for border and padding.
15547 var top = this._box.paddingTop;
15548 var left = this._box.paddingLeft;
15549 var width = offsetWidth - this._box.horizontalSum;
15550 var height = offsetHeight - this._box.verticalSum;
15551 // Update the widget stacking order and layout geometry.
15552 for (var i = 0, n = this._items.length; i < n; ++i) {
15553 // Fetch the item.
15554 var item = this._items[i];
15555 // Ignore hidden items.
15556 if (item.isHidden) {
15557 continue;
15558 }
15559 // Set the z-index for the widget.
15560 item.widget.node.style.zIndex = "" + i;
15561 // Update the item geometry.
15562 item.update(left, top, width, height);
15563 }
15564 };
15565 return StackedLayout;
15566}(PanelLayout));
15567
15568/**
15569 * A panel where visible widgets are stacked atop one another.
15570 *
15571 * #### Notes
15572 * This class provides a convenience wrapper around a [[StackedLayout]].
15573 */
15574var StackedPanel = /** @class */ (function (_super) {
15575 __extends(StackedPanel, _super);
15576 /**
15577 * Construct a new stacked panel.
15578 *
15579 * @param options - The options for initializing the panel.
15580 */
15581 function StackedPanel(options) {
15582 if (options === void 0) { options = {}; }
15583 var _this = _super.call(this, { layout: Private$1.createLayout(options) }) || this;
15584 _this._widgetRemoved = new Signal(_this);
15585 _this.addClass('lm-StackedPanel');
15586 /* <DEPRECATED> */
15587 _this.addClass('p-StackedPanel');
15588 return _this;
15589 /* </DEPRECATED> */
15590 }
15591 Object.defineProperty(StackedPanel.prototype, "hiddenMode", {
15592 /**
15593 * The method for hiding widgets.
15594 *
15595 * #### Notes
15596 * If there is only one child widget, `Display` hiding mode will be used
15597 * regardless of this setting.
15598 */
15599 get: function () {
15600 return this.layout.hiddenMode;
15601 },
15602 /**
15603 * Set the method for hiding widgets.
15604 *
15605 * #### Notes
15606 * If there is only one child widget, `Display` hiding mode will be used
15607 * regardless of this setting.
15608 */
15609 set: function (v) {
15610 this.layout.hiddenMode = v;
15611 },
15612 enumerable: true,
15613 configurable: true
15614 });
15615 Object.defineProperty(StackedPanel.prototype, "widgetRemoved", {
15616 /**
15617 * A signal emitted when a widget is removed from a stacked panel.
15618 */
15619 get: function () {
15620 return this._widgetRemoved;
15621 },
15622 enumerable: true,
15623 configurable: true
15624 });
15625 /**
15626 * A message handler invoked on a `'child-added'` message.
15627 */
15628 StackedPanel.prototype.onChildAdded = function (msg) {
15629 msg.child.addClass('lm-StackedPanel-child');
15630 /* <DEPRECATED> */
15631 msg.child.addClass('p-StackedPanel-child');
15632 /* </DEPRECATED> */
15633 };
15634 /**
15635 * A message handler invoked on a `'child-removed'` message.
15636 */
15637 StackedPanel.prototype.onChildRemoved = function (msg) {
15638 msg.child.removeClass('lm-StackedPanel-child');
15639 /* <DEPRECATED> */
15640 msg.child.removeClass('p-StackedPanel-child');
15641 /* </DEPRECATED> */
15642 this._widgetRemoved.emit(msg.child);
15643 };
15644 return StackedPanel;
15645}(Panel));
15646/**
15647 * The namespace for the module implementation details.
15648 */
15649var Private$1;
15650(function (Private) {
15651 /**
15652 * Create a stacked layout for the given panel options.
15653 */
15654 function createLayout(options) {
15655 return options.layout || new StackedLayout();
15656 }
15657 Private.createLayout = createLayout;
15658})(Private$1 || (Private$1 = {}));
15659
15660/**
15661 * A widget which combines a `TabBar` and a `StackedPanel`.
15662 *
15663 * #### Notes
15664 * This is a simple panel which handles the common case of a tab bar
15665 * placed next to a content area. The selected tab controls the widget
15666 * which is shown in the content area.
15667 *
15668 * For use cases which require more control than is provided by this
15669 * panel, the `TabBar` widget may be used independently.
15670 */
15671var TabPanel = /** @class */ (function (_super) {
15672 __extends(TabPanel, _super);
15673 /**
15674 * Construct a new tab panel.
15675 *
15676 * @param options - The options for initializing the tab panel.
15677 */
15678 function TabPanel(options) {
15679 if (options === void 0) { options = {}; }
15680 var _this = _super.call(this) || this;
15681 _this._currentChanged = new Signal(_this);
15682 _this._addRequested = new Signal(_this);
15683 _this.addClass('lm-TabPanel');
15684 /* <DEPRECATED> */
15685 _this.addClass('p-TabPanel');
15686 /* </DEPRECATED> */
15687 // Create the tab bar and stacked panel.
15688 _this.tabBar = new TabBar(options);
15689 _this.tabBar.addClass('lm-TabPanel-tabBar');
15690 _this.stackedPanel = new StackedPanel();
15691 _this.stackedPanel.addClass('lm-TabPanel-stackedPanel');
15692 /* <DEPRECATED> */
15693 _this.tabBar.addClass('p-TabPanel-tabBar');
15694 _this.stackedPanel.addClass('p-TabPanel-stackedPanel');
15695 /* </DEPRECATED> */
15696 // Connect the tab bar signal handlers.
15697 _this.tabBar.tabMoved.connect(_this._onTabMoved, _this);
15698 _this.tabBar.currentChanged.connect(_this._onCurrentChanged, _this);
15699 _this.tabBar.tabCloseRequested.connect(_this._onTabCloseRequested, _this);
15700 _this.tabBar.tabActivateRequested.connect(_this._onTabActivateRequested, _this);
15701 _this.tabBar.addRequested.connect(_this._onTabAddRequested, _this);
15702 // Connect the stacked panel signal handlers.
15703 _this.stackedPanel.widgetRemoved.connect(_this._onWidgetRemoved, _this);
15704 // Get the data related to the placement.
15705 _this._tabPlacement = options.tabPlacement || 'top';
15706 var direction = Private.directionFromPlacement(_this._tabPlacement);
15707 var orientation = Private.orientationFromPlacement(_this._tabPlacement);
15708 // Configure the tab bar for the placement.
15709 _this.tabBar.orientation = orientation;
15710 _this.tabBar.dataset['placement'] = _this._tabPlacement;
15711 // Create the box layout.
15712 var layout = new BoxLayout({ direction: direction, spacing: 0 });
15713 // Set the stretch factors for the child widgets.
15714 BoxLayout.setStretch(_this.tabBar, 0);
15715 BoxLayout.setStretch(_this.stackedPanel, 1);
15716 // Add the child widgets to the layout.
15717 layout.addWidget(_this.tabBar);
15718 layout.addWidget(_this.stackedPanel);
15719 // Install the layout on the tab panel.
15720 _this.layout = layout;
15721 return _this;
15722 }
15723 Object.defineProperty(TabPanel.prototype, "currentChanged", {
15724 /**
15725 * A signal emitted when the current tab is changed.
15726 *
15727 * #### Notes
15728 * This signal is emitted when the currently selected tab is changed
15729 * either through user or programmatic interaction.
15730 *
15731 * Notably, this signal is not emitted when the index of the current
15732 * tab changes due to tabs being inserted, removed, or moved. It is
15733 * only emitted when the actual current tab node is changed.
15734 */
15735 get: function () {
15736 return this._currentChanged;
15737 },
15738 enumerable: true,
15739 configurable: true
15740 });
15741 Object.defineProperty(TabPanel.prototype, "currentIndex", {
15742 /**
15743 * Get the index of the currently selected tab.
15744 *
15745 * #### Notes
15746 * This will be `-1` if no tab is selected.
15747 */
15748 get: function () {
15749 return this.tabBar.currentIndex;
15750 },
15751 /**
15752 * Set the index of the currently selected tab.
15753 *
15754 * #### Notes
15755 * If the index is out of range, it will be set to `-1`.
15756 */
15757 set: function (value) {
15758 this.tabBar.currentIndex = value;
15759 },
15760 enumerable: true,
15761 configurable: true
15762 });
15763 Object.defineProperty(TabPanel.prototype, "currentWidget", {
15764 /**
15765 * Get the currently selected widget.
15766 *
15767 * #### Notes
15768 * This will be `null` if there is no selected tab.
15769 */
15770 get: function () {
15771 var title = this.tabBar.currentTitle;
15772 return title ? title.owner : null;
15773 },
15774 /**
15775 * Set the currently selected widget.
15776 *
15777 * #### Notes
15778 * If the widget is not in the panel, it will be set to `null`.
15779 */
15780 set: function (value) {
15781 this.tabBar.currentTitle = value ? value.title : null;
15782 },
15783 enumerable: true,
15784 configurable: true
15785 });
15786 Object.defineProperty(TabPanel.prototype, "tabsMovable", {
15787 /**
15788 * Get the whether the tabs are movable by the user.
15789 *
15790 * #### Notes
15791 * Tabs can always be moved programmatically.
15792 */
15793 get: function () {
15794 return this.tabBar.tabsMovable;
15795 },
15796 /**
15797 * Set the whether the tabs are movable by the user.
15798 *
15799 * #### Notes
15800 * Tabs can always be moved programmatically.
15801 */
15802 set: function (value) {
15803 this.tabBar.tabsMovable = value;
15804 },
15805 enumerable: true,
15806 configurable: true
15807 });
15808 Object.defineProperty(TabPanel.prototype, "addButtonEnabled", {
15809 /**
15810 * Get the whether the add button is enabled.
15811 *
15812 */
15813 get: function () {
15814 return this.tabBar.addButtonEnabled;
15815 },
15816 /**
15817 * Set the whether the add button is enabled.
15818 *
15819 */
15820 set: function (value) {
15821 this.tabBar.addButtonEnabled = value;
15822 },
15823 enumerable: true,
15824 configurable: true
15825 });
15826 Object.defineProperty(TabPanel.prototype, "tabPlacement", {
15827 /**
15828 * Get the tab placement for the tab panel.
15829 *
15830 * #### Notes
15831 * This controls the position of the tab bar relative to the content.
15832 */
15833 get: function () {
15834 return this._tabPlacement;
15835 },
15836 /**
15837 * Set the tab placement for the tab panel.
15838 *
15839 * #### Notes
15840 * This controls the position of the tab bar relative to the content.
15841 */
15842 set: function (value) {
15843 // Bail if the placement does not change.
15844 if (this._tabPlacement === value) {
15845 return;
15846 }
15847 // Update the internal value.
15848 this._tabPlacement = value;
15849 // Get the values related to the placement.
15850 var direction = Private.directionFromPlacement(value);
15851 var orientation = Private.orientationFromPlacement(value);
15852 // Configure the tab bar for the placement.
15853 this.tabBar.orientation = orientation;
15854 this.tabBar.dataset['placement'] = value;
15855 // Update the layout direction.
15856 this.layout.direction = direction;
15857 },
15858 enumerable: true,
15859 configurable: true
15860 });
15861 Object.defineProperty(TabPanel.prototype, "addRequested", {
15862 /**
15863 * A signal emitted when the add button on a tab bar is clicked.
15864 *
15865 */
15866 get: function () {
15867 return this._addRequested;
15868 },
15869 enumerable: true,
15870 configurable: true
15871 });
15872 Object.defineProperty(TabPanel.prototype, "widgets", {
15873 /**
15874 * A read-only array of the widgets in the panel.
15875 */
15876 get: function () {
15877 return this.stackedPanel.widgets;
15878 },
15879 enumerable: true,
15880 configurable: true
15881 });
15882 /**
15883 * Add a widget to the end of the tab panel.
15884 *
15885 * @param widget - The widget to add to the tab panel.
15886 *
15887 * #### Notes
15888 * If the widget is already contained in the panel, it will be moved.
15889 *
15890 * The widget's `title` is used to populate the tab.
15891 */
15892 TabPanel.prototype.addWidget = function (widget) {
15893 this.insertWidget(this.widgets.length, widget);
15894 };
15895 /**
15896 * Insert a widget into the tab panel at a specified index.
15897 *
15898 * @param index - The index at which to insert the widget.
15899 *
15900 * @param widget - The widget to insert into to the tab panel.
15901 *
15902 * #### Notes
15903 * If the widget is already contained in the panel, it will be moved.
15904 *
15905 * The widget's `title` is used to populate the tab.
15906 */
15907 TabPanel.prototype.insertWidget = function (index, widget) {
15908 if (widget !== this.currentWidget) {
15909 widget.hide();
15910 }
15911 this.stackedPanel.insertWidget(index, widget);
15912 this.tabBar.insertTab(index, widget.title);
15913 widget.node.setAttribute('role', 'tabpanel');
15914 var renderer = this.tabBar.renderer;
15915 if (renderer instanceof TabBar.Renderer) {
15916 var tabId = renderer.createTabKey({
15917 title: widget.title,
15918 current: false,
15919 zIndex: 0
15920 });
15921 widget.node.setAttribute('aria-labelledby', tabId);
15922 }
15923 };
15924 /**
15925 * Handle the `currentChanged` signal from the tab bar.
15926 */
15927 TabPanel.prototype._onCurrentChanged = function (sender, args) {
15928 // Extract the previous and current title from the args.
15929 var previousIndex = args.previousIndex, previousTitle = args.previousTitle, currentIndex = args.currentIndex, currentTitle = args.currentTitle;
15930 // Extract the widgets from the titles.
15931 var previousWidget = previousTitle ? previousTitle.owner : null;
15932 var currentWidget = currentTitle ? currentTitle.owner : null;
15933 // Hide the previous widget.
15934 if (previousWidget) {
15935 previousWidget.hide();
15936 }
15937 // Show the current widget.
15938 if (currentWidget) {
15939 currentWidget.show();
15940 }
15941 // Emit the `currentChanged` signal for the tab panel.
15942 this._currentChanged.emit({
15943 previousIndex: previousIndex,
15944 previousWidget: previousWidget,
15945 currentIndex: currentIndex,
15946 currentWidget: currentWidget
15947 });
15948 // Flush the message loop on IE and Edge to prevent flicker.
15949 if (Platform.IS_EDGE || Platform.IS_IE) {
15950 MessageLoop.flush();
15951 }
15952 };
15953 /**
15954 * Handle the `tabAddRequested` signal from the tab bar.
15955 */
15956 TabPanel.prototype._onTabAddRequested = function (sender, args) {
15957 this._addRequested.emit(sender);
15958 };
15959 /**
15960 * Handle the `tabActivateRequested` signal from the tab bar.
15961 */
15962 TabPanel.prototype._onTabActivateRequested = function (sender, args) {
15963 args.title.owner.activate();
15964 };
15965 /**
15966 * Handle the `tabCloseRequested` signal from the tab bar.
15967 */
15968 TabPanel.prototype._onTabCloseRequested = function (sender, args) {
15969 args.title.owner.close();
15970 };
15971 /**
15972 * Handle the `tabMoved` signal from the tab bar.
15973 */
15974 TabPanel.prototype._onTabMoved = function (sender, args) {
15975 this.stackedPanel.insertWidget(args.toIndex, args.title.owner);
15976 };
15977 /**
15978 * Handle the `widgetRemoved` signal from the stacked panel.
15979 */
15980 TabPanel.prototype._onWidgetRemoved = function (sender, widget) {
15981 widget.node.removeAttribute('role');
15982 widget.node.removeAttribute('aria-labelledby');
15983 this.tabBar.removeTab(widget.title);
15984 };
15985 return TabPanel;
15986}(Widget));
15987/**
15988 * The namespace for the module implementation details.
15989 */
15990var Private;
15991(function (Private) {
15992 /**
15993 * Convert a tab placement to tab bar orientation.
15994 */
15995 function orientationFromPlacement(plc) {
15996 return placementToOrientationMap[plc];
15997 }
15998 Private.orientationFromPlacement = orientationFromPlacement;
15999 /**
16000 * Convert a tab placement to a box layout direction.
16001 */
16002 function directionFromPlacement(plc) {
16003 return placementToDirectionMap[plc];
16004 }
16005 Private.directionFromPlacement = directionFromPlacement;
16006 /**
16007 * A mapping of tab placement to tab bar orientation.
16008 */
16009 var placementToOrientationMap = {
16010 top: 'horizontal',
16011 left: 'vertical',
16012 right: 'vertical',
16013 bottom: 'horizontal'
16014 };
16015 /**
16016 * A mapping of tab placement to box layout direction.
16017 */
16018 var placementToDirectionMap = {
16019 top: 'top-to-bottom',
16020 left: 'left-to-right',
16021 right: 'right-to-left',
16022 bottom: 'bottom-to-top'
16023 };
16024})(Private || (Private = {}));
16025
16026export { AccordionLayout, AccordionPanel, BoxEngine, BoxLayout, BoxPanel, BoxSizer, CommandPalette, ContextMenu, DockLayout, DockPanel, FocusTracker, GridLayout, Layout, LayoutItem, Menu, MenuBar, Panel, PanelLayout, ScrollBar, SingletonLayout, SplitLayout, SplitPanel, StackedLayout, StackedPanel, TabBar, TabPanel, Title, Widget };
16027//# sourceMappingURL=index.es6.js.map