@datagrok-libraries/dock-spawn-dg 0.0.1

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 (222) hide show
  1. package/.eslintrc.json +47 -0
  2. package/CHANGELOG.md +355 -0
  3. package/LICENSE +21 -0
  4. package/README.md +11 -0
  5. package/css/dock-manager-context-menu.css +19 -0
  6. package/css/dock-manager-style.css +190 -0
  7. package/css/dock-manager.css +411 -0
  8. package/images/close.svg +6 -0
  9. package/images/dock_bottom.png +0 -0
  10. package/images/dock_bottom_sel.png +0 -0
  11. package/images/dock_fill.png +0 -0
  12. package/images/dock_fill_sel.png +0 -0
  13. package/images/dock_left.png +0 -0
  14. package/images/dock_left_sel.png +0 -0
  15. package/images/dock_right.png +0 -0
  16. package/images/dock_right_sel.png +0 -0
  17. package/images/dock_top.png +0 -0
  18. package/images/dock_top_sel.png +0 -0
  19. package/index.ts +32 -0
  20. package/lib/BrowserDialogHelper.d.ts +8 -0
  21. package/lib/BrowserDialogHelper.d.ts.map +1 -0
  22. package/lib/BrowserDialogHelper.js +60 -0
  23. package/lib/ContainerType.d.ts +7 -0
  24. package/lib/ContainerType.d.ts.map +1 -0
  25. package/lib/ContainerType.js +7 -0
  26. package/lib/Dialog.d.ts +51 -0
  27. package/lib/Dialog.d.ts.map +1 -0
  28. package/lib/Dialog.js +209 -0
  29. package/lib/DockConfig.d.ts +9 -0
  30. package/lib/DockConfig.d.ts.map +1 -0
  31. package/lib/DockConfig.js +14 -0
  32. package/lib/DockGraphDeserializer.d.ts +19 -0
  33. package/lib/DockGraphDeserializer.d.ts.map +1 -0
  34. package/lib/DockGraphDeserializer.js +114 -0
  35. package/lib/DockGraphSerializer.d.ts +14 -0
  36. package/lib/DockGraphSerializer.d.ts.map +1 -0
  37. package/lib/DockGraphSerializer.js +40 -0
  38. package/lib/DockLayoutEngine.d.ts +36 -0
  39. package/lib/DockLayoutEngine.d.ts.map +1 -0
  40. package/lib/DockLayoutEngine.js +323 -0
  41. package/lib/DockManager.d.ts +155 -0
  42. package/lib/DockManager.d.ts.map +1 -0
  43. package/lib/DockManager.js +752 -0
  44. package/lib/DockManagerContext.d.ts +10 -0
  45. package/lib/DockManagerContext.d.ts.map +1 -0
  46. package/lib/DockManagerContext.js +12 -0
  47. package/lib/DockModel.d.ts +9 -0
  48. package/lib/DockModel.d.ts.map +1 -0
  49. package/lib/DockModel.js +8 -0
  50. package/lib/DockNode.d.ts +16 -0
  51. package/lib/DockNode.d.ts.map +1 -0
  52. package/lib/DockNode.js +64 -0
  53. package/lib/DockWheel.d.ts +41 -0
  54. package/lib/DockWheel.d.ts.map +1 -0
  55. package/lib/DockWheel.js +208 -0
  56. package/lib/DockWheelItem.d.ts +16 -0
  57. package/lib/DockWheelItem.d.ts.map +1 -0
  58. package/lib/DockWheelItem.js +34 -0
  59. package/lib/DocumentManagerContainer.d.ts +16 -0
  60. package/lib/DocumentManagerContainer.d.ts.map +1 -0
  61. package/lib/DocumentManagerContainer.js +28 -0
  62. package/lib/DocumentTabPage.d.ts +11 -0
  63. package/lib/DocumentTabPage.d.ts.map +1 -0
  64. package/lib/DocumentTabPage.js +26 -0
  65. package/lib/DraggableContainer.d.ts +51 -0
  66. package/lib/DraggableContainer.d.ts.map +1 -0
  67. package/lib/DraggableContainer.js +145 -0
  68. package/lib/EventHandler.d.ts +8 -0
  69. package/lib/EventHandler.d.ts.map +1 -0
  70. package/lib/EventHandler.js +14 -0
  71. package/lib/FillDockContainer.d.ts +34 -0
  72. package/lib/FillDockContainer.d.ts.map +1 -0
  73. package/lib/FillDockContainer.js +80 -0
  74. package/lib/HorizontalDockContainer.d.ts +7 -0
  75. package/lib/HorizontalDockContainer.d.ts.map +1 -0
  76. package/lib/HorizontalDockContainer.js +9 -0
  77. package/lib/PanelContainer.d.ts +114 -0
  78. package/lib/PanelContainer.d.ts.map +1 -0
  79. package/lib/PanelContainer.js +517 -0
  80. package/lib/Point.d.ts +6 -0
  81. package/lib/Point.d.ts.map +1 -0
  82. package/lib/Point.js +8 -0
  83. package/lib/ResizableContainer.d.ts +56 -0
  84. package/lib/ResizableContainer.d.ts.map +1 -0
  85. package/lib/ResizableContainer.js +254 -0
  86. package/lib/ResizeHandle.d.ts +16 -0
  87. package/lib/ResizeHandle.d.ts.map +1 -0
  88. package/lib/ResizeHandle.js +58 -0
  89. package/lib/SplitterBar.d.ts +33 -0
  90. package/lib/SplitterBar.d.ts.map +1 -0
  91. package/lib/SplitterBar.js +137 -0
  92. package/lib/SplitterDockContainer.d.ts +36 -0
  93. package/lib/SplitterDockContainer.d.ts.map +1 -0
  94. package/lib/SplitterDockContainer.js +75 -0
  95. package/lib/SplitterPanel.d.ts +27 -0
  96. package/lib/SplitterPanel.d.ts.map +1 -0
  97. package/lib/SplitterPanel.js +195 -0
  98. package/lib/TabHandle.d.ts +56 -0
  99. package/lib/TabHandle.d.ts.map +1 -0
  100. package/lib/TabHandle.js +292 -0
  101. package/lib/TabHost.d.ts +47 -0
  102. package/lib/TabHost.d.ts.map +1 -0
  103. package/lib/TabHost.js +238 -0
  104. package/lib/TabPage.d.ts +20 -0
  105. package/lib/TabPage.d.ts.map +1 -0
  106. package/lib/TabPage.js +81 -0
  107. package/lib/UndockInitiator.d.ts +32 -0
  108. package/lib/UndockInitiator.d.ts.map +1 -0
  109. package/lib/UndockInitiator.js +152 -0
  110. package/lib/Utils.d.ts +15 -0
  111. package/lib/Utils.d.ts.map +1 -0
  112. package/lib/Utils.js +69 -0
  113. package/lib/VerticalDockContainer.d.ts +7 -0
  114. package/lib/VerticalDockContainer.d.ts.map +1 -0
  115. package/lib/VerticalDockContainer.js +9 -0
  116. package/lib/enums/PanelType.d.ts +5 -0
  117. package/lib/enums/PanelType.d.ts.map +1 -0
  118. package/lib/enums/PanelType.js +5 -0
  119. package/lib/enums/TabHostDirection.d.ts +7 -0
  120. package/lib/enums/TabHostDirection.d.ts.map +1 -0
  121. package/lib/enums/TabHostDirection.js +7 -0
  122. package/lib/enums/WheelTypes.d.ts +12 -0
  123. package/lib/enums/WheelTypes.d.ts.map +1 -0
  124. package/lib/enums/WheelTypes.js +14 -0
  125. package/lib/i18n/Defaults.d.ts +12 -0
  126. package/lib/i18n/Defaults.d.ts.map +1 -0
  127. package/lib/i18n/Defaults.js +9 -0
  128. package/lib/i18n/Localizer.d.ts +7 -0
  129. package/lib/i18n/Localizer.d.ts.map +1 -0
  130. package/lib/i18n/Localizer.js +16 -0
  131. package/lib/index.d.ts +33 -0
  132. package/lib/index.d.ts.map +1 -0
  133. package/lib/index.js +32 -0
  134. package/lib/interfaces/IDockContainer.d.ts +26 -0
  135. package/lib/interfaces/IDockContainer.d.ts.map +1 -0
  136. package/lib/interfaces/IDockContainer.js +1 -0
  137. package/lib/interfaces/IDockContainerWithSize.d.ts +6 -0
  138. package/lib/interfaces/IDockContainerWithSize.d.ts.map +1 -0
  139. package/lib/interfaces/IDockContainerWithSize.js +1 -0
  140. package/lib/interfaces/ILayoutEventListener.d.ts +27 -0
  141. package/lib/interfaces/ILayoutEventListener.d.ts.map +1 -0
  142. package/lib/interfaces/ILayoutEventListener.js +1 -0
  143. package/lib/interfaces/IMouseOrTouchEvent.d.ts +7 -0
  144. package/lib/interfaces/IMouseOrTouchEvent.d.ts.map +1 -0
  145. package/lib/interfaces/IMouseOrTouchEvent.js +1 -0
  146. package/lib/interfaces/INodeInfo.d.ts +8 -0
  147. package/lib/interfaces/INodeInfo.d.ts.map +1 -0
  148. package/lib/interfaces/INodeInfo.js +1 -0
  149. package/lib/interfaces/IPanelInfo.d.ts +10 -0
  150. package/lib/interfaces/IPanelInfo.d.ts.map +1 -0
  151. package/lib/interfaces/IPanelInfo.js +1 -0
  152. package/lib/interfaces/IRectangle.d.ts +7 -0
  153. package/lib/interfaces/IRectangle.d.ts.map +1 -0
  154. package/lib/interfaces/IRectangle.js +1 -0
  155. package/lib/interfaces/ISize.d.ts +5 -0
  156. package/lib/interfaces/ISize.d.ts.map +1 -0
  157. package/lib/interfaces/ISize.js +1 -0
  158. package/lib/interfaces/IState.d.ts +12 -0
  159. package/lib/interfaces/IState.d.ts.map +1 -0
  160. package/lib/interfaces/IState.js +1 -0
  161. package/lib/interfaces/IThickness.d.ts +7 -0
  162. package/lib/interfaces/IThickness.d.ts.map +1 -0
  163. package/lib/interfaces/IThickness.js +1 -0
  164. package/lib/webcomponent/DockSpawnTsWebcomponent.d.ts +35 -0
  165. package/lib/webcomponent/DockSpawnTsWebcomponent.d.ts.map +1 -0
  166. package/lib/webcomponent/DockSpawnTsWebcomponent.js +209 -0
  167. package/lib/webcomponent/styles.d.ts +5 -0
  168. package/lib/webcomponent/styles.d.ts.map +1 -0
  169. package/lib/webcomponent/styles.js +537 -0
  170. package/package.json +36 -0
  171. package/src/BrowserDialogHelper.ts +76 -0
  172. package/src/ContainerType.ts +6 -0
  173. package/src/Dialog.ts +253 -0
  174. package/src/DockConfig.ts +15 -0
  175. package/src/DockGraphDeserializer.ts +129 -0
  176. package/src/DockGraphSerializer.ts +53 -0
  177. package/src/DockLayoutEngine.ts +370 -0
  178. package/src/DockManager.ts +880 -0
  179. package/src/DockManagerContext.ts +16 -0
  180. package/src/DockModel.ts +12 -0
  181. package/src/DockNode.ts +81 -0
  182. package/src/DockWheel.ts +215 -0
  183. package/src/DockWheelItem.ts +41 -0
  184. package/src/DocumentManagerContainer.ts +39 -0
  185. package/src/DocumentTabPage.ts +35 -0
  186. package/src/DraggableContainer.ts +177 -0
  187. package/src/EventHandler.ts +17 -0
  188. package/src/FillDockContainer.ts +98 -0
  189. package/src/HorizontalDockContainer.ts +13 -0
  190. package/src/PanelContainer.ts +596 -0
  191. package/src/Point.ts +10 -0
  192. package/src/ResizableContainer.ts +293 -0
  193. package/src/ResizeHandle.ts +59 -0
  194. package/src/SplitterBar.ts +157 -0
  195. package/src/SplitterDockContainer.ts +95 -0
  196. package/src/SplitterPanel.ts +228 -0
  197. package/src/TabHandle.ts +347 -0
  198. package/src/TabHost.ts +267 -0
  199. package/src/TabPage.ts +98 -0
  200. package/src/UndockInitiator.ts +181 -0
  201. package/src/Utils.ts +85 -0
  202. package/src/VerticalDockContainer.ts +13 -0
  203. package/src/enums/PanelType.ts +4 -0
  204. package/src/enums/TabHostDirection.ts +6 -0
  205. package/src/enums/WheelTypes.ts +14 -0
  206. package/src/i18n/Defaults.ts +20 -0
  207. package/src/i18n/Localizer.ts +23 -0
  208. package/src/index.ts +32 -0
  209. package/src/interfaces/IDockContainer.ts +27 -0
  210. package/src/interfaces/IDockContainerWithSize.ts +6 -0
  211. package/src/interfaces/ILayoutEventListener.ts +28 -0
  212. package/src/interfaces/IMouseOrTouchEvent.ts +6 -0
  213. package/src/interfaces/INodeInfo.ts +8 -0
  214. package/src/interfaces/IPanelInfo.ts +10 -0
  215. package/src/interfaces/IRectangle.ts +6 -0
  216. package/src/interfaces/ISize.ts +4 -0
  217. package/src/interfaces/IState.ts +12 -0
  218. package/src/interfaces/IThickness.ts +6 -0
  219. package/src/webcomponent/DockSpawnTsWebcomponent.ts +248 -0
  220. package/src/webcomponent/styles.ts +544 -0
  221. package/tsconfig.json +74 -0
  222. package/tsconfig.tsbuildinfo +1 -0
