@deephaven/golden-layout 0.43.0 → 0.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/css/goldenlayout-base.css +1 -1
  2. package/css/goldenlayout-base.css.map +1 -1
  3. package/css/goldenlayout-dark-theme.css +1 -1
  4. package/css/goldenlayout-dark-theme.css.map +1 -1
  5. package/dist/GoldenLayout.module.css +1 -0
  6. package/dist/GoldenLayout.module.css.map +1 -0
  7. package/dist/GoldenLayoutThemeExport.js +6 -0
  8. package/dist/GoldenLayoutThemeExport.js.map +1 -0
  9. package/dist/LayoutManager.js +1001 -0
  10. package/dist/LayoutManager.js.map +1 -0
  11. package/dist/base.js +16 -0
  12. package/dist/base.js.map +1 -0
  13. package/dist/config/Config.js +42 -0
  14. package/dist/config/Config.js.map +1 -0
  15. package/dist/config/ItemConfig.js +14 -0
  16. package/dist/config/ItemConfig.js.map +1 -0
  17. package/dist/config/index.js +3 -0
  18. package/dist/config/index.js.map +1 -0
  19. package/dist/container/ItemContainer.js +199 -0
  20. package/dist/container/ItemContainer.js.map +1 -0
  21. package/dist/container/index.js +3 -0
  22. package/dist/container/index.js.map +1 -0
  23. package/dist/controls/BrowserPopout.js +250 -0
  24. package/dist/controls/BrowserPopout.js.map +1 -0
  25. package/dist/controls/DragProxy.js +204 -0
  26. package/dist/controls/DragProxy.js.map +1 -0
  27. package/dist/controls/DragSource.js +52 -0
  28. package/dist/controls/DragSource.js.map +1 -0
  29. package/dist/controls/DragSourceFromEvent.js +71 -0
  30. package/dist/controls/DragSourceFromEvent.js.map +1 -0
  31. package/dist/controls/DropTargetIndicator.js +27 -0
  32. package/dist/controls/DropTargetIndicator.js.map +1 -0
  33. package/dist/controls/Header.js +736 -0
  34. package/dist/controls/Header.js.map +1 -0
  35. package/dist/controls/HeaderButton.js +22 -0
  36. package/dist/controls/HeaderButton.js.map +1 -0
  37. package/dist/controls/Splitter.js +49 -0
  38. package/dist/controls/Splitter.js.map +1 -0
  39. package/dist/controls/Tab.js +225 -0
  40. package/dist/controls/Tab.js.map +1 -0
  41. package/dist/controls/index.js +10 -0
  42. package/dist/controls/index.js.map +1 -0
  43. package/dist/declaration.d.js +2 -0
  44. package/dist/declaration.d.js.map +1 -0
  45. package/dist/errors/ConfigurationError.js +14 -0
  46. package/dist/errors/ConfigurationError.js.map +1 -0
  47. package/dist/errors/index.js +2 -0
  48. package/dist/errors/index.js.map +1 -0
  49. package/dist/index.js +11 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/items/AbstractContentItem.js +565 -0
  52. package/dist/items/AbstractContentItem.js.map +1 -0
  53. package/dist/items/Component.js +80 -0
  54. package/dist/items/Component.js.map +1 -0
  55. package/dist/items/Root.js +100 -0
  56. package/dist/items/Root.js.map +1 -0
  57. package/dist/items/RowOrColumn.js +488 -0
  58. package/dist/items/RowOrColumn.js.map +1 -0
  59. package/dist/items/Stack.js +479 -0
  60. package/dist/items/Stack.js.map +1 -0
  61. package/dist/items/index.js +8 -0
  62. package/dist/items/index.js.map +1 -0
  63. package/dist/utils/BubblingEvent.js +17 -0
  64. package/dist/utils/BubblingEvent.js.map +1 -0
  65. package/dist/utils/ConfigMinifier.js +147 -0
  66. package/dist/utils/ConfigMinifier.js.map +1 -0
  67. package/dist/utils/DragListener.js +125 -0
  68. package/dist/utils/DragListener.js.map +1 -0
  69. package/dist/utils/EventEmitter.js +117 -0
  70. package/dist/utils/EventEmitter.js.map +1 -0
  71. package/dist/utils/EventHub.js +108 -0
  72. package/dist/utils/EventHub.js.map +1 -0
  73. package/dist/utils/ReactComponentHandler.js +136 -0
  74. package/dist/utils/ReactComponentHandler.js.map +1 -0
  75. package/dist/utils/index.js +8 -0
  76. package/dist/utils/index.js.map +1 -0
  77. package/dist/utils/utils.js +65 -0
  78. package/dist/utils/utils.js.map +1 -0
  79. package/package.json +3 -3
