@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
@@ -0,0 +1,228 @@
1
+ import { SplitterBar } from "./SplitterBar.js";
2
+ import { Utils } from "./Utils.js";
3
+ import { IDockContainer } from "./interfaces/IDockContainer.js";
4
+
5
+ /**
6
+ * A splitter panel manages the child containers inside it with splitter bars.
7
+ * It can be stacked horizontally or vertically
8
+ */
9
+ export class SplitterPanel {
10
+ panelElement: HTMLDivElement;
11
+ spiltterBars: SplitterBar[];
12
+ stackedVertical: boolean;
13
+ childContainers: IDockContainer[];
14
+
15
+ constructor(childContainers: IDockContainer[], stackedVertical: boolean) {
16
+ this.childContainers = childContainers;
17
+ this.stackedVertical = stackedVertical;
18
+ this.panelElement = document.createElement('div');
19
+ this.spiltterBars = [];
20
+ this._buildSplitterDOMAndAddElements();
21
+ }
22
+
23
+ _buildSplitterDOMAndAddElements() {
24
+ if (this.childContainers.length <= 1)
25
+ throw new Error('Splitter panel should contain atleast 2 panels');
26
+
27
+ this.spiltterBars = [];
28
+ let afterElement: HTMLElement = null;
29
+ for (let i = 0; i < this.childContainers.length - 1; i++) {
30
+ let previousContainer = this.childContainers[i];
31
+ let nextContainer = this.childContainers[i + 1];
32
+ let splitterBar = new SplitterBar(previousContainer, nextContainer, this.stackedVertical);
33
+ this.spiltterBars.push(splitterBar);
34
+
35
+ // Add the container and split bar to the panel's base div element
36
+ if (!Array.from(this.panelElement.children).includes(previousContainer.containerElement))
37
+ this._insertContainerIntoPanel(previousContainer, afterElement);
38
+ this.panelElement.insertBefore(splitterBar.barElement, previousContainer.containerElement.nextSibling);
39
+ afterElement = splitterBar.barElement;
40
+ }
41
+ let last = this.childContainers.slice(-1)[0];
42
+ if (!Array.from(this.panelElement.children).includes(last.containerElement))
43
+ this._insertContainerIntoPanel(last, afterElement);
44
+ }
45
+
46
+ performLayout(children: IDockContainer[], relayoutEvenIfEqual: boolean) {
47
+ let containersEqual = Utils.arrayEqual(this.childContainers, children);
48
+ if (!containersEqual || relayoutEvenIfEqual) {
49
+ this.childContainers.forEach((container) => {
50
+ if (!children.some((item) => item == container)) {
51
+ if (container.containerElement) {
52
+ container.containerElement.classList.remove('splitter-container-vertical');
53
+ container.containerElement.classList.remove('splitter-container-horizontal');
54
+ Utils.removeNode(container.containerElement);
55
+
56
+ }
57
+ }
58
+ });
59
+ this.spiltterBars.forEach((bar) => { Utils.removeNode(bar.barElement); });
60
+
61
+ // rebuild
62
+ this.childContainers = children;
63
+ this._buildSplitterDOMAndAddElements();
64
+ }
65
+ }
66
+
67
+ removeFromDOM() {
68
+ this.childContainers.forEach((container) => {
69
+ if (container.containerElement) {
70
+ container.containerElement.classList.remove('splitter-container-vertical');
71
+ container.containerElement.classList.remove('splitter-container-horizontal');
72
+ Utils.removeNode(container.containerElement);
73
+ }
74
+ });
75
+ this.spiltterBars.forEach((bar) => { Utils.removeNode(bar.barElement); });
76
+ }
77
+
78
+ destroy() {
79
+ this.removeFromDOM();
80
+ this.panelElement.parentNode.removeChild(this.panelElement);
81
+ }
82
+
83
+ _insertContainerIntoPanel(container: IDockContainer, afterElement: HTMLElement) {
84
+ if (!container) {
85
+ console.error('container is undefined');
86
+ return;
87
+ }
88
+
89
+ if (container.containerElement.parentNode != this.panelElement) {
90
+ Utils.removeNode(container.containerElement);
91
+ if (afterElement)
92
+ this.panelElement.insertBefore(container.containerElement, afterElement.nextSibling);
93
+ else {
94
+ if (this.panelElement.children.length > 0)
95
+ this.panelElement.insertBefore(container.containerElement, this.panelElement.children[0]);
96
+ else
97
+ this.panelElement.appendChild(container.containerElement);
98
+ }
99
+ }
100
+ container.containerElement.classList.add(
101
+ this.stackedVertical ? 'splitter-container-vertical' : 'splitter-container-horizontal'
102
+ );
103
+ }
104
+
105
+ /**
106
+ * Sets the percentage of space the specified [container] takes in the split panel
107
+ * The percentage is specified in [ratio] and is between 0..1
108
+ */
109
+ setContainerRatio(container: IDockContainer, ratio: number) {
110
+ let splitPanelSize = this.stackedVertical ? this.panelElement.clientHeight : this.panelElement.clientWidth;
111
+ let newContainerSize = splitPanelSize * ratio;
112
+ let barSize = this.stackedVertical ? this.spiltterBars[0].barElement.clientHeight : this.spiltterBars[0].barElement.clientWidth;
113
+ let otherPanelSizeQuota = splitPanelSize - newContainerSize - barSize * this.spiltterBars.length;
114
+ let otherPanelScaleMultipler = otherPanelSizeQuota / splitPanelSize;
115
+
116
+ for (let i = 0; i < this.childContainers.length; i++) {
117
+ let child = this.childContainers[i];
118
+ let size;
119
+ if (child !== container) {
120
+ size = this.stackedVertical ? child.containerElement.parentElement.clientHeight : child.containerElement.parentElement.clientWidth;
121
+ size *= otherPanelScaleMultipler;
122
+ }
123
+ else
124
+ size = newContainerSize;
125
+
126
+ if (this.stackedVertical)
127
+ child.resize(child.width, Math.floor(size));
128
+ else
129
+ child.resize(Math.floor(size), child.height);
130
+ }
131
+ }
132
+
133
+ getRatios(): number[] {
134
+ let barSize = this.stackedVertical ? this.spiltterBars[0].barElement.clientHeight : this.spiltterBars[0].barElement.clientWidth;
135
+ let splitPanelSize = (this.stackedVertical ? this.panelElement.clientHeight : this.panelElement.clientWidth) - barSize * this.spiltterBars.length;
136
+ let result: number[] = [];
137
+ for (let i = 0; i < this.childContainers.length; i++) {
138
+ let child = this.childContainers[i];
139
+ let sizeOld = this.stackedVertical ? child.containerElement.clientHeight : child.containerElement.clientWidth;
140
+ result.push(sizeOld / splitPanelSize);
141
+ }
142
+ return result;
143
+ }
144
+
145
+ setRatios(ratios: number[]) {
146
+ let barSize = this.stackedVertical ? this.spiltterBars[0].barElement.clientHeight : this.spiltterBars[0].barElement.clientWidth;
147
+ let splitPanelSize = (this.stackedVertical ? this.panelElement.clientHeight : this.panelElement.clientWidth) - barSize * this.spiltterBars.length;
148
+ for (let i = 0; i < this.childContainers.length; i++) {
149
+ let child = this.childContainers[i];
150
+ let size = splitPanelSize * ratios[i];
151
+ if (this.stackedVertical)
152
+ child.resize(child.width, Math.floor(size));
153
+ else
154
+ child.resize(Math.floor(size), child.height);
155
+ }
156
+ }
157
+
158
+ resize(width: number, height: number) {
159
+ if (this.childContainers.length <= 1)
160
+ return;
161
+
162
+ this.panelElement.style.width = width + 'px';
163
+ this.panelElement.style.height = height + 'px';
164
+
165
+ let i;
166
+
167
+ // Adjust the fixed dimension that is common to all (i.e. width, if stacked vertical; height, if stacked horizontally)
168
+ for (i = 0; i < this.childContainers.length; i++) {
169
+ let childContainer = this.childContainers[i];
170
+ if (this.stackedVertical)
171
+ childContainer.resize(width, !childContainer.height ? height : childContainer.height);
172
+ else
173
+ childContainer.resize(!childContainer.width ? width : childContainer.width, height);
174
+
175
+ if (i < this.spiltterBars.length) {
176
+ let splitBar = this.spiltterBars[i];
177
+ if (this.stackedVertical)
178
+ splitBar.barElement.style.width = width + 'px';
179
+ else
180
+ splitBar.barElement.style.height = height + 'px';
181
+ }
182
+ }
183
+
184
+ // Adjust the varying dimension
185
+ let totalChildPanelSize = 0;
186
+ // Find out how much space existing child containers take up (excluding the splitter bars)
187
+ this.childContainers.forEach((container) => {
188
+ let size = this.stackedVertical ?
189
+ container.height :
190
+ container.width;
191
+ totalChildPanelSize += size;
192
+ });
193
+
194
+ const barRect = this.spiltterBars[0].barElement.getBoundingClientRect();
195
+ // Get the thickness of the bar
196
+ let barSize = this.stackedVertical ? barRect.height : barRect.width;
197
+
198
+ // Find out how much space existing child containers will take after being resized (excluding the splitter bars)
199
+ let targetTotalChildPanelSize = this.stackedVertical ? height : width;
200
+ targetTotalChildPanelSize -= barSize * this.spiltterBars.length;
201
+
202
+ // Get the scale multiplier
203
+ totalChildPanelSize = Math.max(totalChildPanelSize, 1);
204
+ let scaleMultiplier = targetTotalChildPanelSize / totalChildPanelSize;
205
+
206
+
207
+ // Update the size with this multiplier
208
+ let updatedTotalChildPanelSize = 0;
209
+ for (i = 0; i < this.childContainers.length; i++) {
210
+ let child = this.childContainers[i];
211
+ if (child.containerElement.style.display == 'none')
212
+ child.containerElement.style.display = 'block';
213
+ let original = this.stackedVertical ? child.containerElement.clientHeight : child.containerElement.clientWidth;
214
+ let newSize = scaleMultiplier > 1 ? Math.floor(original * scaleMultiplier) : Math.ceil(original * scaleMultiplier);
215
+ updatedTotalChildPanelSize += newSize;
216
+
217
+ // If this is the last node, add any extra pixels to fix the rounding off errors and match the requested size
218
+ if (i === this.childContainers.length - 1)
219
+ newSize += targetTotalChildPanelSize - updatedTotalChildPanelSize;
220
+
221
+ // Set the size of the panel
222
+ if (this.stackedVertical)
223
+ child.resize(child.width, newSize);
224
+ else
225
+ child.resize(newSize, child.height);
226
+ }
227
+ }
228
+ }
@@ -0,0 +1,347 @@
1
+ import {TabPage} from './TabPage.js';
2
+ import {PanelContainer} from './PanelContainer.js';
3
+ import {UndockInitiator} from './UndockInitiator.js';
4
+ import {EventHandler} from './EventHandler.js';
5
+ import {Utils} from './Utils.js';
6
+ import {PanelType} from './enums/PanelType.js';
7
+ import {DockNode} from './DockNode.js';
8
+ import {Localizer} from './i18n/Localizer.js';
9
+
10
+ /**
11
+ * A tab handle represents the tab button on the tab strip
12
+ */
13
+ export class TabHandle {
14
+ parent: TabPage;
15
+ elementBase: HTMLDivElement;
16
+ elementText: HTMLDivElement;
17
+ elementCloseButton: HTMLDivElement;
18
+ undockInitiator: UndockInitiator;
19
+ mouseDownHandler: EventHandler;
20
+ touchDownHandler: EventHandler;
21
+ closeButtonHandler: EventHandler;
22
+ closeButtonTouchHandler: EventHandler;
23
+ auxClickHandler: EventHandler;
24
+ contextMenuHandler: EventHandler;
25
+ mouseMoveHandler: EventHandler;
26
+ touchMoveHandler: EventHandler;
27
+ mouseUpHandler: EventHandler;
28
+ touchUpHandler: EventHandler;
29
+ stargDragPosition: any;
30
+ dragged: boolean;
31
+ eventListeners: any[];
32
+ undockListener: { onDockEnabled: (e: any) => void; onHideCloseButton: (e: any) => void; };
33
+
34
+ prev: number;
35
+ current: number;
36
+ direction: number;
37
+ _ctxMenu: HTMLDivElement;
38
+ _windowsContextMenuCloseBound: any;
39
+
40
+ constructor(parent: TabPage) {
41
+ this.parent = parent;
42
+ const undockHandler = this._performUndock.bind(this);
43
+ this.elementBase = document.createElement('div');
44
+ this.elementText = document.createElement('div');
45
+ this.elementCloseButton = document.createElement('div');
46
+ this.elementBase.classList.add('dockspan-tab-handle');
47
+ this.elementBase.classList.add('disable-selection'); // Disable text selection
48
+ this.elementText.classList.add('dockspan-tab-handle-text');
49
+ this.elementCloseButton.classList.add('dockspan-tab-handle-close-button');
50
+ this.elementBase.appendChild(this.elementText);
51
+ if (this.parent.host.displayCloseButton)
52
+ this.elementBase.appendChild(this.elementCloseButton);
53
+ if ((<PanelContainer> this.parent.container)._hideCloseButton || (<PanelContainer> this.parent.container)._grayOut)
54
+ this.elementCloseButton.style.display = 'none';
55
+ this.parent.host.tabListElement.appendChild(this.elementBase);
56
+
57
+ const panel = parent.container as PanelContainer;
58
+ const title = panel.getRawTitle();
59
+ this.undockListener = {
60
+ onDockEnabled: (e) => {this.undockEnabled(e.state);},
61
+ onHideCloseButton: (e) => {this.hideCloseButton(e.state);},
62
+ };
63
+ this.eventListeners = [];
64
+ panel.addListener(this.undockListener);
65
+
66
+ this.elementText.innerHTML = title;
67
+ this.elementText.setAttribute('dock-spawn-title', this.elementText.innerText);
68
+
69
+ //this._bringToFront(this.elementBase);
70
+
71
+ this.undockInitiator = new UndockInitiator(this.elementBase, undockHandler);
72
+ this.undockInitiator.enabled = true;
73
+ this.mouseDownHandler = new EventHandler(this.elementBase, 'mousedown', this.onMouseDown.bind(this));
74
+ this.touchDownHandler = new EventHandler(this.elementBase, 'touchstart', this.onMouseDown.bind(this), {passive: false});
75
+ this.closeButtonHandler = new EventHandler(this.elementCloseButton, 'click', this.onCloseButtonClicked.bind(this));
76
+ this.closeButtonTouchHandler = new EventHandler(this.elementCloseButton, 'touchstart', this.onCloseButtonClicked.bind(this));
77
+ this.auxClickHandler = new EventHandler(this.elementBase, 'auxclick', this.onCloseButtonClicked.bind(this));
78
+
79
+ if (panel.panelType == PanelType.document)
80
+ this.contextMenuHandler = new EventHandler(this.elementBase, 'contextmenu', this.oncontextMenuClicked.bind(this));
81
+
82
+
83
+ this.windowsContextMenuClose = this.windowsContextMenuClose.bind(this);
84
+ //this.zIndexCounter = parent.host.dockManager.zIndexTabHandle;
85
+ }
86
+
87
+ addListener(listener) {
88
+ this.eventListeners.push(listener);
89
+ }
90
+
91
+ removeListener(listener) {
92
+ this.eventListeners.splice(this.eventListeners.indexOf(listener), 1);
93
+ }
94
+
95
+ undockEnabled(state: boolean) {
96
+ this.undockInitiator.enabled = state;
97
+ }
98
+
99
+ static createContextMenuContentCallback = (tabHandle: TabHandle, documentMangerNodes: DockNode[]): Node[] => {
100
+ const result = [];
101
+
102
+ const btnCloseAll = document.createElement('div');
103
+ btnCloseAll.innerText = Localizer.getString('CloseAll');
104
+ result.push(btnCloseAll);
105
+
106
+ btnCloseAll.onclick = () => {
107
+ const length = documentMangerNodes.length;
108
+ for (let i = length - 1; i >= 0; i--) {
109
+ const panel = (<PanelContainer>documentMangerNodes[i].container);
110
+ if (panel.panelType == PanelType.document)
111
+ panel.close();
112
+ }
113
+ tabHandle.closeContextMenu();
114
+ };
115
+
116
+ const btnCloseAllButThis = document.createElement('div');
117
+ btnCloseAllButThis.innerText = Localizer.getString('CloseAllButThis');
118
+ result.push(btnCloseAllButThis);
119
+
120
+ btnCloseAllButThis.onclick = () => {
121
+ const length = documentMangerNodes.length;
122
+ for (let i = length - 1; i >= 0; i--) {
123
+ const panel = (<PanelContainer>documentMangerNodes[i].container);
124
+ if (tabHandle.parent.container != panel && panel.panelType == PanelType.document)
125
+ panel.close();
126
+ }
127
+ tabHandle.closeContextMenu();
128
+ };
129
+
130
+ if (tabHandle.parent.container.dockManager.config.enableBrowserWindows) {
131
+ const btnNewBrowserWindow = document.createElement('div');
132
+ btnNewBrowserWindow.innerText = Localizer.getString('NewBrowserWindow');
133
+ result.push(btnNewBrowserWindow);
134
+
135
+ btnNewBrowserWindow.onclick = () => {
136
+ (<PanelContainer>tabHandle.parent.container).undockToBrowserDialog();
137
+ tabHandle.closeContextMenu();
138
+ };
139
+ }
140
+
141
+ return result;
142
+ };
143
+
144
+ oncontextMenuClicked(e: MouseEvent) {
145
+ e.preventDefault();
146
+
147
+ if (!this._ctxMenu && TabHandle.createContextMenuContentCallback) {
148
+ const menuItems = TabHandle.createContextMenuContentCallback(
149
+ this,
150
+ this.parent.container.dockManager.context.model.documentManagerNode.children,
151
+ );
152
+
153
+ if (menuItems.length == 0)
154
+ return;
155
+
156
+
157
+ this._ctxMenu = document.createElement('div');
158
+ this._ctxMenu.className = 'dockspab-tab-handle-context-menu';
159
+ this._ctxMenu.append(...menuItems);
160
+ this._ctxMenu.style.left = e.pageX + 'px';
161
+ this._ctxMenu.style.top = e.pageY + 'px';
162
+ document.body.appendChild(this._ctxMenu);
163
+ window.addEventListener('mouseup', this.windowsContextMenuClose);
164
+ } else
165
+ this.closeContextMenu();
166
+ }
167
+
168
+ closeContextMenu() {
169
+ if (this._ctxMenu) {
170
+ document.body.removeChild(this._ctxMenu);
171
+ delete this._ctxMenu;
172
+ window.removeEventListener('mouseup', this.windowsContextMenuClose);
173
+ }
174
+ }
175
+
176
+ windowsContextMenuClose(e: Event) {
177
+ const cp = e.composedPath();
178
+ for (const i in cp) {
179
+ const el = cp[i];
180
+ if (el == this._ctxMenu)
181
+ return;
182
+ }
183
+ this.closeContextMenu();
184
+ }
185
+
186
+ onMouseDown(e) {
187
+ e.preventDefault();
188
+
189
+ this.parent.onSelected();
190
+
191
+ if (this.mouseMoveHandler) {
192
+ this.mouseMoveHandler.cancel();
193
+ delete this.mouseMoveHandler;
194
+ }
195
+ if (this.touchMoveHandler) {
196
+ this.touchMoveHandler.cancel();
197
+ delete this.touchMoveHandler;
198
+ }
199
+ if (this.mouseUpHandler) {
200
+ this.mouseUpHandler.cancel();
201
+ delete this.mouseUpHandler;
202
+ }
203
+ if (this.touchUpHandler) {
204
+ this.touchUpHandler.cancel();
205
+ delete this.touchUpHandler;
206
+ }
207
+ this.stargDragPosition = e.clientX;
208
+ this.mouseMoveHandler = new EventHandler(window, 'mousemove', this.onMouseMove.bind(this));
209
+ this.touchMoveHandler = new EventHandler(window, 'touchmove', this.onMouseMove.bind(this), {passive: false});
210
+ this.mouseUpHandler = new EventHandler(window, 'mouseup', this.onMouseUp.bind(this));
211
+ this.touchUpHandler = new EventHandler(window, 'touchend', this.onMouseUp.bind(this));
212
+ }
213
+
214
+ onMouseUp(e) {
215
+ if (this.elementBase)
216
+ this.elementBase.classList.remove('dockspan-tab-handle-dragged');
217
+
218
+ this.dragged = false;
219
+ if (this.mouseMoveHandler)
220
+ this.mouseMoveHandler.cancel();
221
+ if (this.touchMoveHandler)
222
+ this.touchMoveHandler.cancel();
223
+ if (this.mouseUpHandler)
224
+ this.mouseUpHandler.cancel();
225
+ if (this.touchUpHandler)
226
+ this.touchUpHandler.cancel();
227
+ delete this.mouseMoveHandler;
228
+ delete this.touchMoveHandler;
229
+ delete this.mouseUpHandler;
230
+ delete this.touchUpHandler;
231
+ }
232
+
233
+ moveTabEvent(that, state) {
234
+ that.eventListeners.forEach((listener) => {
235
+ if (listener.onMoveTab)
236
+ listener.onMoveTab({self: that, state: state});
237
+ });
238
+ }
239
+
240
+ onMouseMove(e) {
241
+ e.preventDefault();
242
+
243
+ if (Math.abs(this.stargDragPosition - e.clientX) < 10)
244
+ return;
245
+ if (this.elementBase != null) { //Todo: because of this is null, we need to drag 2 times, needs fix
246
+ this.elementBase.classList.add('dockspan-tab-handle-dragged');
247
+ this.dragged = true;
248
+ this.prev = this.current;
249
+ this.current = e.clientX;
250
+ this.direction = this.current - this.prev;
251
+ const tabRect = this.elementBase.getBoundingClientRect();
252
+ const event = this.direction < 0 ?
253
+ {state: 'left', bound: tabRect.left, rect: tabRect} :
254
+ {state: 'right', bound: tabRect.right, rect: tabRect};
255
+ if ((e.clientX < tabRect.left && this.direction < 0) || (e.clientX > tabRect.left + tabRect.width && this.direction > 0))
256
+ this.moveTabEvent(this, event.state);
257
+ }
258
+ }
259
+
260
+ hideCloseButton(state) {
261
+ this.elementCloseButton.style.display = state ? 'none' : 'block';
262
+ }
263
+
264
+ updateTitle() {
265
+ if (this.parent.container instanceof PanelContainer) {
266
+ const panel = this.parent.container;
267
+ const title = panel.getRawTitle();
268
+ this.elementText.innerHTML = title;
269
+ }
270
+ }
271
+
272
+ destroy() {
273
+ const panel = this.parent.container as PanelContainer;
274
+ panel.removeListener(this.undockListener);
275
+
276
+ this.mouseDownHandler.cancel();
277
+ this.touchDownHandler.cancel();
278
+ this.closeButtonHandler.cancel();
279
+ this.closeButtonTouchHandler.cancel();
280
+ this.auxClickHandler.cancel();
281
+
282
+ if (this.mouseMoveHandler)
283
+ this.mouseMoveHandler.cancel();
284
+
285
+ if (this.touchMoveHandler)
286
+ this.touchMoveHandler.cancel();
287
+
288
+ if (this.mouseUpHandler)
289
+ this.mouseUpHandler.cancel();
290
+
291
+ if (this.touchUpHandler)
292
+ this.touchUpHandler.cancel();
293
+
294
+ if (this.contextMenuHandler)
295
+ this.contextMenuHandler.cancel();
296
+
297
+
298
+ if (this.elementBase) {
299
+ Utils.removeNode(this.elementBase);
300
+ delete this.elementBase;
301
+ }
302
+
303
+ if (this.elementCloseButton) {
304
+ Utils.removeNode(this.elementCloseButton);
305
+ delete this.elementCloseButton;
306
+ }
307
+ }
308
+
309
+ _performUndock(e, dragOffset) {
310
+ if (this.parent.container.containerType === 'panel') {
311
+ this.undockInitiator.enabled = false;
312
+ const panel = this.parent.container as PanelContainer;
313
+ return panel.performUndockToDialog(e, dragOffset);
314
+ } else
315
+ return null;
316
+ }
317
+
318
+ onCloseButtonClicked(e) {
319
+ if (this.elementCloseButton.style.display !== 'none') {
320
+ if (e.button !== 2) {
321
+ // If the page contains a panel element, undock it and destroy it
322
+ if (this.parent.container.containerType === 'panel') {
323
+ const panel = this.parent.container as PanelContainer;
324
+ panel.close();
325
+ }
326
+ }
327
+ }
328
+ }
329
+
330
+ setSelected(isSelected: boolean) {
331
+ if (isSelected)
332
+ this.elementBase.classList.add('dockspan-tab-handle-selected');
333
+ else {
334
+ this.elementBase.classList.remove('dockspan-tab-handle-selected');
335
+ this.elementBase.classList.remove('dockspan-tab-handle-active');
336
+ }
337
+ }
338
+
339
+ setActive(isActive: boolean) {
340
+ if (this.elementBase) {
341
+ if (isActive)
342
+ this.elementBase.classList.add('dockspan-tab-handle-active');
343
+ else
344
+ this.elementBase.classList.remove('dockspan-tab-handle-active');
345
+ }
346
+ }
347
+ }