package/src/TabHost.ts ADDED
@@ -0,0 +1,267 @@
1
+ import { TabPage } from "./TabPage.js";
2
+ import { Utils } from "./Utils.js";
3
+ import { TabHostDirection } from "./enums/TabHostDirection.js";
4
+ import { TabHandle } from "./TabHandle.js";
5
+ import { IDockContainer } from "./interfaces/IDockContainer.js";
6
+ import { DockManager } from "./DockManager.js";
7
+ import { PanelContainer } from "./PanelContainer.js";
8
+ import { EventHandler } from './EventHandler.js';
9
+
10
+ /**
11
+ * Tab Host control contains tabs known as TabPages.
12
+ * The tab strip can be aligned in different orientations
13
+ */
14
+ export class TabHost {
15
+ displayCloseButton: boolean;
16
+ dockManager: DockManager;
17
+ tabStripDirection: TabHostDirection;
18
+ hostElement: HTMLDivElement;
19
+ tabListElement: HTMLDivElement;
20
+ separatorElement: HTMLDivElement;
21
+ contentElement: HTMLDivElement;
22
+ createTabPage: (tabHost: TabHost, container: IDockContainer) => any;
23
+ tabHandleListener: { onMoveTab: (e: any) => void; };
24
+ eventListeners: any[];
25
+ pages: TabPage[];
26
+ activeTab: TabPage;
27
+ _resizeRequested: boolean;
28
+ mouseDownHandler: EventHandler;
29
+ focusHandler: EventHandler;
30
+
31
+ constructor(dockManager: DockManager, tabStripDirection: TabHostDirection, displayCloseButton?: boolean) {
32
+ /**
33
+ * Create a tab host with the tab strip aligned in the [tabStripDirection] direciton
34
+ * Only TabHost.DIRECTION_BOTTOM and TabHost.DIRECTION_TOP are supported
35
+ */
36
+ if (tabStripDirection === undefined) {
37
+ tabStripDirection = TabHostDirection.BOTTOM;
38
+ }
39
+
40
+ if (displayCloseButton === undefined) {
41
+ displayCloseButton = false;
42
+ }
43
+
44
+ this.dockManager = dockManager;
45
+ this.tabStripDirection = tabStripDirection;
46
+ this.displayCloseButton = displayCloseButton; // Indicates if the close button next to the tab handle should be displayed
47
+ this.pages = [];
48
+ this.eventListeners = [];
49
+ this.tabHandleListener = {
50
+ onMoveTab: (e) => { this.onMoveTab(e); }
51
+ };
52
+ this.hostElement = document.createElement('div'); // The main tab host DOM element
53
+ this.tabListElement = document.createElement('div'); // Hosts the tab handles
54
+ this.separatorElement = document.createElement('div'); // A seperator line between the tabs and content
55
+ this.contentElement = document.createElement('div'); // Hosts the active tab content
56
+ this.contentElement.tabIndex = 0;
57
+ this.createTabPage = this._createDefaultTabPage; // Factory for creating tab pages
58
+
59
+ if (this.tabStripDirection === TabHostDirection.BOTTOM) {
60
+ this.hostElement.appendChild(this.contentElement);
61
+ this.hostElement.appendChild(this.separatorElement);
62
+ this.hostElement.appendChild(this.tabListElement);
63
+ } else if (this.tabStripDirection === TabHostDirection.TOP) {
64
+ this.hostElement.appendChild(this.tabListElement);
65
+ this.hostElement.appendChild(this.separatorElement);
66
+ this.hostElement.appendChild(this.contentElement);
67
+ } else {
68
+ throw new Error('Only top and bottom tab strip orientations are supported');
69
+ }
70
+
71
+ this.hostElement.classList.add('dockspan-tab-host');
72
+ this.tabListElement.classList.add('dockspan-tab-handle-list-container');
73
+ this.separatorElement.classList.add('dockspan-tab-handle-content-seperator');
74
+ this.contentElement.classList.add('dockspan-tab-content');
75
+ this.contentElement.tabIndex = 0;
76
+ this.focusHandler = new EventHandler(this.contentElement, 'focus', this.onFocus.bind(this), true);
77
+ this.mouseDownHandler = new EventHandler(this.contentElement, 'mousedown', this.onMousedown.bind(this), true);
78
+ }
79
+
80
+ onFocus() {
81
+ if (this.activeTab && this.dockManager.activePanel != this.activeTab.panel)
82
+ this.dockManager.activePanel = this.activeTab.panel;
83
+ }
84
+
85
+ setActive(isActive: boolean) {
86
+ if (isActive) {
87
+ this.separatorElement.classList.add('dockspan-tab-handle-content-seperator-active');
88
+ } else {
89
+ this.separatorElement.classList.remove('dockspan-tab-handle-content-seperator-active');
90
+ }
91
+ if (this.activeTab) {
92
+ this.activeTab.handle.setActive(isActive);
93
+ }
94
+ }
95
+
96
+ onMousedown() {
97
+ if (this.activeTab && this.dockManager.activePanel != this.activeTab.panel)
98
+ this.dockManager.activePanel = this.activeTab.panel;
99
+ }
100
+
101
+ onMoveTab(e) {
102
+ let index = Array.prototype.slice.call(this.tabListElement.childNodes).indexOf(e.self.elementBase);
103
+ this.change(this, /*handle*/e.self, e.state, index);
104
+ }
105
+
106
+ performTabsLayout(indexes: number[]) {
107
+ this.pages = Utils.orderByIndexes(this.pages, indexes);
108
+
109
+ let items = this.tabListElement.childNodes;
110
+ let itemsArr = [];
111
+ for (let i in items) {
112
+ if (items[i].nodeType === 1) { // get rid of the whitespace text nodes
113
+ itemsArr.push(items[i]);
114
+ }
115
+ }
116
+ itemsArr = Utils.orderByIndexes(itemsArr, indexes);
117
+ for (let i = 0; i < itemsArr.length; ++i) {
118
+ this.tabListElement.appendChild(itemsArr[i]);
119
+ }
120
+
121
+ if (this.activeTab)
122
+ this.onTabPageSelected(this.activeTab, false);
123
+ }
124
+
125
+ getActiveTab() {
126
+ return this.activeTab;
127
+ }
128
+
129
+ addListener(listener) {
130
+ this.eventListeners.push(listener);
131
+ }
132
+
133
+ removeListener(listener) {
134
+ this.eventListeners.splice(this.eventListeners.indexOf(listener), 1);
135
+ }
136
+
137
+ change(host: TabHost, handle: TabHandle, state, index) {
138
+ this.eventListeners.forEach((listener) => {
139
+ if (listener.onChange) {
140
+ listener.onChange({ host: host, handle: handle, state: state, index: index });
141
+ }
142
+ });
143
+ }
144
+
145
+ _createDefaultTabPage(tabHost: TabHost, container: IDockContainer) {
146
+ return new TabPage(tabHost, container);
147
+ }
148
+
149
+ setActiveTab(container: IDockContainer) {
150
+ let currentPage;
151
+ this.pages.forEach((itm) => {
152
+ if (itm.container === container) {
153
+ currentPage = itm;
154
+ }
155
+ });
156
+ if (this.pages.length > 0 && currentPage) {
157
+ this.onTabPageSelected(currentPage, true);
158
+ this.dockManager.activePanel = container as PanelContainer;
159
+ }
160
+ }
161
+
162
+ resize(width: number, height: number) {
163
+ this.hostElement.style.width = width + 'px';
164
+ this.hostElement.style.height = height + 'px';
165
+
166
+ let tabHeight = this.tabListElement.clientHeight;
167
+ if (!this._resizeRequested)
168
+ requestAnimationFrame(() => this.resizeTabListElement(width, height));
169
+ this._resizeRequested = true;
170
+ let separatorHeight = this.separatorElement.clientHeight;
171
+ let contentHeight = height - tabHeight - separatorHeight;
172
+ this.contentElement.style.height = contentHeight + 'px';
173
+
174
+ if (this.activeTab)
175
+ this.activeTab.resize(width, contentHeight);
176
+ }
177
+
178
+ resizeTabListElement(width: number, height?: number) {
179
+ this._resizeRequested = false;
180
+ if (this.pages.length === 0) return;
181
+ let tabListWidth = 0;
182
+ this.pages.forEach((page) => {
183
+ let handle = page.handle;
184
+ if (handle.elementBase != null){
185
+ handle.elementBase.style.width = ''; //clear
186
+ tabListWidth += handle.elementBase.clientWidth;
187
+ }
188
+ });
189
+ let scaleMultiplier = width / tabListWidth;
190
+ if (scaleMultiplier > 1.2) return; //with a reserve
191
+ this.pages.forEach((page, index) => {
192
+ let handle = page.handle;
193
+ let newSize = scaleMultiplier * handle.elementBase.clientWidth;
194
+ if (index === this.pages.length - 1)
195
+ newSize = newSize - 5;
196
+ handle.elementBase.style.width = newSize + 'px';
197
+ });
198
+ }
199
+
200
+ performLayout(children: IDockContainer[]) {
201
+ // Destroy all existing tab pages not in children
202
+ this.pages.forEach((tab) => {
203
+ if (!children.some((x) => x == tab.container)) {
204
+ tab.handle.removeListener(this.tabHandleListener);
205
+ tab.destroy();
206
+ let index = this.pages.indexOf(tab);
207
+ if (index > -1) {
208
+ this.pages.splice(index, 1);
209
+ }
210
+ }
211
+ });
212
+
213
+ let oldActiveTab = this.activeTab;
214
+ delete this.activeTab;
215
+
216
+ let childPanels = children.filter((child) => {
217
+ return child.containerType === 'panel';
218
+ });
219
+
220
+ if (childPanels.length > 0) {
221
+ // Rebuild new tab pages
222
+ childPanels.forEach((child) => {
223
+ let page = null;
224
+ if (!this.pages.some((x) => {
225
+ if (x.container == child) {
226
+ page = x;
227
+ return true;
228
+ }
229
+ return false;
230
+ })) {
231
+ page = this.createTabPage(this, child);
232
+ page.handle.addListener(this.tabHandleListener);
233
+ this.pages.push(page);
234
+ }
235
+
236
+ // Restore the active selected tab
237
+ if (oldActiveTab && page.container === oldActiveTab.container)
238
+ this.activeTab = page;
239
+ });
240
+ this._setTabHandlesVisible(true);
241
+ }
242
+ else
243
+ // Do not show an empty tab handle host with zero tabs
244
+ this._setTabHandlesVisible(false);
245
+
246
+ if (this.activeTab)
247
+ this.onTabPageSelected(this.activeTab, false);
248
+ }
249
+
250
+ _setTabHandlesVisible(visible: boolean) {
251
+ if (visible) {
252
+ this.tabListElement.classList.add('dockspan-tab-handle-list-container-visible');
253
+ this.separatorElement.classList.add('dockspan-tab-handle-content-seperator-visible');
254
+ } else {
255
+ this.tabListElement.classList.remove('dockspan-tab-handle-list-container-visible');
256
+ this.separatorElement.classList.remove('dockspan-tab-handle-content-seperator-visible');
257
+ }
258
+ }
259
+
260
+ onTabPageSelected(page: TabPage, active: boolean) {
261
+ this.activeTab = page;
262
+ this.pages.forEach((tabPage) => {
263
+ let selected = (tabPage === page);
264
+ tabPage.setSelected(selected, active);
265
+ });
266
+ }
267
+ }
package/src/TabPage.ts ADDED
@@ -0,0 +1,98 @@
1
+ import { TabHandle } from "./TabHandle.js";
2
+ import { PanelContainer } from "./PanelContainer.js";
3
+ import { IDockContainer } from "./interfaces/IDockContainer.js";
4
+ import { TabHost } from "./TabHost.js";
5
+ import { Utils } from "./Utils.js";
6
+
7
+ export class TabPage {
8
+ selected: boolean;
9
+ host: TabHost;
10
+ container: IDockContainer;
11
+ panel?: PanelContainer;
12
+ handle: TabHandle;
13
+ containerElement: HTMLElement;
14
+ _initContent: boolean;
15
+
16
+ constructor(host: TabHost, container: IDockContainer) {
17
+ if (arguments.length === 0) {
18
+ return;
19
+ }
20
+
21
+ this.selected = false;
22
+ this.host = host;
23
+ this.container = container;
24
+
25
+ this.handle = new TabHandle(this);
26
+ this.containerElement = container.containerElement;
27
+
28
+ if (container instanceof PanelContainer) {
29
+ this.panel = container;
30
+ this.panel.onTitleChanged = this.onTitleChanged.bind(this);
31
+ this.onTitleChanged();
32
+ }
33
+
34
+ container.tabPage = this;
35
+ }
36
+
37
+ onTitleChanged() {
38
+ this.handle.updateTitle();
39
+ if (this.panel) {
40
+ if (this.panel.hasChanges) {
41
+ this.handle.elementText.classList.add('panel-has-changes')
42
+ } else {
43
+ this.handle.elementText.classList.remove('panel-has-changes')
44
+ }
45
+ }
46
+ }
47
+
48
+ destroy() {
49
+ this.handle.destroy();
50
+
51
+ if (this.container instanceof PanelContainer) {
52
+ let panel = this.container;
53
+ delete panel.onTitleChanged;
54
+ }
55
+
56
+ if (this.host.dockManager.activePanel == this.panel)
57
+ this.host.dockManager.activePanel = null;
58
+
59
+ this.container.tabPage = null;
60
+
61
+ Utils.removeNode(this.containerElement);
62
+ }
63
+
64
+ onSelected() {
65
+ this.host.onTabPageSelected(this, true);
66
+ if (this.container instanceof PanelContainer) {
67
+ let panel = this.container;
68
+ panel.dockManager.notifyOnTabChange(this);
69
+ }
70
+ }
71
+
72
+ setSelected(flag: boolean, isActive: boolean) {
73
+ this.selected = flag;
74
+ this.handle.setSelected(flag);
75
+
76
+ if (!this._initContent)
77
+ this.host.contentElement.appendChild(this.containerElement);
78
+ this._initContent = true;
79
+ if (this.selected) {
80
+ this.containerElement.style.display = 'block';
81
+ this.panel.setVisible(true);
82
+ // force a resize again
83
+ let width = this.host.contentElement.clientWidth;
84
+ let height = this.host.contentElement.clientHeight;
85
+ this.container.resize(width, height);
86
+ if (isActive)
87
+ this.host.dockManager.activePanel = this.container as PanelContainer;
88
+ }
89
+ else {
90
+ this.containerElement.style.display = 'none';
91
+ this.panel.setVisible(false);
92
+ }
93
+ }
94
+
95
+ resize(width: number, height: number) {
96
+ this.container.resize(width, height);
97
+ }
98
+ }
@@ -0,0 +1,181 @@
1
+ import { EventHandler } from "./EventHandler.js";
2
+ import { Point } from "./Point.js";
3
+ import { Dialog } from "./Dialog.js";
4
+ import { IMouseOrTouchEvent } from "./interfaces/IMouseOrTouchEvent.js";
5
+
6
+ /**
7
+ * Listens for events on the [element] and notifies the [listener]
8
+ * if an undock event has been invoked. An undock event is invoked
9
+ * when the user clicks on the event and drags is beyond the
10
+ * specified [thresholdPixels]
11
+ */
12
+ export class UndockInitiator {
13
+ mouseUpHandler: EventHandler;
14
+ touchUpHandler: EventHandler;
15
+ mouseMoveHandler: EventHandler;
16
+ touchMoveHandler: EventHandler;
17
+ dragStartPosition: Point;
18
+ thresholdPixels: number;
19
+ _enabled: boolean;
20
+ mouseDownHandler: EventHandler;
21
+ touchDownHandler: EventHandler;
22
+ element: HTMLElement;
23
+ _undockededCallback: (e: MouseEvent, dragOffset: Point) => Dialog;
24
+ touchDownUndockedHandler: EventHandler;
25
+
26
+ constructor(element: Element, undockededCallback: (e: MouseEvent, dragOffset: Point) => Dialog, thresholdPixels?: number) {
27
+ if (!thresholdPixels) {
28
+ thresholdPixels = 7;
29
+ }
30
+
31
+ this.element = element as HTMLElement;
32
+ this._undockededCallback = undockededCallback;
33
+ this.thresholdPixels = thresholdPixels;
34
+ this._enabled = false;
35
+ }
36
+
37
+ get enabled(): boolean {
38
+ return this._enabled;
39
+ }
40
+ set enabled(value: boolean) {
41
+ this._enabled = value;
42
+ if (this._enabled) {
43
+ if (this.mouseDownHandler) {
44
+ this.mouseDownHandler.cancel();
45
+ delete this.mouseDownHandler;
46
+ }
47
+ if (this.touchDownHandler) {
48
+ this.touchDownHandler.cancel();
49
+ delete this.touchDownHandler;
50
+ }
51
+
52
+ this.mouseDownHandler = new EventHandler(this.element, 'mousedown', this.onMouseDown.bind(this));
53
+ this.touchDownHandler = new EventHandler(this.element, 'touchstart', this.onMouseDown.bind(this), { passive: false });
54
+ }
55
+ else {
56
+ if (this.mouseDownHandler) {
57
+ this.mouseDownHandler.cancel();
58
+ delete this.mouseDownHandler;
59
+ }
60
+
61
+ if (this.touchDownHandler) {
62
+ this.touchDownHandler.cancel();
63
+ delete this.touchDownHandler;
64
+ }
65
+
66
+ if (this.mouseUpHandler) {
67
+ this.mouseUpHandler.cancel();
68
+ delete this.mouseUpHandler;
69
+ }
70
+
71
+ if (this.touchUpHandler) {
72
+ this.touchUpHandler.cancel();
73
+ delete this.touchUpHandler;
74
+ }
75
+
76
+ if (this.mouseMoveHandler) {
77
+ this.mouseMoveHandler.cancel();
78
+ delete this.mouseMoveHandler;
79
+ }
80
+
81
+ if (this.touchMoveHandler) {
82
+ this.touchMoveHandler.cancel();
83
+ delete this.touchMoveHandler;
84
+ }
85
+ }
86
+ }
87
+
88
+ onMouseDown(e) {
89
+ e.preventDefault();
90
+
91
+ // Make sure we dont do this on floating dialogs
92
+ if (this.enabled) {
93
+ if (e.touches) {
94
+ if (e.touches.length > 1)
95
+ return;
96
+ e = e.touches[0];
97
+ }
98
+
99
+ if (this.mouseUpHandler) {
100
+ this.mouseUpHandler.cancel();
101
+ delete this.mouseUpHandler;
102
+ }
103
+
104
+ if (this.touchUpHandler) {
105
+ this.touchUpHandler.cancel();
106
+ delete this.touchUpHandler;
107
+ }
108
+
109
+ if (this.mouseMoveHandler) {
110
+ this.mouseMoveHandler.cancel();
111
+ delete this.mouseMoveHandler;
112
+ }
113
+
114
+ if (this.touchMoveHandler) {
115
+ this.touchMoveHandler.cancel();
116
+ delete this.touchMoveHandler;
117
+ }
118
+
119
+ this.mouseUpHandler = new EventHandler(window, 'mouseup', this.onMouseUp.bind(this));
120
+ this.touchUpHandler = new EventHandler(window, 'touchend', this.onMouseUp.bind(this));
121
+ this.mouseMoveHandler = new EventHandler(window, 'mousemove', this.onMouseMove.bind(this));
122
+ this.touchMoveHandler = new EventHandler(window, 'touchmove', this.onMouseMove.bind(this));
123
+ this.dragStartPosition = new Point(e.clientX, e.clientY);
124
+ }
125
+ }
126
+
127
+ onMouseUp() {
128
+ if (this.mouseUpHandler) {
129
+ this.mouseUpHandler.cancel();
130
+ delete this.mouseUpHandler;
131
+ }
132
+
133
+ if (this.touchUpHandler) {
134
+ this.touchUpHandler.cancel();
135
+ delete this.touchUpHandler;
136
+ }
137
+
138
+ if (this.mouseMoveHandler) {
139
+ this.mouseMoveHandler.cancel();
140
+ delete this.mouseMoveHandler;
141
+ }
142
+
143
+ if (this.touchMoveHandler) {
144
+ this.touchMoveHandler.cancel();
145
+ delete this.touchMoveHandler;
146
+ }
147
+ }
148
+
149
+ onMouseMove(e: IMouseOrTouchEvent) {
150
+ if (e.touches) {
151
+ if (e.touches.length > 1)
152
+ return;
153
+ e = e.touches[0];
154
+ }
155
+
156
+ let position = new Point(e.clientX, e.clientY);
157
+ let dy = position.y - this.dragStartPosition.y;
158
+
159
+ if (dy > this.thresholdPixels || dy < -this.thresholdPixels) {
160
+ this.enabled = false;
161
+ this._requestUndock(e);
162
+ }
163
+ }
164
+
165
+ _requestUndock(e) {
166
+ let top = 0;
167
+ let left = 0;
168
+ let currentElement = this.element;
169
+
170
+ do {
171
+ top += currentElement.offsetTop || 0;
172
+ left += currentElement.offsetLeft || 0;
173
+ currentElement = currentElement.offsetParent as HTMLElement;
174
+ } while (currentElement);
175
+
176
+ let dragOffsetX = this.dragStartPosition.x - left;
177
+ let dragOffsetY = this.dragStartPosition.y - top;
178
+ let dragOffset = new Point(dragOffsetX, dragOffsetY);
179
+ this._undockededCallback(e, dragOffset);
180
+ }
181
+ }
package/src/Utils.ts ADDED
@@ -0,0 +1,85 @@
1
+ import { DockNode } from "./DockNode";
2
+
3
+ export class Utils {
4
+
5
+ private static _counter: number = 0;
6
+
7
+ static getPixels(pixels: string): number {
8
+ if (pixels === null) {
9
+ return 0;
10
+ }
11
+
12
+ return parseInt(pixels.replace('px', ''));
13
+ }
14
+
15
+ static disableGlobalTextSelection(element: HTMLElement) {
16
+ element.classList.add('disable-selection');
17
+ }
18
+
19
+ static enableGlobalTextSelection(element: HTMLElement) {
20
+ element.classList.remove('disable-selection');
21
+ }
22
+
23
+ static isPointInsideNode(px: number, py: number, node: DockNode): boolean {
24
+ let element = node.container.containerElement;
25
+ let rect = element.getBoundingClientRect();
26
+
27
+ return (
28
+ px >= rect.left &&
29
+ px <= rect.left + rect.width &&
30
+ py >= rect.top &&
31
+ py <= rect.top + rect.height
32
+ );
33
+ }
34
+
35
+ static getNextId(prefix: string): string {
36
+ return prefix + Utils._counter++;
37
+ }
38
+
39
+ static removeNode(node: Node): boolean {
40
+ if (node.parentNode === null) {
41
+ return false;
42
+ }
43
+
44
+ node.parentNode.removeChild(node);
45
+
46
+ return true;
47
+ }
48
+
49
+ static orderByIndexes<T>(array: T[], indexes: number[]) {
50
+ let sortedArray = [];
51
+ for (let i = 0; i < indexes.length; i++) {
52
+ sortedArray.push(array[indexes[i]]);
53
+ }
54
+ return sortedArray;
55
+ }
56
+
57
+ static arrayRemove<T>(array: T[], value: any): T[] | false {
58
+ let idx = array.indexOf(value);
59
+ if (idx !== -1) {
60
+ return array.splice(idx, 1);
61
+ }
62
+ return false;
63
+ }
64
+
65
+ static arrayContains<T>(array: T[], value: T): boolean {
66
+ let i = array.length;
67
+ while (i--) {
68
+ if (array[i] === value) {
69
+ return true;
70
+ }
71
+ }
72
+ return false;
73
+ }
74
+
75
+ static arrayEqual<T>(a: T[], b: T[]): boolean {
76
+ if (a === b) return true;
77
+ if (a == null || b == null) return false;
78
+ if (a.length != b.length) return false;
79
+
80
+ for (let i = 0; i < a.length; ++i) {
81
+ if (a[i] !== b[i]) return false;
82
+ }
83
+ return true;
84
+ }
85
+ }
@@ -0,0 +1,13 @@
1
+ import { SplitterDockContainer } from "./SplitterDockContainer.js";
2
+ import { Utils } from "./Utils.js";
3
+ import { ContainerType } from "./ContainerType.js";
4
+ import { DockManager } from "./DockManager.js";
5
+ import { IDockContainer } from "./interfaces/IDockContainer.js";
6
+
7
+ export class VerticalDockContainer extends SplitterDockContainer {
8
+
9
+ constructor(dockManager: DockManager, childContainers: IDockContainer[]) {
10
+ super(Utils.getNextId('vertical_splitter_'), dockManager, childContainers, true)
11
+ this.containerType = ContainerType.vertical;
12
+ }
13
+ }
@@ -0,0 +1,4 @@
1
+ export enum PanelType {
2
+ 'document' = 'document',
3
+ 'panel' = 'panel'
4
+ }
@@ -0,0 +1,6 @@
1
+ export enum TabHostDirection {
2
+ TOP = 0,
3
+ BOTTOM = 1,
4
+ LEFT = 2,
5
+ RIGHT = 3,
6
+ }
@@ -0,0 +1,14 @@
1
+
2
+ export enum WheelTypes {
3
+ // Main dock wheel buttons
4
+ 'left' = 'left',
5
+ 'right' = 'right',
6
+ 'top' = 'top',
7
+ 'down' = 'down',
8
+ 'fill' = 'fill',
9
+ // Buttons on the extreme 4 sides
10
+ 'left-s' = 'left-s',
11
+ 'right-s' = 'right-s',
12
+ 'top-s' = 'top-s',
13
+ 'down-s' = 'down-s'
14
+ }
@@ -0,0 +1,20 @@
1
+ export type TranslationKey = keyof typeof Defaults;
2
+
3
+ export type GetLocalizerParameters<K extends TranslationKey> = K extends keyof LocalizerParameters
4
+ ? LocalizerParameters[K]
5
+ : [];
6
+
7
+ export const Defaults = {
8
+ 'CloseDialog': 'Close dialog',
9
+ 'CloseAll': 'Close all documents',
10
+ 'CloseAllButThis': 'Close all documents but this',
11
+ 'DefaultPanelName': 'Panel',
12
+ 'NewBrowserWindow': 'Open in new window'
13
+ //Example of parameterized translation
14
+ // 'CloseWithName': 'Close tab {0}'
15
+ };
16
+
17
+ export interface LocalizerParameters {
18
+ // Example
19
+ // 'CloseWithName': [tabName: string]
20
+ }