@perspective-dev/workspace 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +193 -0
- package/dist/cdn/perspective-workspace.js +45 -0
- package/dist/cdn/perspective-workspace.js.map +7 -0
- package/dist/css/pro-dark.css +1 -0
- package/dist/css/pro.css +1 -0
- package/dist/esm/perspective-workspace.d.ts +181 -0
- package/dist/esm/perspective-workspace.js +14 -0
- package/dist/esm/perspective-workspace.js.map +7 -0
- package/dist/esm/utils/custom_elements.d.ts +14 -0
- package/dist/esm/utils/observable_map.d.ts +9 -0
- package/dist/esm/workspace/commands.d.ts +3 -0
- package/dist/esm/workspace/dockpanel.d.ts +13 -0
- package/dist/esm/workspace/index.d.ts +1 -0
- package/dist/esm/workspace/menu.d.ts +11 -0
- package/dist/esm/workspace/tabbar.d.ts +25 -0
- package/dist/esm/workspace/tabbarrenderer.d.ts +19 -0
- package/dist/esm/workspace/widget.d.ts +27 -0
- package/dist/esm/workspace/workspace.d.ts +123 -0
- package/package.json +55 -0
- package/src/html/workspace.html +11 -0
- package/src/less/dockpanel.less +95 -0
- package/src/less/injected.less +14 -0
- package/src/less/menu.less +128 -0
- package/src/less/tabbar.less +366 -0
- package/src/less/viewer.less +86 -0
- package/src/less/widget.less +40 -0
- package/src/less/workspace.less +70 -0
- package/src/svg/bookmark-icon.svg +4 -0
- package/src/svg/drag-handle.svg +10 -0
- package/src/themes/pro-dark.less +139 -0
- package/src/themes/pro.less +93 -0
- package/src/ts/external.d.ts +21 -0
- package/src/ts/external.js +11 -0
- package/src/ts/perspective-workspace.ts +306 -0
- package/src/ts/utils/custom_elements.ts +95 -0
- package/src/ts/utils/observable_map.ts +39 -0
- package/src/ts/workspace/commands.ts +269 -0
- package/src/ts/workspace/dockpanel.ts +145 -0
- package/src/ts/workspace/index.ts +13 -0
- package/src/ts/workspace/menu.ts +213 -0
- package/src/ts/workspace/tabbar.ts +237 -0
- package/src/ts/workspace/tabbarrenderer.ts +91 -0
- package/src/ts/workspace/widget.ts +101 -0
- package/src/ts/workspace/workspace.ts +1056 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
|
|
13
|
+
import { ArrayExt } from "@lumino/algorithm";
|
|
14
|
+
import { ElementExt } from "@lumino/domutils";
|
|
15
|
+
import { TabBar } from "@lumino/widgets";
|
|
16
|
+
import { TabBarItems, PerspectiveTabBarRenderer } from "./tabbarrenderer";
|
|
17
|
+
import { VirtualDOM } from "@lumino/virtualdom";
|
|
18
|
+
import { CommandRegistry } from "@lumino/commands";
|
|
19
|
+
import { Menu } from "@lumino/widgets";
|
|
20
|
+
import { PerspectiveWorkspace } from "./workspace";
|
|
21
|
+
import { Message } from "@lumino/messaging";
|
|
22
|
+
import { Title } from "@lumino/widgets";
|
|
23
|
+
import { Signal } from "@lumino/signaling";
|
|
24
|
+
import { ReadonlyJSONObject, ReadonlyJSONValue } from "@lumino/coreutils";
|
|
25
|
+
import { WorkspaceMenu } from "./menu";
|
|
26
|
+
|
|
27
|
+
export class PerspectiveTabBar extends TabBar<any> {
|
|
28
|
+
_workspace: PerspectiveWorkspace;
|
|
29
|
+
__content_node__?: HTMLElement;
|
|
30
|
+
_menu?: Menu;
|
|
31
|
+
__titles: string[];
|
|
32
|
+
|
|
33
|
+
constructor(workspace: PerspectiveWorkspace, options = {}) {
|
|
34
|
+
super(options);
|
|
35
|
+
this._addEventListeners();
|
|
36
|
+
this.__content_node__ = undefined;
|
|
37
|
+
this._workspace = workspace;
|
|
38
|
+
this.__titles = [];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get private_titles(): Title<any>[] {
|
|
42
|
+
let titles: Title<any>[] = (this as any)._titles;
|
|
43
|
+
return titles;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
onUpdateRequest(msg: Message) {
|
|
47
|
+
// NOT INERT! This is a lumino bug fix.
|
|
48
|
+
// lumino/virtualdom keeps a weakmap on contentNode which is later
|
|
49
|
+
// reset - this causes the diff to double some elements. Memoizing
|
|
50
|
+
// prevent collection from the weakmap.
|
|
51
|
+
this.__content_node__ = this.contentNode;
|
|
52
|
+
this.node.style.contain = "";
|
|
53
|
+
|
|
54
|
+
// super.onUpdateRequest(msg);
|
|
55
|
+
|
|
56
|
+
let titles: Title<any>[] = (this as any)._titles;
|
|
57
|
+
let renderer = this.renderer;
|
|
58
|
+
let currentTitle = this.currentTitle!;
|
|
59
|
+
|
|
60
|
+
// Another hack. `TabBar` selects by index and I don't want to fork this
|
|
61
|
+
// logic, so insert empty divs until the indices match.
|
|
62
|
+
let content = new Array();
|
|
63
|
+
for (let i = 0, n = titles.length; i < n; ++i) {
|
|
64
|
+
let title = titles[i];
|
|
65
|
+
let current = title === currentTitle;
|
|
66
|
+
let otherTitles = titles.filter((x) => x !== currentTitle);
|
|
67
|
+
let onClick;
|
|
68
|
+
if (otherTitles.length > 0) {
|
|
69
|
+
onClick = this.onClick.bind(this, otherTitles, i);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (current) {
|
|
73
|
+
content[i] = (
|
|
74
|
+
renderer as unknown as PerspectiveTabBarRenderer
|
|
75
|
+
).renderTab(
|
|
76
|
+
{
|
|
77
|
+
title,
|
|
78
|
+
zIndex: titles.length + 1,
|
|
79
|
+
current,
|
|
80
|
+
} as TabBar.IRenderData<any>,
|
|
81
|
+
onClick,
|
|
82
|
+
);
|
|
83
|
+
} else {
|
|
84
|
+
content[i] = (
|
|
85
|
+
renderer as unknown as PerspectiveTabBarRenderer
|
|
86
|
+
).renderInert();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
VirtualDOM.render(content, this.contentNode);
|
|
91
|
+
this._check_shade();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
onClick(otherTitles: Title<any>[], index: number, event: MouseEvent) {
|
|
95
|
+
const commands = new CommandRegistry();
|
|
96
|
+
this._menu = new WorkspaceMenu(
|
|
97
|
+
this._workspace.menu_elem.shadowRoot!,
|
|
98
|
+
this._workspace.element,
|
|
99
|
+
{
|
|
100
|
+
commands,
|
|
101
|
+
},
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
this._menu.addClass("perspective-workspace-menu");
|
|
105
|
+
this._menu.dataset.minwidth = this.__titles[index];
|
|
106
|
+
for (const title of otherTitles) {
|
|
107
|
+
this._menu.addItem({
|
|
108
|
+
command: "tabbar:switch",
|
|
109
|
+
args: { title } as unknown as ReadonlyJSONObject,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
commands.addCommand("tabbar:switch", {
|
|
114
|
+
execute: async ({ title }) => {
|
|
115
|
+
const psp_title = title as any as Title<any>;
|
|
116
|
+
const index = this.__titles.findIndex((t) => t === title);
|
|
117
|
+
this.currentTitle = psp_title;
|
|
118
|
+
(
|
|
119
|
+
this.tabActivateRequested as unknown as Signal<
|
|
120
|
+
TabBar<any>,
|
|
121
|
+
TabBar.ITabActivateRequestedArgs<any>
|
|
122
|
+
>
|
|
123
|
+
).emit({
|
|
124
|
+
index,
|
|
125
|
+
title: psp_title,
|
|
126
|
+
});
|
|
127
|
+
},
|
|
128
|
+
label: ({ title }) => {
|
|
129
|
+
const psp_title = title as any as Title<any>;
|
|
130
|
+
return psp_title.label || "untitled";
|
|
131
|
+
},
|
|
132
|
+
mnemonic: 0,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
const box = (event.target as HTMLElement).getBoundingClientRect();
|
|
136
|
+
const outer_box = this._workspace.element.getBoundingClientRect();
|
|
137
|
+
this._menu.open(box.x - outer_box.x, box.y + box.height - outer_box.y);
|
|
138
|
+
this._menu.aboutToClose.connect(() => {
|
|
139
|
+
this._menu = undefined;
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
event.preventDefault();
|
|
143
|
+
event.stopPropagation();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
_check_shade() {
|
|
147
|
+
if (
|
|
148
|
+
Array.from(this.contentNode.children).filter(
|
|
149
|
+
(x) =>
|
|
150
|
+
x.classList.contains("settings_open") &&
|
|
151
|
+
x.classList.contains("lm-mod-current"),
|
|
152
|
+
).length > 0
|
|
153
|
+
) {
|
|
154
|
+
this.contentNode.classList.add("inactive-blur");
|
|
155
|
+
} else {
|
|
156
|
+
this.contentNode.classList.remove("inactive-blur");
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
handleEvent(event: MouseEvent) {
|
|
161
|
+
this._menu?.close();
|
|
162
|
+
this.retargetEvent(event);
|
|
163
|
+
switch (event.type) {
|
|
164
|
+
case "contextmenu":
|
|
165
|
+
const widget = this.currentTitle?.owner;
|
|
166
|
+
let parent = widget.parent;
|
|
167
|
+
|
|
168
|
+
// TODO There is probably a better way to find the workspace
|
|
169
|
+
// relative to a widget command
|
|
170
|
+
while (parent && !(parent instanceof PerspectiveWorkspace)) {
|
|
171
|
+
parent = parent.parent;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
(parent as unknown as PerspectiveWorkspace).showContextMenu(
|
|
175
|
+
widget,
|
|
176
|
+
event,
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
if (!event.shiftKey) {
|
|
180
|
+
event.preventDefault();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
break;
|
|
184
|
+
case "mousedown":
|
|
185
|
+
if ((event.target as HTMLElement).id === TabBarItems.Label) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
break;
|
|
189
|
+
case "pointerdown":
|
|
190
|
+
if ((event.target as HTMLElement).id === TabBarItems.Label) {
|
|
191
|
+
const tabs = this.contentNode.children;
|
|
192
|
+
|
|
193
|
+
// Find the index of the released tab.
|
|
194
|
+
const index = ArrayExt.findFirstIndex(tabs, (tab) => {
|
|
195
|
+
return ElementExt.hitTest(
|
|
196
|
+
tab,
|
|
197
|
+
event.clientX,
|
|
198
|
+
event.clientY,
|
|
199
|
+
);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
if (index < 0) {
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const title = this.titles[index];
|
|
207
|
+
this._workspace._maximize(title.owner);
|
|
208
|
+
requestAnimationFrame(() =>
|
|
209
|
+
title.owner.viewer.toggleConfig(),
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
super.handleEvent(event);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Shadow dom targets events at the host, not the clicked element, which
|
|
221
|
+
* Lumino dislikes. This makes the event look like it is not crossing
|
|
222
|
+
* the ShadowDom boundary.
|
|
223
|
+
*
|
|
224
|
+
*/
|
|
225
|
+
retargetEvent(event: MouseEvent) {
|
|
226
|
+
Object.defineProperty(event, "target", {
|
|
227
|
+
value: event.composedPath()[0],
|
|
228
|
+
enumerable: true,
|
|
229
|
+
});
|
|
230
|
+
return event;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
_addEventListeners() {
|
|
234
|
+
this.node.addEventListener("dblclick", this);
|
|
235
|
+
this.node.addEventListener("contextmenu", this);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
|
|
13
|
+
import { h } from "@lumino/virtualdom";
|
|
14
|
+
import { TabBar } from "@lumino/widgets";
|
|
15
|
+
|
|
16
|
+
export const TabBarItems = {
|
|
17
|
+
Config: "config",
|
|
18
|
+
Label: "label",
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const DEFAULT_TITLE = "untitled";
|
|
22
|
+
|
|
23
|
+
export class PerspectiveTabBarRenderer extends TabBar.Renderer {
|
|
24
|
+
maximized: boolean;
|
|
25
|
+
|
|
26
|
+
constructor(maximized: boolean) {
|
|
27
|
+
super();
|
|
28
|
+
this.maximized = maximized;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
renderLabel(data: { title: { label?: string } }) {
|
|
32
|
+
return h.span(
|
|
33
|
+
{
|
|
34
|
+
className: "lm-TabBar-tabLabel",
|
|
35
|
+
id: TabBarItems.Label,
|
|
36
|
+
},
|
|
37
|
+
data.title.label || DEFAULT_TITLE,
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
renderInert() {
|
|
42
|
+
return h.div();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
renderTab(
|
|
46
|
+
data: TabBar.IRenderData<any>,
|
|
47
|
+
onclick?: (this: HTMLElement, event: MouseEvent) => any,
|
|
48
|
+
) {
|
|
49
|
+
const title = data.title.caption;
|
|
50
|
+
const key = this.createTabKey(data);
|
|
51
|
+
const style = this.createTabStyle(data);
|
|
52
|
+
let className = this.createTabClass(data);
|
|
53
|
+
const dataset = this.createTabDataset(data);
|
|
54
|
+
const more: h.Child[] = [];
|
|
55
|
+
if (onclick) {
|
|
56
|
+
more.push(
|
|
57
|
+
h.div(
|
|
58
|
+
{ onclick, className: "bookmarks-button" },
|
|
59
|
+
h.div({ className: "bookmarks" }),
|
|
60
|
+
),
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return h.li(
|
|
65
|
+
{ key, className, title, style, dataset },
|
|
66
|
+
this.renderDragHandle(),
|
|
67
|
+
...more,
|
|
68
|
+
this.renderLabel(data),
|
|
69
|
+
this.renderCloseIcon(),
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
renderDragHandle() {
|
|
74
|
+
return h.div({
|
|
75
|
+
className: "drag-handle",
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// renderConfigIcon() {
|
|
80
|
+
// return h.div({
|
|
81
|
+
// className: "lm-TabBar-tabConfigIcon",
|
|
82
|
+
// id: TabBarItems.Config,
|
|
83
|
+
// });
|
|
84
|
+
// }
|
|
85
|
+
|
|
86
|
+
renderCloseIcon() {
|
|
87
|
+
return h.div({
|
|
88
|
+
className: "lm-TabBar-tabCloseIcon" + " p-TabBar-tabCloseIcon",
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
|
|
13
|
+
import { Widget } from "@lumino/widgets";
|
|
14
|
+
import { Message } from "@lumino/messaging";
|
|
15
|
+
|
|
16
|
+
import type * as psp_viewer from "@perspective-dev/viewer";
|
|
17
|
+
import type * as psp from "@perspective-dev/client";
|
|
18
|
+
|
|
19
|
+
interface IPerspectiveViewerWidgetOptions {
|
|
20
|
+
node: HTMLElement;
|
|
21
|
+
viewer: psp_viewer.HTMLPerspectiveViewerElement;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class PerspectiveViewerWidget extends Widget {
|
|
25
|
+
viewer: psp_viewer.HTMLPerspectiveViewerElement;
|
|
26
|
+
_title: string;
|
|
27
|
+
_is_table_loaded: boolean;
|
|
28
|
+
_is_pivoted: boolean;
|
|
29
|
+
_restore_config?: () => Promise<void>;
|
|
30
|
+
task?: Promise<void>;
|
|
31
|
+
|
|
32
|
+
constructor({ viewer, node }: IPerspectiveViewerWidgetOptions) {
|
|
33
|
+
super({ node });
|
|
34
|
+
this.viewer = viewer;
|
|
35
|
+
this._title = "";
|
|
36
|
+
this._is_table_loaded = false;
|
|
37
|
+
this._is_pivoted = false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
get name(): string {
|
|
41
|
+
return this._title;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
toggleConfig(): Promise<void> {
|
|
45
|
+
return this.viewer.toggleConfig();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async load(table: psp.Table | Promise<psp.Table>) {
|
|
49
|
+
this._is_table_loaded = true;
|
|
50
|
+
let promises = [this.viewer.load(table)];
|
|
51
|
+
if (this._restore_config) {
|
|
52
|
+
promises.push(this._restore_config());
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
await Promise.all(promises);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
restore(
|
|
59
|
+
config: psp_viewer.ViewerConfigUpdate & {
|
|
60
|
+
table: string;
|
|
61
|
+
},
|
|
62
|
+
) {
|
|
63
|
+
const { table, ...viewerConfig } = config;
|
|
64
|
+
this._title = config.title as string;
|
|
65
|
+
this.title.label = config.title as string;
|
|
66
|
+
if (table) {
|
|
67
|
+
this.viewer.setAttribute("table", table);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const restore_config = () => this.viewer.restore({ ...viewerConfig });
|
|
71
|
+
if (this._is_table_loaded) {
|
|
72
|
+
return restore_config();
|
|
73
|
+
} else {
|
|
74
|
+
this._restore_config = restore_config;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async save() {
|
|
79
|
+
let config = {
|
|
80
|
+
...(await this.viewer.save()),
|
|
81
|
+
table: this.viewer.getAttribute("table"),
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
delete config["settings"];
|
|
85
|
+
return config;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
removeClass(name: string) {
|
|
89
|
+
super.removeClass(name);
|
|
90
|
+
this.viewer && this.viewer.classList.remove(name);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async onCloseRequest(msg: Message) {
|
|
94
|
+
super.onCloseRequest(msg);
|
|
95
|
+
if (this.viewer.parentElement) {
|
|
96
|
+
this.viewer.parentElement.removeChild(this.viewer);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
await this.viewer.delete();
|
|
100
|
+
}
|
|
101
|
+
}
|