/
plugin.ts
268 lines (238 loc) · 9.77 KB
/
plugin.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
// ┃ This file is part of the Perspective library, distributed under the terms ┃
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
import type * as perspective from "@finos/perspective";
/**
* The `IPerspectiveViewerPlugin` interface defines the necessary API for a
* `<perspective-viewer>` plugin, which also must be an `HTMLElement` via the
* Custom Elements API or otherwise. Rather than implement this API from
* scratch however, the simplest way is to inherit from
* `<perspective-viewer-plugin>`, which implements `IPerspectiveViewerPlugin`
* with non-offensive default implementations, where only the `draw()` and
* `name()` methods need be overridden to get started with a simple plugin.
*
* Note that plugins are frozen once a `<perspective-viewer>` has been
* instantiated, so generally new plugin code must be executed at the module
* level (if packaged as a library), or during application init to ensure global
* availability of a plugin.
*
* @example
* ```javascript
* const BasePlugin = customElements.get("perspective-viewer-plugin");
* class MyPlugin extends BasePlugin {
* get name() {
* return "My Plugin";
* }
* async draw(view) {
* const count = await view.num_rows();
* this.innerHTML = `View has ${count} rows`;
* }
* }
*
* customElements.define("my-plugin", MyPlugin);
* const Viewer = customElements.get("perspective-viewer");
* Viewer.registerPlugin("my-plugin");
* ```
* @noInheritDoc
*/
export interface IPerspectiveViewerPlugin {
/**
* The name for this plugin, which is used as both it's unique key for use
* as a parameter for the `plugin` field of a `ViewerConfig`, and as the
* display name for this plugin in the `<perspective-viewer>` UI.
*/
get name(): string;
/**
* Select mode determines how column add/remove buttons behave for this
* plugin. `"select"` mode exclusively selects the added column, removing
* other columns. `"toggle"` mode toggles the column on or off (dependent
* on column state), leaving existing columns alone.
*/
get select_mode(): string | undefined;
/**
* The minimum number of columns required for this plugin to operate.
* This mostly affects drag/drop and column remove button behavior,
* preventing the use from applying configs which violate this min.
*
* While this option can technically be `undefined` (as in the case of
* `@finos/perspective-viewer-datagrid`), doing so currently has nearly
* identical behavior to 1.
*/
get min_config_columns(): number | undefined;
/**
* The named column labels, if desired. Named columns behave differently
* in drag/drop mode than unnamed columns, having replace/swap behavior
* rather than insert. If provided, the length of `config_column_names`
* _must_ be `>= min_config_columns`, as this is assumed by the drag/drop
* logic.
*/
get config_column_names(): string[] | undefined;
/**
* The load priority of the plugin. If the plugin shares priority with another,
* the first to load has a higher priority.
*
* A larger number has a higher priority.
*
* The plugin with the highest priority will be loaded by default by the Perspective viewer.
* If you would like to instead begin with a lower priority plugin, choose it explicitly with
* a `HTMLPerspectiveViewerPluginElement.restore` call.
*/
get priority(): number | undefined;
/**
* Render this plugin using the provided `View`. While there is no
* provision to cancel a render in progress per se, calling a method on
* a `View` which has been deleted will throw an exception.
*
* @example
* ```
* async draw(view: perspective.View): Promise<void> {
* const csv = await view.to_csv();
* this.innerHTML = `<pre>${csv}</pre>`;
* }
* ```
*/
draw(view: perspective.View): Promise<void>;
/**
* Draw under the assumption that the `ViewConfig` has not changed since
* the previous call to `draw()`, but the underlying data has. Defaults to
* dispatch to `draw()`.
*
* @example
* ```javascript
* async update(view: perspective.View): Promise<void> {
* return this.draw(view);
* }
* ```
*/
update(view: perspective.View): Promise<void>;
/**
* Clear this plugin, though it is up to the discretion of the plugin
* author to determine what this means. Defaults to resetting this
* element's `innerHTML`, so be sure to override if you want custom
* behavior.
*
* @example
* ```javascript
* async clear(): Promise<void> {
* this.innerHTML = "";
* }
* ```
*/
clear(): Promise<void>;
/**
* Like `update()`, but for when the dimensions of the plugin have changed
* and the underlying data has not.
*/
resize(): Promise<void>;
/**
* Notify the plugin that the style environment has changed. Useful for
* plugins which read CSS styles via `window.getComputedStyle()`.
*/
restyle(): Promise<void>;
/**
* Save this plugin's state to a JSON-serializable value. While this value
* can be anything, it should work reciprocally with `restore()` to return
* this plugin's renderer to the same state, though potentially with a
* different `View`.
*
* `save()` should be used for user-persistent settings that are
* data-agnostic, so the user can have persistent view during refresh or
* reload. For example, `@finos/perspective-viewer-d3fc` uses
* `plugin_config` to remember the user-repositionable legend coordinates.
*/
save(): Promise<any>;
/**
* Restore this plugin to a state previously returned by `save()`.
*/
restore(config: any): Promise<void>;
/**
* Free any resources acquired by this plugin and prepare to be deleted.
*/
delete(): Promise<void>;
}
/**
* The `<perspective-viewer-plugin>` element, the default perspective plugin
* which is registered and activated automcatically when a
* `<perspective-viewer>` is loaded without plugins. While you will not
* typically instantiate this class directly, it is simple enough to function
* as a good "default" plugin implementation which can be extended to create
* custom plugins.
*
* @example
* ```javascript
* class MyPlugin extends customElements.get("perspective-viewer-plugin") {
* // Custom plugin overrides
* }
* ```
* @noInheritDoc
*/
export class HTMLPerspectiveViewerPluginElement
extends HTMLElement
implements IPerspectiveViewerPlugin
{
constructor() {
super();
}
get name(): string {
return "Debug";
}
get select_mode(): "select" | "toggle" {
return "select";
}
get min_config_columns(): number | undefined {
return undefined;
}
get config_column_names(): string[] | undefined {
return undefined;
}
get priority(): number {
return 0;
}
get plugin_attributes(): any {
return {};
}
async update(view: perspective.View): Promise<void> {
return this.draw(view);
}
async draw(view: perspective.View): Promise<void> {
this.style.backgroundColor = "#fff";
const csv = await view.to_csv();
const css = `margin:0;overflow:scroll;position:absolute;width:100%;height:100%`;
this.innerHTML = `<pre style='${css}'>${csv}</pre>`;
}
async clear(): Promise<void> {
this.innerHTML = "";
}
async resize(): Promise<void> {
// Not Implemented
}
async restyle(): Promise<void> {
// Not Implemented
}
async save(): Promise<any> {
// Not Implemented
}
async restore(): Promise<void> {
// Not Implemented
}
async delete(): Promise<void> {
// Not Implemented
}
}
if (
document.createElement("perspective-viewer-plugin").constructor ===
HTMLElement
) {
window.customElements.define(
"perspective-viewer-plugin",
HTMLPerspectiveViewerPluginElement
);
}