@perspective-dev/workspace 4.0.1 → 4.1.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.
- package/dist/cdn/perspective-workspace.js +7 -7
- package/dist/cdn/perspective-workspace.js.map +4 -4
- package/dist/css/pro-dark.css +1 -1
- package/dist/css/pro.css +1 -1
- package/dist/esm/extensions.d.ts +23 -0
- package/dist/esm/perspective-workspace.d.ts +10 -63
- package/dist/esm/perspective-workspace.js +3 -3
- package/dist/esm/perspective-workspace.js.map +4 -4
- package/dist/esm/workspace/dockpanel.d.ts +3 -2
- package/dist/esm/workspace/tabbarrenderer.d.ts +0 -2
- package/dist/esm/workspace/widget.d.ts +11 -6
- package/dist/esm/workspace/workspace.d.ts +43 -36
- package/package.json +2 -2
- package/src/less/dockpanel.less +11 -1
- package/src/less/tabbar.less +40 -17
- package/src/less/viewer.less +26 -1
- package/src/less/widget.less +3 -1
- package/src/less/workspace.less +1 -1
- package/src/svg/bookmark-icon.svg +2 -2
- package/src/themes/pro-dark.less +3 -2
- package/src/themes/pro.less +11 -2
- package/src/ts/extensions.ts +51 -0
- package/src/ts/external.js +3 -0
- package/src/ts/perspective-workspace.ts +62 -102
- package/src/ts/workspace/commands.ts +23 -21
- package/src/ts/workspace/dockpanel.ts +23 -12
- package/src/ts/workspace/tabbar.ts +7 -1
- package/src/ts/workspace/tabbarrenderer.ts +8 -25
- package/src/ts/workspace/widget.ts +38 -29
- package/src/ts/workspace/workspace.ts +477 -238
|
@@ -12,22 +12,21 @@
|
|
|
12
12
|
|
|
13
13
|
import { MessageLoop } from "@lumino/messaging";
|
|
14
14
|
import { Widget } from "@lumino/widgets";
|
|
15
|
-
import { HTMLPerspectiveViewerElement } from "@perspective-dev/viewer";
|
|
15
|
+
import type { HTMLPerspectiveViewerElement } from "@perspective-dev/viewer";
|
|
16
16
|
import type * as psp from "@perspective-dev/client";
|
|
17
|
+
import type * as psp_viewer from "@perspective-dev/viewer";
|
|
18
|
+
import * as msg from "@lumino/messaging";
|
|
17
19
|
|
|
18
|
-
export { PerspectiveWorkspace } from "./workspace";
|
|
20
|
+
export { PerspectiveWorkspace, addViewer, genId } from "./workspace";
|
|
19
21
|
export { PerspectiveViewerWidget } from "./workspace/widget";
|
|
20
|
-
|
|
21
|
-
import "./
|
|
22
|
-
import {
|
|
23
|
-
PerspectiveWorkspace,
|
|
24
|
-
PerspectiveWorkspaceConfig,
|
|
25
|
-
ViewerConfigUpdateExt,
|
|
26
|
-
} from "./workspace";
|
|
22
|
+
export * from "./extensions";
|
|
23
|
+
import { PerspectiveWorkspace, PerspectiveWorkspaceConfig } from "./workspace";
|
|
27
24
|
import { bindTemplate, CustomElementProto } from "./utils/custom_elements";
|
|
28
25
|
import style from "../../build/css/workspace.css";
|
|
29
26
|
import template from "../html/workspace.html";
|
|
30
27
|
|
|
28
|
+
export { PerspectiveWorkspaceConfig };
|
|
29
|
+
|
|
31
30
|
/**
|
|
32
31
|
* A Custom Element for coordinating a set of `<perspective-viewer>` light DOM
|
|
33
32
|
* children. `<perspective-workspace>` is built on Lumino.js to allow a more
|
|
@@ -46,24 +45,13 @@ import template from "../html/workspace.html";
|
|
|
46
45
|
* express your initial view simply:
|
|
47
46
|
*
|
|
48
47
|
* ```html
|
|
49
|
-
* <perspective-workspace>
|
|
50
|
-
* <perspective-viewer
|
|
51
|
-
* name="View One"
|
|
52
|
-
* table="superstore">
|
|
53
|
-
* </perspective-viewer>
|
|
54
|
-
* <perspective-viewer
|
|
55
|
-
* name="View Two"
|
|
56
|
-
* table="superstore">
|
|
57
|
-
* </perspective-viewer>
|
|
58
|
-
* </perspective-workspace>
|
|
48
|
+
* <perspective-workspace></perspective-workspace>
|
|
59
49
|
* ```
|
|
60
50
|
*
|
|
61
51
|
* You can also use the DOM API in Javascript:
|
|
62
52
|
*
|
|
63
53
|
* ```javascript
|
|
64
54
|
* const workspace = document.createElement("perspective-workspace");
|
|
65
|
-
* const viewer = document.createElement("perspective-viewer");
|
|
66
|
-
* workspace.appendChild(viewer);
|
|
67
55
|
* document.body.appendChild(workspace);
|
|
68
56
|
* ```
|
|
69
57
|
*
|
|
@@ -113,7 +101,7 @@ export class HTMLPerspectiveWorkspaceElement extends HTMLElement {
|
|
|
113
101
|
* const workspace = document.querySelector("perspective-workspace");
|
|
114
102
|
* localStorage.set("CONFIG", JSON.stringify(workspace.save()));
|
|
115
103
|
*/
|
|
116
|
-
save() {
|
|
104
|
+
save(): Promise<PerspectiveWorkspaceConfig> {
|
|
117
105
|
return this.workspace!.save();
|
|
118
106
|
}
|
|
119
107
|
|
|
@@ -137,15 +125,15 @@ export class HTMLPerspectiveWorkspaceElement extends HTMLElement {
|
|
|
137
125
|
* // Add `Table` separately.
|
|
138
126
|
* workspace.tables.set("superstore", await worker.table(data));
|
|
139
127
|
*/
|
|
140
|
-
async restore(layout: PerspectiveWorkspaceConfig
|
|
128
|
+
async restore(layout: PerspectiveWorkspaceConfig) {
|
|
141
129
|
await this.workspace!.restore(layout);
|
|
142
130
|
}
|
|
143
131
|
|
|
144
132
|
async clear() {
|
|
145
133
|
await this.restore({
|
|
146
134
|
sizes: [],
|
|
147
|
-
master:
|
|
148
|
-
detail: {
|
|
135
|
+
master: undefined,
|
|
136
|
+
detail: { main: null },
|
|
149
137
|
viewers: {},
|
|
150
138
|
});
|
|
151
139
|
}
|
|
@@ -156,75 +144,41 @@ export class HTMLPerspectiveWorkspaceElement extends HTMLElement {
|
|
|
156
144
|
* are applied.
|
|
157
145
|
*/
|
|
158
146
|
async flush() {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
);
|
|
147
|
+
if (!this.workspace) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
msg.MessageLoop.flush();
|
|
152
|
+
await new Promise((x) => requestAnimationFrame(x));
|
|
153
|
+
await this.workspace._mutex.lock(async () => {
|
|
154
|
+
await Promise.all(
|
|
155
|
+
Array.from(this.querySelectorAll("perspective-viewer")).map(
|
|
156
|
+
(x) => {
|
|
157
|
+
const psp_widget = x as HTMLPerspectiveViewerElement;
|
|
158
|
+
return psp_widget
|
|
159
|
+
.flush()
|
|
160
|
+
.then(() => psp_widget.flush());
|
|
161
|
+
},
|
|
162
|
+
),
|
|
163
|
+
);
|
|
164
|
+
});
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
/**
|
|
168
168
|
* Add a new viewer to the workspace for a given `ViewerConfigUpdateExt`.
|
|
169
169
|
* @param config
|
|
170
170
|
*/
|
|
171
|
-
async addViewer(config:
|
|
172
|
-
this.workspace!.addViewer(config);
|
|
173
|
-
await this.flush();
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Add a new `Table` to the workspace, so that it can be bound by viewers.
|
|
178
|
-
* Each `Table` is identified by a unique `name`.
|
|
179
|
-
*/
|
|
180
|
-
async addTable(name: string, table: Promise<psp.Table>) {
|
|
181
|
-
this.workspace!.addTable(name, table);
|
|
171
|
+
async addViewer(config: psp_viewer.ViewerConfigUpdate) {
|
|
172
|
+
await this.workspace!.addViewer(config);
|
|
182
173
|
await this.flush();
|
|
183
174
|
}
|
|
184
175
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
return this.workspace!.getTable(name);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Replace a `Table` by name. As `Table` doe snot guarantee the same
|
|
196
|
-
* structure, this will wipe the viewer's state.
|
|
197
|
-
* @param name
|
|
198
|
-
* @param table
|
|
199
|
-
*/
|
|
200
|
-
async replaceTable(name: string, table: Promise<psp.Table>) {
|
|
201
|
-
this.workspace!.replaceTable(name, table);
|
|
202
|
-
await this.flush();
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Remove a `Table` by name.
|
|
207
|
-
* @param name
|
|
208
|
-
* @returns
|
|
209
|
-
*/
|
|
210
|
-
removeTable(name: string) {
|
|
211
|
-
return this.workspace!.removeTable(name);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* A `Map()` of `perspective.Table()` by name. The names set here will auto
|
|
216
|
-
* wire any child `perspective-viewer` elements in this Workspace's subtree,
|
|
217
|
-
* by looking up their respective `table` attribute.
|
|
218
|
-
*
|
|
219
|
-
* Calling methods on this `Map()` may have side-effects, as
|
|
220
|
-
* `PerspectiveViewerHTMLElement.load()` is called when a new `Table()` is
|
|
221
|
-
* set with a name matching an existing child `perspective-viewer`.
|
|
222
|
-
*
|
|
223
|
-
* @readonly
|
|
224
|
-
* @memberof HTMLPerspectiveWorkspaceElement
|
|
225
|
-
*/
|
|
226
|
-
get tables() {
|
|
227
|
-
return this.workspace!.tables;
|
|
176
|
+
async load(client: psp.Client | Promise<psp.Client>) {
|
|
177
|
+
if (this.workspace) {
|
|
178
|
+
this.workspace.client.push(await client);
|
|
179
|
+
} else {
|
|
180
|
+
throw new Error("Workspace not mounted");
|
|
181
|
+
}
|
|
228
182
|
}
|
|
229
183
|
|
|
230
184
|
/**
|
|
@@ -269,27 +223,33 @@ export class HTMLPerspectiveWorkspaceElement extends HTMLElement {
|
|
|
269
223
|
*/
|
|
270
224
|
|
|
271
225
|
private _light_dom_changed() {
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
226
|
+
if (!this.workspace) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
275
229
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
230
|
+
this.workspace._mutex.lock(async () => {
|
|
231
|
+
const viewers = Array.from(
|
|
232
|
+
this.childNodes,
|
|
233
|
+
) as HTMLPerspectiveViewerElement[];
|
|
280
234
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
235
|
+
for (const viewer of viewers) {
|
|
236
|
+
if (viewer.nodeType !== Node.ELEMENT_NODE) {
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
285
239
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
240
|
+
if (viewer.tagName !== "PERSPECTIVE-VIEWER") {
|
|
241
|
+
console.warn("Not a <perspective-viewer>");
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
let _task = this.workspace!.update_widget_for_viewer(
|
|
246
|
+
viewer as HTMLPerspectiveViewerElement,
|
|
247
|
+
);
|
|
248
|
+
}
|
|
290
249
|
|
|
291
|
-
|
|
292
|
-
|
|
250
|
+
this.workspace!.remove_unslotted_widgets(viewers);
|
|
251
|
+
this.workspace!.update_details_panel(viewers);
|
|
252
|
+
});
|
|
293
253
|
}
|
|
294
254
|
|
|
295
255
|
private _register_light_dom_listener() {
|
|
@@ -11,12 +11,12 @@
|
|
|
11
11
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
12
|
|
|
13
13
|
import { CommandRegistry } from "@lumino/commands";
|
|
14
|
-
import {
|
|
14
|
+
import { Widget } from "@lumino/widgets";
|
|
15
15
|
import { Signal } from "@lumino/signaling";
|
|
16
16
|
|
|
17
17
|
import type {
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
HTMLPerspectiveViewerCopyMenuElement,
|
|
19
|
+
HTMLPerspectiveViewerExportMenuElement,
|
|
20
20
|
} from "@perspective-dev/viewer";
|
|
21
21
|
|
|
22
22
|
import type { PerspectiveWorkspace } from "./workspace";
|
|
@@ -32,14 +32,14 @@ export const createCommands = (
|
|
|
32
32
|
execute: async (args) => {
|
|
33
33
|
const menu = document.createElement(
|
|
34
34
|
"perspective-export-menu",
|
|
35
|
-
) as unknown as
|
|
35
|
+
) as unknown as HTMLPerspectiveViewerExportMenuElement;
|
|
36
36
|
|
|
37
37
|
workspace.apply_indicator_theme();
|
|
38
38
|
const widget = workspace.getWidgetByName(
|
|
39
39
|
args.widget_name as string,
|
|
40
40
|
)!;
|
|
41
41
|
|
|
42
|
-
menu.
|
|
42
|
+
menu.__set_model(widget.viewer.__get_model());
|
|
43
43
|
menu.open(indicator);
|
|
44
44
|
workspace.get_context_menu()?.init_overlay?.();
|
|
45
45
|
menu.addEventListener("blur", () => {
|
|
@@ -74,13 +74,13 @@ export const createCommands = (
|
|
|
74
74
|
execute: async (args) => {
|
|
75
75
|
const menu = document.createElement(
|
|
76
76
|
"perspective-copy-menu",
|
|
77
|
-
) as
|
|
77
|
+
) as HTMLPerspectiveViewerCopyMenuElement;
|
|
78
78
|
|
|
79
79
|
workspace.apply_indicator_theme();
|
|
80
80
|
const widget = workspace.getWidgetByName(
|
|
81
81
|
args.widget_name as string,
|
|
82
82
|
)!;
|
|
83
|
-
menu.
|
|
83
|
+
menu.__set_model(widget.viewer.__get_model());
|
|
84
84
|
|
|
85
85
|
menu.open(indicator);
|
|
86
86
|
workspace.get_context_menu()?.init_overlay?.();
|
|
@@ -112,9 +112,11 @@ export const createCommands = (
|
|
|
112
112
|
});
|
|
113
113
|
|
|
114
114
|
commands.addCommand("workspace:new", {
|
|
115
|
-
execute: (args) => {
|
|
116
|
-
const widget = workspace._createWidgetAndNode({
|
|
117
|
-
config: {
|
|
115
|
+
execute: async (args) => {
|
|
116
|
+
const widget = await workspace._createWidgetAndNode({
|
|
117
|
+
config: {
|
|
118
|
+
table: args.table as string,
|
|
119
|
+
},
|
|
118
120
|
slot: undefined,
|
|
119
121
|
});
|
|
120
122
|
|
|
@@ -140,7 +142,7 @@ export const createCommands = (
|
|
|
140
142
|
)!;
|
|
141
143
|
|
|
142
144
|
const config = await target_widget.save();
|
|
143
|
-
const new_widget = workspace._createWidgetAndNode({
|
|
145
|
+
const new_widget = await workspace._createWidgetAndNode({
|
|
144
146
|
config,
|
|
145
147
|
slot: undefined,
|
|
146
148
|
});
|
|
@@ -184,19 +186,19 @@ export const createCommands = (
|
|
|
184
186
|
throw new Error(`No widget ${widget_name}`);
|
|
185
187
|
}
|
|
186
188
|
|
|
187
|
-
if (!widget.viewer.hasAttribute("settings")) {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
} else {
|
|
191
|
-
|
|
192
|
-
}
|
|
189
|
+
// if (!widget.viewer.hasAttribute("settings")) {
|
|
190
|
+
// workspace._maximize(widget);
|
|
191
|
+
requestAnimationFrame(() => widget.viewer.toggleConfig());
|
|
192
|
+
// } else {
|
|
193
|
+
// widget.viewer.toggleConfig();
|
|
194
|
+
// }
|
|
193
195
|
},
|
|
194
196
|
isVisible: (args) => {
|
|
195
197
|
const widget = workspace.getWidgetByName(
|
|
196
198
|
args.widget_name as string,
|
|
197
|
-
)
|
|
199
|
+
);
|
|
198
200
|
|
|
199
|
-
return widget
|
|
201
|
+
return widget?.parent! === (workspace.get_dock_panel() as Widget)
|
|
200
202
|
? true
|
|
201
203
|
: false;
|
|
202
204
|
},
|
|
@@ -220,8 +222,8 @@ export const createCommands = (
|
|
|
220
222
|
),
|
|
221
223
|
// iconClass: "menu-duplicate",
|
|
222
224
|
isVisible: (args) => {
|
|
223
|
-
return workspace.getWidgetByName(args.widget_name as string)
|
|
224
|
-
|
|
225
|
+
return workspace.getWidgetByName(args.widget_name as string)
|
|
226
|
+
?.parent! === (workspace.get_dock_panel() as Widget)
|
|
225
227
|
? true
|
|
226
228
|
: false;
|
|
227
229
|
},
|
|
@@ -36,11 +36,13 @@ class PerspectiveDockPanelRenderer extends DockPanel.Renderer {
|
|
|
36
36
|
|
|
37
37
|
// @ts-ignore: extending a private member `_onTabDetachRequested`
|
|
38
38
|
export class PerspectiveDockPanel extends DockPanel {
|
|
39
|
+
_workspace: PerspectiveWorkspace;
|
|
39
40
|
constructor(workspace: PerspectiveWorkspace) {
|
|
40
41
|
super({ renderer: new PerspectiveDockPanelRenderer(workspace) });
|
|
41
42
|
|
|
42
43
|
// @ts-ignore: accessing a private member `_renderer`
|
|
43
44
|
this._renderer.dock = this;
|
|
45
|
+
this._workspace = workspace;
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
_onTabDetachRequested(
|
|
@@ -64,7 +66,7 @@ export class PerspectiveDockPanel extends DockPanel {
|
|
|
64
66
|
// @ts-ignore: accessing a private member `_drag`
|
|
65
67
|
const drag = this._drag;
|
|
66
68
|
if (drag) {
|
|
67
|
-
drag.dragImage?.parentElement
|
|
69
|
+
drag.dragImage?.parentElement?.removeChild?.(drag.dragImage);
|
|
68
70
|
drag.dragImage = null;
|
|
69
71
|
drag._promise.then(() => {
|
|
70
72
|
if (!widget.node.isConnected) {
|
|
@@ -107,12 +109,12 @@ export class PerspectiveDockPanel extends DockPanel {
|
|
|
107
109
|
return super.widgets() as IterableIterator<PerspectiveViewerWidget>;
|
|
108
110
|
}
|
|
109
111
|
|
|
110
|
-
static mapWidgets(
|
|
111
|
-
widgetFunc: (widget: any) => any
|
|
112
|
+
static async mapWidgets(
|
|
113
|
+
widgetFunc: (widget: any) => Promise<any>,
|
|
112
114
|
layout: any,
|
|
113
|
-
): DockPanel.ILayoutConfig {
|
|
115
|
+
): Promise<DockPanel.ILayoutConfig> {
|
|
114
116
|
if (!!layout.main) {
|
|
115
|
-
layout.main = PerspectiveDockPanel.mapAreaWidgets(
|
|
117
|
+
layout.main = await PerspectiveDockPanel.mapAreaWidgets(
|
|
116
118
|
widgetFunc,
|
|
117
119
|
layout.main,
|
|
118
120
|
);
|
|
@@ -121,18 +123,22 @@ export class PerspectiveDockPanel extends DockPanel {
|
|
|
121
123
|
return layout;
|
|
122
124
|
}
|
|
123
125
|
|
|
124
|
-
static mapAreaWidgets(
|
|
125
|
-
widgetFunc: (widget: any) => any
|
|
126
|
+
static async mapAreaWidgets(
|
|
127
|
+
widgetFunc: (widget: any) => Promise<any>,
|
|
126
128
|
layout: DockLayout.AreaConfig,
|
|
127
|
-
): DockLayout.AreaConfig {
|
|
129
|
+
): Promise<DockLayout.AreaConfig> {
|
|
128
130
|
if (layout.hasOwnProperty("children")) {
|
|
129
131
|
const split_panel = layout as DockLayout.ISplitAreaConfig;
|
|
130
|
-
split_panel.children =
|
|
131
|
-
|
|
132
|
+
split_panel.children = await Promise.all(
|
|
133
|
+
split_panel.children.map((widget) =>
|
|
134
|
+
PerspectiveDockPanel.mapAreaWidgets(widgetFunc, widget),
|
|
135
|
+
),
|
|
132
136
|
);
|
|
133
137
|
} else if (layout.hasOwnProperty("widgets")) {
|
|
134
138
|
const tab_panel = layout as DockLayout.ITabAreaConfig;
|
|
135
|
-
tab_panel.widgets =
|
|
139
|
+
tab_panel.widgets = await Promise.all(
|
|
140
|
+
tab_panel.widgets.map(widgetFunc),
|
|
141
|
+
);
|
|
136
142
|
}
|
|
137
143
|
|
|
138
144
|
return layout;
|
|
@@ -140,6 +146,11 @@ export class PerspectiveDockPanel extends DockPanel {
|
|
|
140
146
|
|
|
141
147
|
onAfterAttach() {
|
|
142
148
|
this.spacing =
|
|
143
|
-
parseInt(
|
|
149
|
+
parseInt(
|
|
150
|
+
window
|
|
151
|
+
.getComputedStyle(this._workspace.element)
|
|
152
|
+
.getPropertyValue("--workspace-spacing"),
|
|
153
|
+
) || 0;
|
|
154
|
+
1;
|
|
144
155
|
}
|
|
145
156
|
}
|
|
@@ -62,6 +62,7 @@ export class PerspectiveTabBar extends TabBar<any> {
|
|
|
62
62
|
let content = new Array();
|
|
63
63
|
for (let i = 0, n = titles.length; i < n; ++i) {
|
|
64
64
|
let title = titles[i];
|
|
65
|
+
title.owner._titlebar = this;
|
|
65
66
|
let current = title === currentTitle;
|
|
66
67
|
let otherTitles = titles.filter((x) => x !== currentTitle);
|
|
67
68
|
let onClick;
|
|
@@ -132,7 +133,12 @@ export class PerspectiveTabBar extends TabBar<any> {
|
|
|
132
133
|
mnemonic: 0,
|
|
133
134
|
});
|
|
134
135
|
|
|
135
|
-
const box = (
|
|
136
|
+
const box = (
|
|
137
|
+
(event.target as HTMLElement).shadowRoot?.querySelector(
|
|
138
|
+
"#status_reconnect",
|
|
139
|
+
) as HTMLElement
|
|
140
|
+
).getBoundingClientRect();
|
|
141
|
+
|
|
136
142
|
const outer_box = this._workspace.element.getBoundingClientRect();
|
|
137
143
|
this._menu.open(box.x - outer_box.x, box.y + box.height - outer_box.y);
|
|
138
144
|
this._menu.aboutToClose.connect(() => {
|
|
@@ -53,39 +53,22 @@ export class PerspectiveTabBarRenderer extends TabBar.Renderer {
|
|
|
53
53
|
const dataset = this.createTabDataset(data);
|
|
54
54
|
const more: h.Child[] = [];
|
|
55
55
|
if (onclick) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
);
|
|
56
|
+
data.title.owner.setCallback(onclick);
|
|
57
|
+
data.title.owner.addClass("bookmarks-container");
|
|
58
|
+
} else {
|
|
59
|
+
data.title.owner.setCallback(undefined);
|
|
60
|
+
data.title.owner.removeClass("bookmarks-container");
|
|
62
61
|
}
|
|
63
62
|
|
|
64
63
|
return h.li(
|
|
65
64
|
{ key, className, title, style, dataset },
|
|
66
|
-
this.renderDragHandle(),
|
|
67
|
-
...more,
|
|
68
|
-
this.renderLabel(data),
|
|
69
|
-
this.renderCloseIcon(),
|
|
65
|
+
// this.renderDragHandle(),
|
|
70
66
|
);
|
|
71
67
|
}
|
|
72
68
|
|
|
73
|
-
renderDragHandle() {
|
|
74
|
-
return h.div({
|
|
75
|
-
className: "drag-handle",
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// renderConfigIcon() {
|
|
69
|
+
// renderDragHandle() {
|
|
80
70
|
// return h.div({
|
|
81
|
-
// className: "
|
|
82
|
-
// id: TabBarItems.Config,
|
|
71
|
+
// className: "drag-handle",
|
|
83
72
|
// });
|
|
84
73
|
// }
|
|
85
|
-
|
|
86
|
-
renderCloseIcon() {
|
|
87
|
-
return h.div({
|
|
88
|
-
className: "lm-TabBar-tabCloseIcon" + " p-TabBar-tabCloseIcon",
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
74
|
}
|
|
@@ -15,26 +15,31 @@ import { Message } from "@lumino/messaging";
|
|
|
15
15
|
|
|
16
16
|
import type * as psp_viewer from "@perspective-dev/viewer";
|
|
17
17
|
import type * as psp from "@perspective-dev/client";
|
|
18
|
+
import { PerspectiveTabBar } from "./tabbar";
|
|
18
19
|
|
|
19
20
|
interface IPerspectiveViewerWidgetOptions {
|
|
20
21
|
node: HTMLElement;
|
|
21
22
|
viewer: psp_viewer.HTMLPerspectiveViewerElement;
|
|
23
|
+
onAttach?: () => void;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
export class PerspectiveViewerWidget extends Widget {
|
|
25
27
|
viewer: psp_viewer.HTMLPerspectiveViewerElement;
|
|
26
28
|
_title: string;
|
|
27
|
-
_is_table_loaded: boolean;
|
|
28
29
|
_is_pivoted: boolean;
|
|
29
30
|
_restore_config?: () => Promise<void>;
|
|
30
|
-
|
|
31
|
+
_onAttach?: () => void;
|
|
32
|
+
_titlebar?: PerspectiveTabBar;
|
|
33
|
+
_deleted: boolean;
|
|
34
|
+
_titlebar_callback?: (event: MouseEvent) => {};
|
|
31
35
|
|
|
32
|
-
constructor({ viewer, node }: IPerspectiveViewerWidgetOptions) {
|
|
36
|
+
constructor({ viewer, node, onAttach }: IPerspectiveViewerWidgetOptions) {
|
|
33
37
|
super({ node });
|
|
34
38
|
this.viewer = viewer;
|
|
35
39
|
this._title = "";
|
|
36
|
-
this._is_table_loaded = false;
|
|
37
40
|
this._is_pivoted = false;
|
|
41
|
+
this._onAttach = onAttach;
|
|
42
|
+
this._deleted = false;
|
|
38
43
|
}
|
|
39
44
|
|
|
40
45
|
get name(): string {
|
|
@@ -46,7 +51,6 @@ export class PerspectiveViewerWidget extends Widget {
|
|
|
46
51
|
}
|
|
47
52
|
|
|
48
53
|
async load(table: psp.Table | Promise<psp.Table>) {
|
|
49
|
-
this._is_table_loaded = true;
|
|
50
54
|
let promises = [this.viewer.load(table)];
|
|
51
55
|
if (this._restore_config) {
|
|
52
56
|
promises.push(this._restore_config());
|
|
@@ -55,47 +59,52 @@ export class PerspectiveViewerWidget extends Widget {
|
|
|
55
59
|
await Promise.all(promises);
|
|
56
60
|
}
|
|
57
61
|
|
|
58
|
-
restore(
|
|
59
|
-
config: psp_viewer.ViewerConfigUpdate & {
|
|
60
|
-
table: string;
|
|
61
|
-
},
|
|
62
|
-
) {
|
|
63
|
-
const { table, ...viewerConfig } = config;
|
|
62
|
+
restore(config: psp_viewer.ViewerConfigUpdate) {
|
|
64
63
|
this._title = config.title as string;
|
|
65
64
|
this.title.label = config.title as string;
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
}
|
|
65
|
+
this._is_pivoted = (config.group_by?.length || 0) > 0;
|
|
66
|
+
return this.viewer.restore({ ...config });
|
|
76
67
|
}
|
|
77
68
|
|
|
78
69
|
async save() {
|
|
79
70
|
let config = {
|
|
80
71
|
...(await this.viewer.save()),
|
|
81
|
-
table: this.viewer.getAttribute("table"),
|
|
82
72
|
};
|
|
83
73
|
|
|
84
74
|
delete config["settings"];
|
|
85
75
|
return config;
|
|
86
76
|
}
|
|
87
77
|
|
|
78
|
+
addClass(name: string) {
|
|
79
|
+
super.addClass(name);
|
|
80
|
+
this.viewer?.classList?.add?.(name);
|
|
81
|
+
}
|
|
82
|
+
|
|
88
83
|
removeClass(name: string) {
|
|
89
84
|
super.removeClass(name);
|
|
90
|
-
this.viewer
|
|
85
|
+
this.viewer?.classList?.remove?.(name);
|
|
91
86
|
}
|
|
92
87
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
this.viewer.parentElement.removeChild(this.viewer);
|
|
97
|
-
}
|
|
88
|
+
setCallback(callback?: (event: MouseEvent) => {}) {
|
|
89
|
+
this._titlebar_callback = callback;
|
|
90
|
+
}
|
|
98
91
|
|
|
99
|
-
|
|
92
|
+
protected onAfterAttach(msg: Message) {
|
|
93
|
+
super.onAfterAttach(msg);
|
|
94
|
+
this._onAttach?.();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
onCloseRequest(msg: Message) {
|
|
98
|
+
super.onCloseRequest(msg);
|
|
99
|
+
return (async () => {
|
|
100
|
+
if (this.viewer.parentElement) {
|
|
101
|
+
this.viewer.parentElement.removeChild(this.viewer);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (!this._deleted) {
|
|
105
|
+
await this.viewer.delete();
|
|
106
|
+
this._deleted = true;
|
|
107
|
+
}
|
|
108
|
+
})();
|
|
100
109
|
}
|
|
101
110
|
}
|