@perspective-dev/jupyterlab 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/README.md +21 -0
- package/package.json +66 -0
- package/src/js/index.js +44 -0
- package/src/js/model.js +43 -0
- package/src/js/notebook/css.js +20 -0
- package/src/js/notebook/extension.js +32 -0
- package/src/js/notebook/index.js +27 -0
- package/src/js/plugin.js +38 -0
- package/src/js/psp_widget.js +199 -0
- package/src/js/renderer.js +374 -0
- package/src/js/utils.js +15 -0
- package/src/js/version.js +14 -0
- package/src/js/view.js +420 -0
- package/src/js/widget.js +54 -0
- package/src/less/index.less +53 -0
|
@@ -0,0 +1,199 @@
|
|
|
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 "@perspective-dev/viewer";
|
|
14
|
+
import { Widget } from "@lumino/widgets";
|
|
15
|
+
import { MIME_TYPE, PSP_CLASS, PSP_CONTAINER_CLASS } from "./utils";
|
|
16
|
+
|
|
17
|
+
let _increment = 0;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Class for perspective lumino widget.
|
|
21
|
+
*
|
|
22
|
+
* @class PerspectiveWidget (name) TODO: document
|
|
23
|
+
*/
|
|
24
|
+
export class PerspectiveWidget extends Widget {
|
|
25
|
+
constructor(name = "Perspective", elem, bindingMode) {
|
|
26
|
+
super({
|
|
27
|
+
node: elem || document.createElement("div"),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
this.bindingMode = bindingMode;
|
|
31
|
+
this._viewer = PerspectiveWidget.createNode(this.node);
|
|
32
|
+
this.title.label = name;
|
|
33
|
+
this.title.caption = `${name}`;
|
|
34
|
+
this.id = `${name}-` + _increment;
|
|
35
|
+
_increment += 1;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**********************/
|
|
39
|
+
/* Lumino Overrides */
|
|
40
|
+
/**********************/
|
|
41
|
+
/**
|
|
42
|
+
* Lumino: after visible
|
|
43
|
+
*
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
onAfterShow(msg) {
|
|
47
|
+
this.viewer.resize(true);
|
|
48
|
+
super.onAfterShow(msg);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
onActivateRequest(msg) {
|
|
52
|
+
if (this.isAttached) {
|
|
53
|
+
this.viewer.focus();
|
|
54
|
+
}
|
|
55
|
+
super.onActivateRequest(msg);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async toggleConfig() {
|
|
59
|
+
await this.viewer.toggleConfig();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async save() {
|
|
63
|
+
return await this.viewer.save();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async restore(config) {
|
|
67
|
+
return await this.viewer.restore(config);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Load a `perspective.table` into the viewer.
|
|
72
|
+
*
|
|
73
|
+
* @param table A `perspective.table` object.
|
|
74
|
+
*/
|
|
75
|
+
|
|
76
|
+
async load(table) {
|
|
77
|
+
await this.viewer.load(table);
|
|
78
|
+
this._load_complete = true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Update the viewer with new data.
|
|
83
|
+
*
|
|
84
|
+
* @param data
|
|
85
|
+
*/
|
|
86
|
+
|
|
87
|
+
async _update(data) {
|
|
88
|
+
const table = await this.viewer.getTable(true);
|
|
89
|
+
await table.update(data);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Removes all rows from the viewer's table. Does not reset viewer state.
|
|
94
|
+
*/
|
|
95
|
+
|
|
96
|
+
async clear() {
|
|
97
|
+
const table = await this.viewer.getTable(true);
|
|
98
|
+
await table.clear();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Replaces the data of the viewer's table with new data. New data must
|
|
103
|
+
* conform to the schema of the Table.
|
|
104
|
+
*
|
|
105
|
+
* @param data
|
|
106
|
+
*/
|
|
107
|
+
|
|
108
|
+
async replace(data) {
|
|
109
|
+
const table = await this.viewer.getTable(true);
|
|
110
|
+
await table.replace(data);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Deletes this element's data and clears it's internal state (but not its
|
|
115
|
+
* user state). This (or the underlying `perspective.table`'s equivalent
|
|
116
|
+
* method) must be called in order for its memory to be reclaimed.
|
|
117
|
+
*/
|
|
118
|
+
|
|
119
|
+
async delete() {
|
|
120
|
+
await this.viewer.delete();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Returns a promise that resolves to the element's edit port ID, used
|
|
125
|
+
* internally when edits are made using datagrid in client/server mode.
|
|
126
|
+
*/
|
|
127
|
+
|
|
128
|
+
async getEditPort() {
|
|
129
|
+
return await this.viewer.getEditPort();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async getTable() {
|
|
133
|
+
return await this.viewer.getTable();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/***************************************************************************
|
|
137
|
+
*
|
|
138
|
+
* Getters
|
|
139
|
+
*
|
|
140
|
+
*/
|
|
141
|
+
/**
|
|
142
|
+
* Returns the underlying `PerspectiveViewer` instance.
|
|
143
|
+
*
|
|
144
|
+
* @returns {PerspectiveViewer} The widget's viewer instance.
|
|
145
|
+
*/
|
|
146
|
+
|
|
147
|
+
get viewer() {
|
|
148
|
+
return this._viewer;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Returns the name of the widget.
|
|
153
|
+
*
|
|
154
|
+
* @returns {string} the widget name - "Perspective" if not set by the user.
|
|
155
|
+
*/
|
|
156
|
+
|
|
157
|
+
get name() {
|
|
158
|
+
return this.title.label;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
get selectable() {
|
|
162
|
+
return this.viewer.hasAttribute("selectable");
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
set selectable(row_selection) {
|
|
166
|
+
if (row_selection) {
|
|
167
|
+
this.viewer.setAttribute("selectable", "");
|
|
168
|
+
} else {
|
|
169
|
+
this.viewer.removeAttribute("selectable");
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
static createNode(node) {
|
|
174
|
+
node.classList.add("p-Widget");
|
|
175
|
+
node.classList.add(PSP_CONTAINER_CLASS);
|
|
176
|
+
const viewer = document.createElement("perspective-viewer");
|
|
177
|
+
viewer.classList.add(PSP_CLASS);
|
|
178
|
+
viewer.setAttribute("type", MIME_TYPE);
|
|
179
|
+
while (node.lastChild) {
|
|
180
|
+
node.removeChild(node.lastChild);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
node.appendChild(viewer);
|
|
184
|
+
|
|
185
|
+
// allow perspective's event handlers to do their work
|
|
186
|
+
viewer.addEventListener(
|
|
187
|
+
"contextmenu",
|
|
188
|
+
(event) => event.stopPropagation(),
|
|
189
|
+
false,
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
const div = document.createElement("div");
|
|
193
|
+
div.style.setProperty("display", "flex");
|
|
194
|
+
div.style.setProperty("flex-direction", "row");
|
|
195
|
+
node.appendChild(div);
|
|
196
|
+
|
|
197
|
+
return viewer;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
@@ -0,0 +1,374 @@
|
|
|
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 { ActivityMonitor } from "@jupyterlab/coreutils";
|
|
14
|
+
import { ILayoutRestorer } from "@jupyterlab/application";
|
|
15
|
+
import {
|
|
16
|
+
IThemeManager,
|
|
17
|
+
WidgetTracker,
|
|
18
|
+
Dialog,
|
|
19
|
+
showDialog,
|
|
20
|
+
} from "@jupyterlab/apputils";
|
|
21
|
+
|
|
22
|
+
import { ABCWidgetFactory, DocumentWidget } from "@jupyterlab/docregistry";
|
|
23
|
+
import { PerspectiveWidget } from "./psp_widget";
|
|
24
|
+
|
|
25
|
+
import perspective from "@perspective-dev/client";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The name of the factories that creates widgets.
|
|
29
|
+
*/
|
|
30
|
+
const FACTORY_CSV = "Perspective-CSV";
|
|
31
|
+
const FACTORY_JSON = "Perspective-JSON";
|
|
32
|
+
const FACTORY_ARROW = "Perspective-Arrow";
|
|
33
|
+
const RENDER_TIMEOUT = 1000;
|
|
34
|
+
|
|
35
|
+
// create here to reuse for exception handling
|
|
36
|
+
const baddialog = () => {
|
|
37
|
+
showDialog({
|
|
38
|
+
body: "Perspective could not render the data",
|
|
39
|
+
buttons: [
|
|
40
|
+
Dialog.okButton({
|
|
41
|
+
label: "Dismiss",
|
|
42
|
+
}),
|
|
43
|
+
],
|
|
44
|
+
focusNodeSelector: "input",
|
|
45
|
+
title: "Error",
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export class PerspectiveDocumentWidget extends DocumentWidget {
|
|
50
|
+
constructor(options, type = "csv") {
|
|
51
|
+
super({
|
|
52
|
+
content: new PerspectiveWidget("Perspective"),
|
|
53
|
+
context: options.context,
|
|
54
|
+
reveal: options.reveal,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
this._monitor = null;
|
|
58
|
+
this._psp = this.content;
|
|
59
|
+
this._type = type;
|
|
60
|
+
this._context = options.context;
|
|
61
|
+
this._context.ready.then(() => {
|
|
62
|
+
this._update();
|
|
63
|
+
this._monitor = new ActivityMonitor({
|
|
64
|
+
signal: this.context.model.contentChanged,
|
|
65
|
+
timeout: RENDER_TIMEOUT,
|
|
66
|
+
});
|
|
67
|
+
this._monitor.activityStopped.connect(this._update, this);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async _update() {
|
|
72
|
+
try {
|
|
73
|
+
let data;
|
|
74
|
+
if (this._type === "csv") {
|
|
75
|
+
// load csv directly
|
|
76
|
+
data = this._context.model.toString();
|
|
77
|
+
} else if (this._type === "arrow") {
|
|
78
|
+
// load arrow directly
|
|
79
|
+
data = Uint8Array.from(
|
|
80
|
+
atob(this._context.model.toString()),
|
|
81
|
+
(c) => c.charCodeAt(0),
|
|
82
|
+
).buffer;
|
|
83
|
+
} else if (this._type === "json") {
|
|
84
|
+
data = this._context.model.toJSON();
|
|
85
|
+
if (Array.isArray(data) && data.length > 0) {
|
|
86
|
+
// already is records form, load directly
|
|
87
|
+
data = data;
|
|
88
|
+
} else {
|
|
89
|
+
// Column-oriented or single records JSON
|
|
90
|
+
// don't handle for now, just need to implement
|
|
91
|
+
// a simple transform but we can't handle all
|
|
92
|
+
// cases
|
|
93
|
+
throw "Not handled";
|
|
94
|
+
}
|
|
95
|
+
} else {
|
|
96
|
+
// don't handle other mimetypes for now
|
|
97
|
+
throw "Not handled";
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
const table = await this._psp.viewer.getTable();
|
|
101
|
+
table.replace(data);
|
|
102
|
+
} catch (e) {
|
|
103
|
+
// construct new table
|
|
104
|
+
this.worker = await perspective.worker();
|
|
105
|
+
const table_promise = this.worker.table(data);
|
|
106
|
+
|
|
107
|
+
// load data
|
|
108
|
+
await this._psp.viewer.load(table_promise);
|
|
109
|
+
const table = await this._psp.viewer.getTable();
|
|
110
|
+
|
|
111
|
+
// create a flat view
|
|
112
|
+
const view = await table.view();
|
|
113
|
+
view.on_update(async () => {
|
|
114
|
+
if (this._type === "csv") {
|
|
115
|
+
const result = await view.to_csv();
|
|
116
|
+
this.context.model.fromString(result);
|
|
117
|
+
this.context.save();
|
|
118
|
+
} else if (this._type === "arrow") {
|
|
119
|
+
const result = await view.to_arrow();
|
|
120
|
+
const resultAsB64 = btoa(
|
|
121
|
+
new Uint8Array(result).reduce(
|
|
122
|
+
(acc, i) =>
|
|
123
|
+
(acc += String.fromCharCode.apply(null, [
|
|
124
|
+
i,
|
|
125
|
+
])),
|
|
126
|
+
"",
|
|
127
|
+
),
|
|
128
|
+
);
|
|
129
|
+
this.context.model.fromString(resultAsB64);
|
|
130
|
+
this.context.save();
|
|
131
|
+
} else if (this._type === "json") {
|
|
132
|
+
const result = await view.to_json();
|
|
133
|
+
this.context.model.fromJSON(result);
|
|
134
|
+
this.context.save();
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
} catch (e) {
|
|
139
|
+
baddialog();
|
|
140
|
+
throw e;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// pickup theme from env
|
|
144
|
+
this._psp.theme =
|
|
145
|
+
document.body.getAttribute("data-jp-theme-light") === "false"
|
|
146
|
+
? "Pro Light"
|
|
147
|
+
: "Pro Dark";
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
dispose() {
|
|
151
|
+
if (this._monitor) {
|
|
152
|
+
this._monitor.dispose();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
this.worker.terminate();
|
|
156
|
+
super.dispose();
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
get psp() {
|
|
160
|
+
return this._psp;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* A widget factory for CSV widgets.
|
|
166
|
+
*/
|
|
167
|
+
export class PerspectiveCSVFactory extends ABCWidgetFactory {
|
|
168
|
+
createNewWidget(context) {
|
|
169
|
+
return new PerspectiveDocumentWidget(
|
|
170
|
+
{
|
|
171
|
+
context,
|
|
172
|
+
},
|
|
173
|
+
"csv",
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* A widget factory for JSON widgets.
|
|
180
|
+
*/
|
|
181
|
+
export class PerspectiveJSONFactory extends ABCWidgetFactory {
|
|
182
|
+
createNewWidget(context) {
|
|
183
|
+
return new PerspectiveDocumentWidget(
|
|
184
|
+
{
|
|
185
|
+
context,
|
|
186
|
+
},
|
|
187
|
+
"json",
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* A widget factory for arrow widgets.
|
|
194
|
+
*/
|
|
195
|
+
export class PerspectiveArrowFactory extends ABCWidgetFactory {
|
|
196
|
+
createNewWidget(context) {
|
|
197
|
+
return new PerspectiveDocumentWidget(
|
|
198
|
+
{
|
|
199
|
+
context,
|
|
200
|
+
},
|
|
201
|
+
"arrow",
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Activate cssviewer extension for CSV files
|
|
208
|
+
*/
|
|
209
|
+
|
|
210
|
+
function activate(app, restorer, themeManager) {
|
|
211
|
+
const factorycsv = new PerspectiveCSVFactory({
|
|
212
|
+
name: FACTORY_CSV,
|
|
213
|
+
fileTypes: ["csv"],
|
|
214
|
+
defaultFor: ["csv"],
|
|
215
|
+
readOnly: true,
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
const factoryjson = new PerspectiveJSONFactory({
|
|
219
|
+
name: FACTORY_JSON,
|
|
220
|
+
fileTypes: ["json", "jsonl"],
|
|
221
|
+
defaultFor: ["json", "jsonl"],
|
|
222
|
+
readOnly: true,
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
try {
|
|
226
|
+
app.docRegistry.addFileType({
|
|
227
|
+
name: "arrow",
|
|
228
|
+
displayName: "arrow",
|
|
229
|
+
extensions: [".arrow"],
|
|
230
|
+
mimeTypes: ["application/octet-stream"],
|
|
231
|
+
contentType: "file",
|
|
232
|
+
fileFormat: "base64",
|
|
233
|
+
});
|
|
234
|
+
} catch (_a) {
|
|
235
|
+
// do nothing
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const factoryarrow = new PerspectiveArrowFactory({
|
|
239
|
+
name: FACTORY_ARROW,
|
|
240
|
+
fileTypes: ["arrow"],
|
|
241
|
+
defaultFor: ["arrow"],
|
|
242
|
+
readOnly: true,
|
|
243
|
+
modelName: "base64",
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
const trackercsv = new WidgetTracker({
|
|
247
|
+
namespace: "csvperspective",
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
const trackerjson = new WidgetTracker({
|
|
251
|
+
namespace: "jsonperspective",
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
const trackerarrow = new WidgetTracker({
|
|
255
|
+
namespace: "arrowperspective",
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
if (restorer) {
|
|
259
|
+
// Handle state restoration.
|
|
260
|
+
void restorer.restore(trackercsv, {
|
|
261
|
+
command: "docmanager:open",
|
|
262
|
+
args: (widget) => ({
|
|
263
|
+
path: widget.context.path,
|
|
264
|
+
factory: FACTORY_CSV,
|
|
265
|
+
}),
|
|
266
|
+
name: (widget) => widget.context.path,
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
void restorer.restore(trackerjson, {
|
|
270
|
+
command: "docmanager:open",
|
|
271
|
+
args: (widget) => ({
|
|
272
|
+
path: widget.context.path,
|
|
273
|
+
factory: FACTORY_JSON,
|
|
274
|
+
}),
|
|
275
|
+
name: (widget) => widget.context.path,
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
void restorer.restore(trackerarrow, {
|
|
279
|
+
command: "docmanager:open",
|
|
280
|
+
args: (widget) => ({
|
|
281
|
+
path: widget.context.path,
|
|
282
|
+
factory: FACTORY_ARROW,
|
|
283
|
+
}),
|
|
284
|
+
name: (widget) => widget.context.path,
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
app.docRegistry.addWidgetFactory(factorycsv);
|
|
289
|
+
app.docRegistry.addWidgetFactory(factoryjson);
|
|
290
|
+
app.docRegistry.addWidgetFactory(factoryarrow);
|
|
291
|
+
const ftcsv = app.docRegistry.getFileType("csv");
|
|
292
|
+
const ftjson = app.docRegistry.getFileType("json");
|
|
293
|
+
const ftarrow = app.docRegistry.getFileType("arrow");
|
|
294
|
+
factorycsv.widgetCreated.connect((sender, widget) => {
|
|
295
|
+
// Track the widget.
|
|
296
|
+
void trackercsv.add(widget);
|
|
297
|
+
|
|
298
|
+
// Notify the widget tracker if restore data needs to update.
|
|
299
|
+
widget.context.pathChanged.connect(() => {
|
|
300
|
+
void trackercsv.save(widget);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
if (ftcsv) {
|
|
304
|
+
widget.title.iconClass = ftcsv.iconClass || "";
|
|
305
|
+
widget.title.iconLabel = ftcsv.iconLabel || "";
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
factoryjson.widgetCreated.connect((sender, widget) => {
|
|
310
|
+
// Track the widget.
|
|
311
|
+
void trackerjson.add(widget);
|
|
312
|
+
|
|
313
|
+
// Notify the widget tracker if restore data needs to update.
|
|
314
|
+
widget.context.pathChanged.connect(() => {
|
|
315
|
+
void trackerjson.save(widget);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
if (ftjson) {
|
|
319
|
+
widget.title.iconClass = ftjson.iconClass || "";
|
|
320
|
+
widget.title.iconLabel = ftjson.iconLabel || "";
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
factoryarrow.widgetCreated.connect((sender, widget) => {
|
|
325
|
+
// Track the widget.
|
|
326
|
+
void trackerarrow.add(widget);
|
|
327
|
+
|
|
328
|
+
// Notify the widget tracker if restore data needs to update.
|
|
329
|
+
widget.context.pathChanged.connect(() => {
|
|
330
|
+
void trackerarrow.save(widget);
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
if (ftarrow) {
|
|
334
|
+
widget.title.iconClass = ftarrow.iconClass || "";
|
|
335
|
+
widget.title.iconLabel = ftarrow.iconLabel || "";
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
// Keep the themes up-to-date.
|
|
340
|
+
const updateThemes = () => {
|
|
341
|
+
const isLight =
|
|
342
|
+
themeManager && themeManager.theme
|
|
343
|
+
? themeManager.isLight(themeManager.theme)
|
|
344
|
+
: true;
|
|
345
|
+
|
|
346
|
+
const theme = isLight ? "Pro Light" : "Pro Dark";
|
|
347
|
+
trackercsv.forEach((pspDocWidget) => {
|
|
348
|
+
pspDocWidget.psp.theme = theme;
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
trackerjson.forEach((pspDocWidget) => {
|
|
352
|
+
pspDocWidget.psp.theme = theme;
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
trackerarrow.forEach((pspDocWidget) => {
|
|
356
|
+
pspDocWidget.psp.theme = theme;
|
|
357
|
+
});
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
if (themeManager) {
|
|
361
|
+
themeManager.themeChanged.connect(updateThemes);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* The perspective extension for files
|
|
367
|
+
*/
|
|
368
|
+
export const PerspectiveRenderers = {
|
|
369
|
+
activate: activate,
|
|
370
|
+
id: "@perspective-dev/jupyterlab-renderers",
|
|
371
|
+
requires: [],
|
|
372
|
+
optional: [ILayoutRestorer, IThemeManager],
|
|
373
|
+
autoStart: true,
|
|
374
|
+
};
|
package/src/js/utils.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
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
|
+
export const MIME_TYPE = "application/psp+json";
|
|
14
|
+
export const PSP_CLASS = "PSPViewer";
|
|
15
|
+
export const PSP_CONTAINER_CLASS = "PSPContainer";
|
|
@@ -0,0 +1,14 @@
|
|
|
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
|
+
const pkg_json = require("../../package.json");
|
|
14
|
+
export const PERSPECTIVE_VERSION = pkg_json.version;
|