@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,98 @@
1
+ import { DockManager } from "./DockManager.js";
2
+ import { Utils } from "./Utils.js";
3
+ import { ContainerType } from "./ContainerType.js";
4
+ import { TabHost } from "./TabHost.js";
5
+ import { TabHostDirection } from "./enums/TabHostDirection.js";
6
+ import { ISize } from "./interfaces/ISize.js";
7
+ import { IDockContainerWithSize } from "./interfaces/IDockContainerWithSize.js";
8
+ import { IState } from "./interfaces/IState.js";
9
+ import { IDockContainer } from "./interfaces/IDockContainer.js";
10
+
11
+ export class FillDockContainer implements IDockContainerWithSize {
12
+
13
+ dockManager: DockManager;
14
+ tabOrientation: TabHostDirection;
15
+ name: string;
16
+ element: HTMLDivElement;
17
+ containerElement: HTMLDivElement;
18
+ containerType: ContainerType;
19
+ minimumAllowedChildNodes: number;
20
+ tabHost: TabHost;
21
+ tabHostListener: { onChange: (e: any) => void; };
22
+ state: ISize;
23
+
24
+ constructor(dockManager: DockManager, tabStripDirection?: TabHostDirection) {
25
+ if (tabStripDirection === undefined) {
26
+ tabStripDirection = TabHostDirection.BOTTOM;
27
+ }
28
+
29
+ this.dockManager = dockManager;
30
+ this.tabOrientation = tabStripDirection;
31
+ this.name = Utils.getNextId('fill_');
32
+ this.element = document.createElement('div');
33
+ this.containerElement = this.element;
34
+ this.containerType = ContainerType.fill;
35
+ this.minimumAllowedChildNodes = 2;
36
+ this.element.classList.add('dock-container');
37
+ this.element.classList.add('dock-container-fill');
38
+ this.tabHost = new TabHost(dockManager, this.tabOrientation);
39
+ this.tabHostListener = {
40
+ onChange: (e) => {
41
+ this.dockManager._requestTabReorder(this, e);
42
+ }
43
+ };
44
+ this.tabHost.addListener(this.tabHostListener);
45
+ this.element.appendChild(this.tabHost.hostElement);
46
+ }
47
+
48
+
49
+ setActiveChild(child: IDockContainer) {
50
+ this.tabHost.setActiveTab(child);
51
+ }
52
+
53
+ resize(width: number, height: number) {
54
+ this.element.style.width = width + 'px';
55
+ this.element.style.height = height + 'px';
56
+ this.tabHost.resize(width, height);
57
+ }
58
+
59
+ performLayout(children: IDockContainer[]) {
60
+ this.tabHost.performLayout(children);
61
+ }
62
+
63
+ destroy() {
64
+ this.tabHost.pages.forEach(x => x.destroy());
65
+ if (Utils.removeNode(this.element))
66
+ delete this.element;
67
+ }
68
+
69
+ saveState(state: IState): void {
70
+ state.width = this.width;
71
+ state.height = this.height;
72
+ }
73
+
74
+ loadState(state: IState): void {
75
+ // this.resize(state.width, state.height);
76
+ // this.width = state.width;
77
+ // this.height = state.height;
78
+ this.state = { width: state.width, height: state.height };
79
+ }
80
+
81
+ get width(): number {
82
+ // if(this.element.clientWidth === 0 && this.stateWidth !== 0)
83
+ // return this.stateWidth;
84
+ return this.element.clientWidth;
85
+ }
86
+ set width(value: number) {
87
+ this.element.style.width = value + 'px'
88
+ }
89
+
90
+ get height(): number {
91
+ // if(this.element.clientHeight === 0 && this.stateHeight !== 0)
92
+ // return this.stateHeight;
93
+ return this.element.clientHeight;
94
+ }
95
+ set height(value: number) {
96
+ this.element.style.height = value + 'px'
97
+ }
98
+ }
@@ -0,0 +1,13 @@
1
+ import { SplitterDockContainer } from "./SplitterDockContainer.js";
2
+ import { Utils } from "./Utils.js";
3
+ import { DockManager } from "./DockManager.js";
4
+ import { ContainerType } from "./ContainerType.js";
5
+ import { IDockContainer } from "./interfaces/IDockContainer.js";
6
+
7
+ export class HorizontalDockContainer extends SplitterDockContainer {
8
+
9
+ constructor(dockManager: DockManager, childContainers: IDockContainer[]) {
10
+ super(Utils.getNextId('horizontal_splitter_'), dockManager, childContainers, false)
11
+ this.containerType = ContainerType.horizontal;
12
+ }
13
+ }
@@ -0,0 +1,596 @@
1
+ import {DockManager} from './DockManager.js';
2
+ import {Utils} from './Utils.js';
3
+ import {UndockInitiator} from './UndockInitiator.js';
4
+ import {ContainerType} from './ContainerType.js';
5
+ import {EventHandler} from './EventHandler.js';
6
+ import {ISize} from './interfaces/ISize.js';
7
+ import {IDockContainerWithSize} from './interfaces/IDockContainerWithSize.js';
8
+ import {IState} from './interfaces/IState.js';
9
+ import {Point} from './Point.js';
10
+ import {IDockContainer} from './interfaces/IDockContainer.js';
11
+ import {PanelType} from './enums/PanelType.js';
12
+ import {Dialog} from './Dialog.js';
13
+ import {TabPage} from './TabPage.js';
14
+ import {Localizer} from './i18n/Localizer.js';
15
+ import {moveElementToNewBrowserWindow} from './BrowserDialogHelper.js';
16
+
17
+ /**
18
+ * This dock container wraps the specified element on a panel frame with a title bar and close button
19
+ */
20
+ export class PanelContainer implements IDockContainerWithSize {
21
+ public closePanelContainerCallback: (panelContainer: PanelContainer) => Promise<boolean>;
22
+
23
+ onTitleChanged: (panelContainer: PanelContainer, title: string) => void;
24
+ elementPanel: HTMLDivElement;
25
+ elementTitle: HTMLDivElement;
26
+ elementTitleText: HTMLDivElement;
27
+ elementContentHost: HTMLDivElement;
28
+ name: string;
29
+ state: ISize;
30
+ elementContent: HTMLElement & { resizeHandler?: any, _dockSpawnPanelContainer: PanelContainer };
31
+ private _resolvedElementContent: HTMLElement;
32
+ elementContentContainer: HTMLElement;
33
+ elementContentWrapper: HTMLElement;
34
+ dockManager: DockManager;
35
+ title: string;
36
+ containerType: ContainerType;
37
+ icon: string;
38
+ hasChanges: boolean;
39
+ minimumAllowedChildNodes: number;
40
+ isDialog: boolean;
41
+ eventListeners: any[];
42
+ undockInitiator: UndockInitiator;
43
+ elementButtonClose: HTMLDivElement;
44
+ closeButtonClickedHandler: EventHandler;
45
+ closeButtonTouchedHandler: EventHandler;
46
+ mouseDownHandler: EventHandler;
47
+ touchDownHandler: EventHandler;
48
+ panelType: PanelType;
49
+ tabPage?: TabPage;
50
+ undockedToNewBrowserWindow = false;
51
+ contextMenuHandler: EventHandler;
52
+
53
+ lastDialogSize?: ISize;
54
+
55
+ _floatingDialog?: Dialog;
56
+ _canUndock: boolean;
57
+ _cachedWidth: number;
58
+ _cachedHeight: number;
59
+ _hideCloseButton: boolean;
60
+ _grayOut: HTMLDivElement;
61
+ _ctxMenu: HTMLDivElement;
62
+
63
+ constructor(elementContent: HTMLElement, dockManager: DockManager, title?: string, panelType?: PanelType, hideCloseButton?: boolean, panelIcon?: string) {
64
+ if (!title)
65
+ title = Localizer.getString('DefaultPanelName');
66
+ if (!panelType)
67
+ panelType = PanelType.panel;
68
+ this.panelType = panelType;
69
+
70
+ (<any>elementContent)._dockSpawnPanelContainer = this;
71
+ this.elementContent = <any>elementContent;
72
+ elementContent.style.position = 'absolute';
73
+ elementContent.style.width = '100%';
74
+ elementContent.style.height = '100%';
75
+ elementContent.style.top = '0';
76
+ elementContent.style.bottom = '0';
77
+ this.elementContentContainer = document.createElement('div');
78
+ this.elementContentContainer.className = 'panel-element-content-container';
79
+ this.elementContentContainer.style.position = 'absolute';
80
+ (<any> this.elementContentContainer)._panel = this;
81
+ this.elementContentContainer.addEventListener('pointerdown', (e) => {
82
+ try {
83
+ if (this.isDialog)
84
+ this._floatingDialog.bringToFront();
85
+ else {
86
+ if (this.tabPage)
87
+ this.tabPage.setSelected(true, true);
88
+ }
89
+ this.dockManager.activePanel = this;
90
+ } catch { }
91
+ }, {passive: true});
92
+ this.elementContentContainer.appendChild(elementContent);
93
+ dockManager.config.dialogRootElement.appendChild(this.elementContentContainer);
94
+
95
+ this.dockManager = dockManager;
96
+ this.title = title;
97
+ this.containerType = ContainerType.panel;
98
+ this.icon = panelIcon;
99
+ this.minimumAllowedChildNodes = 0;
100
+ this._floatingDialog = undefined;
101
+ this.isDialog = false;
102
+ this._canUndock = dockManager._undockEnabled;
103
+ this.eventListeners = [];
104
+ this._hideCloseButton = hideCloseButton;
105
+ this.windowsContextMenuClose = this.windowsContextMenuClose.bind(this);
106
+
107
+ this._initialize();
108
+ }
109
+
110
+ _initialize() {
111
+ this.name = Utils.getNextId('panel_');
112
+ this.elementPanel = document.createElement('div');
113
+ this.elementPanel.tabIndex = 0;
114
+ this.elementTitle = document.createElement('div');
115
+ this.contextMenuHandler = new EventHandler(this.elementTitle, 'contextmenu', this.oncontextMenuClicked.bind(this));
116
+
117
+ this.elementTitleText = document.createElement('div');
118
+ this.elementContentHost = document.createElement('div');
119
+ this.elementButtonClose = document.createElement('div');
120
+
121
+ this.elementPanel.appendChild(this.elementTitle);
122
+ this.elementTitle.appendChild(this.elementTitleText);
123
+ this.elementTitle.appendChild(this.elementButtonClose);
124
+ this.elementButtonClose.classList.add('panel-titlebar-button-close');
125
+ this.elementButtonClose.style.display = this._hideCloseButton ? 'none' : 'block';
126
+
127
+ this.elementPanel.appendChild(this.elementContentHost);
128
+
129
+ this.elementPanel.classList.add('panel-base');
130
+ this.elementTitle.classList.add('panel-titlebar');
131
+ this.elementTitle.classList.add('disable-selection');
132
+ this.elementTitleText.classList.add('panel-titlebar-text');
133
+ this.elementContentHost.classList.add('panel-content');
134
+
135
+ // set the size of the dialog elements based on the panel's size
136
+ const panelWidth = this.elementContentContainer.clientWidth;
137
+ const panelHeight = this.elementContentContainer.clientHeight;
138
+ const titleHeight = this.elementTitle.clientHeight;
139
+
140
+ this.elementContentWrapper = document.createElement('div');
141
+ this.elementContentWrapper.classList.add('panel-content-wrapper');
142
+
143
+ this._setPanelDimensions(panelWidth, panelHeight + titleHeight);
144
+
145
+ if (!this._hideCloseButton) {
146
+ this.closeButtonClickedHandler =
147
+ new EventHandler(this.elementButtonClose, 'mousedown', this.onCloseButtonClicked.bind(this));
148
+ this.closeButtonTouchedHandler =
149
+ new EventHandler(this.elementButtonClose, 'touchstart', this.onCloseButtonClicked.bind(this));
150
+ }
151
+
152
+ Utils.removeNode(this.elementContentWrapper);
153
+ this.elementContentHost.appendChild(this.elementContentWrapper);
154
+
155
+ // Extract the title from the content element's attribute
156
+ const contentTitle = this.elementContent.dataset.panelCaption;
157
+ if (contentTitle) this.title = contentTitle;
158
+ this._updateTitle();
159
+
160
+ this.undockInitiator = new UndockInitiator(this.elementTitle, this.performUndockToDialog.bind(this));
161
+ delete this.floatingDialog;
162
+
163
+ this.mouseDownHandler = new EventHandler(this.elementPanel, 'mousedown', this.onMouseDown.bind(this));
164
+ this.touchDownHandler = new EventHandler(this.elementPanel, 'touchstart', this.onMouseDown.bind(this), {passive: true});
165
+
166
+ this._resolvedElementContent = this.elementContent;
167
+ if (this.elementContent instanceof HTMLSlotElement)
168
+ this._resolvedElementContent = <HTMLElement> this.elementContent.assignedElements()?.[0];
169
+ }
170
+
171
+ static createContextMenuContentCallback = (panelContainer: PanelContainer): Node[] => {
172
+ const result = [];
173
+
174
+ if (panelContainer.dockManager.config.enableBrowserWindows) {
175
+ const btnNewBrowserWindow = document.createElement('div');
176
+ btnNewBrowserWindow.innerText = Localizer.getString('NewBrowserWindow');
177
+ result.push(btnNewBrowserWindow);
178
+
179
+ btnNewBrowserWindow.onclick = () => {
180
+ panelContainer.undockToBrowserDialog();
181
+ panelContainer.closeContextMenu();
182
+ };
183
+ }
184
+
185
+ return result;
186
+ };
187
+
188
+ oncontextMenuClicked(e: MouseEvent) {
189
+ e.preventDefault();
190
+
191
+ if (!this._ctxMenu && PanelContainer.createContextMenuContentCallback) {
192
+ const menuItems = PanelContainer.createContextMenuContentCallback(this);
193
+
194
+ if (menuItems.length == 0)
195
+ return;
196
+
197
+
198
+ this._ctxMenu = document.createElement('div');
199
+ this._ctxMenu.className = 'dockspab-tab-handle-context-menu';
200
+ this._ctxMenu.append(...menuItems);
201
+ this._ctxMenu.style.left = e.pageX + 'px';
202
+ this._ctxMenu.style.top = e.pageY + 'px';
203
+ document.body.appendChild(this._ctxMenu);
204
+ window.addEventListener('mouseup', this.windowsContextMenuClose);
205
+ } else
206
+ this.closeContextMenu();
207
+ }
208
+
209
+ closeContextMenu() {
210
+ if (this._ctxMenu) {
211
+ document.body.removeChild(this._ctxMenu);
212
+ delete this._ctxMenu;
213
+ window.removeEventListener('mouseup', this.windowsContextMenuClose);
214
+ }
215
+ }
216
+
217
+ windowsContextMenuClose(e: Event) {
218
+ const cp = e.composedPath();
219
+ for (const i in cp) {
220
+ const el = cp[i];
221
+ if (el == this._ctxMenu)
222
+ return;
223
+ }
224
+ this.closeContextMenu();
225
+ }
226
+
227
+ canUndock(state: boolean) {
228
+ this._canUndock = state;
229
+ this.undockInitiator.enabled = state;
230
+ this.eventListeners.forEach((listener) => {
231
+ if (listener.onDockEnabled)
232
+ listener.onDockEnabled({self: this, state: state});
233
+ });
234
+ }
235
+
236
+ addListener(listener) {
237
+ this.eventListeners.push(listener);
238
+ }
239
+
240
+ removeListener(listener) {
241
+ this.eventListeners.splice(this.eventListeners.indexOf(listener), 1);
242
+ }
243
+
244
+ get floatingDialog(): Dialog {
245
+ return this._floatingDialog;
246
+ }
247
+ set floatingDialog(value: Dialog) {
248
+ this._floatingDialog = value;
249
+ const canUndock = (this._floatingDialog === undefined);
250
+ this.undockInitiator.enabled = canUndock;
251
+ }
252
+
253
+ static async loadFromState(state: IState, dockManager: DockManager) {
254
+ let elementContent: HTMLElement;
255
+ let title: string;
256
+ if (!dockManager.getElementCallback) {
257
+ const elementName = state.element;
258
+ elementContent = document.getElementById(elementName);
259
+ } else {
260
+ const res = await dockManager.getElementCallback(state);
261
+ elementContent = res.element;
262
+ title = res.title;
263
+ }
264
+
265
+ if (elementContent === null)
266
+ return null;
267
+
268
+ const ret = new PanelContainer(elementContent, dockManager, title);
269
+ ret.loadState(state);
270
+ return ret;
271
+ }
272
+
273
+ saveState(state: IState) {
274
+ state.panelIcon = this.icon;
275
+ state.element = this.elementContent.tagName === 'SLOT' ?
276
+ //@ts-ignore
277
+ this.elementContent.assignedElements()[0].getAttribute('dock-spawn-title') :
278
+ this.elementContent.id;
279
+ state.width = this.width;
280
+ state.height = this.height;
281
+ state.canUndock = this._canUndock;
282
+ state.hideCloseButton = this._hideCloseButton;
283
+ state.panelType = this.panelType;
284
+ }
285
+
286
+ loadState(state: IState) {
287
+ this.width = state.width;
288
+ this.height = state.height;
289
+ this.state = {width: state.width, height: state.height};
290
+ this.canUndock(state.canUndock);
291
+ this.hideCloseButton(state.hideCloseButton);
292
+ this.panelType = state.panelType;
293
+ this.icon = state.panelIcon;
294
+ this._updateTitle();
295
+ }
296
+
297
+ setActiveChild(/*child*/) {
298
+ }
299
+
300
+ get containerElement() {
301
+ return this.elementPanel;
302
+ }
303
+
304
+ grayOut(show: boolean) {
305
+ if (!show && this._grayOut) {
306
+ this.elementContentWrapper.removeChild(this._grayOut);
307
+ this.elementButtonClose.style.display = this._hideCloseButton ? 'none' : 'block';
308
+ this._grayOut = null;
309
+ if (!this._hideCloseButton) {
310
+ this.eventListeners.forEach((listener) => {
311
+ if (listener.onHideCloseButton)
312
+ listener.onHideCloseButton({self: this, state: this._hideCloseButton});
313
+ });
314
+ }
315
+ } else if (show && !this._grayOut) {
316
+ this._grayOut = document.createElement('div');
317
+ this._grayOut.className = 'panel-grayout';
318
+ this.elementButtonClose.style.display = 'none';
319
+ this.elementContentWrapper.appendChild(this._grayOut);
320
+ this.eventListeners.forEach((listener) => {
321
+ if (listener.onHideCloseButton)
322
+ listener.onHideCloseButton({self: this, state: true});
323
+ });
324
+ }
325
+ }
326
+
327
+ onMouseDown() {
328
+ this.dockManager.activePanel = this;
329
+ }
330
+
331
+ hideCloseButton(state: boolean) {
332
+ this._hideCloseButton = state;
333
+ this.elementButtonClose.style.display = state ? 'none' : 'block';
334
+ this.eventListeners.forEach((listener) => {
335
+ if (listener.onHideCloseButton)
336
+ listener.onHideCloseButton({self: this, state: state});
337
+ });
338
+ }
339
+
340
+ destroy() {
341
+ if (this.mouseDownHandler) {
342
+ this.mouseDownHandler.cancel();
343
+ delete this.mouseDownHandler;
344
+ }
345
+ if (this.touchDownHandler) {
346
+ this.touchDownHandler.cancel();
347
+ delete this.touchDownHandler;
348
+ }
349
+ if (this.contextMenuHandler)
350
+ this.contextMenuHandler.cancel();
351
+
352
+
353
+ Utils.removeNode(this.elementPanel);
354
+ if (this.closeButtonClickedHandler) {
355
+ this.closeButtonClickedHandler.cancel();
356
+ delete this.closeButtonClickedHandler;
357
+ }
358
+ if (this.closeButtonTouchedHandler) {
359
+ this.closeButtonTouchedHandler.cancel();
360
+ delete this.closeButtonTouchedHandler;
361
+ }
362
+ }
363
+
364
+ /**
365
+ * Undocks the panel and and converts it to a dialog box
366
+ */
367
+ performUndockToDialog(e, dragOffset: Point) {
368
+ this.isDialog = true;
369
+ this.undockInitiator.enabled = false;
370
+ this.elementContentWrapper.style.display = 'block';
371
+ this.elementPanel.style.position = '';
372
+ return this.dockManager.requestUndockToDialog(this, e, dragOffset);
373
+ }
374
+
375
+ /**
376
+ * Closes the panel
377
+ */
378
+ private performClose() {
379
+ this.isDialog = true;
380
+ this.undockInitiator.enabled = false;
381
+ this.elementContentWrapper.style.display = 'block';
382
+ this.elementContentContainer.style.display = 'none';
383
+ this.elementPanel.style.position = '';
384
+ this.dockManager.requestClose(this);
385
+ }
386
+
387
+ /**
388
+ * Undocks the container and from the layout hierarchy
389
+ * The container would be removed from the DOM
390
+ */
391
+ performUndock() {
392
+ this.undockInitiator.enabled = false;
393
+ this.dockManager.requestUndock(this);
394
+ };
395
+
396
+ prepareForDocking() {
397
+ this.isDialog = false;
398
+ this.undockInitiator.enabled = this._canUndock;
399
+ if (this.elementContentContainer.parentElement != this.dockManager.config.dialogRootElement)
400
+ this.dockManager.config.dialogRootElement.appendChild(this.elementContentContainer);
401
+ }
402
+
403
+ get width(): number {
404
+ return this._cachedWidth;
405
+ }
406
+ set width(value: number) {
407
+ if (value !== this._cachedWidth) {
408
+ this._cachedWidth = value;
409
+ this.elementPanel.style.width = value + 'px';
410
+ }
411
+ }
412
+
413
+ get height(): number {
414
+ return this._cachedHeight;
415
+ }
416
+ set height(value: number) {
417
+ if (value !== this._cachedHeight) {
418
+ this._cachedHeight = value;
419
+ this.elementPanel.style.height = value + 'px';
420
+ }
421
+ }
422
+
423
+ get resolvedElementContent(): HTMLElement {
424
+ if (this._resolvedElementContent)
425
+ return this._resolvedElementContent;
426
+ this._resolvedElementContent = this.elementContent;
427
+ if (this.elementContent instanceof HTMLSlotElement)
428
+ this._resolvedElementContent = <HTMLElement> this.elementContent.assignedElements()?.[0];
429
+
430
+ return this._resolvedElementContent;
431
+ }
432
+
433
+ private panelDocked() {
434
+ if (this.elementContent.hidden)
435
+ this.elementContent.hidden = false;
436
+ if (this.elementContentContainer.parentElement !== this.dockManager.config.dialogRootElement)
437
+ this.dockManager.config.dialogRootElement.appendChild(this.elementContentContainer);
438
+ }
439
+
440
+ resize(width: number, height: number) {
441
+ // if (this._cachedWidth === width && this._cachedHeight === height)
442
+ // {
443
+ // // Already in the desired size
444
+ // return;
445
+ // }
446
+ this.panelDocked();
447
+ this.setVisible(true);
448
+ this._setPanelDimensions(width, height);
449
+ this._cachedWidth = width;
450
+ this._cachedHeight = height;
451
+ try {
452
+ if (this.elementContent != undefined && (typeof this.elementContent.resizeHandler == 'function'))
453
+ this.elementContent.resizeHandler(width, height - this.elementTitle.clientHeight);
454
+ } catch (err) {
455
+ console.log('error calling resizeHandler:', err, ' elt:', this.elementContent);
456
+ }
457
+ }
458
+
459
+ _setPanelDimensions(width: number, height: number) {
460
+ this.elementTitle.style.width = width + 'px';
461
+ this.elementContentHost.style.width = width + 'px';
462
+ this.elementContentContainer.style.width = width + 'px';
463
+ this.elementPanel.style.width = width + 'px';
464
+
465
+ const titleBarHeight = this.elementTitle.clientHeight;
466
+ const contentHeight = height - titleBarHeight;
467
+ this.elementContentHost.style.height = contentHeight + 'px';
468
+ this.elementContentContainer.style.height = contentHeight + 'px';
469
+ this.elementPanel.style.height = height + 'px';
470
+
471
+ //if (this.elementContentContainer.parentElement != this.dockManager.config.dialogRootElement)
472
+ // this.dockManager.config.dialogRootElement.appendChild(this.elementContentContainer);
473
+ const rect = this.elementContentWrapper.getBoundingClientRect();
474
+ const rootRect = this.dockManager.config.dialogRootElement.getBoundingClientRect();
475
+ this.elementContentContainer.style.left = (rect.x - rootRect.x) + 'px';
476
+ this.elementContentContainer.style.top = (rect.y - rootRect.y) + 'px';
477
+ this.elementContentContainer.style.width = rect.width + 'px';
478
+ this.elementContentContainer.style.height = rect.height + 'px';
479
+ }
480
+
481
+ setDialogPosition(x: number, y: number) {
482
+ this.elementContentContainer.style.left = x + 'px';
483
+ //todo, 25px if it is a dialog, is it always 25px? where do we know...
484
+ this.elementContentContainer.style.top = (y + this.elementTitle.clientHeight) + 'px';
485
+ }
486
+
487
+ setVisible(isVisible: boolean) {
488
+ this.elementContentContainer.style.display = isVisible ? 'block' : 'none';
489
+ }
490
+
491
+ setTitle(title: string) {
492
+ this.title = title;
493
+ this._updateTitle();
494
+ if (this.onTitleChanged)
495
+ this.onTitleChanged(this, title);
496
+ }
497
+
498
+ setTitleIcon(icon: string) {
499
+ this.icon = icon;
500
+ this._updateTitle();
501
+ if (this.onTitleChanged)
502
+ this.onTitleChanged(this, this.title);
503
+ }
504
+
505
+ setHasChanges(changes: boolean) {
506
+ this.hasChanges = changes;
507
+ this._updateTitle();
508
+ if (changes)
509
+ this.elementTitleText.classList.add('panel-has-changes');
510
+ else
511
+ this.elementTitleText.classList.remove('panel-has-changes');
512
+
513
+ if (this.onTitleChanged)
514
+ this.onTitleChanged(this, this.title);
515
+ }
516
+
517
+ setCloseIconTemplate(closeIconTemplate: string) {
518
+ this.elementButtonClose.innerHTML = closeIconTemplate;
519
+ }
520
+
521
+ _updateTitle() {
522
+ if (!!this.icon) {
523
+ this.elementTitleText.innerHTML = `<i class="grok-icon fal fa-${this.icon}" style="margin-right: 3px"></i><span>${this.title}</span>`;
524
+ return;
525
+ }
526
+ this.elementTitleText.innerHTML = this.title;
527
+ }
528
+
529
+ getRawTitle() {
530
+ return this.elementTitleText.innerHTML;
531
+ }
532
+
533
+ performLayout(children: IDockContainer[], relayoutEvenIfEqual: boolean) {
534
+ }
535
+
536
+ onCloseButtonClicked(e: Event) {
537
+ e.preventDefault();
538
+ e.stopPropagation();
539
+ this.close();
540
+ }
541
+
542
+ undockToBrowserDialog() {
543
+ moveElementToNewBrowserWindow(this.resolvedElementContent, {
544
+ title: this.elementTitleText.textContent,
545
+ closeCallback: () => {
546
+ this.undockedToNewBrowserWindow = true;
547
+ this.closeInternal(false);
548
+ },
549
+ newWindowClosedCallback: () => {
550
+ this.undockedToNewBrowserWindow = false;
551
+ this.dockManager.notifyOnClosePanel(this);
552
+ },
553
+ focused: (e) => {
554
+ this.dockManager.activePanel = this;
555
+ },
556
+ blured: (e) => {
557
+ this.dockManager.activePanel = null;
558
+ },
559
+ });
560
+ }
561
+
562
+ async close() {
563
+ this.closeInternal(true);
564
+ }
565
+
566
+ private async closeInternal(runCallback: boolean) {
567
+ let close = true;
568
+
569
+ if (this.elementContentContainer.parentElement === this.dockManager.config.dialogRootElement) {
570
+ if (!runCallback)
571
+ close = true;
572
+ else if (this.closePanelContainerCallback)
573
+ close = await this.closePanelContainerCallback(this);
574
+ else if (this.dockManager.closePanelContainerCallback)
575
+ close = await this.dockManager.closePanelContainerCallback(this);
576
+
577
+ if (close) {
578
+ this.dockManager.config.dialogRootElement.removeChild(this.elementContentContainer);
579
+
580
+ if (this.isDialog) {
581
+ if (this.floatingDialog) {
582
+ //this.floatingDialog.hide();
583
+ this.floatingDialog.close(); // fires onClose notification
584
+ }
585
+ } else {
586
+ try {
587
+ this.dockManager.notifyOnClosePanel(this);
588
+ } catch (err) {
589
+ console.error(err);
590
+ }
591
+ this.performClose();
592
+ }
593
+ }
594
+ }
595
+ }
596
+ }