UNPKG

640 kBJavaScriptView Raw
1(function (global, factory) {
2 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@lumino/algorithm'), require('@lumino/domutils'), require('@lumino/messaging'), require('@lumino/properties'), require('@lumino/signaling'), require('@lumino/dragdrop'), require('@lumino/coreutils'), require('@lumino/commands'), require('@lumino/virtualdom'), require('@lumino/disposable'), require('@lumino/keyboard')) :
3 typeof define === 'function' && define.amd ? define(['exports', '@lumino/algorithm', '@lumino/domutils', '@lumino/messaging', '@lumino/properties', '@lumino/signaling', '@lumino/dragdrop', '@lumino/coreutils', '@lumino/commands', '@lumino/virtualdom', '@lumino/disposable', '@lumino/keyboard'], factory) :
4 (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.lumino_widgets = {}, global.lumino_algorithm, global.lumino_domutils, global.lumino_messaging, global.lumino_properties, global.lumino_signaling, global.lumino_dragdrop, global.lumino_coreutils, global.lumino_commands, global.lumino_virtualdom, global.lumino_disposable, global.lumino_keyboard));
5}(this, (function (exports, algorithm, domutils, messaging, properties, signaling, dragdrop, coreutils, commands, virtualdom, disposable, keyboard) { 'use strict';
6
7 /*! *****************************************************************************
8 Copyright (c) Microsoft Corporation.
9
10 Permission to use, copy, modify, and/or distribute this software for any
11 purpose with or without fee is hereby granted.
12
13 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
14 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
15 AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
16 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
17 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
18 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 PERFORMANCE OF THIS SOFTWARE.
20 ***************************************************************************** */
21 /* global Reflect, Promise */
22
23 var extendStatics = function(d, b) {
24 extendStatics = Object.setPrototypeOf ||
25 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
26 function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
27 return extendStatics(d, b);
28 };
29
30 function __extends(d, b) {
31 if (typeof b !== "function" && b !== null)
32 throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
33 extendStatics(d, b);
34 function __() { this.constructor = d; }
35 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
36 }
37
38 var __assign = function() {
39 __assign = Object.assign || function __assign(t) {
40 for (var s, i = 1, n = arguments.length; i < n; i++) {
41 s = arguments[i];
42 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
43 }
44 return t;
45 };
46 return __assign.apply(this, arguments);
47 };
48
49 function __rest(s, e) {
50 var t = {};
51 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
52 t[p] = s[p];
53 if (s != null && typeof Object.getOwnPropertySymbols === "function")
54 for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
55 if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
56 t[p[i]] = s[p[i]];
57 }
58 return t;
59 }
60
61 // Copyright (c) Jupyter Development Team.
62 // Distributed under the terms of the Modified BSD License.
63 /*-----------------------------------------------------------------------------
64 | Copyright (c) 2014-2017, PhosphorJS Contributors
65 |
66 | Distributed under the terms of the BSD 3-Clause License.
67 |
68 | The full license is in the file LICENSE, distributed with this software.
69 |----------------------------------------------------------------------------*/
70 /**
71 * A sizer object for use with the box engine layout functions.
72 *
73 * #### Notes
74 * A box sizer holds the geometry information for an object along an
75 * arbitrary layout orientation.
76 *
77 * For best performance, this class should be treated as a raw data
78 * struct. It should not typically be subclassed.
79 */
80 var BoxSizer = /** @class */ (function () {
81 function BoxSizer() {
82 /**
83 * The preferred size for the sizer.
84 *
85 * #### Notes
86 * The sizer will be given this initial size subject to its size
87 * bounds. The sizer will not deviate from this size unless such
88 * deviation is required to fit into the available layout space.
89 *
90 * There is no limit to this value, but it will be clamped to the
91 * bounds defined by [[minSize]] and [[maxSize]].
92 *
93 * The default value is `0`.
94 */
95 this.sizeHint = 0;
96 /**
97 * The minimum size of the sizer.
98 *
99 * #### Notes
100 * The sizer will never be sized less than this value, even if
101 * it means the sizer will overflow the available layout space.
102 *
103 * It is assumed that this value lies in the range `[0, Infinity)`
104 * and that it is `<=` to [[maxSize]]. Failure to adhere to this
105 * constraint will yield undefined results.
106 *
107 * The default value is `0`.
108 */
109 this.minSize = 0;
110 /**
111 * The maximum size of the sizer.
112 *
113 * #### Notes
114 * The sizer will never be sized greater than this value, even if
115 * it means the sizer will underflow the available layout space.
116 *
117 * It is assumed that this value lies in the range `[0, Infinity]`
118 * and that it is `>=` to [[minSize]]. Failure to adhere to this
119 * constraint will yield undefined results.
120 *
121 * The default value is `Infinity`.
122 */
123 this.maxSize = Infinity;
124 /**
125 * The stretch factor for the sizer.
126 *
127 * #### Notes
128 * This controls how much the sizer stretches relative to its sibling
129 * sizers when layout space is distributed. A stretch factor of zero
130 * is special and will cause the sizer to only be resized after all
131 * other sizers with a stretch factor greater than zero have been
132 * resized to their limits.
133 *
134 * It is assumed that this value is an integer that lies in the range
135 * `[0, Infinity)`. Failure to adhere to this constraint will yield
136 * undefined results.
137 *
138 * The default value is `1`.
139 */
140 this.stretch = 1;
141 /**
142 * The computed size of the sizer.
143 *
144 * #### Notes
145 * This value is the output of a call to [[boxCalc]]. It represents
146 * the computed size for the object along the layout orientation,
147 * and will always lie in the range `[minSize, maxSize]`.
148 *
149 * This value is output only.
150 *
151 * Changing this value will have no effect.
152 */
153 this.size = 0;
154 /**
155 * An internal storage property for the layout algorithm.
156 *
157 * #### Notes
158 * This value is used as temporary storage by the layout algorithm.
159 *
160 * Changing this value will have no effect.
161 */
162 this.done = false;
163 }
164 return BoxSizer;
165 }());
166 /**
167 * The namespace for the box engine layout functions.
168 */
169 exports.BoxEngine = void 0;
170 (function (BoxEngine) {
171 /**
172 * Calculate the optimal layout sizes for a sequence of box sizers.
173 *
174 * This distributes the available layout space among the box sizers
175 * according to the following algorithm:
176 *
177 * 1. Initialize the sizers's size to its size hint and compute the
178 * sums for each of size hint, min size, and max size.
179 *
180 * 2. If the total size hint equals the available space, return.
181 *
182 * 3. If the available space is less than the total min size, set all
183 * sizers to their min size and return.
184 *
185 * 4. If the available space is greater than the total max size, set
186 * all sizers to their max size and return.
187 *
188 * 5. If the layout space is less than the total size hint, distribute
189 * the negative delta as follows:
190 *
191 * a. Shrink each sizer with a stretch factor greater than zero by
192 * an amount proportional to the negative space and the sum of
193 * stretch factors. If the sizer reaches its min size, remove
194 * it and its stretch factor from the computation.
195 *
196 * b. If after adjusting all stretch sizers there remains negative
197 * space, distribute the space equally among the sizers with a
198 * stretch factor of zero. If a sizer reaches its min size,
199 * remove it from the computation.
200 *
201 * 6. If the layout space is greater than the total size hint,
202 * distribute the positive delta as follows:
203 *
204 * a. Expand each sizer with a stretch factor greater than zero by
205 * an amount proportional to the postive space and the sum of
206 * stretch factors. If the sizer reaches its max size, remove
207 * it and its stretch factor from the computation.
208 *
209 * b. If after adjusting all stretch sizers there remains positive
210 * space, distribute the space equally among the sizers with a
211 * stretch factor of zero. If a sizer reaches its max size,
212 * remove it from the computation.
213 *
214 * 7. return
215 *
216 * @param sizers - The sizers for a particular layout line.
217 *
218 * @param space - The available layout space for the sizers.
219 *
220 * @returns The delta between the provided available space and the
221 * actual consumed space. This value will be zero if the sizers
222 * can be adjusted to fit, negative if the available space is too
223 * small, and positive if the available space is too large.
224 *
225 * #### Notes
226 * The [[size]] of each sizer is updated with the computed size.
227 *
228 * This function can be called at any time to recompute the layout for
229 * an existing sequence of sizers. The previously computed results will
230 * have no effect on the new output. It is therefore not necessary to
231 * create new sizer objects on each resize event.
232 */
233 function calc(sizers, space) {
234 // Bail early if there is nothing to do.
235 var count = sizers.length;
236 if (count === 0) {
237 return space;
238 }
239 // Setup the size and stretch counters.
240 var totalMin = 0;
241 var totalMax = 0;
242 var totalSize = 0;
243 var totalStretch = 0;
244 var stretchCount = 0;
245 // Setup the sizers and compute the totals.
246 for (var i = 0; i < count; ++i) {
247 var sizer = sizers[i];
248 var min = sizer.minSize;
249 var max = sizer.maxSize;
250 var hint = sizer.sizeHint;
251 sizer.done = false;
252 sizer.size = Math.max(min, Math.min(hint, max));
253 totalSize += sizer.size;
254 totalMin += min;
255 totalMax += max;
256 if (sizer.stretch > 0) {
257 totalStretch += sizer.stretch;
258 stretchCount++;
259 }
260 }
261 // If the space is equal to the total size, return early.
262 if (space === totalSize) {
263 return 0;
264 }
265 // If the space is less than the total min, minimize each sizer.
266 if (space <= totalMin) {
267 for (var i = 0; i < count; ++i) {
268 var sizer = sizers[i];
269 sizer.size = sizer.minSize;
270 }
271 return space - totalMin;
272 }
273 // If the space is greater than the total max, maximize each sizer.
274 if (space >= totalMax) {
275 for (var i = 0; i < count; ++i) {
276 var sizer = sizers[i];
277 sizer.size = sizer.maxSize;
278 }
279 return space - totalMax;
280 }
281 // The loops below perform sub-pixel precision sizing. A near zero
282 // value is used for compares instead of zero to ensure that the
283 // loop terminates when the subdivided space is reasonably small.
284 var nearZero = 0.01;
285 // A counter which is decremented each time a sizer is resized to
286 // its limit. This ensures the loops terminate even if there is
287 // space remaining to distribute.
288 var notDoneCount = count;
289 // Distribute negative delta space.
290 if (space < totalSize) {
291 // Shrink each stretchable sizer by an amount proportional to its
292 // stretch factor. If a sizer reaches its min size it's marked as
293 // done. The loop progresses in phases where each sizer is given
294 // a chance to consume its fair share for the pass, regardless of
295 // whether a sizer before it reached its limit. This continues
296 // until the stretchable sizers or the free space is exhausted.
297 var freeSpace = totalSize - space;
298 while (stretchCount > 0 && freeSpace > nearZero) {
299 var distSpace = freeSpace;
300 var distStretch = totalStretch;
301 for (var i = 0; i < count; ++i) {
302 var sizer = sizers[i];
303 if (sizer.done || sizer.stretch === 0) {
304 continue;
305 }
306 var amt = (sizer.stretch * distSpace) / distStretch;
307 if (sizer.size - amt <= sizer.minSize) {
308 freeSpace -= sizer.size - sizer.minSize;
309 totalStretch -= sizer.stretch;
310 sizer.size = sizer.minSize;
311 sizer.done = true;
312 notDoneCount--;
313 stretchCount--;
314 }
315 else {
316 freeSpace -= amt;
317 sizer.size -= amt;
318 }
319 }
320 }
321 // Distribute any remaining space evenly among the non-stretchable
322 // sizers. This progresses in phases in the same manner as above.
323 while (notDoneCount > 0 && freeSpace > nearZero) {
324 var amt = freeSpace / notDoneCount;
325 for (var i = 0; i < count; ++i) {
326 var sizer = sizers[i];
327 if (sizer.done) {
328 continue;
329 }
330 if (sizer.size - amt <= sizer.minSize) {
331 freeSpace -= sizer.size - sizer.minSize;
332 sizer.size = sizer.minSize;
333 sizer.done = true;
334 notDoneCount--;
335 }
336 else {
337 freeSpace -= amt;
338 sizer.size -= amt;
339 }
340 }
341 }
342 }
343 // Distribute positive delta space.
344 else {
345 // Expand each stretchable sizer by an amount proportional to its
346 // stretch factor. If a sizer reaches its max size it's marked as
347 // done. The loop progresses in phases where each sizer is given
348 // a chance to consume its fair share for the pass, regardless of
349 // whether a sizer before it reached its limit. This continues
350 // until the stretchable sizers or the free space is exhausted.
351 var freeSpace = space - totalSize;
352 while (stretchCount > 0 && freeSpace > nearZero) {
353 var distSpace = freeSpace;
354 var distStretch = totalStretch;
355 for (var i = 0; i < count; ++i) {
356 var sizer = sizers[i];
357 if (sizer.done || sizer.stretch === 0) {
358 continue;
359 }
360 var amt = (sizer.stretch * distSpace) / distStretch;
361 if (sizer.size + amt >= sizer.maxSize) {
362 freeSpace -= sizer.maxSize - sizer.size;
363 totalStretch -= sizer.stretch;
364 sizer.size = sizer.maxSize;
365 sizer.done = true;
366 notDoneCount--;
367 stretchCount--;
368 }
369 else {
370 freeSpace -= amt;
371 sizer.size += amt;
372 }
373 }
374 }
375 // Distribute any remaining space evenly among the non-stretchable
376 // sizers. This progresses in phases in the same manner as above.
377 while (notDoneCount > 0 && freeSpace > nearZero) {
378 var amt = freeSpace / notDoneCount;
379 for (var i = 0; i < count; ++i) {
380 var sizer = sizers[i];
381 if (sizer.done) {
382 continue;
383 }
384 if (sizer.size + amt >= sizer.maxSize) {
385 freeSpace -= sizer.maxSize - sizer.size;
386 sizer.size = sizer.maxSize;
387 sizer.done = true;
388 notDoneCount--;
389 }
390 else {
391 freeSpace -= amt;
392 sizer.size += amt;
393 }
394 }
395 }
396 }
397 // Indicate that the consumed space equals the available space.
398 return 0;
399 }
400 BoxEngine.calc = calc;
401 /**
402 * Adjust a sizer by a delta and update its neighbors accordingly.
403 *
404 * @param sizers - The sizers which should be adjusted.
405 *
406 * @param index - The index of the sizer to grow.
407 *
408 * @param delta - The amount to adjust the sizer, positive or negative.
409 *
410 * #### Notes
411 * This will adjust the indicated sizer by the specified amount, along
412 * with the sizes of the appropriate neighbors, subject to the limits
413 * specified by each of the sizers.
414 *
415 * This is useful when implementing box layouts where the boundaries
416 * between the sizers are interactively adjustable by the user.
417 */
418 function adjust(sizers, index, delta) {
419 // Bail early when there is nothing to do.
420 if (sizers.length === 0 || delta === 0) {
421 return;
422 }
423 // Dispatch to the proper implementation.
424 if (delta > 0) {
425 growSizer(sizers, index, delta);
426 }
427 else {
428 shrinkSizer(sizers, index, -delta);
429 }
430 }
431 BoxEngine.adjust = adjust;
432 /**
433 * Grow a sizer by a positive delta and adjust neighbors.
434 */
435 function growSizer(sizers, index, delta) {
436 // Compute how much the items to the left can expand.
437 var growLimit = 0;
438 for (var i = 0; i <= index; ++i) {
439 var sizer = sizers[i];
440 growLimit += sizer.maxSize - sizer.size;
441 }
442 // Compute how much the items to the right can shrink.
443 var shrinkLimit = 0;
444 for (var i = index + 1, n = sizers.length; i < n; ++i) {
445 var sizer = sizers[i];
446 shrinkLimit += sizer.size - sizer.minSize;
447 }
448 // Clamp the delta adjustment to the limits.
449 delta = Math.min(delta, growLimit, shrinkLimit);
450 // Grow the sizers to the left by the delta.
451 var grow = delta;
452 for (var i = index; i >= 0 && grow > 0; --i) {
453 var sizer = sizers[i];
454 var limit = sizer.maxSize - sizer.size;
455 if (limit >= grow) {
456 sizer.sizeHint = sizer.size + grow;
457 grow = 0;
458 }
459 else {
460 sizer.sizeHint = sizer.size + limit;
461 grow -= limit;
462 }
463 }
464 // Shrink the sizers to the right by the delta.
465 var shrink = delta;
466 for (var i = index + 1, n = sizers.length; i < n && shrink > 0; ++i) {
467 var sizer = sizers[i];
468 var limit = sizer.size - sizer.minSize;
469 if (limit >= shrink) {
470 sizer.sizeHint = sizer.size - shrink;
471 shrink = 0;
472 }
473 else {
474 sizer.sizeHint = sizer.size - limit;
475 shrink -= limit;
476 }
477 }
478 }
479 /**
480 * Shrink a sizer by a positive delta and adjust neighbors.
481 */
482 function shrinkSizer(sizers, index, delta) {
483 // Compute how much the items to the right can expand.
484 var growLimit = 0;
485 for (var i = index + 1, n = sizers.length; i < n; ++i) {
486 var sizer = sizers[i];
487 growLimit += sizer.maxSize - sizer.size;
488 }
489 // Compute how much the items to the left can shrink.
490 var shrinkLimit = 0;
491 for (var i = 0; i <= index; ++i) {
492 var sizer = sizers[i];
493 shrinkLimit += sizer.size - sizer.minSize;
494 }
495 // Clamp the delta adjustment to the limits.
496 delta = Math.min(delta, growLimit, shrinkLimit);
497 // Grow the sizers to the right by the delta.
498 var grow = delta;
499 for (var i = index + 1, n = sizers.length; i < n && grow > 0; ++i) {
500 var sizer = sizers[i];
501 var limit = sizer.maxSize - sizer.size;
502 if (limit >= grow) {
503 sizer.sizeHint = sizer.size + grow;
504 grow = 0;
505 }
506 else {
507 sizer.sizeHint = sizer.size + limit;
508 grow -= limit;
509 }
510 }
511 // Shrink the sizers to the left by the delta.
512 var shrink = delta;
513 for (var i = index; i >= 0 && shrink > 0; --i) {
514 var sizer = sizers[i];
515 var limit = sizer.size - sizer.minSize;
516 if (limit >= shrink) {
517 sizer.sizeHint = sizer.size - shrink;
518 shrink = 0;
519 }
520 else {
521 sizer.sizeHint = sizer.size - limit;
522 shrink -= limit;
523 }
524 }
525 }
526 })(exports.BoxEngine || (exports.BoxEngine = {}));
527
528 // Copyright (c) Jupyter Development Team.
529 /**
530 * An object which holds data related to an object's title.
531 *
532 * #### Notes
533 * A title object is intended to hold the data necessary to display a
534 * header for a particular object. A common example is the `TabPanel`,
535 * which uses the widget title to populate the tab for a child widget.
536 */
537 var Title = /** @class */ (function () {
538 /**
539 * Construct a new title.
540 *
541 * @param options - The options for initializing the title.
542 */
543 function Title(options) {
544 this._label = '';
545 this._caption = '';
546 this._mnemonic = -1;
547 this._iconClass = '';
548 this._iconLabel = '';
549 this._className = '';
550 this._closable = false;
551 this._changed = new signaling.Signal(this);
552 this.owner = options.owner;
553 if (options.label !== undefined) {
554 this._label = options.label;
555 }
556 if (options.mnemonic !== undefined) {
557 this._mnemonic = options.mnemonic;
558 }
559 if (options.icon !== undefined) {
560 /* <DEPRECATED> */
561 if (typeof options.icon === 'string') {
562 // when ._icon is null, the .icon getter will alias .iconClass
563 this._icon = null;
564 this._iconClass = options.icon;
565 }
566 else {
567 /* </DEPRECATED> */
568 this._icon = options.icon;
569 /* <DEPRECATED> */
570 }
571 /* </DEPRECATED> */
572 }
573 else {
574 /* <DEPRECATED> */
575 // if unset, default to aliasing .iconClass
576 this._icon = null;
577 }
578 /* </DEPRECATED> */
579 if (options.iconClass !== undefined) {
580 this._iconClass = options.iconClass;
581 }
582 if (options.iconLabel !== undefined) {
583 this._iconLabel = options.iconLabel;
584 }
585 if (options.iconRenderer !== undefined) {
586 this._icon = options.iconRenderer;
587 }
588 if (options.caption !== undefined) {
589 this._caption = options.caption;
590 }
591 if (options.className !== undefined) {
592 this._className = options.className;
593 }
594 if (options.closable !== undefined) {
595 this._closable = options.closable;
596 }
597 this._dataset = options.dataset || {};
598 }
599 Object.defineProperty(Title.prototype, "changed", {
600 /**
601 * A signal emitted when the state of the title changes.
602 */
603 get: function () {
604 return this._changed;
605 },
606 enumerable: true,
607 configurable: true
608 });
609 Object.defineProperty(Title.prototype, "label", {
610 /**
611 * Get the label for the title.
612 *
613 * #### Notes
614 * The default value is an empty string.
615 */
616 get: function () {
617 return this._label;
618 },
619 /**
620 * Set the label for the title.
621 */
622 set: function (value) {
623 if (this._label === value) {
624 return;
625 }
626 this._label = value;
627 this._changed.emit(undefined);
628 },
629 enumerable: true,
630 configurable: true
631 });
632 Object.defineProperty(Title.prototype, "mnemonic", {
633 /**
634 * Get the mnemonic index for the title.
635 *
636 * #### Notes
637 * The default value is `-1`.
638 */
639 get: function () {
640 return this._mnemonic;
641 },
642 /**
643 * Set the mnemonic index for the title.
644 */
645 set: function (value) {
646 if (this._mnemonic === value) {
647 return;
648 }
649 this._mnemonic = value;
650 this._changed.emit(undefined);
651 },
652 enumerable: true,
653 configurable: true
654 });
655 Object.defineProperty(Title.prototype, "icon", {
656 /**
657 * Get the icon renderer for the title.
658 *
659 * #### Notes
660 * The default value is undefined.
661 *
662 * DEPRECATED: if set to a string value, the .icon field will function as
663 * an alias for the .iconClass field, for backwards compatibility
664 */
665 get: function () {
666 /* <DEPRECATED> */
667 if (this._icon === null) {
668 // only alias .iconClass if ._icon has been explicitly nulled
669 return this.iconClass;
670 }
671 /* </DEPRECATED> */
672 return this._icon;
673 },
674 /**
675 * Set the icon renderer for the title.
676 *
677 * #### Notes
678 * A renderer is an object that supplies a render and unrender function.
679 *
680 * DEPRECATED: if set to a string value, the .icon field will function as
681 * an alias for the .iconClass field, for backwards compatibility
682 */
683 set: function (value /* </DEPRECATED> */) {
684 /* <DEPRECATED> */
685 if (typeof value === 'string') {
686 // when ._icon is null, the .icon getter will alias .iconClass
687 this._icon = null;
688 this.iconClass = value;
689 }
690 else {
691 /* </DEPRECATED> */
692 if (this._icon === value) {
693 return;
694 }
695 this._icon = value;
696 this._changed.emit(undefined);
697 /* <DEPRECATED> */
698 }
699 /* </DEPRECATED> */
700 },
701 enumerable: true,
702 configurable: true
703 });
704 Object.defineProperty(Title.prototype, "iconClass", {
705 /**
706 * Get the icon class name for the title.
707 *
708 * #### Notes
709 * The default value is an empty string.
710 */
711 get: function () {
712 return this._iconClass;
713 },
714 /**
715 * Set the icon class name for the title.
716 *
717 * #### Notes
718 * Multiple class names can be separated with whitespace.
719 */
720 set: function (value) {
721 if (this._iconClass === value) {
722 return;
723 }
724 this._iconClass = value;
725 this._changed.emit(undefined);
726 },
727 enumerable: true,
728 configurable: true
729 });
730 Object.defineProperty(Title.prototype, "iconLabel", {
731 /**
732 * Get the icon label for the title.
733 *
734 * #### Notes
735 * The default value is an empty string.
736 */
737 get: function () {
738 return this._iconLabel;
739 },
740 /**
741 * Set the icon label for the title.
742 *
743 * #### Notes
744 * Multiple class names can be separated with whitespace.
745 */
746 set: function (value) {
747 if (this._iconLabel === value) {
748 return;
749 }
750 this._iconLabel = value;
751 this._changed.emit(undefined);
752 },
753 enumerable: true,
754 configurable: true
755 });
756 Object.defineProperty(Title.prototype, "iconRenderer", {
757 /**
758 * @deprecated Use `icon` instead.
759 */
760 get: function () {
761 return this._icon || undefined;
762 },
763 /**
764 * @deprecated Use `icon` instead.
765 */
766 set: function (value) {
767 this.icon = value;
768 },
769 enumerable: true,
770 configurable: true
771 });
772 Object.defineProperty(Title.prototype, "caption", {
773 /**
774 * Get the caption for the title.
775 *
776 * #### Notes
777 * The default value is an empty string.
778 */
779 get: function () {
780 return this._caption;
781 },
782 /**
783 * Set the caption for the title.
784 */
785 set: function (value) {
786 if (this._caption === value) {
787 return;
788 }
789 this._caption = value;
790 this._changed.emit(undefined);
791 },
792 enumerable: true,
793 configurable: true
794 });
795 Object.defineProperty(Title.prototype, "className", {
796 /**
797 * Get the extra class name for the title.
798 *
799 * #### Notes
800 * The default value is an empty string.
801 */
802 get: function () {
803 return this._className;
804 },
805 /**
806 * Set the extra class name for the title.
807 *
808 * #### Notes
809 * Multiple class names can be separated with whitespace.
810 */
811 set: function (value) {
812 if (this._className === value) {
813 return;
814 }
815 this._className = value;
816 this._changed.emit(undefined);
817 },
818 enumerable: true,
819 configurable: true
820 });
821 Object.defineProperty(Title.prototype, "closable", {
822 /**
823 * Get the closable state for the title.
824 *
825 * #### Notes
826 * The default value is `false`.
827 */
828 get: function () {
829 return this._closable;
830 },
831 /**
832 * Set the closable state for the title.
833 *
834 * #### Notes
835 * This controls the presence of a close icon when applicable.
836 */
837 set: function (value) {
838 if (this._closable === value) {
839 return;
840 }
841 this._closable = value;
842 this._changed.emit(undefined);
843 },
844 enumerable: true,
845 configurable: true
846 });
847 Object.defineProperty(Title.prototype, "dataset", {
848 /**
849 * Get the dataset for the title.
850 *
851 * #### Notes
852 * The default value is an empty dataset.
853 */
854 get: function () {
855 return this._dataset;
856 },
857 /**
858 * Set the dataset for the title.
859 *
860 * #### Notes
861 * This controls the data attributes when applicable.
862 */
863 set: function (value) {
864 if (this._dataset === value) {
865 return;
866 }
867 this._dataset = value;
868 this._changed.emit(undefined);
869 },
870 enumerable: true,
871 configurable: true
872 });
873 return Title;
874 }());
875
876 /**
877 * The base class of the lumino widget hierarchy.
878 *
879 * #### Notes
880 * This class will typically be subclassed in order to create a useful
881 * widget. However, it can be used directly to host externally created
882 * content.
883 */
884 exports.Widget = /** @class */ (function () {
885 /**
886 * Construct a new widget.
887 *
888 * @param options - The options for initializing the widget.
889 */
890 function Widget(options) {
891 if (options === void 0) { options = {}; }
892 this._flags = 0;
893 this._layout = null;
894 this._parent = null;
895 this._disposed = new signaling.Signal(this);
896 this._hiddenMode = Widget.HiddenMode.Display;
897 this.node = Private$j.createNode(options);
898 this.addClass('lm-Widget');
899 /* <DEPRECATED> */
900 this.addClass('p-Widget');
901 /* </DEPRECATED> */
902 }
903 /**
904 * Dispose of the widget and its descendant widgets.
905 *
906 * #### Notes
907 * It is unsafe to use the widget after it has been disposed.
908 *
909 * All calls made to this method after the first are a no-op.
910 */
911 Widget.prototype.dispose = function () {
912 // Do nothing if the widget is already disposed.
913 if (this.isDisposed) {
914 return;
915 }
916 // Set the disposed flag and emit the disposed signal.
917 this.setFlag(Widget.Flag.IsDisposed);
918 this._disposed.emit(undefined);
919 // Remove or detach the widget if necessary.
920 if (this.parent) {
921 this.parent = null;
922 }
923 else if (this.isAttached) {
924 Widget.detach(this);
925 }
926 // Dispose of the widget layout.
927 if (this._layout) {
928 this._layout.dispose();
929 this._layout = null;
930 }
931 // Clear the extra data associated with the widget.
932 signaling.Signal.clearData(this);
933 messaging.MessageLoop.clearData(this);
934 properties.AttachedProperty.clearData(this);
935 };
936 Object.defineProperty(Widget.prototype, "disposed", {
937 /**
938 * A signal emitted when the widget is disposed.
939 */
940 get: function () {
941 return this._disposed;
942 },
943 enumerable: true,
944 configurable: true
945 });
946 Object.defineProperty(Widget.prototype, "isDisposed", {
947 /**
948 * Test whether the widget has been disposed.
949 */
950 get: function () {
951 return this.testFlag(Widget.Flag.IsDisposed);
952 },
953 enumerable: true,
954 configurable: true
955 });
956 Object.defineProperty(Widget.prototype, "isAttached", {
957 /**
958 * Test whether the widget's node is attached to the DOM.
959 */
960 get: function () {
961 return this.testFlag(Widget.Flag.IsAttached);
962 },
963 enumerable: true,
964 configurable: true
965 });
966 Object.defineProperty(Widget.prototype, "isHidden", {
967 /**
968 * Test whether the widget is explicitly hidden.
969 */
970 get: function () {
971 return this.testFlag(Widget.Flag.IsHidden);
972 },
973 enumerable: true,
974 configurable: true
975 });
976 Object.defineProperty(Widget.prototype, "isVisible", {
977 /**
978 * Test whether the widget is visible.
979 *
980 * #### Notes
981 * A widget is visible when it is attached to the DOM, is not
982 * explicitly hidden, and has no explicitly hidden ancestors.
983 */
984 get: function () {
985 return this.testFlag(Widget.Flag.IsVisible);
986 },
987 enumerable: true,
988 configurable: true
989 });
990 Object.defineProperty(Widget.prototype, "title", {
991 /**
992 * The title object for the widget.
993 *
994 * #### Notes
995 * The title object is used by some container widgets when displaying
996 * the widget alongside some title, such as a tab panel or side bar.
997 *
998 * Since not all widgets will use the title, it is created on demand.
999 *
1000 * The `owner` property of the title is set to this widget.
1001 */
1002 get: function () {
1003 return Private$j.titleProperty.get(this);
1004 },
1005 enumerable: true,
1006 configurable: true
1007 });
1008 Object.defineProperty(Widget.prototype, "id", {
1009 /**
1010 * Get the id of the widget's DOM node.
1011 */
1012 get: function () {
1013 return this.node.id;
1014 },
1015 /**
1016 * Set the id of the widget's DOM node.
1017 */
1018 set: function (value) {
1019 this.node.id = value;
1020 },
1021 enumerable: true,
1022 configurable: true
1023 });
1024 Object.defineProperty(Widget.prototype, "dataset", {
1025 /**
1026 * The dataset for the widget's DOM node.
1027 */
1028 get: function () {
1029 return this.node.dataset;
1030 },
1031 enumerable: true,
1032 configurable: true
1033 });
1034 Object.defineProperty(Widget.prototype, "hiddenMode", {
1035 /**
1036 * Get the method for hiding the widget.
1037 */
1038 get: function () {
1039 return this._hiddenMode;
1040 },
1041 /**
1042 * Set the method for hiding the widget.
1043 */
1044 set: function (value) {
1045 if (this._hiddenMode === value) {
1046 return;
1047 }
1048 this._hiddenMode = value;
1049 switch (value) {
1050 case Widget.HiddenMode.Display:
1051 this.node.style.willChange = 'auto';
1052 break;
1053 case Widget.HiddenMode.Scale:
1054 this.node.style.willChange = 'transform';
1055 break;
1056 }
1057 if (this.isHidden) {
1058 if (value === Widget.HiddenMode.Display) {
1059 this.addClass('lm-mod-hidden');
1060 /* <DEPRECATED> */
1061 this.addClass('p-mod-hidden');
1062 /* </DEPRECATED> */
1063 this.node.style.transform = '';
1064 }
1065 else {
1066 this.node.style.transform = 'scale(0)';
1067 this.removeClass('lm-mod-hidden');
1068 /* <DEPRECATED> */
1069 this.removeClass('p-mod-hidden');
1070 /* </DEPRECATED> */
1071 }
1072 }
1073 },
1074 enumerable: true,
1075 configurable: true
1076 });
1077 Object.defineProperty(Widget.prototype, "parent", {
1078 /**
1079 * Get the parent of the widget.
1080 */
1081 get: function () {
1082 return this._parent;
1083 },
1084 /**
1085 * Set the parent of the widget.
1086 *
1087 * #### Notes
1088 * Children are typically added to a widget by using a layout, which
1089 * means user code will not normally set the parent widget directly.
1090 *
1091 * The widget will be automatically removed from its old parent.
1092 *
1093 * This is a no-op if there is no effective parent change.
1094 */
1095 set: function (value) {
1096 if (this._parent === value) {
1097 return;
1098 }
1099 if (value && this.contains(value)) {
1100 throw new Error('Invalid parent widget.');
1101 }
1102 if (this._parent && !this._parent.isDisposed) {
1103 var msg = new Widget.ChildMessage('child-removed', this);
1104 messaging.MessageLoop.sendMessage(this._parent, msg);
1105 }
1106 this._parent = value;
1107 if (this._parent && !this._parent.isDisposed) {
1108 var msg = new Widget.ChildMessage('child-added', this);
1109 messaging.MessageLoop.sendMessage(this._parent, msg);
1110 }
1111 if (!this.isDisposed) {
1112 messaging.MessageLoop.sendMessage(this, Widget.Msg.ParentChanged);
1113 }
1114 },
1115 enumerable: true,
1116 configurable: true
1117 });
1118 Object.defineProperty(Widget.prototype, "layout", {
1119 /**
1120 * Get the layout for the widget.
1121 */
1122 get: function () {
1123 return this._layout;
1124 },
1125 /**
1126 * Set the layout for the widget.
1127 *
1128 * #### Notes
1129 * The layout is single-use only. It cannot be changed after the
1130 * first assignment.
1131 *
1132 * The layout is disposed automatically when the widget is disposed.
1133 */
1134 set: function (value) {
1135 if (this._layout === value) {
1136 return;
1137 }
1138 if (this.testFlag(Widget.Flag.DisallowLayout)) {
1139 throw new Error('Cannot set widget layout.');
1140 }
1141 if (this._layout) {
1142 throw new Error('Cannot change widget layout.');
1143 }
1144 if (value.parent) {
1145 throw new Error('Cannot change layout parent.');
1146 }
1147 this._layout = value;
1148 value.parent = this;
1149 },
1150 enumerable: true,
1151 configurable: true
1152 });
1153 /**
1154 * Create an iterator over the widget's children.
1155 *
1156 * @returns A new iterator over the children of the widget.
1157 *
1158 * #### Notes
1159 * The widget must have a populated layout in order to have children.
1160 *
1161 * If a layout is not installed, the returned iterator will be empty.
1162 */
1163 Widget.prototype.children = function () {
1164 return this._layout ? this._layout.iter() : algorithm.empty();
1165 };
1166 /**
1167 * Test whether a widget is a descendant of this widget.
1168 *
1169 * @param widget - The descendant widget of interest.
1170 *
1171 * @returns `true` if the widget is a descendant, `false` otherwise.
1172 */
1173 Widget.prototype.contains = function (widget) {
1174 for (var value = widget; value; value = value._parent) {
1175 if (value === this) {
1176 return true;
1177 }
1178 }
1179 return false;
1180 };
1181 /**
1182 * Test whether the widget's DOM node has the given class name.
1183 *
1184 * @param name - The class name of interest.
1185 *
1186 * @returns `true` if the node has the class, `false` otherwise.
1187 */
1188 Widget.prototype.hasClass = function (name) {
1189 return this.node.classList.contains(name);
1190 };
1191 /**
1192 * Add a class name to the widget's DOM node.
1193 *
1194 * @param name - The class name to add to the node.
1195 *
1196 * #### Notes
1197 * If the class name is already added to the node, this is a no-op.
1198 *
1199 * The class name must not contain whitespace.
1200 */
1201 Widget.prototype.addClass = function (name) {
1202 this.node.classList.add(name);
1203 };
1204 /**
1205 * Remove a class name from the widget's DOM node.
1206 *
1207 * @param name - The class name to remove from the node.
1208 *
1209 * #### Notes
1210 * If the class name is not yet added to the node, this is a no-op.
1211 *
1212 * The class name must not contain whitespace.
1213 */
1214 Widget.prototype.removeClass = function (name) {
1215 this.node.classList.remove(name);
1216 };
1217 /**
1218 * Toggle a class name on the widget's DOM node.
1219 *
1220 * @param name - The class name to toggle on the node.
1221 *
1222 * @param force - Whether to force add the class (`true`) or force
1223 * remove the class (`false`). If not provided, the presence of
1224 * the class will be toggled from its current state.
1225 *
1226 * @returns `true` if the class is now present, `false` otherwise.
1227 *
1228 * #### Notes
1229 * The class name must not contain whitespace.
1230 */
1231 Widget.prototype.toggleClass = function (name, force) {
1232 if (force === true) {
1233 this.node.classList.add(name);
1234 return true;
1235 }
1236 if (force === false) {
1237 this.node.classList.remove(name);
1238 return false;
1239 }
1240 return this.node.classList.toggle(name);
1241 };
1242 /**
1243 * Post an `'update-request'` message to the widget.
1244 *
1245 * #### Notes
1246 * This is a simple convenience method for posting the message.
1247 */
1248 Widget.prototype.update = function () {
1249 messaging.MessageLoop.postMessage(this, Widget.Msg.UpdateRequest);
1250 };
1251 /**
1252 * Post a `'fit-request'` message to the widget.
1253 *
1254 * #### Notes
1255 * This is a simple convenience method for posting the message.
1256 */
1257 Widget.prototype.fit = function () {
1258 messaging.MessageLoop.postMessage(this, Widget.Msg.FitRequest);
1259 };
1260 /**
1261 * Post an `'activate-request'` message to the widget.
1262 *
1263 * #### Notes
1264 * This is a simple convenience method for posting the message.
1265 */
1266 Widget.prototype.activate = function () {
1267 messaging.MessageLoop.postMessage(this, Widget.Msg.ActivateRequest);
1268 };
1269 /**
1270 * Send a `'close-request'` message to the widget.
1271 *
1272 * #### Notes
1273 * This is a simple convenience method for sending the message.
1274 */
1275 Widget.prototype.close = function () {
1276 messaging.MessageLoop.sendMessage(this, Widget.Msg.CloseRequest);
1277 };
1278 /**
1279 * Show the widget and make it visible to its parent widget.
1280 *
1281 * #### Notes
1282 * This causes the [[isHidden]] property to be `false`.
1283 *
1284 * If the widget is not explicitly hidden, this is a no-op.
1285 */
1286 Widget.prototype.show = function () {
1287 if (!this.testFlag(Widget.Flag.IsHidden)) {
1288 return;
1289 }
1290 if (this.isAttached && (!this.parent || this.parent.isVisible)) {
1291 messaging.MessageLoop.sendMessage(this, Widget.Msg.BeforeShow);
1292 }
1293 this.clearFlag(Widget.Flag.IsHidden);
1294 this.node.removeAttribute('aria-hidden');
1295 if (this.hiddenMode === Widget.HiddenMode.Display) {
1296 this.removeClass('lm-mod-hidden');
1297 /* <DEPRECATED> */
1298 this.removeClass('p-mod-hidden');
1299 /* </DEPRECATED> */
1300 }
1301 else {
1302 this.node.style.transform = '';
1303 }
1304 if (this.isAttached && (!this.parent || this.parent.isVisible)) {
1305 messaging.MessageLoop.sendMessage(this, Widget.Msg.AfterShow);
1306 }
1307 if (this.parent) {
1308 var msg = new Widget.ChildMessage('child-shown', this);
1309 messaging.MessageLoop.sendMessage(this.parent, msg);
1310 }
1311 };
1312 /**
1313 * Hide the widget and make it hidden to its parent widget.
1314 *
1315 * #### Notes
1316 * This causes the [[isHidden]] property to be `true`.
1317 *
1318 * If the widget is explicitly hidden, this is a no-op.
1319 */
1320 Widget.prototype.hide = function () {
1321 if (this.testFlag(Widget.Flag.IsHidden)) {
1322 return;
1323 }
1324 if (this.isAttached && (!this.parent || this.parent.isVisible)) {
1325 messaging.MessageLoop.sendMessage(this, Widget.Msg.BeforeHide);
1326 }
1327 this.setFlag(Widget.Flag.IsHidden);
1328 this.node.setAttribute('aria-hidden', 'true');
1329 if (this.hiddenMode === Widget.HiddenMode.Display) {
1330 this.addClass('lm-mod-hidden');
1331 /* <DEPRECATED> */
1332 this.addClass('p-mod-hidden');
1333 /* </DEPRECATED> */
1334 }
1335 else {
1336 this.node.style.transform = 'scale(0)';
1337 }
1338 if (this.isAttached && (!this.parent || this.parent.isVisible)) {
1339 messaging.MessageLoop.sendMessage(this, Widget.Msg.AfterHide);
1340 }
1341 if (this.parent) {
1342 var msg = new Widget.ChildMessage('child-hidden', this);
1343 messaging.MessageLoop.sendMessage(this.parent, msg);
1344 }
1345 };
1346 /**
1347 * Show or hide the widget according to a boolean value.
1348 *
1349 * @param hidden - `true` to hide the widget, or `false` to show it.
1350 *
1351 * #### Notes
1352 * This is a convenience method for `hide()` and `show()`.
1353 */
1354 Widget.prototype.setHidden = function (hidden) {
1355 if (hidden) {
1356 this.hide();
1357 }
1358 else {
1359 this.show();
1360 }
1361 };
1362 /**
1363 * Test whether the given widget flag is set.
1364 *
1365 * #### Notes
1366 * This will not typically be called directly by user code.
1367 */
1368 Widget.prototype.testFlag = function (flag) {
1369 return (this._flags & flag) !== 0;
1370 };
1371 /**
1372 * Set the given widget flag.
1373 *
1374 * #### Notes
1375 * This will not typically be called directly by user code.
1376 */
1377 Widget.prototype.setFlag = function (flag) {
1378 this._flags |= flag;
1379 };
1380 /**
1381 * Clear the given widget flag.
1382 *
1383 * #### Notes
1384 * This will not typically be called directly by user code.
1385 */
1386 Widget.prototype.clearFlag = function (flag) {
1387 this._flags &= ~flag;
1388 };
1389 /**
1390 * Process a message sent to the widget.
1391 *
1392 * @param msg - The message sent to the widget.
1393 *
1394 * #### Notes
1395 * Subclasses may reimplement this method as needed.
1396 */
1397 Widget.prototype.processMessage = function (msg) {
1398 switch (msg.type) {
1399 case 'resize':
1400 this.notifyLayout(msg);
1401 this.onResize(msg);
1402 break;
1403 case 'update-request':
1404 this.notifyLayout(msg);
1405 this.onUpdateRequest(msg);
1406 break;
1407 case 'fit-request':
1408 this.notifyLayout(msg);
1409 this.onFitRequest(msg);
1410 break;
1411 case 'before-show':
1412 this.notifyLayout(msg);
1413 this.onBeforeShow(msg);
1414 break;
1415 case 'after-show':
1416 this.setFlag(Widget.Flag.IsVisible);
1417 this.notifyLayout(msg);
1418 this.onAfterShow(msg);
1419 break;
1420 case 'before-hide':
1421 this.notifyLayout(msg);
1422 this.onBeforeHide(msg);
1423 break;
1424 case 'after-hide':
1425 this.clearFlag(Widget.Flag.IsVisible);
1426 this.notifyLayout(msg);
1427 this.onAfterHide(msg);
1428 break;
1429 case 'before-attach':
1430 this.notifyLayout(msg);
1431 this.onBeforeAttach(msg);
1432 break;
1433 case 'after-attach':
1434 if (!this.isHidden && (!this.parent || this.parent.isVisible)) {
1435 this.setFlag(Widget.Flag.IsVisible);
1436 }
1437 this.setFlag(Widget.Flag.IsAttached);
1438 this.notifyLayout(msg);
1439 this.onAfterAttach(msg);
1440 break;
1441 case 'before-detach':
1442 this.notifyLayout(msg);
1443 this.onBeforeDetach(msg);
1444 break;
1445 case 'after-detach':
1446 this.clearFlag(Widget.Flag.IsVisible);
1447 this.clearFlag(Widget.Flag.IsAttached);
1448 this.notifyLayout(msg);
1449 this.onAfterDetach(msg);
1450 break;
1451 case 'activate-request':
1452 this.notifyLayout(msg);
1453 this.onActivateRequest(msg);
1454 break;
1455 case 'close-request':
1456 this.notifyLayout(msg);
1457 this.onCloseRequest(msg);
1458 break;
1459 case 'child-added':
1460 this.notifyLayout(msg);
1461 this.onChildAdded(msg);
1462 break;
1463 case 'child-removed':
1464 this.notifyLayout(msg);
1465 this.onChildRemoved(msg);
1466 break;
1467 default:
1468 this.notifyLayout(msg);
1469 break;
1470 }
1471 };
1472 /**
1473 * Invoke the message processing routine of the widget's layout.
1474 *
1475 * @param msg - The message to dispatch to the layout.
1476 *
1477 * #### Notes
1478 * This is a no-op if the widget does not have a layout.
1479 *
1480 * This will not typically be called directly by user code.
1481 */
1482 Widget.prototype.notifyLayout = function (msg) {
1483 if (this._layout) {
1484 this._layout.processParentMessage(msg);
1485 }
1486 };
1487 /**
1488 * A message handler invoked on a `'close-request'` message.
1489 *
1490 * #### Notes
1491 * The default implementation unparents or detaches the widget.
1492 */
1493 Widget.prototype.onCloseRequest = function (msg) {
1494 if (this.parent) {
1495 this.parent = null;
1496 }
1497 else if (this.isAttached) {
1498 Widget.detach(this);
1499 }
1500 };
1501 /**
1502 * A message handler invoked on a `'resize'` message.
1503 *
1504 * #### Notes
1505 * The default implementation of this handler is a no-op.
1506 */
1507 Widget.prototype.onResize = function (msg) { };
1508 /**
1509 * A message handler invoked on an `'update-request'` message.
1510 *
1511 * #### Notes
1512 * The default implementation of this handler is a no-op.
1513 */
1514 Widget.prototype.onUpdateRequest = function (msg) { };
1515 /**
1516 * A message handler invoked on a `'fit-request'` message.
1517 *
1518 * #### Notes
1519 * The default implementation of this handler is a no-op.
1520 */
1521 Widget.prototype.onFitRequest = function (msg) { };
1522 /**
1523 * A message handler invoked on an `'activate-request'` message.
1524 *
1525 * #### Notes
1526 * The default implementation of this handler is a no-op.
1527 */
1528 Widget.prototype.onActivateRequest = function (msg) { };
1529 /**
1530 * A message handler invoked on a `'before-show'` message.
1531 *
1532 * #### Notes
1533 * The default implementation of this handler is a no-op.
1534 */
1535 Widget.prototype.onBeforeShow = function (msg) { };
1536 /**
1537 * A message handler invoked on an `'after-show'` message.
1538 *
1539 * #### Notes
1540 * The default implementation of this handler is a no-op.
1541 */
1542 Widget.prototype.onAfterShow = function (msg) { };
1543 /**
1544 * A message handler invoked on a `'before-hide'` message.
1545 *
1546 * #### Notes
1547 * The default implementation of this handler is a no-op.
1548 */
1549 Widget.prototype.onBeforeHide = function (msg) { };
1550 /**
1551 * A message handler invoked on an `'after-hide'` message.
1552 *
1553 * #### Notes
1554 * The default implementation of this handler is a no-op.
1555 */
1556 Widget.prototype.onAfterHide = function (msg) { };
1557 /**
1558 * A message handler invoked on a `'before-attach'` message.
1559 *
1560 * #### Notes
1561 * The default implementation of this handler is a no-op.
1562 */
1563 Widget.prototype.onBeforeAttach = function (msg) { };
1564 /**
1565 * A message handler invoked on an `'after-attach'` message.
1566 *
1567 * #### Notes
1568 * The default implementation of this handler is a no-op.
1569 */
1570 Widget.prototype.onAfterAttach = function (msg) { };
1571 /**
1572 * A message handler invoked on a `'before-detach'` message.
1573 *
1574 * #### Notes
1575 * The default implementation of this handler is a no-op.
1576 */
1577 Widget.prototype.onBeforeDetach = function (msg) { };
1578 /**
1579 * A message handler invoked on an `'after-detach'` message.
1580 *
1581 * #### Notes
1582 * The default implementation of this handler is a no-op.
1583 */
1584 Widget.prototype.onAfterDetach = function (msg) { };
1585 /**
1586 * A message handler invoked on a `'child-added'` message.
1587 *
1588 * #### Notes
1589 * The default implementation of this handler is a no-op.
1590 */
1591 Widget.prototype.onChildAdded = function (msg) { };
1592 /**
1593 * A message handler invoked on a `'child-removed'` message.
1594 *
1595 * #### Notes
1596 * The default implementation of this handler is a no-op.
1597 */
1598 Widget.prototype.onChildRemoved = function (msg) { };
1599 return Widget;
1600 }());
1601 /**
1602 * The namespace for the `Widget` class statics.
1603 */
1604 (function (Widget) {
1605 (function (HiddenMode) {
1606 /**
1607 * Set a `lm-mod-hidden` CSS class to hide the widget using `display:none`
1608 * CSS from the standard Lumino CSS.
1609 */
1610 HiddenMode[HiddenMode["Display"] = 0] = "Display";
1611 /**
1612 * Hide the widget by setting the `transform` to `'scale(0)'`.
1613 */
1614 HiddenMode[HiddenMode["Scale"] = 1] = "Scale";
1615 })(Widget.HiddenMode || (Widget.HiddenMode = {}));
1616 (function (Flag) {
1617 /**
1618 * The widget has been disposed.
1619 */
1620 Flag[Flag["IsDisposed"] = 1] = "IsDisposed";
1621 /**
1622 * The widget is attached to the DOM.
1623 */
1624 Flag[Flag["IsAttached"] = 2] = "IsAttached";
1625 /**
1626 * The widget is hidden.
1627 */
1628 Flag[Flag["IsHidden"] = 4] = "IsHidden";
1629 /**
1630 * The widget is visible.
1631 */
1632 Flag[Flag["IsVisible"] = 8] = "IsVisible";
1633 /**
1634 * A layout cannot be set on the widget.
1635 */
1636 Flag[Flag["DisallowLayout"] = 16] = "DisallowLayout";
1637 })(Widget.Flag || (Widget.Flag = {}));
1638 (function (Msg) {
1639 /**
1640 * A singleton `'before-show'` message.
1641 *
1642 * #### Notes
1643 * This message is sent to a widget before it becomes visible.
1644 *
1645 * This message is **not** sent when the widget is being attached.
1646 */
1647 Msg.BeforeShow = new messaging.Message('before-show');
1648 /**
1649 * A singleton `'after-show'` message.
1650 *
1651 * #### Notes
1652 * This message is sent to a widget after it becomes visible.
1653 *
1654 * This message is **not** sent when the widget is being attached.
1655 */
1656 Msg.AfterShow = new messaging.Message('after-show');
1657 /**
1658 * A singleton `'before-hide'` message.
1659 *
1660 * #### Notes
1661 * This message is sent to a widget before it becomes not-visible.
1662 *
1663 * This message is **not** sent when the widget is being detached.
1664 */
1665 Msg.BeforeHide = new messaging.Message('before-hide');
1666 /**
1667 * A singleton `'after-hide'` message.
1668 *
1669 * #### Notes
1670 * This message is sent to a widget after it becomes not-visible.
1671 *
1672 * This message is **not** sent when the widget is being detached.
1673 */
1674 Msg.AfterHide = new messaging.Message('after-hide');
1675 /**
1676 * A singleton `'before-attach'` message.
1677 *
1678 * #### Notes
1679 * This message is sent to a widget before it is attached.
1680 */
1681 Msg.BeforeAttach = new messaging.Message('before-attach');
1682 /**
1683 * A singleton `'after-attach'` message.
1684 *
1685 * #### Notes
1686 * This message is sent to a widget after it is attached.
1687 */
1688 Msg.AfterAttach = new messaging.Message('after-attach');
1689 /**
1690 * A singleton `'before-detach'` message.
1691 *
1692 * #### Notes
1693 * This message is sent to a widget before it is detached.
1694 */
1695 Msg.BeforeDetach = new messaging.Message('before-detach');
1696 /**
1697 * A singleton `'after-detach'` message.
1698 *
1699 * #### Notes
1700 * This message is sent to a widget after it is detached.
1701 */
1702 Msg.AfterDetach = new messaging.Message('after-detach');
1703 /**
1704 * A singleton `'parent-changed'` message.
1705 *
1706 * #### Notes
1707 * This message is sent to a widget when its parent has changed.
1708 */
1709 Msg.ParentChanged = new messaging.Message('parent-changed');
1710 /**
1711 * A singleton conflatable `'update-request'` message.
1712 *
1713 * #### Notes
1714 * This message can be dispatched to supporting widgets in order to
1715 * update their content based on the current widget state. Not all
1716 * widgets will respond to messages of this type.
1717 *
1718 * For widgets with a layout, this message will inform the layout to
1719 * update the position and size of its child widgets.
1720 */
1721 Msg.UpdateRequest = new messaging.ConflatableMessage('update-request');
1722 /**
1723 * A singleton conflatable `'fit-request'` message.
1724 *
1725 * #### Notes
1726 * For widgets with a layout, this message will inform the layout to
1727 * recalculate its size constraints to fit the space requirements of
1728 * its child widgets, and to update their position and size. Not all
1729 * layouts will respond to messages of this type.
1730 */
1731 Msg.FitRequest = new messaging.ConflatableMessage('fit-request');
1732 /**
1733 * A singleton conflatable `'activate-request'` message.
1734 *
1735 * #### Notes
1736 * This message should be dispatched to a widget when it should
1737 * perform the actions necessary to activate the widget, which
1738 * may include focusing its node or descendant node.
1739 */
1740 Msg.ActivateRequest = new messaging.ConflatableMessage('activate-request');
1741 /**
1742 * A singleton conflatable `'close-request'` message.
1743 *
1744 * #### Notes
1745 * This message should be dispatched to a widget when it should close
1746 * and remove itself from the widget hierarchy.
1747 */
1748 Msg.CloseRequest = new messaging.ConflatableMessage('close-request');
1749 })(Widget.Msg || (Widget.Msg = {}));
1750 /**
1751 * A message class for child related messages.
1752 */
1753 var ChildMessage = /** @class */ (function (_super) {
1754 __extends(ChildMessage, _super);
1755 /**
1756 * Construct a new child message.
1757 *
1758 * @param type - The message type.
1759 *
1760 * @param child - The child widget for the message.
1761 */
1762 function ChildMessage(type, child) {
1763 var _this = _super.call(this, type) || this;
1764 _this.child = child;
1765 return _this;
1766 }
1767 return ChildMessage;
1768 }(messaging.Message));
1769 Widget.ChildMessage = ChildMessage;
1770 /**
1771 * A message class for `'resize'` messages.
1772 */
1773 var ResizeMessage = /** @class */ (function (_super) {
1774 __extends(ResizeMessage, _super);
1775 /**
1776 * Construct a new resize message.
1777 *
1778 * @param width - The **offset width** of the widget, or `-1` if
1779 * the width is not known.
1780 *
1781 * @param height - The **offset height** of the widget, or `-1` if
1782 * the height is not known.
1783 */
1784 function ResizeMessage(width, height) {
1785 var _this = _super.call(this, 'resize') || this;
1786 _this.width = width;
1787 _this.height = height;
1788 return _this;
1789 }
1790 return ResizeMessage;
1791 }(messaging.Message));
1792 Widget.ResizeMessage = ResizeMessage;
1793 /**
1794 * The namespace for the `ResizeMessage` class statics.
1795 */
1796 (function (ResizeMessage) {
1797 /**
1798 * A singleton `'resize'` message with an unknown size.
1799 */
1800 ResizeMessage.UnknownSize = new ResizeMessage(-1, -1);
1801 })(ResizeMessage = Widget.ResizeMessage || (Widget.ResizeMessage = {}));
1802 /**
1803 * Attach a widget to a host DOM node.
1804 *
1805 * @param widget - The widget of interest.
1806 *
1807 * @param host - The DOM node to use as the widget's host.
1808 *
1809 * @param ref - The child of `host` to use as the reference element.
1810 * If this is provided, the widget will be inserted before this
1811 * node in the host. The default is `null`, which will cause the
1812 * widget to be added as the last child of the host.
1813 *
1814 * #### Notes
1815 * This will throw an error if the widget is not a root widget, if
1816 * the widget is already attached, or if the host is not attached
1817 * to the DOM.
1818 */
1819 function attach(widget, host, ref) {
1820 if (ref === void 0) { ref = null; }
1821 if (widget.parent) {
1822 throw new Error('Cannot attach a child widget.');
1823 }
1824 if (widget.isAttached || widget.node.isConnected) {
1825 throw new Error('Widget is already attached.');
1826 }
1827 if (!host.isConnected) {
1828 throw new Error('Host is not attached.');
1829 }
1830 messaging.MessageLoop.sendMessage(widget, Widget.Msg.BeforeAttach);
1831 host.insertBefore(widget.node, ref);
1832 messaging.MessageLoop.sendMessage(widget, Widget.Msg.AfterAttach);
1833 }
1834 Widget.attach = attach;
1835 /**
1836 * Detach the widget from its host DOM node.
1837 *
1838 * @param widget - The widget of interest.
1839 *
1840 * #### Notes
1841 * This will throw an error if the widget is not a root widget,
1842 * or if the widget is not attached to the DOM.
1843 */
1844 function detach(widget) {
1845 if (widget.parent) {
1846 throw new Error('Cannot detach a child widget.');
1847 }
1848 if (!widget.isAttached || !widget.node.isConnected) {
1849 throw new Error('Widget is not attached.');
1850 }
1851 messaging.MessageLoop.sendMessage(widget, Widget.Msg.BeforeDetach);
1852 widget.node.parentNode.removeChild(widget.node);
1853 messaging.MessageLoop.sendMessage(widget, Widget.Msg.AfterDetach);
1854 }
1855 Widget.detach = detach;
1856 })(exports.Widget || (exports.Widget = {}));
1857 /**
1858 * The namespace for the module implementation details.
1859 */
1860 var Private$j;
1861 (function (Private) {
1862 /**
1863 * An attached property for the widget title object.
1864 */
1865 Private.titleProperty = new properties.AttachedProperty({
1866 name: 'title',
1867 create: function (owner) { return new Title({ owner: owner }); }
1868 });
1869 /**
1870 * Create a DOM node for the given widget options.
1871 */
1872 function createNode(options) {
1873 return options.node || document.createElement(options.tag || 'div');
1874 }
1875 Private.createNode = createNode;
1876 })(Private$j || (Private$j = {}));
1877
1878 /* eslint-disable @typescript-eslint/no-empty-function */
1879 /**
1880 * An abstract base class for creating lumino layouts.
1881 *
1882 * #### Notes
1883 * A layout is used to add widgets to a parent and to arrange those
1884 * widgets within the parent's DOM node.
1885 *
1886 * This class implements the base functionality which is required of
1887 * nearly all layouts. It must be subclassed in order to be useful.
1888 *
1889 * Notably, this class does not define a uniform interface for adding
1890 * widgets to the layout. A subclass should define that API in a way
1891 * which is meaningful for its intended use.
1892 */
1893 exports.Layout = /** @class */ (function () {
1894 /**
1895 * Construct a new layout.
1896 *
1897 * @param options - The options for initializing the layout.
1898 */
1899 function Layout(options) {
1900 if (options === void 0) { options = {}; }
1901 this._disposed = false;
1902 this._parent = null;
1903 this._fitPolicy = options.fitPolicy || 'set-min-size';
1904 }
1905 /**
1906 * Dispose of the resources held by the layout.
1907 *
1908 * #### Notes
1909 * This should be reimplemented to clear and dispose of the widgets.
1910 *
1911 * All reimplementations should call the superclass method.
1912 *
1913 * This method is called automatically when the parent is disposed.
1914 */
1915 Layout.prototype.dispose = function () {
1916 this._parent = null;
1917 this._disposed = true;
1918 signaling.Signal.clearData(this);
1919 properties.AttachedProperty.clearData(this);
1920 };
1921 Object.defineProperty(Layout.prototype, "isDisposed", {
1922 /**
1923 * Test whether the layout is disposed.
1924 */
1925 get: function () {
1926 return this._disposed;
1927 },
1928 enumerable: true,
1929 configurable: true
1930 });
1931 Object.defineProperty(Layout.prototype, "parent", {
1932 /**
1933 * Get the parent widget of the layout.
1934 */
1935 get: function () {
1936 return this._parent;
1937 },
1938 /**
1939 * Set the parent widget of the layout.
1940 *
1941 * #### Notes
1942 * This is set automatically when installing the layout on the parent
1943 * widget. The parent widget should not be set directly by user code.
1944 */
1945 set: function (value) {
1946 if (this._parent === value) {
1947 return;
1948 }
1949 if (this._parent) {
1950 throw new Error('Cannot change parent widget.');
1951 }
1952 if (value.layout !== this) {
1953 throw new Error('Invalid parent widget.');
1954 }
1955 this._parent = value;
1956 this.init();
1957 },
1958 enumerable: true,
1959 configurable: true
1960 });
1961 Object.defineProperty(Layout.prototype, "fitPolicy", {
1962 /**
1963 * Get the fit policy for the layout.
1964 *
1965 * #### Notes
1966 * The fit policy controls the computed size constraints which are
1967 * applied to the parent widget by the layout.
1968 *
1969 * Some layout implementations may ignore the fit policy.
1970 */
1971 get: function () {
1972 return this._fitPolicy;
1973 },
1974 /**
1975 * Set the fit policy for the layout.
1976 *
1977 * #### Notes
1978 * The fit policy controls the computed size constraints which are
1979 * applied to the parent widget by the layout.
1980 *
1981 * Some layout implementations may ignore the fit policy.
1982 *
1983 * Changing the fit policy will clear the current size constraint
1984 * for the parent widget and then re-fit the parent.
1985 */
1986 set: function (value) {
1987 // Bail if the policy does not change
1988 if (this._fitPolicy === value) {
1989 return;
1990 }
1991 // Update the internal policy.
1992 this._fitPolicy = value;
1993 // Clear the size constraints and schedule a fit of the parent.
1994 if (this._parent) {
1995 var style = this._parent.node.style;
1996 style.minWidth = '';
1997 style.minHeight = '';
1998 style.maxWidth = '';
1999 style.maxHeight = '';
2000 this._parent.fit();
2001 }
2002 },
2003 enumerable: true,
2004 configurable: true
2005 });
2006 /**
2007 * Process a message sent to the parent widget.
2008 *
2009 * @param msg - The message sent to the parent widget.
2010 *
2011 * #### Notes
2012 * This method is called by the parent widget to process a message.
2013 *
2014 * Subclasses may reimplement this method as needed.
2015 */
2016 Layout.prototype.processParentMessage = function (msg) {
2017 switch (msg.type) {
2018 case 'resize':
2019 this.onResize(msg);
2020 break;
2021 case 'update-request':
2022 this.onUpdateRequest(msg);
2023 break;
2024 case 'fit-request':
2025 this.onFitRequest(msg);
2026 break;
2027 case 'before-show':
2028 this.onBeforeShow(msg);
2029 break;
2030 case 'after-show':
2031 this.onAfterShow(msg);
2032 break;
2033 case 'before-hide':
2034 this.onBeforeHide(msg);
2035 break;
2036 case 'after-hide':
2037 this.onAfterHide(msg);
2038 break;
2039 case 'before-attach':
2040 this.onBeforeAttach(msg);
2041 break;
2042 case 'after-attach':
2043 this.onAfterAttach(msg);
2044 break;
2045 case 'before-detach':
2046 this.onBeforeDetach(msg);
2047 break;
2048 case 'after-detach':
2049 this.onAfterDetach(msg);
2050 break;
2051 case 'child-removed':
2052 this.onChildRemoved(msg);
2053 break;
2054 case 'child-shown':
2055 this.onChildShown(msg);
2056 break;
2057 case 'child-hidden':
2058 this.onChildHidden(msg);
2059 break;
2060 }
2061 };
2062 /**
2063 * Perform layout initialization which requires the parent widget.
2064 *
2065 * #### Notes
2066 * This method is invoked immediately after the layout is installed
2067 * on the parent widget.
2068 *
2069 * The default implementation reparents all of the widgets to the
2070 * layout parent widget.
2071 *
2072 * Subclasses should reimplement this method and attach the child
2073 * widget nodes to the parent widget's node.
2074 */
2075 Layout.prototype.init = function () {
2076 var _this = this;
2077 algorithm.each(this, function (widget) {
2078 widget.parent = _this.parent;
2079 });
2080 };
2081 /**
2082 * A message handler invoked on a `'resize'` message.
2083 *
2084 * #### Notes
2085 * The layout should ensure that its widgets are resized according
2086 * to the specified layout space, and that they are sent a `'resize'`
2087 * message if appropriate.
2088 *
2089 * The default implementation of this method sends an `UnknownSize`
2090 * resize message to all widgets.
2091 *
2092 * This may be reimplemented by subclasses as needed.
2093 */
2094 Layout.prototype.onResize = function (msg) {
2095 algorithm.each(this, function (widget) {
2096 messaging.MessageLoop.sendMessage(widget, exports.Widget.ResizeMessage.UnknownSize);
2097 });
2098 };
2099 /**
2100 * A message handler invoked on an `'update-request'` message.
2101 *
2102 * #### Notes
2103 * The layout should ensure that its widgets are resized according
2104 * to the available layout space, and that they are sent a `'resize'`
2105 * message if appropriate.
2106 *
2107 * The default implementation of this method sends an `UnknownSize`
2108 * resize message to all widgets.
2109 *
2110 * This may be reimplemented by subclasses as needed.
2111 */
2112 Layout.prototype.onUpdateRequest = function (msg) {
2113 algorithm.each(this, function (widget) {
2114 messaging.MessageLoop.sendMessage(widget, exports.Widget.ResizeMessage.UnknownSize);
2115 });
2116 };
2117 /**
2118 * A message handler invoked on a `'before-attach'` message.
2119 *
2120 * #### Notes
2121 * The default implementation of this method forwards the message
2122 * to all widgets. It assumes all widget nodes are attached to the
2123 * parent widget node.
2124 *
2125 * This may be reimplemented by subclasses as needed.
2126 */
2127 Layout.prototype.onBeforeAttach = function (msg) {
2128 algorithm.each(this, function (widget) {
2129 messaging.MessageLoop.sendMessage(widget, msg);
2130 });
2131 };
2132 /**
2133 * A message handler invoked on an `'after-attach'` message.
2134 *
2135 * #### Notes
2136 * The default implementation of this method forwards the message
2137 * to all widgets. It assumes all widget nodes are attached to the
2138 * parent widget node.
2139 *
2140 * This may be reimplemented by subclasses as needed.
2141 */
2142 Layout.prototype.onAfterAttach = function (msg) {
2143 algorithm.each(this, function (widget) {
2144 messaging.MessageLoop.sendMessage(widget, msg);
2145 });
2146 };
2147 /**
2148 * A message handler invoked on a `'before-detach'` message.
2149 *
2150 * #### Notes
2151 * The default implementation of this method forwards the message
2152 * to all widgets. It assumes all widget nodes are attached to the
2153 * parent widget node.
2154 *
2155 * This may be reimplemented by subclasses as needed.
2156 */
2157 Layout.prototype.onBeforeDetach = function (msg) {
2158 algorithm.each(this, function (widget) {
2159 messaging.MessageLoop.sendMessage(widget, msg);
2160 });
2161 };
2162 /**
2163 * A message handler invoked on an `'after-detach'` message.
2164 *
2165 * #### Notes
2166 * The default implementation of this method forwards the message
2167 * to all widgets. It assumes all widget nodes are attached to the
2168 * parent widget node.
2169 *
2170 * This may be reimplemented by subclasses as needed.
2171 */
2172 Layout.prototype.onAfterDetach = function (msg) {
2173 algorithm.each(this, function (widget) {
2174 messaging.MessageLoop.sendMessage(widget, msg);
2175 });
2176 };
2177 /**
2178 * A message handler invoked on a `'before-show'` message.
2179 *
2180 * #### Notes
2181 * The default implementation of this method forwards the message to
2182 * all non-hidden widgets. It assumes all widget nodes are attached
2183 * to the parent widget node.
2184 *
2185 * This may be reimplemented by subclasses as needed.
2186 */
2187 Layout.prototype.onBeforeShow = function (msg) {
2188 algorithm.each(this, function (widget) {
2189 if (!widget.isHidden) {
2190 messaging.MessageLoop.sendMessage(widget, msg);
2191 }
2192 });
2193 };
2194 /**
2195 * A message handler invoked on an `'after-show'` message.
2196 *
2197 * #### Notes
2198 * The default implementation of this method forwards the message to
2199 * all non-hidden widgets. It assumes all widget nodes are attached
2200 * to the parent widget node.
2201 *
2202 * This may be reimplemented by subclasses as needed.
2203 */
2204 Layout.prototype.onAfterShow = function (msg) {
2205 algorithm.each(this, function (widget) {
2206 if (!widget.isHidden) {
2207 messaging.MessageLoop.sendMessage(widget, msg);
2208 }
2209 });
2210 };
2211 /**
2212 * A message handler invoked on a `'before-hide'` message.
2213 *
2214 * #### Notes
2215 * The default implementation of this method forwards the message to
2216 * all non-hidden widgets. It assumes all widget nodes are attached
2217 * to the parent widget node.
2218 *
2219 * This may be reimplemented by subclasses as needed.
2220 */
2221 Layout.prototype.onBeforeHide = function (msg) {
2222 algorithm.each(this, function (widget) {
2223 if (!widget.isHidden) {
2224 messaging.MessageLoop.sendMessage(widget, msg);
2225 }
2226 });
2227 };
2228 /**
2229 * A message handler invoked on an `'after-hide'` message.
2230 *
2231 * #### Notes
2232 * The default implementation of this method forwards the message to
2233 * all non-hidden widgets. It assumes all widget nodes are attached
2234 * to the parent widget node.
2235 *
2236 * This may be reimplemented by subclasses as needed.
2237 */
2238 Layout.prototype.onAfterHide = function (msg) {
2239 algorithm.each(this, function (widget) {
2240 if (!widget.isHidden) {
2241 messaging.MessageLoop.sendMessage(widget, msg);
2242 }
2243 });
2244 };
2245 /**
2246 * A message handler invoked on a `'child-removed'` message.
2247 *
2248 * #### Notes
2249 * This will remove the child widget from the layout.
2250 *
2251 * Subclasses should **not** typically reimplement this method.
2252 */
2253 Layout.prototype.onChildRemoved = function (msg) {
2254 this.removeWidget(msg.child);
2255 };
2256 /**
2257 * A message handler invoked on a `'fit-request'` message.
2258 *
2259 * #### Notes
2260 * The default implementation of this handler is a no-op.
2261 */
2262 Layout.prototype.onFitRequest = function (msg) { };
2263 /**
2264 * A message handler invoked on a `'child-shown'` message.
2265 *
2266 * #### Notes
2267 * The default implementation of this handler is a no-op.
2268 */
2269 Layout.prototype.onChildShown = function (msg) { };
2270 /**
2271 * A message handler invoked on a `'child-hidden'` message.
2272 *
2273 * #### Notes
2274 * The default implementation of this handler is a no-op.
2275 */
2276 Layout.prototype.onChildHidden = function (msg) { };
2277 return Layout;
2278 }());
2279 /**
2280 * The namespace for the `Layout` class statics.
2281 */
2282 (function (Layout) {
2283 /**
2284 * Get the horizontal alignment for a widget.
2285 *
2286 * @param widget - The widget of interest.
2287 *
2288 * @returns The horizontal alignment for the widget.
2289 *
2290 * #### Notes
2291 * If the layout width allocated to a widget is larger than its max
2292 * width, the horizontal alignment controls how the widget is placed
2293 * within the extra horizontal space.
2294 *
2295 * If the allocated width is less than the widget's max width, the
2296 * horizontal alignment has no effect.
2297 *
2298 * Some layout implementations may ignore horizontal alignment.
2299 */
2300 function getHorizontalAlignment(widget) {
2301 return Private$i.horizontalAlignmentProperty.get(widget);
2302 }
2303 Layout.getHorizontalAlignment = getHorizontalAlignment;
2304 /**
2305 * Set the horizontal alignment for a widget.
2306 *
2307 * @param widget - The widget of interest.
2308 *
2309 * @param value - The value for the horizontal alignment.
2310 *
2311 * #### Notes
2312 * If the layout width allocated to a widget is larger than its max
2313 * width, the horizontal alignment controls how the widget is placed
2314 * within the extra horizontal space.
2315 *
2316 * If the allocated width is less than the widget's max width, the
2317 * horizontal alignment has no effect.
2318 *
2319 * Some layout implementations may ignore horizontal alignment.
2320 *
2321 * Changing the horizontal alignment will post an `update-request`
2322 * message to widget's parent, provided the parent has a layout
2323 * installed.
2324 */
2325 function setHorizontalAlignment(widget, value) {
2326 Private$i.horizontalAlignmentProperty.set(widget, value);
2327 }
2328 Layout.setHorizontalAlignment = setHorizontalAlignment;
2329 /**
2330 * Get the vertical alignment for a widget.
2331 *
2332 * @param widget - The widget of interest.
2333 *
2334 * @returns The vertical alignment for the widget.
2335 *
2336 * #### Notes
2337 * If the layout height allocated to a widget is larger than its max
2338 * height, the vertical alignment controls how the widget is placed
2339 * within the extra vertical space.
2340 *
2341 * If the allocated height is less than the widget's max height, the
2342 * vertical alignment has no effect.
2343 *
2344 * Some layout implementations may ignore vertical alignment.
2345 */
2346 function getVerticalAlignment(widget) {
2347 return Private$i.verticalAlignmentProperty.get(widget);
2348 }
2349 Layout.getVerticalAlignment = getVerticalAlignment;
2350 /**
2351 * Set the vertical alignment for a widget.
2352 *
2353 * @param widget - The widget of interest.
2354 *
2355 * @param value - The value for the vertical alignment.
2356 *
2357 * #### Notes
2358 * If the layout height allocated to a widget is larger than its max
2359 * height, the vertical alignment controls how the widget is placed
2360 * within the extra vertical space.
2361 *
2362 * If the allocated height is less than the widget's max height, the
2363 * vertical alignment has no effect.
2364 *
2365 * Some layout implementations may ignore vertical alignment.
2366 *
2367 * Changing the horizontal alignment will post an `update-request`
2368 * message to widget's parent, provided the parent has a layout
2369 * installed.
2370 */
2371 function setVerticalAlignment(widget, value) {
2372 Private$i.verticalAlignmentProperty.set(widget, value);
2373 }
2374 Layout.setVerticalAlignment = setVerticalAlignment;
2375 })(exports.Layout || (exports.Layout = {}));
2376 /**
2377 * An object which assists in the absolute layout of widgets.
2378 *
2379 * #### Notes
2380 * This class is useful when implementing a layout which arranges its
2381 * widgets using absolute positioning.
2382 *
2383 * This class is used by nearly all of the built-in lumino layouts.
2384 */
2385 var LayoutItem = /** @class */ (function () {
2386 /**
2387 * Construct a new layout item.
2388 *
2389 * @param widget - The widget to be managed by the item.
2390 *
2391 * #### Notes
2392 * The widget will be set to absolute positioning.
2393 */
2394 function LayoutItem(widget) {
2395 this._top = NaN;
2396 this._left = NaN;
2397 this._width = NaN;
2398 this._height = NaN;
2399 this._minWidth = 0;
2400 this._minHeight = 0;
2401 this._maxWidth = Infinity;
2402 this._maxHeight = Infinity;
2403 this._disposed = false;
2404 this.widget = widget;
2405 this.widget.node.style.position = 'absolute';
2406 }
2407 /**
2408 * Dispose of the the layout item.
2409 *
2410 * #### Notes
2411 * This will reset the positioning of the widget.
2412 */
2413 LayoutItem.prototype.dispose = function () {
2414 // Do nothing if the item is already disposed.
2415 if (this._disposed) {
2416 return;
2417 }
2418 // Mark the item as disposed.
2419 this._disposed = true;
2420 // Reset the widget style.
2421 var style = this.widget.node.style;
2422 style.position = '';
2423 style.top = '';
2424 style.left = '';
2425 style.width = '';
2426 style.height = '';
2427 };
2428 Object.defineProperty(LayoutItem.prototype, "minWidth", {
2429 /**
2430 * The computed minimum width of the widget.
2431 *
2432 * #### Notes
2433 * This value can be updated by calling the `fit` method.
2434 */
2435 get: function () {
2436 return this._minWidth;
2437 },
2438 enumerable: true,
2439 configurable: true
2440 });
2441 Object.defineProperty(LayoutItem.prototype, "minHeight", {
2442 /**
2443 * The computed minimum height of the widget.
2444 *
2445 * #### Notes
2446 * This value can be updated by calling the `fit` method.
2447 */
2448 get: function () {
2449 return this._minHeight;
2450 },
2451 enumerable: true,
2452 configurable: true
2453 });
2454 Object.defineProperty(LayoutItem.prototype, "maxWidth", {
2455 /**
2456 * The computed maximum width of the widget.
2457 *
2458 * #### Notes
2459 * This value can be updated by calling the `fit` method.
2460 */
2461 get: function () {
2462 return this._maxWidth;
2463 },
2464 enumerable: true,
2465 configurable: true
2466 });
2467 Object.defineProperty(LayoutItem.prototype, "maxHeight", {
2468 /**
2469 * The computed maximum height of the widget.
2470 *
2471 * #### Notes
2472 * This value can be updated by calling the `fit` method.
2473 */
2474 get: function () {
2475 return this._maxHeight;
2476 },
2477 enumerable: true,
2478 configurable: true
2479 });
2480 Object.defineProperty(LayoutItem.prototype, "isDisposed", {
2481 /**
2482 * Whether the layout item is disposed.
2483 */
2484 get: function () {
2485 return this._disposed;
2486 },
2487 enumerable: true,
2488 configurable: true
2489 });
2490 Object.defineProperty(LayoutItem.prototype, "isHidden", {
2491 /**
2492 * Whether the managed widget is hidden.
2493 */
2494 get: function () {
2495 return this.widget.isHidden;
2496 },
2497 enumerable: true,
2498 configurable: true
2499 });
2500 Object.defineProperty(LayoutItem.prototype, "isVisible", {
2501 /**
2502 * Whether the managed widget is visible.
2503 */
2504 get: function () {
2505 return this.widget.isVisible;
2506 },
2507 enumerable: true,
2508 configurable: true
2509 });
2510 Object.defineProperty(LayoutItem.prototype, "isAttached", {
2511 /**
2512 * Whether the managed widget is attached.
2513 */
2514 get: function () {
2515 return this.widget.isAttached;
2516 },
2517 enumerable: true,
2518 configurable: true
2519 });
2520 /**
2521 * Update the computed size limits of the managed widget.
2522 */
2523 LayoutItem.prototype.fit = function () {
2524 var limits = domutils.ElementExt.sizeLimits(this.widget.node);
2525 this._minWidth = limits.minWidth;
2526 this._minHeight = limits.minHeight;
2527 this._maxWidth = limits.maxWidth;
2528 this._maxHeight = limits.maxHeight;
2529 };
2530 /**
2531 * Update the position and size of the managed widget.
2532 *
2533 * @param left - The left edge position of the layout box.
2534 *
2535 * @param top - The top edge position of the layout box.
2536 *
2537 * @param width - The width of the layout box.
2538 *
2539 * @param height - The height of the layout box.
2540 */
2541 LayoutItem.prototype.update = function (left, top, width, height) {
2542 // Clamp the size to the computed size limits.
2543 var clampW = Math.max(this._minWidth, Math.min(width, this._maxWidth));
2544 var clampH = Math.max(this._minHeight, Math.min(height, this._maxHeight));
2545 // Adjust the left edge for the horizontal alignment, if needed.
2546 if (clampW < width) {
2547 switch (exports.Layout.getHorizontalAlignment(this.widget)) {
2548 case 'left':
2549 break;
2550 case 'center':
2551 left += (width - clampW) / 2;
2552 break;
2553 case 'right':
2554 left += width - clampW;
2555 break;
2556 default:
2557 throw 'unreachable';
2558 }
2559 }
2560 // Adjust the top edge for the vertical alignment, if needed.
2561 if (clampH < height) {
2562 switch (exports.Layout.getVerticalAlignment(this.widget)) {
2563 case 'top':
2564 break;
2565 case 'center':
2566 top += (height - clampH) / 2;
2567 break;
2568 case 'bottom':
2569 top += height - clampH;
2570 break;
2571 default:
2572 throw 'unreachable';
2573 }
2574 }
2575 // Set up the resize variables.
2576 var resized = false;
2577 var style = this.widget.node.style;
2578 // Update the top edge of the widget if needed.
2579 if (this._top !== top) {
2580 this._top = top;
2581 style.top = top + "px";
2582 }
2583 // Update the left edge of the widget if needed.
2584 if (this._left !== left) {
2585 this._left = left;
2586 style.left = left + "px";
2587 }
2588 // Update the width of the widget if needed.
2589 if (this._width !== clampW) {
2590 resized = true;
2591 this._width = clampW;
2592 style.width = clampW + "px";
2593 }
2594 // Update the height of the widget if needed.
2595 if (this._height !== clampH) {
2596 resized = true;
2597 this._height = clampH;
2598 style.height = clampH + "px";
2599 }
2600 // Send a resize message to the widget if needed.
2601 if (resized) {
2602 var msg = new exports.Widget.ResizeMessage(clampW, clampH);
2603 messaging.MessageLoop.sendMessage(this.widget, msg);
2604 }
2605 };
2606 return LayoutItem;
2607 }());
2608 /**
2609 * The namespace for the module implementation details.
2610 */
2611 var Private$i;
2612 (function (Private) {
2613 /**
2614 * The attached property for a widget horizontal alignment.
2615 */
2616 Private.horizontalAlignmentProperty = new properties.AttachedProperty({
2617 name: 'horizontalAlignment',
2618 create: function () { return 'center'; },
2619 changed: onAlignmentChanged
2620 });
2621 /**
2622 * The attached property for a widget vertical alignment.
2623 */
2624 Private.verticalAlignmentProperty = new properties.AttachedProperty({
2625 name: 'verticalAlignment',
2626 create: function () { return 'top'; },
2627 changed: onAlignmentChanged
2628 });
2629 /**
2630 * The change handler for the attached alignment properties.
2631 */
2632 function onAlignmentChanged(child) {
2633 if (child.parent && child.parent.layout) {
2634 child.parent.update();
2635 }
2636 }
2637 })(Private$i || (Private$i = {}));
2638
2639 /**
2640 * A concrete layout implementation suitable for many use cases.
2641 *
2642 * #### Notes
2643 * This class is suitable as a base class for implementing a variety of
2644 * layouts, but can also be used directly with standard CSS to layout a
2645 * collection of widgets.
2646 */
2647 var PanelLayout = /** @class */ (function (_super) {
2648 __extends(PanelLayout, _super);
2649 function PanelLayout() {
2650 var _this = _super !== null && _super.apply(this, arguments) || this;
2651 _this._widgets = [];
2652 return _this;
2653 }
2654 /**
2655 * Dispose of the resources held by the layout.
2656 *
2657 * #### Notes
2658 * This will clear and dispose all widgets in the layout.
2659 *
2660 * All reimplementations should call the superclass method.
2661 *
2662 * This method is called automatically when the parent is disposed.
2663 */
2664 PanelLayout.prototype.dispose = function () {
2665 while (this._widgets.length > 0) {
2666 this._widgets.pop().dispose();
2667 }
2668 _super.prototype.dispose.call(this);
2669 };
2670 Object.defineProperty(PanelLayout.prototype, "widgets", {
2671 /**
2672 * A read-only array of the widgets in the layout.
2673 */
2674 get: function () {
2675 return this._widgets;
2676 },
2677 enumerable: true,
2678 configurable: true
2679 });
2680 /**
2681 * Create an iterator over the widgets in the layout.
2682 *
2683 * @returns A new iterator over the widgets in the layout.
2684 */
2685 PanelLayout.prototype.iter = function () {
2686 return algorithm.iter(this._widgets);
2687 };
2688 /**
2689 * Add a widget to the end of the layout.
2690 *
2691 * @param widget - The widget to add to the layout.
2692 *
2693 * #### Notes
2694 * If the widget is already contained in the layout, it will be moved.
2695 */
2696 PanelLayout.prototype.addWidget = function (widget) {
2697 this.insertWidget(this._widgets.length, widget);
2698 };
2699 /**
2700 * Insert a widget into the layout at the specified index.
2701 *
2702 * @param index - The index at which to insert the widget.
2703 *
2704 * @param widget - The widget to insert into the layout.
2705 *
2706 * #### Notes
2707 * The index will be clamped to the bounds of the widgets.
2708 *
2709 * If the widget is already added to the layout, it will be moved.
2710 *
2711 * #### Undefined Behavior
2712 * An `index` which is non-integral.
2713 */
2714 PanelLayout.prototype.insertWidget = function (index, widget) {
2715 // Remove the widget from its current parent. This is a no-op
2716 // if the widget's parent is already the layout parent widget.
2717 widget.parent = this.parent;
2718 // Look up the current index of the widget.
2719 var i = this._widgets.indexOf(widget);
2720 // Clamp the insert index to the array bounds.
2721 var j = Math.max(0, Math.min(index, this._widgets.length));
2722 // If the widget is not in the array, insert it.
2723 if (i === -1) {
2724 // Insert the widget into the array.
2725 algorithm.ArrayExt.insert(this._widgets, j, widget);
2726 // If the layout is parented, attach the widget to the DOM.
2727 if (this.parent) {
2728 this.attachWidget(j, widget);
2729 }
2730 // There is nothing more to do.
2731 return;
2732 }
2733 // Otherwise, the widget exists in the array and should be moved.
2734 // Adjust the index if the location is at the end of the array.
2735 if (j === this._widgets.length) {
2736 j--;
2737 }
2738 // Bail if there is no effective move.
2739 if (i === j) {
2740 return;
2741 }
2742 // Move the widget to the new location.
2743 algorithm.ArrayExt.move(this._widgets, i, j);
2744 // If the layout is parented, move the widget in the DOM.
2745 if (this.parent) {
2746 this.moveWidget(i, j, widget);
2747 }
2748 };
2749 /**
2750 * Remove a widget from the layout.
2751 *
2752 * @param widget - The widget to remove from the layout.
2753 *
2754 * #### Notes
2755 * A widget is automatically removed from the layout when its `parent`
2756 * is set to `null`. This method should only be invoked directly when
2757 * removing a widget from a layout which has yet to be installed on a
2758 * parent widget.
2759 *
2760 * This method does *not* modify the widget's `parent`.
2761 */
2762 PanelLayout.prototype.removeWidget = function (widget) {
2763 this.removeWidgetAt(this._widgets.indexOf(widget));
2764 };
2765 /**
2766 * Remove the widget at a given index from the layout.
2767 *
2768 * @param index - The index of the widget to remove.
2769 *
2770 * #### Notes
2771 * A widget is automatically removed from the layout when its `parent`
2772 * is set to `null`. This method should only be invoked directly when
2773 * removing a widget from a layout which has yet to be installed on a
2774 * parent widget.
2775 *
2776 * This method does *not* modify the widget's `parent`.
2777 *
2778 * #### Undefined Behavior
2779 * An `index` which is non-integral.
2780 */
2781 PanelLayout.prototype.removeWidgetAt = function (index) {
2782 // Remove the widget from the array.
2783 var widget = algorithm.ArrayExt.removeAt(this._widgets, index);
2784 // If the layout is parented, detach the widget from the DOM.
2785 if (widget && this.parent) {
2786 this.detachWidget(index, widget);
2787 }
2788 };
2789 /**
2790 * Perform layout initialization which requires the parent widget.
2791 */
2792 PanelLayout.prototype.init = function () {
2793 var _this = this;
2794 _super.prototype.init.call(this);
2795 algorithm.each(this, function (widget, index) {
2796 _this.attachWidget(index, widget);
2797 });
2798 };
2799 /**
2800 * Attach a widget to the parent's DOM node.
2801 *
2802 * @param index - The current index of the widget in the layout.
2803 *
2804 * @param widget - The widget to attach to the parent.
2805 *
2806 * #### Notes
2807 * This method is called automatically by the panel layout at the
2808 * appropriate time. It should not be called directly by user code.
2809 *
2810 * The default implementation adds the widgets's node to the parent's
2811 * node at the proper location, and sends the appropriate attach
2812 * messages to the widget if the parent is attached to the DOM.
2813 *
2814 * Subclasses may reimplement this method to control how the widget's
2815 * node is added to the parent's node.
2816 */
2817 PanelLayout.prototype.attachWidget = function (index, widget) {
2818 // Look up the next sibling reference node.
2819 var ref = this.parent.node.children[index];
2820 // Send a `'before-attach'` message if the parent is attached.
2821 if (this.parent.isAttached) {
2822 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.BeforeAttach);
2823 }
2824 // Insert the widget's node before the sibling.
2825 this.parent.node.insertBefore(widget.node, ref);
2826 // Send an `'after-attach'` message if the parent is attached.
2827 if (this.parent.isAttached) {
2828 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.AfterAttach);
2829 }
2830 };
2831 /**
2832 * Move a widget in the parent's DOM node.
2833 *
2834 * @param fromIndex - The previous index of the widget in the layout.
2835 *
2836 * @param toIndex - The current index of the widget in the layout.
2837 *
2838 * @param widget - The widget to move in the parent.
2839 *
2840 * #### Notes
2841 * This method is called automatically by the panel layout at the
2842 * appropriate time. It should not be called directly by user code.
2843 *
2844 * The default implementation moves the widget's node to the proper
2845 * location in the parent's node and sends the appropriate attach and
2846 * detach messages to the widget if the parent is attached to the DOM.
2847 *
2848 * Subclasses may reimplement this method to control how the widget's
2849 * node is moved in the parent's node.
2850 */
2851 PanelLayout.prototype.moveWidget = function (fromIndex, toIndex, widget) {
2852 // Send a `'before-detach'` message if the parent is attached.
2853 if (this.parent.isAttached) {
2854 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.BeforeDetach);
2855 }
2856 // Remove the widget's node from the parent.
2857 this.parent.node.removeChild(widget.node);
2858 // Send an `'after-detach'` and message if the parent is attached.
2859 if (this.parent.isAttached) {
2860 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.AfterDetach);
2861 }
2862 // Look up the next sibling reference node.
2863 var ref = this.parent.node.children[toIndex];
2864 // Send a `'before-attach'` message if the parent is attached.
2865 if (this.parent.isAttached) {
2866 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.BeforeAttach);
2867 }
2868 // Insert the widget's node before the sibling.
2869 this.parent.node.insertBefore(widget.node, ref);
2870 // Send an `'after-attach'` message if the parent is attached.
2871 if (this.parent.isAttached) {
2872 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.AfterAttach);
2873 }
2874 };
2875 /**
2876 * Detach a widget from the parent's DOM node.
2877 *
2878 * @param index - The previous index of the widget in the layout.
2879 *
2880 * @param widget - The widget to detach from the parent.
2881 *
2882 * #### Notes
2883 * This method is called automatically by the panel layout at the
2884 * appropriate time. It should not be called directly by user code.
2885 *
2886 * The default implementation removes the widget's node from the
2887 * parent's node, and sends the appropriate detach messages to the
2888 * widget if the parent is attached to the DOM.
2889 *
2890 * Subclasses may reimplement this method to control how the widget's
2891 * node is removed from the parent's node.
2892 */
2893 PanelLayout.prototype.detachWidget = function (index, widget) {
2894 // Send a `'before-detach'` message if the parent is attached.
2895 if (this.parent.isAttached) {
2896 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.BeforeDetach);
2897 }
2898 // Remove the widget's node from the parent.
2899 this.parent.node.removeChild(widget.node);
2900 // Send an `'after-detach'` message if the parent is attached.
2901 if (this.parent.isAttached) {
2902 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.AfterDetach);
2903 }
2904 };
2905 return PanelLayout;
2906 }(exports.Layout));
2907
2908 var Utils;
2909 (function (Utils) {
2910 /**
2911 * Clamp a dimension value to an integer >= 0.
2912 */
2913 function clampDimension(value) {
2914 return Math.max(0, Math.floor(value));
2915 }
2916 Utils.clampDimension = clampDimension;
2917 })(Utils || (Utils = {}));
2918 var Utils$1 = Utils;
2919
2920 /**
2921 * A layout which arranges its widgets into resizable sections.
2922 */
2923 exports.SplitLayout = /** @class */ (function (_super) {
2924 __extends(SplitLayout, _super);
2925 /**
2926 * Construct a new split layout.
2927 *
2928 * @param options - The options for initializing the layout.
2929 */
2930 function SplitLayout(options) {
2931 var _this = _super.call(this) || this;
2932 _this.widgetOffset = 0;
2933 _this._fixed = 0;
2934 _this._spacing = 4;
2935 _this._dirty = false;
2936 _this._hasNormedSizes = false;
2937 _this._sizers = [];
2938 _this._items = [];
2939 _this._handles = [];
2940 _this._box = null;
2941 _this._alignment = 'start';
2942 _this._orientation = 'horizontal';
2943 _this.renderer = options.renderer;
2944 if (options.orientation !== undefined) {
2945 _this._orientation = options.orientation;
2946 }
2947 if (options.alignment !== undefined) {
2948 _this._alignment = options.alignment;
2949 }
2950 if (options.spacing !== undefined) {
2951 _this._spacing = Utils.clampDimension(options.spacing);
2952 }
2953 return _this;
2954 }
2955 /**
2956 * Dispose of the resources held by the layout.
2957 */
2958 SplitLayout.prototype.dispose = function () {
2959 // Dispose of the layout items.
2960 algorithm.each(this._items, function (item) {
2961 item.dispose();
2962 });
2963 // Clear the layout state.
2964 this._box = null;
2965 this._items.length = 0;
2966 this._sizers.length = 0;
2967 this._handles.length = 0;
2968 // Dispose of the rest of the layout.
2969 _super.prototype.dispose.call(this);
2970 };
2971 Object.defineProperty(SplitLayout.prototype, "orientation", {
2972 /**
2973 * Get the layout orientation for the split layout.
2974 */
2975 get: function () {
2976 return this._orientation;
2977 },
2978 /**
2979 * Set the layout orientation for the split layout.
2980 */
2981 set: function (value) {
2982 if (this._orientation === value) {
2983 return;
2984 }
2985 this._orientation = value;
2986 if (!this.parent) {
2987 return;
2988 }
2989 this.parent.dataset['orientation'] = value;
2990 this.parent.fit();
2991 },
2992 enumerable: true,
2993 configurable: true
2994 });
2995 Object.defineProperty(SplitLayout.prototype, "alignment", {
2996 /**
2997 * Get the content alignment for the split layout.
2998 *
2999 * #### Notes
3000 * This is the alignment of the widgets in the layout direction.
3001 *
3002 * The alignment has no effect if the widgets can expand to fill the
3003 * entire split layout.
3004 */
3005 get: function () {
3006 return this._alignment;
3007 },
3008 /**
3009 * Set the content alignment for the split layout.
3010 *
3011 * #### Notes
3012 * This is the alignment of the widgets in the layout direction.
3013 *
3014 * The alignment has no effect if the widgets can expand to fill the
3015 * entire split layout.
3016 */
3017 set: function (value) {
3018 if (this._alignment === value) {
3019 return;
3020 }
3021 this._alignment = value;
3022 if (!this.parent) {
3023 return;
3024 }
3025 this.parent.dataset['alignment'] = value;
3026 this.parent.update();
3027 },
3028 enumerable: true,
3029 configurable: true
3030 });
3031 Object.defineProperty(SplitLayout.prototype, "spacing", {
3032 /**
3033 * Get the inter-element spacing for the split layout.
3034 */
3035 get: function () {
3036 return this._spacing;
3037 },
3038 /**
3039 * Set the inter-element spacing for the split layout.
3040 */
3041 set: function (value) {
3042 value = Utils.clampDimension(value);
3043 if (this._spacing === value) {
3044 return;
3045 }
3046 this._spacing = value;
3047 if (!this.parent) {
3048 return;
3049 }
3050 this.parent.fit();
3051 },
3052 enumerable: true,
3053 configurable: true
3054 });
3055 Object.defineProperty(SplitLayout.prototype, "handles", {
3056 /**
3057 * A read-only array of the split handles in the layout.
3058 */
3059 get: function () {
3060 return this._handles;
3061 },
3062 enumerable: true,
3063 configurable: true
3064 });
3065 /**
3066 * Get the relative sizes of the widgets in the layout.
3067 *
3068 * @returns A new array of the relative sizes of the widgets.
3069 *
3070 * #### Notes
3071 * The returned sizes reflect the sizes of the widgets normalized
3072 * relative to their siblings.
3073 *
3074 * This method **does not** measure the DOM nodes.
3075 */
3076 SplitLayout.prototype.relativeSizes = function () {
3077 return Private$h.normalize(this._sizers.map(function (sizer) { return sizer.size; }));
3078 };
3079 /**
3080 * Set the relative sizes for the widgets in the layout.
3081 *
3082 * @param sizes - The relative sizes for the widgets in the panel.
3083 *
3084 * #### Notes
3085 * Extra values are ignored, too few will yield an undefined layout.
3086 *
3087 * The actual geometry of the DOM nodes is updated asynchronously.
3088 */
3089 SplitLayout.prototype.setRelativeSizes = function (sizes) {
3090 // Copy the sizes and pad with zeros as needed.
3091 var n = this._sizers.length;
3092 var temp = sizes.slice(0, n);
3093 while (temp.length < n) {
3094 temp.push(0);
3095 }
3096 // Normalize the padded sizes.
3097 var normed = Private$h.normalize(temp);
3098 // Apply the normalized sizes to the sizers.
3099 for (var i = 0; i < n; ++i) {
3100 var sizer = this._sizers[i];
3101 sizer.sizeHint = normed[i];
3102 sizer.size = normed[i];
3103 }
3104 // Set the flag indicating the sizes are normalized.
3105 this._hasNormedSizes = true;
3106 // Trigger an update of the parent widget.
3107 if (this.parent) {
3108 this.parent.update();
3109 }
3110 };
3111 /**
3112 * Move the offset position of a split handle.
3113 *
3114 * @param index - The index of the handle of the interest.
3115 *
3116 * @param position - The desired offset position of the handle.
3117 *
3118 * #### Notes
3119 * The position is relative to the offset parent.
3120 *
3121 * This will move the handle as close as possible to the desired
3122 * position. The sibling widgets will be adjusted as necessary.
3123 */
3124 SplitLayout.prototype.moveHandle = function (index, position) {
3125 // Bail if the index is invalid or the handle is hidden.
3126 var handle = this._handles[index];
3127 if (!handle || handle.classList.contains('lm-mod-hidden')) {
3128 return;
3129 }
3130 // Compute the desired delta movement for the handle.
3131 var delta;
3132 if (this._orientation === 'horizontal') {
3133 delta = position - handle.offsetLeft;
3134 }
3135 else {
3136 delta = position - handle.offsetTop;
3137 }
3138 // Bail if there is no handle movement.
3139 if (delta === 0) {
3140 return;
3141 }
3142 // Prevent widget resizing unless needed.
3143 for (var _i = 0, _a = this._sizers; _i < _a.length; _i++) {
3144 var sizer = _a[_i];
3145 if (sizer.size > 0) {
3146 sizer.sizeHint = sizer.size;
3147 }
3148 }
3149 // Adjust the sizers to reflect the handle movement.
3150 exports.BoxEngine.adjust(this._sizers, index, delta);
3151 // Update the layout of the widgets.
3152 if (this.parent) {
3153 this.parent.update();
3154 }
3155 };
3156 /**
3157 * Perform layout initialization which requires the parent widget.
3158 */
3159 SplitLayout.prototype.init = function () {
3160 this.parent.dataset['orientation'] = this.orientation;
3161 this.parent.dataset['alignment'] = this.alignment;
3162 _super.prototype.init.call(this);
3163 };
3164 /**
3165 * Attach a widget to the parent's DOM node.
3166 *
3167 * @param index - The current index of the widget in the layout.
3168 *
3169 * @param widget - The widget to attach to the parent.
3170 *
3171 * #### Notes
3172 * This is a reimplementation of the superclass method.
3173 */
3174 SplitLayout.prototype.attachWidget = function (index, widget) {
3175 // Create the item, handle, and sizer for the new widget.
3176 var item = new LayoutItem(widget);
3177 var handle = Private$h.createHandle(this.renderer);
3178 var average = Private$h.averageSize(this._sizers);
3179 var sizer = Private$h.createSizer(average);
3180 // Insert the item, handle, and sizer into the internal arrays.
3181 algorithm.ArrayExt.insert(this._items, index, item);
3182 algorithm.ArrayExt.insert(this._sizers, index, sizer);
3183 algorithm.ArrayExt.insert(this._handles, index, handle);
3184 // Send a `'before-attach'` message if the parent is attached.
3185 if (this.parent.isAttached) {
3186 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.BeforeAttach);
3187 }
3188 // Add the widget and handle nodes to the parent.
3189 this.parent.node.appendChild(widget.node);
3190 this.parent.node.appendChild(handle);
3191 // Send an `'after-attach'` message if the parent is attached.
3192 if (this.parent.isAttached) {
3193 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.AfterAttach);
3194 }
3195 // Post a fit request for the parent widget.
3196 this.parent.fit();
3197 };
3198 /**
3199 * Move a widget in the parent's DOM node.
3200 *
3201 * @param fromIndex - The previous index of the widget in the layout.
3202 *
3203 * @param toIndex - The current index of the widget in the layout.
3204 *
3205 * @param widget - The widget to move in the parent.
3206 *
3207 * #### Notes
3208 * This is a reimplementation of the superclass method.
3209 */
3210 SplitLayout.prototype.moveWidget = function (fromIndex, toIndex, widget) {
3211 // Move the item, sizer, and handle for the widget.
3212 algorithm.ArrayExt.move(this._items, fromIndex, toIndex);
3213 algorithm.ArrayExt.move(this._sizers, fromIndex, toIndex);
3214 algorithm.ArrayExt.move(this._handles, fromIndex, toIndex);
3215 // Post a fit request to the parent to show/hide last handle.
3216 this.parent.fit();
3217 };
3218 /**
3219 * Detach a widget from the parent's DOM node.
3220 *
3221 * @param index - The previous index of the widget in the layout.
3222 *
3223 * @param widget - The widget to detach from the parent.
3224 *
3225 * #### Notes
3226 * This is a reimplementation of the superclass method.
3227 */
3228 SplitLayout.prototype.detachWidget = function (index, widget) {
3229 // Remove the item, handle, and sizer for the widget.
3230 var item = algorithm.ArrayExt.removeAt(this._items, index);
3231 var handle = algorithm.ArrayExt.removeAt(this._handles, index);
3232 algorithm.ArrayExt.removeAt(this._sizers, index);
3233 // Send a `'before-detach'` message if the parent is attached.
3234 if (this.parent.isAttached) {
3235 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.BeforeDetach);
3236 }
3237 // Remove the widget and handle nodes from the parent.
3238 this.parent.node.removeChild(widget.node);
3239 this.parent.node.removeChild(handle);
3240 // Send an `'after-detach'` message if the parent is attached.
3241 if (this.parent.isAttached) {
3242 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.AfterDetach);
3243 }
3244 // Dispose of the layout item.
3245 item.dispose();
3246 // Post a fit request for the parent widget.
3247 this.parent.fit();
3248 };
3249 /**
3250 * A message handler invoked on a `'before-show'` message.
3251 */
3252 SplitLayout.prototype.onBeforeShow = function (msg) {
3253 _super.prototype.onBeforeShow.call(this, msg);
3254 this.parent.update();
3255 };
3256 /**
3257 * A message handler invoked on a `'before-attach'` message.
3258 */
3259 SplitLayout.prototype.onBeforeAttach = function (msg) {
3260 _super.prototype.onBeforeAttach.call(this, msg);
3261 this.parent.fit();
3262 };
3263 /**
3264 * A message handler invoked on a `'child-shown'` message.
3265 */
3266 SplitLayout.prototype.onChildShown = function (msg) {
3267 this.parent.fit();
3268 };
3269 /**
3270 * A message handler invoked on a `'child-hidden'` message.
3271 */
3272 SplitLayout.prototype.onChildHidden = function (msg) {
3273 this.parent.fit();
3274 };
3275 /**
3276 * A message handler invoked on a `'resize'` message.
3277 */
3278 SplitLayout.prototype.onResize = function (msg) {
3279 if (this.parent.isVisible) {
3280 this._update(msg.width, msg.height);
3281 }
3282 };
3283 /**
3284 * A message handler invoked on an `'update-request'` message.
3285 */
3286 SplitLayout.prototype.onUpdateRequest = function (msg) {
3287 if (this.parent.isVisible) {
3288 this._update(-1, -1);
3289 }
3290 };
3291 /**
3292 * A message handler invoked on a `'fit-request'` message.
3293 */
3294 SplitLayout.prototype.onFitRequest = function (msg) {
3295 if (this.parent.isAttached) {
3296 this._fit();
3297 }
3298 };
3299 /**
3300 * Update the item position.
3301 *
3302 * @param i Item index
3303 * @param isHorizontal Whether the layout is horizontal or not
3304 * @param left Left position in pixels
3305 * @param top Top position in pixels
3306 * @param height Item height
3307 * @param width Item width
3308 * @param size Item size
3309 */
3310 SplitLayout.prototype.updateItemPosition = function (i, isHorizontal, left, top, height, width, size) {
3311 var item = this._items[i];
3312 if (item.isHidden) {
3313 return;
3314 }
3315 // Fetch the style for the handle.
3316 var handleStyle = this._handles[i].style;
3317 // Update the widget and handle, and advance the relevant edge.
3318 if (isHorizontal) {
3319 left += this.widgetOffset;
3320 item.update(left, top, size, height);
3321 left += size;
3322 handleStyle.top = top + "px";
3323 handleStyle.left = left + "px";
3324 handleStyle.width = this._spacing + "px";
3325 handleStyle.height = height + "px";
3326 }
3327 else {
3328 top += this.widgetOffset;
3329 item.update(left, top, width, size);
3330 top += size;
3331 handleStyle.top = top + "px";
3332 handleStyle.left = left + "px";
3333 handleStyle.width = width + "px";
3334 handleStyle.height = this._spacing + "px";
3335 }
3336 };
3337 /**
3338 * Fit the layout to the total size required by the widgets.
3339 */
3340 SplitLayout.prototype._fit = function () {
3341 // Update the handles and track the visible widget count.
3342 var nVisible = 0;
3343 var lastHandleIndex = -1;
3344 for (var i = 0, n = this._items.length; i < n; ++i) {
3345 if (this._items[i].isHidden) {
3346 this._handles[i].classList.add('lm-mod-hidden');
3347 /* <DEPRECATED> */
3348 this._handles[i].classList.add('p-mod-hidden');
3349 /* </DEPRECATED> */
3350 }
3351 else {
3352 this._handles[i].classList.remove('lm-mod-hidden');
3353 /* <DEPRECATED> */
3354 this._handles[i].classList.remove('p-mod-hidden');
3355 /* </DEPRECATED> */
3356 lastHandleIndex = i;
3357 nVisible++;
3358 }
3359 }
3360 // Hide the handle for the last visible widget.
3361 if (lastHandleIndex !== -1) {
3362 this._handles[lastHandleIndex].classList.add('lm-mod-hidden');
3363 /* <DEPRECATED> */
3364 this._handles[lastHandleIndex].classList.add('p-mod-hidden');
3365 /* </DEPRECATED> */
3366 }
3367 // Update the fixed space for the visible items.
3368 this._fixed =
3369 this._spacing * Math.max(0, nVisible - 1) +
3370 this.widgetOffset * this._items.length;
3371 // Setup the computed minimum size.
3372 var horz = this._orientation === 'horizontal';
3373 var minW = horz ? this._fixed : 0;
3374 var minH = horz ? 0 : this._fixed;
3375 // Update the sizers and computed size limits.
3376 for (var i = 0, n = this._items.length; i < n; ++i) {
3377 // Fetch the item and corresponding box sizer.
3378 var item = this._items[i];
3379 var sizer = this._sizers[i];
3380 // Prevent resizing unless necessary.
3381 if (sizer.size > 0) {
3382 sizer.sizeHint = sizer.size;
3383 }
3384 // If the item is hidden, it should consume zero size.
3385 if (item.isHidden) {
3386 sizer.minSize = 0;
3387 sizer.maxSize = 0;
3388 continue;
3389 }
3390 // Update the size limits for the item.
3391 item.fit();
3392 // Update the stretch factor.
3393 sizer.stretch = SplitLayout.getStretch(item.widget);
3394 // Update the sizer limits and computed min size.
3395 if (horz) {
3396 sizer.minSize = item.minWidth;
3397 sizer.maxSize = item.maxWidth;
3398 minW += item.minWidth;
3399 minH = Math.max(minH, item.minHeight);
3400 }
3401 else {
3402 sizer.minSize = item.minHeight;
3403 sizer.maxSize = item.maxHeight;
3404 minH += item.minHeight;
3405 minW = Math.max(minW, item.minWidth);
3406 }
3407 }
3408 // Update the box sizing and add it to the computed min size.
3409 var box = (this._box = domutils.ElementExt.boxSizing(this.parent.node));
3410 minW += box.horizontalSum;
3411 minH += box.verticalSum;
3412 // Update the parent's min size constraints.
3413 var style = this.parent.node.style;
3414 style.minWidth = minW + "px";
3415 style.minHeight = minH + "px";
3416 // Set the dirty flag to ensure only a single update occurs.
3417 this._dirty = true;
3418 // Notify the ancestor that it should fit immediately. This may
3419 // cause a resize of the parent, fulfilling the required update.
3420 if (this.parent.parent) {
3421 messaging.MessageLoop.sendMessage(this.parent.parent, exports.Widget.Msg.FitRequest);
3422 }
3423 // If the dirty flag is still set, the parent was not resized.
3424 // Trigger the required update on the parent widget immediately.
3425 if (this._dirty) {
3426 messaging.MessageLoop.sendMessage(this.parent, exports.Widget.Msg.UpdateRequest);
3427 }
3428 };
3429 /**
3430 * Update the layout position and size of the widgets.
3431 *
3432 * The parent offset dimensions should be `-1` if unknown.
3433 */
3434 SplitLayout.prototype._update = function (offsetWidth, offsetHeight) {
3435 // Clear the dirty flag to indicate the update occurred.
3436 this._dirty = false;
3437 // Compute the visible item count.
3438 var nVisible = 0;
3439 for (var i = 0, n = this._items.length; i < n; ++i) {
3440 nVisible += +!this._items[i].isHidden;
3441 }
3442 // Bail early if there are no visible items to layout.
3443 if (nVisible === 0 && this.widgetOffset === 0) {
3444 return;
3445 }
3446 // Measure the parent if the offset dimensions are unknown.
3447 if (offsetWidth < 0) {
3448 offsetWidth = this.parent.node.offsetWidth;
3449 }
3450 if (offsetHeight < 0) {
3451 offsetHeight = this.parent.node.offsetHeight;
3452 }
3453 // Ensure the parent box sizing data is computed.
3454 if (!this._box) {
3455 this._box = domutils.ElementExt.boxSizing(this.parent.node);
3456 }
3457 // Compute the actual layout bounds adjusted for border and padding.
3458 var top = this._box.paddingTop;
3459 var left = this._box.paddingLeft;
3460 var width = offsetWidth - this._box.horizontalSum;
3461 var height = offsetHeight - this._box.verticalSum;
3462 // Set up the variables for justification and alignment offset.
3463 var extra = 0;
3464 var offset = 0;
3465 var horz = this._orientation === 'horizontal';
3466 if (nVisible > 0) {
3467 // Compute the adjusted layout space.
3468 var space = void 0;
3469 if (horz) {
3470 // left += this.widgetOffset;
3471 space = Math.max(0, width - this._fixed);
3472 }
3473 else {
3474 // top += this.widgetOffset;
3475 space = Math.max(0, height - this._fixed);
3476 }
3477 // Scale the size hints if they are normalized.
3478 if (this._hasNormedSizes) {
3479 for (var _i = 0, _a = this._sizers; _i < _a.length; _i++) {
3480 var sizer = _a[_i];
3481 sizer.sizeHint *= space;
3482 }
3483 this._hasNormedSizes = false;
3484 }
3485 // Distribute the layout space to the box sizers.
3486 var delta = exports.BoxEngine.calc(this._sizers, space);
3487 // Account for alignment if there is extra layout space.
3488 if (delta > 0) {
3489 switch (this._alignment) {
3490 case 'start':
3491 break;
3492 case 'center':
3493 extra = 0;
3494 offset = delta / 2;
3495 break;
3496 case 'end':
3497 extra = 0;
3498 offset = delta;
3499 break;
3500 case 'justify':
3501 extra = delta / nVisible;
3502 offset = 0;
3503 break;
3504 default:
3505 throw 'unreachable';
3506 }
3507 }
3508 }
3509 // Layout the items using the computed box sizes.
3510 for (var i = 0, n = this._items.length; i < n; ++i) {
3511 // Fetch the item.
3512 var item = this._items[i];
3513 // Fetch the computed size for the widget.
3514 var size = item.isHidden ? 0 : this._sizers[i].size + extra;
3515 this.updateItemPosition(i, horz, horz ? left + offset : left, horz ? top : top + offset, height, width, size);
3516 var fullOffset = this.widgetOffset +
3517 (this._handles[i].classList.contains('lm-mod-hidden')
3518 ? 0
3519 : this._spacing);
3520 if (horz) {
3521 left += size + fullOffset;
3522 }
3523 else {
3524 top += size + fullOffset;
3525 }
3526 }
3527 };
3528 return SplitLayout;
3529 }(PanelLayout));
3530 /**
3531 * The namespace for the `SplitLayout` class statics.
3532 */
3533 (function (SplitLayout) {
3534 /**
3535 * Get the split layout stretch factor for the given widget.
3536 *
3537 * @param widget - The widget of interest.
3538 *
3539 * @returns The split layout stretch factor for the widget.
3540 */
3541 function getStretch(widget) {
3542 return Private$h.stretchProperty.get(widget);
3543 }
3544 SplitLayout.getStretch = getStretch;
3545 /**
3546 * Set the split layout stretch factor for the given widget.
3547 *
3548 * @param widget - The widget of interest.
3549 *
3550 * @param value - The value for the stretch factor.
3551 */
3552 function setStretch(widget, value) {
3553 Private$h.stretchProperty.set(widget, value);
3554 }
3555 SplitLayout.setStretch = setStretch;
3556 })(exports.SplitLayout || (exports.SplitLayout = {}));
3557 /**
3558 * The namespace for the module implementation details.
3559 */
3560 var Private$h;
3561 (function (Private) {
3562 /**
3563 * The property descriptor for a widget stretch factor.
3564 */
3565 Private.stretchProperty = new properties.AttachedProperty({
3566 name: 'stretch',
3567 create: function () { return 0; },
3568 coerce: function (owner, value) { return Math.max(0, Math.floor(value)); },
3569 changed: onChildSizingChanged
3570 });
3571 /**
3572 * Create a new box sizer with the given size hint.
3573 */
3574 function createSizer(size) {
3575 var sizer = new BoxSizer();
3576 sizer.sizeHint = Math.floor(size);
3577 return sizer;
3578 }
3579 Private.createSizer = createSizer;
3580 /**
3581 * Create a new split handle node using the given renderer.
3582 */
3583 function createHandle(renderer) {
3584 var handle = renderer.createHandle();
3585 handle.style.position = 'absolute';
3586 return handle;
3587 }
3588 Private.createHandle = createHandle;
3589 /**
3590 * Compute the average size of an array of box sizers.
3591 */
3592 function averageSize(sizers) {
3593 return sizers.reduce(function (v, s) { return v + s.size; }, 0) / sizers.length || 0;
3594 }
3595 Private.averageSize = averageSize;
3596 /**
3597 * Normalize an array of values.
3598 */
3599 function normalize(values) {
3600 var n = values.length;
3601 if (n === 0) {
3602 return [];
3603 }
3604 var sum = values.reduce(function (a, b) { return a + Math.abs(b); }, 0);
3605 return sum === 0 ? values.map(function (v) { return 1 / n; }) : values.map(function (v) { return v / sum; });
3606 }
3607 Private.normalize = normalize;
3608 /**
3609 * The change handler for the attached sizing properties.
3610 */
3611 function onChildSizingChanged(child) {
3612 if (child.parent && child.parent.layout instanceof exports.SplitLayout) {
3613 child.parent.fit();
3614 }
3615 }
3616 })(Private$h || (Private$h = {}));
3617
3618 /**
3619 * A layout which arranges its widgets into collapsible resizable sections.
3620 */
3621 var AccordionLayout = /** @class */ (function (_super) {
3622 __extends(AccordionLayout, _super);
3623 /**
3624 * Construct a new accordion layout.
3625 *
3626 * @param options - The options for initializing the layout.
3627 *
3628 * #### Notes
3629 * The default orientation will be vertical.
3630 *
3631 * Titles must be rotated for horizontal accordion panel using CSS: see accordionpanel.css
3632 */
3633 function AccordionLayout(options) {
3634 var _this = _super.call(this, __assign(__assign({}, options), { orientation: options.orientation || 'vertical' })) || this;
3635 _this._titles = [];
3636 _this.titleSpace = options.titleSpace || 22;
3637 return _this;
3638 }
3639 Object.defineProperty(AccordionLayout.prototype, "titleSpace", {
3640 /**
3641 * The section title height or width depending on the orientation.
3642 */
3643 get: function () {
3644 return this.widgetOffset;
3645 },
3646 set: function (value) {
3647 value = Utils$1.clampDimension(value);
3648 if (this.widgetOffset === value) {
3649 return;
3650 }
3651 this.widgetOffset = value;
3652 if (!this.parent) {
3653 return;
3654 }
3655 this.parent.fit();
3656 },
3657 enumerable: true,
3658 configurable: true
3659 });
3660 Object.defineProperty(AccordionLayout.prototype, "titles", {
3661 /**
3662 * A read-only array of the section titles in the panel.
3663 */
3664 get: function () {
3665 return this._titles;
3666 },
3667 enumerable: true,
3668 configurable: true
3669 });
3670 /**
3671 * Dispose of the resources held by the layout.
3672 */
3673 AccordionLayout.prototype.dispose = function () {
3674 if (this.isDisposed) {
3675 return;
3676 }
3677 // Clear the layout state.
3678 this._titles.length = 0;
3679 // Dispose of the rest of the layout.
3680 _super.prototype.dispose.call(this);
3681 };
3682 AccordionLayout.prototype.updateTitle = function (index, widget) {
3683 var oldTitle = this._titles[index];
3684 var expanded = oldTitle.classList.contains('lm-mod-expanded');
3685 var newTitle = Private$g.createTitle(this.renderer, widget.title, expanded);
3686 this._titles[index] = newTitle;
3687 // Add the title node to the parent before the widget.
3688 this.parent.node.replaceChild(newTitle, oldTitle);
3689 };
3690 /**
3691 * Attach a widget to the parent's DOM node.
3692 *
3693 * @param index - The current index of the widget in the layout.
3694 *
3695 * @param widget - The widget to attach to the parent.
3696 */
3697 AccordionLayout.prototype.attachWidget = function (index, widget) {
3698 var title = Private$g.createTitle(this.renderer, widget.title);
3699 algorithm.ArrayExt.insert(this._titles, index, title);
3700 // Add the title node to the parent before the widget.
3701 this.parent.node.appendChild(title);
3702 widget.node.setAttribute('role', 'region');
3703 widget.node.setAttribute('aria-labelledby', title.id);
3704 _super.prototype.attachWidget.call(this, index, widget);
3705 };
3706 /**
3707 * Move a widget in the parent's DOM node.
3708 *
3709 * @param fromIndex - The previous index of the widget in the layout.
3710 *
3711 * @param toIndex - The current index of the widget in the layout.
3712 *
3713 * @param widget - The widget to move in the parent.
3714 */
3715 AccordionLayout.prototype.moveWidget = function (fromIndex, toIndex, widget) {
3716 algorithm.ArrayExt.move(this._titles, fromIndex, toIndex);
3717 _super.prototype.moveWidget.call(this, fromIndex, toIndex, widget);
3718 };
3719 /**
3720 * Detach a widget from the parent's DOM node.
3721 *
3722 * @param index - The previous index of the widget in the layout.
3723 *
3724 * @param widget - The widget to detach from the parent.
3725 *
3726 * #### Notes
3727 * This is a reimplementation of the superclass method.
3728 */
3729 AccordionLayout.prototype.detachWidget = function (index, widget) {
3730 var title = algorithm.ArrayExt.removeAt(this._titles, index);
3731 this.parent.node.removeChild(title);
3732 _super.prototype.detachWidget.call(this, index, widget);
3733 };
3734 /**
3735 * Update the item position.
3736 *
3737 * @param i Item index
3738 * @param isHorizontal Whether the layout is horizontal or not
3739 * @param left Left position in pixels
3740 * @param top Top position in pixels
3741 * @param height Item height
3742 * @param width Item width
3743 * @param size Item size
3744 */
3745 AccordionLayout.prototype.updateItemPosition = function (i, isHorizontal, left, top, height, width, size) {
3746 var titleStyle = this._titles[i].style;
3747 // Titles must be rotated for horizontal accordion panel using CSS: see accordionpanel.css
3748 titleStyle.top = top + "px";
3749 titleStyle.left = left + "px";
3750 titleStyle.height = this.widgetOffset + "px";
3751 if (isHorizontal) {
3752 titleStyle.width = height + "px";
3753 }
3754 else {
3755 titleStyle.width = width + "px";
3756 }
3757 _super.prototype.updateItemPosition.call(this, i, isHorizontal, left, top, height, width, size);
3758 };
3759 return AccordionLayout;
3760 }(exports.SplitLayout));
3761 var Private$g;
3762 (function (Private) {
3763 /**
3764 * Create the title HTML element.
3765 *
3766 * @param renderer Accordion renderer
3767 * @param data Widget title
3768 * @returns Title HTML element
3769 */
3770 function createTitle(renderer, data, expanded) {
3771 if (expanded === void 0) { expanded = true; }
3772 var title = renderer.createSectionTitle(data);
3773 title.style.position = 'absolute';
3774 title.setAttribute('aria-label', data.label + " Section");
3775 title.setAttribute('aria-expanded', expanded ? 'true' : 'false');
3776 title.setAttribute('aria-controls', data.owner.id);
3777 if (expanded) {
3778 title.classList.add('lm-mod-expanded');
3779 }
3780 return title;
3781 }
3782 Private.createTitle = createTitle;
3783 })(Private$g || (Private$g = {}));
3784
3785 /**
3786 * A simple and convenient panel widget class.
3787 *
3788 * #### Notes
3789 * This class is suitable as a base class for implementing a variety of
3790 * convenience panel widgets, but can also be used directly with CSS to
3791 * arrange a collection of widgets.
3792 *
3793 * This class provides a convenience wrapper around a [[PanelLayout]].
3794 */
3795 var Panel = /** @class */ (function (_super) {
3796 __extends(Panel, _super);
3797 /**
3798 * Construct a new panel.
3799 *
3800 * @param options - The options for initializing the panel.
3801 */
3802 function Panel(options) {
3803 if (options === void 0) { options = {}; }
3804 var _this = _super.call(this) || this;
3805 _this.addClass('lm-Panel');
3806 /* <DEPRECATED> */
3807 _this.addClass('p-Panel');
3808 /* </DEPRECATED> */
3809 _this.layout = Private$f.createLayout(options);
3810 return _this;
3811 }
3812 Object.defineProperty(Panel.prototype, "widgets", {
3813 /**
3814 * A read-only array of the widgets in the panel.
3815 */
3816 get: function () {
3817 return this.layout.widgets;
3818 },
3819 enumerable: true,
3820 configurable: true
3821 });
3822 /**
3823 * Add a widget to the end of the panel.
3824 *
3825 * @param widget - The widget to add to the panel.
3826 *
3827 * #### Notes
3828 * If the widget is already contained in the panel, it will be moved.
3829 */
3830 Panel.prototype.addWidget = function (widget) {
3831 this.layout.addWidget(widget);
3832 };
3833 /**
3834 * Insert a widget at the specified index.
3835 *
3836 * @param index - The index at which to insert the widget.
3837 *
3838 * @param widget - The widget to insert into to the panel.
3839 *
3840 * #### Notes
3841 * If the widget is already contained in the panel, it will be moved.
3842 */
3843 Panel.prototype.insertWidget = function (index, widget) {
3844 this.layout.insertWidget(index, widget);
3845 };
3846 return Panel;
3847 }(exports.Widget));
3848 /**
3849 * The namespace for the module implementation details.
3850 */
3851 var Private$f;
3852 (function (Private) {
3853 /**
3854 * Create a panel layout for the given panel options.
3855 */
3856 function createLayout(options) {
3857 return options.layout || new PanelLayout();
3858 }
3859 Private.createLayout = createLayout;
3860 })(Private$f || (Private$f = {}));
3861
3862 /**
3863 * A panel which arranges its widgets into resizable sections.
3864 *
3865 * #### Notes
3866 * This class provides a convenience wrapper around a [[SplitLayout]].
3867 */
3868 exports.SplitPanel = /** @class */ (function (_super) {
3869 __extends(SplitPanel, _super);
3870 /**
3871 * Construct a new split panel.
3872 *
3873 * @param options - The options for initializing the split panel.
3874 */
3875 function SplitPanel(options) {
3876 if (options === void 0) { options = {}; }
3877 var _this = _super.call(this, { layout: Private$e.createLayout(options) }) || this;
3878 _this._handleMoved = new signaling.Signal(_this);
3879 _this._pressData = null;
3880 _this.addClass('lm-SplitPanel');
3881 /* <DEPRECATED> */
3882 _this.addClass('p-SplitPanel');
3883 return _this;
3884 /* </DEPRECATED> */
3885 }
3886 /**
3887 * Dispose of the resources held by the panel.
3888 */
3889 SplitPanel.prototype.dispose = function () {
3890 this._releaseMouse();
3891 _super.prototype.dispose.call(this);
3892 };
3893 Object.defineProperty(SplitPanel.prototype, "orientation", {
3894 /**
3895 * Get the layout orientation for the split panel.
3896 */
3897 get: function () {
3898 return this.layout.orientation;
3899 },
3900 /**
3901 * Set the layout orientation for the split panel.
3902 */
3903 set: function (value) {
3904 this.layout.orientation = value;
3905 },
3906 enumerable: true,
3907 configurable: true
3908 });
3909 Object.defineProperty(SplitPanel.prototype, "alignment", {
3910 /**
3911 * Get the content alignment for the split panel.
3912 *
3913 * #### Notes
3914 * This is the alignment of the widgets in the layout direction.
3915 *
3916 * The alignment has no effect if the widgets can expand to fill the
3917 * entire split panel.
3918 */
3919 get: function () {
3920 return this.layout.alignment;
3921 },
3922 /**
3923 * Set the content alignment for the split panel.
3924 *
3925 * #### Notes
3926 * This is the alignment of the widgets in the layout direction.
3927 *
3928 * The alignment has no effect if the widgets can expand to fill the
3929 * entire split panel.
3930 */
3931 set: function (value) {
3932 this.layout.alignment = value;
3933 },
3934 enumerable: true,
3935 configurable: true
3936 });
3937 Object.defineProperty(SplitPanel.prototype, "spacing", {
3938 /**
3939 * Get the inter-element spacing for the split panel.
3940 */
3941 get: function () {
3942 return this.layout.spacing;
3943 },
3944 /**
3945 * Set the inter-element spacing for the split panel.
3946 */
3947 set: function (value) {
3948 this.layout.spacing = value;
3949 },
3950 enumerable: true,
3951 configurable: true
3952 });
3953 Object.defineProperty(SplitPanel.prototype, "renderer", {
3954 /**
3955 * The renderer used by the split panel.
3956 */
3957 get: function () {
3958 return this.layout.renderer;
3959 },
3960 enumerable: true,
3961 configurable: true
3962 });
3963 Object.defineProperty(SplitPanel.prototype, "handleMoved", {
3964 /**
3965 * A signal emitted when a split handle has moved.
3966 */
3967 get: function () {
3968 return this._handleMoved;
3969 },
3970 enumerable: true,
3971 configurable: true
3972 });
3973 Object.defineProperty(SplitPanel.prototype, "handles", {
3974 /**
3975 * A read-only array of the split handles in the panel.
3976 */
3977 get: function () {
3978 return this.layout.handles;
3979 },
3980 enumerable: true,
3981 configurable: true
3982 });
3983 /**
3984 * Get the relative sizes of the widgets in the panel.
3985 *
3986 * @returns A new array of the relative sizes of the widgets.
3987 *
3988 * #### Notes
3989 * The returned sizes reflect the sizes of the widgets normalized
3990 * relative to their siblings.
3991 *
3992 * This method **does not** measure the DOM nodes.
3993 */
3994 SplitPanel.prototype.relativeSizes = function () {
3995 return this.layout.relativeSizes();
3996 };
3997 /**
3998 * Set the relative sizes for the widgets in the panel.
3999 *
4000 * @param sizes - The relative sizes for the widgets in the panel.
4001 *
4002 * #### Notes
4003 * Extra values are ignored, too few will yield an undefined layout.
4004 *
4005 * The actual geometry of the DOM nodes is updated asynchronously.
4006 */
4007 SplitPanel.prototype.setRelativeSizes = function (sizes) {
4008 this.layout.setRelativeSizes(sizes);
4009 };
4010 /**
4011 * Handle the DOM events for the split panel.
4012 *
4013 * @param event - The DOM event sent to the panel.
4014 *
4015 * #### Notes
4016 * This method implements the DOM `EventListener` interface and is
4017 * called in response to events on the panel's DOM node. It should
4018 * not be called directly by user code.
4019 */
4020 SplitPanel.prototype.handleEvent = function (event) {
4021 switch (event.type) {
4022 case 'mousedown':
4023 this._evtMouseDown(event);
4024 break;
4025 case 'mousemove':
4026 this._evtMouseMove(event);
4027 break;
4028 case 'mouseup':
4029 this._evtMouseUp(event);
4030 break;
4031 case 'pointerdown':
4032 this._evtMouseDown(event);
4033 break;
4034 case 'pointermove':
4035 this._evtMouseMove(event);
4036 break;
4037 case 'pointerup':
4038 this._evtMouseUp(event);
4039 break;
4040 case 'keydown':
4041 this._evtKeyDown(event);
4042 break;
4043 case 'contextmenu':
4044 event.preventDefault();
4045 event.stopPropagation();
4046 break;
4047 }
4048 };
4049 /**
4050 * A message handler invoked on a `'before-attach'` message.
4051 */
4052 SplitPanel.prototype.onBeforeAttach = function (msg) {
4053 this.node.addEventListener('mousedown', this);
4054 this.node.addEventListener('pointerdown', this);
4055 };
4056 /**
4057 * A message handler invoked on an `'after-detach'` message.
4058 */
4059 SplitPanel.prototype.onAfterDetach = function (msg) {
4060 this.node.removeEventListener('mousedown', this);
4061 this.node.removeEventListener('pointerdown', this);
4062 this._releaseMouse();
4063 };
4064 /**
4065 * A message handler invoked on a `'child-added'` message.
4066 */
4067 SplitPanel.prototype.onChildAdded = function (msg) {
4068 msg.child.addClass('lm-SplitPanel-child');
4069 /* <DEPRECATED> */
4070 msg.child.addClass('p-SplitPanel-child');
4071 /* </DEPRECATED> */
4072 this._releaseMouse();
4073 };
4074 /**
4075 * A message handler invoked on a `'child-removed'` message.
4076 */
4077 SplitPanel.prototype.onChildRemoved = function (msg) {
4078 msg.child.removeClass('lm-SplitPanel-child');
4079 /* <DEPRECATED> */
4080 msg.child.removeClass('p-SplitPanel-child');
4081 /* </DEPRECATED> */
4082 this._releaseMouse();
4083 };
4084 /**
4085 * Handle the `'keydown'` event for the split panel.
4086 */
4087 SplitPanel.prototype._evtKeyDown = function (event) {
4088 // Stop input events during drag.
4089 if (this._pressData) {
4090 event.preventDefault();
4091 event.stopPropagation();
4092 }
4093 // Release the mouse if `Escape` is pressed.
4094 if (event.keyCode === 27) {
4095 this._releaseMouse();
4096 }
4097 };
4098 /**
4099 * Handle the `'mousedown'` event for the split panel.
4100 */
4101 SplitPanel.prototype._evtMouseDown = function (event) {
4102 // Do nothing if the left mouse button is not pressed.
4103 if (event.button !== 0) {
4104 return;
4105 }
4106 // Find the handle which contains the mouse target, if any.
4107 var layout = this.layout;
4108 var index = algorithm.ArrayExt.findFirstIndex(layout.handles, function (handle) {
4109 return handle.contains(event.target);
4110 });
4111 // Bail early if the mouse press was not on a handle.
4112 if (index === -1) {
4113 return;
4114 }
4115 // Stop the event when a split handle is pressed.
4116 event.preventDefault();
4117 event.stopPropagation();
4118 // Add the extra document listeners.
4119 document.addEventListener('mouseup', this, true);
4120 document.addEventListener('mousemove', this, true);
4121 document.addEventListener('pointerup', this, true);
4122 document.addEventListener('pointermove', this, true);
4123 document.addEventListener('keydown', this, true);
4124 document.addEventListener('contextmenu', this, true);
4125 // Compute the offset delta for the handle press.
4126 var delta;
4127 var handle = layout.handles[index];
4128 var rect = handle.getBoundingClientRect();
4129 if (layout.orientation === 'horizontal') {
4130 delta = event.clientX - rect.left;
4131 }
4132 else {
4133 delta = event.clientY - rect.top;
4134 }
4135 // Override the cursor and store the press data.
4136 var style = window.getComputedStyle(handle);
4137 var override = dragdrop.Drag.overrideCursor(style.cursor);
4138 this._pressData = { index: index, delta: delta, override: override };
4139 };
4140 /**
4141 * Handle the `'mousemove'` event for the split panel.
4142 */
4143 SplitPanel.prototype._evtMouseMove = function (event) {
4144 // Stop the event when dragging a split handle.
4145 event.preventDefault();
4146 event.stopPropagation();
4147 // Compute the desired offset position for the handle.
4148 var pos;
4149 var layout = this.layout;
4150 var rect = this.node.getBoundingClientRect();
4151 if (layout.orientation === 'horizontal') {
4152 pos = event.clientX - rect.left - this._pressData.delta;
4153 }
4154 else {
4155 pos = event.clientY - rect.top - this._pressData.delta;
4156 }
4157 // Move the handle as close to the desired position as possible.
4158 layout.moveHandle(this._pressData.index, pos);
4159 };
4160 /**
4161 * Handle the `'mouseup'` event for the split panel.
4162 */
4163 SplitPanel.prototype._evtMouseUp = function (event) {
4164 // Do nothing if the left mouse button is not released.
4165 if (event.button !== 0) {
4166 return;
4167 }
4168 // Stop the event when releasing a handle.
4169 event.preventDefault();
4170 event.stopPropagation();
4171 // Finalize the mouse release.
4172 this._releaseMouse();
4173 };
4174 /**
4175 * Release the mouse grab for the split panel.
4176 */
4177 SplitPanel.prototype._releaseMouse = function () {
4178 // Bail early if no drag is in progress.
4179 if (!this._pressData) {
4180 return;
4181 }
4182 // Clear the override cursor.
4183 this._pressData.override.dispose();
4184 this._pressData = null;
4185 // Emit the handle moved signal.
4186 this._handleMoved.emit();
4187 // Remove the extra document listeners.
4188 document.removeEventListener('mouseup', this, true);
4189 document.removeEventListener('mousemove', this, true);
4190 document.removeEventListener('keydown', this, true);
4191 document.removeEventListener('pointerup', this, true);
4192 document.removeEventListener('pointermove', this, true);
4193 document.removeEventListener('contextmenu', this, true);
4194 };
4195 return SplitPanel;
4196 }(Panel));
4197 /**
4198 * The namespace for the `SplitPanel` class statics.
4199 */
4200 (function (SplitPanel) {
4201 /**
4202 * The default implementation of `IRenderer`.
4203 */
4204 var Renderer = /** @class */ (function () {
4205 function Renderer() {
4206 }
4207 /**
4208 * Create a new handle for use with a split panel.
4209 *
4210 * @returns A new handle element for a split panel.
4211 */
4212 Renderer.prototype.createHandle = function () {
4213 var handle = document.createElement('div');
4214 handle.className = 'lm-SplitPanel-handle';
4215 /* <DEPRECATED> */
4216 handle.classList.add('p-SplitPanel-handle');
4217 /* </DEPRECATED> */
4218 return handle;
4219 };
4220 return Renderer;
4221 }());
4222 SplitPanel.Renderer = Renderer;
4223 /**
4224 * The default `Renderer` instance.
4225 */
4226 SplitPanel.defaultRenderer = new Renderer();
4227 /**
4228 * Get the split panel stretch factor for the given widget.
4229 *
4230 * @param widget - The widget of interest.
4231 *
4232 * @returns The split panel stretch factor for the widget.
4233 */
4234 function getStretch(widget) {
4235 return exports.SplitLayout.getStretch(widget);
4236 }
4237 SplitPanel.getStretch = getStretch;
4238 /**
4239 * Set the split panel stretch factor for the given widget.
4240 *
4241 * @param widget - The widget of interest.
4242 *
4243 * @param value - The value for the stretch factor.
4244 */
4245 function setStretch(widget, value) {
4246 exports.SplitLayout.setStretch(widget, value);
4247 }
4248 SplitPanel.setStretch = setStretch;
4249 })(exports.SplitPanel || (exports.SplitPanel = {}));
4250 /**
4251 * The namespace for the module implementation details.
4252 */
4253 var Private$e;
4254 (function (Private) {
4255 /**
4256 * Create a split layout for the given panel options.
4257 */
4258 function createLayout(options) {
4259 return (options.layout ||
4260 new exports.SplitLayout({
4261 renderer: options.renderer || exports.SplitPanel.defaultRenderer,
4262 orientation: options.orientation,
4263 alignment: options.alignment,
4264 spacing: options.spacing
4265 }));
4266 }
4267 Private.createLayout = createLayout;
4268 })(Private$e || (Private$e = {}));
4269
4270 // Copyright (c) Jupyter Development Team.
4271 /**
4272 * A panel which arranges its widgets into resizable sections separated by a title widget.
4273 *
4274 * #### Notes
4275 * This class provides a convenience wrapper around [[AccordionLayout]].
4276 */
4277 exports.AccordionPanel = /** @class */ (function (_super) {
4278 __extends(AccordionPanel, _super);
4279 /**
4280 * Construct a new accordion panel.
4281 *
4282 * @param options - The options for initializing the accordion panel.
4283 */
4284 function AccordionPanel(options) {
4285 if (options === void 0) { options = {}; }
4286 var _this = _super.call(this, __assign(__assign({}, options), { layout: Private$d.createLayout(options) })) || this;
4287 _this.addClass('lm-AccordionPanel');
4288 return _this;
4289 }
4290 Object.defineProperty(AccordionPanel.prototype, "renderer", {
4291 /**
4292 * The renderer used by the accordion panel.
4293 */
4294 get: function () {
4295 return this.layout.renderer;
4296 },
4297 enumerable: true,
4298 configurable: true
4299 });
4300 Object.defineProperty(AccordionPanel.prototype, "titleSpace", {
4301 /**
4302 * The section title space.
4303 *
4304 * This is the height if the panel is vertical and the width if it is
4305 * horizontal.
4306 */
4307 get: function () {
4308 return this.layout.titleSpace;
4309 },
4310 set: function (value) {
4311 this.layout.titleSpace = value;
4312 },
4313 enumerable: true,
4314 configurable: true
4315 });
4316 Object.defineProperty(AccordionPanel.prototype, "titles", {
4317 /**
4318 * A read-only array of the section titles in the panel.
4319 */
4320 get: function () {
4321 return this.layout.titles;
4322 },
4323 enumerable: true,
4324 configurable: true
4325 });
4326 /**
4327 * Add a widget to the end of the panel.
4328 *
4329 * @param widget - The widget to add to the panel.
4330 *
4331 * #### Notes
4332 * If the widget is already contained in the panel, it will be moved.
4333 */
4334 AccordionPanel.prototype.addWidget = function (widget) {
4335 _super.prototype.addWidget.call(this, widget);
4336 widget.title.changed.connect(this._onTitleChanged, this);
4337 };
4338 /**
4339 * Insert a widget at the specified index.
4340 *
4341 * @param index - The index at which to insert the widget.
4342 *
4343 * @param widget - The widget to insert into to the panel.
4344 *
4345 * #### Notes
4346 * If the widget is already contained in the panel, it will be moved.
4347 */
4348 AccordionPanel.prototype.insertWidget = function (index, widget) {
4349 _super.prototype.insertWidget.call(this, index, widget);
4350 widget.title.changed.connect(this._onTitleChanged, this);
4351 };
4352 /**
4353 * Handle the DOM events for the accordion panel.
4354 *
4355 * @param event - The DOM event sent to the panel.
4356 *
4357 * #### Notes
4358 * This method implements the DOM `EventListener` interface and is
4359 * called in response to events on the panel's DOM node. It should
4360 * not be called directly by user code.
4361 */
4362 AccordionPanel.prototype.handleEvent = function (event) {
4363 _super.prototype.handleEvent.call(this, event);
4364 switch (event.type) {
4365 case 'click':
4366 this._evtClick(event);
4367 break;
4368 case 'keydown':
4369 this._eventKeyDown(event);
4370 break;
4371 }
4372 };
4373 /**
4374 * A message handler invoked on a `'before-attach'` message.
4375 */
4376 AccordionPanel.prototype.onBeforeAttach = function (msg) {
4377 this.node.addEventListener('click', this);
4378 this.node.addEventListener('keydown', this);
4379 _super.prototype.onBeforeAttach.call(this, msg);
4380 };
4381 /**
4382 * A message handler invoked on an `'after-detach'` message.
4383 */
4384 AccordionPanel.prototype.onAfterDetach = function (msg) {
4385 _super.prototype.onAfterDetach.call(this, msg);
4386 this.node.removeEventListener('click', this);
4387 this.node.removeEventListener('keydown', this);
4388 };
4389 /**
4390 * Handle the `changed` signal of a title object.
4391 */
4392 AccordionPanel.prototype._onTitleChanged = function (sender) {
4393 var index = algorithm.ArrayExt.findFirstIndex(this.widgets, function (widget) {
4394 return widget.contains(sender.owner);
4395 });
4396 if (index >= 0) {
4397 this.layout.updateTitle(index, sender.owner);
4398 this.update();
4399 }
4400 };
4401 /**
4402 * Handle the `'click'` event for the accordion panel
4403 */
4404 AccordionPanel.prototype._evtClick = function (event) {
4405 var target = event.target;
4406 if (target) {
4407 var index = algorithm.ArrayExt.findFirstIndex(this.titles, function (title) {
4408 return title.contains(target);
4409 });
4410 if (index >= 0) {
4411 event.preventDefault();
4412 event.stopPropagation();
4413 var title = this.titles[index];
4414 var widget = this.layout.widgets[index];
4415 if (widget.isHidden) {
4416 title.classList.add('lm-mod-expanded');
4417 title.setAttribute('aria-expanded', 'true');
4418 widget.show();
4419 }
4420 else {
4421 title.classList.remove('lm-mod-expanded');
4422 title.setAttribute('aria-expanded', 'false');
4423 widget.hide();
4424 }
4425 }
4426 }
4427 };
4428 /**
4429 * Handle the `'keydown'` event for the accordion panel.
4430 */
4431 AccordionPanel.prototype._eventKeyDown = function (event) {
4432 if (event.defaultPrevented) {
4433 return;
4434 }
4435 var target = event.target;
4436 var handled = false;
4437 if (target) {
4438 var index = algorithm.ArrayExt.findFirstIndex(this.titles, function (title) {
4439 return title.contains(target);
4440 });
4441 if (index >= 0) {
4442 var keyCode = event.keyCode.toString();
4443 // If Space or Enter is pressed on title, emulate click event
4444 if (event.key.match(/Space|Enter/) || keyCode.match(/13|32/)) {
4445 target.click();
4446 handled = true;
4447 }
4448 else if (this.orientation === 'horizontal'
4449 ? event.key.match(/ArrowLeft|ArrowRight/) || keyCode.match(/37|39/)
4450 : event.key.match(/ArrowUp|ArrowDown/) || keyCode.match(/38|40/)) {
4451 // If Up or Down (for vertical) / Left or Right (for horizontal) is pressed on title, loop on titles
4452 var direction = event.key.match(/ArrowLeft|ArrowUp/) || keyCode.match(/37|38/)
4453 ? -1
4454 : 1;
4455 var length_1 = this.titles.length;
4456 var newIndex = (index + length_1 + direction) % length_1;
4457 this.titles[newIndex].focus();
4458 handled = true;
4459 }
4460 else if (event.key === 'End' || keyCode === '35') {
4461 // If End is pressed on title, focus on the last title
4462 this.titles[this.titles.length - 1].focus();
4463 handled = true;
4464 }
4465 else if (event.key === 'Home' || keyCode === '36') {
4466 // If Home is pressed on title, focus on the first title
4467 this.titles[0].focus();
4468 handled = true;
4469 }
4470 }
4471 if (handled) {
4472 event.preventDefault();
4473 }
4474 }
4475 };
4476 return AccordionPanel;
4477 }(exports.SplitPanel));
4478 /**
4479 * The namespace for the `AccordionPanel` class statics.
4480 */
4481 (function (AccordionPanel) {
4482 /**
4483 * The default implementation of `IRenderer`.
4484 */
4485 var Renderer = /** @class */ (function (_super) {
4486 __extends(Renderer, _super);
4487 function Renderer() {
4488 var _this = _super !== null && _super.apply(this, arguments) || this;
4489 /**
4490 * A selector which matches any title node in the accordion.
4491 */
4492 _this.titleClassName = 'lm-AccordionPanel-title';
4493 _this._titleID = 0;
4494 _this._titleKeys = new WeakMap();
4495 return _this;
4496 }
4497 /**
4498 * Render the collapse indicator for a section title.
4499 *
4500 * @param data - The data to use for rendering the section title.
4501 *
4502 * @returns A element representing the collapse indicator.
4503 */
4504 Renderer.prototype.createCollapseIcon = function (data) {
4505 return document.createElement('span');
4506 };
4507 /**
4508 * Render the element for a section title.
4509 *
4510 * @param data - The data to use for rendering the section title.
4511 *
4512 * @returns A element representing the section title.
4513 */
4514 Renderer.prototype.createSectionTitle = function (data) {
4515 var handle = document.createElement('h3');
4516 handle.setAttribute('role', 'button');
4517 handle.setAttribute('tabindex', '0');
4518 handle.id = this.createTitleKey(data);
4519 handle.className = this.titleClassName;
4520 handle.title = data.caption;
4521 for (var aData in data.dataset) {
4522 handle.dataset[aData] = data.dataset[aData];
4523 }
4524 var collapser = handle.appendChild(this.createCollapseIcon(data));
4525 collapser.className = 'lm-AccordionPanel-titleCollapser';
4526 var label = handle.appendChild(document.createElement('span'));
4527 label.className = 'lm-AccordionPanel-titleLabel';
4528 label.textContent = data.label;
4529 return handle;
4530 };
4531 /**
4532 * Create a unique render key for the title.
4533 *
4534 * @param data - The data to use for the title.
4535 *
4536 * @returns The unique render key for the title.
4537 *
4538 * #### Notes
4539 * This method caches the key against the section title the first time
4540 * the key is generated.
4541 */
4542 Renderer.prototype.createTitleKey = function (data) {
4543 var key = this._titleKeys.get(data);
4544 if (key === undefined) {
4545 key = "title-key-" + this._titleID++;
4546 this._titleKeys.set(data, key);
4547 }
4548 return key;
4549 };
4550 return Renderer;
4551 }(exports.SplitPanel.Renderer));
4552 AccordionPanel.Renderer = Renderer;
4553 /**
4554 * The default `Renderer` instance.
4555 */
4556 AccordionPanel.defaultRenderer = new Renderer();
4557 })(exports.AccordionPanel || (exports.AccordionPanel = {}));
4558 var Private$d;
4559 (function (Private) {
4560 /**
4561 * Create an accordion layout for the given panel options.
4562 *
4563 * @param options Panel options
4564 * @returns Panel layout
4565 */
4566 function createLayout(options) {
4567 return (options.layout ||
4568 new AccordionLayout({
4569 renderer: options.renderer || exports.AccordionPanel.defaultRenderer,
4570 orientation: options.orientation,
4571 alignment: options.alignment,
4572 spacing: options.spacing,
4573 titleSpace: options.titleSpace
4574 }));
4575 }
4576 Private.createLayout = createLayout;
4577 })(Private$d || (Private$d = {}));
4578
4579 /**
4580 * A layout which arranges its widgets in a single row or column.
4581 */
4582 exports.BoxLayout = /** @class */ (function (_super) {
4583 __extends(BoxLayout, _super);
4584 /**
4585 * Construct a new box layout.
4586 *
4587 * @param options - The options for initializing the layout.
4588 */
4589 function BoxLayout(options) {
4590 if (options === void 0) { options = {}; }
4591 var _this = _super.call(this) || this;
4592 _this._fixed = 0;
4593 _this._spacing = 4;
4594 _this._dirty = false;
4595 _this._sizers = [];
4596 _this._items = [];
4597 _this._box = null;
4598 _this._alignment = 'start';
4599 _this._direction = 'top-to-bottom';
4600 if (options.direction !== undefined) {
4601 _this._direction = options.direction;
4602 }
4603 if (options.alignment !== undefined) {
4604 _this._alignment = options.alignment;
4605 }
4606 if (options.spacing !== undefined) {
4607 _this._spacing = Utils$1.clampDimension(options.spacing);
4608 }
4609 return _this;
4610 }
4611 /**
4612 * Dispose of the resources held by the layout.
4613 */
4614 BoxLayout.prototype.dispose = function () {
4615 // Dispose of the layout items.
4616 algorithm.each(this._items, function (item) {
4617 item.dispose();
4618 });
4619 // Clear the layout state.
4620 this._box = null;
4621 this._items.length = 0;
4622 this._sizers.length = 0;
4623 // Dispose of the rest of the layout.
4624 _super.prototype.dispose.call(this);
4625 };
4626 Object.defineProperty(BoxLayout.prototype, "direction", {
4627 /**
4628 * Get the layout direction for the box layout.
4629 */
4630 get: function () {
4631 return this._direction;
4632 },
4633 /**
4634 * Set the layout direction for the box layout.
4635 */
4636 set: function (value) {
4637 if (this._direction === value) {
4638 return;
4639 }
4640 this._direction = value;
4641 if (!this.parent) {
4642 return;
4643 }
4644 this.parent.dataset['direction'] = value;
4645 this.parent.fit();
4646 },
4647 enumerable: true,
4648 configurable: true
4649 });
4650 Object.defineProperty(BoxLayout.prototype, "alignment", {
4651 /**
4652 * Get the content alignment for the box layout.
4653 *
4654 * #### Notes
4655 * This is the alignment of the widgets in the layout direction.
4656 *
4657 * The alignment has no effect if the widgets can expand to fill the
4658 * entire box layout.
4659 */
4660 get: function () {
4661 return this._alignment;
4662 },
4663 /**
4664 * Set the content alignment for the box layout.
4665 *
4666 * #### Notes
4667 * This is the alignment of the widgets in the layout direction.
4668 *
4669 * The alignment has no effect if the widgets can expand to fill the
4670 * entire box layout.
4671 */
4672 set: function (value) {
4673 if (this._alignment === value) {
4674 return;
4675 }
4676 this._alignment = value;
4677 if (!this.parent) {
4678 return;
4679 }
4680 this.parent.dataset['alignment'] = value;
4681 this.parent.update();
4682 },
4683 enumerable: true,
4684 configurable: true
4685 });
4686 Object.defineProperty(BoxLayout.prototype, "spacing", {
4687 /**
4688 * Get the inter-element spacing for the box layout.
4689 */
4690 get: function () {
4691 return this._spacing;
4692 },
4693 /**
4694 * Set the inter-element spacing for the box layout.
4695 */
4696 set: function (value) {
4697 value = Utils$1.clampDimension(value);
4698 if (this._spacing === value) {
4699 return;
4700 }
4701 this._spacing = value;
4702 if (!this.parent) {
4703 return;
4704 }
4705 this.parent.fit();
4706 },
4707 enumerable: true,
4708 configurable: true
4709 });
4710 /**
4711 * Perform layout initialization which requires the parent widget.
4712 */
4713 BoxLayout.prototype.init = function () {
4714 this.parent.dataset['direction'] = this.direction;
4715 this.parent.dataset['alignment'] = this.alignment;
4716 _super.prototype.init.call(this);
4717 };
4718 /**
4719 * Attach a widget to the parent's DOM node.
4720 *
4721 * @param index - The current index of the widget in the layout.
4722 *
4723 * @param widget - The widget to attach to the parent.
4724 *
4725 * #### Notes
4726 * This is a reimplementation of the superclass method.
4727 */
4728 BoxLayout.prototype.attachWidget = function (index, widget) {
4729 // Create and add a new layout item for the widget.
4730 algorithm.ArrayExt.insert(this._items, index, new LayoutItem(widget));
4731 // Create and add a new sizer for the widget.
4732 algorithm.ArrayExt.insert(this._sizers, index, new BoxSizer());
4733 // Send a `'before-attach'` message if the parent is attached.
4734 if (this.parent.isAttached) {
4735 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.BeforeAttach);
4736 }
4737 // Add the widget's node to the parent.
4738 this.parent.node.appendChild(widget.node);
4739 // Send an `'after-attach'` message if the parent is attached.
4740 if (this.parent.isAttached) {
4741 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.AfterAttach);
4742 }
4743 // Post a fit request for the parent widget.
4744 this.parent.fit();
4745 };
4746 /**
4747 * Move a widget in the parent's DOM node.
4748 *
4749 * @param fromIndex - The previous index of the widget in the layout.
4750 *
4751 * @param toIndex - The current index of the widget in the layout.
4752 *
4753 * @param widget - The widget to move in the parent.
4754 *
4755 * #### Notes
4756 * This is a reimplementation of the superclass method.
4757 */
4758 BoxLayout.prototype.moveWidget = function (fromIndex, toIndex, widget) {
4759 // Move the layout item for the widget.
4760 algorithm.ArrayExt.move(this._items, fromIndex, toIndex);
4761 // Move the sizer for the widget.
4762 algorithm.ArrayExt.move(this._sizers, fromIndex, toIndex);
4763 // Post an update request for the parent widget.
4764 this.parent.update();
4765 };
4766 /**
4767 * Detach a widget from the parent's DOM node.
4768 *
4769 * @param index - The previous index of the widget in the layout.
4770 *
4771 * @param widget - The widget to detach from the parent.
4772 *
4773 * #### Notes
4774 * This is a reimplementation of the superclass method.
4775 */
4776 BoxLayout.prototype.detachWidget = function (index, widget) {
4777 // Remove the layout item for the widget.
4778 var item = algorithm.ArrayExt.removeAt(this._items, index);
4779 // Remove the sizer for the widget.
4780 algorithm.ArrayExt.removeAt(this._sizers, index);
4781 // Send a `'before-detach'` message if the parent is attached.
4782 if (this.parent.isAttached) {
4783 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.BeforeDetach);
4784 }
4785 // Remove the widget's node from the parent.
4786 this.parent.node.removeChild(widget.node);
4787 // Send an `'after-detach'` message if the parent is attached.
4788 if (this.parent.isAttached) {
4789 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.AfterDetach);
4790 }
4791 // Dispose of the layout item.
4792 item.dispose();
4793 // Post a fit request for the parent widget.
4794 this.parent.fit();
4795 };
4796 /**
4797 * A message handler invoked on a `'before-show'` message.
4798 */
4799 BoxLayout.prototype.onBeforeShow = function (msg) {
4800 _super.prototype.onBeforeShow.call(this, msg);
4801 this.parent.update();
4802 };
4803 /**
4804 * A message handler invoked on a `'before-attach'` message.
4805 */
4806 BoxLayout.prototype.onBeforeAttach = function (msg) {
4807 _super.prototype.onBeforeAttach.call(this, msg);
4808 this.parent.fit();
4809 };
4810 /**
4811 * A message handler invoked on a `'child-shown'` message.
4812 */
4813 BoxLayout.prototype.onChildShown = function (msg) {
4814 this.parent.fit();
4815 };
4816 /**
4817 * A message handler invoked on a `'child-hidden'` message.
4818 */
4819 BoxLayout.prototype.onChildHidden = function (msg) {
4820 this.parent.fit();
4821 };
4822 /**
4823 * A message handler invoked on a `'resize'` message.
4824 */
4825 BoxLayout.prototype.onResize = function (msg) {
4826 if (this.parent.isVisible) {
4827 this._update(msg.width, msg.height);
4828 }
4829 };
4830 /**
4831 * A message handler invoked on an `'update-request'` message.
4832 */
4833 BoxLayout.prototype.onUpdateRequest = function (msg) {
4834 if (this.parent.isVisible) {
4835 this._update(-1, -1);
4836 }
4837 };
4838 /**
4839 * A message handler invoked on a `'fit-request'` message.
4840 */
4841 BoxLayout.prototype.onFitRequest = function (msg) {
4842 if (this.parent.isAttached) {
4843 this._fit();
4844 }
4845 };
4846 /**
4847 * Fit the layout to the total size required by the widgets.
4848 */
4849 BoxLayout.prototype._fit = function () {
4850 // Compute the visible item count.
4851 var nVisible = 0;
4852 for (var i = 0, n = this._items.length; i < n; ++i) {
4853 nVisible += +!this._items[i].isHidden;
4854 }
4855 // Update the fixed space for the visible items.
4856 this._fixed = this._spacing * Math.max(0, nVisible - 1);
4857 // Setup the computed minimum size.
4858 var horz = Private$c.isHorizontal(this._direction);
4859 var minW = horz ? this._fixed : 0;
4860 var minH = horz ? 0 : this._fixed;
4861 // Update the sizers and computed minimum size.
4862 for (var i = 0, n = this._items.length; i < n; ++i) {
4863 // Fetch the item and corresponding box sizer.
4864 var item = this._items[i];
4865 var sizer = this._sizers[i];
4866 // If the item is hidden, it should consume zero size.
4867 if (item.isHidden) {
4868 sizer.minSize = 0;
4869 sizer.maxSize = 0;
4870 continue;
4871 }
4872 // Update the size limits for the item.
4873 item.fit();
4874 // Update the size basis and stretch factor.
4875 sizer.sizeHint = BoxLayout.getSizeBasis(item.widget);
4876 sizer.stretch = BoxLayout.getStretch(item.widget);
4877 // Update the sizer limits and computed min size.
4878 if (horz) {
4879 sizer.minSize = item.minWidth;
4880 sizer.maxSize = item.maxWidth;
4881 minW += item.minWidth;
4882 minH = Math.max(minH, item.minHeight);
4883 }
4884 else {
4885 sizer.minSize = item.minHeight;
4886 sizer.maxSize = item.maxHeight;
4887 minH += item.minHeight;
4888 minW = Math.max(minW, item.minWidth);
4889 }
4890 }
4891 // Update the box sizing and add it to the computed min size.
4892 var box = (this._box = domutils.ElementExt.boxSizing(this.parent.node));
4893 minW += box.horizontalSum;
4894 minH += box.verticalSum;
4895 // Update the parent's min size constraints.
4896 var style = this.parent.node.style;
4897 style.minWidth = minW + "px";
4898 style.minHeight = minH + "px";
4899 // Set the dirty flag to ensure only a single update occurs.
4900 this._dirty = true;
4901 // Notify the ancestor that it should fit immediately. This may
4902 // cause a resize of the parent, fulfilling the required update.
4903 if (this.parent.parent) {
4904 messaging.MessageLoop.sendMessage(this.parent.parent, exports.Widget.Msg.FitRequest);
4905 }
4906 // If the dirty flag is still set, the parent was not resized.
4907 // Trigger the required update on the parent widget immediately.
4908 if (this._dirty) {
4909 messaging.MessageLoop.sendMessage(this.parent, exports.Widget.Msg.UpdateRequest);
4910 }
4911 };
4912 /**
4913 * Update the layout position and size of the widgets.
4914 *
4915 * The parent offset dimensions should be `-1` if unknown.
4916 */
4917 BoxLayout.prototype._update = function (offsetWidth, offsetHeight) {
4918 // Clear the dirty flag to indicate the update occurred.
4919 this._dirty = false;
4920 // Compute the visible item count.
4921 var nVisible = 0;
4922 for (var i = 0, n = this._items.length; i < n; ++i) {
4923 nVisible += +!this._items[i].isHidden;
4924 }
4925 // Bail early if there are no visible items to layout.
4926 if (nVisible === 0) {
4927 return;
4928 }
4929 // Measure the parent if the offset dimensions are unknown.
4930 if (offsetWidth < 0) {
4931 offsetWidth = this.parent.node.offsetWidth;
4932 }
4933 if (offsetHeight < 0) {
4934 offsetHeight = this.parent.node.offsetHeight;
4935 }
4936 // Ensure the parent box sizing data is computed.
4937 if (!this._box) {
4938 this._box = domutils.ElementExt.boxSizing(this.parent.node);
4939 }
4940 // Compute the layout area adjusted for border and padding.
4941 var top = this._box.paddingTop;
4942 var left = this._box.paddingLeft;
4943 var width = offsetWidth - this._box.horizontalSum;
4944 var height = offsetHeight - this._box.verticalSum;
4945 // Distribute the layout space and adjust the start position.
4946 var delta;
4947 switch (this._direction) {
4948 case 'left-to-right':
4949 delta = exports.BoxEngine.calc(this._sizers, Math.max(0, width - this._fixed));
4950 break;
4951 case 'top-to-bottom':
4952 delta = exports.BoxEngine.calc(this._sizers, Math.max(0, height - this._fixed));
4953 break;
4954 case 'right-to-left':
4955 delta = exports.BoxEngine.calc(this._sizers, Math.max(0, width - this._fixed));
4956 left += width;
4957 break;
4958 case 'bottom-to-top':
4959 delta = exports.BoxEngine.calc(this._sizers, Math.max(0, height - this._fixed));
4960 top += height;
4961 break;
4962 default:
4963 throw 'unreachable';
4964 }
4965 // Setup the variables for justification and alignment offset.
4966 var extra = 0;
4967 var offset = 0;
4968 // Account for alignment if there is extra layout space.
4969 if (delta > 0) {
4970 switch (this._alignment) {
4971 case 'start':
4972 break;
4973 case 'center':
4974 extra = 0;
4975 offset = delta / 2;
4976 break;
4977 case 'end':
4978 extra = 0;
4979 offset = delta;
4980 break;
4981 case 'justify':
4982 extra = delta / nVisible;
4983 offset = 0;
4984 break;
4985 default:
4986 throw 'unreachable';
4987 }
4988 }
4989 // Layout the items using the computed box sizes.
4990 for (var i = 0, n = this._items.length; i < n; ++i) {
4991 // Fetch the item.
4992 var item = this._items[i];
4993 // Ignore hidden items.
4994 if (item.isHidden) {
4995 continue;
4996 }
4997 // Fetch the computed size for the widget.
4998 var size = this._sizers[i].size;
4999 // Update the widget geometry and advance the relevant edge.
5000 switch (this._direction) {
5001 case 'left-to-right':
5002 item.update(left + offset, top, size + extra, height);
5003 left += size + extra + this._spacing;
5004 break;
5005 case 'top-to-bottom':
5006 item.update(left, top + offset, width, size + extra);
5007 top += size + extra + this._spacing;
5008 break;
5009 case 'right-to-left':
5010 item.update(left - offset - size - extra, top, size + extra, height);
5011 left -= size + extra + this._spacing;
5012 break;
5013 case 'bottom-to-top':
5014 item.update(left, top - offset - size - extra, width, size + extra);
5015 top -= size + extra + this._spacing;
5016 break;
5017 default:
5018 throw 'unreachable';
5019 }
5020 }
5021 };
5022 return BoxLayout;
5023 }(PanelLayout));
5024 /**
5025 * The namespace for the `BoxLayout` class statics.
5026 */
5027 (function (BoxLayout) {
5028 /**
5029 * Get the box layout stretch factor for the given widget.
5030 *
5031 * @param widget - The widget of interest.
5032 *
5033 * @returns The box layout stretch factor for the widget.
5034 */
5035 function getStretch(widget) {
5036 return Private$c.stretchProperty.get(widget);
5037 }
5038 BoxLayout.getStretch = getStretch;
5039 /**
5040 * Set the box layout stretch factor for the given widget.
5041 *
5042 * @param widget - The widget of interest.
5043 *
5044 * @param value - The value for the stretch factor.
5045 */
5046 function setStretch(widget, value) {
5047 Private$c.stretchProperty.set(widget, value);
5048 }
5049 BoxLayout.setStretch = setStretch;
5050 /**
5051 * Get the box layout size basis for the given widget.
5052 *
5053 * @param widget - The widget of interest.
5054 *
5055 * @returns The box layout size basis for the widget.
5056 */
5057 function getSizeBasis(widget) {
5058 return Private$c.sizeBasisProperty.get(widget);
5059 }
5060 BoxLayout.getSizeBasis = getSizeBasis;
5061 /**
5062 * Set the box layout size basis for the given widget.
5063 *
5064 * @param widget - The widget of interest.
5065 *
5066 * @param value - The value for the size basis.
5067 */
5068 function setSizeBasis(widget, value) {
5069 Private$c.sizeBasisProperty.set(widget, value);
5070 }
5071 BoxLayout.setSizeBasis = setSizeBasis;
5072 })(exports.BoxLayout || (exports.BoxLayout = {}));
5073 /**
5074 * The namespace for the module implementation details.
5075 */
5076 var Private$c;
5077 (function (Private) {
5078 /**
5079 * The property descriptor for a widget stretch factor.
5080 */
5081 Private.stretchProperty = new properties.AttachedProperty({
5082 name: 'stretch',
5083 create: function () { return 0; },
5084 coerce: function (owner, value) { return Math.max(0, Math.floor(value)); },
5085 changed: onChildSizingChanged
5086 });
5087 /**
5088 * The property descriptor for a widget size basis.
5089 */
5090 Private.sizeBasisProperty = new properties.AttachedProperty({
5091 name: 'sizeBasis',
5092 create: function () { return 0; },
5093 coerce: function (owner, value) { return Math.max(0, Math.floor(value)); },
5094 changed: onChildSizingChanged
5095 });
5096 /**
5097 * Test whether a direction has horizontal orientation.
5098 */
5099 function isHorizontal(dir) {
5100 return dir === 'left-to-right' || dir === 'right-to-left';
5101 }
5102 Private.isHorizontal = isHorizontal;
5103 /**
5104 * Clamp a spacing value to an integer >= 0.
5105 */
5106 function clampSpacing(value) {
5107 return Math.max(0, Math.floor(value));
5108 }
5109 Private.clampSpacing = clampSpacing;
5110 /**
5111 * The change handler for the attached sizing properties.
5112 */
5113 function onChildSizingChanged(child) {
5114 if (child.parent && child.parent.layout instanceof exports.BoxLayout) {
5115 child.parent.fit();
5116 }
5117 }
5118 })(Private$c || (Private$c = {}));
5119
5120 /**
5121 * A panel which arranges its widgets in a single row or column.
5122 *
5123 * #### Notes
5124 * This class provides a convenience wrapper around a [[BoxLayout]].
5125 */
5126 exports.BoxPanel = /** @class */ (function (_super) {
5127 __extends(BoxPanel, _super);
5128 /**
5129 * Construct a new box panel.
5130 *
5131 * @param options - The options for initializing the box panel.
5132 */
5133 function BoxPanel(options) {
5134 if (options === void 0) { options = {}; }
5135 var _this = _super.call(this, { layout: Private$b.createLayout(options) }) || this;
5136 _this.addClass('lm-BoxPanel');
5137 /* <DEPRECATED> */
5138 _this.addClass('p-BoxPanel');
5139 return _this;
5140 /* </DEPRECATED> */
5141 }
5142 Object.defineProperty(BoxPanel.prototype, "direction", {
5143 /**
5144 * Get the layout direction for the box panel.
5145 */
5146 get: function () {
5147 return this.layout.direction;
5148 },
5149 /**
5150 * Set the layout direction for the box panel.
5151 */
5152 set: function (value) {
5153 this.layout.direction = value;
5154 },
5155 enumerable: true,
5156 configurable: true
5157 });
5158 Object.defineProperty(BoxPanel.prototype, "alignment", {
5159 /**
5160 * Get the content alignment for the box panel.
5161 *
5162 * #### Notes
5163 * This is the alignment of the widgets in the layout direction.
5164 *
5165 * The alignment has no effect if the widgets can expand to fill the
5166 * entire box layout.
5167 */
5168 get: function () {
5169 return this.layout.alignment;
5170 },
5171 /**
5172 * Set the content alignment for the box panel.
5173 *
5174 * #### Notes
5175 * This is the alignment of the widgets in the layout direction.
5176 *
5177 * The alignment has no effect if the widgets can expand to fill the
5178 * entire box layout.
5179 */
5180 set: function (value) {
5181 this.layout.alignment = value;
5182 },
5183 enumerable: true,
5184 configurable: true
5185 });
5186 Object.defineProperty(BoxPanel.prototype, "spacing", {
5187 /**
5188 * Get the inter-element spacing for the box panel.
5189 */
5190 get: function () {
5191 return this.layout.spacing;
5192 },
5193 /**
5194 * Set the inter-element spacing for the box panel.
5195 */
5196 set: function (value) {
5197 this.layout.spacing = value;
5198 },
5199 enumerable: true,
5200 configurable: true
5201 });
5202 /**
5203 * A message handler invoked on a `'child-added'` message.
5204 */
5205 BoxPanel.prototype.onChildAdded = function (msg) {
5206 msg.child.addClass('lm-BoxPanel-child');
5207 /* <DEPRECATED> */
5208 msg.child.addClass('p-BoxPanel-child');
5209 /* </DEPRECATED> */
5210 };
5211 /**
5212 * A message handler invoked on a `'child-removed'` message.
5213 */
5214 BoxPanel.prototype.onChildRemoved = function (msg) {
5215 msg.child.removeClass('lm-BoxPanel-child');
5216 /* <DEPRECATED> */
5217 msg.child.removeClass('p-BoxPanel-child');
5218 /* </DEPRECATED> */
5219 };
5220 return BoxPanel;
5221 }(Panel));
5222 /**
5223 * The namespace for the `BoxPanel` class statics.
5224 */
5225 (function (BoxPanel) {
5226 /**
5227 * Get the box panel stretch factor for the given widget.
5228 *
5229 * @param widget - The widget of interest.
5230 *
5231 * @returns The box panel stretch factor for the widget.
5232 */
5233 function getStretch(widget) {
5234 return exports.BoxLayout.getStretch(widget);
5235 }
5236 BoxPanel.getStretch = getStretch;
5237 /**
5238 * Set the box panel stretch factor for the given widget.
5239 *
5240 * @param widget - The widget of interest.
5241 *
5242 * @param value - The value for the stretch factor.
5243 */
5244 function setStretch(widget, value) {
5245 exports.BoxLayout.setStretch(widget, value);
5246 }
5247 BoxPanel.setStretch = setStretch;
5248 /**
5249 * Get the box panel size basis for the given widget.
5250 *
5251 * @param widget - The widget of interest.
5252 *
5253 * @returns The box panel size basis for the widget.
5254 */
5255 function getSizeBasis(widget) {
5256 return exports.BoxLayout.getSizeBasis(widget);
5257 }
5258 BoxPanel.getSizeBasis = getSizeBasis;
5259 /**
5260 * Set the box panel size basis for the given widget.
5261 *
5262 * @param widget - The widget of interest.
5263 *
5264 * @param value - The value for the size basis.
5265 */
5266 function setSizeBasis(widget, value) {
5267 exports.BoxLayout.setSizeBasis(widget, value);
5268 }
5269 BoxPanel.setSizeBasis = setSizeBasis;
5270 })(exports.BoxPanel || (exports.BoxPanel = {}));
5271 /**
5272 * The namespace for the module implementation details.
5273 */
5274 var Private$b;
5275 (function (Private) {
5276 /**
5277 * Create a box layout for the given panel options.
5278 */
5279 function createLayout(options) {
5280 return options.layout || new exports.BoxLayout(options);
5281 }
5282 Private.createLayout = createLayout;
5283 })(Private$b || (Private$b = {}));
5284
5285 /**
5286 * A widget which displays command items as a searchable palette.
5287 */
5288 exports.CommandPalette = /** @class */ (function (_super) {
5289 __extends(CommandPalette, _super);
5290 /**
5291 * Construct a new command palette.
5292 *
5293 * @param options - The options for initializing the palette.
5294 */
5295 function CommandPalette(options) {
5296 var _this = _super.call(this, { node: Private$a.createNode() }) || this;
5297 _this._activeIndex = -1;
5298 _this._items = [];
5299 _this._results = null;
5300 _this.addClass('lm-CommandPalette');
5301 /* <DEPRECATED> */
5302 _this.addClass('p-CommandPalette');
5303 /* </DEPRECATED> */
5304 _this.setFlag(exports.Widget.Flag.DisallowLayout);
5305 _this.commands = options.commands;
5306 _this.renderer = options.renderer || CommandPalette.defaultRenderer;
5307 _this.commands.commandChanged.connect(_this._onGenericChange, _this);
5308 _this.commands.keyBindingChanged.connect(_this._onGenericChange, _this);
5309 return _this;
5310 }
5311 /**
5312 * Dispose of the resources held by the widget.
5313 */
5314 CommandPalette.prototype.dispose = function () {
5315 this._items.length = 0;
5316 this._results = null;
5317 _super.prototype.dispose.call(this);
5318 };
5319 Object.defineProperty(CommandPalette.prototype, "searchNode", {
5320 /**
5321 * The command palette search node.
5322 *
5323 * #### Notes
5324 * This is the node which contains the search-related elements.
5325 */
5326 get: function () {
5327 return this.node.getElementsByClassName('lm-CommandPalette-search')[0];
5328 },
5329 enumerable: true,
5330 configurable: true
5331 });
5332 Object.defineProperty(CommandPalette.prototype, "inputNode", {
5333 /**
5334 * The command palette input node.
5335 *
5336 * #### Notes
5337 * This is the actual input node for the search area.
5338 */
5339 get: function () {
5340 return this.node.getElementsByClassName('lm-CommandPalette-input')[0];
5341 },
5342 enumerable: true,
5343 configurable: true
5344 });
5345 Object.defineProperty(CommandPalette.prototype, "contentNode", {
5346 /**
5347 * The command palette content node.
5348 *
5349 * #### Notes
5350 * This is the node which holds the command item nodes.
5351 *
5352 * Modifying this node directly can lead to undefined behavior.
5353 */
5354 get: function () {
5355 return this.node.getElementsByClassName('lm-CommandPalette-content')[0];
5356 },
5357 enumerable: true,
5358 configurable: true
5359 });
5360 Object.defineProperty(CommandPalette.prototype, "items", {
5361 /**
5362 * A read-only array of the command items in the palette.
5363 */
5364 get: function () {
5365 return this._items;
5366 },
5367 enumerable: true,
5368 configurable: true
5369 });
5370 /**
5371 * Add a command item to the command palette.
5372 *
5373 * @param options - The options for creating the command item.
5374 *
5375 * @returns The command item added to the palette.
5376 */
5377 CommandPalette.prototype.addItem = function (options) {
5378 // Create a new command item for the options.
5379 var item = Private$a.createItem(this.commands, options);
5380 // Add the item to the array.
5381 this._items.push(item);
5382 // Refresh the search results.
5383 this.refresh();
5384 // Return the item added to the palette.
5385 return item;
5386 };
5387 /**
5388 * Adds command items to the command palette.
5389 *
5390 * @param items - An array of options for creating each command item.
5391 *
5392 * @returns The command items added to the palette.
5393 */
5394 CommandPalette.prototype.addItems = function (items) {
5395 var _this = this;
5396 var newItems = items.map(function (item) { return Private$a.createItem(_this.commands, item); });
5397 newItems.forEach(function (item) { return _this._items.push(item); });
5398 this.refresh();
5399 return newItems;
5400 };
5401 /**
5402 * Remove an item from the command palette.
5403 *
5404 * @param item - The item to remove from the palette.
5405 *
5406 * #### Notes
5407 * This is a no-op if the item is not in the palette.
5408 */
5409 CommandPalette.prototype.removeItem = function (item) {
5410 this.removeItemAt(this._items.indexOf(item));
5411 };
5412 /**
5413 * Remove the item at a given index from the command palette.
5414 *
5415 * @param index - The index of the item to remove.
5416 *
5417 * #### Notes
5418 * This is a no-op if the index is out of range.
5419 */
5420 CommandPalette.prototype.removeItemAt = function (index) {
5421 // Remove the item from the array.
5422 var item = algorithm.ArrayExt.removeAt(this._items, index);
5423 // Bail if the index is out of range.
5424 if (!item) {
5425 return;
5426 }
5427 // Refresh the search results.
5428 this.refresh();
5429 };
5430 /**
5431 * Remove all items from the command palette.
5432 */
5433 CommandPalette.prototype.clearItems = function () {
5434 // Bail if there is nothing to remove.
5435 if (this._items.length === 0) {
5436 return;
5437 }
5438 // Clear the array of items.
5439 this._items.length = 0;
5440 // Refresh the search results.
5441 this.refresh();
5442 };
5443 /**
5444 * Clear the search results and schedule an update.
5445 *
5446 * #### Notes
5447 * This should be called whenever the search results of the palette
5448 * should be updated.
5449 *
5450 * This is typically called automatically by the palette as needed,
5451 * but can be called manually if the input text is programatically
5452 * changed.
5453 *
5454 * The rendered results are updated asynchronously.
5455 */
5456 CommandPalette.prototype.refresh = function () {
5457 this._results = null;
5458 if (this.inputNode.value !== '') {
5459 var clear = this.node.getElementsByClassName('lm-close-icon')[0];
5460 clear.style.display = 'inherit';
5461 }
5462 else {
5463 var clear = this.node.getElementsByClassName('lm-close-icon')[0];
5464 clear.style.display = 'none';
5465 }
5466 this.update();
5467 };
5468 /**
5469 * Handle the DOM events for the command palette.
5470 *
5471 * @param event - The DOM event sent to the command palette.
5472 *
5473 * #### Notes
5474 * This method implements the DOM `EventListener` interface and is
5475 * called in response to events on the command palette's DOM node.
5476 * It should not be called directly by user code.
5477 */
5478 CommandPalette.prototype.handleEvent = function (event) {
5479 switch (event.type) {
5480 case 'click':
5481 this._evtClick(event);
5482 break;
5483 case 'keydown':
5484 this._evtKeyDown(event);
5485 break;
5486 case 'input':
5487 this.refresh();
5488 break;
5489 case 'focus':
5490 case 'blur':
5491 this._toggleFocused();
5492 break;
5493 }
5494 };
5495 /**
5496 * A message handler invoked on a `'before-attach'` message.
5497 */
5498 CommandPalette.prototype.onBeforeAttach = function (msg) {
5499 this.node.addEventListener('click', this);
5500 this.node.addEventListener('keydown', this);
5501 this.node.addEventListener('input', this);
5502 this.node.addEventListener('focus', this, true);
5503 this.node.addEventListener('blur', this, true);
5504 };
5505 /**
5506 * A message handler invoked on an `'after-detach'` message.
5507 */
5508 CommandPalette.prototype.onAfterDetach = function (msg) {
5509 this.node.removeEventListener('click', this);
5510 this.node.removeEventListener('keydown', this);
5511 this.node.removeEventListener('input', this);
5512 this.node.removeEventListener('focus', this, true);
5513 this.node.removeEventListener('blur', this, true);
5514 };
5515 /**
5516 * A message handler invoked on an `'activate-request'` message.
5517 */
5518 CommandPalette.prototype.onActivateRequest = function (msg) {
5519 if (this.isAttached) {
5520 var input = this.inputNode;
5521 input.focus();
5522 input.select();
5523 }
5524 };
5525 /**
5526 * A message handler invoked on an `'update-request'` message.
5527 */
5528 CommandPalette.prototype.onUpdateRequest = function (msg) {
5529 // Fetch the current query text and content node.
5530 var query = this.inputNode.value;
5531 var contentNode = this.contentNode;
5532 // Ensure the search results are generated.
5533 var results = this._results;
5534 if (!results) {
5535 // Generate and store the new search results.
5536 results = this._results = Private$a.search(this._items, query);
5537 // Reset the active index.
5538 this._activeIndex = query
5539 ? algorithm.ArrayExt.findFirstIndex(results, Private$a.canActivate)
5540 : -1;
5541 }
5542 // If there is no query and no results, clear the content.
5543 if (!query && results.length === 0) {
5544 virtualdom.VirtualDOM.render(null, contentNode);
5545 return;
5546 }
5547 // If the is a query but no results, render the empty message.
5548 if (query && results.length === 0) {
5549 var content_1 = this.renderer.renderEmptyMessage({ query: query });
5550 virtualdom.VirtualDOM.render(content_1, contentNode);
5551 return;
5552 }
5553 // Create the render content for the search results.
5554 var renderer = this.renderer;
5555 var activeIndex = this._activeIndex;
5556 var content = new Array(results.length);
5557 for (var i = 0, n = results.length; i < n; ++i) {
5558 var result = results[i];
5559 if (result.type === 'header') {
5560 var indices = result.indices;
5561 var category = result.category;
5562 content[i] = renderer.renderHeader({ category: category, indices: indices });
5563 }
5564 else {
5565 var item = result.item;
5566 var indices = result.indices;
5567 var active = i === activeIndex;
5568 content[i] = renderer.renderItem({ item: item, indices: indices, active: active });
5569 }
5570 }
5571 // Render the search result content.
5572 virtualdom.VirtualDOM.render(content, contentNode);
5573 // Adjust the scroll position as needed.
5574 if (activeIndex < 0 || activeIndex >= results.length) {
5575 contentNode.scrollTop = 0;
5576 }
5577 else {
5578 var element = contentNode.children[activeIndex];
5579 domutils.ElementExt.scrollIntoViewIfNeeded(contentNode, element);
5580 }
5581 };
5582 /**
5583 * Handle the `'click'` event for the command palette.
5584 */
5585 CommandPalette.prototype._evtClick = function (event) {
5586 // Bail if the click is not the left button.
5587 if (event.button !== 0) {
5588 return;
5589 }
5590 // Clear input if the target is clear button
5591 if (event.target.classList.contains('lm-close-icon')) {
5592 this.inputNode.value = '';
5593 this.refresh();
5594 return;
5595 }
5596 // Find the index of the item which was clicked.
5597 var index = algorithm.ArrayExt.findFirstIndex(this.contentNode.children, function (node) {
5598 return node.contains(event.target);
5599 });
5600 // Bail if the click was not on an item.
5601 if (index === -1) {
5602 return;
5603 }
5604 // Kill the event when a content item is clicked.
5605 event.preventDefault();
5606 event.stopPropagation();
5607 // Execute the item if possible.
5608 this._execute(index);
5609 };
5610 /**
5611 * Handle the `'keydown'` event for the command palette.
5612 */
5613 CommandPalette.prototype._evtKeyDown = function (event) {
5614 if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {
5615 return;
5616 }
5617 switch (event.keyCode) {
5618 case 13: // Enter
5619 event.preventDefault();
5620 event.stopPropagation();
5621 this._execute(this._activeIndex);
5622 break;
5623 case 38: // Up Arrow
5624 event.preventDefault();
5625 event.stopPropagation();
5626 this._activatePreviousItem();
5627 break;
5628 case 40: // Down Arrow
5629 event.preventDefault();
5630 event.stopPropagation();
5631 this._activateNextItem();
5632 break;
5633 }
5634 };
5635 /**
5636 * Activate the next enabled command item.
5637 */
5638 CommandPalette.prototype._activateNextItem = function () {
5639 // Bail if there are no search results.
5640 if (!this._results || this._results.length === 0) {
5641 return;
5642 }
5643 // Find the next enabled item index.
5644 var ai = this._activeIndex;
5645 var n = this._results.length;
5646 var start = ai < n - 1 ? ai + 1 : 0;
5647 var stop = start === 0 ? n - 1 : start - 1;
5648 this._activeIndex = algorithm.ArrayExt.findFirstIndex(this._results, Private$a.canActivate, start, stop);
5649 // Schedule an update of the items.
5650 this.update();
5651 };
5652 /**
5653 * Activate the previous enabled command item.
5654 */
5655 CommandPalette.prototype._activatePreviousItem = function () {
5656 // Bail if there are no search results.
5657 if (!this._results || this._results.length === 0) {
5658 return;
5659 }
5660 // Find the previous enabled item index.
5661 var ai = this._activeIndex;
5662 var n = this._results.length;
5663 var start = ai <= 0 ? n - 1 : ai - 1;
5664 var stop = start === n - 1 ? 0 : start + 1;
5665 this._activeIndex = algorithm.ArrayExt.findLastIndex(this._results, Private$a.canActivate, start, stop);
5666 // Schedule an update of the items.
5667 this.update();
5668 };
5669 /**
5670 * Execute the command item at the given index, if possible.
5671 */
5672 CommandPalette.prototype._execute = function (index) {
5673 // Bail if there are no search results.
5674 if (!this._results) {
5675 return;
5676 }
5677 // Bail if the index is out of range.
5678 var part = this._results[index];
5679 if (!part) {
5680 return;
5681 }
5682 // Update the search text if the item is a header.
5683 if (part.type === 'header') {
5684 var input = this.inputNode;
5685 input.value = part.category.toLowerCase() + " ";
5686 input.focus();
5687 this.refresh();
5688 return;
5689 }
5690 // Bail if item is not enabled.
5691 if (!part.item.isEnabled) {
5692 return;
5693 }
5694 // Execute the item.
5695 this.commands.execute(part.item.command, part.item.args);
5696 // Clear the query text.
5697 this.inputNode.value = '';
5698 // Refresh the search results.
5699 this.refresh();
5700 };
5701 /**
5702 * Toggle the focused modifier based on the input node focus state.
5703 */
5704 CommandPalette.prototype._toggleFocused = function () {
5705 var focused = document.activeElement === this.inputNode;
5706 this.toggleClass('lm-mod-focused', focused);
5707 /* <DEPRECATED> */
5708 this.toggleClass('p-mod-focused', focused);
5709 /* </DEPRECATED> */
5710 };
5711 /**
5712 * A signal handler for generic command changes.
5713 */
5714 CommandPalette.prototype._onGenericChange = function () {
5715 this.refresh();
5716 };
5717 return CommandPalette;
5718 }(exports.Widget));
5719 /**
5720 * The namespace for the `CommandPalette` class statics.
5721 */
5722 (function (CommandPalette) {
5723 /**
5724 * The default implementation of `IRenderer`.
5725 */
5726 var Renderer = /** @class */ (function () {
5727 function Renderer() {
5728 }
5729 /**
5730 * Render the virtual element for a command palette header.
5731 *
5732 * @param data - The data to use for rendering the header.
5733 *
5734 * @returns A virtual element representing the header.
5735 */
5736 Renderer.prototype.renderHeader = function (data) {
5737 var content = this.formatHeader(data);
5738 return virtualdom.h.li({
5739 className: 'lm-CommandPalette-header' +
5740 /* <DEPRECATED> */
5741 ' p-CommandPalette-header'
5742 /* </DEPRECATED> */
5743 }, content);
5744 };
5745 /**
5746 * Render the virtual element for a command palette item.
5747 *
5748 * @param data - The data to use for rendering the item.
5749 *
5750 * @returns A virtual element representing the item.
5751 */
5752 Renderer.prototype.renderItem = function (data) {
5753 var className = this.createItemClass(data);
5754 var dataset = this.createItemDataset(data);
5755 if (data.item.isToggleable) {
5756 return virtualdom.h.li({
5757 className: className,
5758 dataset: dataset,
5759 role: 'checkbox',
5760 'aria-checked': "" + data.item.isToggled
5761 }, this.renderItemIcon(data), this.renderItemContent(data), this.renderItemShortcut(data));
5762 }
5763 return virtualdom.h.li({
5764 className: className,
5765 dataset: dataset
5766 }, this.renderItemIcon(data), this.renderItemContent(data), this.renderItemShortcut(data));
5767 };
5768 /**
5769 * Render the empty results message for a command palette.
5770 *
5771 * @param data - The data to use for rendering the message.
5772 *
5773 * @returns A virtual element representing the message.
5774 */
5775 Renderer.prototype.renderEmptyMessage = function (data) {
5776 var content = this.formatEmptyMessage(data);
5777 return virtualdom.h.li({
5778 className: 'lm-CommandPalette-emptyMessage' +
5779 /* <DEPRECATED> */
5780 ' p-CommandPalette-emptyMessage'
5781 /* </DEPRECATED> */
5782 }, content);
5783 };
5784 /**
5785 * Render the icon for a command palette item.
5786 *
5787 * @param data - The data to use for rendering the icon.
5788 *
5789 * @returns A virtual element representing the icon.
5790 */
5791 Renderer.prototype.renderItemIcon = function (data) {
5792 var className = this.createIconClass(data);
5793 /* <DEPRECATED> */
5794 if (typeof data.item.icon === 'string') {
5795 return virtualdom.h.div({ className: className }, data.item.iconLabel);
5796 }
5797 /* </DEPRECATED> */
5798 // if data.item.icon is undefined, it will be ignored
5799 return virtualdom.h.div({ className: className }, data.item.icon, data.item.iconLabel);
5800 };
5801 /**
5802 * Render the content for a command palette item.
5803 *
5804 * @param data - The data to use for rendering the content.
5805 *
5806 * @returns A virtual element representing the content.
5807 */
5808 Renderer.prototype.renderItemContent = function (data) {
5809 return virtualdom.h.div({
5810 className: 'lm-CommandPalette-itemContent' +
5811 /* <DEPRECATED> */
5812 ' p-CommandPalette-itemContent'
5813 /* </DEPRECATED> */
5814 }, this.renderItemLabel(data), this.renderItemCaption(data));
5815 };
5816 /**
5817 * Render the label for a command palette item.
5818 *
5819 * @param data - The data to use for rendering the label.
5820 *
5821 * @returns A virtual element representing the label.
5822 */
5823 Renderer.prototype.renderItemLabel = function (data) {
5824 var content = this.formatItemLabel(data);
5825 return virtualdom.h.div({
5826 className: 'lm-CommandPalette-itemLabel' +
5827 /* <DEPRECATED> */
5828 ' p-CommandPalette-itemLabel'
5829 /* </DEPRECATED> */
5830 }, content);
5831 };
5832 /**
5833 * Render the caption for a command palette item.
5834 *
5835 * @param data - The data to use for rendering the caption.
5836 *
5837 * @returns A virtual element representing the caption.
5838 */
5839 Renderer.prototype.renderItemCaption = function (data) {
5840 var content = this.formatItemCaption(data);
5841 return virtualdom.h.div({
5842 className: 'lm-CommandPalette-itemCaption' +
5843 /* <DEPRECATED> */
5844 ' p-CommandPalette-itemCaption'
5845 /* </DEPRECATED> */
5846 }, content);
5847 };
5848 /**
5849 * Render the shortcut for a command palette item.
5850 *
5851 * @param data - The data to use for rendering the shortcut.
5852 *
5853 * @returns A virtual element representing the shortcut.
5854 */
5855 Renderer.prototype.renderItemShortcut = function (data) {
5856 var content = this.formatItemShortcut(data);
5857 return virtualdom.h.div({
5858 className: 'lm-CommandPalette-itemShortcut' +
5859 /* <DEPRECATED> */
5860 ' p-CommandPalette-itemShortcut'
5861 /* </DEPRECATED> */
5862 }, content);
5863 };
5864 /**
5865 * Create the class name for the command palette item.
5866 *
5867 * @param data - The data to use for the class name.
5868 *
5869 * @returns The full class name for the command palette item.
5870 */
5871 Renderer.prototype.createItemClass = function (data) {
5872 // Set up the initial class name.
5873 var name = 'lm-CommandPalette-item';
5874 /* <DEPRECATED> */
5875 name += ' p-CommandPalette-item';
5876 /* </DEPRECATED> */
5877 // Add the boolean state classes.
5878 if (!data.item.isEnabled) {
5879 name += ' lm-mod-disabled';
5880 /* <DEPRECATED> */
5881 name += ' p-mod-disabled';
5882 /* </DEPRECATED> */
5883 }
5884 if (data.item.isToggled) {
5885 name += ' lm-mod-toggled';
5886 /* <DEPRECATED> */
5887 name += ' p-mod-toggled';
5888 /* </DEPRECATED> */
5889 }
5890 if (data.active) {
5891 name += ' lm-mod-active';
5892 /* <DEPRECATED> */
5893 name += ' p-mod-active';
5894 /* </DEPRECATED> */
5895 }
5896 // Add the extra class.
5897 var extra = data.item.className;
5898 if (extra) {
5899 name += " " + extra;
5900 }
5901 // Return the complete class name.
5902 return name;
5903 };
5904 /**
5905 * Create the dataset for the command palette item.
5906 *
5907 * @param data - The data to use for creating the dataset.
5908 *
5909 * @returns The dataset for the command palette item.
5910 */
5911 Renderer.prototype.createItemDataset = function (data) {
5912 return __assign(__assign({}, data.item.dataset), { command: data.item.command });
5913 };
5914 /**
5915 * Create the class name for the command item icon.
5916 *
5917 * @param data - The data to use for the class name.
5918 *
5919 * @returns The full class name for the item icon.
5920 */
5921 Renderer.prototype.createIconClass = function (data) {
5922 var name = 'lm-CommandPalette-itemIcon';
5923 /* <DEPRECATED> */
5924 name += ' p-CommandPalette-itemIcon';
5925 /* </DEPRECATED> */
5926 var extra = data.item.iconClass;
5927 return extra ? name + " " + extra : name;
5928 };
5929 /**
5930 * Create the render content for the header node.
5931 *
5932 * @param data - The data to use for the header content.
5933 *
5934 * @returns The content to add to the header node.
5935 */
5936 Renderer.prototype.formatHeader = function (data) {
5937 if (!data.indices || data.indices.length === 0) {
5938 return data.category;
5939 }
5940 return algorithm.StringExt.highlight(data.category, data.indices, virtualdom.h.mark);
5941 };
5942 /**
5943 * Create the render content for the empty message node.
5944 *
5945 * @param data - The data to use for the empty message content.
5946 *
5947 * @returns The content to add to the empty message node.
5948 */
5949 Renderer.prototype.formatEmptyMessage = function (data) {
5950 return "No commands found that match '" + data.query + "'";
5951 };
5952 /**
5953 * Create the render content for the item shortcut node.
5954 *
5955 * @param data - The data to use for the shortcut content.
5956 *
5957 * @returns The content to add to the shortcut node.
5958 */
5959 Renderer.prototype.formatItemShortcut = function (data) {
5960 var kb = data.item.keyBinding;
5961 return kb
5962 ? kb.keys.map(commands.CommandRegistry.formatKeystroke).join(', ')
5963 : null;
5964 };
5965 /**
5966 * Create the render content for the item label node.
5967 *
5968 * @param data - The data to use for the label content.
5969 *
5970 * @returns The content to add to the label node.
5971 */
5972 Renderer.prototype.formatItemLabel = function (data) {
5973 if (!data.indices || data.indices.length === 0) {
5974 return data.item.label;
5975 }
5976 return algorithm.StringExt.highlight(data.item.label, data.indices, virtualdom.h.mark);
5977 };
5978 /**
5979 * Create the render content for the item caption node.
5980 *
5981 * @param data - The data to use for the caption content.
5982 *
5983 * @returns The content to add to the caption node.
5984 */
5985 Renderer.prototype.formatItemCaption = function (data) {
5986 return data.item.caption;
5987 };
5988 return Renderer;
5989 }());
5990 CommandPalette.Renderer = Renderer;
5991 /**
5992 * The default `Renderer` instance.
5993 */
5994 CommandPalette.defaultRenderer = new Renderer();
5995 })(exports.CommandPalette || (exports.CommandPalette = {}));
5996 /**
5997 * The namespace for the module implementation details.
5998 */
5999 var Private$a;
6000 (function (Private) {
6001 /**
6002 * Create the DOM node for a command palette.
6003 */
6004 function createNode() {
6005 var node = document.createElement('div');
6006 var search = document.createElement('div');
6007 var wrapper = document.createElement('div');
6008 var input = document.createElement('input');
6009 var content = document.createElement('ul');
6010 var clear = document.createElement('button');
6011 search.className = 'lm-CommandPalette-search';
6012 wrapper.className = 'lm-CommandPalette-wrapper';
6013 input.className = 'lm-CommandPalette-input';
6014 clear.className = 'lm-close-icon';
6015 content.className = 'lm-CommandPalette-content';
6016 /* <DEPRECATED> */
6017 search.classList.add('p-CommandPalette-search');
6018 wrapper.classList.add('p-CommandPalette-wrapper');
6019 input.classList.add('p-CommandPalette-input');
6020 content.classList.add('p-CommandPalette-content');
6021 /* </DEPRECATED> */
6022 input.spellcheck = false;
6023 wrapper.appendChild(input);
6024 wrapper.appendChild(clear);
6025 search.appendChild(wrapper);
6026 node.appendChild(search);
6027 node.appendChild(content);
6028 return node;
6029 }
6030 Private.createNode = createNode;
6031 /**
6032 * Create a new command item from a command registry and options.
6033 */
6034 function createItem(commands, options) {
6035 return new CommandItem(commands, options);
6036 }
6037 Private.createItem = createItem;
6038 /**
6039 * Search an array of command items for fuzzy matches.
6040 */
6041 function search(items, query) {
6042 // Fuzzy match the items for the query.
6043 var scores = matchItems(items, query);
6044 // Sort the items based on their score.
6045 scores.sort(scoreCmp);
6046 // Create the results for the search.
6047 return createResults(scores);
6048 }
6049 Private.search = search;
6050 /**
6051 * Test whether a result item can be activated.
6052 */
6053 function canActivate(result) {
6054 return result.type === 'item' && result.item.isEnabled;
6055 }
6056 Private.canActivate = canActivate;
6057 /**
6058 * Normalize a category for a command item.
6059 */
6060 function normalizeCategory(category) {
6061 return category.trim().replace(/\s+/g, ' ');
6062 }
6063 /**
6064 * Normalize the query text for a fuzzy search.
6065 */
6066 function normalizeQuery(text) {
6067 return text.replace(/\s+/g, '').toLowerCase();
6068 }
6069 /**
6070 * Perform a fuzzy match on an array of command items.
6071 */
6072 function matchItems(items, query) {
6073 // Normalize the query text to lower case with no whitespace.
6074 query = normalizeQuery(query);
6075 // Create the array to hold the scores.
6076 var scores = [];
6077 // Iterate over the items and match against the query.
6078 for (var i = 0, n = items.length; i < n; ++i) {
6079 // Ignore items which are not visible.
6080 var item = items[i];
6081 if (!item.isVisible) {
6082 continue;
6083 }
6084 // If the query is empty, all items are matched by default.
6085 if (!query) {
6086 scores.push({
6087 matchType: 3 /* Default */,
6088 categoryIndices: null,
6089 labelIndices: null,
6090 score: 0,
6091 item: item
6092 });
6093 continue;
6094 }
6095 // Run the fuzzy search for the item and query.
6096 var score = fuzzySearch(item, query);
6097 // Ignore the item if it is not a match.
6098 if (!score) {
6099 continue;
6100 }
6101 // Penalize disabled items.
6102 // TODO - push disabled items all the way down in sort cmp?
6103 if (!item.isEnabled) {
6104 score.score += 1000;
6105 }
6106 // Add the score to the results.
6107 scores.push(score);
6108 }
6109 // Return the final array of scores.
6110 return scores;
6111 }
6112 /**
6113 * Perform a fuzzy search on a single command item.
6114 */
6115 function fuzzySearch(item, query) {
6116 // Create the source text to be searched.
6117 var category = item.category.toLowerCase();
6118 var label = item.label.toLowerCase();
6119 var source = category + " " + label;
6120 // Set up the match score and indices array.
6121 var score = Infinity;
6122 var indices = null;
6123 // The regex for search word boundaries
6124 var rgx = /\b\w/g;
6125 // Search the source by word boundary.
6126 // eslint-disable-next-line no-constant-condition
6127 while (true) {
6128 // Find the next word boundary in the source.
6129 var rgxMatch = rgx.exec(source);
6130 // Break if there is no more source context.
6131 if (!rgxMatch) {
6132 break;
6133 }
6134 // Run the string match on the relevant substring.
6135 var match = algorithm.StringExt.matchSumOfDeltas(source, query, rgxMatch.index);
6136 // Break if there is no match.
6137 if (!match) {
6138 break;
6139 }
6140 // Update the match if the score is better.
6141 if (match && match.score <= score) {
6142 score = match.score;
6143 indices = match.indices;
6144 }
6145 }
6146 // Bail if there was no match.
6147 if (!indices || score === Infinity) {
6148 return null;
6149 }
6150 // Compute the pivot index between category and label text.
6151 var pivot = category.length + 1;
6152 // Find the slice index to separate matched indices.
6153 var j = algorithm.ArrayExt.lowerBound(indices, pivot, function (a, b) { return a - b; });
6154 // Extract the matched category and label indices.
6155 var categoryIndices = indices.slice(0, j);
6156 var labelIndices = indices.slice(j);
6157 // Adjust the label indices for the pivot offset.
6158 for (var i = 0, n = labelIndices.length; i < n; ++i) {
6159 labelIndices[i] -= pivot;
6160 }
6161 // Handle a pure label match.
6162 if (categoryIndices.length === 0) {
6163 return {
6164 matchType: 0 /* Label */,
6165 categoryIndices: null,
6166 labelIndices: labelIndices,
6167 score: score,
6168 item: item
6169 };
6170 }
6171 // Handle a pure category match.
6172 if (labelIndices.length === 0) {
6173 return {
6174 matchType: 1 /* Category */,
6175 categoryIndices: categoryIndices,
6176 labelIndices: null,
6177 score: score,
6178 item: item
6179 };
6180 }
6181 // Handle a split match.
6182 return {
6183 matchType: 2 /* Split */,
6184 categoryIndices: categoryIndices,
6185 labelIndices: labelIndices,
6186 score: score,
6187 item: item
6188 };
6189 }
6190 /**
6191 * A sort comparison function for a match score.
6192 */
6193 function scoreCmp(a, b) {
6194 // First compare based on the match type
6195 var m1 = a.matchType - b.matchType;
6196 if (m1 !== 0) {
6197 return m1;
6198 }
6199 // Otherwise, compare based on the match score.
6200 var d1 = a.score - b.score;
6201 if (d1 !== 0) {
6202 return d1;
6203 }
6204 // Find the match index based on the match type.
6205 var i1 = 0;
6206 var i2 = 0;
6207 switch (a.matchType) {
6208 case 0 /* Label */:
6209 i1 = a.labelIndices[0];
6210 i2 = b.labelIndices[0];
6211 break;
6212 case 1 /* Category */:
6213 case 2 /* Split */:
6214 i1 = a.categoryIndices[0];
6215 i2 = b.categoryIndices[0];
6216 break;
6217 }
6218 // Compare based on the match index.
6219 if (i1 !== i2) {
6220 return i1 - i2;
6221 }
6222 // Otherwise, compare by category.
6223 var d2 = a.item.category.localeCompare(b.item.category);
6224 if (d2 !== 0) {
6225 return d2;
6226 }
6227 // Otherwise, compare by rank.
6228 var r1 = a.item.rank;
6229 var r2 = b.item.rank;
6230 if (r1 !== r2) {
6231 return r1 < r2 ? -1 : 1; // Infinity safe
6232 }
6233 // Finally, compare by label.
6234 return a.item.label.localeCompare(b.item.label);
6235 }
6236 /**
6237 * Create the results from an array of sorted scores.
6238 */
6239 function createResults(scores) {
6240 // Set up an array to track which scores have been visited.
6241 var visited = new Array(scores.length);
6242 algorithm.ArrayExt.fill(visited, false);
6243 // Set up the search results array.
6244 var results = [];
6245 // Iterate over each score in the array.
6246 for (var i = 0, n = scores.length; i < n; ++i) {
6247 // Ignore a score which has already been processed.
6248 if (visited[i]) {
6249 continue;
6250 }
6251 // Extract the current item and indices.
6252 var _a = scores[i], item = _a.item, categoryIndices = _a.categoryIndices;
6253 // Extract the category for the current item.
6254 var category = item.category;
6255 // Add the header result for the category.
6256 results.push({ type: 'header', category: category, indices: categoryIndices });
6257 // Find the rest of the scores with the same category.
6258 for (var j = i; j < n; ++j) {
6259 // Ignore a score which has already been processed.
6260 if (visited[j]) {
6261 continue;
6262 }
6263 // Extract the data for the current score.
6264 var _b = scores[j], item_1 = _b.item, labelIndices = _b.labelIndices;
6265 // Ignore an item with a different category.
6266 if (item_1.category !== category) {
6267 continue;
6268 }
6269 // Create the item result for the score.
6270 results.push({ type: 'item', item: item_1, indices: labelIndices });
6271 // Mark the score as processed.
6272 visited[j] = true;
6273 }
6274 }
6275 // Return the final results.
6276 return results;
6277 }
6278 /**
6279 * A concrete implementation of `CommandPalette.IItem`.
6280 */
6281 var CommandItem = /** @class */ (function () {
6282 /**
6283 * Construct a new command item.
6284 */
6285 function CommandItem(commands, options) {
6286 this._commands = commands;
6287 this.category = normalizeCategory(options.category);
6288 this.command = options.command;
6289 this.args = options.args || coreutils.JSONExt.emptyObject;
6290 this.rank = options.rank !== undefined ? options.rank : Infinity;
6291 }
6292 Object.defineProperty(CommandItem.prototype, "label", {
6293 /**
6294 * The display label for the command item.
6295 */
6296 get: function () {
6297 return this._commands.label(this.command, this.args);
6298 },
6299 enumerable: true,
6300 configurable: true
6301 });
6302 Object.defineProperty(CommandItem.prototype, "icon", {
6303 /**
6304 * The icon renderer for the command item.
6305 */
6306 get: function () {
6307 return this._commands.icon(this.command, this.args);
6308 },
6309 enumerable: true,
6310 configurable: true
6311 });
6312 Object.defineProperty(CommandItem.prototype, "iconClass", {
6313 /**
6314 * The icon class for the command item.
6315 */
6316 get: function () {
6317 return this._commands.iconClass(this.command, this.args);
6318 },
6319 enumerable: true,
6320 configurable: true
6321 });
6322 Object.defineProperty(CommandItem.prototype, "iconLabel", {
6323 /**
6324 * The icon label for the command item.
6325 */
6326 get: function () {
6327 return this._commands.iconLabel(this.command, this.args);
6328 },
6329 enumerable: true,
6330 configurable: true
6331 });
6332 Object.defineProperty(CommandItem.prototype, "caption", {
6333 /**
6334 * The display caption for the command item.
6335 */
6336 get: function () {
6337 return this._commands.caption(this.command, this.args);
6338 },
6339 enumerable: true,
6340 configurable: true
6341 });
6342 Object.defineProperty(CommandItem.prototype, "className", {
6343 /**
6344 * The extra class name for the command item.
6345 */
6346 get: function () {
6347 return this._commands.className(this.command, this.args);
6348 },
6349 enumerable: true,
6350 configurable: true
6351 });
6352 Object.defineProperty(CommandItem.prototype, "dataset", {
6353 /**
6354 * The dataset for the command item.
6355 */
6356 get: function () {
6357 return this._commands.dataset(this.command, this.args);
6358 },
6359 enumerable: true,
6360 configurable: true
6361 });
6362 Object.defineProperty(CommandItem.prototype, "isEnabled", {
6363 /**
6364 * Whether the command item is enabled.
6365 */
6366 get: function () {
6367 return this._commands.isEnabled(this.command, this.args);
6368 },
6369 enumerable: true,
6370 configurable: true
6371 });
6372 Object.defineProperty(CommandItem.prototype, "isToggled", {
6373 /**
6374 * Whether the command item is toggled.
6375 */
6376 get: function () {
6377 return this._commands.isToggled(this.command, this.args);
6378 },
6379 enumerable: true,
6380 configurable: true
6381 });
6382 Object.defineProperty(CommandItem.prototype, "isToggleable", {
6383 /**
6384 * Whether the command item is toggleable.
6385 */
6386 get: function () {
6387 return this._commands.isToggleable(this.command, this.args);
6388 },
6389 enumerable: true,
6390 configurable: true
6391 });
6392 Object.defineProperty(CommandItem.prototype, "isVisible", {
6393 /**
6394 * Whether the command item is visible.
6395 */
6396 get: function () {
6397 return this._commands.isVisible(this.command, this.args);
6398 },
6399 enumerable: true,
6400 configurable: true
6401 });
6402 Object.defineProperty(CommandItem.prototype, "keyBinding", {
6403 /**
6404 * The key binding for the command item.
6405 */
6406 get: function () {
6407 var _a = this, command = _a.command, args = _a.args;
6408 return (algorithm.ArrayExt.findLastValue(this._commands.keyBindings, function (kb) {
6409 return kb.command === command && coreutils.JSONExt.deepEqual(kb.args, args);
6410 }) || null);
6411 },
6412 enumerable: true,
6413 configurable: true
6414 });
6415 return CommandItem;
6416 }());
6417 })(Private$a || (Private$a = {}));
6418
6419 /**
6420 * A widget which displays items as a canonical menu.
6421 */
6422 exports.Menu = /** @class */ (function (_super) {
6423 __extends(Menu, _super);
6424 /**
6425 * Construct a new menu.
6426 *
6427 * @param options - The options for initializing the menu.
6428 */
6429 function Menu(options) {
6430 var _this = _super.call(this, { node: Private$9.createNode() }) || this;
6431 _this._childIndex = -1;
6432 _this._activeIndex = -1;
6433 _this._openTimerID = 0;
6434 _this._closeTimerID = 0;
6435 _this._items = [];
6436 _this._childMenu = null;
6437 _this._parentMenu = null;
6438 _this._aboutToClose = new signaling.Signal(_this);
6439 _this._menuRequested = new signaling.Signal(_this);
6440 _this.addClass('lm-Menu');
6441 /* <DEPRECATED> */
6442 _this.addClass('p-Menu');
6443 /* </DEPRECATED> */
6444 _this.setFlag(exports.Widget.Flag.DisallowLayout);
6445 _this.commands = options.commands;
6446 _this.renderer = options.renderer || Menu.defaultRenderer;
6447 return _this;
6448 }
6449 /**
6450 * Dispose of the resources held by the menu.
6451 */
6452 Menu.prototype.dispose = function () {
6453 this.close();
6454 this._items.length = 0;
6455 _super.prototype.dispose.call(this);
6456 };
6457 Object.defineProperty(Menu.prototype, "aboutToClose", {
6458 /**
6459 * A signal emitted just before the menu is closed.
6460 *
6461 * #### Notes
6462 * This signal is emitted when the menu receives a `'close-request'`
6463 * message, just before it removes itself from the DOM.
6464 *
6465 * This signal is not emitted if the menu is already detached from
6466 * the DOM when it receives the `'close-request'` message.
6467 */
6468 get: function () {
6469 return this._aboutToClose;
6470 },
6471 enumerable: true,
6472 configurable: true
6473 });
6474 Object.defineProperty(Menu.prototype, "menuRequested", {
6475 /**
6476 * A signal emitted when a new menu is requested by the user.
6477 *
6478 * #### Notes
6479 * This signal is emitted whenever the user presses the right or left
6480 * arrow keys, and a submenu cannot be opened or closed in response.
6481 *
6482 * This signal is useful when implementing menu bars in order to open
6483 * the next or previous menu in response to a user key press.
6484 *
6485 * This signal is only emitted for the root menu in a hierarchy.
6486 */
6487 get: function () {
6488 return this._menuRequested;
6489 },
6490 enumerable: true,
6491 configurable: true
6492 });
6493 Object.defineProperty(Menu.prototype, "parentMenu", {
6494 /**
6495 * The parent menu of the menu.
6496 *
6497 * #### Notes
6498 * This is `null` unless the menu is an open submenu.
6499 */
6500 get: function () {
6501 return this._parentMenu;
6502 },
6503 enumerable: true,
6504 configurable: true
6505 });
6506 Object.defineProperty(Menu.prototype, "childMenu", {
6507 /**
6508 * The child menu of the menu.
6509 *
6510 * #### Notes
6511 * This is `null` unless the menu has an open submenu.
6512 */
6513 get: function () {
6514 return this._childMenu;
6515 },
6516 enumerable: true,
6517 configurable: true
6518 });
6519 Object.defineProperty(Menu.prototype, "rootMenu", {
6520 /**
6521 * The root menu of the menu hierarchy.
6522 */
6523 get: function () {
6524 // eslint-disable-next-line @typescript-eslint/no-this-alias
6525 var menu = this;
6526 while (menu._parentMenu) {
6527 menu = menu._parentMenu;
6528 }
6529 return menu;
6530 },
6531 enumerable: true,
6532 configurable: true
6533 });
6534 Object.defineProperty(Menu.prototype, "leafMenu", {
6535 /**
6536 * The leaf menu of the menu hierarchy.
6537 */
6538 get: function () {
6539 // eslint-disable-next-line @typescript-eslint/no-this-alias
6540 var menu = this;
6541 while (menu._childMenu) {
6542 menu = menu._childMenu;
6543 }
6544 return menu;
6545 },
6546 enumerable: true,
6547 configurable: true
6548 });
6549 Object.defineProperty(Menu.prototype, "contentNode", {
6550 /**
6551 * The menu content node.
6552 *
6553 * #### Notes
6554 * This is the node which holds the menu item nodes.
6555 *
6556 * Modifying this node directly can lead to undefined behavior.
6557 */
6558 get: function () {
6559 return this.node.getElementsByClassName('lm-Menu-content')[0];
6560 },
6561 enumerable: true,
6562 configurable: true
6563 });
6564 Object.defineProperty(Menu.prototype, "activeItem", {
6565 /**
6566 * Get the currently active menu item.
6567 */
6568 get: function () {
6569 return this._items[this._activeIndex] || null;
6570 },
6571 /**
6572 * Set the currently active menu item.
6573 *
6574 * #### Notes
6575 * If the item cannot be activated, the item will be set to `null`.
6576 */
6577 set: function (value) {
6578 this.activeIndex = value ? this._items.indexOf(value) : -1;
6579 },
6580 enumerable: true,
6581 configurable: true
6582 });
6583 Object.defineProperty(Menu.prototype, "activeIndex", {
6584 /**
6585 * Get the index of the currently active menu item.
6586 *
6587 * #### Notes
6588 * This will be `-1` if no menu item is active.
6589 */
6590 get: function () {
6591 return this._activeIndex;
6592 },
6593 /**
6594 * Set the index of the currently active menu item.
6595 *
6596 * #### Notes
6597 * If the item cannot be activated, the index will be set to `-1`.
6598 */
6599 set: function (value) {
6600 // Adjust the value for an out of range index.
6601 if (value < 0 || value >= this._items.length) {
6602 value = -1;
6603 }
6604 // Ensure the item can be activated.
6605 if (value !== -1 && !Private$9.canActivate(this._items[value])) {
6606 value = -1;
6607 }
6608 // Bail if the index will not change.
6609 if (this._activeIndex === value) {
6610 return;
6611 }
6612 // Update the active index.
6613 this._activeIndex = value;
6614 // Make active element in focus
6615 if (this._activeIndex >= 0 &&
6616 this.contentNode.childNodes[this._activeIndex]) {
6617 this.contentNode.childNodes[this._activeIndex].focus();
6618 }
6619 // schedule an update of the items.
6620 this.update();
6621 },
6622 enumerable: true,
6623 configurable: true
6624 });
6625 Object.defineProperty(Menu.prototype, "items", {
6626 /**
6627 * A read-only array of the menu items in the menu.
6628 */
6629 get: function () {
6630 return this._items;
6631 },
6632 enumerable: true,
6633 configurable: true
6634 });
6635 /**
6636 * Activate the next selectable item in the menu.
6637 *
6638 * #### Notes
6639 * If no item is selectable, the index will be set to `-1`.
6640 */
6641 Menu.prototype.activateNextItem = function () {
6642 var n = this._items.length;
6643 var ai = this._activeIndex;
6644 var start = ai < n - 1 ? ai + 1 : 0;
6645 var stop = start === 0 ? n - 1 : start - 1;
6646 this.activeIndex = algorithm.ArrayExt.findFirstIndex(this._items, Private$9.canActivate, start, stop);
6647 };
6648 /**
6649 * Activate the previous selectable item in the menu.
6650 *
6651 * #### Notes
6652 * If no item is selectable, the index will be set to `-1`.
6653 */
6654 Menu.prototype.activatePreviousItem = function () {
6655 var n = this._items.length;
6656 var ai = this._activeIndex;
6657 var start = ai <= 0 ? n - 1 : ai - 1;
6658 var stop = start === n - 1 ? 0 : start + 1;
6659 this.activeIndex = algorithm.ArrayExt.findLastIndex(this._items, Private$9.canActivate, start, stop);
6660 };
6661 /**
6662 * Trigger the active menu item.
6663 *
6664 * #### Notes
6665 * If the active item is a submenu, it will be opened and the first
6666 * item will be activated.
6667 *
6668 * If the active item is a command, the command will be executed.
6669 *
6670 * If the menu is not attached, this is a no-op.
6671 *
6672 * If there is no active item, this is a no-op.
6673 */
6674 Menu.prototype.triggerActiveItem = function () {
6675 // Bail if the menu is not attached.
6676 if (!this.isAttached) {
6677 return;
6678 }
6679 // Bail if there is no active item.
6680 var item = this.activeItem;
6681 if (!item) {
6682 return;
6683 }
6684 // Cancel the pending timers.
6685 this._cancelOpenTimer();
6686 this._cancelCloseTimer();
6687 // If the item is a submenu, open it.
6688 if (item.type === 'submenu') {
6689 this._openChildMenu(true);
6690 return;
6691 }
6692 // Close the root menu before executing the command.
6693 this.rootMenu.close();
6694 // Execute the command for the item.
6695 var command = item.command, args = item.args;
6696 if (this.commands.isEnabled(command, args)) {
6697 this.commands.execute(command, args);
6698 }
6699 else {
6700 console.log("Command '" + command + "' is disabled.");
6701 }
6702 };
6703 /**
6704 * Add a menu item to the end of the menu.
6705 *
6706 * @param options - The options for creating the menu item.
6707 *
6708 * @returns The menu item added to the menu.
6709 */
6710 Menu.prototype.addItem = function (options) {
6711 return this.insertItem(this._items.length, options);
6712 };
6713 /**
6714 * Insert a menu item into the menu at the specified index.
6715 *
6716 * @param index - The index at which to insert the item.
6717 *
6718 * @param options - The options for creating the menu item.
6719 *
6720 * @returns The menu item added to the menu.
6721 *
6722 * #### Notes
6723 * The index will be clamped to the bounds of the items.
6724 */
6725 Menu.prototype.insertItem = function (index, options) {
6726 // Close the menu if it's attached.
6727 if (this.isAttached) {
6728 this.close();
6729 }
6730 // Reset the active index.
6731 this.activeIndex = -1;
6732 // Clamp the insert index to the array bounds.
6733 var i = Math.max(0, Math.min(index, this._items.length));
6734 // Create the item for the options.
6735 var item = Private$9.createItem(this, options);
6736 // Insert the item into the array.
6737 algorithm.ArrayExt.insert(this._items, i, item);
6738 // Schedule an update of the items.
6739 this.update();
6740 // Return the item added to the menu.
6741 return item;
6742 };
6743 /**
6744 * Remove an item from the menu.
6745 *
6746 * @param item - The item to remove from the menu.
6747 *
6748 * #### Notes
6749 * This is a no-op if the item is not in the menu.
6750 */
6751 Menu.prototype.removeItem = function (item) {
6752 this.removeItemAt(this._items.indexOf(item));
6753 };
6754 /**
6755 * Remove the item at a given index from the menu.
6756 *
6757 * @param index - The index of the item to remove.
6758 *
6759 * #### Notes
6760 * This is a no-op if the index is out of range.
6761 */
6762 Menu.prototype.removeItemAt = function (index) {
6763 // Close the menu if it's attached.
6764 if (this.isAttached) {
6765 this.close();
6766 }
6767 // Reset the active index.
6768 this.activeIndex = -1;
6769 // Remove the item from the array.
6770 var item = algorithm.ArrayExt.removeAt(this._items, index);
6771 // Bail if the index is out of range.
6772 if (!item) {
6773 return;
6774 }
6775 // Schedule an update of the items.
6776 this.update();
6777 };
6778 /**
6779 * Remove all menu items from the menu.
6780 */
6781 Menu.prototype.clearItems = function () {
6782 // Close the menu if it's attached.
6783 if (this.isAttached) {
6784 this.close();
6785 }
6786 // Reset the active index.
6787 this.activeIndex = -1;
6788 // Bail if there is nothing to remove.
6789 if (this._items.length === 0) {
6790 return;
6791 }
6792 // Clear the items.
6793 this._items.length = 0;
6794 // Schedule an update of the items.
6795 this.update();
6796 };
6797 /**
6798 * Open the menu at the specified location.
6799 *
6800 * @param x - The client X coordinate of the menu location.
6801 *
6802 * @param y - The client Y coordinate of the menu location.
6803 *
6804 * @param options - The additional options for opening the menu.
6805 *
6806 * #### Notes
6807 * The menu will be opened at the given location unless it will not
6808 * fully fit on the screen. If it will not fit, it will be adjusted
6809 * to fit naturally on the screen.
6810 *
6811 * This is a no-op if the menu is already attached to the DOM.
6812 */
6813 Menu.prototype.open = function (x, y, options) {
6814 if (options === void 0) { options = {}; }
6815 // Bail early if the menu is already attached.
6816 if (this.isAttached) {
6817 return;
6818 }
6819 // Extract the position options.
6820 var forceX = options.forceX || false;
6821 var forceY = options.forceY || false;
6822 // Open the menu as a root menu.
6823 Private$9.openRootMenu(this, x, y, forceX, forceY);
6824 // Activate the menu to accept keyboard input.
6825 this.activate();
6826 };
6827 /**
6828 * Handle the DOM events for the menu.
6829 *
6830 * @param event - The DOM event sent to the menu.
6831 *
6832 * #### Notes
6833 * This method implements the DOM `EventListener` interface and is
6834 * called in response to events on the menu's DOM nodes. It should
6835 * not be called directly by user code.
6836 */
6837 Menu.prototype.handleEvent = function (event) {
6838 switch (event.type) {
6839 case 'keydown':
6840 this._evtKeyDown(event);
6841 break;
6842 case 'mouseup':
6843 this._evtMouseUp(event);
6844 break;
6845 case 'mousemove':
6846 this._evtMouseMove(event);
6847 break;
6848 case 'mouseenter':
6849 this._evtMouseEnter(event);
6850 break;
6851 case 'mouseleave':
6852 this._evtMouseLeave(event);
6853 break;
6854 case 'mousedown':
6855 this._evtMouseDown(event);
6856 break;
6857 case 'contextmenu':
6858 event.preventDefault();
6859 event.stopPropagation();
6860 break;
6861 }
6862 };
6863 /**
6864 * A message handler invoked on a `'before-attach'` message.
6865 */
6866 Menu.prototype.onBeforeAttach = function (msg) {
6867 this.node.addEventListener('keydown', this);
6868 this.node.addEventListener('mouseup', this);
6869 this.node.addEventListener('mousemove', this);
6870 this.node.addEventListener('mouseenter', this);
6871 this.node.addEventListener('mouseleave', this);
6872 this.node.addEventListener('contextmenu', this);
6873 document.addEventListener('mousedown', this, true);
6874 };
6875 /**
6876 * A message handler invoked on an `'after-detach'` message.
6877 */
6878 Menu.prototype.onAfterDetach = function (msg) {
6879 this.node.removeEventListener('keydown', this);
6880 this.node.removeEventListener('mouseup', this);
6881 this.node.removeEventListener('mousemove', this);
6882 this.node.removeEventListener('mouseenter', this);
6883 this.node.removeEventListener('mouseleave', this);
6884 this.node.removeEventListener('contextmenu', this);
6885 document.removeEventListener('mousedown', this, true);
6886 };
6887 /**
6888 * A message handler invoked on an `'activate-request'` message.
6889 */
6890 Menu.prototype.onActivateRequest = function (msg) {
6891 if (this.isAttached) {
6892 this.node.focus();
6893 }
6894 };
6895 /**
6896 * A message handler invoked on an `'update-request'` message.
6897 */
6898 Menu.prototype.onUpdateRequest = function (msg) {
6899 var _this = this;
6900 var items = this._items;
6901 var renderer = this.renderer;
6902 var activeIndex = this._activeIndex;
6903 var collapsedFlags = Private$9.computeCollapsed(items);
6904 var content = new Array(items.length);
6905 var _loop_1 = function (i, n) {
6906 var item = items[i];
6907 var active = i === activeIndex;
6908 var collapsed = collapsedFlags[i];
6909 content[i] = renderer.renderItem({
6910 item: item,
6911 active: active,
6912 collapsed: collapsed,
6913 onfocus: function () {
6914 _this.activeIndex = i;
6915 }
6916 });
6917 };
6918 for (var i = 0, n = items.length; i < n; ++i) {
6919 _loop_1(i);
6920 }
6921 virtualdom.VirtualDOM.render(content, this.contentNode);
6922 };
6923 /**
6924 * A message handler invoked on a `'close-request'` message.
6925 */
6926 Menu.prototype.onCloseRequest = function (msg) {
6927 // Cancel the pending timers.
6928 this._cancelOpenTimer();
6929 this._cancelCloseTimer();
6930 // Reset the active index.
6931 this.activeIndex = -1;
6932 // Close any open child menu.
6933 var childMenu = this._childMenu;
6934 if (childMenu) {
6935 this._childIndex = -1;
6936 this._childMenu = null;
6937 childMenu._parentMenu = null;
6938 childMenu.close();
6939 }
6940 // Remove this menu from its parent and activate the parent.
6941 var parentMenu = this._parentMenu;
6942 if (parentMenu) {
6943 this._parentMenu = null;
6944 parentMenu._childIndex = -1;
6945 parentMenu._childMenu = null;
6946 parentMenu.activate();
6947 }
6948 // Emit the `aboutToClose` signal if the menu is attached.
6949 if (this.isAttached) {
6950 this._aboutToClose.emit(undefined);
6951 }
6952 // Finish closing the menu.
6953 _super.prototype.onCloseRequest.call(this, msg);
6954 };
6955 /**
6956 * Handle the `'keydown'` event for the menu.
6957 *
6958 * #### Notes
6959 * This listener is attached to the menu node.
6960 */
6961 Menu.prototype._evtKeyDown = function (event) {
6962 // A menu handles all keydown events.
6963 event.preventDefault();
6964 event.stopPropagation();
6965 // Fetch the key code for the event.
6966 var kc = event.keyCode;
6967 // Enter
6968 if (kc === 13) {
6969 this.triggerActiveItem();
6970 return;
6971 }
6972 // Escape
6973 if (kc === 27) {
6974 this.close();
6975 return;
6976 }
6977 // Left Arrow
6978 if (kc === 37) {
6979 if (this._parentMenu) {
6980 this.close();
6981 }
6982 else {
6983 this._menuRequested.emit('previous');
6984 }
6985 return;
6986 }
6987 // Up Arrow
6988 if (kc === 38) {
6989 this.activatePreviousItem();
6990 return;
6991 }
6992 // Right Arrow
6993 if (kc === 39) {
6994 var item = this.activeItem;
6995 if (item && item.type === 'submenu') {
6996 this.triggerActiveItem();
6997 }
6998 else {
6999 this.rootMenu._menuRequested.emit('next');
7000 }
7001 return;
7002 }
7003 // Down Arrow
7004 if (kc === 40) {
7005 this.activateNextItem();
7006 return;
7007 }
7008 // Get the pressed key character.
7009 var key = keyboard.getKeyboardLayout().keyForKeydownEvent(event);
7010 // Bail if the key is not valid.
7011 if (!key) {
7012 return;
7013 }
7014 // Search for the next best matching mnemonic item.
7015 var start = this._activeIndex + 1;
7016 var result = Private$9.findMnemonic(this._items, key, start);
7017 // Handle the requested mnemonic based on the search results.
7018 // If exactly one mnemonic is matched, that item is triggered.
7019 // Otherwise, the next mnemonic is activated if available,
7020 // followed by the auto mnemonic if available.
7021 if (result.index !== -1 && !result.multiple) {
7022 this.activeIndex = result.index;
7023 this.triggerActiveItem();
7024 }
7025 else if (result.index !== -1) {
7026 this.activeIndex = result.index;
7027 }
7028 else if (result.auto !== -1) {
7029 this.activeIndex = result.auto;
7030 }
7031 };
7032 /**
7033 * Handle the `'mouseup'` event for the menu.
7034 *
7035 * #### Notes
7036 * This listener is attached to the menu node.
7037 */
7038 Menu.prototype._evtMouseUp = function (event) {
7039 if (event.button !== 0) {
7040 return;
7041 }
7042 event.preventDefault();
7043 event.stopPropagation();
7044 this.triggerActiveItem();
7045 };
7046 /**
7047 * Handle the `'mousemove'` event for the menu.
7048 *
7049 * #### Notes
7050 * This listener is attached to the menu node.
7051 */
7052 Menu.prototype._evtMouseMove = function (event) {
7053 // Hit test the item nodes for the item under the mouse.
7054 var index = algorithm.ArrayExt.findFirstIndex(this.contentNode.children, function (node) {
7055 return domutils.ElementExt.hitTest(node, event.clientX, event.clientY);
7056 });
7057 // Bail early if the mouse is already over the active index.
7058 if (index === this._activeIndex) {
7059 return;
7060 }
7061 // Update and coerce the active index.
7062 this.activeIndex = index;
7063 index = this.activeIndex;
7064 // If the index is the current child index, cancel the timers.
7065 if (index === this._childIndex) {
7066 this._cancelOpenTimer();
7067 this._cancelCloseTimer();
7068 return;
7069 }
7070 // If a child menu is currently open, start the close timer.
7071 if (this._childIndex !== -1) {
7072 this._startCloseTimer();
7073 }
7074 // Cancel the open timer to give a full delay for opening.
7075 this._cancelOpenTimer();
7076 // Bail if the active item is not a valid submenu item.
7077 var item = this.activeItem;
7078 if (!item || item.type !== 'submenu' || !item.submenu) {
7079 return;
7080 }
7081 // Start the open timer to open the active item submenu.
7082 this._startOpenTimer();
7083 };
7084 /**
7085 * Handle the `'mouseenter'` event for the menu.
7086 *
7087 * #### Notes
7088 * This listener is attached to the menu node.
7089 */
7090 Menu.prototype._evtMouseEnter = function (event) {
7091 // Synchronize the active ancestor items.
7092 for (var menu = this._parentMenu; menu; menu = menu._parentMenu) {
7093 menu._cancelOpenTimer();
7094 menu._cancelCloseTimer();
7095 menu.activeIndex = menu._childIndex;
7096 }
7097 };
7098 /**
7099 * Handle the `'mouseleave'` event for the menu.
7100 *
7101 * #### Notes
7102 * This listener is attached to the menu node.
7103 */
7104 Menu.prototype._evtMouseLeave = function (event) {
7105 // Cancel any pending submenu opening.
7106 this._cancelOpenTimer();
7107 // If there is no open child menu, just reset the active index.
7108 if (!this._childMenu) {
7109 this.activeIndex = -1;
7110 return;
7111 }
7112 // If the mouse is over the child menu, cancel the close timer.
7113 var clientX = event.clientX, clientY = event.clientY;
7114 if (domutils.ElementExt.hitTest(this._childMenu.node, clientX, clientY)) {
7115 this._cancelCloseTimer();
7116 return;
7117 }
7118 // Otherwise, reset the active index and start the close timer.
7119 this.activeIndex = -1;
7120 this._startCloseTimer();
7121 };
7122 /**
7123 * Handle the `'mousedown'` event for the menu.
7124 *
7125 * #### Notes
7126 * This listener is attached to the document node.
7127 */
7128 Menu.prototype._evtMouseDown = function (event) {
7129 // Bail if the menu is not a root menu.
7130 if (this._parentMenu) {
7131 return;
7132 }
7133 // The mouse button which is pressed is irrelevant. If the press
7134 // is not on a menu, the entire hierarchy is closed and the event
7135 // is allowed to propagate. This allows other code to act on the
7136 // event, such as focusing the clicked element.
7137 if (Private$9.hitTestMenus(this, event.clientX, event.clientY)) {
7138 event.preventDefault();
7139 event.stopPropagation();
7140 }
7141 else {
7142 this.close();
7143 }
7144 };
7145 /**
7146 * Open the child menu at the active index immediately.
7147 *
7148 * If a different child menu is already open, it will be closed,
7149 * even if the active item is not a valid submenu.
7150 */
7151 Menu.prototype._openChildMenu = function (activateFirst) {
7152 if (activateFirst === void 0) { activateFirst = false; }
7153 // If the item is not a valid submenu, close the child menu.
7154 var item = this.activeItem;
7155 if (!item || item.type !== 'submenu' || !item.submenu) {
7156 this._closeChildMenu();
7157 return;
7158 }
7159 // Do nothing if the child menu will not change.
7160 var submenu = item.submenu;
7161 if (submenu === this._childMenu) {
7162 return;
7163 }
7164 // Ensure the current child menu is closed.
7165 this._closeChildMenu();
7166 // Update the private child state.
7167 this._childMenu = submenu;
7168 this._childIndex = this._activeIndex;
7169 // Set the parent menu reference for the child.
7170 submenu._parentMenu = this;
7171 // Ensure the menu is updated and lookup the item node.
7172 messaging.MessageLoop.sendMessage(this, exports.Widget.Msg.UpdateRequest);
7173 var itemNode = this.contentNode.children[this._activeIndex];
7174 // Open the submenu at the active node.
7175 Private$9.openSubmenu(submenu, itemNode);
7176 // Activate the first item if desired.
7177 if (activateFirst) {
7178 submenu.activeIndex = -1;
7179 submenu.activateNextItem();
7180 }
7181 // Activate the child menu.
7182 submenu.activate();
7183 };
7184 /**
7185 * Close the child menu immediately.
7186 *
7187 * This is a no-op if a child menu is not open.
7188 */
7189 Menu.prototype._closeChildMenu = function () {
7190 if (this._childMenu) {
7191 this._childMenu.close();
7192 }
7193 };
7194 /**
7195 * Start the open timer, unless it is already pending.
7196 */
7197 Menu.prototype._startOpenTimer = function () {
7198 var _this = this;
7199 if (this._openTimerID === 0) {
7200 this._openTimerID = window.setTimeout(function () {
7201 _this._openTimerID = 0;
7202 _this._openChildMenu();
7203 }, Private$9.TIMER_DELAY);
7204 }
7205 };
7206 /**
7207 * Start the close timer, unless it is already pending.
7208 */
7209 Menu.prototype._startCloseTimer = function () {
7210 var _this = this;
7211 if (this._closeTimerID === 0) {
7212 this._closeTimerID = window.setTimeout(function () {
7213 _this._closeTimerID = 0;
7214 _this._closeChildMenu();
7215 }, Private$9.TIMER_DELAY);
7216 }
7217 };
7218 /**
7219 * Cancel the open timer, if the timer is pending.
7220 */
7221 Menu.prototype._cancelOpenTimer = function () {
7222 if (this._openTimerID !== 0) {
7223 clearTimeout(this._openTimerID);
7224 this._openTimerID = 0;
7225 }
7226 };
7227 /**
7228 * Cancel the close timer, if the timer is pending.
7229 */
7230 Menu.prototype._cancelCloseTimer = function () {
7231 if (this._closeTimerID !== 0) {
7232 clearTimeout(this._closeTimerID);
7233 this._closeTimerID = 0;
7234 }
7235 };
7236 return Menu;
7237 }(exports.Widget));
7238 /**
7239 * The namespace for the `Menu` class statics.
7240 */
7241 (function (Menu) {
7242 /**
7243 * The default implementation of `IRenderer`.
7244 *
7245 * #### Notes
7246 * Subclasses are free to reimplement rendering methods as needed.
7247 */
7248 var Renderer = /** @class */ (function () {
7249 function Renderer() {
7250 }
7251 /**
7252 * Render the virtual element for a menu item.
7253 *
7254 * @param data - The data to use for rendering the item.
7255 *
7256 * @returns A virtual element representing the item.
7257 */
7258 Renderer.prototype.renderItem = function (data) {
7259 var className = this.createItemClass(data);
7260 var dataset = this.createItemDataset(data);
7261 var aria = this.createItemARIA(data);
7262 return virtualdom.h.li(__assign({ className: className,
7263 dataset: dataset, tabindex: '0', onfocus: data.onfocus }, aria), this.renderIcon(data), this.renderLabel(data), this.renderShortcut(data), this.renderSubmenu(data));
7264 };
7265 /**
7266 * Render the icon element for a menu item.
7267 *
7268 * @param data - The data to use for rendering the icon.
7269 *
7270 * @returns A virtual element representing the item icon.
7271 */
7272 Renderer.prototype.renderIcon = function (data) {
7273 var className = this.createIconClass(data);
7274 /* <DEPRECATED> */
7275 if (typeof data.item.icon === 'string') {
7276 return virtualdom.h.div({ className: className }, data.item.iconLabel);
7277 }
7278 /* </DEPRECATED> */
7279 // if data.item.icon is undefined, it will be ignored
7280 return virtualdom.h.div({ className: className }, data.item.icon, data.item.iconLabel);
7281 };
7282 /**
7283 * Render the label element for a menu item.
7284 *
7285 * @param data - The data to use for rendering the label.
7286 *
7287 * @returns A virtual element representing the item label.
7288 */
7289 Renderer.prototype.renderLabel = function (data) {
7290 var content = this.formatLabel(data);
7291 return virtualdom.h.div({
7292 className: 'lm-Menu-itemLabel' +
7293 /* <DEPRECATED> */
7294 ' p-Menu-itemLabel'
7295 /* </DEPRECATED> */
7296 }, content);
7297 };
7298 /**
7299 * Render the shortcut element for a menu item.
7300 *
7301 * @param data - The data to use for rendering the shortcut.
7302 *
7303 * @returns A virtual element representing the item shortcut.
7304 */
7305 Renderer.prototype.renderShortcut = function (data) {
7306 var content = this.formatShortcut(data);
7307 return virtualdom.h.div({
7308 className: 'lm-Menu-itemShortcut' +
7309 /* <DEPRECATED> */
7310 ' p-Menu-itemShortcut'
7311 /* </DEPRECATED> */
7312 }, content);
7313 };
7314 /**
7315 * Render the submenu icon element for a menu item.
7316 *
7317 * @param data - The data to use for rendering the submenu icon.
7318 *
7319 * @returns A virtual element representing the submenu icon.
7320 */
7321 Renderer.prototype.renderSubmenu = function (data) {
7322 return virtualdom.h.div({
7323 className: 'lm-Menu-itemSubmenuIcon' +
7324 /* <DEPRECATED> */
7325 ' p-Menu-itemSubmenuIcon'
7326 /* </DEPRECATED> */
7327 });
7328 };
7329 /**
7330 * Create the class name for the menu item.
7331 *
7332 * @param data - The data to use for the class name.
7333 *
7334 * @returns The full class name for the menu item.
7335 */
7336 Renderer.prototype.createItemClass = function (data) {
7337 // Setup the initial class name.
7338 var name = 'lm-Menu-item';
7339 /* <DEPRECATED> */
7340 name += ' p-Menu-item';
7341 /* </DEPRECATED> */
7342 // Add the boolean state classes.
7343 if (!data.item.isEnabled) {
7344 name += ' lm-mod-disabled';
7345 /* <DEPRECATED> */
7346 name += ' p-mod-disabled';
7347 /* </DEPRECATED> */
7348 }
7349 if (data.item.isToggled) {
7350 name += ' lm-mod-toggled';
7351 /* <DEPRECATED> */
7352 name += ' p-mod-toggled';
7353 /* </DEPRECATED> */
7354 }
7355 if (!data.item.isVisible) {
7356 name += ' lm-mod-hidden';
7357 /* <DEPRECATED> */
7358 name += ' p-mod-hidden';
7359 /* </DEPRECATED> */
7360 }
7361 if (data.active) {
7362 name += ' lm-mod-active';
7363 /* <DEPRECATED> */
7364 name += ' p-mod-active';
7365 /* </DEPRECATED> */
7366 }
7367 if (data.collapsed) {
7368 name += ' lm-mod-collapsed';
7369 /* <DEPRECATED> */
7370 name += ' p-mod-collapsed';
7371 /* </DEPRECATED> */
7372 }
7373 // Add the extra class.
7374 var extra = data.item.className;
7375 if (extra) {
7376 name += " " + extra;
7377 }
7378 // Return the complete class name.
7379 return name;
7380 };
7381 /**
7382 * Create the dataset for the menu item.
7383 *
7384 * @param data - The data to use for creating the dataset.
7385 *
7386 * @returns The dataset for the menu item.
7387 */
7388 Renderer.prototype.createItemDataset = function (data) {
7389 var result;
7390 var _a = data.item, type = _a.type, command = _a.command, dataset = _a.dataset;
7391 if (type === 'command') {
7392 result = __assign(__assign({}, dataset), { type: type, command: command });
7393 }
7394 else {
7395 result = __assign(__assign({}, dataset), { type: type });
7396 }
7397 return result;
7398 };
7399 /**
7400 * Create the class name for the menu item icon.
7401 *
7402 * @param data - The data to use for the class name.
7403 *
7404 * @returns The full class name for the item icon.
7405 */
7406 Renderer.prototype.createIconClass = function (data) {
7407 var name = 'lm-Menu-itemIcon';
7408 /* <DEPRECATED> */
7409 name += ' p-Menu-itemIcon';
7410 /* </DEPRECATED> */
7411 var extra = data.item.iconClass;
7412 return extra ? name + " " + extra : name;
7413 };
7414 /**
7415 * Create the aria attributes for menu item.
7416 *
7417 * @param data - The data to use for the aria attributes.
7418 *
7419 * @returns The aria attributes object for the item.
7420 */
7421 Renderer.prototype.createItemARIA = function (data) {
7422 var aria = {};
7423 switch (data.item.type) {
7424 case 'separator':
7425 aria.role = 'presentation';
7426 break;
7427 case 'submenu':
7428 aria['aria-haspopup'] = 'true';
7429 if (!data.item.isEnabled) {
7430 aria['aria-disabled'] = 'true';
7431 }
7432 break;
7433 default:
7434 if (!data.item.isEnabled) {
7435 aria['aria-disabled'] = 'true';
7436 }
7437 aria.role = 'menuitem';
7438 }
7439 return aria;
7440 };
7441 /**
7442 * Create the render content for the label node.
7443 *
7444 * @param data - The data to use for the label content.
7445 *
7446 * @returns The content to add to the label node.
7447 */
7448 Renderer.prototype.formatLabel = function (data) {
7449 // Fetch the label text and mnemonic index.
7450 var _a = data.item, label = _a.label, mnemonic = _a.mnemonic;
7451 // If the index is out of range, do not modify the label.
7452 if (mnemonic < 0 || mnemonic >= label.length) {
7453 return label;
7454 }
7455 // Split the label into parts.
7456 var prefix = label.slice(0, mnemonic);
7457 var suffix = label.slice(mnemonic + 1);
7458 var char = label[mnemonic];
7459 // Wrap the mnemonic character in a span.
7460 var span = virtualdom.h.span({
7461 className: 'lm-Menu-itemMnemonic' +
7462 /* <DEPRECATED> */
7463 ' p-Menu-itemMnemonic'
7464 /* </DEPRECATED> */
7465 }, char);
7466 // Return the content parts.
7467 return [prefix, span, suffix];
7468 };
7469 /**
7470 * Create the render content for the shortcut node.
7471 *
7472 * @param data - The data to use for the shortcut content.
7473 *
7474 * @returns The content to add to the shortcut node.
7475 */
7476 Renderer.prototype.formatShortcut = function (data) {
7477 var kb = data.item.keyBinding;
7478 return kb
7479 ? kb.keys.map(commands.CommandRegistry.formatKeystroke).join(', ')
7480 : null;
7481 };
7482 return Renderer;
7483 }());
7484 Menu.Renderer = Renderer;
7485 /**
7486 * The default `Renderer` instance.
7487 */
7488 Menu.defaultRenderer = new Renderer();
7489 })(exports.Menu || (exports.Menu = {}));
7490 /**
7491 * The namespace for the module implementation details.
7492 */
7493 var Private$9;
7494 (function (Private) {
7495 /**
7496 * The ms delay for opening and closing a submenu.
7497 */
7498 Private.TIMER_DELAY = 300;
7499 /**
7500 * The horizontal pixel overlap for an open submenu.
7501 */
7502 Private.SUBMENU_OVERLAP = 3;
7503 /**
7504 * Create the DOM node for a menu.
7505 */
7506 function createNode() {
7507 var node = document.createElement('div');
7508 var content = document.createElement('ul');
7509 content.className = 'lm-Menu-content';
7510 /* <DEPRECATED> */
7511 content.classList.add('p-Menu-content');
7512 /* </DEPRECATED> */
7513 node.appendChild(content);
7514 content.setAttribute('role', 'menu');
7515 node.tabIndex = 0;
7516 return node;
7517 }
7518 Private.createNode = createNode;
7519 /**
7520 * Test whether a menu item can be activated.
7521 */
7522 function canActivate(item) {
7523 return item.type !== 'separator' && item.isEnabled && item.isVisible;
7524 }
7525 Private.canActivate = canActivate;
7526 /**
7527 * Create a new menu item for an owner menu.
7528 */
7529 function createItem(owner, options) {
7530 return new MenuItem(owner.commands, options);
7531 }
7532 Private.createItem = createItem;
7533 /**
7534 * Hit test a menu hierarchy starting at the given root.
7535 */
7536 function hitTestMenus(menu, x, y) {
7537 for (var temp = menu; temp; temp = temp.childMenu) {
7538 if (domutils.ElementExt.hitTest(temp.node, x, y)) {
7539 return true;
7540 }
7541 }
7542 return false;
7543 }
7544 Private.hitTestMenus = hitTestMenus;
7545 /**
7546 * Compute which extra separator items should be collapsed.
7547 */
7548 function computeCollapsed(items) {
7549 // Allocate the return array and fill it with `false`.
7550 var result = new Array(items.length);
7551 algorithm.ArrayExt.fill(result, false);
7552 // Collapse the leading separators.
7553 var k1 = 0;
7554 var n = items.length;
7555 for (; k1 < n; ++k1) {
7556 var item = items[k1];
7557 if (!item.isVisible) {
7558 continue;
7559 }
7560 if (item.type !== 'separator') {
7561 break;
7562 }
7563 result[k1] = true;
7564 }
7565 // Hide the trailing separators.
7566 var k2 = n - 1;
7567 for (; k2 >= 0; --k2) {
7568 var item = items[k2];
7569 if (!item.isVisible) {
7570 continue;
7571 }
7572 if (item.type !== 'separator') {
7573 break;
7574 }
7575 result[k2] = true;
7576 }
7577 // Hide the remaining consecutive separators.
7578 var hide = false;
7579 while (++k1 < k2) {
7580 var item = items[k1];
7581 if (!item.isVisible) {
7582 continue;
7583 }
7584 if (item.type !== 'separator') {
7585 hide = false;
7586 }
7587 else if (hide) {
7588 result[k1] = true;
7589 }
7590 else {
7591 hide = true;
7592 }
7593 }
7594 // Return the resulting flags.
7595 return result;
7596 }
7597 Private.computeCollapsed = computeCollapsed;
7598 /**
7599 * Open a menu as a root menu at the target location.
7600 */
7601 function openRootMenu(menu, x, y, forceX, forceY) {
7602 // Ensure the menu is updated before attaching and measuring.
7603 messaging.MessageLoop.sendMessage(menu, exports.Widget.Msg.UpdateRequest);
7604 // Get the current position and size of the main viewport.
7605 var px = window.pageXOffset;
7606 var py = window.pageYOffset;
7607 var cw = document.documentElement.clientWidth;
7608 var ch = document.documentElement.clientHeight;
7609 // Compute the maximum allowed height for the menu.
7610 var maxHeight = ch - (forceY ? y : 0);
7611 // Fetch common variables.
7612 var node = menu.node;
7613 var style = node.style;
7614 // Clear the menu geometry and prepare it for measuring.
7615 style.top = '';
7616 style.left = '';
7617 style.width = '';
7618 style.height = '';
7619 style.visibility = 'hidden';
7620 style.maxHeight = maxHeight + "px";
7621 // Attach the menu to the document.
7622 exports.Widget.attach(menu, document.body);
7623 // Measure the size of the menu.
7624 var _a = node.getBoundingClientRect(), width = _a.width, height = _a.height;
7625 // Adjust the X position of the menu to fit on-screen.
7626 if (!forceX && x + width > px + cw) {
7627 x = px + cw - width;
7628 }
7629 // Adjust the Y position of the menu to fit on-screen.
7630 if (!forceY && y + height > py + ch) {
7631 if (y > py + ch) {
7632 y = py + ch - height;
7633 }
7634 else {
7635 y = y - height;
7636 }
7637 }
7638 // Update the position of the menu to the computed position.
7639 style.top = Math.max(0, y) + "px";
7640 style.left = Math.max(0, x) + "px";
7641 // Finally, make the menu visible on the screen.
7642 style.visibility = '';
7643 }
7644 Private.openRootMenu = openRootMenu;
7645 /**
7646 * Open a menu as a submenu using an item node for positioning.
7647 */
7648 function openSubmenu(submenu, itemNode) {
7649 // Ensure the menu is updated before opening.
7650 messaging.MessageLoop.sendMessage(submenu, exports.Widget.Msg.UpdateRequest);
7651 // Get the current position and size of the main viewport.
7652 var px = window.pageXOffset;
7653 var py = window.pageYOffset;
7654 var cw = document.documentElement.clientWidth;
7655 var ch = document.documentElement.clientHeight;
7656 // Compute the maximum allowed height for the menu.
7657 var maxHeight = ch;
7658 // Fetch common variables.
7659 var node = submenu.node;
7660 var style = node.style;
7661 // Clear the menu geometry and prepare it for measuring.
7662 style.top = '';
7663 style.left = '';
7664 style.width = '';
7665 style.height = '';
7666 style.visibility = 'hidden';
7667 style.maxHeight = maxHeight + "px";
7668 // Attach the menu to the document.
7669 exports.Widget.attach(submenu, document.body);
7670 // Measure the size of the menu.
7671 var _a = node.getBoundingClientRect(), width = _a.width, height = _a.height;
7672 // Compute the box sizing for the menu.
7673 var box = domutils.ElementExt.boxSizing(submenu.node);
7674 // Get the bounding rect for the target item node.
7675 var itemRect = itemNode.getBoundingClientRect();
7676 // Compute the target X position.
7677 var x = itemRect.right - Private.SUBMENU_OVERLAP;
7678 // Adjust the X position to fit on the screen.
7679 if (x + width > px + cw) {
7680 x = itemRect.left + Private.SUBMENU_OVERLAP - width;
7681 }
7682 // Compute the target Y position.
7683 var y = itemRect.top - box.borderTop - box.paddingTop;
7684 // Adjust the Y position to fit on the screen.
7685 if (y + height > py + ch) {
7686 y = itemRect.bottom + box.borderBottom + box.paddingBottom - height;
7687 }
7688 // Update the position of the menu to the computed position.
7689 style.top = Math.max(0, y) + "px";
7690 style.left = Math.max(0, x) + "px";
7691 // Finally, make the menu visible on the screen.
7692 style.visibility = '';
7693 }
7694 Private.openSubmenu = openSubmenu;
7695 /**
7696 * Find the best matching mnemonic item.
7697 *
7698 * The search starts at the given index and wraps around.
7699 */
7700 function findMnemonic(items, key, start) {
7701 // Setup the result variables.
7702 var index = -1;
7703 var auto = -1;
7704 var multiple = false;
7705 // Normalize the key to upper case.
7706 var upperKey = key.toUpperCase();
7707 // Search the items from the given start index.
7708 for (var i = 0, n = items.length; i < n; ++i) {
7709 // Compute the wrapped index.
7710 var k = (i + start) % n;
7711 // Lookup the item
7712 var item = items[k];
7713 // Ignore items which cannot be activated.
7714 if (!canActivate(item)) {
7715 continue;
7716 }
7717 // Ignore items with an empty label.
7718 var label = item.label;
7719 if (label.length === 0) {
7720 continue;
7721 }
7722 // Lookup the mnemonic index for the label.
7723 var mn = item.mnemonic;
7724 // Handle a valid mnemonic index.
7725 if (mn >= 0 && mn < label.length) {
7726 if (label[mn].toUpperCase() === upperKey) {
7727 if (index === -1) {
7728 index = k;
7729 }
7730 else {
7731 multiple = true;
7732 }
7733 }
7734 continue;
7735 }
7736 // Finally, handle the auto index if possible.
7737 if (auto === -1 && label[0].toUpperCase() === upperKey) {
7738 auto = k;
7739 }
7740 }
7741 // Return the search results.
7742 return { index: index, multiple: multiple, auto: auto };
7743 }
7744 Private.findMnemonic = findMnemonic;
7745 /**
7746 * A concrete implementation of `Menu.IItem`.
7747 */
7748 var MenuItem = /** @class */ (function () {
7749 /**
7750 * Construct a new menu item.
7751 */
7752 function MenuItem(commands, options) {
7753 this._commands = commands;
7754 this.type = options.type || 'command';
7755 this.command = options.command || '';
7756 this.args = options.args || coreutils.JSONExt.emptyObject;
7757 this.submenu = options.submenu || null;
7758 }
7759 Object.defineProperty(MenuItem.prototype, "label", {
7760 /**
7761 * The display label for the menu item.
7762 */
7763 get: function () {
7764 if (this.type === 'command') {
7765 return this._commands.label(this.command, this.args);
7766 }
7767 if (this.type === 'submenu' && this.submenu) {
7768 return this.submenu.title.label;
7769 }
7770 return '';
7771 },
7772 enumerable: true,
7773 configurable: true
7774 });
7775 Object.defineProperty(MenuItem.prototype, "mnemonic", {
7776 /**
7777 * The mnemonic index for the menu item.
7778 */
7779 get: function () {
7780 if (this.type === 'command') {
7781 return this._commands.mnemonic(this.command, this.args);
7782 }
7783 if (this.type === 'submenu' && this.submenu) {
7784 return this.submenu.title.mnemonic;
7785 }
7786 return -1;
7787 },
7788 enumerable: true,
7789 configurable: true
7790 });
7791 Object.defineProperty(MenuItem.prototype, "icon", {
7792 /**
7793 * The icon renderer for the menu item.
7794 */
7795 get: function () {
7796 if (this.type === 'command') {
7797 return this._commands.icon(this.command, this.args);
7798 }
7799 if (this.type === 'submenu' && this.submenu) {
7800 return this.submenu.title.icon;
7801 }
7802 /* <DEPRECATED> */
7803 // alias to icon class if not otherwise defined
7804 return this.iconClass;
7805 /* </DEPRECATED> */
7806 /* <FUTURE>
7807 return undefined;
7808 </FUTURE> */
7809 },
7810 enumerable: true,
7811 configurable: true
7812 });
7813 Object.defineProperty(MenuItem.prototype, "iconClass", {
7814 /**
7815 * The icon class for the menu item.
7816 */
7817 get: function () {
7818 if (this.type === 'command') {
7819 return this._commands.iconClass(this.command, this.args);
7820 }
7821 if (this.type === 'submenu' && this.submenu) {
7822 return this.submenu.title.iconClass;
7823 }
7824 return '';
7825 },
7826 enumerable: true,
7827 configurable: true
7828 });
7829 Object.defineProperty(MenuItem.prototype, "iconLabel", {
7830 /**
7831 * The icon label for the menu item.
7832 */
7833 get: function () {
7834 if (this.type === 'command') {
7835 return this._commands.iconLabel(this.command, this.args);
7836 }
7837 if (this.type === 'submenu' && this.submenu) {
7838 return this.submenu.title.iconLabel;
7839 }
7840 return '';
7841 },
7842 enumerable: true,
7843 configurable: true
7844 });
7845 Object.defineProperty(MenuItem.prototype, "caption", {
7846 /**
7847 * The display caption for the menu item.
7848 */
7849 get: function () {
7850 if (this.type === 'command') {
7851 return this._commands.caption(this.command, this.args);
7852 }
7853 if (this.type === 'submenu' && this.submenu) {
7854 return this.submenu.title.caption;
7855 }
7856 return '';
7857 },
7858 enumerable: true,
7859 configurable: true
7860 });
7861 Object.defineProperty(MenuItem.prototype, "className", {
7862 /**
7863 * The extra class name for the menu item.
7864 */
7865 get: function () {
7866 if (this.type === 'command') {
7867 return this._commands.className(this.command, this.args);
7868 }
7869 if (this.type === 'submenu' && this.submenu) {
7870 return this.submenu.title.className;
7871 }
7872 return '';
7873 },
7874 enumerable: true,
7875 configurable: true
7876 });
7877 Object.defineProperty(MenuItem.prototype, "dataset", {
7878 /**
7879 * The dataset for the menu item.
7880 */
7881 get: function () {
7882 if (this.type === 'command') {
7883 return this._commands.dataset(this.command, this.args);
7884 }
7885 if (this.type === 'submenu' && this.submenu) {
7886 return this.submenu.title.dataset;
7887 }
7888 return {};
7889 },
7890 enumerable: true,
7891 configurable: true
7892 });
7893 Object.defineProperty(MenuItem.prototype, "isEnabled", {
7894 /**
7895 * Whether the menu item is enabled.
7896 */
7897 get: function () {
7898 if (this.type === 'command') {
7899 return this._commands.isEnabled(this.command, this.args);
7900 }
7901 if (this.type === 'submenu') {
7902 return this.submenu !== null;
7903 }
7904 return true;
7905 },
7906 enumerable: true,
7907 configurable: true
7908 });
7909 Object.defineProperty(MenuItem.prototype, "isToggled", {
7910 /**
7911 * Whether the menu item is toggled.
7912 */
7913 get: function () {
7914 if (this.type === 'command') {
7915 return this._commands.isToggled(this.command, this.args);
7916 }
7917 return false;
7918 },
7919 enumerable: true,
7920 configurable: true
7921 });
7922 Object.defineProperty(MenuItem.prototype, "isVisible", {
7923 /**
7924 * Whether the menu item is visible.
7925 */
7926 get: function () {
7927 if (this.type === 'command') {
7928 return this._commands.isVisible(this.command, this.args);
7929 }
7930 if (this.type === 'submenu') {
7931 return this.submenu !== null;
7932 }
7933 return true;
7934 },
7935 enumerable: true,
7936 configurable: true
7937 });
7938 Object.defineProperty(MenuItem.prototype, "keyBinding", {
7939 /**
7940 * The key binding for the menu item.
7941 */
7942 get: function () {
7943 if (this.type === 'command') {
7944 var _a = this, command_1 = _a.command, args_1 = _a.args;
7945 return (algorithm.ArrayExt.findLastValue(this._commands.keyBindings, function (kb) {
7946 return kb.command === command_1 && coreutils.JSONExt.deepEqual(kb.args, args_1);
7947 }) || null);
7948 }
7949 return null;
7950 },
7951 enumerable: true,
7952 configurable: true
7953 });
7954 return MenuItem;
7955 }());
7956 })(Private$9 || (Private$9 = {}));
7957
7958 /**
7959 * An object which implements a universal context menu.
7960 *
7961 * #### Notes
7962 * The items shown in the context menu are determined by CSS selector
7963 * matching against the DOM hierarchy at the site of the mouse click.
7964 * This is similar in concept to how keyboard shortcuts are matched
7965 * in the command registry.
7966 */
7967 var ContextMenu = /** @class */ (function () {
7968 /**
7969 * Construct a new context menu.
7970 *
7971 * @param options - The options for initializing the menu.
7972 */
7973 function ContextMenu(options) {
7974 this._groupByTarget = true;
7975 this._idTick = 0;
7976 this._items = [];
7977 this._sortBySelector = true;
7978 var groupByTarget = options.groupByTarget, sortBySelector = options.sortBySelector, others = __rest(options, ["groupByTarget", "sortBySelector"]);
7979 this.menu = new exports.Menu(others);
7980 this._groupByTarget = groupByTarget !== false;
7981 this._sortBySelector = sortBySelector !== false;
7982 }
7983 /**
7984 * Add an item to the context menu.
7985 *
7986 * @param options - The options for creating the item.
7987 *
7988 * @returns A disposable which will remove the item from the menu.
7989 */
7990 ContextMenu.prototype.addItem = function (options) {
7991 var _this = this;
7992 // Create an item from the given options.
7993 var item = Private$8.createItem(options, this._idTick++);
7994 // Add the item to the internal array.
7995 this._items.push(item);
7996 // Return a disposable which will remove the item.
7997 return new disposable.DisposableDelegate(function () {
7998 algorithm.ArrayExt.removeFirstOf(_this._items, item);
7999 });
8000 };
8001 /**
8002 * Open the context menu in response to a `'contextmenu'` event.
8003 *
8004 * @param event - The `'contextmenu'` event of interest.
8005 *
8006 * @returns `true` if the menu was opened, or `false` if no items
8007 * matched the event and the menu was not opened.
8008 *
8009 * #### Notes
8010 * This method will populate the context menu with items which match
8011 * the propagation path of the event, then open the menu at the mouse
8012 * position indicated by the event.
8013 */
8014 ContextMenu.prototype.open = function (event) {
8015 var _this = this;
8016 // Clear the current contents of the context menu.
8017 this.menu.clearItems();
8018 // Bail early if there are no items to match.
8019 if (this._items.length === 0) {
8020 return false;
8021 }
8022 // Find the matching items for the event.
8023 var items = Private$8.matchItems(this._items, event, this._groupByTarget, this._sortBySelector);
8024 // Bail if there are no matching items.
8025 if (!items || items.length === 0) {
8026 return false;
8027 }
8028 // Add the filtered items to the menu.
8029 algorithm.each(items, function (item) {
8030 _this.menu.addItem(item);
8031 });
8032 // Open the context menu at the current mouse position.
8033 this.menu.open(event.clientX, event.clientY);
8034 // Indicate success.
8035 return true;
8036 };
8037 return ContextMenu;
8038 }());
8039 /**
8040 * The namespace for the module implementation details.
8041 */
8042 var Private$8;
8043 (function (Private) {
8044 /**
8045 * Create a normalized context menu item from an options object.
8046 */
8047 function createItem(options, id) {
8048 var selector = validateSelector(options.selector);
8049 var rank = options.rank !== undefined ? options.rank : Infinity;
8050 return __assign(__assign({}, options), { selector: selector, rank: rank, id: id });
8051 }
8052 Private.createItem = createItem;
8053 /**
8054 * Find the items which match a context menu event.
8055 *
8056 * The results are sorted by DOM level, specificity, and rank.
8057 */
8058 function matchItems(items, event, groupByTarget, sortBySelector) {
8059 // Look up the target of the event.
8060 var target = event.target;
8061 // Bail if there is no target.
8062 if (!target) {
8063 return null;
8064 }
8065 // Look up the current target of the event.
8066 var currentTarget = event.currentTarget;
8067 // Bail if there is no current target.
8068 if (!currentTarget) {
8069 return null;
8070 }
8071 // There are some third party libraries that cause the `target` to
8072 // be detached from the DOM before lumino can process the event.
8073 // If that happens, search for a new target node by point. If that
8074 // node is still dangling, bail.
8075 if (!currentTarget.contains(target)) {
8076 target = document.elementFromPoint(event.clientX, event.clientY);
8077 if (!target || !currentTarget.contains(target)) {
8078 return null;
8079 }
8080 }
8081 // Set up the result array.
8082 var result = [];
8083 // Copy the items array to allow in-place modification.
8084 var availableItems = items.slice();
8085 // Walk up the DOM hierarchy searching for matches.
8086 while (target !== null) {
8087 // Set up the match array for this DOM level.
8088 var matches = [];
8089 // Search the remaining items for matches.
8090 for (var i = 0, n = availableItems.length; i < n; ++i) {
8091 // Fetch the item.
8092 var item = availableItems[i];
8093 // Skip items which are already consumed.
8094 if (!item) {
8095 continue;
8096 }
8097 // Skip items which do not match the element.
8098 if (!domutils.Selector.matches(target, item.selector)) {
8099 continue;
8100 }
8101 // Add the matched item to the result for this DOM level.
8102 matches.push(item);
8103 // Mark the item as consumed.
8104 availableItems[i] = null;
8105 }
8106 // Sort the matches for this level and add them to the results.
8107 if (matches.length !== 0) {
8108 if (groupByTarget) {
8109 matches.sort(sortBySelector ? itemCmp : itemCmpRank);
8110 }
8111 result.push.apply(result, matches);
8112 }
8113 // Stop searching at the limits of the DOM range.
8114 if (target === currentTarget) {
8115 break;
8116 }
8117 // Step to the parent DOM level.
8118 target = target.parentElement;
8119 }
8120 if (!groupByTarget) {
8121 result.sort(sortBySelector ? itemCmp : itemCmpRank);
8122 }
8123 // Return the matched and sorted results.
8124 return result;
8125 }
8126 Private.matchItems = matchItems;
8127 /**
8128 * Validate the selector for a menu item.
8129 *
8130 * This returns the validated selector, or throws if the selector is
8131 * invalid or contains commas.
8132 */
8133 function validateSelector(selector) {
8134 if (selector.indexOf(',') !== -1) {
8135 throw new Error("Selector cannot contain commas: " + selector);
8136 }
8137 if (!domutils.Selector.isValid(selector)) {
8138 throw new Error("Invalid selector: " + selector);
8139 }
8140 return selector;
8141 }
8142 /**
8143 * A sort comparison function for a context menu item by ranks.
8144 */
8145 function itemCmpRank(a, b) {
8146 // Sort based on rank.
8147 var r1 = a.rank;
8148 var r2 = b.rank;
8149 if (r1 !== r2) {
8150 return r1 < r2 ? -1 : 1; // Infinity-safe
8151 }
8152 // When all else fails, sort by item id.
8153 return a.id - b.id;
8154 }
8155 /**
8156 * A sort comparison function for a context menu item by selectors and ranks.
8157 */
8158 function itemCmp(a, b) {
8159 // Sort first based on selector specificity.
8160 var s1 = domutils.Selector.calculateSpecificity(a.selector);
8161 var s2 = domutils.Selector.calculateSpecificity(b.selector);
8162 if (s1 !== s2) {
8163 return s2 - s1;
8164 }
8165 // If specificities are equal
8166 return itemCmpRank(a, b);
8167 }
8168 })(Private$8 || (Private$8 = {}));
8169
8170 /**
8171 * A widget which displays titles as a single row or column of tabs.
8172 *
8173 * #### Notes
8174 * If CSS transforms are used to rotate nodes for vertically oriented
8175 * text, then tab dragging will not work correctly. The `tabsMovable`
8176 * property should be set to `false` when rotating nodes from CSS.
8177 */
8178 exports.TabBar = /** @class */ (function (_super) {
8179 __extends(TabBar, _super);
8180 /**
8181 * Construct a new tab bar.
8182 *
8183 * @param options - The options for initializing the tab bar.
8184 */
8185 function TabBar(options) {
8186 if (options === void 0) { options = {}; }
8187 var _this = _super.call(this, { node: Private$7.createNode() }) || this;
8188 _this._currentIndex = -1;
8189 _this._titles = [];
8190 _this._titlesEditable = false;
8191 _this._previousTitle = null;
8192 _this._dragData = null;
8193 _this._addButtonEnabled = false;
8194 _this._tabMoved = new signaling.Signal(_this);
8195 _this._currentChanged = new signaling.Signal(_this);
8196 _this._addRequested = new signaling.Signal(_this);
8197 _this._tabCloseRequested = new signaling.Signal(_this);
8198 _this._tabDetachRequested = new signaling.Signal(_this);
8199 _this._tabActivateRequested = new signaling.Signal(_this);
8200 _this.addClass('lm-TabBar');
8201 /* <DEPRECATED> */
8202 _this.addClass('p-TabBar');
8203 /* </DEPRECATED> */
8204 _this.contentNode.setAttribute('role', 'tablist');
8205 _this.setFlag(exports.Widget.Flag.DisallowLayout);
8206 _this._document = options.document || document;
8207 _this.tabsMovable = options.tabsMovable || false;
8208 _this.titlesEditable = options.titlesEditable || false;
8209 _this.allowDeselect = options.allowDeselect || false;
8210 _this.addButtonEnabled = options.addButtonEnabled || false;
8211 _this.insertBehavior = options.insertBehavior || 'select-tab-if-needed';
8212 _this.name = options.name || '';
8213 _this.orientation = options.orientation || 'horizontal';
8214 _this.removeBehavior = options.removeBehavior || 'select-tab-after';
8215 _this.renderer = options.renderer || TabBar.defaultRenderer;
8216 return _this;
8217 }
8218 /**
8219 * Dispose of the resources held by the widget.
8220 */
8221 TabBar.prototype.dispose = function () {
8222 this._releaseMouse();
8223 this._titles.length = 0;
8224 this._previousTitle = null;
8225 _super.prototype.dispose.call(this);
8226 };
8227 Object.defineProperty(TabBar.prototype, "currentChanged", {
8228 /**
8229 * A signal emitted when the current tab is changed.
8230 *
8231 * #### Notes
8232 * This signal is emitted when the currently selected tab is changed
8233 * either through user or programmatic interaction.
8234 *
8235 * Notably, this signal is not emitted when the index of the current
8236 * tab changes due to tabs being inserted, removed, or moved. It is
8237 * only emitted when the actual current tab node is changed.
8238 */
8239 get: function () {
8240 return this._currentChanged;
8241 },
8242 enumerable: true,
8243 configurable: true
8244 });
8245 Object.defineProperty(TabBar.prototype, "tabMoved", {
8246 /**
8247 * A signal emitted when a tab is moved by the user.
8248 *
8249 * #### Notes
8250 * This signal is emitted when a tab is moved by user interaction.
8251 *
8252 * This signal is not emitted when a tab is moved programmatically.
8253 */
8254 get: function () {
8255 return this._tabMoved;
8256 },
8257 enumerable: true,
8258 configurable: true
8259 });
8260 Object.defineProperty(TabBar.prototype, "tabActivateRequested", {
8261 /**
8262 * A signal emitted when a tab is clicked by the user.
8263 *
8264 * #### Notes
8265 * If the clicked tab is not the current tab, the clicked tab will be
8266 * made current and the `currentChanged` signal will be emitted first.
8267 *
8268 * This signal is emitted even if the clicked tab is the current tab.
8269 */
8270 get: function () {
8271 return this._tabActivateRequested;
8272 },
8273 enumerable: true,
8274 configurable: true
8275 });
8276 Object.defineProperty(TabBar.prototype, "addRequested", {
8277 /**
8278 * A signal emitted when the tab bar add button is clicked.
8279 */
8280 get: function () {
8281 return this._addRequested;
8282 },
8283 enumerable: true,
8284 configurable: true
8285 });
8286 Object.defineProperty(TabBar.prototype, "tabCloseRequested", {
8287 /**
8288 * A signal emitted when a tab close icon is clicked.
8289 *
8290 * #### Notes
8291 * This signal is not emitted unless the tab title is `closable`.
8292 */
8293 get: function () {
8294 return this._tabCloseRequested;
8295 },
8296 enumerable: true,
8297 configurable: true
8298 });
8299 Object.defineProperty(TabBar.prototype, "tabDetachRequested", {
8300 /**
8301 * A signal emitted when a tab is dragged beyond the detach threshold.
8302 *
8303 * #### Notes
8304 * This signal is emitted when the user drags a tab with the mouse,
8305 * and mouse is dragged beyond the detach threshold.
8306 *
8307 * The consumer of the signal should call `releaseMouse` and remove
8308 * the tab in order to complete the detach.
8309 *
8310 * This signal is only emitted once per drag cycle.
8311 */
8312 get: function () {
8313 return this._tabDetachRequested;
8314 },
8315 enumerable: true,
8316 configurable: true
8317 });
8318 Object.defineProperty(TabBar.prototype, "document", {
8319 /**
8320 * The document to use with the tab bar.
8321 *
8322 * The default is the global `document` instance.
8323 */
8324 get: function () {
8325 return this._document;
8326 },
8327 enumerable: true,
8328 configurable: true
8329 });
8330 Object.defineProperty(TabBar.prototype, "titlesEditable", {
8331 /**
8332 * Whether the titles can be user-edited.
8333 *
8334 */
8335 get: function () {
8336 return this._titlesEditable;
8337 },
8338 /**
8339 * Set whether titles can be user edited.
8340 *
8341 */
8342 set: function (value) {
8343 this._titlesEditable = value;
8344 },
8345 enumerable: true,
8346 configurable: true
8347 });
8348 Object.defineProperty(TabBar.prototype, "currentTitle", {
8349 /**
8350 * Get the currently selected title.
8351 *
8352 * #### Notes
8353 * This will be `null` if no tab is selected.
8354 */
8355 get: function () {
8356 return this._titles[this._currentIndex] || null;
8357 },
8358 /**
8359 * Set the currently selected title.
8360 *
8361 * #### Notes
8362 * If the title does not exist, the title will be set to `null`.
8363 */
8364 set: function (value) {
8365 this.currentIndex = value ? this._titles.indexOf(value) : -1;
8366 },
8367 enumerable: true,
8368 configurable: true
8369 });
8370 Object.defineProperty(TabBar.prototype, "currentIndex", {
8371 /**
8372 * Get the index of the currently selected tab.
8373 *
8374 * #### Notes
8375 * This will be `-1` if no tab is selected.
8376 */
8377 get: function () {
8378 return this._currentIndex;
8379 },
8380 /**
8381 * Set the index of the currently selected tab.
8382 *
8383 * #### Notes
8384 * If the value is out of range, the index will be set to `-1`.
8385 */
8386 set: function (value) {
8387 // Adjust for an out of range index.
8388 if (value < 0 || value >= this._titles.length) {
8389 value = -1;
8390 }
8391 // Bail early if the index will not change.
8392 if (this._currentIndex === value) {
8393 return;
8394 }
8395 // Look up the previous index and title.
8396 var pi = this._currentIndex;
8397 var pt = this._titles[pi] || null;
8398 // Look up the current index and title.
8399 var ci = value;
8400 var ct = this._titles[ci] || null;
8401 // Update the current index and previous title.
8402 this._currentIndex = ci;
8403 this._previousTitle = pt;
8404 // Schedule an update of the tabs.
8405 this.update();
8406 // Emit the current changed signal.
8407 this._currentChanged.emit({
8408 previousIndex: pi,
8409 previousTitle: pt,
8410 currentIndex: ci,
8411 currentTitle: ct
8412 });
8413 },
8414 enumerable: true,
8415 configurable: true
8416 });
8417 Object.defineProperty(TabBar.prototype, "name", {
8418 /**
8419 * Get the name of the tab bar.
8420 */
8421 get: function () {
8422 return this._name;
8423 },
8424 /**
8425 * Set the name of the tab bar.
8426 */
8427 set: function (value) {
8428 this._name = value;
8429 if (value) {
8430 this.contentNode.setAttribute('aria-label', value);
8431 }
8432 else {
8433 this.contentNode.removeAttribute('aria-label');
8434 }
8435 },
8436 enumerable: true,
8437 configurable: true
8438 });
8439 Object.defineProperty(TabBar.prototype, "orientation", {
8440 /**
8441 * Get the orientation of the tab bar.
8442 *
8443 * #### Notes
8444 * This controls whether the tabs are arranged in a row or column.
8445 */
8446 get: function () {
8447 return this._orientation;
8448 },
8449 /**
8450 * Set the orientation of the tab bar.
8451 *
8452 * #### Notes
8453 * This controls whether the tabs are arranged in a row or column.
8454 */
8455 set: function (value) {
8456 // Do nothing if the orientation does not change.
8457 if (this._orientation === value) {
8458 return;
8459 }
8460 // Release the mouse before making any changes.
8461 this._releaseMouse();
8462 // Toggle the orientation values.
8463 this._orientation = value;
8464 this.dataset['orientation'] = value;
8465 this.contentNode.setAttribute('aria-orientation', value);
8466 },
8467 enumerable: true,
8468 configurable: true
8469 });
8470 Object.defineProperty(TabBar.prototype, "addButtonEnabled", {
8471 /**
8472 * Whether the add button is enabled.
8473 */
8474 get: function () {
8475 return this._addButtonEnabled;
8476 },
8477 /**
8478 * Set whether the add button is enabled.
8479 */
8480 set: function (value) {
8481 // Do nothing if the value does not change.
8482 if (this._addButtonEnabled === value) {
8483 return;
8484 }
8485 this._addButtonEnabled = value;
8486 if (value) {
8487 this.addButtonNode.classList.remove('lm-mod-hidden');
8488 }
8489 else {
8490 this.addButtonNode.classList.add('lm-mod-hidden');
8491 }
8492 },
8493 enumerable: true,
8494 configurable: true
8495 });
8496 Object.defineProperty(TabBar.prototype, "titles", {
8497 /**
8498 * A read-only array of the titles in the tab bar.
8499 */
8500 get: function () {
8501 return this._titles;
8502 },
8503 enumerable: true,
8504 configurable: true
8505 });
8506 Object.defineProperty(TabBar.prototype, "contentNode", {
8507 /**
8508 * The tab bar content node.
8509 *
8510 * #### Notes
8511 * This is the node which holds the tab nodes.
8512 *
8513 * Modifying this node directly can lead to undefined behavior.
8514 */
8515 get: function () {
8516 return this.node.getElementsByClassName('lm-TabBar-content')[0];
8517 },
8518 enumerable: true,
8519 configurable: true
8520 });
8521 Object.defineProperty(TabBar.prototype, "addButtonNode", {
8522 /**
8523 * The tab bar add button node.
8524 *
8525 * #### Notes
8526 * This is the node which holds the add button.
8527 *
8528 * Modifying this node directly can lead to undefined behavior.
8529 */
8530 get: function () {
8531 return this.node.getElementsByClassName('lm-TabBar-addButton')[0];
8532 },
8533 enumerable: true,
8534 configurable: true
8535 });
8536 /**
8537 * Add a tab to the end of the tab bar.
8538 *
8539 * @param value - The title which holds the data for the tab,
8540 * or an options object to convert to a title.
8541 *
8542 * @returns The title object added to the tab bar.
8543 *
8544 * #### Notes
8545 * If the title is already added to the tab bar, it will be moved.
8546 */
8547 TabBar.prototype.addTab = function (value) {
8548 return this.insertTab(this._titles.length, value);
8549 };
8550 /**
8551 * Insert a tab into the tab bar at the specified index.
8552 *
8553 * @param index - The index at which to insert the tab.
8554 *
8555 * @param value - The title which holds the data for the tab,
8556 * or an options object to convert to a title.
8557 *
8558 * @returns The title object added to the tab bar.
8559 *
8560 * #### Notes
8561 * The index will be clamped to the bounds of the tabs.
8562 *
8563 * If the title is already added to the tab bar, it will be moved.
8564 */
8565 TabBar.prototype.insertTab = function (index, value) {
8566 // Release the mouse before making any changes.
8567 this._releaseMouse();
8568 // Coerce the value to a title.
8569 var title = Private$7.asTitle(value);
8570 // Look up the index of the title.
8571 var i = this._titles.indexOf(title);
8572 // Clamp the insert index to the array bounds.
8573 var j = Math.max(0, Math.min(index, this._titles.length));
8574 // If the title is not in the array, insert it.
8575 if (i === -1) {
8576 // Insert the title into the array.
8577 algorithm.ArrayExt.insert(this._titles, j, title);
8578 // Connect to the title changed signal.
8579 title.changed.connect(this._onTitleChanged, this);
8580 // Schedule an update of the tabs.
8581 this.update();
8582 // Adjust the current index for the insert.
8583 this._adjustCurrentForInsert(j, title);
8584 // Return the title added to the tab bar.
8585 return title;
8586 }
8587 // Otherwise, the title exists in the array and should be moved.
8588 // Adjust the index if the location is at the end of the array.
8589 if (j === this._titles.length) {
8590 j--;
8591 }
8592 // Bail if there is no effective move.
8593 if (i === j) {
8594 return title;
8595 }
8596 // Move the title to the new location.
8597 algorithm.ArrayExt.move(this._titles, i, j);
8598 // Schedule an update of the tabs.
8599 this.update();
8600 // Adjust the current index for the move.
8601 this._adjustCurrentForMove(i, j);
8602 // Return the title added to the tab bar.
8603 return title;
8604 };
8605 /**
8606 * Remove a tab from the tab bar.
8607 *
8608 * @param title - The title for the tab to remove.
8609 *
8610 * #### Notes
8611 * This is a no-op if the title is not in the tab bar.
8612 */
8613 TabBar.prototype.removeTab = function (title) {
8614 this.removeTabAt(this._titles.indexOf(title));
8615 };
8616 /**
8617 * Remove the tab at a given index from the tab bar.
8618 *
8619 * @param index - The index of the tab to remove.
8620 *
8621 * #### Notes
8622 * This is a no-op if the index is out of range.
8623 */
8624 TabBar.prototype.removeTabAt = function (index) {
8625 // Release the mouse before making any changes.
8626 this._releaseMouse();
8627 // Remove the title from the array.
8628 var title = algorithm.ArrayExt.removeAt(this._titles, index);
8629 // Bail if the index is out of range.
8630 if (!title) {
8631 return;
8632 }
8633 // Disconnect from the title changed signal.
8634 title.changed.disconnect(this._onTitleChanged, this);
8635 // Clear the previous title if it's being removed.
8636 if (title === this._previousTitle) {
8637 this._previousTitle = null;
8638 }
8639 // Schedule an update of the tabs.
8640 this.update();
8641 // Adjust the current index for the remove.
8642 this._adjustCurrentForRemove(index, title);
8643 };
8644 /**
8645 * Remove all tabs from the tab bar.
8646 */
8647 TabBar.prototype.clearTabs = function () {
8648 // Bail if there is nothing to remove.
8649 if (this._titles.length === 0) {
8650 return;
8651 }
8652 // Release the mouse before making any changes.
8653 this._releaseMouse();
8654 // Disconnect from the title changed signals.
8655 for (var _i = 0, _a = this._titles; _i < _a.length; _i++) {
8656 var title = _a[_i];
8657 title.changed.disconnect(this._onTitleChanged, this);
8658 }
8659 // Get the current index and title.
8660 var pi = this.currentIndex;
8661 var pt = this.currentTitle;
8662 // Reset the current index and previous title.
8663 this._currentIndex = -1;
8664 this._previousTitle = null;
8665 // Clear the title array.
8666 this._titles.length = 0;
8667 // Schedule an update of the tabs.
8668 this.update();
8669 // If no tab was selected, there's nothing else to do.
8670 if (pi === -1) {
8671 return;
8672 }
8673 // Emit the current changed signal.
8674 this._currentChanged.emit({
8675 previousIndex: pi,
8676 previousTitle: pt,
8677 currentIndex: -1,
8678 currentTitle: null
8679 });
8680 };
8681 /**
8682 * Release the mouse and restore the non-dragged tab positions.
8683 *
8684 * #### Notes
8685 * This will cause the tab bar to stop handling mouse events and to
8686 * restore the tabs to their non-dragged positions.
8687 */
8688 TabBar.prototype.releaseMouse = function () {
8689 this._releaseMouse();
8690 };
8691 /**
8692 * Handle the DOM events for the tab bar.
8693 *
8694 * @param event - The DOM event sent to the tab bar.
8695 *
8696 * #### Notes
8697 * This method implements the DOM `EventListener` interface and is
8698 * called in response to events on the tab bar's DOM node.
8699 *
8700 * This should not be called directly by user code.
8701 */
8702 TabBar.prototype.handleEvent = function (event) {
8703 switch (event.type) {
8704 case 'mousedown': // <DEPRECATED>
8705 this._evtMouseDown(event);
8706 break;
8707 case 'mousemove': // <DEPRECATED>
8708 this._evtMouseMove(event);
8709 break;
8710 case 'mouseup': // <DEPRECATED>
8711 this._evtMouseUp(event);
8712 break;
8713 case 'pointerdown':
8714 this._evtMouseDown(event);
8715 break;
8716 case 'pointermove':
8717 this._evtMouseMove(event);
8718 break;
8719 case 'pointerup':
8720 this._evtMouseUp(event);
8721 break;
8722 case 'dblclick':
8723 this._evtDblClick(event);
8724 break;
8725 case 'keydown':
8726 this._evtKeyDown(event);
8727 break;
8728 case 'contextmenu':
8729 event.preventDefault();
8730 event.stopPropagation();
8731 break;
8732 }
8733 };
8734 /**
8735 * A message handler invoked on a `'before-attach'` message.
8736 */
8737 TabBar.prototype.onBeforeAttach = function (msg) {
8738 this.node.addEventListener('mousedown', this); // <DEPRECATED>
8739 this.node.addEventListener('pointerdown', this);
8740 this.node.addEventListener('dblclick', this);
8741 };
8742 /**
8743 * A message handler invoked on an `'after-detach'` message.
8744 */
8745 TabBar.prototype.onAfterDetach = function (msg) {
8746 this.node.removeEventListener('mousedown', this); // <DEPRECATED>
8747 this.node.removeEventListener('pointerdown', this);
8748 this.node.removeEventListener('dblclick', this);
8749 this._releaseMouse();
8750 };
8751 /**
8752 * A message handler invoked on an `'update-request'` message.
8753 */
8754 TabBar.prototype.onUpdateRequest = function (msg) {
8755 var titles = this._titles;
8756 var renderer = this.renderer;
8757 var currentTitle = this.currentTitle;
8758 var content = new Array(titles.length);
8759 for (var i = 0, n = titles.length; i < n; ++i) {
8760 var title = titles[i];
8761 var current = title === currentTitle;
8762 var zIndex = current ? n : n - i - 1;
8763 content[i] = renderer.renderTab({ title: title, current: current, zIndex: zIndex });
8764 }
8765 virtualdom.VirtualDOM.render(content, this.contentNode);
8766 };
8767 /**
8768 * Handle the `'dblclick'` event for the tab bar.
8769 */
8770 TabBar.prototype._evtDblClick = function (event) {
8771 // Do nothing if titles are not editable
8772 if (!this.titlesEditable) {
8773 return;
8774 }
8775 var tabs = this.contentNode.children;
8776 // Find the index of the released tab.
8777 var index = algorithm.ArrayExt.findFirstIndex(tabs, function (tab) {
8778 return domutils.ElementExt.hitTest(tab, event.clientX, event.clientY);
8779 });
8780 // Do nothing if the press is not on a tab.
8781 if (index === -1) {
8782 return;
8783 }
8784 var title = this.titles[index];
8785 var label = tabs[index].querySelector('.lm-TabBar-tabLabel');
8786 if (label && label.contains(event.target)) {
8787 var value = title.label || '';
8788 // Clear the label element
8789 var oldValue_1 = label.innerHTML;
8790 label.innerHTML = '';
8791 var input_1 = document.createElement('input');
8792 input_1.classList.add('lm-TabBar-tabInput');
8793 input_1.value = value;
8794 label.appendChild(input_1);
8795 var onblur_1 = function () {
8796 input_1.removeEventListener('blur', onblur_1);
8797 label.innerHTML = oldValue_1;
8798 };
8799 input_1.addEventListener('dblclick', function (event) {
8800 return event.stopPropagation();
8801 });
8802 input_1.addEventListener('blur', onblur_1);
8803 input_1.addEventListener('keydown', function (event) {
8804 if (event.key === 'Enter') {
8805 if (input_1.value !== '') {
8806 title.label = title.caption = input_1.value;
8807 }
8808 onblur_1();
8809 }
8810 else if (event.key === 'Escape') {
8811 onblur_1();
8812 }
8813 });
8814 input_1.select();
8815 input_1.focus();
8816 if (label.children.length > 0) {
8817 label.children[0].focus();
8818 }
8819 }
8820 };
8821 /**
8822 * Handle the `'keydown'` event for the tab bar.
8823 */
8824 TabBar.prototype._evtKeyDown = function (event) {
8825 // Stop all input events during drag.
8826 event.preventDefault();
8827 event.stopPropagation();
8828 // Release the mouse if `Escape` is pressed.
8829 if (event.keyCode === 27) {
8830 this._releaseMouse();
8831 }
8832 };
8833 /**
8834 * Handle the `'mousedown'` event for the tab bar.
8835 */
8836 TabBar.prototype._evtMouseDown = function (event) {
8837 // Do nothing if it's not a left or middle mouse press.
8838 if (event.button !== 0 && event.button !== 1) {
8839 return;
8840 }
8841 // Do nothing if a drag is in progress.
8842 if (this._dragData) {
8843 return;
8844 }
8845 // Check if the add button was clicked.
8846 var addButtonClicked = this.addButtonEnabled &&
8847 this.addButtonNode.contains(event.target);
8848 // Lookup the tab nodes.
8849 var tabs = this.contentNode.children;
8850 // Find the index of the pressed tab.
8851 var index = algorithm.ArrayExt.findFirstIndex(tabs, function (tab) {
8852 return domutils.ElementExt.hitTest(tab, event.clientX, event.clientY);
8853 });
8854 // Do nothing if the press is not on a tab or the add button.
8855 if (index === -1 && !addButtonClicked) {
8856 return;
8857 }
8858 // Pressing on a tab stops the event propagation.
8859 event.preventDefault();
8860 event.stopPropagation();
8861 // Initialize the non-measured parts of the drag data.
8862 this._dragData = {
8863 tab: tabs[index],
8864 index: index,
8865 pressX: event.clientX,
8866 pressY: event.clientY,
8867 tabPos: -1,
8868 tabSize: -1,
8869 tabPressPos: -1,
8870 targetIndex: -1,
8871 tabLayout: null,
8872 contentRect: null,
8873 override: null,
8874 dragActive: false,
8875 dragAborted: false,
8876 detachRequested: false
8877 };
8878 // Add the document mouse up listener.
8879 this.document.addEventListener('mouseup', this, true); // <DEPRECATED>
8880 this.document.addEventListener('pointerup', this, true);
8881 // Do nothing else if the middle button or add button is clicked.
8882 if (event.button === 1 || addButtonClicked) {
8883 return;
8884 }
8885 // Do nothing else if the close icon is clicked.
8886 var icon = tabs[index].querySelector(this.renderer.closeIconSelector);
8887 if (icon && icon.contains(event.target)) {
8888 return;
8889 }
8890 // Add the extra listeners if the tabs are movable.
8891 if (this.tabsMovable) {
8892 this.document.addEventListener('mousemove', this, true); // <DEPRECATED>
8893 this.document.addEventListener('pointermove', this, true);
8894 this.document.addEventListener('keydown', this, true);
8895 this.document.addEventListener('contextmenu', this, true);
8896 }
8897 // Update the current index as appropriate.
8898 if (this.allowDeselect && this.currentIndex === index) {
8899 this.currentIndex = -1;
8900 }
8901 else {
8902 this.currentIndex = index;
8903 }
8904 // Do nothing else if there is no current tab.
8905 if (this.currentIndex === -1) {
8906 return;
8907 }
8908 // Emit the tab activate request signal.
8909 this._tabActivateRequested.emit({
8910 index: this.currentIndex,
8911 title: this.currentTitle
8912 });
8913 };
8914 /**
8915 * Handle the `'mousemove'` event for the tab bar.
8916 */
8917 TabBar.prototype._evtMouseMove = function (event) {
8918 // Do nothing if no drag is in progress.
8919 var data = this._dragData;
8920 if (!data) {
8921 return;
8922 }
8923 // Suppress the event during a drag.
8924 event.preventDefault();
8925 event.stopPropagation();
8926 // Lookup the tab nodes.
8927 var tabs = this.contentNode.children;
8928 // Bail early if the drag threshold has not been met.
8929 if (!data.dragActive && !Private$7.dragExceeded(data, event)) {
8930 return;
8931 }
8932 // Activate the drag if necessary.
8933 if (!data.dragActive) {
8934 // Fill in the rest of the drag data measurements.
8935 var tabRect = data.tab.getBoundingClientRect();
8936 if (this._orientation === 'horizontal') {
8937 data.tabPos = data.tab.offsetLeft;
8938 data.tabSize = tabRect.width;
8939 data.tabPressPos = data.pressX - tabRect.left;
8940 }
8941 else {
8942 data.tabPos = data.tab.offsetTop;
8943 data.tabSize = tabRect.height;
8944 data.tabPressPos = data.pressY - tabRect.top;
8945 }
8946 data.tabLayout = Private$7.snapTabLayout(tabs, this._orientation);
8947 data.contentRect = this.contentNode.getBoundingClientRect();
8948 data.override = dragdrop.Drag.overrideCursor('default');
8949 // Add the dragging style classes.
8950 data.tab.classList.add('lm-mod-dragging');
8951 this.addClass('lm-mod-dragging');
8952 /* <DEPRECATED> */
8953 data.tab.classList.add('p-mod-dragging');
8954 this.addClass('p-mod-dragging');
8955 /* </DEPRECATED> */
8956 // Mark the drag as active.
8957 data.dragActive = true;
8958 }
8959 // Emit the detach requested signal if the threshold is exceeded.
8960 if (!data.detachRequested && Private$7.detachExceeded(data, event)) {
8961 // Only emit the signal once per drag cycle.
8962 data.detachRequested = true;
8963 // Setup the arguments for the signal.
8964 var index = data.index;
8965 var clientX = event.clientX;
8966 var clientY = event.clientY;
8967 var tab = tabs[index];
8968 var title = this._titles[index];
8969 // Emit the tab detach requested signal.
8970 this._tabDetachRequested.emit({ index: index, title: title, tab: tab, clientX: clientX, clientY: clientY });
8971 // Bail if the signal handler aborted the drag.
8972 if (data.dragAborted) {
8973 return;
8974 }
8975 }
8976 // Update the positions of the tabs.
8977 Private$7.layoutTabs(tabs, data, event, this._orientation);
8978 };
8979 /**
8980 * Handle the `'mouseup'` event for the document.
8981 */
8982 TabBar.prototype._evtMouseUp = function (event) {
8983 var _this = this;
8984 // Do nothing if it's not a left or middle mouse release.
8985 if (event.button !== 0 && event.button !== 1) {
8986 return;
8987 }
8988 // Do nothing if no drag is in progress.
8989 var data = this._dragData;
8990 if (!data) {
8991 return;
8992 }
8993 // Stop the event propagation.
8994 event.preventDefault();
8995 event.stopPropagation();
8996 // Remove the extra mouse event listeners.
8997 this.document.removeEventListener('mousemove', this, true); // <DEPRECATED>
8998 this.document.removeEventListener('mouseup', this, true); // <DEPRECATED>
8999 this.document.removeEventListener('pointermove', this, true);
9000 this.document.removeEventListener('pointerup', this, true);
9001 this.document.removeEventListener('keydown', this, true);
9002 this.document.removeEventListener('contextmenu', this, true);
9003 // Handle a release when the drag is not active.
9004 if (!data.dragActive) {
9005 // Clear the drag data.
9006 this._dragData = null;
9007 // Handle clicking the add button.
9008 var addButtonClicked = this.addButtonEnabled &&
9009 this.addButtonNode.contains(event.target);
9010 if (addButtonClicked) {
9011 this._addRequested.emit(undefined);
9012 return;
9013 }
9014 // Lookup the tab nodes.
9015 var tabs = this.contentNode.children;
9016 // Find the index of the released tab.
9017 var index = algorithm.ArrayExt.findFirstIndex(tabs, function (tab) {
9018 return domutils.ElementExt.hitTest(tab, event.clientX, event.clientY);
9019 });
9020 // Do nothing if the release is not on the original pressed tab.
9021 if (index !== data.index) {
9022 return;
9023 }
9024 // Ignore the release if the title is not closable.
9025 var title = this._titles[index];
9026 if (!title.closable) {
9027 return;
9028 }
9029 // Emit the close requested signal if the middle button is released.
9030 if (event.button === 1) {
9031 this._tabCloseRequested.emit({ index: index, title: title });
9032 return;
9033 }
9034 // Emit the close requested signal if the close icon was released.
9035 var icon = tabs[index].querySelector(this.renderer.closeIconSelector);
9036 if (icon && icon.contains(event.target)) {
9037 this._tabCloseRequested.emit({ index: index, title: title });
9038 return;
9039 }
9040 // Otherwise, there is nothing left to do.
9041 return;
9042 }
9043 // Do nothing if the left button is not released.
9044 if (event.button !== 0) {
9045 return;
9046 }
9047 // Position the tab at its final resting position.
9048 Private$7.finalizeTabPosition(data, this._orientation);
9049 // Remove the dragging class from the tab so it can be transitioned.
9050 data.tab.classList.remove('lm-mod-dragging');
9051 /* <DEPRECATED> */
9052 data.tab.classList.remove('p-mod-dragging');
9053 /* </DEPRECATED> */
9054 // Parse the transition duration for releasing the tab.
9055 var duration = Private$7.parseTransitionDuration(data.tab);
9056 // Complete the release on a timer to allow the tab to transition.
9057 setTimeout(function () {
9058 // Do nothing if the drag has been aborted.
9059 if (data.dragAborted) {
9060 return;
9061 }
9062 // Clear the drag data reference.
9063 _this._dragData = null;
9064 // Reset the positions of the tabs.
9065 Private$7.resetTabPositions(_this.contentNode.children, _this._orientation);
9066 // Clear the cursor grab.
9067 data.override.dispose();
9068 // Remove the remaining dragging style.
9069 _this.removeClass('lm-mod-dragging');
9070 /* <DEPRECATED> */
9071 _this.removeClass('p-mod-dragging');
9072 /* </DEPRECATED> */
9073 // If the tab was not moved, there is nothing else to do.
9074 var i = data.index;
9075 var j = data.targetIndex;
9076 if (j === -1 || i === j) {
9077 return;
9078 }
9079 // Move the title to the new locations.
9080 algorithm.ArrayExt.move(_this._titles, i, j);
9081 // Adjust the current index for the move.
9082 _this._adjustCurrentForMove(i, j);
9083 // Emit the tab moved signal.
9084 _this._tabMoved.emit({
9085 fromIndex: i,
9086 toIndex: j,
9087 title: _this._titles[j]
9088 });
9089 // Update the tabs immediately to prevent flicker.
9090 messaging.MessageLoop.sendMessage(_this, exports.Widget.Msg.UpdateRequest);
9091 }, duration);
9092 };
9093 /**
9094 * Release the mouse and restore the non-dragged tab positions.
9095 */
9096 TabBar.prototype._releaseMouse = function () {
9097 // Do nothing if no drag is in progress.
9098 var data = this._dragData;
9099 if (!data) {
9100 return;
9101 }
9102 // Clear the drag data reference.
9103 this._dragData = null;
9104 // Remove the extra mouse listeners.
9105 this.document.removeEventListener('mousemove', this, true); // <DEPRECATED>
9106 this.document.removeEventListener('mouseup', this, true); // <DEPRECATED>
9107 this.document.removeEventListener('pointermove', this, true);
9108 this.document.removeEventListener('pointerup', this, true);
9109 this.document.removeEventListener('keydown', this, true);
9110 this.document.removeEventListener('contextmenu', this, true);
9111 // Indicate the drag has been aborted. This allows the mouse
9112 // event handlers to return early when the drag is canceled.
9113 data.dragAborted = true;
9114 // If the drag is not active, there's nothing more to do.
9115 if (!data.dragActive) {
9116 return;
9117 }
9118 // Reset the tabs to their non-dragged positions.
9119 Private$7.resetTabPositions(this.contentNode.children, this._orientation);
9120 // Clear the cursor override.
9121 data.override.dispose();
9122 // Clear the dragging style classes.
9123 data.tab.classList.remove('lm-mod-dragging');
9124 this.removeClass('lm-mod-dragging');
9125 /* <DEPRECATED> */
9126 data.tab.classList.remove('p-mod-dragging');
9127 this.removeClass('p-mod-dragging');
9128 /* </DEPRECATED> */
9129 };
9130 /**
9131 * Adjust the current index for a tab insert operation.
9132 *
9133 * This method accounts for the tab bar's insertion behavior when
9134 * adjusting the current index and emitting the changed signal.
9135 */
9136 TabBar.prototype._adjustCurrentForInsert = function (i, title) {
9137 // Lookup commonly used variables.
9138 var ct = this.currentTitle;
9139 var ci = this._currentIndex;
9140 var bh = this.insertBehavior;
9141 // TODO: do we need to do an update to update the aria-selected attribute?
9142 // Handle the behavior where the new tab is always selected,
9143 // or the behavior where the new tab is selected if needed.
9144 if (bh === 'select-tab' || (bh === 'select-tab-if-needed' && ci === -1)) {
9145 this._currentIndex = i;
9146 this._previousTitle = ct;
9147 this._currentChanged.emit({
9148 previousIndex: ci,
9149 previousTitle: ct,
9150 currentIndex: i,
9151 currentTitle: title
9152 });
9153 return;
9154 }
9155 // Otherwise, silently adjust the current index if needed.
9156 if (ci >= i) {
9157 this._currentIndex++;
9158 }
9159 };
9160 /**
9161 * Adjust the current index for a tab move operation.
9162 *
9163 * This method will not cause the actual current tab to change.
9164 * It silently adjusts the index to account for the given move.
9165 */
9166 TabBar.prototype._adjustCurrentForMove = function (i, j) {
9167 if (this._currentIndex === i) {
9168 this._currentIndex = j;
9169 }
9170 else if (this._currentIndex < i && this._currentIndex >= j) {
9171 this._currentIndex++;
9172 }
9173 else if (this._currentIndex > i && this._currentIndex <= j) {
9174 this._currentIndex--;
9175 }
9176 };
9177 /**
9178 * Adjust the current index for a tab remove operation.
9179 *
9180 * This method accounts for the tab bar's remove behavior when
9181 * adjusting the current index and emitting the changed signal.
9182 */
9183 TabBar.prototype._adjustCurrentForRemove = function (i, title) {
9184 // Lookup commonly used variables.
9185 var ci = this._currentIndex;
9186 var bh = this.removeBehavior;
9187 // Silently adjust the index if the current tab is not removed.
9188 if (ci !== i) {
9189 if (ci > i) {
9190 this._currentIndex--;
9191 }
9192 return;
9193 }
9194 // TODO: do we need to do an update to adjust the aria-selected value?
9195 // No tab gets selected if the tab bar is empty.
9196 if (this._titles.length === 0) {
9197 this._currentIndex = -1;
9198 this._currentChanged.emit({
9199 previousIndex: i,
9200 previousTitle: title,
9201 currentIndex: -1,
9202 currentTitle: null
9203 });
9204 return;
9205 }
9206 // Handle behavior where the next sibling tab is selected.
9207 if (bh === 'select-tab-after') {
9208 this._currentIndex = Math.min(i, this._titles.length - 1);
9209 this._currentChanged.emit({
9210 previousIndex: i,
9211 previousTitle: title,
9212 currentIndex: this._currentIndex,
9213 currentTitle: this.currentTitle
9214 });
9215 return;
9216 }
9217 // Handle behavior where the previous sibling tab is selected.
9218 if (bh === 'select-tab-before') {
9219 this._currentIndex = Math.max(0, i - 1);
9220 this._currentChanged.emit({
9221 previousIndex: i,
9222 previousTitle: title,
9223 currentIndex: this._currentIndex,
9224 currentTitle: this.currentTitle
9225 });
9226 return;
9227 }
9228 // Handle behavior where the previous history tab is selected.
9229 if (bh === 'select-previous-tab') {
9230 if (this._previousTitle) {
9231 this._currentIndex = this._titles.indexOf(this._previousTitle);
9232 this._previousTitle = null;
9233 }
9234 else {
9235 this._currentIndex = Math.min(i, this._titles.length - 1);
9236 }
9237 this._currentChanged.emit({
9238 previousIndex: i,
9239 previousTitle: title,
9240 currentIndex: this._currentIndex,
9241 currentTitle: this.currentTitle
9242 });
9243 return;
9244 }
9245 // Otherwise, no tab gets selected.
9246 this._currentIndex = -1;
9247 this._currentChanged.emit({
9248 previousIndex: i,
9249 previousTitle: title,
9250 currentIndex: -1,
9251 currentTitle: null
9252 });
9253 };
9254 /**
9255 * Handle the `changed` signal of a title object.
9256 */
9257 TabBar.prototype._onTitleChanged = function (sender) {
9258 this.update();
9259 };
9260 return TabBar;
9261 }(exports.Widget));
9262 /**
9263 * The namespace for the `TabBar` class statics.
9264 */
9265 (function (TabBar) {
9266 /**
9267 * The default implementation of `IRenderer`.
9268 *
9269 * #### Notes
9270 * Subclasses are free to reimplement rendering methods as needed.
9271 */
9272 var Renderer = /** @class */ (function () {
9273 function Renderer() {
9274 /**
9275 * A selector which matches the close icon node in a tab.
9276 */
9277 this.closeIconSelector = '.lm-TabBar-tabCloseIcon';
9278 this._tabID = 0;
9279 this._tabKeys = new WeakMap();
9280 }
9281 /**
9282 * Render the virtual element for a tab.
9283 *
9284 * @param data - The data to use for rendering the tab.
9285 *
9286 * @returns A virtual element representing the tab.
9287 */
9288 Renderer.prototype.renderTab = function (data) {
9289 var title = data.title.caption;
9290 var key = this.createTabKey(data);
9291 var id = key;
9292 var style = this.createTabStyle(data);
9293 var className = this.createTabClass(data);
9294 var dataset = this.createTabDataset(data);
9295 var aria = this.createTabARIA(data);
9296 if (data.title.closable) {
9297 return virtualdom.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));
9298 }
9299 else {
9300 return virtualdom.h.li(__assign({ id: id, key: key, className: className, title: title, style: style, dataset: dataset }, aria), this.renderIcon(data), this.renderLabel(data));
9301 }
9302 };
9303 /**
9304 * Render the icon element for a tab.
9305 *
9306 * @param data - The data to use for rendering the tab.
9307 *
9308 * @returns A virtual element representing the tab icon.
9309 */
9310 Renderer.prototype.renderIcon = function (data) {
9311 var title = data.title;
9312 var className = this.createIconClass(data);
9313 /* <DEPRECATED> */
9314 if (typeof title.icon === 'string') {
9315 return virtualdom.h.div({ className: className }, title.iconLabel);
9316 }
9317 /* </DEPRECATED> */
9318 // if title.icon is undefined, it will be ignored
9319 return virtualdom.h.div({ className: className }, title.icon, title.iconLabel);
9320 };
9321 /**
9322 * Render the label element for a tab.
9323 *
9324 * @param data - The data to use for rendering the tab.
9325 *
9326 * @returns A virtual element representing the tab label.
9327 */
9328 Renderer.prototype.renderLabel = function (data) {
9329 return virtualdom.h.div({
9330 className: 'lm-TabBar-tabLabel' +
9331 /* <DEPRECATED> */
9332 ' p-TabBar-tabLabel'
9333 /* </DEPRECATED> */
9334 }, data.title.label);
9335 };
9336 /**
9337 * Render the close icon element for a tab.
9338 *
9339 * @param data - The data to use for rendering the tab.
9340 *
9341 * @returns A virtual element representing the tab close icon.
9342 */
9343 Renderer.prototype.renderCloseIcon = function (data) {
9344 return virtualdom.h.div({
9345 className: 'lm-TabBar-tabCloseIcon' +
9346 /* <DEPRECATED> */
9347 ' p-TabBar-tabCloseIcon'
9348 /* </DEPRECATED> */
9349 });
9350 };
9351 /**
9352 * Create a unique render key for the tab.
9353 *
9354 * @param data - The data to use for the tab.
9355 *
9356 * @returns The unique render key for the tab.
9357 *
9358 * #### Notes
9359 * This method caches the key against the tab title the first time
9360 * the key is generated. This enables efficient rendering of moved
9361 * tabs and avoids subtle hover style artifacts.
9362 */
9363 Renderer.prototype.createTabKey = function (data) {
9364 var key = this._tabKeys.get(data.title);
9365 if (key === undefined) {
9366 key = "tab-key-" + this._tabID++;
9367 this._tabKeys.set(data.title, key);
9368 }
9369 return key;
9370 };
9371 /**
9372 * Create the inline style object for a tab.
9373 *
9374 * @param data - The data to use for the tab.
9375 *
9376 * @returns The inline style data for the tab.
9377 */
9378 Renderer.prototype.createTabStyle = function (data) {
9379 return { zIndex: "" + data.zIndex };
9380 };
9381 /**
9382 * Create the class name for the tab.
9383 *
9384 * @param data - The data to use for the tab.
9385 *
9386 * @returns The full class name for the tab.
9387 */
9388 Renderer.prototype.createTabClass = function (data) {
9389 var name = 'lm-TabBar-tab';
9390 /* <DEPRECATED> */
9391 name += ' p-TabBar-tab';
9392 /* </DEPRECATED> */
9393 if (data.title.className) {
9394 name += " " + data.title.className;
9395 }
9396 if (data.title.closable) {
9397 name += ' lm-mod-closable';
9398 /* <DEPRECATED> */
9399 name += ' p-mod-closable';
9400 /* </DEPRECATED> */
9401 }
9402 if (data.current) {
9403 name += ' lm-mod-current';
9404 /* <DEPRECATED> */
9405 name += ' p-mod-current';
9406 /* </DEPRECATED> */
9407 }
9408 return name;
9409 };
9410 /**
9411 * Create the dataset for a tab.
9412 *
9413 * @param data - The data to use for the tab.
9414 *
9415 * @returns The dataset for the tab.
9416 */
9417 Renderer.prototype.createTabDataset = function (data) {
9418 return data.title.dataset;
9419 };
9420 /**
9421 * Create the ARIA attributes for a tab.
9422 *
9423 * @param data - The data to use for the tab.
9424 *
9425 * @returns The ARIA attributes for the tab.
9426 */
9427 Renderer.prototype.createTabARIA = function (data) {
9428 return { role: 'tab', 'aria-selected': data.current.toString() };
9429 };
9430 /**
9431 * Create the class name for the tab icon.
9432 *
9433 * @param data - The data to use for the tab.
9434 *
9435 * @returns The full class name for the tab icon.
9436 */
9437 Renderer.prototype.createIconClass = function (data) {
9438 var name = 'lm-TabBar-tabIcon';
9439 /* <DEPRECATED> */
9440 name += ' p-TabBar-tabIcon';
9441 /* </DEPRECATED> */
9442 var extra = data.title.iconClass;
9443 return extra ? name + " " + extra : name;
9444 };
9445 return Renderer;
9446 }());
9447 TabBar.Renderer = Renderer;
9448 /**
9449 * The default `Renderer` instance.
9450 */
9451 TabBar.defaultRenderer = new Renderer();
9452 /**
9453 * A selector which matches the add button node in the tab bar.
9454 */
9455 TabBar.addButtonSelector = '.lm-TabBar-addButton';
9456 })(exports.TabBar || (exports.TabBar = {}));
9457 /**
9458 * The namespace for the module implementation details.
9459 */
9460 var Private$7;
9461 (function (Private) {
9462 /**
9463 * The start drag distance threshold.
9464 */
9465 Private.DRAG_THRESHOLD = 5;
9466 /**
9467 * The detach distance threshold.
9468 */
9469 Private.DETACH_THRESHOLD = 20;
9470 /**
9471 * Create the DOM node for a tab bar.
9472 */
9473 function createNode() {
9474 var node = document.createElement('div');
9475 var content = document.createElement('ul');
9476 content.setAttribute('role', 'tablist');
9477 content.className = 'lm-TabBar-content';
9478 /* <DEPRECATED> */
9479 content.classList.add('p-TabBar-content');
9480 /* </DEPRECATED> */
9481 node.appendChild(content);
9482 var add = document.createElement('div');
9483 add.className = 'lm-TabBar-addButton lm-mod-hidden';
9484 node.appendChild(add);
9485 return node;
9486 }
9487 Private.createNode = createNode;
9488 /**
9489 * Coerce a title or options into a real title.
9490 */
9491 function asTitle(value) {
9492 return value instanceof Title ? value : new Title(value);
9493 }
9494 Private.asTitle = asTitle;
9495 /**
9496 * Parse the transition duration for a tab node.
9497 */
9498 function parseTransitionDuration(tab) {
9499 var style = window.getComputedStyle(tab);
9500 return 1000 * (parseFloat(style.transitionDuration) || 0);
9501 }
9502 Private.parseTransitionDuration = parseTransitionDuration;
9503 /**
9504 * Get a snapshot of the current tab layout values.
9505 */
9506 function snapTabLayout(tabs, orientation) {
9507 var layout = new Array(tabs.length);
9508 for (var i = 0, n = tabs.length; i < n; ++i) {
9509 var node = tabs[i];
9510 var style = window.getComputedStyle(node);
9511 if (orientation === 'horizontal') {
9512 layout[i] = {
9513 pos: node.offsetLeft,
9514 size: node.offsetWidth,
9515 margin: parseFloat(style.marginLeft) || 0
9516 };
9517 }
9518 else {
9519 layout[i] = {
9520 pos: node.offsetTop,
9521 size: node.offsetHeight,
9522 margin: parseFloat(style.marginTop) || 0
9523 };
9524 }
9525 }
9526 return layout;
9527 }
9528 Private.snapTabLayout = snapTabLayout;
9529 /**
9530 * Test if the event exceeds the drag threshold.
9531 */
9532 function dragExceeded(data, event) {
9533 var dx = Math.abs(event.clientX - data.pressX);
9534 var dy = Math.abs(event.clientY - data.pressY);
9535 return dx >= Private.DRAG_THRESHOLD || dy >= Private.DRAG_THRESHOLD;
9536 }
9537 Private.dragExceeded = dragExceeded;
9538 /**
9539 * Test if the event exceeds the drag detach threshold.
9540 */
9541 function detachExceeded(data, event) {
9542 var rect = data.contentRect;
9543 return (event.clientX < rect.left - Private.DETACH_THRESHOLD ||
9544 event.clientX >= rect.right + Private.DETACH_THRESHOLD ||
9545 event.clientY < rect.top - Private.DETACH_THRESHOLD ||
9546 event.clientY >= rect.bottom + Private.DETACH_THRESHOLD);
9547 }
9548 Private.detachExceeded = detachExceeded;
9549 /**
9550 * Update the relative tab positions and computed target index.
9551 */
9552 function layoutTabs(tabs, data, event, orientation) {
9553 // Compute the orientation-sensitive values.
9554 var pressPos;
9555 var localPos;
9556 var clientPos;
9557 var clientSize;
9558 if (orientation === 'horizontal') {
9559 pressPos = data.pressX;
9560 localPos = event.clientX - data.contentRect.left;
9561 clientPos = event.clientX;
9562 clientSize = data.contentRect.width;
9563 }
9564 else {
9565 pressPos = data.pressY;
9566 localPos = event.clientY - data.contentRect.top;
9567 clientPos = event.clientY;
9568 clientSize = data.contentRect.height;
9569 }
9570 // Compute the target data.
9571 var targetIndex = data.index;
9572 var targetPos = localPos - data.tabPressPos;
9573 var targetEnd = targetPos + data.tabSize;
9574 // Update the relative tab positions.
9575 for (var i = 0, n = tabs.length; i < n; ++i) {
9576 var pxPos = void 0;
9577 var layout = data.tabLayout[i];
9578 var threshold = layout.pos + (layout.size >> 1);
9579 if (i < data.index && targetPos < threshold) {
9580 pxPos = data.tabSize + data.tabLayout[i + 1].margin + "px";
9581 targetIndex = Math.min(targetIndex, i);
9582 }
9583 else if (i > data.index && targetEnd > threshold) {
9584 pxPos = -data.tabSize - layout.margin + "px";
9585 targetIndex = Math.max(targetIndex, i);
9586 }
9587 else if (i === data.index) {
9588 var ideal = clientPos - pressPos;
9589 var limit = clientSize - (data.tabPos + data.tabSize);
9590 pxPos = Math.max(-data.tabPos, Math.min(ideal, limit)) + "px";
9591 }
9592 else {
9593 pxPos = '';
9594 }
9595 if (orientation === 'horizontal') {
9596 tabs[i].style.left = pxPos;
9597 }
9598 else {
9599 tabs[i].style.top = pxPos;
9600 }
9601 }
9602 // Update the computed target index.
9603 data.targetIndex = targetIndex;
9604 }
9605 Private.layoutTabs = layoutTabs;
9606 /**
9607 * Position the drag tab at its final resting relative position.
9608 */
9609 function finalizeTabPosition(data, orientation) {
9610 // Compute the orientation-sensitive client size.
9611 var clientSize;
9612 if (orientation === 'horizontal') {
9613 clientSize = data.contentRect.width;
9614 }
9615 else {
9616 clientSize = data.contentRect.height;
9617 }
9618 // Compute the ideal final tab position.
9619 var ideal;
9620 if (data.targetIndex === data.index) {
9621 ideal = 0;
9622 }
9623 else if (data.targetIndex > data.index) {
9624 var tgt = data.tabLayout[data.targetIndex];
9625 ideal = tgt.pos + tgt.size - data.tabSize - data.tabPos;
9626 }
9627 else {
9628 var tgt = data.tabLayout[data.targetIndex];
9629 ideal = tgt.pos - data.tabPos;
9630 }
9631 // Compute the tab position limit.
9632 var limit = clientSize - (data.tabPos + data.tabSize);
9633 var final = Math.max(-data.tabPos, Math.min(ideal, limit));
9634 // Set the final orientation-sensitive position.
9635 if (orientation === 'horizontal') {
9636 data.tab.style.left = final + "px";
9637 }
9638 else {
9639 data.tab.style.top = final + "px";
9640 }
9641 }
9642 Private.finalizeTabPosition = finalizeTabPosition;
9643 /**
9644 * Reset the relative positions of the given tabs.
9645 */
9646 function resetTabPositions(tabs, orientation) {
9647 algorithm.each(tabs, function (tab) {
9648 if (orientation === 'horizontal') {
9649 tab.style.left = '';
9650 }
9651 else {
9652 tab.style.top = '';
9653 }
9654 });
9655 }
9656 Private.resetTabPositions = resetTabPositions;
9657 })(Private$7 || (Private$7 = {}));
9658
9659 /**
9660 * A layout which provides a flexible docking arrangement.
9661 *
9662 * #### Notes
9663 * The consumer of this layout is responsible for handling all signals
9664 * from the generated tab bars and managing the visibility of widgets
9665 * and tab bars as needed.
9666 */
9667 var DockLayout = /** @class */ (function (_super) {
9668 __extends(DockLayout, _super);
9669 /**
9670 * Construct a new dock layout.
9671 *
9672 * @param options - The options for initializing the layout.
9673 */
9674 function DockLayout(options) {
9675 var _this = _super.call(this) || this;
9676 _this._spacing = 4;
9677 _this._dirty = false;
9678 _this._root = null;
9679 _this._box = null;
9680 _this._items = new Map();
9681 _this.renderer = options.renderer;
9682 if (options.spacing !== undefined) {
9683 _this._spacing = Utils$1.clampDimension(options.spacing);
9684 }
9685 _this._document = options.document || document;
9686 _this._hiddenMode =
9687 options.hiddenMode !== undefined
9688 ? options.hiddenMode
9689 : exports.Widget.HiddenMode.Display;
9690 return _this;
9691 }
9692 /**
9693 * Dispose of the resources held by the layout.
9694 *
9695 * #### Notes
9696 * This will clear and dispose all widgets in the layout.
9697 */
9698 DockLayout.prototype.dispose = function () {
9699 // Get an iterator over the widgets in the layout.
9700 var widgets = this.iter();
9701 // Dispose of the layout items.
9702 this._items.forEach(function (item) {
9703 item.dispose();
9704 });
9705 // Clear the layout state before disposing the widgets.
9706 this._box = null;
9707 this._root = null;
9708 this._items.clear();
9709 // Dispose of the widgets contained in the old layout root.
9710 algorithm.each(widgets, function (widget) {
9711 widget.dispose();
9712 });
9713 // Dispose of the base class.
9714 _super.prototype.dispose.call(this);
9715 };
9716 Object.defineProperty(DockLayout.prototype, "hiddenMode", {
9717 /**
9718 * The method for hiding child widgets.
9719 *
9720 * #### Notes
9721 * If there is only one child widget, `Display` hiding mode will be used
9722 * regardless of this setting.
9723 */
9724 get: function () {
9725 return this._hiddenMode;
9726 },
9727 set: function (v) {
9728 var _this = this;
9729 if (this._hiddenMode === v) {
9730 return;
9731 }
9732 this._hiddenMode = v;
9733 algorithm.each(this.tabBars(), function (bar) {
9734 if (bar.titles.length > 1) {
9735 bar.titles.forEach(function (title) {
9736 title.owner.hiddenMode = _this._hiddenMode;
9737 });
9738 }
9739 });
9740 },
9741 enumerable: true,
9742 configurable: true
9743 });
9744 Object.defineProperty(DockLayout.prototype, "spacing", {
9745 /**
9746 * Get the inter-element spacing for the dock layout.
9747 */
9748 get: function () {
9749 return this._spacing;
9750 },
9751 /**
9752 * Set the inter-element spacing for the dock layout.
9753 */
9754 set: function (value) {
9755 value = Utils$1.clampDimension(value);
9756 if (this._spacing === value) {
9757 return;
9758 }
9759 this._spacing = value;
9760 if (!this.parent) {
9761 return;
9762 }
9763 this.parent.fit();
9764 },
9765 enumerable: true,
9766 configurable: true
9767 });
9768 Object.defineProperty(DockLayout.prototype, "isEmpty", {
9769 /**
9770 * Whether the dock layout is empty.
9771 */
9772 get: function () {
9773 return this._root === null;
9774 },
9775 enumerable: true,
9776 configurable: true
9777 });
9778 /**
9779 * Create an iterator over all widgets in the layout.
9780 *
9781 * @returns A new iterator over the widgets in the layout.
9782 *
9783 * #### Notes
9784 * This iterator includes the generated tab bars.
9785 */
9786 DockLayout.prototype.iter = function () {
9787 return this._root ? this._root.iterAllWidgets() : algorithm.empty();
9788 };
9789 /**
9790 * Create an iterator over the user widgets in the layout.
9791 *
9792 * @returns A new iterator over the user widgets in the layout.
9793 *
9794 * #### Notes
9795 * This iterator does not include the generated tab bars.
9796 */
9797 DockLayout.prototype.widgets = function () {
9798 return this._root ? this._root.iterUserWidgets() : algorithm.empty();
9799 };
9800 /**
9801 * Create an iterator over the selected widgets in the layout.
9802 *
9803 * @returns A new iterator over the selected user widgets.
9804 *
9805 * #### Notes
9806 * This iterator yields the widgets corresponding to the current tab
9807 * of each tab bar in the layout.
9808 */
9809 DockLayout.prototype.selectedWidgets = function () {
9810 return this._root ? this._root.iterSelectedWidgets() : algorithm.empty();
9811 };
9812 /**
9813 * Create an iterator over the tab bars in the layout.
9814 *
9815 * @returns A new iterator over the tab bars in the layout.
9816 *
9817 * #### Notes
9818 * This iterator does not include the user widgets.
9819 */
9820 DockLayout.prototype.tabBars = function () {
9821 return this._root ? this._root.iterTabBars() : algorithm.empty();
9822 };
9823 /**
9824 * Create an iterator over the handles in the layout.
9825 *
9826 * @returns A new iterator over the handles in the layout.
9827 */
9828 DockLayout.prototype.handles = function () {
9829 return this._root ? this._root.iterHandles() : algorithm.empty();
9830 };
9831 /**
9832 * Move a handle to the given offset position.
9833 *
9834 * @param handle - The handle to move.
9835 *
9836 * @param offsetX - The desired offset X position of the handle.
9837 *
9838 * @param offsetY - The desired offset Y position of the handle.
9839 *
9840 * #### Notes
9841 * If the given handle is not contained in the layout, this is no-op.
9842 *
9843 * The handle will be moved as close as possible to the desired
9844 * position without violating any of the layout constraints.
9845 *
9846 * Only one of the coordinates is used depending on the orientation
9847 * of the handle. This method accepts both coordinates to make it
9848 * easy to invoke from a mouse move event without needing to know
9849 * the handle orientation.
9850 */
9851 DockLayout.prototype.moveHandle = function (handle, offsetX, offsetY) {
9852 // Bail early if there is no root or if the handle is hidden.
9853 var hidden = handle.classList.contains('lm-mod-hidden');
9854 /* <DEPRECATED> */
9855 hidden = hidden || handle.classList.contains('p-mod-hidden');
9856 /* </DEPRECATED> */
9857 if (!this._root || hidden) {
9858 return;
9859 }
9860 // Lookup the split node for the handle.
9861 var data = this._root.findSplitNode(handle);
9862 if (!data) {
9863 return;
9864 }
9865 // Compute the desired delta movement for the handle.
9866 var delta;
9867 if (data.node.orientation === 'horizontal') {
9868 delta = offsetX - handle.offsetLeft;
9869 }
9870 else {
9871 delta = offsetY - handle.offsetTop;
9872 }
9873 // Bail if there is no handle movement.
9874 if (delta === 0) {
9875 return;
9876 }
9877 // Prevent sibling resizing unless needed.
9878 data.node.holdSizes();
9879 // Adjust the sizers to reflect the handle movement.
9880 exports.BoxEngine.adjust(data.node.sizers, data.index, delta);
9881 // Update the layout of the widgets.
9882 if (this.parent) {
9883 this.parent.update();
9884 }
9885 };
9886 /**
9887 * Save the current configuration of the dock layout.
9888 *
9889 * @returns A new config object for the current layout state.
9890 *
9891 * #### Notes
9892 * The return value can be provided to the `restoreLayout` method
9893 * in order to restore the layout to its current configuration.
9894 */
9895 DockLayout.prototype.saveLayout = function () {
9896 // Bail early if there is no root.
9897 if (!this._root) {
9898 return { main: null };
9899 }
9900 // Hold the current sizes in the layout tree.
9901 this._root.holdAllSizes();
9902 // Return the layout config.
9903 return { main: this._root.createConfig() };
9904 };
9905 /**
9906 * Restore the layout to a previously saved configuration.
9907 *
9908 * @param config - The layout configuration to restore.
9909 *
9910 * #### Notes
9911 * Widgets which currently belong to the layout but which are not
9912 * contained in the config will be unparented.
9913 */
9914 DockLayout.prototype.restoreLayout = function (config) {
9915 var _this = this;
9916 // Create the widget set for validating the config.
9917 var widgetSet = new Set();
9918 // Normalize the main area config and collect the widgets.
9919 var mainConfig;
9920 if (config.main) {
9921 mainConfig = Private$6.normalizeAreaConfig(config.main, widgetSet);
9922 }
9923 else {
9924 mainConfig = null;
9925 }
9926 // Create iterators over the old content.
9927 var oldWidgets = this.widgets();
9928 var oldTabBars = this.tabBars();
9929 var oldHandles = this.handles();
9930 // Clear the root before removing the old content.
9931 this._root = null;
9932 // Unparent the old widgets which are not in the new config.
9933 algorithm.each(oldWidgets, function (widget) {
9934 if (!widgetSet.has(widget)) {
9935 widget.parent = null;
9936 }
9937 });
9938 // Dispose of the old tab bars.
9939 algorithm.each(oldTabBars, function (tabBar) {
9940 tabBar.dispose();
9941 });
9942 // Remove the old handles.
9943 algorithm.each(oldHandles, function (handle) {
9944 if (handle.parentNode) {
9945 handle.parentNode.removeChild(handle);
9946 }
9947 });
9948 // Reparent the new widgets to the current parent.
9949 widgetSet.forEach(function (widget) {
9950 widget.parent = _this.parent;
9951 });
9952 // Create the root node for the new config.
9953 if (mainConfig) {
9954 this._root = Private$6.realizeAreaConfig(mainConfig, {
9955 // Ignoring optional `document` argument as we must reuse `this._document`
9956 createTabBar: function (document) {
9957 return _this._createTabBar();
9958 },
9959 createHandle: function () { return _this._createHandle(); }
9960 }, this._document);
9961 }
9962 else {
9963 this._root = null;
9964 }
9965 // If there is no parent, there is nothing more to do.
9966 if (!this.parent) {
9967 return;
9968 }
9969 // Attach the new widgets to the parent.
9970 widgetSet.forEach(function (widget) {
9971 _this.attachWidget(widget);
9972 });
9973 // Post a fit request to the parent.
9974 this.parent.fit();
9975 };
9976 /**
9977 * Add a widget to the dock layout.
9978 *
9979 * @param widget - The widget to add to the dock layout.
9980 *
9981 * @param options - The additional options for adding the widget.
9982 *
9983 * #### Notes
9984 * The widget will be moved if it is already contained in the layout.
9985 *
9986 * An error will be thrown if the reference widget is invalid.
9987 */
9988 DockLayout.prototype.addWidget = function (widget, options) {
9989 if (options === void 0) { options = {}; }
9990 // Parse the options.
9991 var ref = options.ref || null;
9992 var mode = options.mode || 'tab-after';
9993 // Find the tab node which holds the reference widget.
9994 var refNode = null;
9995 if (this._root && ref) {
9996 refNode = this._root.findTabNode(ref);
9997 }
9998 // Throw an error if the reference widget is invalid.
9999 if (ref && !refNode) {
10000 throw new Error('Reference widget is not in the layout.');
10001 }
10002 // Reparent the widget to the current layout parent.
10003 widget.parent = this.parent;
10004 // Insert the widget according to the insert mode.
10005 switch (mode) {
10006 case 'tab-after':
10007 this._insertTab(widget, ref, refNode, true);
10008 break;
10009 case 'tab-before':
10010 this._insertTab(widget, ref, refNode, false);
10011 break;
10012 case 'split-top':
10013 this._insertSplit(widget, ref, refNode, 'vertical', false);
10014 break;
10015 case 'split-left':
10016 this._insertSplit(widget, ref, refNode, 'horizontal', false);
10017 break;
10018 case 'split-right':
10019 this._insertSplit(widget, ref, refNode, 'horizontal', true);
10020 break;
10021 case 'split-bottom':
10022 this._insertSplit(widget, ref, refNode, 'vertical', true);
10023 break;
10024 }
10025 // Do nothing else if there is no parent widget.
10026 if (!this.parent) {
10027 return;
10028 }
10029 // Ensure the widget is attached to the parent widget.
10030 this.attachWidget(widget);
10031 // Post a fit request for the parent widget.
10032 this.parent.fit();
10033 };
10034 /**
10035 * Remove a widget from the layout.
10036 *
10037 * @param widget - The widget to remove from the layout.
10038 *
10039 * #### Notes
10040 * A widget is automatically removed from the layout when its `parent`
10041 * is set to `null`. This method should only be invoked directly when
10042 * removing a widget from a layout which has yet to be installed on a
10043 * parent widget.
10044 *
10045 * This method does *not* modify the widget's `parent`.
10046 */
10047 DockLayout.prototype.removeWidget = function (widget) {
10048 // Remove the widget from its current layout location.
10049 this._removeWidget(widget);
10050 // Do nothing else if there is no parent widget.
10051 if (!this.parent) {
10052 return;
10053 }
10054 // Detach the widget from the parent widget.
10055 this.detachWidget(widget);
10056 // Post a fit request for the parent widget.
10057 this.parent.fit();
10058 };
10059 /**
10060 * Find the tab area which contains the given client position.
10061 *
10062 * @param clientX - The client X position of interest.
10063 *
10064 * @param clientY - The client Y position of interest.
10065 *
10066 * @returns The geometry of the tab area at the given position, or
10067 * `null` if there is no tab area at the given position.
10068 */
10069 DockLayout.prototype.hitTestTabAreas = function (clientX, clientY) {
10070 // Bail early if hit testing cannot produce valid results.
10071 if (!this._root || !this.parent || !this.parent.isVisible) {
10072 return null;
10073 }
10074 // Ensure the parent box sizing data is computed.
10075 if (!this._box) {
10076 this._box = domutils.ElementExt.boxSizing(this.parent.node);
10077 }
10078 // Convert from client to local coordinates.
10079 var rect = this.parent.node.getBoundingClientRect();
10080 var x = clientX - rect.left - this._box.borderLeft;
10081 var y = clientY - rect.top - this._box.borderTop;
10082 // Find the tab layout node at the local position.
10083 var tabNode = this._root.hitTestTabNodes(x, y);
10084 // Bail if a tab layout node was not found.
10085 if (!tabNode) {
10086 return null;
10087 }
10088 // Extract the data from the tab node.
10089 var tabBar = tabNode.tabBar, top = tabNode.top, left = tabNode.left, width = tabNode.width, height = tabNode.height;
10090 // Compute the right and bottom edges of the tab area.
10091 var borderWidth = this._box.borderLeft + this._box.borderRight;
10092 var borderHeight = this._box.borderTop + this._box.borderBottom;
10093 var right = rect.width - borderWidth - (left + width);
10094 var bottom = rect.height - borderHeight - (top + height);
10095 // Return the hit test results.
10096 return { tabBar: tabBar, x: x, y: y, top: top, left: left, right: right, bottom: bottom, width: width, height: height };
10097 };
10098 /**
10099 * Perform layout initialization which requires the parent widget.
10100 */
10101 DockLayout.prototype.init = function () {
10102 var _this = this;
10103 // Perform superclass initialization.
10104 _super.prototype.init.call(this);
10105 // Attach each widget to the parent.
10106 algorithm.each(this, function (widget) {
10107 _this.attachWidget(widget);
10108 });
10109 // Attach each handle to the parent.
10110 algorithm.each(this.handles(), function (handle) {
10111 _this.parent.node.appendChild(handle);
10112 });
10113 // Post a fit request for the parent widget.
10114 this.parent.fit();
10115 };
10116 /**
10117 * Attach the widget to the layout parent widget.
10118 *
10119 * @param widget - The widget to attach to the parent.
10120 *
10121 * #### Notes
10122 * This is a no-op if the widget is already attached.
10123 */
10124 DockLayout.prototype.attachWidget = function (widget) {
10125 // Do nothing if the widget is already attached.
10126 if (this.parent.node === widget.node.parentNode) {
10127 return;
10128 }
10129 // Create the layout item for the widget.
10130 this._items.set(widget, new LayoutItem(widget));
10131 // Send a `'before-attach'` message if the parent is attached.
10132 if (this.parent.isAttached) {
10133 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.BeforeAttach);
10134 }
10135 // Add the widget's node to the parent.
10136 this.parent.node.appendChild(widget.node);
10137 // Send an `'after-attach'` message if the parent is attached.
10138 if (this.parent.isAttached) {
10139 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.AfterAttach);
10140 }
10141 };
10142 /**
10143 * Detach the widget from the layout parent widget.
10144 *
10145 * @param widget - The widget to detach from the parent.
10146 *
10147 * #### Notes
10148 * This is a no-op if the widget is not attached.
10149 */
10150 DockLayout.prototype.detachWidget = function (widget) {
10151 // Do nothing if the widget is not attached.
10152 if (this.parent.node !== widget.node.parentNode) {
10153 return;
10154 }
10155 // Send a `'before-detach'` message if the parent is attached.
10156 if (this.parent.isAttached) {
10157 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.BeforeDetach);
10158 }
10159 // Remove the widget's node from the parent.
10160 this.parent.node.removeChild(widget.node);
10161 // Send an `'after-detach'` message if the parent is attached.
10162 if (this.parent.isAttached) {
10163 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.AfterDetach);
10164 }
10165 // Delete the layout item for the widget.
10166 var item = this._items.get(widget);
10167 if (item) {
10168 this._items.delete(widget);
10169 item.dispose();
10170 }
10171 };
10172 /**
10173 * A message handler invoked on a `'before-show'` message.
10174 */
10175 DockLayout.prototype.onBeforeShow = function (msg) {
10176 _super.prototype.onBeforeShow.call(this, msg);
10177 this.parent.update();
10178 };
10179 /**
10180 * A message handler invoked on a `'before-attach'` message.
10181 */
10182 DockLayout.prototype.onBeforeAttach = function (msg) {
10183 _super.prototype.onBeforeAttach.call(this, msg);
10184 this.parent.fit();
10185 };
10186 /**
10187 * A message handler invoked on a `'child-shown'` message.
10188 */
10189 DockLayout.prototype.onChildShown = function (msg) {
10190 this.parent.fit();
10191 };
10192 /**
10193 * A message handler invoked on a `'child-hidden'` message.
10194 */
10195 DockLayout.prototype.onChildHidden = function (msg) {
10196 this.parent.fit();
10197 };
10198 /**
10199 * A message handler invoked on a `'resize'` message.
10200 */
10201 DockLayout.prototype.onResize = function (msg) {
10202 if (this.parent.isVisible) {
10203 this._update(msg.width, msg.height);
10204 }
10205 };
10206 /**
10207 * A message handler invoked on an `'update-request'` message.
10208 */
10209 DockLayout.prototype.onUpdateRequest = function (msg) {
10210 if (this.parent.isVisible) {
10211 this._update(-1, -1);
10212 }
10213 };
10214 /**
10215 * A message handler invoked on a `'fit-request'` message.
10216 */
10217 DockLayout.prototype.onFitRequest = function (msg) {
10218 if (this.parent.isAttached) {
10219 this._fit();
10220 }
10221 };
10222 /**
10223 * Remove the specified widget from the layout structure.
10224 *
10225 * #### Notes
10226 * This is a no-op if the widget is not in the layout tree.
10227 *
10228 * This does not detach the widget from the parent node.
10229 */
10230 DockLayout.prototype._removeWidget = function (widget) {
10231 // Bail early if there is no layout root.
10232 if (!this._root) {
10233 return;
10234 }
10235 // Find the tab node which contains the given widget.
10236 var tabNode = this._root.findTabNode(widget);
10237 // Bail early if the tab node is not found.
10238 if (!tabNode) {
10239 return;
10240 }
10241 Private$6.removeAria(widget);
10242 // If there are multiple tabs, just remove the widget's tab.
10243 if (tabNode.tabBar.titles.length > 1) {
10244 tabNode.tabBar.removeTab(widget.title);
10245 if (this._hiddenMode === exports.Widget.HiddenMode.Scale &&
10246 tabNode.tabBar.titles.length == 1) {
10247 var existingWidget = tabNode.tabBar.titles[0].owner;
10248 existingWidget.hiddenMode = exports.Widget.HiddenMode.Display;
10249 }
10250 return;
10251 }
10252 // Otherwise, the tab node needs to be removed...
10253 // Dispose the tab bar.
10254 tabNode.tabBar.dispose();
10255 // Handle the case where the tab node is the root.
10256 if (this._root === tabNode) {
10257 this._root = null;
10258 return;
10259 }
10260 // Otherwise, remove the tab node from its parent...
10261 // Prevent widget resizing unless needed.
10262 this._root.holdAllSizes();
10263 // Clear the parent reference on the tab node.
10264 var splitNode = tabNode.parent;
10265 tabNode.parent = null;
10266 // Remove the tab node from its parent split node.
10267 var i = algorithm.ArrayExt.removeFirstOf(splitNode.children, tabNode);
10268 var handle = algorithm.ArrayExt.removeAt(splitNode.handles, i);
10269 algorithm.ArrayExt.removeAt(splitNode.sizers, i);
10270 // Remove the handle from its parent DOM node.
10271 if (handle.parentNode) {
10272 handle.parentNode.removeChild(handle);
10273 }
10274 // If there are multiple children, just update the handles.
10275 if (splitNode.children.length > 1) {
10276 splitNode.syncHandles();
10277 return;
10278 }
10279 // Otherwise, the split node also needs to be removed...
10280 // Clear the parent reference on the split node.
10281 var maybeParent = splitNode.parent;
10282 splitNode.parent = null;
10283 // Lookup the remaining child node and handle.
10284 var childNode = splitNode.children[0];
10285 var childHandle = splitNode.handles[0];
10286 // Clear the split node data.
10287 splitNode.children.length = 0;
10288 splitNode.handles.length = 0;
10289 splitNode.sizers.length = 0;
10290 // Remove the child handle from its parent node.
10291 if (childHandle.parentNode) {
10292 childHandle.parentNode.removeChild(childHandle);
10293 }
10294 // Handle the case where the split node is the root.
10295 if (this._root === splitNode) {
10296 childNode.parent = null;
10297 this._root = childNode;
10298 return;
10299 }
10300 // Otherwise, move the child node to the parent node...
10301 var parentNode = maybeParent;
10302 // Lookup the index of the split node.
10303 var j = parentNode.children.indexOf(splitNode);
10304 // Handle the case where the child node is a tab node.
10305 if (childNode instanceof Private$6.TabLayoutNode) {
10306 childNode.parent = parentNode;
10307 parentNode.children[j] = childNode;
10308 return;
10309 }
10310 // Remove the split data from the parent.
10311 var splitHandle = algorithm.ArrayExt.removeAt(parentNode.handles, j);
10312 algorithm.ArrayExt.removeAt(parentNode.children, j);
10313 algorithm.ArrayExt.removeAt(parentNode.sizers, j);
10314 // Remove the handle from its parent node.
10315 if (splitHandle.parentNode) {
10316 splitHandle.parentNode.removeChild(splitHandle);
10317 }
10318 // The child node and the split parent node will have the same
10319 // orientation. Merge the grand-children with the parent node.
10320 for (var i_1 = 0, n = childNode.children.length; i_1 < n; ++i_1) {
10321 var gChild = childNode.children[i_1];
10322 var gHandle = childNode.handles[i_1];
10323 var gSizer = childNode.sizers[i_1];
10324 algorithm.ArrayExt.insert(parentNode.children, j + i_1, gChild);
10325 algorithm.ArrayExt.insert(parentNode.handles, j + i_1, gHandle);
10326 algorithm.ArrayExt.insert(parentNode.sizers, j + i_1, gSizer);
10327 gChild.parent = parentNode;
10328 }
10329 // Clear the child node.
10330 childNode.children.length = 0;
10331 childNode.handles.length = 0;
10332 childNode.sizers.length = 0;
10333 childNode.parent = null;
10334 // Sync the handles on the parent node.
10335 parentNode.syncHandles();
10336 };
10337 /**
10338 * Insert a widget next to an existing tab.
10339 *
10340 * #### Notes
10341 * This does not attach the widget to the parent widget.
10342 */
10343 DockLayout.prototype._insertTab = function (widget, ref, refNode, after) {
10344 // Do nothing if the tab is inserted next to itself.
10345 if (widget === ref) {
10346 return;
10347 }
10348 // Create the root if it does not exist.
10349 if (!this._root) {
10350 var tabNode = new Private$6.TabLayoutNode(this._createTabBar());
10351 tabNode.tabBar.addTab(widget.title);
10352 this._root = tabNode;
10353 Private$6.addAria(widget, tabNode.tabBar);
10354 return;
10355 }
10356 // Use the first tab node as the ref node if needed.
10357 if (!refNode) {
10358 refNode = this._root.findFirstTabNode();
10359 }
10360 // If the widget is not contained in the ref node, ensure it is
10361 // removed from the layout and hidden before being added again.
10362 if (refNode.tabBar.titles.indexOf(widget.title) === -1) {
10363 this._removeWidget(widget);
10364 widget.hide();
10365 }
10366 // Lookup the target index for inserting the tab.
10367 var index;
10368 if (ref) {
10369 index = refNode.tabBar.titles.indexOf(ref.title);
10370 }
10371 else {
10372 index = refNode.tabBar.currentIndex;
10373 }
10374 // Using transform create an additional layer in the pixel pipeline
10375 // to limit the number of layer, it is set only if there is more than one widget.
10376 if (this._hiddenMode === exports.Widget.HiddenMode.Scale &&
10377 refNode.tabBar.titles.length > 0) {
10378 if (refNode.tabBar.titles.length == 1) {
10379 var existingWidget = refNode.tabBar.titles[0].owner;
10380 existingWidget.hiddenMode = exports.Widget.HiddenMode.Scale;
10381 }
10382 widget.hiddenMode = exports.Widget.HiddenMode.Scale;
10383 }
10384 else {
10385 widget.hiddenMode = exports.Widget.HiddenMode.Display;
10386 }
10387 // Insert the widget's tab relative to the target index.
10388 refNode.tabBar.insertTab(index + (after ? 1 : 0), widget.title);
10389 Private$6.addAria(widget, refNode.tabBar);
10390 };
10391 /**
10392 * Insert a widget as a new split area.
10393 *
10394 * #### Notes
10395 * This does not attach the widget to the parent widget.
10396 */
10397 DockLayout.prototype._insertSplit = function (widget, ref, refNode, orientation, after) {
10398 // Do nothing if there is no effective split.
10399 if (widget === ref && refNode && refNode.tabBar.titles.length === 1) {
10400 return;
10401 }
10402 // Ensure the widget is removed from the current layout.
10403 this._removeWidget(widget);
10404 // Create the tab layout node to hold the widget.
10405 var tabNode = new Private$6.TabLayoutNode(this._createTabBar());
10406 tabNode.tabBar.addTab(widget.title);
10407 Private$6.addAria(widget, tabNode.tabBar);
10408 // Set the root if it does not exist.
10409 if (!this._root) {
10410 this._root = tabNode;
10411 return;
10412 }
10413 // If the ref node parent is null, split the root.
10414 if (!refNode || !refNode.parent) {
10415 // Ensure the root is split with the correct orientation.
10416 var root = this._splitRoot(orientation);
10417 // Determine the insert index for the new tab node.
10418 var i_2 = after ? root.children.length : 0;
10419 // Normalize the split node.
10420 root.normalizeSizes();
10421 // Create the sizer for new tab node.
10422 var sizer = Private$6.createSizer(refNode ? 1 : Private$6.GOLDEN_RATIO);
10423 // Insert the tab node sized to the golden ratio.
10424 algorithm.ArrayExt.insert(root.children, i_2, tabNode);
10425 algorithm.ArrayExt.insert(root.sizers, i_2, sizer);
10426 algorithm.ArrayExt.insert(root.handles, i_2, this._createHandle());
10427 tabNode.parent = root;
10428 // Re-normalize the split node to maintain the ratios.
10429 root.normalizeSizes();
10430 // Finally, synchronize the visibility of the handles.
10431 root.syncHandles();
10432 return;
10433 }
10434 // Lookup the split node for the ref widget.
10435 var splitNode = refNode.parent;
10436 // If the split node already had the correct orientation,
10437 // the widget can be inserted into the split node directly.
10438 if (splitNode.orientation === orientation) {
10439 // Find the index of the ref node.
10440 var i_3 = splitNode.children.indexOf(refNode);
10441 // Normalize the split node.
10442 splitNode.normalizeSizes();
10443 // Consume half the space for the insert location.
10444 var s = (splitNode.sizers[i_3].sizeHint /= 2);
10445 // Insert the tab node sized to the other half.
10446 var j_1 = i_3 + (after ? 1 : 0);
10447 algorithm.ArrayExt.insert(splitNode.children, j_1, tabNode);
10448 algorithm.ArrayExt.insert(splitNode.sizers, j_1, Private$6.createSizer(s));
10449 algorithm.ArrayExt.insert(splitNode.handles, j_1, this._createHandle());
10450 tabNode.parent = splitNode;
10451 // Finally, synchronize the visibility of the handles.
10452 splitNode.syncHandles();
10453 return;
10454 }
10455 // Remove the ref node from the split node.
10456 var i = algorithm.ArrayExt.removeFirstOf(splitNode.children, refNode);
10457 // Create a new normalized split node for the children.
10458 var childNode = new Private$6.SplitLayoutNode(orientation);
10459 childNode.normalized = true;
10460 // Add the ref node sized to half the space.
10461 childNode.children.push(refNode);
10462 childNode.sizers.push(Private$6.createSizer(0.5));
10463 childNode.handles.push(this._createHandle());
10464 refNode.parent = childNode;
10465 // Add the tab node sized to the other half.
10466 var j = after ? 1 : 0;
10467 algorithm.ArrayExt.insert(childNode.children, j, tabNode);
10468 algorithm.ArrayExt.insert(childNode.sizers, j, Private$6.createSizer(0.5));
10469 algorithm.ArrayExt.insert(childNode.handles, j, this._createHandle());
10470 tabNode.parent = childNode;
10471 // Synchronize the visibility of the handles.
10472 childNode.syncHandles();
10473 // Finally, add the new child node to the original split node.
10474 algorithm.ArrayExt.insert(splitNode.children, i, childNode);
10475 childNode.parent = splitNode;
10476 };
10477 /**
10478 * Ensure the root is a split node with the given orientation.
10479 */
10480 DockLayout.prototype._splitRoot = function (orientation) {
10481 // Bail early if the root already meets the requirements.
10482 var oldRoot = this._root;
10483 if (oldRoot instanceof Private$6.SplitLayoutNode) {
10484 if (oldRoot.orientation === orientation) {
10485 return oldRoot;
10486 }
10487 }
10488 // Create a new root node with the specified orientation.
10489 var newRoot = (this._root = new Private$6.SplitLayoutNode(orientation));
10490 // Add the old root to the new root.
10491 if (oldRoot) {
10492 newRoot.children.push(oldRoot);
10493 newRoot.sizers.push(Private$6.createSizer(0));
10494 newRoot.handles.push(this._createHandle());
10495 oldRoot.parent = newRoot;
10496 }
10497 // Return the new root as a convenience.
10498 return newRoot;
10499 };
10500 /**
10501 * Fit the layout to the total size required by the widgets.
10502 */
10503 DockLayout.prototype._fit = function () {
10504 // Set up the computed minimum size.
10505 var minW = 0;
10506 var minH = 0;
10507 // Update the size limits for the layout tree.
10508 if (this._root) {
10509 var limits = this._root.fit(this._spacing, this._items);
10510 minW = limits.minWidth;
10511 minH = limits.minHeight;
10512 }
10513 // Update the box sizing and add it to the computed min size.
10514 var box = (this._box = domutils.ElementExt.boxSizing(this.parent.node));
10515 minW += box.horizontalSum;
10516 minH += box.verticalSum;
10517 // Update the parent's min size constraints.
10518 var style = this.parent.node.style;
10519 style.minWidth = minW + "px";
10520 style.minHeight = minH + "px";
10521 // Set the dirty flag to ensure only a single update occurs.
10522 this._dirty = true;
10523 // Notify the ancestor that it should fit immediately. This may
10524 // cause a resize of the parent, fulfilling the required update.
10525 if (this.parent.parent) {
10526 messaging.MessageLoop.sendMessage(this.parent.parent, exports.Widget.Msg.FitRequest);
10527 }
10528 // If the dirty flag is still set, the parent was not resized.
10529 // Trigger the required update on the parent widget immediately.
10530 if (this._dirty) {
10531 messaging.MessageLoop.sendMessage(this.parent, exports.Widget.Msg.UpdateRequest);
10532 }
10533 };
10534 /**
10535 * Update the layout position and size of the widgets.
10536 *
10537 * The parent offset dimensions should be `-1` if unknown.
10538 */
10539 DockLayout.prototype._update = function (offsetWidth, offsetHeight) {
10540 // Clear the dirty flag to indicate the update occurred.
10541 this._dirty = false;
10542 // Bail early if there is no root layout node.
10543 if (!this._root) {
10544 return;
10545 }
10546 // Measure the parent if the offset dimensions are unknown.
10547 if (offsetWidth < 0) {
10548 offsetWidth = this.parent.node.offsetWidth;
10549 }
10550 if (offsetHeight < 0) {
10551 offsetHeight = this.parent.node.offsetHeight;
10552 }
10553 // Ensure the parent box sizing data is computed.
10554 if (!this._box) {
10555 this._box = domutils.ElementExt.boxSizing(this.parent.node);
10556 }
10557 // Compute the actual layout bounds adjusted for border and padding.
10558 var x = this._box.paddingTop;
10559 var y = this._box.paddingLeft;
10560 var width = offsetWidth - this._box.horizontalSum;
10561 var height = offsetHeight - this._box.verticalSum;
10562 // Update the geometry of the layout tree.
10563 this._root.update(x, y, width, height, this._spacing, this._items);
10564 };
10565 /**
10566 * Create a new tab bar for use by the dock layout.
10567 *
10568 * #### Notes
10569 * The tab bar will be attached to the parent if it exists.
10570 */
10571 DockLayout.prototype._createTabBar = function () {
10572 // Create the tab bar using the renderer.
10573 var tabBar = this.renderer.createTabBar(this._document);
10574 // Enforce necessary tab bar behavior.
10575 tabBar.orientation = 'horizontal';
10576 // Reparent and attach the tab bar to the parent if possible.
10577 if (this.parent) {
10578 tabBar.parent = this.parent;
10579 this.attachWidget(tabBar);
10580 }
10581 // Return the initialized tab bar.
10582 return tabBar;
10583 };
10584 /**
10585 * Create a new handle for the dock layout.
10586 *
10587 * #### Notes
10588 * The handle will be attached to the parent if it exists.
10589 */
10590 DockLayout.prototype._createHandle = function () {
10591 // Create the handle using the renderer.
10592 var handle = this.renderer.createHandle();
10593 // Initialize the handle layout behavior.
10594 var style = handle.style;
10595 style.position = 'absolute';
10596 style.top = '0';
10597 style.left = '0';
10598 style.width = '0';
10599 style.height = '0';
10600 // Attach the handle to the parent if it exists.
10601 if (this.parent) {
10602 this.parent.node.appendChild(handle);
10603 }
10604 // Return the initialized handle.
10605 return handle;
10606 };
10607 return DockLayout;
10608 }(exports.Layout));
10609 /**
10610 * The namespace for the module implementation details.
10611 */
10612 var Private$6;
10613 (function (Private) {
10614 /**
10615 * A fraction used for sizing root panels; ~= `1 / golden_ratio`.
10616 */
10617 Private.GOLDEN_RATIO = 0.618;
10618 /**
10619 * Create a box sizer with an initial size hint.
10620 */
10621 function createSizer(hint) {
10622 var sizer = new BoxSizer();
10623 sizer.sizeHint = hint;
10624 sizer.size = hint;
10625 return sizer;
10626 }
10627 Private.createSizer = createSizer;
10628 /**
10629 * Normalize an area config object and collect the visited widgets.
10630 */
10631 function normalizeAreaConfig(config, widgetSet) {
10632 var result;
10633 if (config.type === 'tab-area') {
10634 result = normalizeTabAreaConfig(config, widgetSet);
10635 }
10636 else {
10637 result = normalizeSplitAreaConfig(config, widgetSet);
10638 }
10639 return result;
10640 }
10641 Private.normalizeAreaConfig = normalizeAreaConfig;
10642 /**
10643 * Convert a normalized area config into a layout tree.
10644 */
10645 function realizeAreaConfig(config, renderer, document) {
10646 var node;
10647 if (config.type === 'tab-area') {
10648 node = realizeTabAreaConfig(config, renderer, document);
10649 }
10650 else {
10651 node = realizeSplitAreaConfig(config, renderer, document);
10652 }
10653 return node;
10654 }
10655 Private.realizeAreaConfig = realizeAreaConfig;
10656 /**
10657 * A layout node which holds the data for a tabbed area.
10658 */
10659 var TabLayoutNode = /** @class */ (function () {
10660 /**
10661 * Construct a new tab layout node.
10662 *
10663 * @param tabBar - The tab bar to use for the layout node.
10664 */
10665 function TabLayoutNode(tabBar) {
10666 /**
10667 * The parent of the layout node.
10668 */
10669 this.parent = null;
10670 this._top = 0;
10671 this._left = 0;
10672 this._width = 0;
10673 this._height = 0;
10674 var tabSizer = new BoxSizer();
10675 var widgetSizer = new BoxSizer();
10676 tabSizer.stretch = 0;
10677 widgetSizer.stretch = 1;
10678 this.tabBar = tabBar;
10679 this.sizers = [tabSizer, widgetSizer];
10680 }
10681 Object.defineProperty(TabLayoutNode.prototype, "top", {
10682 /**
10683 * The most recent value for the `top` edge of the layout box.
10684 */
10685 get: function () {
10686 return this._top;
10687 },
10688 enumerable: true,
10689 configurable: true
10690 });
10691 Object.defineProperty(TabLayoutNode.prototype, "left", {
10692 /**
10693 * The most recent value for the `left` edge of the layout box.
10694 */
10695 get: function () {
10696 return this._left;
10697 },
10698 enumerable: true,
10699 configurable: true
10700 });
10701 Object.defineProperty(TabLayoutNode.prototype, "width", {
10702 /**
10703 * The most recent value for the `width` of the layout box.
10704 */
10705 get: function () {
10706 return this._width;
10707 },
10708 enumerable: true,
10709 configurable: true
10710 });
10711 Object.defineProperty(TabLayoutNode.prototype, "height", {
10712 /**
10713 * The most recent value for the `height` of the layout box.
10714 */
10715 get: function () {
10716 return this._height;
10717 },
10718 enumerable: true,
10719 configurable: true
10720 });
10721 /**
10722 * Create an iterator for all widgets in the layout tree.
10723 */
10724 TabLayoutNode.prototype.iterAllWidgets = function () {
10725 return algorithm.chain(algorithm.once(this.tabBar), this.iterUserWidgets());
10726 };
10727 /**
10728 * Create an iterator for the user widgets in the layout tree.
10729 */
10730 TabLayoutNode.prototype.iterUserWidgets = function () {
10731 return algorithm.map(this.tabBar.titles, function (title) { return title.owner; });
10732 };
10733 /**
10734 * Create an iterator for the selected widgets in the layout tree.
10735 */
10736 TabLayoutNode.prototype.iterSelectedWidgets = function () {
10737 var title = this.tabBar.currentTitle;
10738 return title ? algorithm.once(title.owner) : algorithm.empty();
10739 };
10740 /**
10741 * Create an iterator for the tab bars in the layout tree.
10742 */
10743 TabLayoutNode.prototype.iterTabBars = function () {
10744 return algorithm.once(this.tabBar);
10745 };
10746 /**
10747 * Create an iterator for the handles in the layout tree.
10748 */
10749 TabLayoutNode.prototype.iterHandles = function () {
10750 return algorithm.empty();
10751 };
10752 /**
10753 * Find the tab layout node which contains the given widget.
10754 */
10755 TabLayoutNode.prototype.findTabNode = function (widget) {
10756 return this.tabBar.titles.indexOf(widget.title) !== -1 ? this : null;
10757 };
10758 /**
10759 * Find the split layout node which contains the given handle.
10760 */
10761 TabLayoutNode.prototype.findSplitNode = function (handle) {
10762 return null;
10763 };
10764 /**
10765 * Find the first tab layout node in a layout tree.
10766 */
10767 TabLayoutNode.prototype.findFirstTabNode = function () {
10768 return this;
10769 };
10770 /**
10771 * Find the tab layout node which contains the local point.
10772 */
10773 TabLayoutNode.prototype.hitTestTabNodes = function (x, y) {
10774 if (x < this._left || x >= this._left + this._width) {
10775 return null;
10776 }
10777 if (y < this._top || y >= this._top + this._height) {
10778 return null;
10779 }
10780 return this;
10781 };
10782 /**
10783 * Create a configuration object for the layout tree.
10784 */
10785 TabLayoutNode.prototype.createConfig = function () {
10786 var widgets = this.tabBar.titles.map(function (title) { return title.owner; });
10787 var currentIndex = this.tabBar.currentIndex;
10788 return { type: 'tab-area', widgets: widgets, currentIndex: currentIndex };
10789 };
10790 /**
10791 * Recursively hold all of the sizes in the layout tree.
10792 *
10793 * This ignores the sizers of tab layout nodes.
10794 */
10795 TabLayoutNode.prototype.holdAllSizes = function () {
10796 return;
10797 };
10798 /**
10799 * Fit the layout tree.
10800 */
10801 TabLayoutNode.prototype.fit = function (spacing, items) {
10802 // Set up the limit variables.
10803 var minWidth = 0;
10804 var minHeight = 0;
10805 var maxWidth = Infinity;
10806 var maxHeight = Infinity;
10807 // Lookup the tab bar layout item.
10808 var tabBarItem = items.get(this.tabBar);
10809 // Lookup the widget layout item.
10810 var current = this.tabBar.currentTitle;
10811 var widgetItem = current ? items.get(current.owner) : undefined;
10812 // Lookup the tab bar and widget sizers.
10813 var _a = this.sizers, tabBarSizer = _a[0], widgetSizer = _a[1];
10814 // Update the tab bar limits.
10815 if (tabBarItem) {
10816 tabBarItem.fit();
10817 }
10818 // Update the widget limits.
10819 if (widgetItem) {
10820 widgetItem.fit();
10821 }
10822 // Update the results and sizer for the tab bar.
10823 if (tabBarItem && !tabBarItem.isHidden) {
10824 minWidth = Math.max(minWidth, tabBarItem.minWidth);
10825 minHeight += tabBarItem.minHeight;
10826 tabBarSizer.minSize = tabBarItem.minHeight;
10827 tabBarSizer.maxSize = tabBarItem.maxHeight;
10828 }
10829 else {
10830 tabBarSizer.minSize = 0;
10831 tabBarSizer.maxSize = 0;
10832 }
10833 // Update the results and sizer for the current widget.
10834 if (widgetItem && !widgetItem.isHidden) {
10835 minWidth = Math.max(minWidth, widgetItem.minWidth);
10836 minHeight += widgetItem.minHeight;
10837 widgetSizer.minSize = widgetItem.minHeight;
10838 widgetSizer.maxSize = Infinity;
10839 }
10840 else {
10841 widgetSizer.minSize = 0;
10842 widgetSizer.maxSize = Infinity;
10843 }
10844 // Return the computed size limits for the layout node.
10845 return { minWidth: minWidth, minHeight: minHeight, maxWidth: maxWidth, maxHeight: maxHeight };
10846 };
10847 /**
10848 * Update the layout tree.
10849 */
10850 TabLayoutNode.prototype.update = function (left, top, width, height, spacing, items) {
10851 // Update the layout box values.
10852 this._top = top;
10853 this._left = left;
10854 this._width = width;
10855 this._height = height;
10856 // Lookup the tab bar layout item.
10857 var tabBarItem = items.get(this.tabBar);
10858 // Lookup the widget layout item.
10859 var current = this.tabBar.currentTitle;
10860 var widgetItem = current ? items.get(current.owner) : undefined;
10861 // Distribute the layout space to the sizers.
10862 exports.BoxEngine.calc(this.sizers, height);
10863 // Update the tab bar item using the computed size.
10864 if (tabBarItem && !tabBarItem.isHidden) {
10865 var size = this.sizers[0].size;
10866 tabBarItem.update(left, top, width, size);
10867 top += size;
10868 }
10869 // Layout the widget using the computed size.
10870 if (widgetItem && !widgetItem.isHidden) {
10871 var size = this.sizers[1].size;
10872 widgetItem.update(left, top, width, size);
10873 }
10874 };
10875 return TabLayoutNode;
10876 }());
10877 Private.TabLayoutNode = TabLayoutNode;
10878 /**
10879 * A layout node which holds the data for a split area.
10880 */
10881 var SplitLayoutNode = /** @class */ (function () {
10882 /**
10883 * Construct a new split layout node.
10884 *
10885 * @param orientation - The orientation of the node.
10886 */
10887 function SplitLayoutNode(orientation) {
10888 /**
10889 * The parent of the layout node.
10890 */
10891 this.parent = null;
10892 /**
10893 * Whether the sizers have been normalized.
10894 */
10895 this.normalized = false;
10896 /**
10897 * The child nodes for the split node.
10898 */
10899 this.children = [];
10900 /**
10901 * The box sizers for the layout children.
10902 */
10903 this.sizers = [];
10904 /**
10905 * The handles for the layout children.
10906 */
10907 this.handles = [];
10908 this.orientation = orientation;
10909 }
10910 /**
10911 * Create an iterator for all widgets in the layout tree.
10912 */
10913 SplitLayoutNode.prototype.iterAllWidgets = function () {
10914 var children = algorithm.map(this.children, function (child) { return child.iterAllWidgets(); });
10915 return new algorithm.ChainIterator(children);
10916 };
10917 /**
10918 * Create an iterator for the user widgets in the layout tree.
10919 */
10920 SplitLayoutNode.prototype.iterUserWidgets = function () {
10921 var children = algorithm.map(this.children, function (child) { return child.iterUserWidgets(); });
10922 return new algorithm.ChainIterator(children);
10923 };
10924 /**
10925 * Create an iterator for the selected widgets in the layout tree.
10926 */
10927 SplitLayoutNode.prototype.iterSelectedWidgets = function () {
10928 var children = algorithm.map(this.children, function (child) { return child.iterSelectedWidgets(); });
10929 return new algorithm.ChainIterator(children);
10930 };
10931 /**
10932 * Create an iterator for the tab bars in the layout tree.
10933 */
10934 SplitLayoutNode.prototype.iterTabBars = function () {
10935 var children = algorithm.map(this.children, function (child) { return child.iterTabBars(); });
10936 return new algorithm.ChainIterator(children);
10937 };
10938 /**
10939 * Create an iterator for the handles in the layout tree.
10940 */
10941 SplitLayoutNode.prototype.iterHandles = function () {
10942 var children = algorithm.map(this.children, function (child) { return child.iterHandles(); });
10943 return algorithm.chain(this.handles, new algorithm.ChainIterator(children));
10944 };
10945 /**
10946 * Find the tab layout node which contains the given widget.
10947 */
10948 SplitLayoutNode.prototype.findTabNode = function (widget) {
10949 for (var i = 0, n = this.children.length; i < n; ++i) {
10950 var result = this.children[i].findTabNode(widget);
10951 if (result) {
10952 return result;
10953 }
10954 }
10955 return null;
10956 };
10957 /**
10958 * Find the split layout node which contains the given handle.
10959 */
10960 SplitLayoutNode.prototype.findSplitNode = function (handle) {
10961 var index = this.handles.indexOf(handle);
10962 if (index !== -1) {
10963 return { index: index, node: this };
10964 }
10965 for (var i = 0, n = this.children.length; i < n; ++i) {
10966 var result = this.children[i].findSplitNode(handle);
10967 if (result) {
10968 return result;
10969 }
10970 }
10971 return null;
10972 };
10973 /**
10974 * Find the first tab layout node in a layout tree.
10975 */
10976 SplitLayoutNode.prototype.findFirstTabNode = function () {
10977 if (this.children.length === 0) {
10978 return null;
10979 }
10980 return this.children[0].findFirstTabNode();
10981 };
10982 /**
10983 * Find the tab layout node which contains the local point.
10984 */
10985 SplitLayoutNode.prototype.hitTestTabNodes = function (x, y) {
10986 for (var i = 0, n = this.children.length; i < n; ++i) {
10987 var result = this.children[i].hitTestTabNodes(x, y);
10988 if (result) {
10989 return result;
10990 }
10991 }
10992 return null;
10993 };
10994 /**
10995 * Create a configuration object for the layout tree.
10996 */
10997 SplitLayoutNode.prototype.createConfig = function () {
10998 var orientation = this.orientation;
10999 var sizes = this.createNormalizedSizes();
11000 var children = this.children.map(function (child) { return child.createConfig(); });
11001 return { type: 'split-area', orientation: orientation, children: children, sizes: sizes };
11002 };
11003 /**
11004 * Sync the visibility and orientation of the handles.
11005 */
11006 SplitLayoutNode.prototype.syncHandles = function () {
11007 var _this = this;
11008 algorithm.each(this.handles, function (handle, i) {
11009 handle.setAttribute('data-orientation', _this.orientation);
11010 if (i === _this.handles.length - 1) {
11011 handle.classList.add('lm-mod-hidden');
11012 /* <DEPRECATED> */
11013 handle.classList.add('p-mod-hidden');
11014 /* </DEPRECATED> */
11015 }
11016 else {
11017 handle.classList.remove('lm-mod-hidden');
11018 /* <DEPRECATED> */
11019 handle.classList.remove('p-mod-hidden');
11020 /* </DEPRECATED> */
11021 }
11022 });
11023 };
11024 /**
11025 * Hold the current sizes of the box sizers.
11026 *
11027 * This sets the size hint of each sizer to its current size.
11028 */
11029 SplitLayoutNode.prototype.holdSizes = function () {
11030 algorithm.each(this.sizers, function (sizer) {
11031 sizer.sizeHint = sizer.size;
11032 });
11033 };
11034 /**
11035 * Recursively hold all of the sizes in the layout tree.
11036 *
11037 * This ignores the sizers of tab layout nodes.
11038 */
11039 SplitLayoutNode.prototype.holdAllSizes = function () {
11040 algorithm.each(this.children, function (child) { return child.holdAllSizes(); });
11041 this.holdSizes();
11042 };
11043 /**
11044 * Normalize the sizes of the split layout node.
11045 */
11046 SplitLayoutNode.prototype.normalizeSizes = function () {
11047 // Bail early if the sizers are empty.
11048 var n = this.sizers.length;
11049 if (n === 0) {
11050 return;
11051 }
11052 // Hold the current sizes of the sizers.
11053 this.holdSizes();
11054 // Compute the sum of the sizes.
11055 var sum = algorithm.reduce(this.sizers, function (v, sizer) { return v + sizer.sizeHint; }, 0);
11056 // Normalize the sizes based on the sum.
11057 if (sum === 0) {
11058 algorithm.each(this.sizers, function (sizer) {
11059 sizer.size = sizer.sizeHint = 1 / n;
11060 });
11061 }
11062 else {
11063 algorithm.each(this.sizers, function (sizer) {
11064 sizer.size = sizer.sizeHint /= sum;
11065 });
11066 }
11067 // Mark the sizes as normalized.
11068 this.normalized = true;
11069 };
11070 /**
11071 * Snap the normalized sizes of the split layout node.
11072 */
11073 SplitLayoutNode.prototype.createNormalizedSizes = function () {
11074 // Bail early if the sizers are empty.
11075 var n = this.sizers.length;
11076 if (n === 0) {
11077 return [];
11078 }
11079 // Grab the current sizes of the sizers.
11080 var sizes = this.sizers.map(function (sizer) { return sizer.size; });
11081 // Compute the sum of the sizes.
11082 var sum = algorithm.reduce(sizes, function (v, size) { return v + size; }, 0);
11083 // Normalize the sizes based on the sum.
11084 if (sum === 0) {
11085 algorithm.each(sizes, function (size, i) {
11086 sizes[i] = 1 / n;
11087 });
11088 }
11089 else {
11090 algorithm.each(sizes, function (size, i) {
11091 sizes[i] = size / sum;
11092 });
11093 }
11094 // Return the normalized sizes.
11095 return sizes;
11096 };
11097 /**
11098 * Fit the layout tree.
11099 */
11100 SplitLayoutNode.prototype.fit = function (spacing, items) {
11101 // Compute the required fixed space.
11102 var horizontal = this.orientation === 'horizontal';
11103 var fixed = Math.max(0, this.children.length - 1) * spacing;
11104 // Set up the limit variables.
11105 var minWidth = horizontal ? fixed : 0;
11106 var minHeight = horizontal ? 0 : fixed;
11107 var maxWidth = Infinity;
11108 var maxHeight = Infinity;
11109 // Fit the children and update the limits.
11110 for (var i = 0, n = this.children.length; i < n; ++i) {
11111 var limits = this.children[i].fit(spacing, items);
11112 if (horizontal) {
11113 minHeight = Math.max(minHeight, limits.minHeight);
11114 minWidth += limits.minWidth;
11115 this.sizers[i].minSize = limits.minWidth;
11116 }
11117 else {
11118 minWidth = Math.max(minWidth, limits.minWidth);
11119 minHeight += limits.minHeight;
11120 this.sizers[i].minSize = limits.minHeight;
11121 }
11122 }
11123 // Return the computed limits for the layout node.
11124 return { minWidth: minWidth, minHeight: minHeight, maxWidth: maxWidth, maxHeight: maxHeight };
11125 };
11126 /**
11127 * Update the layout tree.
11128 */
11129 SplitLayoutNode.prototype.update = function (left, top, width, height, spacing, items) {
11130 // Compute the available layout space.
11131 var horizontal = this.orientation === 'horizontal';
11132 var fixed = Math.max(0, this.children.length - 1) * spacing;
11133 var space = Math.max(0, (horizontal ? width : height) - fixed);
11134 // De-normalize the sizes if needed.
11135 if (this.normalized) {
11136 algorithm.each(this.sizers, function (sizer) {
11137 sizer.sizeHint *= space;
11138 });
11139 this.normalized = false;
11140 }
11141 // Distribute the layout space to the sizers.
11142 exports.BoxEngine.calc(this.sizers, space);
11143 // Update the geometry of the child nodes and handles.
11144 for (var i = 0, n = this.children.length; i < n; ++i) {
11145 var child = this.children[i];
11146 var size = this.sizers[i].size;
11147 var handleStyle = this.handles[i].style;
11148 if (horizontal) {
11149 child.update(left, top, size, height, spacing, items);
11150 left += size;
11151 handleStyle.top = top + "px";
11152 handleStyle.left = left + "px";
11153 handleStyle.width = spacing + "px";
11154 handleStyle.height = height + "px";
11155 left += spacing;
11156 }
11157 else {
11158 child.update(left, top, width, size, spacing, items);
11159 top += size;
11160 handleStyle.top = top + "px";
11161 handleStyle.left = left + "px";
11162 handleStyle.width = width + "px";
11163 handleStyle.height = spacing + "px";
11164 top += spacing;
11165 }
11166 }
11167 };
11168 return SplitLayoutNode;
11169 }());
11170 Private.SplitLayoutNode = SplitLayoutNode;
11171 function addAria(widget, tabBar) {
11172 widget.node.setAttribute('role', 'tabpanel');
11173 var renderer = tabBar.renderer;
11174 if (renderer instanceof exports.TabBar.Renderer) {
11175 var tabId = renderer.createTabKey({
11176 title: widget.title,
11177 current: false,
11178 zIndex: 0
11179 });
11180 widget.node.setAttribute('aria-labelledby', tabId);
11181 }
11182 }
11183 Private.addAria = addAria;
11184 function removeAria(widget) {
11185 widget.node.removeAttribute('role');
11186 widget.node.removeAttribute('aria-labelledby');
11187 }
11188 Private.removeAria = removeAria;
11189 /**
11190 * Normalize a tab area config and collect the visited widgets.
11191 */
11192 function normalizeTabAreaConfig(config, widgetSet) {
11193 // Bail early if there is no content.
11194 if (config.widgets.length === 0) {
11195 return null;
11196 }
11197 // Setup the filtered widgets array.
11198 var widgets = [];
11199 // Filter the config for unique widgets.
11200 algorithm.each(config.widgets, function (widget) {
11201 if (!widgetSet.has(widget)) {
11202 widgetSet.add(widget);
11203 widgets.push(widget);
11204 }
11205 });
11206 // Bail if there are no effective widgets.
11207 if (widgets.length === 0) {
11208 return null;
11209 }
11210 // Normalize the current index.
11211 var index = config.currentIndex;
11212 if (index !== -1 && (index < 0 || index >= widgets.length)) {
11213 index = 0;
11214 }
11215 // Return a normalized config object.
11216 return { type: 'tab-area', widgets: widgets, currentIndex: index };
11217 }
11218 /**
11219 * Normalize a split area config and collect the visited widgets.
11220 */
11221 function normalizeSplitAreaConfig(config, widgetSet) {
11222 // Set up the result variables.
11223 var orientation = config.orientation;
11224 var children = [];
11225 var sizes = [];
11226 // Normalize the config children.
11227 for (var i = 0, n = config.children.length; i < n; ++i) {
11228 // Normalize the child config.
11229 var child = normalizeAreaConfig(config.children[i], widgetSet);
11230 // Ignore an empty child.
11231 if (!child) {
11232 continue;
11233 }
11234 // Add the child or hoist its content as appropriate.
11235 if (child.type === 'tab-area' || child.orientation !== orientation) {
11236 children.push(child);
11237 sizes.push(Math.abs(config.sizes[i] || 0));
11238 }
11239 else {
11240 children.push.apply(children, child.children);
11241 sizes.push.apply(sizes, child.sizes);
11242 }
11243 }
11244 // Bail if there are no effective children.
11245 if (children.length === 0) {
11246 return null;
11247 }
11248 // If there is only one effective child, return that child.
11249 if (children.length === 1) {
11250 return children[0];
11251 }
11252 // Return a normalized config object.
11253 return { type: 'split-area', orientation: orientation, children: children, sizes: sizes };
11254 }
11255 /**
11256 * Convert a normalized tab area config into a layout tree.
11257 */
11258 function realizeTabAreaConfig(config, renderer, document) {
11259 // Create the tab bar for the layout node.
11260 var tabBar = renderer.createTabBar(document);
11261 // Hide each widget and add it to the tab bar.
11262 algorithm.each(config.widgets, function (widget) {
11263 widget.hide();
11264 tabBar.addTab(widget.title);
11265 Private.addAria(widget, tabBar);
11266 });
11267 // Set the current index of the tab bar.
11268 tabBar.currentIndex = config.currentIndex;
11269 // Return the new tab layout node.
11270 return new TabLayoutNode(tabBar);
11271 }
11272 /**
11273 * Convert a normalized split area config into a layout tree.
11274 */
11275 function realizeSplitAreaConfig(config, renderer, document) {
11276 // Create the split layout node.
11277 var node = new SplitLayoutNode(config.orientation);
11278 // Add each child to the layout node.
11279 algorithm.each(config.children, function (child, i) {
11280 // Create the child data for the layout node.
11281 var childNode = realizeAreaConfig(child, renderer, document);
11282 var sizer = createSizer(config.sizes[i]);
11283 var handle = renderer.createHandle();
11284 // Add the child data to the layout node.
11285 node.children.push(childNode);
11286 node.handles.push(handle);
11287 node.sizers.push(sizer);
11288 // Update the parent for the child node.
11289 childNode.parent = node;
11290 });
11291 // Synchronize the handle state for the layout node.
11292 node.syncHandles();
11293 // Normalize the sizes for the layout node.
11294 node.normalizeSizes();
11295 // Return the new layout node.
11296 return node;
11297 }
11298 })(Private$6 || (Private$6 = {}));
11299
11300 /**
11301 * A widget which provides a flexible docking area for widgets.
11302 */
11303 exports.DockPanel = /** @class */ (function (_super) {
11304 __extends(DockPanel, _super);
11305 /**
11306 * Construct a new dock panel.
11307 *
11308 * @param options - The options for initializing the panel.
11309 */
11310 function DockPanel(options) {
11311 if (options === void 0) { options = {}; }
11312 var _this = _super.call(this) || this;
11313 _this._drag = null;
11314 _this._tabsMovable = true;
11315 _this._tabsConstrained = false;
11316 _this._addButtonEnabled = false;
11317 _this._pressData = null;
11318 _this._layoutModified = new signaling.Signal(_this);
11319 _this._addRequested = new signaling.Signal(_this);
11320 _this.addClass('lm-DockPanel');
11321 /* <DEPRECATED> */
11322 _this.addClass('p-DockPanel');
11323 /* </DEPRECATED> */
11324 _this._document = options.document || document;
11325 _this._mode = options.mode || 'multiple-document';
11326 _this._renderer = options.renderer || DockPanel.defaultRenderer;
11327 _this._edges = options.edges || Private$5.DEFAULT_EDGES;
11328 if (options.tabsMovable !== undefined) {
11329 _this._tabsMovable = options.tabsMovable;
11330 }
11331 if (options.tabsConstrained !== undefined) {
11332 _this._tabsConstrained = options.tabsConstrained;
11333 }
11334 if (options.addButtonEnabled !== undefined) {
11335 _this._addButtonEnabled = options.addButtonEnabled;
11336 }
11337 // Toggle the CSS mode attribute.
11338 _this.dataset['mode'] = _this._mode;
11339 // Create the delegate renderer for the layout.
11340 var renderer = {
11341 createTabBar: function () { return _this._createTabBar(); },
11342 createHandle: function () { return _this._createHandle(); }
11343 };
11344 // Set up the dock layout for the panel.
11345 _this.layout = new DockLayout({
11346 document: _this._document,
11347 renderer: renderer,
11348 spacing: options.spacing,
11349 hiddenMode: options.hiddenMode
11350 });
11351 // Set up the overlay drop indicator.
11352 _this.overlay = options.overlay || new DockPanel.Overlay();
11353 _this.node.appendChild(_this.overlay.node);
11354 return _this;
11355 }
11356 /**
11357 * Dispose of the resources held by the panel.
11358 */
11359 DockPanel.prototype.dispose = function () {
11360 // Ensure the mouse is released.
11361 this._releaseMouse();
11362 // Hide the overlay.
11363 this.overlay.hide(0);
11364 // Cancel a drag if one is in progress.
11365 if (this._drag) {
11366 this._drag.dispose();
11367 }
11368 // Dispose of the base class.
11369 _super.prototype.dispose.call(this);
11370 };
11371 Object.defineProperty(DockPanel.prototype, "hiddenMode", {
11372 /**
11373 * The method for hiding widgets.
11374 */
11375 get: function () {
11376 return this.layout.hiddenMode;
11377 },
11378 /**
11379 * Set the method for hiding widgets.
11380 */
11381 set: function (v) {
11382 this.layout.hiddenMode = v;
11383 },
11384 enumerable: true,
11385 configurable: true
11386 });
11387 Object.defineProperty(DockPanel.prototype, "layoutModified", {
11388 /**
11389 * A signal emitted when the layout configuration is modified.
11390 *
11391 * #### Notes
11392 * This signal is emitted whenever the current layout configuration
11393 * may have changed.
11394 *
11395 * This signal is emitted asynchronously in a collapsed fashion, so
11396 * that multiple synchronous modifications results in only a single
11397 * emit of the signal.
11398 */
11399 get: function () {
11400 return this._layoutModified;
11401 },
11402 enumerable: true,
11403 configurable: true
11404 });
11405 Object.defineProperty(DockPanel.prototype, "addRequested", {
11406 /**
11407 * A signal emitted when the add button on a tab bar is clicked.
11408 *
11409 */
11410 get: function () {
11411 return this._addRequested;
11412 },
11413 enumerable: true,
11414 configurable: true
11415 });
11416 Object.defineProperty(DockPanel.prototype, "renderer", {
11417 /**
11418 * The renderer used by the dock panel.
11419 */
11420 get: function () {
11421 return this.layout.renderer;
11422 },
11423 enumerable: true,
11424 configurable: true
11425 });
11426 Object.defineProperty(DockPanel.prototype, "spacing", {
11427 /**
11428 * Get the spacing between the widgets.
11429 */
11430 get: function () {
11431 return this.layout.spacing;
11432 },
11433 /**
11434 * Set the spacing between the widgets.
11435 */
11436 set: function (value) {
11437 this.layout.spacing = value;
11438 },
11439 enumerable: true,
11440 configurable: true
11441 });
11442 Object.defineProperty(DockPanel.prototype, "mode", {
11443 /**
11444 * Get the mode for the dock panel.
11445 */
11446 get: function () {
11447 return this._mode;
11448 },
11449 /**
11450 * Set the mode for the dock panel.
11451 *
11452 * #### Notes
11453 * Changing the mode is a destructive operation with respect to the
11454 * panel's layout configuration. If layout state must be preserved,
11455 * save the current layout config before changing the mode.
11456 */
11457 set: function (value) {
11458 // Bail early if the mode does not change.
11459 if (this._mode === value) {
11460 return;
11461 }
11462 // Update the internal mode.
11463 this._mode = value;
11464 // Toggle the CSS mode attribute.
11465 this.dataset['mode'] = value;
11466 // Get the layout for the panel.
11467 var layout = this.layout;
11468 // Configure the layout for the specified mode.
11469 switch (value) {
11470 case 'multiple-document':
11471 algorithm.each(layout.tabBars(), function (tabBar) {
11472 tabBar.show();
11473 });
11474 break;
11475 case 'single-document':
11476 layout.restoreLayout(Private$5.createSingleDocumentConfig(this));
11477 break;
11478 default:
11479 throw 'unreachable';
11480 }
11481 // Schedule an emit of the layout modified signal.
11482 messaging.MessageLoop.postMessage(this, Private$5.LayoutModified);
11483 },
11484 enumerable: true,
11485 configurable: true
11486 });
11487 Object.defineProperty(DockPanel.prototype, "tabsMovable", {
11488 /**
11489 * Whether the tabs can be dragged / moved at runtime.
11490 */
11491 get: function () {
11492 return this._tabsMovable;
11493 },
11494 /**
11495 * Enable / Disable draggable / movable tabs.
11496 */
11497 set: function (value) {
11498 this._tabsMovable = value;
11499 algorithm.each(this.tabBars(), function (tabbar) {
11500 tabbar.tabsMovable = value;
11501 });
11502 },
11503 enumerable: true,
11504 configurable: true
11505 });
11506 Object.defineProperty(DockPanel.prototype, "tabsConstrained", {
11507 /**
11508 * Whether the tabs are constrained to their source dock panel
11509 */
11510 get: function () {
11511 return this._tabsConstrained;
11512 },
11513 /**
11514 * Constrain/Allow tabs to be dragged outside of this dock panel
11515 */
11516 set: function (value) {
11517 this._tabsConstrained = value;
11518 },
11519 enumerable: true,
11520 configurable: true
11521 });
11522 Object.defineProperty(DockPanel.prototype, "addButtonEnabled", {
11523 /**
11524 * Whether the add buttons for each tab bar are enabled.
11525 */
11526 get: function () {
11527 return this._addButtonEnabled;
11528 },
11529 /**
11530 * Set whether the add buttons for each tab bar are enabled.
11531 */
11532 set: function (value) {
11533 this._addButtonEnabled = value;
11534 algorithm.each(this.tabBars(), function (tabbar) {
11535 tabbar.addButtonEnabled = value;
11536 });
11537 },
11538 enumerable: true,
11539 configurable: true
11540 });
11541 Object.defineProperty(DockPanel.prototype, "isEmpty", {
11542 /**
11543 * Whether the dock panel is empty.
11544 */
11545 get: function () {
11546 return this.layout.isEmpty;
11547 },
11548 enumerable: true,
11549 configurable: true
11550 });
11551 /**
11552 * Create an iterator over the user widgets in the panel.
11553 *
11554 * @returns A new iterator over the user widgets in the panel.
11555 *
11556 * #### Notes
11557 * This iterator does not include the generated tab bars.
11558 */
11559 DockPanel.prototype.widgets = function () {
11560 return this.layout.widgets();
11561 };
11562 /**
11563 * Create an iterator over the selected widgets in the panel.
11564 *
11565 * @returns A new iterator over the selected user widgets.
11566 *
11567 * #### Notes
11568 * This iterator yields the widgets corresponding to the current tab
11569 * of each tab bar in the panel.
11570 */
11571 DockPanel.prototype.selectedWidgets = function () {
11572 return this.layout.selectedWidgets();
11573 };
11574 /**
11575 * Create an iterator over the tab bars in the panel.
11576 *
11577 * @returns A new iterator over the tab bars in the panel.
11578 *
11579 * #### Notes
11580 * This iterator does not include the user widgets.
11581 */
11582 DockPanel.prototype.tabBars = function () {
11583 return this.layout.tabBars();
11584 };
11585 /**
11586 * Create an iterator over the handles in the panel.
11587 *
11588 * @returns A new iterator over the handles in the panel.
11589 */
11590 DockPanel.prototype.handles = function () {
11591 return this.layout.handles();
11592 };
11593 /**
11594 * Select a specific widget in the dock panel.
11595 *
11596 * @param widget - The widget of interest.
11597 *
11598 * #### Notes
11599 * This will make the widget the current widget in its tab area.
11600 */
11601 DockPanel.prototype.selectWidget = function (widget) {
11602 // Find the tab bar which contains the widget.
11603 var tabBar = algorithm.find(this.tabBars(), function (bar) {
11604 return bar.titles.indexOf(widget.title) !== -1;
11605 });
11606 // Throw an error if no tab bar is found.
11607 if (!tabBar) {
11608 throw new Error('Widget is not contained in the dock panel.');
11609 }
11610 // Ensure the widget is the current widget.
11611 tabBar.currentTitle = widget.title;
11612 };
11613 /**
11614 * Activate a specified widget in the dock panel.
11615 *
11616 * @param widget - The widget of interest.
11617 *
11618 * #### Notes
11619 * This will select and activate the given widget.
11620 */
11621 DockPanel.prototype.activateWidget = function (widget) {
11622 this.selectWidget(widget);
11623 widget.activate();
11624 };
11625 /**
11626 * Save the current layout configuration of the dock panel.
11627 *
11628 * @returns A new config object for the current layout state.
11629 *
11630 * #### Notes
11631 * The return value can be provided to the `restoreLayout` method
11632 * in order to restore the layout to its current configuration.
11633 */
11634 DockPanel.prototype.saveLayout = function () {
11635 return this.layout.saveLayout();
11636 };
11637 /**
11638 * Restore the layout to a previously saved configuration.
11639 *
11640 * @param config - The layout configuration to restore.
11641 *
11642 * #### Notes
11643 * Widgets which currently belong to the layout but which are not
11644 * contained in the config will be unparented.
11645 *
11646 * The dock panel automatically reverts to `'multiple-document'`
11647 * mode when a layout config is restored.
11648 */
11649 DockPanel.prototype.restoreLayout = function (config) {
11650 // Reset the mode.
11651 this._mode = 'multiple-document';
11652 // Restore the layout.
11653 this.layout.restoreLayout(config);
11654 // Flush the message loop on IE and Edge to prevent flicker.
11655 if (domutils.Platform.IS_EDGE || domutils.Platform.IS_IE) {
11656 messaging.MessageLoop.flush();
11657 }
11658 // Schedule an emit of the layout modified signal.
11659 messaging.MessageLoop.postMessage(this, Private$5.LayoutModified);
11660 };
11661 /**
11662 * Add a widget to the dock panel.
11663 *
11664 * @param widget - The widget to add to the dock panel.
11665 *
11666 * @param options - The additional options for adding the widget.
11667 *
11668 * #### Notes
11669 * If the panel is in single document mode, the options are ignored
11670 * and the widget is always added as tab in the hidden tab bar.
11671 */
11672 DockPanel.prototype.addWidget = function (widget, options) {
11673 if (options === void 0) { options = {}; }
11674 // Add the widget to the layout.
11675 if (this._mode === 'single-document') {
11676 this.layout.addWidget(widget);
11677 }
11678 else {
11679 this.layout.addWidget(widget, options);
11680 }
11681 // Schedule an emit of the layout modified signal.
11682 messaging.MessageLoop.postMessage(this, Private$5.LayoutModified);
11683 };
11684 /**
11685 * Process a message sent to the widget.
11686 *
11687 * @param msg - The message sent to the widget.
11688 */
11689 DockPanel.prototype.processMessage = function (msg) {
11690 if (msg.type === 'layout-modified') {
11691 this._layoutModified.emit(undefined);
11692 }
11693 else {
11694 _super.prototype.processMessage.call(this, msg);
11695 }
11696 };
11697 /**
11698 * Handle the DOM events for the dock panel.
11699 *
11700 * @param event - The DOM event sent to the panel.
11701 *
11702 * #### Notes
11703 * This method implements the DOM `EventListener` interface and is
11704 * called in response to events on the panel's DOM node. It should
11705 * not be called directly by user code.
11706 */
11707 DockPanel.prototype.handleEvent = function (event) {
11708 switch (event.type) {
11709 case 'lm-dragenter':
11710 this._evtDragEnter(event);
11711 break;
11712 case 'lm-dragleave':
11713 this._evtDragLeave(event);
11714 break;
11715 case 'lm-dragover':
11716 this._evtDragOver(event);
11717 break;
11718 case 'lm-drop':
11719 this._evtDrop(event);
11720 break;
11721 case 'mousedown': // <DEPRECATED>
11722 this._evtMouseDown(event);
11723 break;
11724 case 'mousemove': // <DEPRECATED>
11725 this._evtMouseMove(event);
11726 break;
11727 case 'mouseup': // <DEPRECATED>
11728 this._evtMouseUp(event);
11729 break;
11730 case 'pointerdown':
11731 this._evtMouseDown(event);
11732 break;
11733 case 'pointermove':
11734 this._evtMouseMove(event);
11735 break;
11736 case 'pointerup':
11737 this._evtMouseUp(event);
11738 break;
11739 case 'keydown':
11740 this._evtKeyDown(event);
11741 break;
11742 case 'contextmenu':
11743 event.preventDefault();
11744 event.stopPropagation();
11745 break;
11746 }
11747 };
11748 /**
11749 * A message handler invoked on a `'before-attach'` message.
11750 */
11751 DockPanel.prototype.onBeforeAttach = function (msg) {
11752 this.node.addEventListener('lm-dragenter', this);
11753 this.node.addEventListener('lm-dragleave', this);
11754 this.node.addEventListener('lm-dragover', this);
11755 this.node.addEventListener('lm-drop', this);
11756 this.node.addEventListener('mousedown', this); // <DEPRECATED>
11757 this.node.addEventListener('pointerdown', this);
11758 };
11759 /**
11760 * A message handler invoked on an `'after-detach'` message.
11761 */
11762 DockPanel.prototype.onAfterDetach = function (msg) {
11763 this.node.removeEventListener('lm-dragenter', this);
11764 this.node.removeEventListener('lm-dragleave', this);
11765 this.node.removeEventListener('lm-dragover', this);
11766 this.node.removeEventListener('lm-drop', this);
11767 this.node.removeEventListener('mousedown', this); // <DEPRECATED>
11768 this.node.removeEventListener('pointerdown', this);
11769 this._releaseMouse();
11770 };
11771 /**
11772 * A message handler invoked on a `'child-added'` message.
11773 */
11774 DockPanel.prototype.onChildAdded = function (msg) {
11775 // Ignore the generated tab bars.
11776 if (Private$5.isGeneratedTabBarProperty.get(msg.child)) {
11777 return;
11778 }
11779 // Add the widget class to the child.
11780 msg.child.addClass('lm-DockPanel-widget');
11781 /* <DEPRECATED> */
11782 msg.child.addClass('p-DockPanel-widget');
11783 /* </DEPRECATED> */
11784 };
11785 /**
11786 * A message handler invoked on a `'child-removed'` message.
11787 */
11788 DockPanel.prototype.onChildRemoved = function (msg) {
11789 // Ignore the generated tab bars.
11790 if (Private$5.isGeneratedTabBarProperty.get(msg.child)) {
11791 return;
11792 }
11793 // Remove the widget class from the child.
11794 msg.child.removeClass('lm-DockPanel-widget');
11795 /* <DEPRECATED> */
11796 msg.child.removeClass('p-DockPanel-widget');
11797 /* </DEPRECATED> */
11798 // Schedule an emit of the layout modified signal.
11799 messaging.MessageLoop.postMessage(this, Private$5.LayoutModified);
11800 };
11801 /**
11802 * Handle the `'lm-dragenter'` event for the dock panel.
11803 */
11804 DockPanel.prototype._evtDragEnter = function (event) {
11805 // If the factory mime type is present, mark the event as
11806 // handled in order to get the rest of the drag events.
11807 if (event.mimeData.hasData('application/vnd.lumino.widget-factory')) {
11808 event.preventDefault();
11809 event.stopPropagation();
11810 }
11811 };
11812 /**
11813 * Handle the `'lm-dragleave'` event for the dock panel.
11814 */
11815 DockPanel.prototype._evtDragLeave = function (event) {
11816 // Mark the event as handled.
11817 event.preventDefault();
11818 event.stopPropagation();
11819 // The new target might be a descendant, so we might still handle the drop.
11820 // Hide asynchronously so that if a lm-dragover event bubbles up to us, the
11821 // hide is cancelled by the lm-dragover handler's show overlay logic.
11822 this.overlay.hide(1);
11823 };
11824 /**
11825 * Handle the `'lm-dragover'` event for the dock panel.
11826 */
11827 DockPanel.prototype._evtDragOver = function (event) {
11828 // Mark the event as handled.
11829 event.preventDefault();
11830 event.stopPropagation();
11831 // Show the drop indicator overlay and update the drop
11832 // action based on the drop target zone under the mouse.
11833 if ((this._tabsConstrained && event.source !== this) ||
11834 this._showOverlay(event.clientX, event.clientY) === 'invalid') {
11835 event.dropAction = 'none';
11836 }
11837 else {
11838 event.dropAction = event.proposedAction;
11839 }
11840 };
11841 /**
11842 * Handle the `'lm-drop'` event for the dock panel.
11843 */
11844 DockPanel.prototype._evtDrop = function (event) {
11845 // Mark the event as handled.
11846 event.preventDefault();
11847 event.stopPropagation();
11848 // Hide the drop indicator overlay.
11849 this.overlay.hide(0);
11850 // Bail if the proposed action is to do nothing.
11851 if (event.proposedAction === 'none') {
11852 event.dropAction = 'none';
11853 return;
11854 }
11855 // Find the drop target under the mouse.
11856 var clientX = event.clientX, clientY = event.clientY;
11857 var _a = Private$5.findDropTarget(this, clientX, clientY, this._edges), zone = _a.zone, target = _a.target;
11858 // Bail if the drop zone is invalid.
11859 if (zone === 'invalid') {
11860 event.dropAction = 'none';
11861 return;
11862 }
11863 // Bail if the factory mime type has invalid data.
11864 var mimeData = event.mimeData;
11865 var factory = mimeData.getData('application/vnd.lumino.widget-factory');
11866 if (typeof factory !== 'function') {
11867 event.dropAction = 'none';
11868 return;
11869 }
11870 // Bail if the factory does not produce a widget.
11871 var widget = factory();
11872 if (!(widget instanceof exports.Widget)) {
11873 event.dropAction = 'none';
11874 return;
11875 }
11876 // Bail if the widget is an ancestor of the dock panel.
11877 if (widget.contains(this)) {
11878 event.dropAction = 'none';
11879 return;
11880 }
11881 // Find the reference widget for the drop target.
11882 var ref = target ? Private$5.getDropRef(target.tabBar) : null;
11883 // Add the widget according to the indicated drop zone.
11884 switch (zone) {
11885 case 'root-all':
11886 this.addWidget(widget);
11887 break;
11888 case 'root-top':
11889 this.addWidget(widget, { mode: 'split-top' });
11890 break;
11891 case 'root-left':
11892 this.addWidget(widget, { mode: 'split-left' });
11893 break;
11894 case 'root-right':
11895 this.addWidget(widget, { mode: 'split-right' });
11896 break;
11897 case 'root-bottom':
11898 this.addWidget(widget, { mode: 'split-bottom' });
11899 break;
11900 case 'widget-all':
11901 this.addWidget(widget, { mode: 'tab-after', ref: ref });
11902 break;
11903 case 'widget-top':
11904 this.addWidget(widget, { mode: 'split-top', ref: ref });
11905 break;
11906 case 'widget-left':
11907 this.addWidget(widget, { mode: 'split-left', ref: ref });
11908 break;
11909 case 'widget-right':
11910 this.addWidget(widget, { mode: 'split-right', ref: ref });
11911 break;
11912 case 'widget-bottom':
11913 this.addWidget(widget, { mode: 'split-bottom', ref: ref });
11914 break;
11915 case 'widget-tab':
11916 this.addWidget(widget, { mode: 'tab-after', ref: ref });
11917 break;
11918 default:
11919 throw 'unreachable';
11920 }
11921 // Accept the proposed drop action.
11922 event.dropAction = event.proposedAction;
11923 // Activate the dropped widget.
11924 this.activateWidget(widget);
11925 };
11926 /**
11927 * Handle the `'keydown'` event for the dock panel.
11928 */
11929 DockPanel.prototype._evtKeyDown = function (event) {
11930 // Stop input events during drag.
11931 event.preventDefault();
11932 event.stopPropagation();
11933 // Release the mouse if `Escape` is pressed.
11934 if (event.keyCode === 27) {
11935 // Finalize the mouse release.
11936 this._releaseMouse();
11937 // Schedule an emit of the layout modified signal.
11938 messaging.MessageLoop.postMessage(this, Private$5.LayoutModified);
11939 }
11940 };
11941 /**
11942 * Handle the `'mousedown'` event for the dock panel.
11943 */
11944 DockPanel.prototype._evtMouseDown = function (event) {
11945 // Do nothing if the left mouse button is not pressed.
11946 if (event.button !== 0) {
11947 return;
11948 }
11949 // Find the handle which contains the mouse target, if any.
11950 var layout = this.layout;
11951 var target = event.target;
11952 var handle = algorithm.find(layout.handles(), function (handle) { return handle.contains(target); });
11953 if (!handle) {
11954 return;
11955 }
11956 // Stop the event when a handle is pressed.
11957 event.preventDefault();
11958 event.stopPropagation();
11959 // Add the extra document listeners.
11960 this._document.addEventListener('keydown', this, true);
11961 this._document.addEventListener('mouseup', this, true); // <DEPRECATED>
11962 this._document.addEventListener('mousemove', this, true); // <DEPRECATED>
11963 this._document.addEventListener('pointerup', this, true);
11964 this._document.addEventListener('pointermove', this, true);
11965 this._document.addEventListener('contextmenu', this, true);
11966 // Compute the offset deltas for the handle press.
11967 var rect = handle.getBoundingClientRect();
11968 var deltaX = event.clientX - rect.left;
11969 var deltaY = event.clientY - rect.top;
11970 // Override the cursor and store the press data.
11971 var style = window.getComputedStyle(handle);
11972 var override = dragdrop.Drag.overrideCursor(style.cursor, this._document);
11973 this._pressData = { handle: handle, deltaX: deltaX, deltaY: deltaY, override: override };
11974 };
11975 /**
11976 * Handle the `'mousemove'` event for the dock panel.
11977 */
11978 DockPanel.prototype._evtMouseMove = function (event) {
11979 // Bail early if no drag is in progress.
11980 if (!this._pressData) {
11981 return;
11982 }
11983 // Stop the event when dragging a handle.
11984 event.preventDefault();
11985 event.stopPropagation();
11986 // Compute the desired offset position for the handle.
11987 var rect = this.node.getBoundingClientRect();
11988 var xPos = event.clientX - rect.left - this._pressData.deltaX;
11989 var yPos = event.clientY - rect.top - this._pressData.deltaY;
11990 // Set the handle as close to the desired position as possible.
11991 var layout = this.layout;
11992 layout.moveHandle(this._pressData.handle, xPos, yPos);
11993 };
11994 /**
11995 * Handle the `'mouseup'` event for the dock panel.
11996 */
11997 DockPanel.prototype._evtMouseUp = function (event) {
11998 // Do nothing if the left mouse button is not released.
11999 if (event.button !== 0) {
12000 return;
12001 }
12002 // Stop the event when releasing a handle.
12003 event.preventDefault();
12004 event.stopPropagation();
12005 // Finalize the mouse release.
12006 this._releaseMouse();
12007 // Schedule an emit of the layout modified signal.
12008 messaging.MessageLoop.postMessage(this, Private$5.LayoutModified);
12009 };
12010 /**
12011 * Release the mouse grab for the dock panel.
12012 */
12013 DockPanel.prototype._releaseMouse = function () {
12014 // Bail early if no drag is in progress.
12015 if (!this._pressData) {
12016 return;
12017 }
12018 // Clear the override cursor.
12019 this._pressData.override.dispose();
12020 this._pressData = null;
12021 // Remove the extra document listeners.
12022 this._document.removeEventListener('keydown', this, true);
12023 this._document.removeEventListener('mouseup', this, true); // <DEPRECATED>
12024 this._document.removeEventListener('mousemove', this, true); // <DEPRECATED>
12025 this._document.removeEventListener('pointerup', this, true);
12026 this._document.removeEventListener('pointermove', this, true);
12027 this._document.removeEventListener('contextmenu', this, true);
12028 };
12029 /**
12030 * Show the overlay indicator at the given client position.
12031 *
12032 * Returns the drop zone at the specified client position.
12033 *
12034 * #### Notes
12035 * If the position is not over a valid zone, the overlay is hidden.
12036 */
12037 DockPanel.prototype._showOverlay = function (clientX, clientY) {
12038 // Find the dock target for the given client position.
12039 var _a = Private$5.findDropTarget(this, clientX, clientY, this._edges), zone = _a.zone, target = _a.target;
12040 // If the drop zone is invalid, hide the overlay and bail.
12041 if (zone === 'invalid') {
12042 this.overlay.hide(100);
12043 return zone;
12044 }
12045 // Setup the variables needed to compute the overlay geometry.
12046 var top;
12047 var left;
12048 var right;
12049 var bottom;
12050 var box = domutils.ElementExt.boxSizing(this.node); // TODO cache this?
12051 var rect = this.node.getBoundingClientRect();
12052 // Compute the overlay geometry based on the dock zone.
12053 switch (zone) {
12054 case 'root-all':
12055 top = box.paddingTop;
12056 left = box.paddingLeft;
12057 right = box.paddingRight;
12058 bottom = box.paddingBottom;
12059 break;
12060 case 'root-top':
12061 top = box.paddingTop;
12062 left = box.paddingLeft;
12063 right = box.paddingRight;
12064 bottom = rect.height * Private$5.GOLDEN_RATIO;
12065 break;
12066 case 'root-left':
12067 top = box.paddingTop;
12068 left = box.paddingLeft;
12069 right = rect.width * Private$5.GOLDEN_RATIO;
12070 bottom = box.paddingBottom;
12071 break;
12072 case 'root-right':
12073 top = box.paddingTop;
12074 left = rect.width * Private$5.GOLDEN_RATIO;
12075 right = box.paddingRight;
12076 bottom = box.paddingBottom;
12077 break;
12078 case 'root-bottom':
12079 top = rect.height * Private$5.GOLDEN_RATIO;
12080 left = box.paddingLeft;
12081 right = box.paddingRight;
12082 bottom = box.paddingBottom;
12083 break;
12084 case 'widget-all':
12085 top = target.top;
12086 left = target.left;
12087 right = target.right;
12088 bottom = target.bottom;
12089 break;
12090 case 'widget-top':
12091 top = target.top;
12092 left = target.left;
12093 right = target.right;
12094 bottom = target.bottom + target.height / 2;
12095 break;
12096 case 'widget-left':
12097 top = target.top;
12098 left = target.left;
12099 right = target.right + target.width / 2;
12100 bottom = target.bottom;
12101 break;
12102 case 'widget-right':
12103 top = target.top;
12104 left = target.left + target.width / 2;
12105 right = target.right;
12106 bottom = target.bottom;
12107 break;
12108 case 'widget-bottom':
12109 top = target.top + target.height / 2;
12110 left = target.left;
12111 right = target.right;
12112 bottom = target.bottom;
12113 break;
12114 case 'widget-tab':
12115 var tabHeight = target.tabBar.node.getBoundingClientRect().height;
12116 top = target.top;
12117 left = target.left;
12118 right = target.right;
12119 bottom = target.bottom + target.height - tabHeight;
12120 break;
12121 default:
12122 throw 'unreachable';
12123 }
12124 // Show the overlay with the computed geometry.
12125 this.overlay.show({ top: top, left: left, right: right, bottom: bottom });
12126 // Finally, return the computed drop zone.
12127 return zone;
12128 };
12129 /**
12130 * Create a new tab bar for use by the panel.
12131 */
12132 DockPanel.prototype._createTabBar = function () {
12133 // Create the tab bar.
12134 var tabBar = this._renderer.createTabBar(this._document);
12135 // Set the generated tab bar property for the tab bar.
12136 Private$5.isGeneratedTabBarProperty.set(tabBar, true);
12137 // Hide the tab bar when in single document mode.
12138 if (this._mode === 'single-document') {
12139 tabBar.hide();
12140 }
12141 // Enforce necessary tab bar behavior.
12142 // TODO do we really want to enforce *all* of these?
12143 tabBar.tabsMovable = this._tabsMovable;
12144 tabBar.allowDeselect = false;
12145 tabBar.addButtonEnabled = this._addButtonEnabled;
12146 tabBar.removeBehavior = 'select-previous-tab';
12147 tabBar.insertBehavior = 'select-tab-if-needed';
12148 // Connect the signal handlers for the tab bar.
12149 tabBar.tabMoved.connect(this._onTabMoved, this);
12150 tabBar.currentChanged.connect(this._onCurrentChanged, this);
12151 tabBar.tabCloseRequested.connect(this._onTabCloseRequested, this);
12152 tabBar.tabDetachRequested.connect(this._onTabDetachRequested, this);
12153 tabBar.tabActivateRequested.connect(this._onTabActivateRequested, this);
12154 tabBar.addRequested.connect(this._onTabAddRequested, this);
12155 // Return the initialized tab bar.
12156 return tabBar;
12157 };
12158 /**
12159 * Create a new handle for use by the panel.
12160 */
12161 DockPanel.prototype._createHandle = function () {
12162 return this._renderer.createHandle();
12163 };
12164 /**
12165 * Handle the `tabMoved` signal from a tab bar.
12166 */
12167 DockPanel.prototype._onTabMoved = function () {
12168 messaging.MessageLoop.postMessage(this, Private$5.LayoutModified);
12169 };
12170 /**
12171 * Handle the `currentChanged` signal from a tab bar.
12172 */
12173 DockPanel.prototype._onCurrentChanged = function (sender, args) {
12174 // Extract the previous and current title from the args.
12175 var previousTitle = args.previousTitle, currentTitle = args.currentTitle;
12176 // Hide the previous widget.
12177 if (previousTitle) {
12178 previousTitle.owner.hide();
12179 }
12180 // Show the current widget.
12181 if (currentTitle) {
12182 currentTitle.owner.show();
12183 }
12184 // Flush the message loop on IE and Edge to prevent flicker.
12185 if (domutils.Platform.IS_EDGE || domutils.Platform.IS_IE) {
12186 messaging.MessageLoop.flush();
12187 }
12188 // Schedule an emit of the layout modified signal.
12189 messaging.MessageLoop.postMessage(this, Private$5.LayoutModified);
12190 };
12191 /**
12192 * Handle the `addRequested` signal from a tab bar.
12193 */
12194 DockPanel.prototype._onTabAddRequested = function (sender) {
12195 this._addRequested.emit(sender);
12196 };
12197 /**
12198 * Handle the `tabActivateRequested` signal from a tab bar.
12199 */
12200 DockPanel.prototype._onTabActivateRequested = function (sender, args) {
12201 args.title.owner.activate();
12202 };
12203 /**
12204 * Handle the `tabCloseRequested` signal from a tab bar.
12205 */
12206 DockPanel.prototype._onTabCloseRequested = function (sender, args) {
12207 args.title.owner.close();
12208 };
12209 /**
12210 * Handle the `tabDetachRequested` signal from a tab bar.
12211 */
12212 DockPanel.prototype._onTabDetachRequested = function (sender, args) {
12213 var _this = this;
12214 // Do nothing if a drag is already in progress.
12215 if (this._drag) {
12216 return;
12217 }
12218 // Release the tab bar's hold on the mouse.
12219 sender.releaseMouse();
12220 // Extract the data from the args.
12221 var title = args.title, tab = args.tab, clientX = args.clientX, clientY = args.clientY;
12222 // Setup the mime data for the drag operation.
12223 var mimeData = new coreutils.MimeData();
12224 var factory = function () { return title.owner; };
12225 mimeData.setData('application/vnd.lumino.widget-factory', factory);
12226 // Create the drag image for the drag operation.
12227 var dragImage = tab.cloneNode(true);
12228 // Create the drag object to manage the drag-drop operation.
12229 this._drag = new dragdrop.Drag({
12230 document: this._document,
12231 mimeData: mimeData,
12232 dragImage: dragImage,
12233 proposedAction: 'move',
12234 supportedActions: 'move',
12235 source: this
12236 });
12237 // Hide the tab node in the original tab.
12238 tab.classList.add('lm-mod-hidden');
12239 /* <DEPRECATED> */
12240 tab.classList.add('p-mod-hidden'); // Create the cleanup callback.
12241 /* </DEPRECATED> */ var cleanup = function () {
12242 _this._drag = null;
12243 tab.classList.remove('lm-mod-hidden');
12244 /* <DEPRECATED> */
12245 tab.classList.remove('p-mod-hidden');
12246 /* </DEPRECATED> */
12247 };
12248 // Start the drag operation and cleanup when done.
12249 this._drag.start(clientX, clientY).then(cleanup);
12250 };
12251 return DockPanel;
12252 }(exports.Widget));
12253 /**
12254 * The namespace for the `DockPanel` class statics.
12255 */
12256 (function (DockPanel) {
12257 /**
12258 * A concrete implementation of `IOverlay`.
12259 *
12260 * This is the default overlay implementation for a dock panel.
12261 */
12262 var Overlay = /** @class */ (function () {
12263 /**
12264 * Construct a new overlay.
12265 */
12266 function Overlay() {
12267 this._timer = -1;
12268 this._hidden = true;
12269 this.node = document.createElement('div');
12270 this.node.classList.add('lm-DockPanel-overlay');
12271 this.node.classList.add('lm-mod-hidden');
12272 /* <DEPRECATED> */
12273 this.node.classList.add('p-DockPanel-overlay');
12274 this.node.classList.add('p-mod-hidden');
12275 /* </DEPRECATED> */ this.node.style.position = 'absolute';
12276 }
12277 /**
12278 * Show the overlay using the given overlay geometry.
12279 *
12280 * @param geo - The desired geometry for the overlay.
12281 */
12282 Overlay.prototype.show = function (geo) {
12283 // Update the position of the overlay.
12284 var style = this.node.style;
12285 style.top = geo.top + "px";
12286 style.left = geo.left + "px";
12287 style.right = geo.right + "px";
12288 style.bottom = geo.bottom + "px";
12289 // Clear any pending hide timer.
12290 clearTimeout(this._timer);
12291 this._timer = -1;
12292 // If the overlay is already visible, we're done.
12293 if (!this._hidden) {
12294 return;
12295 }
12296 // Clear the hidden flag.
12297 this._hidden = false;
12298 // Finally, show the overlay.
12299 this.node.classList.remove('lm-mod-hidden');
12300 /* <DEPRECATED> */
12301 this.node.classList.remove('p-mod-hidden');
12302 /* </DEPRECATED> */
12303 };
12304 /**
12305 * Hide the overlay node.
12306 *
12307 * @param delay - The delay (in ms) before hiding the overlay.
12308 * A delay value <= 0 will hide the overlay immediately.
12309 */
12310 Overlay.prototype.hide = function (delay) {
12311 var _this = this;
12312 // Do nothing if the overlay is already hidden.
12313 if (this._hidden) {
12314 return;
12315 }
12316 // Hide immediately if the delay is <= 0.
12317 if (delay <= 0) {
12318 clearTimeout(this._timer);
12319 this._timer = -1;
12320 this._hidden = true;
12321 this.node.classList.add('lm-mod-hidden');
12322 /* <DEPRECATED> */
12323 this.node.classList.add('p-mod-hidden');
12324 /* </DEPRECATED> */ return;
12325 }
12326 // Do nothing if a hide is already pending.
12327 if (this._timer !== -1) {
12328 return;
12329 }
12330 // Otherwise setup the hide timer.
12331 this._timer = window.setTimeout(function () {
12332 _this._timer = -1;
12333 _this._hidden = true;
12334 _this.node.classList.add('lm-mod-hidden');
12335 /* <DEPRECATED> */
12336 _this.node.classList.add('p-mod-hidden');
12337 /* </DEPRECATED> */
12338 }, delay);
12339 };
12340 return Overlay;
12341 }());
12342 DockPanel.Overlay = Overlay;
12343 /**
12344 * The default implementation of `IRenderer`.
12345 */
12346 var Renderer = /** @class */ (function () {
12347 function Renderer() {
12348 }
12349 /**
12350 * Create a new tab bar for use with a dock panel.
12351 *
12352 * @returns A new tab bar for a dock panel.
12353 */
12354 Renderer.prototype.createTabBar = function (document) {
12355 var bar = new exports.TabBar({ document: document });
12356 bar.addClass('lm-DockPanel-tabBar');
12357 /* <DEPRECATED> */
12358 bar.addClass('p-DockPanel-tabBar');
12359 /* </DEPRECATED> */
12360 return bar;
12361 };
12362 /**
12363 * Create a new handle node for use with a dock panel.
12364 *
12365 * @returns A new handle node for a dock panel.
12366 */
12367 Renderer.prototype.createHandle = function () {
12368 var handle = document.createElement('div');
12369 handle.className = 'lm-DockPanel-handle';
12370 /* <DEPRECATED> */
12371 handle.classList.add('p-DockPanel-handle');
12372 /* </DEPRECATED> */ return handle;
12373 };
12374 return Renderer;
12375 }());
12376 DockPanel.Renderer = Renderer;
12377 /**
12378 * The default `Renderer` instance.
12379 */
12380 DockPanel.defaultRenderer = new Renderer();
12381 })(exports.DockPanel || (exports.DockPanel = {}));
12382 /**
12383 * The namespace for the module implementation details.
12384 */
12385 var Private$5;
12386 (function (Private) {
12387 /**
12388 * A fraction used for sizing root panels; ~= `1 / golden_ratio`.
12389 */
12390 Private.GOLDEN_RATIO = 0.618;
12391 /**
12392 * The default sizes for the edge drop zones, in pixels.
12393 */
12394 Private.DEFAULT_EDGES = {
12395 /**
12396 * The size of the top edge dock zone for the root panel, in pixels.
12397 * This is different from the others to distinguish between the top
12398 * tab bar and the top root zone.
12399 */
12400 top: 12,
12401 /**
12402 * The size of the edge dock zone for the root panel, in pixels.
12403 */
12404 right: 40,
12405 /**
12406 * The size of the edge dock zone for the root panel, in pixels.
12407 */
12408 bottom: 40,
12409 /**
12410 * The size of the edge dock zone for the root panel, in pixels.
12411 */
12412 left: 40
12413 };
12414 /**
12415 * A singleton `'layout-modified'` conflatable message.
12416 */
12417 Private.LayoutModified = new messaging.ConflatableMessage('layout-modified');
12418 /**
12419 * An attached property used to track generated tab bars.
12420 */
12421 Private.isGeneratedTabBarProperty = new properties.AttachedProperty({
12422 name: 'isGeneratedTabBar',
12423 create: function () { return false; }
12424 });
12425 /**
12426 * Create a single document config for the widgets in a dock panel.
12427 */
12428 function createSingleDocumentConfig(panel) {
12429 // Return an empty config if the panel is empty.
12430 if (panel.isEmpty) {
12431 return { main: null };
12432 }
12433 // Get a flat array of the widgets in the panel.
12434 var widgets = algorithm.toArray(panel.widgets());
12435 // Get the first selected widget in the panel.
12436 var selected = panel.selectedWidgets().next();
12437 // Compute the current index for the new config.
12438 var currentIndex = selected ? widgets.indexOf(selected) : -1;
12439 // Return the single document config.
12440 return { main: { type: 'tab-area', widgets: widgets, currentIndex: currentIndex } };
12441 }
12442 Private.createSingleDocumentConfig = createSingleDocumentConfig;
12443 /**
12444 * Find the drop target at the given client position.
12445 */
12446 function findDropTarget(panel, clientX, clientY, edges) {
12447 // Bail if the mouse is not over the dock panel.
12448 if (!domutils.ElementExt.hitTest(panel.node, clientX, clientY)) {
12449 return { zone: 'invalid', target: null };
12450 }
12451 // Look up the layout for the panel.
12452 var layout = panel.layout;
12453 // If the layout is empty, indicate the entire root drop zone.
12454 if (layout.isEmpty) {
12455 return { zone: 'root-all', target: null };
12456 }
12457 // Test the edge zones when in multiple document mode.
12458 if (panel.mode === 'multiple-document') {
12459 // Get the client rect for the dock panel.
12460 var panelRect = panel.node.getBoundingClientRect();
12461 // Compute the distance to each edge of the panel.
12462 var pl = clientX - panelRect.left + 1;
12463 var pt = clientY - panelRect.top + 1;
12464 var pr = panelRect.right - clientX;
12465 var pb = panelRect.bottom - clientY;
12466 // Find the minimum distance to an edge.
12467 var pd = Math.min(pt, pr, pb, pl);
12468 // Return a root zone if the mouse is within an edge.
12469 switch (pd) {
12470 case pt:
12471 if (pt < edges.top) {
12472 return { zone: 'root-top', target: null };
12473 }
12474 break;
12475 case pr:
12476 if (pr < edges.right) {
12477 return { zone: 'root-right', target: null };
12478 }
12479 break;
12480 case pb:
12481 if (pb < edges.bottom) {
12482 return { zone: 'root-bottom', target: null };
12483 }
12484 break;
12485 case pl:
12486 if (pl < edges.left) {
12487 return { zone: 'root-left', target: null };
12488 }
12489 break;
12490 default:
12491 throw 'unreachable';
12492 }
12493 }
12494 // Hit test the dock layout at the given client position.
12495 var target = layout.hitTestTabAreas(clientX, clientY);
12496 // Bail if no target area was found.
12497 if (!target) {
12498 return { zone: 'invalid', target: null };
12499 }
12500 // Return the whole tab area when in single document mode.
12501 if (panel.mode === 'single-document') {
12502 return { zone: 'widget-all', target: target };
12503 }
12504 // Compute the distance to each edge of the tab area.
12505 var al = target.x - target.left + 1;
12506 var at = target.y - target.top + 1;
12507 var ar = target.left + target.width - target.x;
12508 var ab = target.top + target.height - target.y;
12509 var tabHeight = target.tabBar.node.getBoundingClientRect().height;
12510 if (at < tabHeight) {
12511 return { zone: 'widget-tab', target: target };
12512 }
12513 // Get the X and Y edge sizes for the area.
12514 var rx = Math.round(target.width / 3);
12515 var ry = Math.round(target.height / 3);
12516 // If the mouse is not within an edge, indicate the entire area.
12517 if (al > rx && ar > rx && at > ry && ab > ry) {
12518 return { zone: 'widget-all', target: target };
12519 }
12520 // Scale the distances by the slenderness ratio.
12521 al /= rx;
12522 at /= ry;
12523 ar /= rx;
12524 ab /= ry;
12525 // Find the minimum distance to the area edge.
12526 var ad = Math.min(al, at, ar, ab);
12527 // Find the widget zone for the area edge.
12528 var zone;
12529 switch (ad) {
12530 case al:
12531 zone = 'widget-left';
12532 break;
12533 case at:
12534 zone = 'widget-top';
12535 break;
12536 case ar:
12537 zone = 'widget-right';
12538 break;
12539 case ab:
12540 zone = 'widget-bottom';
12541 break;
12542 default:
12543 throw 'unreachable';
12544 }
12545 // Return the final drop target.
12546 return { zone: zone, target: target };
12547 }
12548 Private.findDropTarget = findDropTarget;
12549 /**
12550 * Get the drop reference widget for a tab bar.
12551 */
12552 function getDropRef(tabBar) {
12553 if (tabBar.titles.length === 0) {
12554 return null;
12555 }
12556 if (tabBar.currentTitle) {
12557 return tabBar.currentTitle.owner;
12558 }
12559 return tabBar.titles[tabBar.titles.length - 1].owner;
12560 }
12561 Private.getDropRef = getDropRef;
12562 })(Private$5 || (Private$5 = {}));
12563
12564 // Copyright (c) Jupyter Development Team.
12565 /**
12566 * A class which tracks focus among a set of widgets.
12567 *
12568 * This class is useful when code needs to keep track of the most
12569 * recently focused widget(s) among a set of related widgets.
12570 */
12571 var FocusTracker = /** @class */ (function () {
12572 function FocusTracker() {
12573 this._counter = 0;
12574 this._widgets = [];
12575 this._activeWidget = null;
12576 this._currentWidget = null;
12577 this._numbers = new Map();
12578 this._nodes = new Map();
12579 this._activeChanged = new signaling.Signal(this);
12580 this._currentChanged = new signaling.Signal(this);
12581 }
12582 /**
12583 * Dispose of the resources held by the tracker.
12584 */
12585 FocusTracker.prototype.dispose = function () {
12586 var _this = this;
12587 // Do nothing if the tracker is already disposed.
12588 if (this._counter < 0) {
12589 return;
12590 }
12591 // Mark the tracker as disposed.
12592 this._counter = -1;
12593 // Clear the connections for the tracker.
12594 signaling.Signal.clearData(this);
12595 // Remove all event listeners.
12596 algorithm.each(this._widgets, function (w) {
12597 w.node.removeEventListener('focus', _this, true);
12598 w.node.removeEventListener('blur', _this, true);
12599 });
12600 // Clear the internal data structures.
12601 this._activeWidget = null;
12602 this._currentWidget = null;
12603 this._nodes.clear();
12604 this._numbers.clear();
12605 this._widgets.length = 0;
12606 };
12607 Object.defineProperty(FocusTracker.prototype, "currentChanged", {
12608 /**
12609 * A signal emitted when the current widget has changed.
12610 */
12611 get: function () {
12612 return this._currentChanged;
12613 },
12614 enumerable: true,
12615 configurable: true
12616 });
12617 Object.defineProperty(FocusTracker.prototype, "activeChanged", {
12618 /**
12619 * A signal emitted when the active widget has changed.
12620 */
12621 get: function () {
12622 return this._activeChanged;
12623 },
12624 enumerable: true,
12625 configurable: true
12626 });
12627 Object.defineProperty(FocusTracker.prototype, "isDisposed", {
12628 /**
12629 * A flag indicating whether the tracker is disposed.
12630 */
12631 get: function () {
12632 return this._counter < 0;
12633 },
12634 enumerable: true,
12635 configurable: true
12636 });
12637 Object.defineProperty(FocusTracker.prototype, "currentWidget", {
12638 /**
12639 * The current widget in the tracker.
12640 *
12641 * #### Notes
12642 * The current widget is the widget among the tracked widgets which
12643 * has the *descendant node* which has most recently been focused.
12644 *
12645 * The current widget will not be updated if the node loses focus. It
12646 * will only be updated when a different tracked widget gains focus.
12647 *
12648 * If the current widget is removed from the tracker, the previous
12649 * current widget will be restored.
12650 *
12651 * This behavior is intended to follow a user's conceptual model of
12652 * a semantically "current" widget, where the "last thing of type X"
12653 * to be interacted with is the "current instance of X", regardless
12654 * of whether that instance still has focus.
12655 */
12656 get: function () {
12657 return this._currentWidget;
12658 },
12659 enumerable: true,
12660 configurable: true
12661 });
12662 Object.defineProperty(FocusTracker.prototype, "activeWidget", {
12663 /**
12664 * The active widget in the tracker.
12665 *
12666 * #### Notes
12667 * The active widget is the widget among the tracked widgets which
12668 * has the *descendant node* which is currently focused.
12669 */
12670 get: function () {
12671 return this._activeWidget;
12672 },
12673 enumerable: true,
12674 configurable: true
12675 });
12676 Object.defineProperty(FocusTracker.prototype, "widgets", {
12677 /**
12678 * A read only array of the widgets being tracked.
12679 */
12680 get: function () {
12681 return this._widgets;
12682 },
12683 enumerable: true,
12684 configurable: true
12685 });
12686 /**
12687 * Get the focus number for a particular widget in the tracker.
12688 *
12689 * @param widget - The widget of interest.
12690 *
12691 * @returns The focus number for the given widget, or `-1` if the
12692 * widget has not had focus since being added to the tracker, or
12693 * is not contained by the tracker.
12694 *
12695 * #### Notes
12696 * The focus number indicates the relative order in which the widgets
12697 * have gained focus. A widget with a larger number has gained focus
12698 * more recently than a widget with a smaller number.
12699 *
12700 * The `currentWidget` will always have the largest focus number.
12701 *
12702 * All widgets start with a focus number of `-1`, which indicates that
12703 * the widget has not been focused since being added to the tracker.
12704 */
12705 FocusTracker.prototype.focusNumber = function (widget) {
12706 var n = this._numbers.get(widget);
12707 return n === undefined ? -1 : n;
12708 };
12709 /**
12710 * Test whether the focus tracker contains a given widget.
12711 *
12712 * @param widget - The widget of interest.
12713 *
12714 * @returns `true` if the widget is tracked, `false` otherwise.
12715 */
12716 FocusTracker.prototype.has = function (widget) {
12717 return this._numbers.has(widget);
12718 };
12719 /**
12720 * Add a widget to the focus tracker.
12721 *
12722 * @param widget - The widget of interest.
12723 *
12724 * #### Notes
12725 * A widget will be automatically removed from the tracker if it
12726 * is disposed after being added.
12727 *
12728 * If the widget is already tracked, this is a no-op.
12729 */
12730 FocusTracker.prototype.add = function (widget) {
12731 // Do nothing if the widget is already tracked.
12732 if (this._numbers.has(widget)) {
12733 return;
12734 }
12735 // Test whether the widget has focus.
12736 var focused = widget.node.contains(document.activeElement);
12737 // Set up the initial focus number.
12738 var n = focused ? this._counter++ : -1;
12739 // Add the widget to the internal data structures.
12740 this._widgets.push(widget);
12741 this._numbers.set(widget, n);
12742 this._nodes.set(widget.node, widget);
12743 // Set up the event listeners. The capturing phase must be used
12744 // since the 'focus' and 'blur' events don't bubble and Firefox
12745 // doesn't support the 'focusin' or 'focusout' events.
12746 widget.node.addEventListener('focus', this, true);
12747 widget.node.addEventListener('blur', this, true);
12748 // Connect the disposed signal handler.
12749 widget.disposed.connect(this._onWidgetDisposed, this);
12750 // Set the current and active widgets if needed.
12751 if (focused) {
12752 this._setWidgets(widget, widget);
12753 }
12754 };
12755 /**
12756 * Remove a widget from the focus tracker.
12757 *
12758 * #### Notes
12759 * If the widget is the `currentWidget`, the previous current widget
12760 * will become the new `currentWidget`.
12761 *
12762 * A widget will be automatically removed from the tracker if it
12763 * is disposed after being added.
12764 *
12765 * If the widget is not tracked, this is a no-op.
12766 */
12767 FocusTracker.prototype.remove = function (widget) {
12768 var _this = this;
12769 // Bail early if the widget is not tracked.
12770 if (!this._numbers.has(widget)) {
12771 return;
12772 }
12773 // Disconnect the disposed signal handler.
12774 widget.disposed.disconnect(this._onWidgetDisposed, this);
12775 // Remove the event listeners.
12776 widget.node.removeEventListener('focus', this, true);
12777 widget.node.removeEventListener('blur', this, true);
12778 // Remove the widget from the internal data structures.
12779 algorithm.ArrayExt.removeFirstOf(this._widgets, widget);
12780 this._nodes.delete(widget.node);
12781 this._numbers.delete(widget);
12782 // Bail early if the widget is not the current widget.
12783 if (this._currentWidget !== widget) {
12784 return;
12785 }
12786 // Filter the widgets for those which have had focus.
12787 var valid = algorithm.filter(this._widgets, function (w) { return _this._numbers.get(w) !== -1; });
12788 // Get the valid widget with the max focus number.
12789 var previous = algorithm.max(valid, function (first, second) {
12790 var a = _this._numbers.get(first);
12791 var b = _this._numbers.get(second);
12792 return a - b;
12793 }) || null;
12794 // Set the current and active widgets.
12795 this._setWidgets(previous, null);
12796 };
12797 /**
12798 * Handle the DOM events for the focus tracker.
12799 *
12800 * @param event - The DOM event sent to the panel.
12801 *
12802 * #### Notes
12803 * This method implements the DOM `EventListener` interface and is
12804 * called in response to events on the tracked nodes. It should
12805 * not be called directly by user code.
12806 */
12807 FocusTracker.prototype.handleEvent = function (event) {
12808 switch (event.type) {
12809 case 'focus':
12810 this._evtFocus(event);
12811 break;
12812 case 'blur':
12813 this._evtBlur(event);
12814 break;
12815 }
12816 };
12817 /**
12818 * Set the current and active widgets for the tracker.
12819 */
12820 FocusTracker.prototype._setWidgets = function (current, active) {
12821 // Swap the current widget.
12822 var oldCurrent = this._currentWidget;
12823 this._currentWidget = current;
12824 // Swap the active widget.
12825 var oldActive = this._activeWidget;
12826 this._activeWidget = active;
12827 // Emit the `currentChanged` signal if needed.
12828 if (oldCurrent !== current) {
12829 this._currentChanged.emit({ oldValue: oldCurrent, newValue: current });
12830 }
12831 // Emit the `activeChanged` signal if needed.
12832 if (oldActive !== active) {
12833 this._activeChanged.emit({ oldValue: oldActive, newValue: active });
12834 }
12835 };
12836 /**
12837 * Handle the `'focus'` event for a tracked widget.
12838 */
12839 FocusTracker.prototype._evtFocus = function (event) {
12840 // Find the widget which gained focus, which is known to exist.
12841 var widget = this._nodes.get(event.currentTarget);
12842 // Update the focus number if necessary.
12843 if (widget !== this._currentWidget) {
12844 this._numbers.set(widget, this._counter++);
12845 }
12846 // Set the current and active widgets.
12847 this._setWidgets(widget, widget);
12848 };
12849 /**
12850 * Handle the `'blur'` event for a tracked widget.
12851 */
12852 FocusTracker.prototype._evtBlur = function (event) {
12853 // Find the widget which lost focus, which is known to exist.
12854 var widget = this._nodes.get(event.currentTarget);
12855 // Get the node which being focused after this blur.
12856 var focusTarget = event.relatedTarget;
12857 // If no other node is being focused, clear the active widget.
12858 if (!focusTarget) {
12859 this._setWidgets(this._currentWidget, null);
12860 return;
12861 }
12862 // Bail if the focus widget is not changing.
12863 if (widget.node.contains(focusTarget)) {
12864 return;
12865 }
12866 // If no tracked widget is being focused, clear the active widget.
12867 if (!algorithm.find(this._widgets, function (w) { return w.node.contains(focusTarget); })) {
12868 this._setWidgets(this._currentWidget, null);
12869 return;
12870 }
12871 };
12872 /**
12873 * Handle the `disposed` signal for a tracked widget.
12874 */
12875 FocusTracker.prototype._onWidgetDisposed = function (sender) {
12876 this.remove(sender);
12877 };
12878 return FocusTracker;
12879 }());
12880
12881 /**
12882 * A layout which arranges its widgets in a grid.
12883 */
12884 exports.GridLayout = /** @class */ (function (_super) {
12885 __extends(GridLayout, _super);
12886 /**
12887 * Construct a new grid layout.
12888 *
12889 * @param options - The options for initializing the layout.
12890 */
12891 function GridLayout(options) {
12892 if (options === void 0) { options = {}; }
12893 var _this = _super.call(this, options) || this;
12894 _this._dirty = false;
12895 _this._rowSpacing = 4;
12896 _this._columnSpacing = 4;
12897 _this._items = [];
12898 _this._rowStarts = [];
12899 _this._columnStarts = [];
12900 _this._rowSizers = [new BoxSizer()];
12901 _this._columnSizers = [new BoxSizer()];
12902 _this._box = null;
12903 if (options.rowCount !== undefined) {
12904 Private$4.reallocSizers(_this._rowSizers, options.rowCount);
12905 }
12906 if (options.columnCount !== undefined) {
12907 Private$4.reallocSizers(_this._columnSizers, options.columnCount);
12908 }
12909 if (options.rowSpacing !== undefined) {
12910 _this._rowSpacing = Private$4.clampValue(options.rowSpacing);
12911 }
12912 if (options.columnSpacing !== undefined) {
12913 _this._columnSpacing = Private$4.clampValue(options.columnSpacing);
12914 }
12915 return _this;
12916 }
12917 /**
12918 * Dispose of the resources held by the layout.
12919 */
12920 GridLayout.prototype.dispose = function () {
12921 // Dispose of the widgets and layout items.
12922 algorithm.each(this._items, function (item) {
12923 var widget = item.widget;
12924 item.dispose();
12925 widget.dispose();
12926 });
12927 // Clear the layout state.
12928 this._box = null;
12929 this._items.length = 0;
12930 this._rowStarts.length = 0;
12931 this._rowSizers.length = 0;
12932 this._columnStarts.length = 0;
12933 this._columnSizers.length = 0;
12934 // Dispose of the rest of the layout.
12935 _super.prototype.dispose.call(this);
12936 };
12937 Object.defineProperty(GridLayout.prototype, "rowCount", {
12938 /**
12939 * Get the number of rows in the layout.
12940 */
12941 get: function () {
12942 return this._rowSizers.length;
12943 },
12944 /**
12945 * Set the number of rows in the layout.
12946 *
12947 * #### Notes
12948 * The minimum row count is `1`.
12949 */
12950 set: function (value) {
12951 // Do nothing if the row count does not change.
12952 if (value === this.rowCount) {
12953 return;
12954 }
12955 // Reallocate the row sizers.
12956 Private$4.reallocSizers(this._rowSizers, value);
12957 // Schedule a fit of the parent.
12958 if (this.parent) {
12959 this.parent.fit();
12960 }
12961 },
12962 enumerable: true,
12963 configurable: true
12964 });
12965 Object.defineProperty(GridLayout.prototype, "columnCount", {
12966 /**
12967 * Get the number of columns in the layout.
12968 */
12969 get: function () {
12970 return this._columnSizers.length;
12971 },
12972 /**
12973 * Set the number of columns in the layout.
12974 *
12975 * #### Notes
12976 * The minimum column count is `1`.
12977 */
12978 set: function (value) {
12979 // Do nothing if the column count does not change.
12980 if (value === this.columnCount) {
12981 return;
12982 }
12983 // Reallocate the column sizers.
12984 Private$4.reallocSizers(this._columnSizers, value);
12985 // Schedule a fit of the parent.
12986 if (this.parent) {
12987 this.parent.fit();
12988 }
12989 },
12990 enumerable: true,
12991 configurable: true
12992 });
12993 Object.defineProperty(GridLayout.prototype, "rowSpacing", {
12994 /**
12995 * Get the row spacing for the layout.
12996 */
12997 get: function () {
12998 return this._rowSpacing;
12999 },
13000 /**
13001 * Set the row spacing for the layout.
13002 */
13003 set: function (value) {
13004 // Clamp the spacing to the allowed range.
13005 value = Private$4.clampValue(value);
13006 // Bail if the spacing does not change
13007 if (this._rowSpacing === value) {
13008 return;
13009 }
13010 // Update the internal spacing.
13011 this._rowSpacing = value;
13012 // Schedule a fit of the parent.
13013 if (this.parent) {
13014 this.parent.fit();
13015 }
13016 },
13017 enumerable: true,
13018 configurable: true
13019 });
13020 Object.defineProperty(GridLayout.prototype, "columnSpacing", {
13021 /**
13022 * Get the column spacing for the layout.
13023 */
13024 get: function () {
13025 return this._columnSpacing;
13026 },
13027 /**
13028 * Set the col spacing for the layout.
13029 */
13030 set: function (value) {
13031 // Clamp the spacing to the allowed range.
13032 value = Private$4.clampValue(value);
13033 // Bail if the spacing does not change
13034 if (this._columnSpacing === value) {
13035 return;
13036 }
13037 // Update the internal spacing.
13038 this._columnSpacing = value;
13039 // Schedule a fit of the parent.
13040 if (this.parent) {
13041 this.parent.fit();
13042 }
13043 },
13044 enumerable: true,
13045 configurable: true
13046 });
13047 /**
13048 * Get the stretch factor for a specific row.
13049 *
13050 * @param index - The row index of interest.
13051 *
13052 * @returns The stretch factor for the row.
13053 *
13054 * #### Notes
13055 * This returns `-1` if the index is out of range.
13056 */
13057 GridLayout.prototype.rowStretch = function (index) {
13058 var sizer = this._rowSizers[index];
13059 return sizer ? sizer.stretch : -1;
13060 };
13061 /**
13062 * Set the stretch factor for a specific row.
13063 *
13064 * @param index - The row index of interest.
13065 *
13066 * @param value - The stretch factor for the row.
13067 *
13068 * #### Notes
13069 * This is a no-op if the index is out of range.
13070 */
13071 GridLayout.prototype.setRowStretch = function (index, value) {
13072 // Look up the row sizer.
13073 var sizer = this._rowSizers[index];
13074 // Bail if the index is out of range.
13075 if (!sizer) {
13076 return;
13077 }
13078 // Clamp the value to the allowed range.
13079 value = Private$4.clampValue(value);
13080 // Bail if the stretch does not change.
13081 if (sizer.stretch === value) {
13082 return;
13083 }
13084 // Update the sizer stretch.
13085 sizer.stretch = value;
13086 // Schedule an update of the parent.
13087 if (this.parent) {
13088 this.parent.update();
13089 }
13090 };
13091 /**
13092 * Get the stretch factor for a specific column.
13093 *
13094 * @param index - The column index of interest.
13095 *
13096 * @returns The stretch factor for the column.
13097 *
13098 * #### Notes
13099 * This returns `-1` if the index is out of range.
13100 */
13101 GridLayout.prototype.columnStretch = function (index) {
13102 var sizer = this._columnSizers[index];
13103 return sizer ? sizer.stretch : -1;
13104 };
13105 /**
13106 * Set the stretch factor for a specific column.
13107 *
13108 * @param index - The column index of interest.
13109 *
13110 * @param value - The stretch factor for the column.
13111 *
13112 * #### Notes
13113 * This is a no-op if the index is out of range.
13114 */
13115 GridLayout.prototype.setColumnStretch = function (index, value) {
13116 // Look up the column sizer.
13117 var sizer = this._columnSizers[index];
13118 // Bail if the index is out of range.
13119 if (!sizer) {
13120 return;
13121 }
13122 // Clamp the value to the allowed range.
13123 value = Private$4.clampValue(value);
13124 // Bail if the stretch does not change.
13125 if (sizer.stretch === value) {
13126 return;
13127 }
13128 // Update the sizer stretch.
13129 sizer.stretch = value;
13130 // Schedule an update of the parent.
13131 if (this.parent) {
13132 this.parent.update();
13133 }
13134 };
13135 /**
13136 * Create an iterator over the widgets in the layout.
13137 *
13138 * @returns A new iterator over the widgets in the layout.
13139 */
13140 GridLayout.prototype.iter = function () {
13141 return algorithm.map(this._items, function (item) { return item.widget; });
13142 };
13143 /**
13144 * Add a widget to the grid layout.
13145 *
13146 * @param widget - The widget to add to the layout.
13147 *
13148 * #### Notes
13149 * If the widget is already contained in the layout, this is no-op.
13150 */
13151 GridLayout.prototype.addWidget = function (widget) {
13152 // Look up the index for the widget.
13153 var i = algorithm.ArrayExt.findFirstIndex(this._items, function (it) { return it.widget === widget; });
13154 // Bail if the widget is already in the layout.
13155 if (i !== -1) {
13156 return;
13157 }
13158 // Add the widget to the layout.
13159 this._items.push(new LayoutItem(widget));
13160 // Attach the widget to the parent.
13161 if (this.parent) {
13162 this.attachWidget(widget);
13163 }
13164 };
13165 /**
13166 * Remove a widget from the grid layout.
13167 *
13168 * @param widget - The widget to remove from the layout.
13169 *
13170 * #### Notes
13171 * A widget is automatically removed from the layout when its `parent`
13172 * is set to `null`. This method should only be invoked directly when
13173 * removing a widget from a layout which has yet to be installed on a
13174 * parent widget.
13175 *
13176 * This method does *not* modify the widget's `parent`.
13177 */
13178 GridLayout.prototype.removeWidget = function (widget) {
13179 // Look up the index for the widget.
13180 var i = algorithm.ArrayExt.findFirstIndex(this._items, function (it) { return it.widget === widget; });
13181 // Bail if the widget is not in the layout.
13182 if (i === -1) {
13183 return;
13184 }
13185 // Remove the widget from the layout.
13186 var item = algorithm.ArrayExt.removeAt(this._items, i);
13187 // Detach the widget from the parent.
13188 if (this.parent) {
13189 this.detachWidget(widget);
13190 }
13191 // Dispose the layout item.
13192 item.dispose();
13193 };
13194 /**
13195 * Perform layout initialization which requires the parent widget.
13196 */
13197 GridLayout.prototype.init = function () {
13198 var _this = this;
13199 _super.prototype.init.call(this);
13200 algorithm.each(this, function (widget) {
13201 _this.attachWidget(widget);
13202 });
13203 };
13204 /**
13205 * Attach a widget to the parent's DOM node.
13206 *
13207 * @param widget - The widget to attach to the parent.
13208 */
13209 GridLayout.prototype.attachWidget = function (widget) {
13210 // Send a `'before-attach'` message if the parent is attached.
13211 if (this.parent.isAttached) {
13212 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.BeforeAttach);
13213 }
13214 // Add the widget's node to the parent.
13215 this.parent.node.appendChild(widget.node);
13216 // Send an `'after-attach'` message if the parent is attached.
13217 if (this.parent.isAttached) {
13218 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.AfterAttach);
13219 }
13220 // Post a fit request for the parent widget.
13221 this.parent.fit();
13222 };
13223 /**
13224 * Detach a widget from the parent's DOM node.
13225 *
13226 * @param widget - The widget to detach from the parent.
13227 */
13228 GridLayout.prototype.detachWidget = function (widget) {
13229 // Send a `'before-detach'` message if the parent is attached.
13230 if (this.parent.isAttached) {
13231 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.BeforeDetach);
13232 }
13233 // Remove the widget's node from the parent.
13234 this.parent.node.removeChild(widget.node);
13235 // Send an `'after-detach'` message if the parent is attached.
13236 if (this.parent.isAttached) {
13237 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.AfterDetach);
13238 }
13239 // Post a fit request for the parent widget.
13240 this.parent.fit();
13241 };
13242 /**
13243 * A message handler invoked on a `'before-show'` message.
13244 */
13245 GridLayout.prototype.onBeforeShow = function (msg) {
13246 _super.prototype.onBeforeShow.call(this, msg);
13247 this.parent.update();
13248 };
13249 /**
13250 * A message handler invoked on a `'before-attach'` message.
13251 */
13252 GridLayout.prototype.onBeforeAttach = function (msg) {
13253 _super.prototype.onBeforeAttach.call(this, msg);
13254 this.parent.fit();
13255 };
13256 /**
13257 * A message handler invoked on a `'child-shown'` message.
13258 */
13259 GridLayout.prototype.onChildShown = function (msg) {
13260 this.parent.fit();
13261 };
13262 /**
13263 * A message handler invoked on a `'child-hidden'` message.
13264 */
13265 GridLayout.prototype.onChildHidden = function (msg) {
13266 this.parent.fit();
13267 };
13268 /**
13269 * A message handler invoked on a `'resize'` message.
13270 */
13271 GridLayout.prototype.onResize = function (msg) {
13272 if (this.parent.isVisible) {
13273 this._update(msg.width, msg.height);
13274 }
13275 };
13276 /**
13277 * A message handler invoked on an `'update-request'` message.
13278 */
13279 GridLayout.prototype.onUpdateRequest = function (msg) {
13280 if (this.parent.isVisible) {
13281 this._update(-1, -1);
13282 }
13283 };
13284 /**
13285 * A message handler invoked on a `'fit-request'` message.
13286 */
13287 GridLayout.prototype.onFitRequest = function (msg) {
13288 if (this.parent.isAttached) {
13289 this._fit();
13290 }
13291 };
13292 /**
13293 * Fit the layout to the total size required by the widgets.
13294 */
13295 GridLayout.prototype._fit = function () {
13296 // Reset the min sizes of the sizers.
13297 for (var i = 0, n = this.rowCount; i < n; ++i) {
13298 this._rowSizers[i].minSize = 0;
13299 }
13300 for (var i = 0, n = this.columnCount; i < n; ++i) {
13301 this._columnSizers[i].minSize = 0;
13302 }
13303 // Filter for the visible layout items.
13304 var items = this._items.filter(function (it) { return !it.isHidden; });
13305 // Fit the layout items.
13306 for (var i = 0, n = items.length; i < n; ++i) {
13307 items[i].fit();
13308 }
13309 // Get the max row and column index.
13310 var maxRow = this.rowCount - 1;
13311 var maxCol = this.columnCount - 1;
13312 // Sort the items by row span.
13313 items.sort(Private$4.rowSpanCmp);
13314 // Update the min sizes of the row sizers.
13315 for (var i = 0, n = items.length; i < n; ++i) {
13316 // Fetch the item.
13317 var item = items[i];
13318 // Get the row bounds for the item.
13319 var config = GridLayout.getCellConfig(item.widget);
13320 var r1 = Math.min(config.row, maxRow);
13321 var r2 = Math.min(config.row + config.rowSpan - 1, maxRow);
13322 // Distribute the minimum height to the sizers as needed.
13323 Private$4.distributeMin(this._rowSizers, r1, r2, item.minHeight);
13324 }
13325 // Sort the items by column span.
13326 items.sort(Private$4.columnSpanCmp);
13327 // Update the min sizes of the column sizers.
13328 for (var i = 0, n = items.length; i < n; ++i) {
13329 // Fetch the item.
13330 var item = items[i];
13331 // Get the column bounds for the item.
13332 var config = GridLayout.getCellConfig(item.widget);
13333 var c1 = Math.min(config.column, maxCol);
13334 var c2 = Math.min(config.column + config.columnSpan - 1, maxCol);
13335 // Distribute the minimum width to the sizers as needed.
13336 Private$4.distributeMin(this._columnSizers, c1, c2, item.minWidth);
13337 }
13338 // If no size constraint is needed, just update the parent.
13339 if (this.fitPolicy === 'set-no-constraint') {
13340 messaging.MessageLoop.sendMessage(this.parent, exports.Widget.Msg.UpdateRequest);
13341 return;
13342 }
13343 // Set up the computed min size.
13344 var minH = maxRow * this._rowSpacing;
13345 var minW = maxCol * this._columnSpacing;
13346 // Add the sizer minimums to the computed min size.
13347 for (var i = 0, n = this.rowCount; i < n; ++i) {
13348 minH += this._rowSizers[i].minSize;
13349 }
13350 for (var i = 0, n = this.columnCount; i < n; ++i) {
13351 minW += this._columnSizers[i].minSize;
13352 }
13353 // Update the box sizing and add it to the computed min size.
13354 var box = (this._box = domutils.ElementExt.boxSizing(this.parent.node));
13355 minW += box.horizontalSum;
13356 minH += box.verticalSum;
13357 // Update the parent's min size constraints.
13358 var style = this.parent.node.style;
13359 style.minWidth = minW + "px";
13360 style.minHeight = minH + "px";
13361 // Set the dirty flag to ensure only a single update occurs.
13362 this._dirty = true;
13363 // Notify the ancestor that it should fit immediately. This may
13364 // cause a resize of the parent, fulfilling the required update.
13365 if (this.parent.parent) {
13366 messaging.MessageLoop.sendMessage(this.parent.parent, exports.Widget.Msg.FitRequest);
13367 }
13368 // If the dirty flag is still set, the parent was not resized.
13369 // Trigger the required update on the parent widget immediately.
13370 if (this._dirty) {
13371 messaging.MessageLoop.sendMessage(this.parent, exports.Widget.Msg.UpdateRequest);
13372 }
13373 };
13374 /**
13375 * Update the layout position and size of the widgets.
13376 *
13377 * The parent offset dimensions should be `-1` if unknown.
13378 */
13379 GridLayout.prototype._update = function (offsetWidth, offsetHeight) {
13380 // Clear the dirty flag to indicate the update occurred.
13381 this._dirty = false;
13382 // Measure the parent if the offset dimensions are unknown.
13383 if (offsetWidth < 0) {
13384 offsetWidth = this.parent.node.offsetWidth;
13385 }
13386 if (offsetHeight < 0) {
13387 offsetHeight = this.parent.node.offsetHeight;
13388 }
13389 // Ensure the parent box sizing data is computed.
13390 if (!this._box) {
13391 this._box = domutils.ElementExt.boxSizing(this.parent.node);
13392 }
13393 // Compute the layout area adjusted for border and padding.
13394 var top = this._box.paddingTop;
13395 var left = this._box.paddingLeft;
13396 var width = offsetWidth - this._box.horizontalSum;
13397 var height = offsetHeight - this._box.verticalSum;
13398 // Get the max row and column index.
13399 var maxRow = this.rowCount - 1;
13400 var maxCol = this.columnCount - 1;
13401 // Compute the total fixed row and column space.
13402 var fixedRowSpace = maxRow * this._rowSpacing;
13403 var fixedColSpace = maxCol * this._columnSpacing;
13404 // Distribute the available space to the box sizers.
13405 exports.BoxEngine.calc(this._rowSizers, Math.max(0, height - fixedRowSpace));
13406 exports.BoxEngine.calc(this._columnSizers, Math.max(0, width - fixedColSpace));
13407 // Update the row start positions.
13408 for (var i = 0, pos = top, n = this.rowCount; i < n; ++i) {
13409 this._rowStarts[i] = pos;
13410 pos += this._rowSizers[i].size + this._rowSpacing;
13411 }
13412 // Update the column start positions.
13413 for (var i = 0, pos = left, n = this.columnCount; i < n; ++i) {
13414 this._columnStarts[i] = pos;
13415 pos += this._columnSizers[i].size + this._columnSpacing;
13416 }
13417 // Update the geometry of the layout items.
13418 for (var i = 0, n = this._items.length; i < n; ++i) {
13419 // Fetch the item.
13420 var item = this._items[i];
13421 // Ignore hidden items.
13422 if (item.isHidden) {
13423 continue;
13424 }
13425 // Fetch the cell bounds for the widget.
13426 var config = GridLayout.getCellConfig(item.widget);
13427 var r1 = Math.min(config.row, maxRow);
13428 var c1 = Math.min(config.column, maxCol);
13429 var r2 = Math.min(config.row + config.rowSpan - 1, maxRow);
13430 var c2 = Math.min(config.column + config.columnSpan - 1, maxCol);
13431 // Compute the cell geometry.
13432 var x = this._columnStarts[c1];
13433 var y = this._rowStarts[r1];
13434 var w = this._columnStarts[c2] + this._columnSizers[c2].size - x;
13435 var h = this._rowStarts[r2] + this._rowSizers[r2].size - y;
13436 // Update the geometry of the layout item.
13437 item.update(x, y, w, h);
13438 }
13439 };
13440 return GridLayout;
13441 }(exports.Layout));
13442 /**
13443 * The namespace for the `GridLayout` class statics.
13444 */
13445 (function (GridLayout) {
13446 /**
13447 * Get the cell config for the given widget.
13448 *
13449 * @param widget - The widget of interest.
13450 *
13451 * @returns The cell config for the widget.
13452 */
13453 function getCellConfig(widget) {
13454 return Private$4.cellConfigProperty.get(widget);
13455 }
13456 GridLayout.getCellConfig = getCellConfig;
13457 /**
13458 * Set the cell config for the given widget.
13459 *
13460 * @param widget - The widget of interest.
13461 *
13462 * @param value - The value for the cell config.
13463 */
13464 function setCellConfig(widget, value) {
13465 Private$4.cellConfigProperty.set(widget, Private$4.normalizeConfig(value));
13466 }
13467 GridLayout.setCellConfig = setCellConfig;
13468 })(exports.GridLayout || (exports.GridLayout = {}));
13469 /**
13470 * The namespace for the module implementation details.
13471 */
13472 var Private$4;
13473 (function (Private) {
13474 /**
13475 * The property descriptor for the widget cell config.
13476 */
13477 Private.cellConfigProperty = new properties.AttachedProperty({
13478 name: 'cellConfig',
13479 create: function () { return ({ row: 0, column: 0, rowSpan: 1, columnSpan: 1 }); },
13480 changed: onChildCellConfigChanged
13481 });
13482 /**
13483 * Normalize a partial cell config object.
13484 */
13485 function normalizeConfig(config) {
13486 var row = Math.max(0, Math.floor(config.row || 0));
13487 var column = Math.max(0, Math.floor(config.column || 0));
13488 var rowSpan = Math.max(1, Math.floor(config.rowSpan || 0));
13489 var columnSpan = Math.max(1, Math.floor(config.columnSpan || 0));
13490 return { row: row, column: column, rowSpan: rowSpan, columnSpan: columnSpan };
13491 }
13492 Private.normalizeConfig = normalizeConfig;
13493 /**
13494 * Clamp a value to an integer >= 0.
13495 */
13496 function clampValue(value) {
13497 return Math.max(0, Math.floor(value));
13498 }
13499 Private.clampValue = clampValue;
13500 /**
13501 * A sort comparison function for row spans.
13502 */
13503 function rowSpanCmp(a, b) {
13504 var c1 = Private.cellConfigProperty.get(a.widget);
13505 var c2 = Private.cellConfigProperty.get(b.widget);
13506 return c1.rowSpan - c2.rowSpan;
13507 }
13508 Private.rowSpanCmp = rowSpanCmp;
13509 /**
13510 * A sort comparison function for column spans.
13511 */
13512 function columnSpanCmp(a, b) {
13513 var c1 = Private.cellConfigProperty.get(a.widget);
13514 var c2 = Private.cellConfigProperty.get(b.widget);
13515 return c1.columnSpan - c2.columnSpan;
13516 }
13517 Private.columnSpanCmp = columnSpanCmp;
13518 /**
13519 * Reallocate the box sizers for the given grid dimensions.
13520 */
13521 function reallocSizers(sizers, count) {
13522 // Coerce the count to the valid range.
13523 count = Math.max(1, Math.floor(count));
13524 // Add the missing sizers.
13525 while (sizers.length < count) {
13526 sizers.push(new BoxSizer());
13527 }
13528 // Remove the extra sizers.
13529 if (sizers.length > count) {
13530 sizers.length = count;
13531 }
13532 }
13533 Private.reallocSizers = reallocSizers;
13534 /**
13535 * Distribute a min size constraint across a range of sizers.
13536 */
13537 function distributeMin(sizers, i1, i2, minSize) {
13538 // Sanity check the indices.
13539 if (i2 < i1) {
13540 return;
13541 }
13542 // Handle the simple case of no cell span.
13543 if (i1 === i2) {
13544 var sizer = sizers[i1];
13545 sizer.minSize = Math.max(sizer.minSize, minSize);
13546 return;
13547 }
13548 // Compute the total current min size of the span.
13549 var totalMin = 0;
13550 for (var i = i1; i <= i2; ++i) {
13551 totalMin += sizers[i].minSize;
13552 }
13553 // Do nothing if the total is greater than the required.
13554 if (totalMin >= minSize) {
13555 return;
13556 }
13557 // Compute the portion of the space to allocate to each sizer.
13558 var portion = (minSize - totalMin) / (i2 - i1 + 1);
13559 // Add the portion to each sizer.
13560 for (var i = i1; i <= i2; ++i) {
13561 sizers[i].minSize += portion;
13562 }
13563 }
13564 Private.distributeMin = distributeMin;
13565 /**
13566 * The change handler for the child cell config property.
13567 */
13568 function onChildCellConfigChanged(child) {
13569 if (child.parent && child.parent.layout instanceof exports.GridLayout) {
13570 child.parent.fit();
13571 }
13572 }
13573 })(Private$4 || (Private$4 = {}));
13574
13575 /**
13576 * A widget which displays menus as a canonical menu bar.
13577 */
13578 exports.MenuBar = /** @class */ (function (_super) {
13579 __extends(MenuBar, _super);
13580 /**
13581 * Construct a new menu bar.
13582 *
13583 * @param options - The options for initializing the menu bar.
13584 */
13585 function MenuBar(options) {
13586 if (options === void 0) { options = {}; }
13587 var _this = _super.call(this, { node: Private$3.createNode() }) || this;
13588 _this._activeIndex = -1;
13589 _this._menus = [];
13590 _this._childMenu = null;
13591 _this.addClass('lm-MenuBar');
13592 /* <DEPRECATED> */
13593 _this.addClass('p-MenuBar');
13594 /* </DEPRECATED> */
13595 _this.setFlag(exports.Widget.Flag.DisallowLayout);
13596 _this.renderer = options.renderer || MenuBar.defaultRenderer;
13597 _this._forceItemsPosition = options.forceItemsPosition || {
13598 forceX: true,
13599 forceY: true
13600 };
13601 return _this;
13602 }
13603 /**
13604 * Dispose of the resources held by the widget.
13605 */
13606 MenuBar.prototype.dispose = function () {
13607 this._closeChildMenu();
13608 this._menus.length = 0;
13609 _super.prototype.dispose.call(this);
13610 };
13611 Object.defineProperty(MenuBar.prototype, "childMenu", {
13612 /**
13613 * The child menu of the menu bar.
13614 *
13615 * #### Notes
13616 * This will be `null` if the menu bar does not have an open menu.
13617 */
13618 get: function () {
13619 return this._childMenu;
13620 },
13621 enumerable: true,
13622 configurable: true
13623 });
13624 Object.defineProperty(MenuBar.prototype, "contentNode", {
13625 /**
13626 * Get the menu bar content node.
13627 *
13628 * #### Notes
13629 * This is the node which holds the menu title nodes.
13630 *
13631 * Modifying this node directly can lead to undefined behavior.
13632 */
13633 get: function () {
13634 return this.node.getElementsByClassName('lm-MenuBar-content')[0];
13635 },
13636 enumerable: true,
13637 configurable: true
13638 });
13639 Object.defineProperty(MenuBar.prototype, "activeMenu", {
13640 /**
13641 * Get the currently active menu.
13642 */
13643 get: function () {
13644 return this._menus[this._activeIndex] || null;
13645 },
13646 /**
13647 * Set the currently active menu.
13648 *
13649 * #### Notes
13650 * If the menu does not exist, the menu will be set to `null`.
13651 */
13652 set: function (value) {
13653 this.activeIndex = value ? this._menus.indexOf(value) : -1;
13654 },
13655 enumerable: true,
13656 configurable: true
13657 });
13658 Object.defineProperty(MenuBar.prototype, "activeIndex", {
13659 /**
13660 * Get the index of the currently active menu.
13661 *
13662 * #### Notes
13663 * This will be `-1` if no menu is active.
13664 */
13665 get: function () {
13666 return this._activeIndex;
13667 },
13668 /**
13669 * Set the index of the currently active menu.
13670 *
13671 * #### Notes
13672 * If the menu cannot be activated, the index will be set to `-1`.
13673 */
13674 set: function (value) {
13675 // Adjust the value for an out of range index.
13676 if (value < 0 || value >= this._menus.length) {
13677 value = -1;
13678 }
13679 // Bail early if the index will not change.
13680 if (this._activeIndex === value) {
13681 return;
13682 }
13683 // Update the active index.
13684 this._activeIndex = value;
13685 // Update focus to new active index
13686 if (this._activeIndex >= 0 &&
13687 this.contentNode.childNodes[this._activeIndex]) {
13688 this.contentNode.childNodes[this._activeIndex].focus();
13689 }
13690 // Schedule an update of the items.
13691 this.update();
13692 },
13693 enumerable: true,
13694 configurable: true
13695 });
13696 Object.defineProperty(MenuBar.prototype, "menus", {
13697 /**
13698 * A read-only array of the menus in the menu bar.
13699 */
13700 get: function () {
13701 return this._menus;
13702 },
13703 enumerable: true,
13704 configurable: true
13705 });
13706 /**
13707 * Open the active menu and activate its first menu item.
13708 *
13709 * #### Notes
13710 * If there is no active menu, this is a no-op.
13711 */
13712 MenuBar.prototype.openActiveMenu = function () {
13713 // Bail early if there is no active item.
13714 if (this._activeIndex === -1) {
13715 return;
13716 }
13717 // Open the child menu.
13718 this._openChildMenu();
13719 // Activate the first item in the child menu.
13720 if (this._childMenu) {
13721 this._childMenu.activeIndex = -1;
13722 this._childMenu.activateNextItem();
13723 }
13724 };
13725 /**
13726 * Add a menu to the end of the menu bar.
13727 *
13728 * @param menu - The menu to add to the menu bar.
13729 *
13730 * #### Notes
13731 * If the menu is already added to the menu bar, it will be moved.
13732 */
13733 MenuBar.prototype.addMenu = function (menu) {
13734 this.insertMenu(this._menus.length, menu);
13735 };
13736 /**
13737 * Insert a menu into the menu bar at the specified index.
13738 *
13739 * @param index - The index at which to insert the menu.
13740 *
13741 * @param menu - The menu to insert into the menu bar.
13742 *
13743 * #### Notes
13744 * The index will be clamped to the bounds of the menus.
13745 *
13746 * If the menu is already added to the menu bar, it will be moved.
13747 */
13748 MenuBar.prototype.insertMenu = function (index, menu) {
13749 // Close the child menu before making changes.
13750 this._closeChildMenu();
13751 // Look up the index of the menu.
13752 var i = this._menus.indexOf(menu);
13753 // Clamp the insert index to the array bounds.
13754 var j = Math.max(0, Math.min(index, this._menus.length));
13755 // If the menu is not in the array, insert it.
13756 if (i === -1) {
13757 // Insert the menu into the array.
13758 algorithm.ArrayExt.insert(this._menus, j, menu);
13759 // Add the styling class to the menu.
13760 menu.addClass('lm-MenuBar-menu');
13761 /* <DEPRECATED> */
13762 menu.addClass('p-MenuBar-menu');
13763 /* </DEPRECATED> */
13764 // Connect to the menu signals.
13765 menu.aboutToClose.connect(this._onMenuAboutToClose, this);
13766 menu.menuRequested.connect(this._onMenuMenuRequested, this);
13767 menu.title.changed.connect(this._onTitleChanged, this);
13768 // Schedule an update of the items.
13769 this.update();
13770 // There is nothing more to do.
13771 return;
13772 }
13773 // Otherwise, the menu exists in the array and should be moved.
13774 // Adjust the index if the location is at the end of the array.
13775 if (j === this._menus.length) {
13776 j--;
13777 }
13778 // Bail if there is no effective move.
13779 if (i === j) {
13780 return;
13781 }
13782 // Move the menu to the new locations.
13783 algorithm.ArrayExt.move(this._menus, i, j);
13784 // Schedule an update of the items.
13785 this.update();
13786 };
13787 /**
13788 * Remove a menu from the menu bar.
13789 *
13790 * @param menu - The menu to remove from the menu bar.
13791 *
13792 * #### Notes
13793 * This is a no-op if the menu is not in the menu bar.
13794 */
13795 MenuBar.prototype.removeMenu = function (menu) {
13796 this.removeMenuAt(this._menus.indexOf(menu));
13797 };
13798 /**
13799 * Remove the menu at a given index from the menu bar.
13800 *
13801 * @param index - The index of the menu to remove.
13802 *
13803 * #### Notes
13804 * This is a no-op if the index is out of range.
13805 */
13806 MenuBar.prototype.removeMenuAt = function (index) {
13807 // Close the child menu before making changes.
13808 this._closeChildMenu();
13809 // Remove the menu from the array.
13810 var menu = algorithm.ArrayExt.removeAt(this._menus, index);
13811 // Bail if the index is out of range.
13812 if (!menu) {
13813 return;
13814 }
13815 // Disconnect from the menu signals.
13816 menu.aboutToClose.disconnect(this._onMenuAboutToClose, this);
13817 menu.menuRequested.disconnect(this._onMenuMenuRequested, this);
13818 menu.title.changed.disconnect(this._onTitleChanged, this);
13819 // Remove the styling class from the menu.
13820 menu.removeClass('lm-MenuBar-menu');
13821 /* <DEPRECATED> */
13822 menu.removeClass('p-MenuBar-menu');
13823 /* </DEPRECATED> */
13824 // Schedule an update of the items.
13825 this.update();
13826 };
13827 /**
13828 * Remove all menus from the menu bar.
13829 */
13830 MenuBar.prototype.clearMenus = function () {
13831 // Bail if there is nothing to remove.
13832 if (this._menus.length === 0) {
13833 return;
13834 }
13835 // Close the child menu before making changes.
13836 this._closeChildMenu();
13837 // Disconnect from the menu signals and remove the styling class.
13838 for (var _i = 0, _a = this._menus; _i < _a.length; _i++) {
13839 var menu = _a[_i];
13840 menu.aboutToClose.disconnect(this._onMenuAboutToClose, this);
13841 menu.menuRequested.disconnect(this._onMenuMenuRequested, this);
13842 menu.title.changed.disconnect(this._onTitleChanged, this);
13843 menu.removeClass('lm-MenuBar-menu');
13844 /* <DEPRECATED> */
13845 menu.removeClass('p-MenuBar-menu');
13846 /* </DEPRECATED> */
13847 }
13848 // Clear the menus array.
13849 this._menus.length = 0;
13850 // Schedule an update of the items.
13851 this.update();
13852 };
13853 /**
13854 * Handle the DOM events for the menu bar.
13855 *
13856 * @param event - The DOM event sent to the menu bar.
13857 *
13858 * #### Notes
13859 * This method implements the DOM `EventListener` interface and is
13860 * called in response to events on the menu bar's DOM nodes. It
13861 * should not be called directly by user code.
13862 */
13863 MenuBar.prototype.handleEvent = function (event) {
13864 switch (event.type) {
13865 case 'keydown':
13866 this._evtKeyDown(event);
13867 break;
13868 case 'mousedown':
13869 this._evtMouseDown(event);
13870 break;
13871 case 'mousemove':
13872 this._evtMouseMove(event);
13873 break;
13874 case 'mouseleave':
13875 this._evtMouseLeave(event);
13876 break;
13877 case 'contextmenu':
13878 event.preventDefault();
13879 event.stopPropagation();
13880 break;
13881 }
13882 };
13883 /**
13884 * A message handler invoked on a `'before-attach'` message.
13885 */
13886 MenuBar.prototype.onBeforeAttach = function (msg) {
13887 this.node.addEventListener('keydown', this);
13888 this.node.addEventListener('mousedown', this);
13889 this.node.addEventListener('mousemove', this);
13890 this.node.addEventListener('mouseleave', this);
13891 this.node.addEventListener('contextmenu', this);
13892 };
13893 /**
13894 * A message handler invoked on an `'after-detach'` message.
13895 */
13896 MenuBar.prototype.onAfterDetach = function (msg) {
13897 this.node.removeEventListener('keydown', this);
13898 this.node.removeEventListener('mousedown', this);
13899 this.node.removeEventListener('mousemove', this);
13900 this.node.removeEventListener('mouseleave', this);
13901 this.node.removeEventListener('contextmenu', this);
13902 this._closeChildMenu();
13903 };
13904 /**
13905 * A message handler invoked on an `'activate-request'` message.
13906 */
13907 MenuBar.prototype.onActivateRequest = function (msg) {
13908 if (this.isAttached) {
13909 this.node.focus();
13910 }
13911 };
13912 /**
13913 * A message handler invoked on an `'update-request'` message.
13914 */
13915 MenuBar.prototype.onUpdateRequest = function (msg) {
13916 var _this = this;
13917 var menus = this._menus;
13918 var renderer = this.renderer;
13919 var activeIndex = this._activeIndex;
13920 var content = new Array(menus.length);
13921 var _loop_1 = function (i, n) {
13922 var title = menus[i].title;
13923 var active = i === activeIndex;
13924 if (active && menus[i].items.length == 0) {
13925 active = false;
13926 }
13927 content[i] = renderer.renderItem({
13928 title: title,
13929 active: active,
13930 onfocus: function () {
13931 _this.activeIndex = i;
13932 }
13933 });
13934 };
13935 for (var i = 0, n = menus.length; i < n; ++i) {
13936 _loop_1(i);
13937 }
13938 virtualdom.VirtualDOM.render(content, this.contentNode);
13939 };
13940 /**
13941 * Handle the `'keydown'` event for the menu bar.
13942 */
13943 MenuBar.prototype._evtKeyDown = function (event) {
13944 // A menu bar handles all keydown events.
13945 event.preventDefault();
13946 event.stopPropagation();
13947 // Fetch the key code for the event.
13948 var kc = event.keyCode;
13949 // Enter, Up Arrow, Down Arrow
13950 if (kc === 13 || kc === 38 || kc === 40) {
13951 this.openActiveMenu();
13952 return;
13953 }
13954 // Escape
13955 if (kc === 27) {
13956 this._closeChildMenu();
13957 this.activeIndex = -1;
13958 this.node.blur();
13959 return;
13960 }
13961 // Left Arrow
13962 if (kc === 37) {
13963 var i = this._activeIndex;
13964 var n = this._menus.length;
13965 this.activeIndex = i === 0 ? n - 1 : i - 1;
13966 return;
13967 }
13968 // Right Arrow
13969 if (kc === 39) {
13970 var i = this._activeIndex;
13971 var n = this._menus.length;
13972 this.activeIndex = i === n - 1 ? 0 : i + 1;
13973 return;
13974 }
13975 // Get the pressed key character.
13976 var key = keyboard.getKeyboardLayout().keyForKeydownEvent(event);
13977 // Bail if the key is not valid.
13978 if (!key) {
13979 return;
13980 }
13981 // Search for the next best matching mnemonic item.
13982 var start = this._activeIndex + 1;
13983 var result = Private$3.findMnemonic(this._menus, key, start);
13984 // Handle the requested mnemonic based on the search results.
13985 // If exactly one mnemonic is matched, that menu is opened.
13986 // Otherwise, the next mnemonic is activated if available,
13987 // followed by the auto mnemonic if available.
13988 if (result.index !== -1 && !result.multiple) {
13989 this.activeIndex = result.index;
13990 this.openActiveMenu();
13991 }
13992 else if (result.index !== -1) {
13993 this.activeIndex = result.index;
13994 }
13995 else if (result.auto !== -1) {
13996 this.activeIndex = result.auto;
13997 }
13998 };
13999 /**
14000 * Handle the `'mousedown'` event for the menu bar.
14001 */
14002 MenuBar.prototype._evtMouseDown = function (event) {
14003 // Bail if the mouse press was not on the menu bar. This can occur
14004 // when the document listener is installed for an active menu bar.
14005 if (!domutils.ElementExt.hitTest(this.node, event.clientX, event.clientY)) {
14006 return;
14007 }
14008 // Stop the propagation of the event. Immediate propagation is
14009 // also stopped so that an open menu does not handle the event.
14010 event.preventDefault();
14011 event.stopPropagation();
14012 event.stopImmediatePropagation();
14013 // Check if the mouse is over one of the menu items.
14014 var index = algorithm.ArrayExt.findFirstIndex(this.contentNode.children, function (node) {
14015 return domutils.ElementExt.hitTest(node, event.clientX, event.clientY);
14016 });
14017 // If the press was not on an item, close the child menu.
14018 if (index === -1) {
14019 this._closeChildMenu();
14020 return;
14021 }
14022 // If the press was not the left mouse button, do nothing further.
14023 if (event.button !== 0) {
14024 return;
14025 }
14026 // Otherwise, toggle the open state of the child menu.
14027 if (this._childMenu) {
14028 this._closeChildMenu();
14029 this.activeIndex = index;
14030 }
14031 else {
14032 this.activeIndex = index;
14033 this._openChildMenu();
14034 }
14035 };
14036 /**
14037 * Handle the `'mousemove'` event for the menu bar.
14038 */
14039 MenuBar.prototype._evtMouseMove = function (event) {
14040 // Check if the mouse is over one of the menu items.
14041 var index = algorithm.ArrayExt.findFirstIndex(this.contentNode.children, function (node) {
14042 return domutils.ElementExt.hitTest(node, event.clientX, event.clientY);
14043 });
14044 // Bail early if the active index will not change.
14045 if (index === this._activeIndex) {
14046 return;
14047 }
14048 // Bail early if a child menu is open and the mouse is not over
14049 // an item. This allows the child menu to be kept open when the
14050 // mouse is over the empty part of the menu bar.
14051 if (index === -1 && this._childMenu) {
14052 return;
14053 }
14054 // Update the active index to the hovered item.
14055 this.activeIndex = index;
14056 // Open the new menu if a menu is already open.
14057 if (this._childMenu) {
14058 this._openChildMenu();
14059 }
14060 };
14061 /**
14062 * Handle the `'mouseleave'` event for the menu bar.
14063 */
14064 MenuBar.prototype._evtMouseLeave = function (event) {
14065 // Reset the active index if there is no open menu.
14066 if (!this._childMenu) {
14067 this.activeIndex = -1;
14068 }
14069 };
14070 /**
14071 * Open the child menu at the active index immediately.
14072 *
14073 * If a different child menu is already open, it will be closed,
14074 * even if there is no active menu.
14075 */
14076 MenuBar.prototype._openChildMenu = function () {
14077 // If there is no active menu, close the current menu.
14078 var newMenu = this.activeMenu;
14079 if (!newMenu) {
14080 this._closeChildMenu();
14081 return;
14082 }
14083 // Bail if there is no effective menu change.
14084 var oldMenu = this._childMenu;
14085 if (oldMenu === newMenu) {
14086 return;
14087 }
14088 // Swap the internal menu reference.
14089 this._childMenu = newMenu;
14090 // Close the current menu, or setup for the new menu.
14091 if (oldMenu) {
14092 oldMenu.close();
14093 }
14094 else {
14095 this.addClass('lm-mod-active');
14096 /* <DEPRECATED> */
14097 this.addClass('p-mod-active');
14098 /* </DEPRECATED> */
14099 document.addEventListener('mousedown', this, true);
14100 }
14101 // Ensure the menu bar is updated and look up the item node.
14102 messaging.MessageLoop.sendMessage(this, exports.Widget.Msg.UpdateRequest);
14103 var itemNode = this.contentNode.children[this._activeIndex];
14104 // Get the positioning data for the new menu.
14105 var _a = itemNode.getBoundingClientRect(), left = _a.left, bottom = _a.bottom;
14106 // Open the new menu at the computed location.
14107 if (newMenu.items.length > 0) {
14108 newMenu.open(left, bottom, this._forceItemsPosition);
14109 }
14110 };
14111 /**
14112 * Close the child menu immediately.
14113 *
14114 * This is a no-op if a child menu is not open.
14115 */
14116 MenuBar.prototype._closeChildMenu = function () {
14117 // Bail if no child menu is open.
14118 if (!this._childMenu) {
14119 return;
14120 }
14121 // Remove the active class from the menu bar.
14122 this.removeClass('lm-mod-active');
14123 /* <DEPRECATED> */
14124 this.removeClass('p-mod-active');
14125 /* </DEPRECATED> */
14126 // Remove the document listeners.
14127 document.removeEventListener('mousedown', this, true);
14128 // Clear the internal menu reference.
14129 var menu = this._childMenu;
14130 this._childMenu = null;
14131 // Close the menu.
14132 menu.close();
14133 // Reset the active index.
14134 this.activeIndex = -1;
14135 };
14136 /**
14137 * Handle the `aboutToClose` signal of a menu.
14138 */
14139 MenuBar.prototype._onMenuAboutToClose = function (sender) {
14140 // Bail if the sender is not the child menu.
14141 if (sender !== this._childMenu) {
14142 return;
14143 }
14144 // Remove the active class from the menu bar.
14145 this.removeClass('lm-mod-active');
14146 /* <DEPRECATED> */
14147 this.removeClass('p-mod-active');
14148 /* </DEPRECATED> */
14149 // Remove the document listeners.
14150 document.removeEventListener('mousedown', this, true);
14151 // Clear the internal menu reference.
14152 this._childMenu = null;
14153 // Reset the active index.
14154 this.activeIndex = -1;
14155 };
14156 /**
14157 * Handle the `menuRequested` signal of a child menu.
14158 */
14159 MenuBar.prototype._onMenuMenuRequested = function (sender, args) {
14160 // Bail if the sender is not the child menu.
14161 if (sender !== this._childMenu) {
14162 return;
14163 }
14164 // Look up the active index and menu count.
14165 var i = this._activeIndex;
14166 var n = this._menus.length;
14167 // Active the next requested index.
14168 switch (args) {
14169 case 'next':
14170 this.activeIndex = i === n - 1 ? 0 : i + 1;
14171 break;
14172 case 'previous':
14173 this.activeIndex = i === 0 ? n - 1 : i - 1;
14174 break;
14175 }
14176 // Open the active menu.
14177 this.openActiveMenu();
14178 };
14179 /**
14180 * Handle the `changed` signal of a title object.
14181 */
14182 MenuBar.prototype._onTitleChanged = function () {
14183 this.update();
14184 };
14185 return MenuBar;
14186 }(exports.Widget));
14187 /**
14188 * The namespace for the `MenuBar` class statics.
14189 */
14190 (function (MenuBar) {
14191 /**
14192 * The default implementation of `IRenderer`.
14193 *
14194 * #### Notes
14195 * Subclasses are free to reimplement rendering methods as needed.
14196 */
14197 var Renderer = /** @class */ (function () {
14198 function Renderer() {
14199 }
14200 /**
14201 * Render the virtual element for a menu bar item.
14202 *
14203 * @param data - The data to use for rendering the item.
14204 *
14205 * @returns A virtual element representing the item.
14206 */
14207 Renderer.prototype.renderItem = function (data) {
14208 var className = this.createItemClass(data);
14209 var dataset = this.createItemDataset(data);
14210 var aria = this.createItemARIA(data);
14211 return virtualdom.h.li(__assign({ className: className, dataset: dataset, tabindex: '0', onfocus: data.onfocus }, aria), this.renderIcon(data), this.renderLabel(data));
14212 };
14213 /**
14214 * Render the icon element for a menu bar item.
14215 *
14216 * @param data - The data to use for rendering the icon.
14217 *
14218 * @returns A virtual element representing the item icon.
14219 */
14220 Renderer.prototype.renderIcon = function (data) {
14221 var className = this.createIconClass(data);
14222 /* <DEPRECATED> */
14223 if (typeof data.title.icon === 'string') {
14224 return virtualdom.h.div({ className: className }, data.title.iconLabel);
14225 }
14226 /* </DEPRECATED> */
14227 // if data.title.icon is undefined, it will be ignored
14228 return virtualdom.h.div({ className: className }, data.title.icon, data.title.iconLabel);
14229 };
14230 /**
14231 * Render the label element for a menu item.
14232 *
14233 * @param data - The data to use for rendering the label.
14234 *
14235 * @returns A virtual element representing the item label.
14236 */
14237 Renderer.prototype.renderLabel = function (data) {
14238 var content = this.formatLabel(data);
14239 return virtualdom.h.div({
14240 className: 'lm-MenuBar-itemLabel' +
14241 /* <DEPRECATED> */
14242 ' p-MenuBar-itemLabel'
14243 /* </DEPRECATED> */
14244 }, content);
14245 };
14246 /**
14247 * Create the class name for the menu bar item.
14248 *
14249 * @param data - The data to use for the class name.
14250 *
14251 * @returns The full class name for the menu item.
14252 */
14253 Renderer.prototype.createItemClass = function (data) {
14254 var name = 'lm-MenuBar-item';
14255 /* <DEPRECATED> */
14256 name += ' p-MenuBar-item';
14257 /* </DEPRECATED> */
14258 if (data.title.className) {
14259 name += " " + data.title.className;
14260 }
14261 if (data.active) {
14262 name += ' lm-mod-active';
14263 /* <DEPRECATED> */
14264 name += ' p-mod-active';
14265 /* </DEPRECATED> */
14266 }
14267 return name;
14268 };
14269 /**
14270 * Create the dataset for a menu bar item.
14271 *
14272 * @param data - The data to use for the item.
14273 *
14274 * @returns The dataset for the menu bar item.
14275 */
14276 Renderer.prototype.createItemDataset = function (data) {
14277 return data.title.dataset;
14278 };
14279 /**
14280 * Create the aria attributes for menu bar item.
14281 *
14282 * @param data - The data to use for the aria attributes.
14283 *
14284 * @returns The aria attributes object for the item.
14285 */
14286 Renderer.prototype.createItemARIA = function (data) {
14287 return { role: 'menuitem', 'aria-haspopup': 'true' };
14288 };
14289 /**
14290 * Create the class name for the menu bar item icon.
14291 *
14292 * @param data - The data to use for the class name.
14293 *
14294 * @returns The full class name for the item icon.
14295 */
14296 Renderer.prototype.createIconClass = function (data) {
14297 var name = 'lm-MenuBar-itemIcon';
14298 /* <DEPRECATED> */
14299 name += ' p-MenuBar-itemIcon';
14300 /* </DEPRECATED> */
14301 var extra = data.title.iconClass;
14302 return extra ? name + " " + extra : name;
14303 };
14304 /**
14305 * Create the render content for the label node.
14306 *
14307 * @param data - The data to use for the label content.
14308 *
14309 * @returns The content to add to the label node.
14310 */
14311 Renderer.prototype.formatLabel = function (data) {
14312 // Fetch the label text and mnemonic index.
14313 var _a = data.title, label = _a.label, mnemonic = _a.mnemonic;
14314 // If the index is out of range, do not modify the label.
14315 if (mnemonic < 0 || mnemonic >= label.length) {
14316 return label;
14317 }
14318 // Split the label into parts.
14319 var prefix = label.slice(0, mnemonic);
14320 var suffix = label.slice(mnemonic + 1);
14321 var char = label[mnemonic];
14322 // Wrap the mnemonic character in a span.
14323 var span = virtualdom.h.span({
14324 className: 'lm-MenuBar-itemMnemonic' +
14325 /* <DEPRECATED> */
14326 ' p-MenuBar-itemMnemonic'
14327 /* </DEPRECATED> */
14328 }, char);
14329 // Return the content parts.
14330 return [prefix, span, suffix];
14331 };
14332 return Renderer;
14333 }());
14334 MenuBar.Renderer = Renderer;
14335 /**
14336 * The default `Renderer` instance.
14337 */
14338 MenuBar.defaultRenderer = new Renderer();
14339 })(exports.MenuBar || (exports.MenuBar = {}));
14340 /**
14341 * The namespace for the module implementation details.
14342 */
14343 var Private$3;
14344 (function (Private) {
14345 /**
14346 * Create the DOM node for a menu bar.
14347 */
14348 function createNode() {
14349 var node = document.createElement('div');
14350 var content = document.createElement('ul');
14351 content.className = 'lm-MenuBar-content';
14352 /* <DEPRECATED> */
14353 content.classList.add('p-MenuBar-content');
14354 /* </DEPRECATED> */
14355 node.appendChild(content);
14356 content.setAttribute('role', 'menubar');
14357 node.tabIndex = 0;
14358 content.tabIndex = 0;
14359 return node;
14360 }
14361 Private.createNode = createNode;
14362 /**
14363 * Find the best matching mnemonic item.
14364 *
14365 * The search starts at the given index and wraps around.
14366 */
14367 function findMnemonic(menus, key, start) {
14368 // Setup the result variables.
14369 var index = -1;
14370 var auto = -1;
14371 var multiple = false;
14372 // Normalize the key to upper case.
14373 var upperKey = key.toUpperCase();
14374 // Search the items from the given start index.
14375 for (var i = 0, n = menus.length; i < n; ++i) {
14376 // Compute the wrapped index.
14377 var k = (i + start) % n;
14378 // Look up the menu title.
14379 var title = menus[k].title;
14380 // Ignore titles with an empty label.
14381 if (title.label.length === 0) {
14382 continue;
14383 }
14384 // Look up the mnemonic index for the label.
14385 var mn = title.mnemonic;
14386 // Handle a valid mnemonic index.
14387 if (mn >= 0 && mn < title.label.length) {
14388 if (title.label[mn].toUpperCase() === upperKey) {
14389 if (index === -1) {
14390 index = k;
14391 }
14392 else {
14393 multiple = true;
14394 }
14395 }
14396 continue;
14397 }
14398 // Finally, handle the auto index if possible.
14399 if (auto === -1 && title.label[0].toUpperCase() === upperKey) {
14400 auto = k;
14401 }
14402 }
14403 // Return the search results.
14404 return { index: index, multiple: multiple, auto: auto };
14405 }
14406 Private.findMnemonic = findMnemonic;
14407 })(Private$3 || (Private$3 = {}));
14408
14409 /**
14410 * A widget which implements a canonical scroll bar.
14411 */
14412 var ScrollBar = /** @class */ (function (_super) {
14413 __extends(ScrollBar, _super);
14414 /**
14415 * Construct a new scroll bar.
14416 *
14417 * @param options - The options for initializing the scroll bar.
14418 */
14419 function ScrollBar(options) {
14420 if (options === void 0) { options = {}; }
14421 var _this = _super.call(this, { node: Private$2.createNode() }) || this;
14422 /**
14423 * A timeout callback for repeating the mouse press.
14424 */
14425 _this._onRepeat = function () {
14426 // Clear the repeat timer id.
14427 _this._repeatTimer = -1;
14428 // Bail if the mouse has been released.
14429 if (!_this._pressData) {
14430 return;
14431 }
14432 // Look up the part that was pressed.
14433 var part = _this._pressData.part;
14434 // Bail if the thumb was pressed.
14435 if (part === 'thumb') {
14436 return;
14437 }
14438 // Schedule the timer for another repeat.
14439 _this._repeatTimer = window.setTimeout(_this._onRepeat, 20);
14440 // Get the current mouse position.
14441 var mouseX = _this._pressData.mouseX;
14442 var mouseY = _this._pressData.mouseY;
14443 // Handle a decrement button repeat.
14444 if (part === 'decrement') {
14445 // Bail if the mouse is not over the button.
14446 if (!domutils.ElementExt.hitTest(_this.decrementNode, mouseX, mouseY)) {
14447 return;
14448 }
14449 // Emit the step requested signal.
14450 _this._stepRequested.emit('decrement');
14451 // Finished.
14452 return;
14453 }
14454 // Handle an increment button repeat.
14455 if (part === 'increment') {
14456 // Bail if the mouse is not over the button.
14457 if (!domutils.ElementExt.hitTest(_this.incrementNode, mouseX, mouseY)) {
14458 return;
14459 }
14460 // Emit the step requested signal.
14461 _this._stepRequested.emit('increment');
14462 // Finished.
14463 return;
14464 }
14465 // Handle a track repeat.
14466 if (part === 'track') {
14467 // Bail if the mouse is not over the track.
14468 if (!domutils.ElementExt.hitTest(_this.trackNode, mouseX, mouseY)) {
14469 return;
14470 }
14471 // Fetch the thumb node.
14472 var thumbNode = _this.thumbNode;
14473 // Bail if the mouse is over the thumb.
14474 if (domutils.ElementExt.hitTest(thumbNode, mouseX, mouseY)) {
14475 return;
14476 }
14477 // Fetch the client rect for the thumb.
14478 var thumbRect = thumbNode.getBoundingClientRect();
14479 // Determine the direction for the page request.
14480 var dir = void 0;
14481 if (_this._orientation === 'horizontal') {
14482 dir = mouseX < thumbRect.left ? 'decrement' : 'increment';
14483 }
14484 else {
14485 dir = mouseY < thumbRect.top ? 'decrement' : 'increment';
14486 }
14487 // Emit the page requested signal.
14488 _this._pageRequested.emit(dir);
14489 // Finished.
14490 return;
14491 }
14492 };
14493 _this._value = 0;
14494 _this._page = 10;
14495 _this._maximum = 100;
14496 _this._repeatTimer = -1;
14497 _this._pressData = null;
14498 _this._thumbMoved = new signaling.Signal(_this);
14499 _this._stepRequested = new signaling.Signal(_this);
14500 _this._pageRequested = new signaling.Signal(_this);
14501 _this.addClass('lm-ScrollBar');
14502 /* <DEPRECATED> */
14503 _this.addClass('p-ScrollBar');
14504 /* </DEPRECATED> */
14505 _this.setFlag(exports.Widget.Flag.DisallowLayout);
14506 // Set the orientation.
14507 _this._orientation = options.orientation || 'vertical';
14508 _this.dataset['orientation'] = _this._orientation;
14509 // Parse the rest of the options.
14510 if (options.maximum !== undefined) {
14511 _this._maximum = Math.max(0, options.maximum);
14512 }
14513 if (options.page !== undefined) {
14514 _this._page = Math.max(0, options.page);
14515 }
14516 if (options.value !== undefined) {
14517 _this._value = Math.max(0, Math.min(options.value, _this._maximum));
14518 }
14519 return _this;
14520 }
14521 Object.defineProperty(ScrollBar.prototype, "thumbMoved", {
14522 /**
14523 * A signal emitted when the user moves the scroll thumb.
14524 *
14525 * #### Notes
14526 * The payload is the current value of the scroll bar.
14527 */
14528 get: function () {
14529 return this._thumbMoved;
14530 },
14531 enumerable: true,
14532 configurable: true
14533 });
14534 Object.defineProperty(ScrollBar.prototype, "stepRequested", {
14535 /**
14536 * A signal emitted when the user clicks a step button.
14537 *
14538 * #### Notes
14539 * The payload is whether a decrease or increase is requested.
14540 */
14541 get: function () {
14542 return this._stepRequested;
14543 },
14544 enumerable: true,
14545 configurable: true
14546 });
14547 Object.defineProperty(ScrollBar.prototype, "pageRequested", {
14548 /**
14549 * A signal emitted when the user clicks the scroll track.
14550 *
14551 * #### Notes
14552 * The payload is whether a decrease or increase is requested.
14553 */
14554 get: function () {
14555 return this._pageRequested;
14556 },
14557 enumerable: true,
14558 configurable: true
14559 });
14560 Object.defineProperty(ScrollBar.prototype, "orientation", {
14561 /**
14562 * Get the orientation of the scroll bar.
14563 */
14564 get: function () {
14565 return this._orientation;
14566 },
14567 /**
14568 * Set the orientation of the scroll bar.
14569 */
14570 set: function (value) {
14571 // Do nothing if the orientation does not change.
14572 if (this._orientation === value) {
14573 return;
14574 }
14575 // Release the mouse before making changes.
14576 this._releaseMouse();
14577 // Update the internal orientation.
14578 this._orientation = value;
14579 this.dataset['orientation'] = value;
14580 // Schedule an update the scroll bar.
14581 this.update();
14582 },
14583 enumerable: true,
14584 configurable: true
14585 });
14586 Object.defineProperty(ScrollBar.prototype, "value", {
14587 /**
14588 * Get the current value of the scroll bar.
14589 */
14590 get: function () {
14591 return this._value;
14592 },
14593 /**
14594 * Set the current value of the scroll bar.
14595 *
14596 * #### Notes
14597 * The value will be clamped to the range `[0, maximum]`.
14598 */
14599 set: function (value) {
14600 // Clamp the value to the allowable range.
14601 value = Math.max(0, Math.min(value, this._maximum));
14602 // Do nothing if the value does not change.
14603 if (this._value === value) {
14604 return;
14605 }
14606 // Update the internal value.
14607 this._value = value;
14608 // Schedule an update the scroll bar.
14609 this.update();
14610 },
14611 enumerable: true,
14612 configurable: true
14613 });
14614 Object.defineProperty(ScrollBar.prototype, "page", {
14615 /**
14616 * Get the page size of the scroll bar.
14617 *
14618 * #### Notes
14619 * The page size is the amount of visible content in the scrolled
14620 * region, expressed in data units. It determines the size of the
14621 * scroll bar thumb.
14622 */
14623 get: function () {
14624 return this._page;
14625 },
14626 /**
14627 * Set the page size of the scroll bar.
14628 *
14629 * #### Notes
14630 * The page size will be clamped to the range `[0, Infinity]`.
14631 */
14632 set: function (value) {
14633 // Clamp the page size to the allowable range.
14634 value = Math.max(0, value);
14635 // Do nothing if the value does not change.
14636 if (this._page === value) {
14637 return;
14638 }
14639 // Update the internal page size.
14640 this._page = value;
14641 // Schedule an update the scroll bar.
14642 this.update();
14643 },
14644 enumerable: true,
14645 configurable: true
14646 });
14647 Object.defineProperty(ScrollBar.prototype, "maximum", {
14648 /**
14649 * Get the maximum value of the scroll bar.
14650 */
14651 get: function () {
14652 return this._maximum;
14653 },
14654 /**
14655 * Set the maximum value of the scroll bar.
14656 *
14657 * #### Notes
14658 * The max size will be clamped to the range `[0, Infinity]`.
14659 */
14660 set: function (value) {
14661 // Clamp the value to the allowable range.
14662 value = Math.max(0, value);
14663 // Do nothing if the value does not change.
14664 if (this._maximum === value) {
14665 return;
14666 }
14667 // Update the internal values.
14668 this._maximum = value;
14669 // Clamp the current value to the new range.
14670 this._value = Math.min(this._value, value);
14671 // Schedule an update the scroll bar.
14672 this.update();
14673 },
14674 enumerable: true,
14675 configurable: true
14676 });
14677 Object.defineProperty(ScrollBar.prototype, "decrementNode", {
14678 /**
14679 * The scroll bar decrement button node.
14680 *
14681 * #### Notes
14682 * Modifying this node directly can lead to undefined behavior.
14683 */
14684 get: function () {
14685 return this.node.getElementsByClassName('lm-ScrollBar-button')[0];
14686 },
14687 enumerable: true,
14688 configurable: true
14689 });
14690 Object.defineProperty(ScrollBar.prototype, "incrementNode", {
14691 /**
14692 * The scroll bar increment button node.
14693 *
14694 * #### Notes
14695 * Modifying this node directly can lead to undefined behavior.
14696 */
14697 get: function () {
14698 return this.node.getElementsByClassName('lm-ScrollBar-button')[1];
14699 },
14700 enumerable: true,
14701 configurable: true
14702 });
14703 Object.defineProperty(ScrollBar.prototype, "trackNode", {
14704 /**
14705 * The scroll bar track node.
14706 *
14707 * #### Notes
14708 * Modifying this node directly can lead to undefined behavior.
14709 */
14710 get: function () {
14711 return this.node.getElementsByClassName('lm-ScrollBar-track')[0];
14712 },
14713 enumerable: true,
14714 configurable: true
14715 });
14716 Object.defineProperty(ScrollBar.prototype, "thumbNode", {
14717 /**
14718 * The scroll bar thumb node.
14719 *
14720 * #### Notes
14721 * Modifying this node directly can lead to undefined behavior.
14722 */
14723 get: function () {
14724 return this.node.getElementsByClassName('lm-ScrollBar-thumb')[0];
14725 },
14726 enumerable: true,
14727 configurable: true
14728 });
14729 /**
14730 * Handle the DOM events for the scroll bar.
14731 *
14732 * @param event - The DOM event sent to the scroll bar.
14733 *
14734 * #### Notes
14735 * This method implements the DOM `EventListener` interface and is
14736 * called in response to events on the scroll bar's DOM node.
14737 *
14738 * This should not be called directly by user code.
14739 */
14740 ScrollBar.prototype.handleEvent = function (event) {
14741 switch (event.type) {
14742 case 'mousedown':
14743 this._evtMouseDown(event);
14744 break;
14745 case 'mousemove':
14746 this._evtMouseMove(event);
14747 break;
14748 case 'mouseup':
14749 this._evtMouseUp(event);
14750 break;
14751 case 'keydown':
14752 this._evtKeyDown(event);
14753 break;
14754 case 'contextmenu':
14755 event.preventDefault();
14756 event.stopPropagation();
14757 break;
14758 }
14759 };
14760 /**
14761 * A method invoked on a 'before-attach' message.
14762 */
14763 ScrollBar.prototype.onBeforeAttach = function (msg) {
14764 this.node.addEventListener('mousedown', this);
14765 this.update();
14766 };
14767 /**
14768 * A method invoked on an 'after-detach' message.
14769 */
14770 ScrollBar.prototype.onAfterDetach = function (msg) {
14771 this.node.removeEventListener('mousedown', this);
14772 this._releaseMouse();
14773 };
14774 /**
14775 * A method invoked on an 'update-request' message.
14776 */
14777 ScrollBar.prototype.onUpdateRequest = function (msg) {
14778 // Convert the value and page into percentages.
14779 var value = (this._value * 100) / this._maximum;
14780 var page = (this._page * 100) / (this._page + this._maximum);
14781 // Clamp the value and page to the relevant range.
14782 value = Math.max(0, Math.min(value, 100));
14783 page = Math.max(0, Math.min(page, 100));
14784 // Fetch the thumb style.
14785 var thumbStyle = this.thumbNode.style;
14786 // Update the thumb style for the current orientation.
14787 if (this._orientation === 'horizontal') {
14788 thumbStyle.top = '';
14789 thumbStyle.height = '';
14790 thumbStyle.left = value + "%";
14791 thumbStyle.width = page + "%";
14792 thumbStyle.transform = "translate(" + -value + "%, 0%)";
14793 }
14794 else {
14795 thumbStyle.left = '';
14796 thumbStyle.width = '';
14797 thumbStyle.top = value + "%";
14798 thumbStyle.height = page + "%";
14799 thumbStyle.transform = "translate(0%, " + -value + "%)";
14800 }
14801 };
14802 /**
14803 * Handle the `'keydown'` event for the scroll bar.
14804 */
14805 ScrollBar.prototype._evtKeyDown = function (event) {
14806 // Stop all input events during drag.
14807 event.preventDefault();
14808 event.stopPropagation();
14809 // Ignore anything except the `Escape` key.
14810 if (event.keyCode !== 27) {
14811 return;
14812 }
14813 // Fetch the previous scroll value.
14814 var value = this._pressData ? this._pressData.value : -1;
14815 // Release the mouse.
14816 this._releaseMouse();
14817 // Restore the old scroll value if possible.
14818 if (value !== -1) {
14819 this._moveThumb(value);
14820 }
14821 };
14822 /**
14823 * Handle the `'mousedown'` event for the scroll bar.
14824 */
14825 ScrollBar.prototype._evtMouseDown = function (event) {
14826 // Do nothing if it's not a left mouse press.
14827 if (event.button !== 0) {
14828 return;
14829 }
14830 // Send an activate request to the scroll bar. This can be
14831 // used by message hooks to activate something relevant.
14832 this.activate();
14833 // Do nothing if the mouse is already captured.
14834 if (this._pressData) {
14835 return;
14836 }
14837 // Find the pressed scroll bar part.
14838 var part = Private$2.findPart(this, event.target);
14839 // Do nothing if the part is not of interest.
14840 if (!part) {
14841 return;
14842 }
14843 // Stop the event propagation.
14844 event.preventDefault();
14845 event.stopPropagation();
14846 // Override the mouse cursor.
14847 var override = dragdrop.Drag.overrideCursor('default');
14848 // Set up the press data.
14849 this._pressData = {
14850 part: part,
14851 override: override,
14852 delta: -1,
14853 value: -1,
14854 mouseX: event.clientX,
14855 mouseY: event.clientY
14856 };
14857 // Add the extra event listeners.
14858 document.addEventListener('mousemove', this, true);
14859 document.addEventListener('mouseup', this, true);
14860 document.addEventListener('keydown', this, true);
14861 document.addEventListener('contextmenu', this, true);
14862 // Handle a thumb press.
14863 if (part === 'thumb') {
14864 // Fetch the thumb node.
14865 var thumbNode = this.thumbNode;
14866 // Fetch the client rect for the thumb.
14867 var thumbRect = thumbNode.getBoundingClientRect();
14868 // Update the press data delta for the current orientation.
14869 if (this._orientation === 'horizontal') {
14870 this._pressData.delta = event.clientX - thumbRect.left;
14871 }
14872 else {
14873 this._pressData.delta = event.clientY - thumbRect.top;
14874 }
14875 // Add the active class to the thumb node.
14876 thumbNode.classList.add('lm-mod-active');
14877 /* <DEPRECATED> */
14878 thumbNode.classList.add('p-mod-active');
14879 /* </DEPRECATED> */
14880 // Store the current value in the press data.
14881 this._pressData.value = this._value;
14882 // Finished.
14883 return;
14884 }
14885 // Handle a track press.
14886 if (part === 'track') {
14887 // Fetch the client rect for the thumb.
14888 var thumbRect = this.thumbNode.getBoundingClientRect();
14889 // Determine the direction for the page request.
14890 var dir = void 0;
14891 if (this._orientation === 'horizontal') {
14892 dir = event.clientX < thumbRect.left ? 'decrement' : 'increment';
14893 }
14894 else {
14895 dir = event.clientY < thumbRect.top ? 'decrement' : 'increment';
14896 }
14897 // Start the repeat timer.
14898 this._repeatTimer = window.setTimeout(this._onRepeat, 350);
14899 // Emit the page requested signal.
14900 this._pageRequested.emit(dir);
14901 // Finished.
14902 return;
14903 }
14904 // Handle a decrement button press.
14905 if (part === 'decrement') {
14906 // Add the active class to the decrement node.
14907 this.decrementNode.classList.add('lm-mod-active');
14908 /* <DEPRECATED> */
14909 this.decrementNode.classList.add('p-mod-active');
14910 /* </DEPRECATED> */
14911 // Start the repeat timer.
14912 this._repeatTimer = window.setTimeout(this._onRepeat, 350);
14913 // Emit the step requested signal.
14914 this._stepRequested.emit('decrement');
14915 // Finished.
14916 return;
14917 }
14918 // Handle an increment button press.
14919 if (part === 'increment') {
14920 // Add the active class to the increment node.
14921 this.incrementNode.classList.add('lm-mod-active');
14922 /* <DEPRECATED> */
14923 this.incrementNode.classList.add('p-mod-active');
14924 /* </DEPRECATED> */
14925 // Start the repeat timer.
14926 this._repeatTimer = window.setTimeout(this._onRepeat, 350);
14927 // Emit the step requested signal.
14928 this._stepRequested.emit('increment');
14929 // Finished.
14930 return;
14931 }
14932 };
14933 /**
14934 * Handle the `'mousemove'` event for the scroll bar.
14935 */
14936 ScrollBar.prototype._evtMouseMove = function (event) {
14937 // Do nothing if no drag is in progress.
14938 if (!this._pressData) {
14939 return;
14940 }
14941 // Stop the event propagation.
14942 event.preventDefault();
14943 event.stopPropagation();
14944 // Update the mouse position.
14945 this._pressData.mouseX = event.clientX;
14946 this._pressData.mouseY = event.clientY;
14947 // Bail if the thumb is not being dragged.
14948 if (this._pressData.part !== 'thumb') {
14949 return;
14950 }
14951 // Get the client rect for the thumb and track.
14952 var thumbRect = this.thumbNode.getBoundingClientRect();
14953 var trackRect = this.trackNode.getBoundingClientRect();
14954 // Fetch the scroll geometry based on the orientation.
14955 var trackPos;
14956 var trackSpan;
14957 if (this._orientation === 'horizontal') {
14958 trackPos = event.clientX - trackRect.left - this._pressData.delta;
14959 trackSpan = trackRect.width - thumbRect.width;
14960 }
14961 else {
14962 trackPos = event.clientY - trackRect.top - this._pressData.delta;
14963 trackSpan = trackRect.height - thumbRect.height;
14964 }
14965 // Compute the desired value from the scroll geometry.
14966 var value = trackSpan === 0 ? 0 : (trackPos * this._maximum) / trackSpan;
14967 // Move the thumb to the computed value.
14968 this._moveThumb(value);
14969 };
14970 /**
14971 * Handle the `'mouseup'` event for the scroll bar.
14972 */
14973 ScrollBar.prototype._evtMouseUp = function (event) {
14974 // Do nothing if it's not a left mouse release.
14975 if (event.button !== 0) {
14976 return;
14977 }
14978 // Stop the event propagation.
14979 event.preventDefault();
14980 event.stopPropagation();
14981 // Release the mouse.
14982 this._releaseMouse();
14983 };
14984 /**
14985 * Release the mouse and restore the node states.
14986 */
14987 ScrollBar.prototype._releaseMouse = function () {
14988 // Bail if there is no press data.
14989 if (!this._pressData) {
14990 return;
14991 }
14992 // Clear the repeat timer.
14993 clearTimeout(this._repeatTimer);
14994 this._repeatTimer = -1;
14995 // Clear the press data.
14996 this._pressData.override.dispose();
14997 this._pressData = null;
14998 // Remove the extra event listeners.
14999 document.removeEventListener('mousemove', this, true);
15000 document.removeEventListener('mouseup', this, true);
15001 document.removeEventListener('keydown', this, true);
15002 document.removeEventListener('contextmenu', this, true);
15003 // Remove the active classes from the nodes.
15004 this.thumbNode.classList.remove('lm-mod-active');
15005 this.decrementNode.classList.remove('lm-mod-active');
15006 this.incrementNode.classList.remove('lm-mod-active');
15007 /* <DEPRECATED> */
15008 this.thumbNode.classList.remove('p-mod-active');
15009 this.decrementNode.classList.remove('p-mod-active');
15010 this.incrementNode.classList.remove('p-mod-active');
15011 /* </DEPRECATED> */
15012 };
15013 /**
15014 * Move the thumb to the specified position.
15015 */
15016 ScrollBar.prototype._moveThumb = function (value) {
15017 // Clamp the value to the allowed range.
15018 value = Math.max(0, Math.min(value, this._maximum));
15019 // Bail if the value does not change.
15020 if (this._value === value) {
15021 return;
15022 }
15023 // Update the internal value.
15024 this._value = value;
15025 // Schedule an update of the scroll bar.
15026 this.update();
15027 // Emit the thumb moved signal.
15028 this._thumbMoved.emit(value);
15029 };
15030 return ScrollBar;
15031 }(exports.Widget));
15032 /**
15033 * The namespace for the module implementation details.
15034 */
15035 var Private$2;
15036 (function (Private) {
15037 /**
15038 * Create the DOM node for a scroll bar.
15039 */
15040 function createNode() {
15041 var node = document.createElement('div');
15042 var decrement = document.createElement('div');
15043 var increment = document.createElement('div');
15044 var track = document.createElement('div');
15045 var thumb = document.createElement('div');
15046 decrement.className = 'lm-ScrollBar-button';
15047 increment.className = 'lm-ScrollBar-button';
15048 decrement.dataset['action'] = 'decrement';
15049 increment.dataset['action'] = 'increment';
15050 track.className = 'lm-ScrollBar-track';
15051 thumb.className = 'lm-ScrollBar-thumb';
15052 /* <DEPRECATED> */
15053 decrement.classList.add('p-ScrollBar-button');
15054 increment.classList.add('p-ScrollBar-button');
15055 track.classList.add('p-ScrollBar-track');
15056 thumb.classList.add('p-ScrollBar-thumb');
15057 /* </DEPRECATED> */
15058 track.appendChild(thumb);
15059 node.appendChild(decrement);
15060 node.appendChild(track);
15061 node.appendChild(increment);
15062 return node;
15063 }
15064 Private.createNode = createNode;
15065 /**
15066 * Find the scroll bar part which contains the given target.
15067 */
15068 function findPart(scrollBar, target) {
15069 // Test the thumb.
15070 if (scrollBar.thumbNode.contains(target)) {
15071 return 'thumb';
15072 }
15073 // Test the track.
15074 if (scrollBar.trackNode.contains(target)) {
15075 return 'track';
15076 }
15077 // Test the decrement button.
15078 if (scrollBar.decrementNode.contains(target)) {
15079 return 'decrement';
15080 }
15081 // Test the increment button.
15082 if (scrollBar.incrementNode.contains(target)) {
15083 return 'increment';
15084 }
15085 // Indicate no match.
15086 return null;
15087 }
15088 Private.findPart = findPart;
15089 })(Private$2 || (Private$2 = {}));
15090
15091 /**
15092 * A concrete layout implementation which holds a single widget.
15093 *
15094 * #### Notes
15095 * This class is useful for creating simple container widgets which
15096 * hold a single child. The child should be positioned with CSS.
15097 */
15098 var SingletonLayout = /** @class */ (function (_super) {
15099 __extends(SingletonLayout, _super);
15100 function SingletonLayout() {
15101 var _this = _super !== null && _super.apply(this, arguments) || this;
15102 _this._widget = null;
15103 return _this;
15104 }
15105 /**
15106 * Dispose of the resources held by the layout.
15107 */
15108 SingletonLayout.prototype.dispose = function () {
15109 if (this._widget) {
15110 var widget = this._widget;
15111 this._widget = null;
15112 widget.dispose();
15113 }
15114 _super.prototype.dispose.call(this);
15115 };
15116 Object.defineProperty(SingletonLayout.prototype, "widget", {
15117 /**
15118 * Get the child widget for the layout.
15119 */
15120 get: function () {
15121 return this._widget;
15122 },
15123 /**
15124 * Set the child widget for the layout.
15125 *
15126 * #### Notes
15127 * Setting the child widget will cause the old child widget to be
15128 * automatically disposed. If that is not desired, set the parent
15129 * of the old child to `null` before assigning a new child.
15130 */
15131 set: function (widget) {
15132 // Remove the widget from its current parent. This is a no-op
15133 // if the widget's parent is already the layout parent widget.
15134 if (widget) {
15135 widget.parent = this.parent;
15136 }
15137 // Bail early if the widget does not change.
15138 if (this._widget === widget) {
15139 return;
15140 }
15141 // Dispose of the old child widget.
15142 if (this._widget) {
15143 this._widget.dispose();
15144 }
15145 // Update the internal widget.
15146 this._widget = widget;
15147 // Attach the new child widget if needed.
15148 if (this.parent && widget) {
15149 this.attachWidget(widget);
15150 }
15151 },
15152 enumerable: true,
15153 configurable: true
15154 });
15155 /**
15156 * Create an iterator over the widgets in the layout.
15157 *
15158 * @returns A new iterator over the widgets in the layout.
15159 */
15160 SingletonLayout.prototype.iter = function () {
15161 return this._widget ? algorithm.once(this._widget) : algorithm.empty();
15162 };
15163 /**
15164 * Remove a widget from the layout.
15165 *
15166 * @param widget - The widget to remove from the layout.
15167 *
15168 * #### Notes
15169 * A widget is automatically removed from the layout when its `parent`
15170 * is set to `null`. This method should only be invoked directly when
15171 * removing a widget from a layout which has yet to be installed on a
15172 * parent widget.
15173 *
15174 * This method does *not* modify the widget's `parent`.
15175 */
15176 SingletonLayout.prototype.removeWidget = function (widget) {
15177 // Bail early if the widget does not exist in the layout.
15178 if (this._widget !== widget) {
15179 return;
15180 }
15181 // Clear the internal widget.
15182 this._widget = null;
15183 // If the layout is parented, detach the widget from the DOM.
15184 if (this.parent) {
15185 this.detachWidget(widget);
15186 }
15187 };
15188 /**
15189 * Perform layout initialization which requires the parent widget.
15190 */
15191 SingletonLayout.prototype.init = function () {
15192 var _this = this;
15193 _super.prototype.init.call(this);
15194 algorithm.each(this, function (widget) {
15195 _this.attachWidget(widget);
15196 });
15197 };
15198 /**
15199 * Attach a widget to the parent's DOM node.
15200 *
15201 * @param index - The current index of the widget in the layout.
15202 *
15203 * @param widget - The widget to attach to the parent.
15204 *
15205 * #### Notes
15206 * This method is called automatically by the single layout at the
15207 * appropriate time. It should not be called directly by user code.
15208 *
15209 * The default implementation adds the widgets's node to the parent's
15210 * node at the proper location, and sends the appropriate attach
15211 * messages to the widget if the parent is attached to the DOM.
15212 *
15213 * Subclasses may reimplement this method to control how the widget's
15214 * node is added to the parent's node.
15215 */
15216 SingletonLayout.prototype.attachWidget = function (widget) {
15217 // Send a `'before-attach'` message if the parent is attached.
15218 if (this.parent.isAttached) {
15219 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.BeforeAttach);
15220 }
15221 // Add the widget's node to the parent.
15222 this.parent.node.appendChild(widget.node);
15223 // Send an `'after-attach'` message if the parent is attached.
15224 if (this.parent.isAttached) {
15225 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.AfterAttach);
15226 }
15227 };
15228 /**
15229 * Detach a widget from the parent's DOM node.
15230 *
15231 * @param widget - The widget to detach from the parent.
15232 *
15233 * #### Notes
15234 * This method is called automatically by the single layout at the
15235 * appropriate time. It should not be called directly by user code.
15236 *
15237 * The default implementation removes the widget's node from the
15238 * parent's node, and sends the appropriate detach messages to the
15239 * widget if the parent is attached to the DOM.
15240 *
15241 * Subclasses may reimplement this method to control how the widget's
15242 * node is removed from the parent's node.
15243 */
15244 SingletonLayout.prototype.detachWidget = function (widget) {
15245 // Send a `'before-detach'` message if the parent is attached.
15246 if (this.parent.isAttached) {
15247 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.BeforeDetach);
15248 }
15249 // Remove the widget's node from the parent.
15250 this.parent.node.removeChild(widget.node);
15251 // Send an `'after-detach'` message if the parent is attached.
15252 if (this.parent.isAttached) {
15253 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.AfterDetach);
15254 }
15255 };
15256 return SingletonLayout;
15257 }(exports.Layout));
15258
15259 /**
15260 * A layout where visible widgets are stacked atop one another.
15261 *
15262 * #### Notes
15263 * The Z-order of the visible widgets follows their layout order.
15264 */
15265 var StackedLayout = /** @class */ (function (_super) {
15266 __extends(StackedLayout, _super);
15267 function StackedLayout(options) {
15268 if (options === void 0) { options = {}; }
15269 var _this = _super.call(this, options) || this;
15270 _this._dirty = false;
15271 _this._items = [];
15272 _this._box = null;
15273 _this._hiddenMode =
15274 options.hiddenMode !== undefined
15275 ? options.hiddenMode
15276 : exports.Widget.HiddenMode.Display;
15277 return _this;
15278 }
15279 Object.defineProperty(StackedLayout.prototype, "hiddenMode", {
15280 /**
15281 * The method for hiding widgets.
15282 *
15283 * #### Notes
15284 * If there is only one child widget, `Display` hiding mode will be used
15285 * regardless of this setting.
15286 */
15287 get: function () {
15288 return this._hiddenMode;
15289 },
15290 /**
15291 * Set the method for hiding widgets.
15292 *
15293 * #### Notes
15294 * If there is only one child widget, `Display` hiding mode will be used
15295 * regardless of this setting.
15296 */
15297 set: function (v) {
15298 var _this = this;
15299 if (this._hiddenMode === v) {
15300 return;
15301 }
15302 this._hiddenMode = v;
15303 if (this.widgets.length > 1) {
15304 this.widgets.forEach(function (w) {
15305 w.hiddenMode = _this._hiddenMode;
15306 });
15307 }
15308 },
15309 enumerable: true,
15310 configurable: true
15311 });
15312 /**
15313 * Dispose of the resources held by the layout.
15314 */
15315 StackedLayout.prototype.dispose = function () {
15316 // Dispose of the layout items.
15317 algorithm.each(this._items, function (item) {
15318 item.dispose();
15319 });
15320 // Clear the layout state.
15321 this._box = null;
15322 this._items.length = 0;
15323 // Dispose of the rest of the layout.
15324 _super.prototype.dispose.call(this);
15325 };
15326 /**
15327 * Attach a widget to the parent's DOM node.
15328 *
15329 * @param index - The current index of the widget in the layout.
15330 *
15331 * @param widget - The widget to attach to the parent.
15332 *
15333 * #### Notes
15334 * This is a reimplementation of the superclass method.
15335 */
15336 StackedLayout.prototype.attachWidget = function (index, widget) {
15337 // Using transform create an additional layer in the pixel pipeline
15338 // to limit the number of layer, it is set only if there is more than one widget.
15339 if (this._hiddenMode === exports.Widget.HiddenMode.Scale &&
15340 this._items.length > 0) {
15341 if (this._items.length === 1) {
15342 this.widgets[0].hiddenMode = exports.Widget.HiddenMode.Scale;
15343 }
15344 widget.hiddenMode = exports.Widget.HiddenMode.Scale;
15345 }
15346 else {
15347 widget.hiddenMode = exports.Widget.HiddenMode.Display;
15348 }
15349 // Create and add a new layout item for the widget.
15350 algorithm.ArrayExt.insert(this._items, index, new LayoutItem(widget));
15351 // Send a `'before-attach'` message if the parent is attached.
15352 if (this.parent.isAttached) {
15353 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.BeforeAttach);
15354 }
15355 // Add the widget's node to the parent.
15356 this.parent.node.appendChild(widget.node);
15357 // Send an `'after-attach'` message if the parent is attached.
15358 if (this.parent.isAttached) {
15359 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.AfterAttach);
15360 }
15361 // Post a fit request for the parent widget.
15362 this.parent.fit();
15363 };
15364 /**
15365 * Move a widget in the parent's DOM node.
15366 *
15367 * @param fromIndex - The previous index of the widget in the layout.
15368 *
15369 * @param toIndex - The current index of the widget in the layout.
15370 *
15371 * @param widget - The widget to move in the parent.
15372 *
15373 * #### Notes
15374 * This is a reimplementation of the superclass method.
15375 */
15376 StackedLayout.prototype.moveWidget = function (fromIndex, toIndex, widget) {
15377 // Move the layout item for the widget.
15378 algorithm.ArrayExt.move(this._items, fromIndex, toIndex);
15379 // Post an update request for the parent widget.
15380 this.parent.update();
15381 };
15382 /**
15383 * Detach a widget from the parent's DOM node.
15384 *
15385 * @param index - The previous index of the widget in the layout.
15386 *
15387 * @param widget - The widget to detach from the parent.
15388 *
15389 * #### Notes
15390 * This is a reimplementation of the superclass method.
15391 */
15392 StackedLayout.prototype.detachWidget = function (index, widget) {
15393 // Remove the layout item for the widget.
15394 var item = algorithm.ArrayExt.removeAt(this._items, index);
15395 // Send a `'before-detach'` message if the parent is attached.
15396 if (this.parent.isAttached) {
15397 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.BeforeDetach);
15398 }
15399 // Remove the widget's node from the parent.
15400 this.parent.node.removeChild(widget.node);
15401 // Send an `'after-detach'` message if the parent is attached.
15402 if (this.parent.isAttached) {
15403 messaging.MessageLoop.sendMessage(widget, exports.Widget.Msg.AfterDetach);
15404 }
15405 // Reset the z-index for the widget.
15406 item.widget.node.style.zIndex = '';
15407 // Reset the hidden mode for the widget.
15408 if (this._hiddenMode === exports.Widget.HiddenMode.Scale) {
15409 widget.hiddenMode = exports.Widget.HiddenMode.Display;
15410 // Reset the hidden mode for the first widget if necessary.
15411 if (this._items.length === 1) {
15412 this._items[0].widget.hiddenMode = exports.Widget.HiddenMode.Display;
15413 }
15414 }
15415 // Dispose of the layout item.
15416 item.dispose();
15417 // Post a fit request for the parent widget.
15418 this.parent.fit();
15419 };
15420 /**
15421 * A message handler invoked on a `'before-show'` message.
15422 */
15423 StackedLayout.prototype.onBeforeShow = function (msg) {
15424 _super.prototype.onBeforeShow.call(this, msg);
15425 this.parent.update();
15426 };
15427 /**
15428 * A message handler invoked on a `'before-attach'` message.
15429 */
15430 StackedLayout.prototype.onBeforeAttach = function (msg) {
15431 _super.prototype.onBeforeAttach.call(this, msg);
15432 this.parent.fit();
15433 };
15434 /**
15435 * A message handler invoked on a `'child-shown'` message.
15436 */
15437 StackedLayout.prototype.onChildShown = function (msg) {
15438 this.parent.fit();
15439 };
15440 /**
15441 * A message handler invoked on a `'child-hidden'` message.
15442 */
15443 StackedLayout.prototype.onChildHidden = function (msg) {
15444 this.parent.fit();
15445 };
15446 /**
15447 * A message handler invoked on a `'resize'` message.
15448 */
15449 StackedLayout.prototype.onResize = function (msg) {
15450 if (this.parent.isVisible) {
15451 this._update(msg.width, msg.height);
15452 }
15453 };
15454 /**
15455 * A message handler invoked on an `'update-request'` message.
15456 */
15457 StackedLayout.prototype.onUpdateRequest = function (msg) {
15458 if (this.parent.isVisible) {
15459 this._update(-1, -1);
15460 }
15461 };
15462 /**
15463 * A message handler invoked on a `'fit-request'` message.
15464 */
15465 StackedLayout.prototype.onFitRequest = function (msg) {
15466 if (this.parent.isAttached) {
15467 this._fit();
15468 }
15469 };
15470 /**
15471 * Fit the layout to the total size required by the widgets.
15472 */
15473 StackedLayout.prototype._fit = function () {
15474 // Set up the computed minimum size.
15475 var minW = 0;
15476 var minH = 0;
15477 // Update the computed minimum size.
15478 for (var i = 0, n = this._items.length; i < n; ++i) {
15479 // Fetch the item.
15480 var item = this._items[i];
15481 // Ignore hidden items.
15482 if (item.isHidden) {
15483 continue;
15484 }
15485 // Update the size limits for the item.
15486 item.fit();
15487 // Update the computed minimum size.
15488 minW = Math.max(minW, item.minWidth);
15489 minH = Math.max(minH, item.minHeight);
15490 }
15491 // Update the box sizing and add it to the computed min size.
15492 var box = (this._box = domutils.ElementExt.boxSizing(this.parent.node));
15493 minW += box.horizontalSum;
15494 minH += box.verticalSum;
15495 // Update the parent's min size constraints.
15496 var style = this.parent.node.style;
15497 style.minWidth = minW + "px";
15498 style.minHeight = minH + "px";
15499 // Set the dirty flag to ensure only a single update occurs.
15500 this._dirty = true;
15501 // Notify the ancestor that it should fit immediately. This may
15502 // cause a resize of the parent, fulfilling the required update.
15503 if (this.parent.parent) {
15504 messaging.MessageLoop.sendMessage(this.parent.parent, exports.Widget.Msg.FitRequest);
15505 }
15506 // If the dirty flag is still set, the parent was not resized.
15507 // Trigger the required update on the parent widget immediately.
15508 if (this._dirty) {
15509 messaging.MessageLoop.sendMessage(this.parent, exports.Widget.Msg.UpdateRequest);
15510 }
15511 };
15512 /**
15513 * Update the layout position and size of the widgets.
15514 *
15515 * The parent offset dimensions should be `-1` if unknown.
15516 */
15517 StackedLayout.prototype._update = function (offsetWidth, offsetHeight) {
15518 // Clear the dirty flag to indicate the update occurred.
15519 this._dirty = false;
15520 // Compute the visible item count.
15521 var nVisible = 0;
15522 for (var i = 0, n = this._items.length; i < n; ++i) {
15523 nVisible += +!this._items[i].isHidden;
15524 }
15525 // Bail early if there are no visible items to layout.
15526 if (nVisible === 0) {
15527 return;
15528 }
15529 // Measure the parent if the offset dimensions are unknown.
15530 if (offsetWidth < 0) {
15531 offsetWidth = this.parent.node.offsetWidth;
15532 }
15533 if (offsetHeight < 0) {
15534 offsetHeight = this.parent.node.offsetHeight;
15535 }
15536 // Ensure the parent box sizing data is computed.
15537 if (!this._box) {
15538 this._box = domutils.ElementExt.boxSizing(this.parent.node);
15539 }
15540 // Compute the actual layout bounds adjusted for border and padding.
15541 var top = this._box.paddingTop;
15542 var left = this._box.paddingLeft;
15543 var width = offsetWidth - this._box.horizontalSum;
15544 var height = offsetHeight - this._box.verticalSum;
15545 // Update the widget stacking order and layout geometry.
15546 for (var i = 0, n = this._items.length; i < n; ++i) {
15547 // Fetch the item.
15548 var item = this._items[i];
15549 // Ignore hidden items.
15550 if (item.isHidden) {
15551 continue;
15552 }
15553 // Set the z-index for the widget.
15554 item.widget.node.style.zIndex = "" + i;
15555 // Update the item geometry.
15556 item.update(left, top, width, height);
15557 }
15558 };
15559 return StackedLayout;
15560 }(PanelLayout));
15561
15562 /**
15563 * A panel where visible widgets are stacked atop one another.
15564 *
15565 * #### Notes
15566 * This class provides a convenience wrapper around a [[StackedLayout]].
15567 */
15568 var StackedPanel = /** @class */ (function (_super) {
15569 __extends(StackedPanel, _super);
15570 /**
15571 * Construct a new stacked panel.
15572 *
15573 * @param options - The options for initializing the panel.
15574 */
15575 function StackedPanel(options) {
15576 if (options === void 0) { options = {}; }
15577 var _this = _super.call(this, { layout: Private$1.createLayout(options) }) || this;
15578 _this._widgetRemoved = new signaling.Signal(_this);
15579 _this.addClass('lm-StackedPanel');
15580 /* <DEPRECATED> */
15581 _this.addClass('p-StackedPanel');
15582 return _this;
15583 /* </DEPRECATED> */
15584 }
15585 Object.defineProperty(StackedPanel.prototype, "hiddenMode", {
15586 /**
15587 * The method for hiding widgets.
15588 *
15589 * #### Notes
15590 * If there is only one child widget, `Display` hiding mode will be used
15591 * regardless of this setting.
15592 */
15593 get: function () {
15594 return this.layout.hiddenMode;
15595 },
15596 /**
15597 * Set the method for hiding widgets.
15598 *
15599 * #### Notes
15600 * If there is only one child widget, `Display` hiding mode will be used
15601 * regardless of this setting.
15602 */
15603 set: function (v) {
15604 this.layout.hiddenMode = v;
15605 },
15606 enumerable: true,
15607 configurable: true
15608 });
15609 Object.defineProperty(StackedPanel.prototype, "widgetRemoved", {
15610 /**
15611 * A signal emitted when a widget is removed from a stacked panel.
15612 */
15613 get: function () {
15614 return this._widgetRemoved;
15615 },
15616 enumerable: true,
15617 configurable: true
15618 });
15619 /**
15620 * A message handler invoked on a `'child-added'` message.
15621 */
15622 StackedPanel.prototype.onChildAdded = function (msg) {
15623 msg.child.addClass('lm-StackedPanel-child');
15624 /* <DEPRECATED> */
15625 msg.child.addClass('p-StackedPanel-child');
15626 /* </DEPRECATED> */
15627 };
15628 /**
15629 * A message handler invoked on a `'child-removed'` message.
15630 */
15631 StackedPanel.prototype.onChildRemoved = function (msg) {
15632 msg.child.removeClass('lm-StackedPanel-child');
15633 /* <DEPRECATED> */
15634 msg.child.removeClass('p-StackedPanel-child');
15635 /* </DEPRECATED> */
15636 this._widgetRemoved.emit(msg.child);
15637 };
15638 return StackedPanel;
15639 }(Panel));
15640 /**
15641 * The namespace for the module implementation details.
15642 */
15643 var Private$1;
15644 (function (Private) {
15645 /**
15646 * Create a stacked layout for the given panel options.
15647 */
15648 function createLayout(options) {
15649 return options.layout || new StackedLayout();
15650 }
15651 Private.createLayout = createLayout;
15652 })(Private$1 || (Private$1 = {}));
15653
15654 /**
15655 * A widget which combines a `TabBar` and a `StackedPanel`.
15656 *
15657 * #### Notes
15658 * This is a simple panel which handles the common case of a tab bar
15659 * placed next to a content area. The selected tab controls the widget
15660 * which is shown in the content area.
15661 *
15662 * For use cases which require more control than is provided by this
15663 * panel, the `TabBar` widget may be used independently.
15664 */
15665 var TabPanel = /** @class */ (function (_super) {
15666 __extends(TabPanel, _super);
15667 /**
15668 * Construct a new tab panel.
15669 *
15670 * @param options - The options for initializing the tab panel.
15671 */
15672 function TabPanel(options) {
15673 if (options === void 0) { options = {}; }
15674 var _this = _super.call(this) || this;
15675 _this._currentChanged = new signaling.Signal(_this);
15676 _this._addRequested = new signaling.Signal(_this);
15677 _this.addClass('lm-TabPanel');
15678 /* <DEPRECATED> */
15679 _this.addClass('p-TabPanel');
15680 /* </DEPRECATED> */
15681 // Create the tab bar and stacked panel.
15682 _this.tabBar = new exports.TabBar(options);
15683 _this.tabBar.addClass('lm-TabPanel-tabBar');
15684 _this.stackedPanel = new StackedPanel();
15685 _this.stackedPanel.addClass('lm-TabPanel-stackedPanel');
15686 /* <DEPRECATED> */
15687 _this.tabBar.addClass('p-TabPanel-tabBar');
15688 _this.stackedPanel.addClass('p-TabPanel-stackedPanel');
15689 /* </DEPRECATED> */
15690 // Connect the tab bar signal handlers.
15691 _this.tabBar.tabMoved.connect(_this._onTabMoved, _this);
15692 _this.tabBar.currentChanged.connect(_this._onCurrentChanged, _this);
15693 _this.tabBar.tabCloseRequested.connect(_this._onTabCloseRequested, _this);
15694 _this.tabBar.tabActivateRequested.connect(_this._onTabActivateRequested, _this);
15695 _this.tabBar.addRequested.connect(_this._onTabAddRequested, _this);
15696 // Connect the stacked panel signal handlers.
15697 _this.stackedPanel.widgetRemoved.connect(_this._onWidgetRemoved, _this);
15698 // Get the data related to the placement.
15699 _this._tabPlacement = options.tabPlacement || 'top';
15700 var direction = Private.directionFromPlacement(_this._tabPlacement);
15701 var orientation = Private.orientationFromPlacement(_this._tabPlacement);
15702 // Configure the tab bar for the placement.
15703 _this.tabBar.orientation = orientation;
15704 _this.tabBar.dataset['placement'] = _this._tabPlacement;
15705 // Create the box layout.
15706 var layout = new exports.BoxLayout({ direction: direction, spacing: 0 });
15707 // Set the stretch factors for the child widgets.
15708 exports.BoxLayout.setStretch(_this.tabBar, 0);
15709 exports.BoxLayout.setStretch(_this.stackedPanel, 1);
15710 // Add the child widgets to the layout.
15711 layout.addWidget(_this.tabBar);
15712 layout.addWidget(_this.stackedPanel);
15713 // Install the layout on the tab panel.
15714 _this.layout = layout;
15715 return _this;
15716 }
15717 Object.defineProperty(TabPanel.prototype, "currentChanged", {
15718 /**
15719 * A signal emitted when the current tab is changed.
15720 *
15721 * #### Notes
15722 * This signal is emitted when the currently selected tab is changed
15723 * either through user or programmatic interaction.
15724 *
15725 * Notably, this signal is not emitted when the index of the current
15726 * tab changes due to tabs being inserted, removed, or moved. It is
15727 * only emitted when the actual current tab node is changed.
15728 */
15729 get: function () {
15730 return this._currentChanged;
15731 },
15732 enumerable: true,
15733 configurable: true
15734 });
15735 Object.defineProperty(TabPanel.prototype, "currentIndex", {
15736 /**
15737 * Get the index of the currently selected tab.
15738 *
15739 * #### Notes
15740 * This will be `-1` if no tab is selected.
15741 */
15742 get: function () {
15743 return this.tabBar.currentIndex;
15744 },
15745 /**
15746 * Set the index of the currently selected tab.
15747 *
15748 * #### Notes
15749 * If the index is out of range, it will be set to `-1`.
15750 */
15751 set: function (value) {
15752 this.tabBar.currentIndex = value;
15753 },
15754 enumerable: true,
15755 configurable: true
15756 });
15757 Object.defineProperty(TabPanel.prototype, "currentWidget", {
15758 /**
15759 * Get the currently selected widget.
15760 *
15761 * #### Notes
15762 * This will be `null` if there is no selected tab.
15763 */
15764 get: function () {
15765 var title = this.tabBar.currentTitle;
15766 return title ? title.owner : null;
15767 },
15768 /**
15769 * Set the currently selected widget.
15770 *
15771 * #### Notes
15772 * If the widget is not in the panel, it will be set to `null`.
15773 */
15774 set: function (value) {
15775 this.tabBar.currentTitle = value ? value.title : null;
15776 },
15777 enumerable: true,
15778 configurable: true
15779 });
15780 Object.defineProperty(TabPanel.prototype, "tabsMovable", {
15781 /**
15782 * Get the whether the tabs are movable by the user.
15783 *
15784 * #### Notes
15785 * Tabs can always be moved programmatically.
15786 */
15787 get: function () {
15788 return this.tabBar.tabsMovable;
15789 },
15790 /**
15791 * Set the whether the tabs are movable by the user.
15792 *
15793 * #### Notes
15794 * Tabs can always be moved programmatically.
15795 */
15796 set: function (value) {
15797 this.tabBar.tabsMovable = value;
15798 },
15799 enumerable: true,
15800 configurable: true
15801 });
15802 Object.defineProperty(TabPanel.prototype, "addButtonEnabled", {
15803 /**
15804 * Get the whether the add button is enabled.
15805 *
15806 */
15807 get: function () {
15808 return this.tabBar.addButtonEnabled;
15809 },
15810 /**
15811 * Set the whether the add button is enabled.
15812 *
15813 */
15814 set: function (value) {
15815 this.tabBar.addButtonEnabled = value;
15816 },
15817 enumerable: true,
15818 configurable: true
15819 });
15820 Object.defineProperty(TabPanel.prototype, "tabPlacement", {
15821 /**
15822 * Get the tab placement for the tab panel.
15823 *
15824 * #### Notes
15825 * This controls the position of the tab bar relative to the content.
15826 */
15827 get: function () {
15828 return this._tabPlacement;
15829 },
15830 /**
15831 * Set the tab placement for the tab panel.
15832 *
15833 * #### Notes
15834 * This controls the position of the tab bar relative to the content.
15835 */
15836 set: function (value) {
15837 // Bail if the placement does not change.
15838 if (this._tabPlacement === value) {
15839 return;
15840 }
15841 // Update the internal value.
15842 this._tabPlacement = value;
15843 // Get the values related to the placement.
15844 var direction = Private.directionFromPlacement(value);
15845 var orientation = Private.orientationFromPlacement(value);
15846 // Configure the tab bar for the placement.
15847 this.tabBar.orientation = orientation;
15848 this.tabBar.dataset['placement'] = value;
15849 // Update the layout direction.
15850 this.layout.direction = direction;
15851 },
15852 enumerable: true,
15853 configurable: true
15854 });
15855 Object.defineProperty(TabPanel.prototype, "addRequested", {
15856 /**
15857 * A signal emitted when the add button on a tab bar is clicked.
15858 *
15859 */
15860 get: function () {
15861 return this._addRequested;
15862 },
15863 enumerable: true,
15864 configurable: true
15865 });
15866 Object.defineProperty(TabPanel.prototype, "widgets", {
15867 /**
15868 * A read-only array of the widgets in the panel.
15869 */
15870 get: function () {
15871 return this.stackedPanel.widgets;
15872 },
15873 enumerable: true,
15874 configurable: true
15875 });
15876 /**
15877 * Add a widget to the end of the tab panel.
15878 *
15879 * @param widget - The widget to add to the tab panel.
15880 *
15881 * #### Notes
15882 * If the widget is already contained in the panel, it will be moved.
15883 *
15884 * The widget's `title` is used to populate the tab.
15885 */
15886 TabPanel.prototype.addWidget = function (widget) {
15887 this.insertWidget(this.widgets.length, widget);
15888 };
15889 /**
15890 * Insert a widget into the tab panel at a specified index.
15891 *
15892 * @param index - The index at which to insert the widget.
15893 *
15894 * @param widget - The widget to insert into to the tab panel.
15895 *
15896 * #### Notes
15897 * If the widget is already contained in the panel, it will be moved.
15898 *
15899 * The widget's `title` is used to populate the tab.
15900 */
15901 TabPanel.prototype.insertWidget = function (index, widget) {
15902 if (widget !== this.currentWidget) {
15903 widget.hide();
15904 }
15905 this.stackedPanel.insertWidget(index, widget);
15906 this.tabBar.insertTab(index, widget.title);
15907 widget.node.setAttribute('role', 'tabpanel');
15908 var renderer = this.tabBar.renderer;
15909 if (renderer instanceof exports.TabBar.Renderer) {
15910 var tabId = renderer.createTabKey({
15911 title: widget.title,
15912 current: false,
15913 zIndex: 0
15914 });
15915 widget.node.setAttribute('aria-labelledby', tabId);
15916 }
15917 };
15918 /**
15919 * Handle the `currentChanged` signal from the tab bar.
15920 */
15921 TabPanel.prototype._onCurrentChanged = function (sender, args) {
15922 // Extract the previous and current title from the args.
15923 var previousIndex = args.previousIndex, previousTitle = args.previousTitle, currentIndex = args.currentIndex, currentTitle = args.currentTitle;
15924 // Extract the widgets from the titles.
15925 var previousWidget = previousTitle ? previousTitle.owner : null;
15926 var currentWidget = currentTitle ? currentTitle.owner : null;
15927 // Hide the previous widget.
15928 if (previousWidget) {
15929 previousWidget.hide();
15930 }
15931 // Show the current widget.
15932 if (currentWidget) {
15933 currentWidget.show();
15934 }
15935 // Emit the `currentChanged` signal for the tab panel.
15936 this._currentChanged.emit({
15937 previousIndex: previousIndex,
15938 previousWidget: previousWidget,
15939 currentIndex: currentIndex,
15940 currentWidget: currentWidget
15941 });
15942 // Flush the message loop on IE and Edge to prevent flicker.
15943 if (domutils.Platform.IS_EDGE || domutils.Platform.IS_IE) {
15944 messaging.MessageLoop.flush();
15945 }
15946 };
15947 /**
15948 * Handle the `tabAddRequested` signal from the tab bar.
15949 */
15950 TabPanel.prototype._onTabAddRequested = function (sender, args) {
15951 this._addRequested.emit(sender);
15952 };
15953 /**
15954 * Handle the `tabActivateRequested` signal from the tab bar.
15955 */
15956 TabPanel.prototype._onTabActivateRequested = function (sender, args) {
15957 args.title.owner.activate();
15958 };
15959 /**
15960 * Handle the `tabCloseRequested` signal from the tab bar.
15961 */
15962 TabPanel.prototype._onTabCloseRequested = function (sender, args) {
15963 args.title.owner.close();
15964 };
15965 /**
15966 * Handle the `tabMoved` signal from the tab bar.
15967 */
15968 TabPanel.prototype._onTabMoved = function (sender, args) {
15969 this.stackedPanel.insertWidget(args.toIndex, args.title.owner);
15970 };
15971 /**
15972 * Handle the `widgetRemoved` signal from the stacked panel.
15973 */
15974 TabPanel.prototype._onWidgetRemoved = function (sender, widget) {
15975 widget.node.removeAttribute('role');
15976 widget.node.removeAttribute('aria-labelledby');
15977 this.tabBar.removeTab(widget.title);
15978 };
15979 return TabPanel;
15980 }(exports.Widget));
15981 /**
15982 * The namespace for the module implementation details.
15983 */
15984 var Private;
15985 (function (Private) {
15986 /**
15987 * Convert a tab placement to tab bar orientation.
15988 */
15989 function orientationFromPlacement(plc) {
15990 return placementToOrientationMap[plc];
15991 }
15992 Private.orientationFromPlacement = orientationFromPlacement;
15993 /**
15994 * Convert a tab placement to a box layout direction.
15995 */
15996 function directionFromPlacement(plc) {
15997 return placementToDirectionMap[plc];
15998 }
15999 Private.directionFromPlacement = directionFromPlacement;
16000 /**
16001 * A mapping of tab placement to tab bar orientation.
16002 */
16003 var placementToOrientationMap = {
16004 top: 'horizontal',
16005 left: 'vertical',
16006 right: 'vertical',
16007 bottom: 'horizontal'
16008 };
16009 /**
16010 * A mapping of tab placement to box layout direction.
16011 */
16012 var placementToDirectionMap = {
16013 top: 'top-to-bottom',
16014 left: 'left-to-right',
16015 right: 'right-to-left',
16016 bottom: 'bottom-to-top'
16017 };
16018 })(Private || (Private = {}));
16019
16020 exports.AccordionLayout = AccordionLayout;
16021 exports.BoxSizer = BoxSizer;
16022 exports.ContextMenu = ContextMenu;
16023 exports.DockLayout = DockLayout;
16024 exports.FocusTracker = FocusTracker;
16025 exports.LayoutItem = LayoutItem;
16026 exports.Panel = Panel;
16027 exports.PanelLayout = PanelLayout;
16028 exports.ScrollBar = ScrollBar;
16029 exports.SingletonLayout = SingletonLayout;
16030 exports.StackedLayout = StackedLayout;
16031 exports.StackedPanel = StackedPanel;
16032 exports.TabPanel = TabPanel;
16033 exports.Title = Title;
16034
16035 Object.defineProperty(exports, '__esModule', { value: true });
16036
16037})));
16038//# sourceMappingURL=index.js.map