@@ -0,0 +1,736 @@
1
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
2
+ function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
3
+ function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
4
+ import $ from 'jquery';
5
+ import { EventEmitter } from "../utils/index.js";
6
+ import HeaderButton from "./HeaderButton.js";
7
+ import Tab from "./Tab.js";
8
+ /**
9
+ * This class represents a header above a Stack ContentItem.
10
+ *
11
+ * @param layoutManager
12
+ * @param parent
13
+ */
14
+ export default class Header extends EventEmitter {
15
+ // use for scroll repeat
16
+
17
+ // mouse hold timeout to act as hold instead of click
18
+
19
+ // mouse hold acceleration
20
+
21
+ constructor(layoutManager, parent) {
22
+ var _this$layoutManager$c, _this$layoutManager$c2;
23
+ super();
24
+ _defineProperty(this, "layoutManager", void 0);
25
+ _defineProperty(this, "element", $(Header._template));
26
+ _defineProperty(this, "tabsContainer", void 0);
27
+ _defineProperty(this, "tabDropdownContainer", void 0);
28
+ _defineProperty(this, "tabDropdownSearch", void 0);
29
+ _defineProperty(this, "tabDropdownList", null);
30
+ _defineProperty(this, "controlsContainer", void 0);
31
+ _defineProperty(this, "parent", void 0);
32
+ _defineProperty(this, "tabs", []);
33
+ _defineProperty(this, "activeContentItem", null);
34
+ _defineProperty(this, "closeButton", null);
35
+ _defineProperty(this, "tabDropdownButton", null);
36
+ _defineProperty(this, "tabNextButton", $(Header._nextButtonTemplate));
37
+ _defineProperty(this, "tabPreviousButton", $(Header._previousButtonTemplate));
38
+ _defineProperty(this, "holdTimer", null);
39
+ _defineProperty(this, "rAF", null);
40
+ _defineProperty(this, "CLICK_TIMEOUT", 500);
41
+ _defineProperty(this, "START_SPEED", 0.01);
42
+ _defineProperty(this, "ACCELERATION", 0.0005);
43
+ _defineProperty(this, "PADDING", 10);
44
+ _defineProperty(this, "SCROLL_LEFT", 'left');
45
+ _defineProperty(this, "SCROLL_RIGHT", 'right');
46
+ _defineProperty(this, "isDraggingTab", false);
47
+ _defineProperty(this, "isOverflowing", false);
48
+ _defineProperty(this, "isDropdownShown", false);
49
+ _defineProperty(this, "dropdownKeyIndex", 0);
50
+ _defineProperty(this, "_lastVisibleTabIndex", -1);
51
+ _defineProperty(this, "_tabControlOffset", void 0);
52
+ this.layoutManager = layoutManager;
53
+ if ((_this$layoutManager$c = this.layoutManager.config.settings) !== null && _this$layoutManager$c !== void 0 && _this$layoutManager$c.selectionEnabled) {
54
+ this.element.addClass('lm_selectable');
55
+ this.element.on('click', this._onHeaderClick.bind(this));
56
+ }
57
+ this.tabsContainer = this.element.find('.lm_tabs');
58
+ this.tabDropdownContainer = this.element.find('.lm_tabdropdown_list');
59
+ this.tabDropdownContainer.hide();
60
+ this.tabDropdownSearch = this.element.find('.lm_tabdropdown_search input');
61
+ this._handleFilterInput = this._handleFilterInput.bind(this);
62
+ this._handleFilterKeydown = this._handleFilterKeydown.bind(this);
63
+ this.tabDropdownSearch.on('input', this._handleFilterInput);
64
+ this.tabDropdownSearch.on('keydown', this._handleFilterKeydown);
65
+ this.controlsContainer = this.element.find('.lm_controls');
66
+ this.parent = parent;
67
+ this.parent.on('resize', this._updateTabSizes, this);
68
+ this._handleItemPickedUp = this._handleItemPickedUp.bind(this);
69
+ this._handleItemDropped = this._handleItemDropped.bind(this);
70
+ this._handleNextMouseEnter = this._handleNextMouseEnter.bind(this);
71
+ this._handleNextMouseLeave = this._handleNextMouseLeave.bind(this);
72
+ this._handlePreviousMouseEnter = this._handlePreviousMouseEnter.bind(this);
73
+ this._handlePreviousMouseLeave = this._handlePreviousMouseLeave.bind(this);
74
+ this._handleScrollRepeat = this._handleScrollRepeat.bind(this);
75
+ this._handleNextButtonMouseDown = this._handleNextButtonMouseDown.bind(this);
76
+ this._handlePreviousButtonMouseDown = this._handlePreviousButtonMouseDown.bind(this);
77
+ this._handleScrollButtonMouseDown = this._handleScrollButtonMouseDown.bind(this);
78
+ this._handleScrollButtonMouseUp = this._handleScrollButtonMouseUp.bind(this);
79
+ this._handleScrollEvent = this._handleScrollEvent.bind(this);
80
+ this.tabNextButton.on('mousedown', this._handleNextButtonMouseDown);
81
+ this.tabPreviousButton.on('mousedown', this._handlePreviousButtonMouseDown);
82
+ this.tabsContainer.on('scroll', this._handleScrollEvent);
83
+ this.layoutManager.on('itemPickedUp', this._handleItemPickedUp);
84
+ this.layoutManager.on('itemDropped', this._handleItemDropped);
85
+
86
+ // append previous button template
87
+ this.tabsContainer.before(this.tabPreviousButton);
88
+ // change reference to just the li, not the wrapping ul
89
+ this.tabPreviousButton = this.tabPreviousButton.find('>:first-child');
90
+ this.tabPreviousButton.hide();
91
+ this._showAdditionalTabsDropdown = this._showAdditionalTabsDropdown.bind(this);
92
+ this._hideAdditionalTabsDropdown = this._hideAdditionalTabsDropdown.bind(this);
93
+ this._tabControlOffset = (_this$layoutManager$c2 = this.layoutManager.config.settings) === null || _this$layoutManager$c2 === void 0 ? void 0 : _this$layoutManager$c2.tabControlOffset;
94
+ this._createControls();
95
+ }
96
+
97
+ /**
98
+ * Creates a new tab and associates it with a contentItem
99
+ *
100
+ * @param contentItem
101
+ * @param index The position of the tab
102
+ */
103
+ createTab(contentItem, index) {
104
+ //If there's already a tab relating to the
105
+ //content item, don't do anything
106
+ for (var i = 0; i < this.tabs.length; i++) {
107
+ if (this.tabs[i].contentItem === contentItem) {
108
+ return;
109
+ }
110
+ }
111
+ var tab = new Tab(this, contentItem);
112
+ if (this.tabs.length === 0) {
113
+ this.tabs.push(tab);
114
+ this.tabsContainer.append(tab.element);
115
+ return;
116
+ }
117
+ if (index === undefined) {
118
+ index = this.tabs.length;
119
+ }
120
+ if (index > 0) {
121
+ this.tabs[index - 1].element.after(tab.element);
122
+ } else {
123
+ this.tabs[0].element.before(tab.element);
124
+ }
125
+ this.tabs.splice(index, 0, tab);
126
+ this._updateTabSizes();
127
+ }
128
+
129
+ /**
130
+ * Finds a tab based on the contentItem its associated with and removes it.
131
+ *
132
+ * @param contentItem
133
+ */
134
+ removeTab(contentItem) {
135
+ for (var i = 0; i < this.tabs.length; i++) {
136
+ if (this.tabs[i].contentItem === contentItem) {
137
+ this.tabs[i]._$destroy();
138
+ this.tabs.splice(i, 1);
139
+ return;
140
+ }
141
+ }
142
+ throw new Error('contentItem is not controlled by this header');
143
+ }
144
+
145
+ /**
146
+ * The programmatical equivalent of clicking a Tab.
147
+ *
148
+ * @param contentItem
149
+ */
150
+ setActiveContentItem(contentItem) {
151
+ var _this$tabs$element$ge, _this$parent$config$a;
152
+ var isActive;
153
+ for (var i = 0; i < this.tabs.length; i++) {
154
+ isActive = this.tabs[i].contentItem === contentItem;
155
+ this.tabs[i].setActive(isActive);
156
+ if (isActive === true) {
157
+ this.activeContentItem = contentItem;
158
+ this.parent.config.activeItemIndex = i;
159
+ }
160
+ }
161
+
162
+ // makes sure dropped tabs are scrollintoview, removed any re-ordering
163
+ (_this$tabs$element$ge = this.tabs[(_this$parent$config$a = this.parent.config.activeItemIndex) !== null && _this$parent$config$a !== void 0 ? _this$parent$config$a : 0].element.get(0)) === null || _this$tabs$element$ge === void 0 ? void 0 : _this$tabs$element$ge.scrollIntoView({
164
+ inline: 'nearest'
165
+ });
166
+ this._hideAdditionalTabsDropdown();
167
+ this._updateTabSizes();
168
+ this.parent.emitBubblingEvent('stateChanged');
169
+ }
170
+
171
+ /**
172
+ * Programmatically operate with header position.
173
+ *
174
+ * @param position one of ('top','left','right','bottom') to set or empty to get it.
175
+ *
176
+ * @returns previous header position
177
+ */
178
+ position(position) {
179
+ var previous = this.parent._header.show;
180
+ if (previous && !this.parent._side) previous = 'top';
181
+ if (position !== undefined && this.parent._header.show !== position) {
182
+ this.parent._header.show = position;
183
+ this.parent._setupHeaderPosition();
184
+ }
185
+ return previous;
186
+ }
187
+
188
+ // Manually attaching so wheel can be passive instead of jquery .on
189
+ // _attachWheelListener is called by parent init
190
+ _attachWheelListener() {
191
+ var _this$tabsContainer$g;
192
+ (_this$tabsContainer$g = this.tabsContainer.get(0)) === null || _this$tabsContainer$g === void 0 ? void 0 : _this$tabsContainer$g.addEventListener('wheel', this._handleWheelEvent, {
193
+ passive: true
194
+ });
195
+ }
196
+
197
+ // detach called by this.destroy
198
+ _detachWheelListener() {
199
+ var _this$tabsContainer$g2;
200
+ (_this$tabsContainer$g2 = this.tabsContainer.get(0)) === null || _this$tabsContainer$g2 === void 0 ? void 0 : _this$tabsContainer$g2.removeEventListener('wheel', this._handleWheelEvent);
201
+ }
202
+ _handleWheelEvent(event) {
203
+ var target = event.currentTarget;
204
+ if (!(target instanceof HTMLElement)) {
205
+ return;
206
+ }
207
+
208
+ // we only care about the larger of the two deltas
209
+ var delta = Math.abs(event.deltaY) > Math.abs(event.deltaX) ? event.deltaY : event.deltaX;
210
+
211
+ // jshint
212
+ /* globals WheelEvent */
213
+ if (event.deltaMode === WheelEvent.DOM_DELTA_PAGE) {
214
+ var _this$tabsContainer$i;
215
+ // Users can set OS to be in deltaMode page
216
+ // scrolly by page units as pixels
217
+ delta *= (_this$tabsContainer$i = this.tabsContainer.innerWidth()) !== null && _this$tabsContainer$i !== void 0 ? _this$tabsContainer$i : 1;
218
+ } else if (event.deltaMode === WheelEvent.DOM_DELTA_LINE) {
219
+ // chrome goes 100px per 3 lines, and firefox would go 102 per 3 (17 lineheight * 3 lines * 2)
220
+ delta *= 100 / 3;
221
+ }
222
+ target.scrollLeft += Math.round(delta);
223
+ }
224
+
225
+ // on scroll we need to check if side error might need to be disabled
226
+ _handleScrollEvent() {
227
+ this._checkScrollArrows();
228
+ }
229
+
230
+ // when and item is picked up, attach mouse enter listeners to next/previous buttons
231
+ _handleItemPickedUp() {
232
+ this.isDraggingTab = true;
233
+ if (this.isDropdownShown) this._hideAdditionalTabsDropdown();
234
+ this.controlsContainer.on('mouseenter', this._handleNextMouseEnter);
235
+ this.tabPreviousButton.on('mouseenter', this._handlePreviousMouseEnter);
236
+ }
237
+
238
+ // when an item is dropped remove listeners and cancel animation
239
+ _handleItemDropped() {
240
+ var _this$rAF;
241
+ this.isDraggingTab = false;
242
+ window.cancelAnimationFrame((_this$rAF = this.rAF) !== null && _this$rAF !== void 0 ? _this$rAF : -1);
243
+ this.rAF = null;
244
+ this.controlsContainer.off('mouseenter', this._handleNextMouseEnter);
245
+ this.controlsContainer.off('mouseleave', this._handleNextMouseLeave);
246
+ this.tabPreviousButton.off('mouseenter', this._handlePreviousMouseEnter);
247
+ this.tabPreviousButton.off('mouseleave', this._handlePreviousMouseLeave);
248
+ }
249
+
250
+ // on next/previous enter start scroll repeat animation loop
251
+ // and attach a listener looking for mouseleave
252
+ // cancel animation on mouse leave, and remove leave listener
253
+ _handleNextMouseEnter() {
254
+ var _this$tabsContainer$s;
255
+ this.controlsContainer.on('mouseleave', this._handleNextMouseLeave);
256
+ this._handleScrollRepeat(this.SCROLL_RIGHT, (_this$tabsContainer$s = this.tabsContainer.scrollLeft()) !== null && _this$tabsContainer$s !== void 0 ? _this$tabsContainer$s : 0);
257
+ }
258
+ _handlePreviousMouseEnter() {
259
+ var _this$tabsContainer$s2;
260
+ this.tabPreviousButton.on('mouseleave', this._handlePreviousMouseLeave);
261
+ this._handleScrollRepeat(this.SCROLL_LEFT, (_this$tabsContainer$s2 = this.tabsContainer.scrollLeft()) !== null && _this$tabsContainer$s2 !== void 0 ? _this$tabsContainer$s2 : 0);
262
+ }
263
+ _handleNextMouseLeave() {
264
+ var _this$rAF2;
265
+ window.cancelAnimationFrame((_this$rAF2 = this.rAF) !== null && _this$rAF2 !== void 0 ? _this$rAF2 : -1);
266
+ this.rAF = null;
267
+ this.controlsContainer.off('mouseleave', this._handleNextMouseLeave);
268
+ }
269
+ _handlePreviousMouseLeave() {
270
+ var _this$rAF3;
271
+ window.cancelAnimationFrame((_this$rAF3 = this.rAF) !== null && _this$rAF3 !== void 0 ? _this$rAF3 : -1);
272
+ this.rAF = null;
273
+ this.tabPreviousButton.off('mouseleave', this._handlePreviousMouseLeave);
274
+ }
275
+
276
+ // scroll one tab to the right on mouse down
277
+ // start scrollRepeat if mouse is held down
278
+ _handleNextButtonMouseDown() {
279
+ var rightOffscreenChild;
280
+ for (var i = 0; i < this.tabs.length; i += 1) {
281
+ var _this$tabs$i$element$, _this$tabs$i$element$2, _this$tabsContainer$g3, _this$tabsContainer$g4, _this$tabsContainer$s3;
282
+ if (((_this$tabs$i$element$ = (_this$tabs$i$element$2 = this.tabs[i].element.get(0)) === null || _this$tabs$i$element$2 === void 0 ? void 0 : _this$tabs$i$element$2.offsetLeft) !== null && _this$tabs$i$element$ !== void 0 ? _this$tabs$i$element$ : 0) > ((_this$tabsContainer$g3 = (_this$tabsContainer$g4 = this.tabsContainer.get(0)) === null || _this$tabsContainer$g4 === void 0 ? void 0 : _this$tabsContainer$g4.offsetWidth) !== null && _this$tabsContainer$g3 !== void 0 ? _this$tabsContainer$g3 : 0) + ((_this$tabsContainer$s3 = this.tabsContainer.scrollLeft()) !== null && _this$tabsContainer$s3 !== void 0 ? _this$tabsContainer$s3 : 0)) {
283
+ rightOffscreenChild = this.tabs[i].element.get(0);
284
+ break;
285
+ }
286
+ }
287
+ if (rightOffscreenChild) {
288
+ rightOffscreenChild.scrollIntoView({
289
+ behavior: 'smooth',
290
+ inline: 'nearest'
291
+ });
292
+ this._handleScrollButtonMouseDown(this.SCROLL_RIGHT);
293
+ } else {
294
+ var tabsContainer = this.tabsContainer.get(0);
295
+ if (tabsContainer) {
296
+ var _this$tabsContainer$g5, _this$tabsContainer$g6;
297
+ tabsContainer.scrollLeft = (_this$tabsContainer$g5 = (_this$tabsContainer$g6 = this.tabsContainer.get(0)) === null || _this$tabsContainer$g6 === void 0 ? void 0 : _this$tabsContainer$g6.scrollWidth) !== null && _this$tabsContainer$g5 !== void 0 ? _this$tabsContainer$g5 : 0;
298
+ }
299
+ }
300
+ }
301
+
302
+ // scroll left by one tab
303
+ // start scrollRepeat if mouse is held down
304
+ _handlePreviousButtonMouseDown() {
305
+ var leftOffscreenChild;
306
+ for (var i = this.tabs.length - 1; i >= 0; i -= 1) {
307
+ var _this$tabs$i$element$3, _this$tabs$i$element$4, _this$tabsContainer$s4;
308
+ if (((_this$tabs$i$element$3 = (_this$tabs$i$element$4 = this.tabs[i].element.get(0)) === null || _this$tabs$i$element$4 === void 0 ? void 0 : _this$tabs$i$element$4.offsetLeft) !== null && _this$tabs$i$element$3 !== void 0 ? _this$tabs$i$element$3 : 0) < ((_this$tabsContainer$s4 = this.tabsContainer.scrollLeft()) !== null && _this$tabsContainer$s4 !== void 0 ? _this$tabsContainer$s4 : 0)) {
309
+ leftOffscreenChild = this.tabs[i].element.get(0);
310
+ break;
311
+ }
312
+ }
313
+ if (leftOffscreenChild) {
314
+ leftOffscreenChild.scrollIntoView({
315
+ behavior: 'smooth',
316
+ inline: 'start'
317
+ });
318
+ this._handleScrollButtonMouseDown(this.SCROLL_LEFT);
319
+ } else {
320
+ var tabsContainer = this.tabsContainer.get(0);
321
+ if (tabsContainer) {
322
+ tabsContainer.scrollLeft = 0;
323
+ }
324
+ }
325
+ }
326
+
327
+ // when hold timer is reached start scroll repeat anim loop
328
+ // cancel it when mouse up happens anywhere
329
+ _handleScrollButtonMouseDown(direction) {
330
+ // closure so that scrollLeft is value at end of timer, and not start of timer
331
+ this.holdTimer = window.setTimeout(() => {
332
+ var _this$tabsContainer$s5;
333
+ this._handleScrollRepeat(direction, (_this$tabsContainer$s5 = this.tabsContainer.scrollLeft()) !== null && _this$tabsContainer$s5 !== void 0 ? _this$tabsContainer$s5 : 0, 100); // kickstart deltaX to be faster
334
+ }, this.CLICK_TIMEOUT);
335
+ window.addEventListener('mouseup', this._handleScrollButtonMouseUp);
336
+ }
337
+
338
+ // cancel scroll repeat
339
+ _handleScrollButtonMouseUp() {
340
+ var _this$holdTimer, _this$rAF4;
341
+ clearTimeout((_this$holdTimer = this.holdTimer) !== null && _this$holdTimer !== void 0 ? _this$holdTimer : -1);
342
+ this.holdTimer = null;
343
+ cancelAnimationFrame((_this$rAF4 = this.rAF) !== null && _this$rAF4 !== void 0 ? _this$rAF4 : -1);
344
+ this.rAF = null;
345
+ window.removeEventListener('mouseup', this._handleScrollButtonMouseUp);
346
+ }
347
+
348
+ // disables scroll arrow if at edge of scroll area
349
+ _checkScrollArrows() {
350
+ var _this$tabsContainer$s6, _this$tabsContainer$i2, _this$tabsContainer$g7;
351
+ if (this.tabsContainer.scrollLeft() === 0) {
352
+ this.tabPreviousButton.first().prop('disabled', true);
353
+ } else if (((_this$tabsContainer$s6 = this.tabsContainer.scrollLeft()) !== null && _this$tabsContainer$s6 !== void 0 ? _this$tabsContainer$s6 : 0) + ((_this$tabsContainer$i2 = this.tabsContainer.innerWidth()) !== null && _this$tabsContainer$i2 !== void 0 ? _this$tabsContainer$i2 : 0) === ((_this$tabsContainer$g7 = this.tabsContainer.get(0)) === null || _this$tabsContainer$g7 === void 0 ? void 0 : _this$tabsContainer$g7.scrollWidth)) {
354
+ this.tabNextButton.prop('disabled', true);
355
+ } else {
356
+ this.tabNextButton.prop('disabled', false);
357
+ this.tabPreviousButton.first().prop('disabled', false);
358
+ }
359
+ }
360
+
361
+ // scrolls the tab header container on drag tab over control buttons
362
+ // or on press and hold of scroll arrows at either end
363
+ // called recurisevly in an animation loop until cancelled
364
+ // or directional end is reached
365
+ _handleScrollRepeat(direction, startX) {
366
+ var _this$rAF5;
367
+ var deltaX = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
368
+ var prevTimestamp = arguments.length > 3 ? arguments[3] : undefined;
369
+ var tabContainer = this.tabsContainer.get(0);
370
+ if (!tabContainer) {
371
+ return;
372
+ }
373
+ var tabContainerRect = tabContainer.getBoundingClientRect();
374
+ if (direction === this.SCROLL_LEFT) {
375
+ this.tabsContainer.scrollLeft(startX - deltaX);
376
+ if (this.isDraggingTab) {
377
+ // update drag placeholder
378
+ this.parent._highlightHeaderDropZone(tabContainerRect.left - 1);
379
+ }
380
+ // stop loop at left edge
381
+ if (this.tabsContainer.scrollLeft() === 0) {
382
+ this._checkScrollArrows();
383
+ return;
384
+ }
385
+ } else if (direction === this.SCROLL_RIGHT) {
386
+ var _this$tabsContainer$s7, _this$tabsContainer$i3;
387
+ this.tabsContainer.scrollLeft(startX + deltaX);
388
+ if (this.isDraggingTab) {
389
+ // update drag placeholder
390
+ this.parent._highlightHeaderDropZone(tabContainerRect.right + 1);
391
+ }
392
+ // stop loop at right edge
393
+ if (((_this$tabsContainer$s7 = this.tabsContainer.scrollLeft()) !== null && _this$tabsContainer$s7 !== void 0 ? _this$tabsContainer$s7 : 0) + ((_this$tabsContainer$i3 = this.tabsContainer.innerWidth()) !== null && _this$tabsContainer$i3 !== void 0 ? _this$tabsContainer$i3 : 0) === tabContainer.scrollWidth) {
394
+ this._checkScrollArrows();
395
+ return;
396
+ }
397
+ }
398
+
399
+ // setup animation loop, scroll with acceleration
400
+ window.cancelAnimationFrame((_this$rAF5 = this.rAF) !== null && _this$rAF5 !== void 0 ? _this$rAF5 : -1);
401
+ this.rAF = window.requestAnimationFrame(timestamp => {
402
+ var _this$tabsContainer$g8, _this$tabsContainer$g9;
403
+ var startTime = prevTimestamp || timestamp;
404
+ var deltaTime = timestamp - startTime;
405
+ var newDeltaX = this.START_SPEED * deltaTime + 0.5 * this.ACCELERATION * (deltaTime * deltaTime);
406
+ newDeltaX = Math.min(newDeltaX, (_this$tabsContainer$g8 = (_this$tabsContainer$g9 = this.tabsContainer.get(0)) === null || _this$tabsContainer$g9 === void 0 ? void 0 : _this$tabsContainer$g9.scrollWidth) !== null && _this$tabsContainer$g8 !== void 0 ? _this$tabsContainer$g8 : Infinity);
407
+ this._handleScrollRepeat(direction, startX, newDeltaX, startTime);
408
+ });
409
+ }
410
+
411
+ /**
412
+ * Programmatically set closability.
413
+ * @param isClosable Whether to enable/disable closability.
414
+ * @returns Whether the action was successful
415
+ */
416
+ _$setClosable(isClosable) {
417
+ if (this.closeButton && this._isClosable()) {
418
+ this.closeButton.element[isClosable ? 'show' : 'hide']();
419
+ return true;
420
+ }
421
+ return false;
422
+ }
423
+
424
+ /**
425
+ * Destroys the entire header
426
+ */
427
+ _$destroy() {
428
+ this.emit('destroy', this);
429
+ for (var i = 0; i < this.tabs.length; i++) {
430
+ this.tabs[i]._$destroy();
431
+ }
432
+ this._detachWheelListener();
433
+ this._handleItemDropped();
434
+ $(document).off('mouseup', this._hideAdditionalTabsDropdown);
435
+ this.tabDropdownSearch.off('input', this._handleFilterInput);
436
+ this.tabDropdownSearch.off('keydown', this._handleFilterKeydown);
437
+ this.element.remove();
438
+ }
439
+
440
+ /**
441
+ * get settings from header
442
+ *
443
+ * @returns when exists
444
+ */
445
+ _getHeaderSetting(name) {
446
+ if (name in this.parent._header) return this.parent._header[name];
447
+ }
448
+
449
+ /**
450
+ * Creates the popout, maximise and close buttons in the header's top right corner
451
+ */
452
+ _createControls() {
453
+ var closeStack, popout, label, maximise, tabDropdownLabel, tabOverflowNextLabel, tabOverflowPreviousLabel;
454
+
455
+ /**
456
+ * Dropdown to show additional tabs.
457
+ */
458
+
459
+ tabDropdownLabel = this.layoutManager.config.labels.tabDropdown;
460
+ tabOverflowNextLabel = this.layoutManager.config.labels.tabNextLabel;
461
+ tabOverflowPreviousLabel = this.layoutManager.config.labels.tabPreviousLabel;
462
+ this.tabDropdownButton = new HeaderButton(this, tabDropdownLabel, 'lm_tabdropdown', this._showAdditionalTabsDropdown);
463
+ this.tabDropdownButton.element.hide();
464
+ this.controlsContainer.prepend(this.tabNextButton);
465
+ this.tabNextButton.hide();
466
+
467
+ /**
468
+ * Popout control to launch component in new window.
469
+ */
470
+ if (this._getHeaderSetting('popout')) {
471
+ popout = this._onPopoutClick.bind(this);
472
+ label = this._getHeaderSetting('popout');
473
+ new HeaderButton(this, label, 'lm_popout', popout);
474
+ }
475
+
476
+ /**
477
+ * Maximise control - set the component to the full size of the layout
478
+ */
479
+ if (this._getHeaderSetting('maximise')) {
480
+ maximise = this.parent.toggleMaximise.bind(this.parent);
481
+ var maximiseLabel = this._getHeaderSetting('maximise');
482
+ var minimiseLabel = this._getHeaderSetting('minimise');
483
+ var maximiseButton = new HeaderButton(this, maximiseLabel, 'lm_maximise', maximise);
484
+ this.parent.on('maximised', function () {
485
+ maximiseButton.element.attr('title', minimiseLabel !== null && minimiseLabel !== void 0 ? minimiseLabel : '');
486
+ });
487
+ this.parent.on('minimised', function () {
488
+ maximiseButton.element.attr('title', maximiseLabel !== null && maximiseLabel !== void 0 ? maximiseLabel : '');
489
+ });
490
+ }
491
+
492
+ /**
493
+ * Close button
494
+ */
495
+ if (this._isClosable()) {
496
+ closeStack = this.parent.remove.bind(this.parent);
497
+ label = this._getHeaderSetting('close');
498
+ this.closeButton = new HeaderButton(this, label, 'lm_close', closeStack);
499
+ }
500
+ }
501
+
502
+ /**
503
+ * Shows drop down for additional tabs when there are too many to display.
504
+ *
505
+ * @returns {void}
506
+ */
507
+ _showAdditionalTabsDropdown() {
508
+ if (this.isDropdownShown) {
509
+ this._hideAdditionalTabsDropdown();
510
+ return;
511
+ }
512
+
513
+ // clone tabs in the current list, with event listeners
514
+ // and add them to the drop down
515
+ this.tabDropdownList = this.tabsContainer.clone(true).appendTo(this.tabDropdownContainer).children().removeClass('lm_active');
516
+
517
+ // move it to be absolutely positioned in document root
518
+ // as header has overflow hidden, and we need to escape that
519
+ $(document.body).append(this.tabDropdownContainer);
520
+
521
+ // show the dropdown
522
+ this.tabDropdownContainer.show();
523
+ this.isDropdownShown = true;
524
+
525
+ // dropdown is a part of the header z-index context
526
+ // add class to header when dropdown is open
527
+ // so we can bump the z-index of the lists parent
528
+ this.element.addClass('lm_dropdown_open');
529
+
530
+ // focus the dropdown filter list input
531
+ this.tabDropdownSearch.val('').focus();
532
+ this.dropdownKeyIndex = 0;
533
+ this.tabDropdownList.eq(this.dropdownKeyIndex).addClass('lm_keyboard_active');
534
+ $(document).on('mousedown', this._hideAdditionalTabsDropdown);
535
+ this._updateAdditionalTabsDropdown();
536
+ }
537
+
538
+ // enables synthetic keyboard navigation of the list
539
+ _handleFilterKeydown(e) {
540
+ if (e.key === 'Escape') {
541
+ this._hideAdditionalTabsDropdown();
542
+ return;
543
+ }
544
+
545
+ // a negative dropdownKeyIndex means the list is filtered to an empty state
546
+ if (this.dropdownKeyIndex === -1) return;
547
+ if (e.key === 'Enter' || e.key === ' ') {
548
+ // simulate "click"
549
+ this._hideAdditionalTabsDropdown();
550
+ this.tabs[this.dropdownKeyIndex]._onTabClick();
551
+ return;
552
+ }
553
+ function getNextDropdownIndex(startIndex, delta, tabDropdownList) {
554
+ if (tabDropdownList == null || tabDropdownList.length < 2) {
555
+ return -1;
556
+ }
557
+ var i = (startIndex + delta + tabDropdownList.length) % tabDropdownList.length;
558
+ while (i !== startIndex) {
559
+ if (tabDropdownList.eq(i).css('display') !== 'none') {
560
+ return i;
561
+ }
562
+ i = (i + delta + tabDropdownList.length) % tabDropdownList.length;
563
+ }
564
+ return startIndex;
565
+ }
566
+
567
+ // allow tab or arrow key navigation of list, prevent tabs default behaviour
568
+ if (e.key === 'ArrowDown' || e.key === 'Tab' && e.shiftKey === false) {
569
+ var _this$tabDropdownList, _this$tabDropdownList2;
570
+ e.preventDefault();
571
+ (_this$tabDropdownList = this.tabDropdownList) === null || _this$tabDropdownList === void 0 ? void 0 : _this$tabDropdownList.eq(this.dropdownKeyIndex).removeClass('lm_keyboard_active');
572
+ this.dropdownKeyIndex = getNextDropdownIndex(this.dropdownKeyIndex, 1, this.tabDropdownList);
573
+ (_this$tabDropdownList2 = this.tabDropdownList) === null || _this$tabDropdownList2 === void 0 ? void 0 : _this$tabDropdownList2.eq(this.dropdownKeyIndex).addClass('lm_keyboard_active');
574
+ } else if (e.key === 'ArrowUp' || e.key === 'Tab') {
575
+ var _this$tabDropdownList3, _this$tabDropdownList4;
576
+ e.preventDefault();
577
+ (_this$tabDropdownList3 = this.tabDropdownList) === null || _this$tabDropdownList3 === void 0 ? void 0 : _this$tabDropdownList3.eq(this.dropdownKeyIndex).removeClass('lm_keyboard_active');
578
+ this.dropdownKeyIndex = getNextDropdownIndex(this.dropdownKeyIndex, -1, this.tabDropdownList);
579
+ (_this$tabDropdownList4 = this.tabDropdownList) === null || _this$tabDropdownList4 === void 0 ? void 0 : _this$tabDropdownList4.eq(this.dropdownKeyIndex).addClass('lm_keyboard_active');
580
+ }
581
+ }
582
+
583
+ // filters the list
584
+ _handleFilterInput(event) {
585
+ if (this.tabDropdownList == null) {
586
+ return;
587
+ }
588
+ // reset keyboard index
589
+ this.tabDropdownList.eq(this.dropdownKeyIndex).removeClass('lm_keyboard_active');
590
+ this.dropdownKeyIndex = -1;
591
+ for (var i = 0; i < this.tabDropdownList.length; i++) {
592
+ var _this$tabs$i$contentI, _this$tabs$i$contentI2;
593
+ if (((_this$tabs$i$contentI = (_this$tabs$i$contentI2 = this.tabs[i].contentItem.config.title) === null || _this$tabs$i$contentI2 === void 0 ? void 0 : _this$tabs$i$contentI2.toLowerCase().indexOf(event.target.value.toLowerCase())) !== null && _this$tabs$i$contentI !== void 0 ? _this$tabs$i$contentI : -1) !== -1) {
594
+ this.tabDropdownList.eq(i).css('display', '');
595
+ if (this.dropdownKeyIndex === -1) this.dropdownKeyIndex = i;
596
+ } else {
597
+ this.tabDropdownList.eq(i).css('display', 'none');
598
+ }
599
+ }
600
+ if (this.dropdownKeyIndex !== -1) {
601
+ this.tabDropdownList.eq(this.dropdownKeyIndex).addClass('lm_keyboard_active');
602
+ }
603
+ }
604
+
605
+ /**
606
+ * Hides drop down for additional tabs when needed. It is called via mousedown
607
+ * event on document when list is open, or programmatically when drag starts,
608
+ * or active tab changes etc.
609
+ */
610
+ _hideAdditionalTabsDropdown(event) {
611
+ var _this$tabDropdownCont, _this$tabDropdownButt;
612
+ // dropdown already closed, do nothing
613
+ if (!this.isDropdownShown) return;
614
+ if (event && (_this$tabDropdownCont = this.tabDropdownContainer.get(0)) !== null && _this$tabDropdownCont !== void 0 && _this$tabDropdownCont.contains(event.target)) {
615
+ // prevent events occuring inside the list from causing a close
616
+ return;
617
+ } else if (event && ((_this$tabDropdownButt = this.tabDropdownButton) === null || _this$tabDropdownButt === void 0 ? void 0 : _this$tabDropdownButt.element.get(0)) === event.target) {
618
+ // do nothing on the mouse down so that the click event can close, rather then re-open
619
+ return;
620
+ }
621
+ this.element.removeClass('lm_dropdown_open');
622
+ this.tabDropdownContainer.hide();
623
+ this.isDropdownShown = false;
624
+
625
+ // put it back in the header dom to keep the root tidy
626
+ this.element.append(this.tabDropdownContainer);
627
+
628
+ // remove the current tab list
629
+ this.tabDropdownContainer.find('.lm_tabs').remove();
630
+ $(document).off('mousedown', this._hideAdditionalTabsDropdown);
631
+ }
632
+
633
+ /**
634
+ * Ensures additional tab drop down which is absolutely positioned in the root
635
+ * doesn't overflow the screen, and instead becomes scrollable. Positions the
636
+ * floating menu in the correct location relative to the dropdown button.
637
+ */
638
+ _updateAdditionalTabsDropdown() {
639
+ var _this$tabDropdownCont2, _this$tabDropdownCont3, _$$height, _$$width;
640
+ if (!this.isDropdownShown) return;
641
+ if (!this.tabDropdownList || this.tabDropdownList.length == 0) return;
642
+ var scrollHeight = (_this$tabDropdownCont2 = (_this$tabDropdownCont3 = this.tabDropdownContainer.get(0)) === null || _this$tabDropdownCont3 === void 0 ? void 0 : _this$tabDropdownCont3.scrollHeight) !== null && _this$tabDropdownCont2 !== void 0 ? _this$tabDropdownCont2 : 0;
643
+ if (scrollHeight === 0) return; // height can be zero if called on a hidden or empty list
644
+
645
+ var list_rect = this.tabDropdownContainer[0].getBoundingClientRect();
646
+ var windowHeight = (_$$height = $(window).height()) !== null && _$$height !== void 0 ? _$$height : 0;
647
+ var windowWidth = (_$$width = $(window).width()) !== null && _$$width !== void 0 ? _$$width : 0;
648
+
649
+ // position relative to the dropdown button
650
+ if (!this.tabDropdownButton) return;
651
+ var button_rect = this.tabDropdownButton.element[0].getBoundingClientRect();
652
+
653
+ // If it fits below button, put it there. If it doesn't and there is more
654
+ // than 60% space above, then flip to displaying menu above button
655
+ var hasSpaceBelow = scrollHeight < windowHeight - button_rect.bottom;
656
+ var shouldFlip = !hasSpaceBelow && button_rect.bottom > windowHeight * 0.6; // 0.6 bias to not flipping rather than strictly 0.5
657
+
658
+ // keep from going of right edge
659
+ // when flipped offset to right edge of button
660
+ var left = Math.min(button_rect.left + (shouldFlip ? button_rect.width : 0), windowWidth - list_rect.width - this.PADDING);
661
+ // flip, with limit of top of screen
662
+ var top = shouldFlip ? Math.max(button_rect.top - scrollHeight, this.PADDING) : button_rect.bottom;
663
+
664
+ // if needs scroll to fit, apply a max-height
665
+ var maxHeight = windowHeight - top - this.PADDING;
666
+ this.tabDropdownContainer.css({
667
+ 'max-height': maxHeight,
668
+ top,
669
+ left
670
+ });
671
+ }
672
+
673
+ /**
674
+ * Checks whether the header is closable based on the parent config and
675
+ * the global config.
676
+ *
677
+ * @returns Whether the header is closable.
678
+ */
679
+ _isClosable() {
680
+ return Boolean(this.parent.config.isClosable && this.layoutManager.config.settings.showCloseIcon);
681
+ }
682
+ _onPopoutClick() {
683
+ if (this.layoutManager.config.settings.popoutWholeStack === true) {
684
+ this.parent.popout();
685
+ } else {
686
+ var _this$activeContentIt;
687
+ (_this$activeContentIt = this.activeContentItem) === null || _this$activeContentIt === void 0 ? void 0 : _this$activeContentIt.popout();
688
+ }
689
+ }
690
+
691
+ /**
692
+ * Invoked when the header's background is clicked (not it's tabs or controls)
693
+ *
694
+ * @param event
695
+ */
696
+ _onHeaderClick(event) {
697
+ if (event.target === this.element[0]) {
698
+ this.parent.select();
699
+ }
700
+ }
701
+
702
+ /**
703
+ * Pushes the tabs to the tab dropdown if the available space is not sufficient
704
+ */
705
+ _updateTabSizes() {
706
+ if (this.tabs.length === 0) {
707
+ return;
708
+ }
709
+ var tabsContainer = this.tabsContainer.get(0);
710
+ if (this.isDropdownShown) {
711
+ // resize the dropdown list too as it is currently open
712
+ this._updateAdditionalTabsDropdown();
713
+ }
714
+ if (!tabsContainer) {
715
+ return;
716
+ }
717
+ if (!this.isOverflowing && tabsContainer.scrollWidth > tabsContainer.clientWidth) {
718
+ var _this$tabDropdownButt2;
719
+ (_this$tabDropdownButt2 = this.tabDropdownButton) === null || _this$tabDropdownButt2 === void 0 ? void 0 : _this$tabDropdownButt2.element.show();
720
+ this.tabNextButton.show();
721
+ this.tabPreviousButton.show();
722
+ this.isOverflowing = true;
723
+ } else if (this.isOverflowing && tabsContainer.scrollWidth <= tabsContainer.clientWidth) {
724
+ var _this$tabDropdownButt3;
725
+ (_this$tabDropdownButt3 = this.tabDropdownButton) === null || _this$tabDropdownButt3 === void 0 ? void 0 : _this$tabDropdownButt3.element.hide();
726
+ this.tabNextButton.hide();
727
+ this.tabPreviousButton.hide();
728
+ this.isOverflowing = false;
729
+ }
730
+ if (this.isOverflowing) this._checkScrollArrows();
731
+ }
732
+ }
733
+ _defineProperty(Header, "_template", ['<div class="lm_header">', '<ul class="lm_tabs"></ul>', '<ul class="lm_controls"></ul>', '<ul class="lm_tabdropdown_list">', '<li class="lm_tabdropdown_search"><input type="text" placeholder="Find tab..."></li>', '</ul>', '</div>'].join(''));
734
+ _defineProperty(Header, "_previousButtonTemplate", ['<ul class="lm_controls">', '<li class="lm_tabpreviousbutton"></li>', '</ul>'].join(''));
735
+ _defineProperty(Header, "_nextButtonTemplate", ['<li class="lm_tabnextbutton"></li>'].join(''));
736
+ //# sourceMappingURL=Header.js.map