@perspective-dev/viewer 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-viewer.js +2 -2
- package/dist/cdn/perspective-viewer.js.map +4 -4
- package/dist/css/dracula.css +1 -1
- package/dist/css/gruvbox-dark.css +1 -1
- package/dist/css/gruvbox.css +1 -1
- package/dist/css/icons.css +1 -1
- package/dist/css/monokai.css +1 -1
- package/dist/css/pro-dark.css +1 -1
- package/dist/css/pro.css +1 -1
- package/dist/css/solarized-dark.css +1 -1
- package/dist/css/solarized.css +1 -1
- package/dist/css/themes.css +1 -1
- package/dist/css/vaporwave.css +1 -1
- package/dist/esm/extensions.d.ts +23 -2
- package/dist/esm/perspective-viewer.d.ts +2 -7
- package/dist/esm/perspective-viewer.inline.js +2 -2
- package/dist/esm/perspective-viewer.inline.js.map +4 -4
- package/dist/esm/perspective-viewer.js +2 -2
- package/dist/esm/perspective-viewer.js.map +4 -4
- package/dist/esm/plugin.d.ts +1 -1
- package/dist/esm/ts-rs/ViewerConfigUpdate.d.ts +1 -0
- package/dist/wasm/perspective-viewer.d.ts +218 -46
- package/dist/wasm/perspective-viewer.js +1242 -753
- package/dist/wasm/perspective-viewer.wasm +0 -0
- package/dist/wasm/perspective-viewer.wasm.d.ts +38 -19
- package/package.json +1 -1
- package/src/less/containers/scroll-panel.less +0 -1
- package/src/less/plugin-selector.less +15 -5
- package/src/less/status-bar.less +75 -27
- package/src/less/viewer.less +140 -58
- package/src/rust/components/column_dropdown.rs +21 -21
- package/src/rust/components/column_selector/active_column.rs +131 -120
- package/src/rust/components/column_selector/add_expression_button.rs +5 -0
- package/src/rust/components/column_selector/aggregate_selector.rs +8 -4
- package/src/rust/components/column_selector/config_selector.rs +170 -161
- package/src/rust/components/column_selector/empty_column.rs +16 -11
- package/src/rust/components/column_selector/{expression_toolbar.rs → expr_edit_button.rs} +7 -0
- package/src/rust/components/column_selector/filter_column.rs +195 -194
- package/src/rust/components/column_selector/inactive_column.rs +82 -67
- package/src/rust/components/column_selector/pivot_column.rs +16 -11
- package/src/rust/components/column_selector/sort_column.rs +9 -7
- package/src/rust/components/column_selector.rs +42 -37
- package/src/rust/components/column_settings_sidebar/save_settings.rs +3 -1
- package/src/rust/components/column_settings_sidebar/style_tab/agg_depth_selector.rs +58 -0
- package/src/rust/components/column_settings_sidebar/style_tab/symbol/row_selector.rs +6 -6
- package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_pairs.rs +2 -94
- package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_pairs_item.rs +111 -0
- package/src/rust/components/column_settings_sidebar/style_tab/symbol.rs +3 -3
- package/src/rust/components/column_settings_sidebar/style_tab.rs +23 -83
- package/src/rust/components/{column_settings_sidebar/sidebar.rs → column_settings_sidebar.rs} +198 -171
- package/src/rust/components/containers/dragdrop_list.rs +20 -20
- package/src/rust/components/containers/dropdown_menu.rs +4 -6
- package/src/rust/components/containers/mod.rs +1 -4
- package/src/rust/components/containers/scroll_panel.rs +80 -80
- package/src/rust/components/containers/scroll_panel_item.rs +36 -36
- package/src/rust/components/containers/select.rs +46 -44
- package/src/rust/components/containers/sidebar.rs +3 -19
- package/src/rust/components/{column_settings_sidebar/style_tab/symbol/symbol_config.rs → containers/sidebar_close_button.rs} +15 -9
- package/src/rust/components/containers/split_panel.rs +212 -200
- package/src/rust/components/containers/tab_list.rs +11 -11
- package/src/rust/components/copy_dropdown.rs +22 -25
- package/src/rust/components/datetime_column_style/custom.rs +19 -19
- package/src/rust/components/datetime_column_style/simple.rs +13 -14
- package/src/rust/components/datetime_column_style.rs +75 -76
- package/src/rust/components/editable_header.rs +18 -14
- package/src/rust/components/empty_row.rs +5 -5
- package/src/rust/components/export_dropdown.rs +42 -42
- package/src/rust/components/expression_editor.rs +25 -19
- package/src/rust/components/filter_dropdown.rs +22 -22
- package/src/rust/components/font_loader.rs +11 -9
- package/src/rust/components/form/code_editor.rs +106 -105
- package/src/rust/components/form/color_range_selector.rs +14 -12
- package/src/rust/components/form/color_selector.rs +3 -1
- package/src/rust/components/form/debug.rs +95 -94
- package/src/rust/components/form/highlight.rs +5 -3
- package/src/rust/components/form/mod.rs +3 -2
- package/src/rust/components/form/optional_field.rs +2 -2
- package/src/rust/components/form/{select_field.rs → select_enum_field.rs} +1 -46
- package/src/rust/components/form/select_value_field.rs +64 -0
- package/src/rust/components/function_dropdown.rs +21 -21
- package/src/rust/components/main_panel.rs +219 -0
- package/src/rust/components/mod.rs +6 -6
- package/src/rust/components/modal.rs +42 -42
- package/src/rust/components/number_column_style.rs +34 -88
- package/src/rust/components/plugin_selector.rs +22 -25
- package/src/rust/components/render_warning.rs +9 -6
- package/src/rust/components/settings_panel.rs +82 -0
- package/src/rust/components/status_bar.rs +250 -146
- package/src/rust/components/status_bar_counter.rs +26 -119
- package/src/rust/components/status_indicator.rs +95 -79
- package/src/rust/components/string_column_style.rs +45 -45
- package/src/rust/components/style/style_provider.rs +1 -15
- package/src/rust/components/style_controls/number_string_format/digits_section.rs +1 -1
- package/src/rust/components/style_controls/number_string_format/misc_section.rs +1 -1
- package/src/rust/components/style_controls/number_string_format/style_section.rs +1 -1
- package/src/rust/components/style_controls/number_string_format.rs +45 -46
- package/src/rust/components/type_icon.rs +14 -11
- package/src/rust/components/viewer.rs +241 -384
- package/src/rust/config/columns_config.rs +2 -2
- package/src/rust/config/datetime_column_style.rs +1 -6
- package/src/rust/config/mod.rs +1 -0
- package/src/rust/config/number_column_style.rs +0 -6
- package/src/rust/config/number_string_format.rs +27 -4
- package/src/rust/config/viewer_config.rs +27 -167
- package/src/rust/custom_elements/copy_dropdown.rs +14 -6
- package/src/rust/custom_elements/export_dropdown.rs +15 -7
- package/src/rust/custom_elements/filter_dropdown.rs +4 -4
- package/src/rust/custom_elements/mod.rs +3 -0
- package/src/rust/custom_elements/viewer.rs +367 -169
- package/src/rust/custom_events.rs +55 -32
- package/src/rust/dragdrop.rs +4 -24
- package/src/rust/exprtk/cursor.rs +10 -1
- package/src/rust/exprtk/mod.rs +2 -0
- package/src/rust/exprtk/tokenize.rs +20 -3
- package/src/rust/js/clipboard.rs +2 -2
- package/src/rust/js/mimetype.rs +2 -7
- package/src/rust/js/mod.rs +0 -1
- package/src/rust/js/plugin.rs +7 -0
- package/src/rust/lib.rs +18 -5
- package/src/rust/model/column_locator.rs +82 -0
- package/src/rust/model/columns_iter_set.rs +1 -0
- package/src/rust/model/copy_export.rs +50 -14
- package/src/rust/model/edit_expression.rs +2 -5
- package/src/rust/model/eject.rs +41 -0
- package/src/rust/model/get_viewer_config.rs +4 -28
- package/src/rust/model/intersection_observer.rs +20 -8
- package/src/rust/model/mod.rs +11 -4
- package/src/rust/model/plugin_column_styles.rs +0 -31
- package/src/rust/model/reset_all.rs +38 -0
- package/src/rust/model/resize_observer.rs +34 -7
- package/src/rust/model/restore_and_render.rs +12 -7
- package/src/rust/{utils/scope.rs → model/send_plugin_config.rs} +32 -35
- package/src/rust/model/structural.rs +194 -23
- package/src/rust/model/update_and_render.rs +14 -4
- package/src/rust/{model/create_col.rs → presentation/column_locator.rs} +73 -42
- package/src/rust/{utils/wasm_abi.rs → presentation/sheets.rs} +54 -40
- package/src/rust/presentation.rs +60 -119
- package/src/rust/renderer/activate.rs +20 -5
- package/src/rust/renderer/limits.rs +0 -149
- package/src/rust/renderer/render_timer.rs +1 -1
- package/src/rust/renderer.rs +34 -18
- package/src/rust/root.rs +50 -0
- package/src/rust/session/column_defaults_update.rs +4 -4
- package/src/rust/session/drag_drop_update.rs +1 -1
- package/src/rust/session/metadata.rs +3 -17
- package/src/rust/session/replace_expression_update.rs +1 -2
- package/src/rust/session.rs +162 -82
- package/src/rust/utils/browser/blob.rs +16 -2
- package/src/rust/utils/browser/download.rs +1 -0
- package/src/rust/{components/column_settings_sidebar/mod.rs → utils/browser/dragdrop.rs} +14 -5
- package/src/rust/utils/browser/mod.rs +8 -4
- package/src/rust/utils/browser/selection.rs +5 -0
- package/src/rust/utils/custom_element.rs +28 -13
- package/src/rust/utils/datetime.rs +5 -0
- package/src/rust/utils/debounce.rs +7 -1
- package/src/rust/utils/hooks/use_async_callback.rs +7 -17
- package/src/rust/utils/mod.rs +28 -40
- package/src/rust/utils/number_format.rs +6 -5
- package/src/rust/utils/pubsub.rs +15 -10
- package/src/rust/utils/weak_scope.rs +11 -1
- package/src/svg/bookmark-icon.svg +4 -0
- package/src/svg/drag-handle copy.svg +10 -0
- package/src/svg/drawer-tab-hover.svg +5 -7
- package/src/svg/drawer-tab-invert-hover.svg +4 -8
- package/src/svg/drawer-tab-invert.svg +4 -7
- package/src/svg/drawer-tab.svg +4 -6
- package/src/svg/status_ok.svg +24 -24
- package/src/ts/extensions.ts +51 -3
- package/src/ts/perspective-viewer.ts +2 -14
- package/src/ts/plugin.ts +1 -1
- package/src/ts/ts-rs/ViewerConfigUpdate.ts +1 -1
- package/src/rust/components/column_settings_sidebar/style_tab/column_style.rs +0 -177
- package/src/rust/components/containers/tests/mod.rs +0 -11
- package/src/rust/components/containers/tests/split_panel.rs +0 -91
- package/src/rust/js/testing.rs +0 -149
- package/src/rust/utils/tee.rs +0 -88
- /package/dist/wasm/snippets/{perspective-viewer-9a89352df1552d2b → perspective-viewer-11a3c51b6310ee99}/inline0.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-9a89352df1552d2b → perspective-viewer-11a3c51b6310ee99}/inline1.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-9a89352df1552d2b → perspective-viewer-11a3c51b6310ee99}/inline2.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-9a89352df1552d2b → perspective-viewer-11a3c51b6310ee99}/inline3.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-9a89352df1552d2b → perspective-viewer-11a3c51b6310ee99}/inline4.js +0 -0
- /package/src/rust/components/{style_controls.rs → style_controls/mod.rs} +0 -0
- /package/src/rust/{components/containers → config}/kvpair.rs +0 -0
|
@@ -14,20 +14,19 @@
|
|
|
14
14
|
|
|
15
15
|
use std::cell::RefCell;
|
|
16
16
|
use std::rc::Rc;
|
|
17
|
-
use std::str::FromStr;
|
|
18
17
|
|
|
19
|
-
use ::
|
|
20
|
-
use
|
|
21
|
-
use js_sys::*;
|
|
18
|
+
use futures::channel::oneshot::channel;
|
|
19
|
+
use js_sys::{Array, JsString};
|
|
22
20
|
use perspective_client::config::ViewConfigUpdate;
|
|
23
|
-
use
|
|
21
|
+
use perspective_client::utils::PerspectiveResultExt;
|
|
22
|
+
use perspective_js::{JsViewConfig, JsViewWindow, Table, View, apierror};
|
|
24
23
|
use wasm_bindgen::JsCast;
|
|
25
24
|
use wasm_bindgen::prelude::*;
|
|
25
|
+
use wasm_bindgen_derive::try_from_js_option;
|
|
26
26
|
use wasm_bindgen_futures::JsFuture;
|
|
27
|
-
use web_sys
|
|
28
|
-
use yew::prelude::*;
|
|
27
|
+
use web_sys::HtmlElement;
|
|
29
28
|
|
|
30
|
-
use crate::components::viewer::{
|
|
29
|
+
use crate::components::viewer::{PerspectiveViewerMsg, PerspectiveViewerProps};
|
|
31
30
|
use crate::config::*;
|
|
32
31
|
use crate::custom_events::*;
|
|
33
32
|
use crate::dragdrop::*;
|
|
@@ -35,7 +34,8 @@ use crate::js::*;
|
|
|
35
34
|
use crate::model::*;
|
|
36
35
|
use crate::presentation::*;
|
|
37
36
|
use crate::renderer::*;
|
|
38
|
-
use crate::
|
|
37
|
+
use crate::root::Root;
|
|
38
|
+
use crate::session::{ResetOptions, Session};
|
|
39
39
|
use crate::utils::*;
|
|
40
40
|
use crate::*;
|
|
41
41
|
|
|
@@ -49,21 +49,36 @@ use crate::*;
|
|
|
49
49
|
/// const viewer = document.createElement("perspective-viewer");
|
|
50
50
|
/// window.body.appendChild(viewer);
|
|
51
51
|
/// ```
|
|
52
|
-
|
|
52
|
+
///
|
|
53
|
+
/// Complete example including loading and restoring the [`Table`]:
|
|
54
|
+
///
|
|
55
|
+
/// ```javascript
|
|
56
|
+
/// import perspective from "@perspective-dev/viewer";
|
|
57
|
+
/// import perspective from "@perspective-dev/client";
|
|
58
|
+
///
|
|
59
|
+
/// const viewer = document.createElement("perspective-viewer");
|
|
60
|
+
/// const worker = await perspective.worker();
|
|
61
|
+
///
|
|
62
|
+
/// await worker.table("x\n1", {name: "table_one"});
|
|
63
|
+
/// await viewer.load(worker);
|
|
64
|
+
/// await viewer.restore({table: "table_one"});
|
|
65
|
+
/// ```
|
|
66
|
+
#[derive(Clone, PerspectiveProperties!)]
|
|
53
67
|
#[wasm_bindgen]
|
|
54
68
|
pub struct PerspectiveViewerElement {
|
|
55
69
|
elem: HtmlElement,
|
|
56
|
-
root:
|
|
70
|
+
root: Root<components::viewer::PerspectiveViewer>,
|
|
57
71
|
resize_handle: Rc<RefCell<Option<ResizeObserverHandle>>>,
|
|
58
72
|
intersection_handle: Rc<RefCell<Option<IntersectionObserverHandle>>>,
|
|
59
73
|
session: Session,
|
|
60
74
|
renderer: Renderer,
|
|
61
75
|
presentation: Presentation,
|
|
62
|
-
|
|
63
|
-
_subscriptions: Rc<Subscription>,
|
|
76
|
+
custom_events: CustomEvents,
|
|
77
|
+
_subscriptions: Rc<[Subscription; 2]>,
|
|
64
78
|
}
|
|
65
79
|
|
|
66
|
-
derive_model!( Renderer, Session, Presentation for
|
|
80
|
+
// derive_model!( Renderer, Root, Session, Presentation for
|
|
81
|
+
// PerspectiveViewerElement);
|
|
67
82
|
|
|
68
83
|
impl CustomElementMetadata for PerspectiveViewerElement {
|
|
69
84
|
const CUSTOM_ELEMENT_NAME: &'static str = "perspective-viewer";
|
|
@@ -86,10 +101,10 @@ impl PerspectiveViewerElement {
|
|
|
86
101
|
|
|
87
102
|
fn new_from_shadow(elem: web_sys::HtmlElement, shadow_root: web_sys::Element) -> Self {
|
|
88
103
|
// Application State
|
|
89
|
-
let session = Session::
|
|
104
|
+
let session = Session::new();
|
|
90
105
|
let renderer = Renderer::new(&elem);
|
|
91
106
|
let presentation = Presentation::new(&elem);
|
|
92
|
-
let
|
|
107
|
+
let custom_events = CustomEvents::new(&elem, &session, &renderer, &presentation);
|
|
93
108
|
|
|
94
109
|
// Create Yew App
|
|
95
110
|
let props = yew::props!(PerspectiveViewerProps {
|
|
@@ -98,50 +113,90 @@ impl PerspectiveViewerElement {
|
|
|
98
113
|
renderer: renderer.clone(),
|
|
99
114
|
presentation: presentation.clone(),
|
|
100
115
|
dragdrop: DragDrop::default(),
|
|
101
|
-
custom_events:
|
|
102
|
-
weak_link: WeakScope::default(),
|
|
116
|
+
custom_events: custom_events.clone(),
|
|
103
117
|
});
|
|
104
118
|
|
|
105
|
-
let
|
|
119
|
+
let state = props.clone_state();
|
|
120
|
+
let root = Root::new(shadow_root, props);
|
|
106
121
|
|
|
107
122
|
// Create callbacks
|
|
108
123
|
let update_sub = session.table_updated.add_listener({
|
|
109
124
|
clone!(renderer, session);
|
|
110
125
|
move |_| {
|
|
111
126
|
clone!(renderer, session);
|
|
112
|
-
ApiFuture::spawn(async move {
|
|
127
|
+
ApiFuture::spawn(async move {
|
|
128
|
+
renderer
|
|
129
|
+
.update(session.get_view())
|
|
130
|
+
.await
|
|
131
|
+
.ignore_view_delete()
|
|
132
|
+
.map(|_| ())
|
|
133
|
+
})
|
|
113
134
|
}
|
|
114
135
|
});
|
|
115
136
|
|
|
116
|
-
let
|
|
137
|
+
let eject_sub = presentation.on_eject.add_listener({
|
|
138
|
+
let root = root.clone();
|
|
139
|
+
move |_| ApiFuture::spawn(state.delete_all(&root))
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
let resize_handle = ResizeObserverHandle::new(&elem, &renderer, &session, &root);
|
|
143
|
+
let intersect_handle =
|
|
144
|
+
IntersectionObserverHandle::new(&elem, &presentation, &session, &renderer);
|
|
145
|
+
|
|
117
146
|
Self {
|
|
118
147
|
elem,
|
|
119
|
-
root
|
|
148
|
+
root,
|
|
120
149
|
session,
|
|
121
150
|
renderer,
|
|
122
151
|
presentation,
|
|
123
152
|
resize_handle: Rc::new(RefCell::new(Some(resize_handle))),
|
|
124
|
-
intersection_handle: Rc::new(RefCell::new(
|
|
125
|
-
|
|
126
|
-
_subscriptions: Rc::new(update_sub),
|
|
153
|
+
intersection_handle: Rc::new(RefCell::new(Some(intersect_handle))),
|
|
154
|
+
custom_events,
|
|
155
|
+
_subscriptions: Rc::new([update_sub, eject_sub]),
|
|
127
156
|
}
|
|
128
157
|
}
|
|
129
158
|
|
|
130
159
|
#[doc(hidden)]
|
|
131
160
|
#[wasm_bindgen(js_name = "connectedCallback")]
|
|
132
|
-
pub fn connected_callback(&self) {
|
|
161
|
+
pub fn connected_callback(&self) -> ApiResult<()> {
|
|
133
162
|
tracing::debug!("Connected <perspective-viewer>");
|
|
163
|
+
Ok(())
|
|
134
164
|
}
|
|
135
165
|
|
|
136
|
-
/// Loads a [`
|
|
137
|
-
/// [`Table`]
|
|
166
|
+
/// Loads a [`Client`], or optionally [`Table`], or optionally a Javascript
|
|
167
|
+
/// `Promise` which returns a [`Client`] or [`Table`], in this viewer.
|
|
168
|
+
///
|
|
169
|
+
/// Loading a [`Client`] does not render, but subsequent calls to
|
|
170
|
+
/// [`PerspectiveViewerElement::restore`] will use this [`Client`] to look
|
|
171
|
+
/// up the proviced `table` name field for the provided
|
|
172
|
+
/// [`ViewerConfigUpdate`].
|
|
173
|
+
///
|
|
174
|
+
/// Loading a [`Table`] is equivalent to subsequently calling
|
|
175
|
+
/// [`Self::restore`] with the `table` field set to [`Table::get_name`], and
|
|
176
|
+
/// will render the UI in its default state when [`Self::load`] resolves.
|
|
177
|
+
/// If you plan to call [`Self::restore`] anyway, prefer passing a
|
|
178
|
+
/// [`Client`] argument to [`Self::load`] as it will conserve one render.
|
|
138
179
|
///
|
|
139
180
|
/// When [`PerspectiveViewerElement::load`] resolves, the first frame of the
|
|
140
181
|
/// UI + visualization is guaranteed to have been drawn. Awaiting the result
|
|
141
182
|
/// of this method in a `try`/`catch` block will capture any errors
|
|
142
|
-
/// thrown during the loading process, or from the [`
|
|
183
|
+
/// thrown during the loading process, or from the [`Client`] `Promise`
|
|
143
184
|
/// itself.
|
|
144
185
|
///
|
|
186
|
+
/// [`PerspectiveViewerElement::load`] may also be called with a [`Table`],
|
|
187
|
+
/// which is equivalent to:
|
|
188
|
+
///
|
|
189
|
+
/// ```javascript
|
|
190
|
+
/// await viewer.load(await table.get_client());
|
|
191
|
+
/// await viewer.restore({name: await table.get_name()})
|
|
192
|
+
/// ```
|
|
193
|
+
///
|
|
194
|
+
/// If you plan to call [`PerspectiveViewerElement::restore`] immediately
|
|
195
|
+
/// after [`PerspectiveViewerElement::load`] yourself, as is commonly
|
|
196
|
+
/// done when loading and configuring a new `<perspective-viewer>`, you
|
|
197
|
+
/// should use a [`Client`] as an argument and set the `table` field in the
|
|
198
|
+
/// restore call as
|
|
199
|
+
///
|
|
145
200
|
/// A [`Table`] can be created using the
|
|
146
201
|
/// [`@perspective-dev/client`](https://www.npmjs.com/package/@perspective-dev/client)
|
|
147
202
|
/// library from NPM (see [`perspective_js`] documentation for details).
|
|
@@ -152,76 +207,104 @@ impl PerspectiveViewerElement {
|
|
|
152
207
|
/// import perspective from "@perspective-dev/client";
|
|
153
208
|
///
|
|
154
209
|
/// const worker = await perspective.worker();
|
|
155
|
-
/// viewer.load(worker
|
|
210
|
+
/// viewer.load(worker);
|
|
156
211
|
/// ```
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
212
|
+
///
|
|
213
|
+
/// ... or
|
|
214
|
+
///
|
|
215
|
+
/// ```javascript
|
|
216
|
+
/// const table = await worker.table(data, {name: "superstore"});
|
|
217
|
+
/// viewer.load(table);
|
|
218
|
+
/// ```
|
|
219
|
+
///
|
|
220
|
+
/// Complete example:
|
|
221
|
+
///
|
|
222
|
+
/// ```javascript
|
|
223
|
+
/// const viewer = document.createElement("perspective-viewer");
|
|
224
|
+
/// const worker = await perspective.worker();
|
|
225
|
+
///
|
|
226
|
+
/// await worker.table("x\n1", {name: "table_one"});
|
|
227
|
+
/// await viewer.load(worker);
|
|
228
|
+
/// await viewer.restore({table: "table_one", columns: ["x"]});
|
|
229
|
+
/// ```
|
|
230
|
+
///
|
|
231
|
+
/// ... or, if you don't want to pass your own arguments to `restore`:
|
|
232
|
+
///
|
|
233
|
+
/// ```javascript
|
|
234
|
+
/// const viewer = document.createElement("perspective-viewer");
|
|
235
|
+
/// const worker = await perspective.worker();
|
|
236
|
+
///
|
|
237
|
+
/// const table = await worker.table("x\n1", {name: "table_one"});
|
|
238
|
+
/// await viewer.load(table);
|
|
239
|
+
/// ```
|
|
240
|
+
pub fn load(&self, table: JsValue) -> ApiResult<ApiFuture<()>> {
|
|
160
241
|
let promise = table
|
|
161
242
|
.clone()
|
|
162
243
|
.dyn_into::<js_sys::Promise>()
|
|
163
244
|
.unwrap_or_else(|_| js_sys::Promise::resolve(&table));
|
|
164
245
|
|
|
165
|
-
self.
|
|
166
|
-
let
|
|
246
|
+
let _plugin = self.renderer.get_active_plugin()?;
|
|
247
|
+
let task = self.session.reset(ResetOptions {
|
|
248
|
+
config: true,
|
|
249
|
+
expressions: true,
|
|
250
|
+
stats: true,
|
|
251
|
+
..ResetOptions::default()
|
|
252
|
+
});
|
|
253
|
+
|
|
167
254
|
let mut config = ViewConfigUpdate {
|
|
168
255
|
columns: Some(self.session.get_view_config().columns.clone()),
|
|
169
256
|
..ViewConfigUpdate::default()
|
|
170
257
|
};
|
|
171
258
|
|
|
259
|
+
let metadata = self.renderer.metadata();
|
|
172
260
|
self.session
|
|
173
|
-
.set_update_column_defaults(&mut config, &
|
|
261
|
+
.set_update_column_defaults(&mut config, &metadata);
|
|
262
|
+
self.session.update_view_config(config)?;
|
|
174
263
|
|
|
175
|
-
let update_task = self.session.update_view_config(config);
|
|
176
264
|
clone!(self.renderer, self.session);
|
|
177
|
-
ApiFuture::
|
|
265
|
+
Ok(ApiFuture::new_throttled(async move {
|
|
178
266
|
let task = async {
|
|
179
|
-
|
|
267
|
+
// Ignore this error, which is blown away by the table anyway.
|
|
268
|
+
let _ = task.await;
|
|
180
269
|
let jstable = JsFuture::from(promise)
|
|
181
270
|
.await
|
|
182
271
|
.map_err(|x| apierror!(TableError(x)))?;
|
|
183
272
|
|
|
184
|
-
if let Some(table) =
|
|
185
|
-
|
|
273
|
+
if let Ok(Some(table)) =
|
|
274
|
+
try_from_js_option::<perspective_js::Table>(jstable.clone())
|
|
186
275
|
{
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
"Table `{}` already loaded, skipping",
|
|
191
|
-
table.get_name().await
|
|
192
|
-
);
|
|
193
|
-
|
|
194
|
-
return Ok(&session);
|
|
195
|
-
} else {
|
|
196
|
-
tracing::debug!(
|
|
197
|
-
"New table {} vs {}",
|
|
198
|
-
table.get_table().get_name(),
|
|
199
|
-
existing_table.get_name()
|
|
200
|
-
);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
276
|
+
let client = table.get_client().await;
|
|
277
|
+
session.set_client(client.get_client().clone());
|
|
278
|
+
let name = table.get_name().await;
|
|
204
279
|
tracing::debug!(
|
|
205
|
-
"
|
|
206
|
-
table.size().await
|
|
280
|
+
"Loading {:.0} rows from `Table` {}",
|
|
281
|
+
table.size().await?,
|
|
282
|
+
name
|
|
207
283
|
);
|
|
208
284
|
|
|
209
|
-
session.set_table(
|
|
210
|
-
|
|
285
|
+
if session.set_table(name).await? {
|
|
286
|
+
session.validate().await?.create_view().await?;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
Ok(session.get_view())
|
|
290
|
+
} else if let Ok(Some(client)) =
|
|
291
|
+
wasm_bindgen_derive::try_from_js_option::<perspective_js::Client>(jstable)
|
|
292
|
+
{
|
|
293
|
+
session.set_client(client.get_client().clone());
|
|
294
|
+
Ok(session.get_view())
|
|
211
295
|
} else {
|
|
212
|
-
Err(ApiError::new("Invalid
|
|
296
|
+
Err(ApiError::new("Invalid argument"))
|
|
213
297
|
}
|
|
214
298
|
};
|
|
215
299
|
|
|
216
300
|
renderer.set_throttle(None);
|
|
217
|
-
let
|
|
218
|
-
let result = draw.and(delete);
|
|
301
|
+
let result = renderer.draw(task).await;
|
|
219
302
|
if let Err(e) = &result {
|
|
220
303
|
session.set_error(false, e.clone()).await?;
|
|
221
304
|
}
|
|
222
305
|
|
|
223
306
|
result
|
|
224
|
-
})
|
|
307
|
+
}))
|
|
225
308
|
}
|
|
226
309
|
|
|
227
310
|
/// Delete the internal [`View`] and all associated state, rendering this
|
|
@@ -246,17 +329,7 @@ impl PerspectiveViewerElement {
|
|
|
246
329
|
/// await viewer.delete();
|
|
247
330
|
/// ```
|
|
248
331
|
pub fn delete(self) -> ApiFuture<()> {
|
|
249
|
-
|
|
250
|
-
ApiFuture::new(self.renderer.clone().with_lock(async move {
|
|
251
|
-
renderer.delete()?;
|
|
252
|
-
root.borrow_mut()
|
|
253
|
-
.take()
|
|
254
|
-
.ok_or("Already deleted!")?
|
|
255
|
-
.destroy();
|
|
256
|
-
session.delete().await?;
|
|
257
|
-
tracing::info!("Deleted <perspective-viewer>");
|
|
258
|
-
Ok(())
|
|
259
|
-
}))
|
|
332
|
+
self.delete_all(self.root())
|
|
260
333
|
}
|
|
261
334
|
|
|
262
335
|
/// Restart this `<perspective-viewer>` to its initial state, before
|
|
@@ -273,9 +346,9 @@ impl PerspectiveViewerElement {
|
|
|
273
346
|
);
|
|
274
347
|
|
|
275
348
|
std::mem::swap(self, &mut state);
|
|
276
|
-
state.delete()
|
|
349
|
+
ApiFuture::new_throttled(state.delete())
|
|
277
350
|
} else {
|
|
278
|
-
ApiFuture::
|
|
351
|
+
ApiFuture::new_throttled(async move { Ok(()) })
|
|
279
352
|
}
|
|
280
353
|
}
|
|
281
354
|
|
|
@@ -304,8 +377,23 @@ impl PerspectiveViewerElement {
|
|
|
304
377
|
ApiFuture::new(async move { Ok(session.get_view().ok_or("No table set")?.into()) })
|
|
305
378
|
}
|
|
306
379
|
|
|
380
|
+
/// Get a copy of the [`ViewConfig`] for the current [`View`]. This is
|
|
381
|
+
/// non-blocking as it does not need to access the plugin (unlike
|
|
382
|
+
/// [`PerspectiveViewerElement::save`]), and also makes no API calls to the
|
|
383
|
+
/// server (unlike [`PerspectiveViewerElement::getView`] followed by
|
|
384
|
+
/// [`View::get_config`])
|
|
385
|
+
#[wasm_bindgen]
|
|
386
|
+
pub fn getViewConfig(&self) -> ApiFuture<JsViewConfig> {
|
|
387
|
+
let session = self.session.clone();
|
|
388
|
+
ApiFuture::new(async move {
|
|
389
|
+
let config = session.get_view_config();
|
|
390
|
+
Ok(JsValue::from_serde_ext(&*config)?.unchecked_into())
|
|
391
|
+
})
|
|
392
|
+
}
|
|
393
|
+
|
|
307
394
|
/// Get the underlying [`Table`] for this viewer (as passed to
|
|
308
|
-
/// [`PerspectiveViewerElement::load`]
|
|
395
|
+
/// [`PerspectiveViewerElement::load`] or as the `table` field to
|
|
396
|
+
/// [`PerspectiveViewerElement::restore`]).
|
|
309
397
|
///
|
|
310
398
|
/// # Arguments
|
|
311
399
|
///
|
|
@@ -324,10 +412,40 @@ impl PerspectiveViewerElement {
|
|
|
324
412
|
ApiFuture::new(async move {
|
|
325
413
|
match session.get_table() {
|
|
326
414
|
Some(table) => Ok(table.into()),
|
|
327
|
-
None if !wait_for_table.unwrap_or_default() => Err("No
|
|
415
|
+
None if !wait_for_table.unwrap_or_default() => Err("No `Table` set".into()),
|
|
328
416
|
None => {
|
|
329
|
-
session.table_loaded.
|
|
330
|
-
Ok(session.get_table().ok_or("No
|
|
417
|
+
session.table_loaded.read_next().await?;
|
|
418
|
+
Ok(session.get_table().ok_or("No `Table` set")?.into())
|
|
419
|
+
},
|
|
420
|
+
}
|
|
421
|
+
})
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/// Get the underlying [`Client`] for this viewer (as passed to, or
|
|
425
|
+
/// associated with the [`Table`] passed to,
|
|
426
|
+
/// [`PerspectiveViewerElement::load`]).
|
|
427
|
+
///
|
|
428
|
+
/// # Arguments
|
|
429
|
+
///
|
|
430
|
+
/// - `wait_for_client` - whether to wait for
|
|
431
|
+
/// [`PerspectiveViewerElement::load`] to be called, or fail immediately
|
|
432
|
+
/// if [`PerspectiveViewerElement::load`] has not yet been called.
|
|
433
|
+
///
|
|
434
|
+
/// # JavaScript Examples
|
|
435
|
+
///
|
|
436
|
+
/// ```javascript
|
|
437
|
+
/// const client = await viewer.getClient();
|
|
438
|
+
/// ```
|
|
439
|
+
#[wasm_bindgen]
|
|
440
|
+
pub fn getClient(&self, wait_for_client: Option<bool>) -> ApiFuture<perspective_js::Client> {
|
|
441
|
+
let session = self.session.clone();
|
|
442
|
+
ApiFuture::new(async move {
|
|
443
|
+
match session.get_client() {
|
|
444
|
+
Some(client) => Ok(client.into()),
|
|
445
|
+
None if !wait_for_client.unwrap_or_default() => Err("No `Client` set".into()),
|
|
446
|
+
None => {
|
|
447
|
+
session.table_loaded.read_next().await?;
|
|
448
|
+
Ok(session.get_client().ok_or("No `Client` set")?.into())
|
|
331
449
|
},
|
|
332
450
|
}
|
|
333
451
|
})
|
|
@@ -369,14 +487,24 @@ impl PerspectiveViewerElement {
|
|
|
369
487
|
/// ```
|
|
370
488
|
pub fn flush(&self) -> ApiFuture<()> {
|
|
371
489
|
clone!(self.renderer);
|
|
372
|
-
ApiFuture::
|
|
490
|
+
ApiFuture::new_throttled(async move {
|
|
491
|
+
// We must let two AFs pass to guarantee listeners to the DOM state
|
|
492
|
+
// have themselves triggered, or else `request_animation_frame`
|
|
493
|
+
// may finish before a `ResizeObserver` triggered before is
|
|
494
|
+
// notifiedd.
|
|
495
|
+
//
|
|
496
|
+
// https://github.com/w3c/csswg-drafts/issues/9560
|
|
497
|
+
// https://html.spec.whatwg.org/multipage/webappapis.html#update-the-rendering
|
|
373
498
|
request_animation_frame().await;
|
|
499
|
+
request_animation_frame().await;
|
|
500
|
+
renderer.clone().with_lock(async { Ok(()) }).await?;
|
|
374
501
|
renderer.with_lock(async { Ok(()) }).await
|
|
375
502
|
})
|
|
376
503
|
}
|
|
377
504
|
|
|
378
505
|
/// Restores this element from a full/partial
|
|
379
|
-
/// [`perspective_js::JsViewConfig`]
|
|
506
|
+
/// [`perspective_js::JsViewConfig`] (this element's user-configurable
|
|
507
|
+
/// state, including the `Table` name).
|
|
380
508
|
///
|
|
381
509
|
/// One of the best ways to use [`Self::restore`] is by first configuring
|
|
382
510
|
/// a `<perspective-viewer>` as you wish, then using either the `Debug`
|
|
@@ -390,55 +518,70 @@ impl PerspectiveViewerElement {
|
|
|
390
518
|
///
|
|
391
519
|
/// # JavaScript Examples
|
|
392
520
|
///
|
|
393
|
-
///
|
|
394
|
-
///
|
|
521
|
+
/// Loads a default plugin for the table named `"superstore"`:
|
|
522
|
+
///
|
|
523
|
+
/// ```javascript
|
|
524
|
+
/// await viewer.restore({table: "superstore"});
|
|
525
|
+
/// ```
|
|
526
|
+
///
|
|
527
|
+
/// Apply a `group_by` to the same `viewer` element, without
|
|
528
|
+
/// modifying/resetting other fields - you can omit the `table` field,
|
|
529
|
+
/// this has already been set once and is not modified:
|
|
395
530
|
///
|
|
396
531
|
/// ```javascript
|
|
397
532
|
/// await viewer.restore({group_by: ["State"]});
|
|
398
533
|
/// ```
|
|
399
534
|
pub fn restore(&self, update: JsValue) -> ApiFuture<()> {
|
|
400
|
-
tracing::info!("Restoring ViewerConfig");
|
|
401
535
|
let this = self.clone();
|
|
402
|
-
ApiFuture::
|
|
536
|
+
ApiFuture::new_throttled(async move {
|
|
403
537
|
let decoded_update = ViewerConfigUpdate::decode(&update)?;
|
|
538
|
+
tracing::info!("Restoring {}", decoded_update);
|
|
404
539
|
let root = this.root.clone();
|
|
405
540
|
let settings = decoded_update.settings.clone();
|
|
406
|
-
let
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
.send_message_async(move |x| {
|
|
411
|
-
PerspectiveViewerMsg::ToggleSettingsComplete(settings, x)
|
|
412
|
-
});
|
|
541
|
+
let (sender, receiver) = channel::<()>();
|
|
542
|
+
root.borrow().as_ref().into_apierror()?.send_message(
|
|
543
|
+
PerspectiveViewerMsg::ToggleSettingsComplete(settings, sender),
|
|
544
|
+
);
|
|
413
545
|
|
|
414
|
-
let
|
|
415
|
-
.restore_and_render(decoded_update,
|
|
546
|
+
let result = this
|
|
547
|
+
.restore_and_render(decoded_update.clone(), {
|
|
548
|
+
clone!(this, decoded_update.table);
|
|
549
|
+
async move {
|
|
550
|
+
if let OptionalUpdate::Update(name) = table {
|
|
551
|
+
this.session.set_table(name).await?;
|
|
552
|
+
this.session
|
|
553
|
+
.update_column_defaults(&this.renderer.metadata());
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
// Something abnormal in the DOM happened, e.g. the
|
|
557
|
+
// element was disconnected while rendering.
|
|
558
|
+
receiver.await.unwrap_or_log();
|
|
559
|
+
Ok(())
|
|
560
|
+
}
|
|
561
|
+
})
|
|
416
562
|
.await;
|
|
417
563
|
|
|
418
|
-
if let Err(e) =
|
|
564
|
+
if let Err(e) = &result {
|
|
419
565
|
this.session().set_error(false, e.clone()).await?;
|
|
420
|
-
Err(e)
|
|
421
|
-
} else {
|
|
422
|
-
Ok(())
|
|
423
566
|
}
|
|
567
|
+
result
|
|
424
568
|
})
|
|
425
569
|
}
|
|
426
570
|
|
|
571
|
+
/// If this element is in an _errored_ state, this method will clear it and
|
|
572
|
+
/// re-render. Calling this method is equivalent to clicking the error reset
|
|
573
|
+
/// button in the UI.
|
|
427
574
|
pub fn resetError(&self) -> ApiFuture<()> {
|
|
428
|
-
self.session.
|
|
575
|
+
ApiFuture::spawn(self.session.reset(ResetOptions::default()));
|
|
429
576
|
let this = self.clone();
|
|
430
|
-
ApiFuture::
|
|
577
|
+
ApiFuture::new_throttled(async move {
|
|
431
578
|
this.update_and_render(ViewConfigUpdate::default())?.await?;
|
|
432
579
|
Ok(())
|
|
433
580
|
})
|
|
434
581
|
}
|
|
435
582
|
|
|
436
|
-
/// Save this element
|
|
437
|
-
/// via the [`Self::restore`] method.
|
|
438
|
-
///
|
|
439
|
-
/// # Arguments
|
|
440
|
-
///
|
|
441
|
-
/// - `format` - Supports "json" (default), "arraybuffer" or "string".
|
|
583
|
+
/// Save this element's user-configurable state to a serialized state
|
|
584
|
+
/// object, one which can be restored via the [`Self::restore`] method.
|
|
442
585
|
///
|
|
443
586
|
/// # JavaScript Examples
|
|
444
587
|
///
|
|
@@ -456,26 +599,25 @@ impl PerspectiveViewerElement {
|
|
|
456
599
|
/// await viewer.restore(token);
|
|
457
600
|
/// });
|
|
458
601
|
/// ```
|
|
459
|
-
pub fn save(&self
|
|
602
|
+
pub fn save(&self) -> ApiFuture<JsValue> {
|
|
460
603
|
let this = self.clone();
|
|
461
604
|
ApiFuture::new(async move {
|
|
462
|
-
let
|
|
463
|
-
|
|
464
|
-
.
|
|
465
|
-
.
|
|
466
|
-
.
|
|
605
|
+
let viewer_config = this
|
|
606
|
+
.renderer
|
|
607
|
+
.clone()
|
|
608
|
+
.with_lock(async { this.get_viewer_config().await })
|
|
609
|
+
.await?;
|
|
467
610
|
|
|
468
|
-
|
|
469
|
-
viewer_config.encode(&format)
|
|
611
|
+
viewer_config.encode()
|
|
470
612
|
})
|
|
471
613
|
}
|
|
472
614
|
|
|
473
|
-
/// Download this viewer's internal [`View`] data
|
|
615
|
+
/// Download this viewer's internal [`View`] data via a browser download
|
|
616
|
+
/// event.
|
|
474
617
|
///
|
|
475
618
|
/// # Arguments
|
|
476
619
|
///
|
|
477
|
-
/// - `
|
|
478
|
-
/// to generate this data, or use the default.
|
|
620
|
+
/// - `method` - The `ExportMethod` to use to render the data to download.
|
|
479
621
|
///
|
|
480
622
|
/// # JavaScript Examples
|
|
481
623
|
///
|
|
@@ -484,16 +626,58 @@ impl PerspectiveViewerElement {
|
|
|
484
626
|
/// await viewer.download();
|
|
485
627
|
/// })
|
|
486
628
|
/// ```
|
|
487
|
-
pub fn download(&self,
|
|
488
|
-
let
|
|
629
|
+
pub fn download(&self, method: Option<JsString>) -> ApiFuture<()> {
|
|
630
|
+
let this = self.clone();
|
|
631
|
+
ApiFuture::new_throttled(async move {
|
|
632
|
+
let method = if let Some(method) = method
|
|
633
|
+
.map(|x| x.unchecked_into())
|
|
634
|
+
.map(serde_wasm_bindgen::from_value)
|
|
635
|
+
{
|
|
636
|
+
method?
|
|
637
|
+
} else {
|
|
638
|
+
ExportMethod::Csv
|
|
639
|
+
};
|
|
640
|
+
|
|
641
|
+
let blob = this.export_method_to_blob(method).await?;
|
|
642
|
+
let is_chart = this.renderer.is_chart();
|
|
643
|
+
download(
|
|
644
|
+
format!("untitled{}", method.as_filename(is_chart)).as_ref(),
|
|
645
|
+
&blob,
|
|
646
|
+
)
|
|
647
|
+
})
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/// Exports this viewer's internal [`View`] as a JavaSript data, the
|
|
651
|
+
/// exact type of which depends on the `method` but defaults to `String`
|
|
652
|
+
/// in CSV format.
|
|
653
|
+
///
|
|
654
|
+
/// This method is only really useful for the `"plugin"` method, which
|
|
655
|
+
/// will use the configured plugin's export (e.g. PNG for
|
|
656
|
+
/// `@perspective-dev/viewer-d3fc`). Otherwise, prefer to call the
|
|
657
|
+
/// equivalent method on the underlying [`View`] directly.
|
|
658
|
+
///
|
|
659
|
+
/// # Arguments
|
|
660
|
+
///
|
|
661
|
+
/// - `method` - The `ExportMethod` to use to render the data to download.
|
|
662
|
+
///
|
|
663
|
+
/// # JavaScript Examples
|
|
664
|
+
///
|
|
665
|
+
/// ```javascript
|
|
666
|
+
/// const data = await viewer.export("plugin");
|
|
667
|
+
/// ```
|
|
668
|
+
pub fn export(&self, method: Option<JsString>) -> ApiFuture<JsValue> {
|
|
669
|
+
let this = self.clone();
|
|
489
670
|
ApiFuture::new(async move {
|
|
490
|
-
let
|
|
491
|
-
.
|
|
492
|
-
.
|
|
493
|
-
|
|
671
|
+
let method = if let Some(method) = method
|
|
672
|
+
.map(|x| x.unchecked_into())
|
|
673
|
+
.map(serde_wasm_bindgen::from_value)
|
|
674
|
+
{
|
|
675
|
+
method?
|
|
676
|
+
} else {
|
|
677
|
+
ExportMethod::Csv
|
|
678
|
+
};
|
|
494
679
|
|
|
495
|
-
|
|
496
|
-
download("untitled.csv", &val)
|
|
680
|
+
this.export_method_to_jsvalue(method).await
|
|
497
681
|
})
|
|
498
682
|
}
|
|
499
683
|
|
|
@@ -514,7 +698,7 @@ impl PerspectiveViewerElement {
|
|
|
514
698
|
/// ```
|
|
515
699
|
pub fn copy(&self, method: Option<JsString>) -> ApiFuture<()> {
|
|
516
700
|
let this = self.clone();
|
|
517
|
-
ApiFuture::
|
|
701
|
+
ApiFuture::new_throttled(async move {
|
|
518
702
|
let method = if let Some(method) = method
|
|
519
703
|
.map(|x| x.unchecked_into())
|
|
520
704
|
.map(serde_wasm_bindgen::from_value)
|
|
@@ -524,7 +708,7 @@ impl PerspectiveViewerElement {
|
|
|
524
708
|
ExportMethod::Csv
|
|
525
709
|
};
|
|
526
710
|
|
|
527
|
-
let js_task = this.
|
|
711
|
+
let js_task = this.export_method_to_blob(method);
|
|
528
712
|
copy_to_clipboard(js_task, MimeType::TextPlain).await
|
|
529
713
|
})
|
|
530
714
|
}
|
|
@@ -542,17 +726,17 @@ impl PerspectiveViewerElement {
|
|
|
542
726
|
/// await viewer.reset();
|
|
543
727
|
/// ```
|
|
544
728
|
pub fn reset(&self, reset_all: Option<bool>) -> ApiFuture<()> {
|
|
545
|
-
tracing::
|
|
729
|
+
tracing::debug!("Resetting config");
|
|
546
730
|
let root = self.root.clone();
|
|
547
731
|
let all = reset_all.unwrap_or_default();
|
|
548
|
-
ApiFuture::
|
|
549
|
-
let
|
|
550
|
-
|
|
732
|
+
ApiFuture::new_throttled(async move {
|
|
733
|
+
let (sender, receiver) = channel::<()>();
|
|
734
|
+
root.borrow()
|
|
551
735
|
.as_ref()
|
|
552
736
|
.ok_or("Already deleted")?
|
|
553
|
-
.
|
|
737
|
+
.send_message(PerspectiveViewerMsg::Reset(all, Some(sender)));
|
|
554
738
|
|
|
555
|
-
Ok(
|
|
739
|
+
Ok(receiver.await?)
|
|
556
740
|
})
|
|
557
741
|
}
|
|
558
742
|
|
|
@@ -584,8 +768,18 @@ impl PerspectiveViewerElement {
|
|
|
584
768
|
*self.resize_handle.borrow_mut() = None;
|
|
585
769
|
}
|
|
586
770
|
|
|
587
|
-
let
|
|
588
|
-
ApiFuture::
|
|
771
|
+
let state = self.clone_state();
|
|
772
|
+
ApiFuture::new_throttled(async move {
|
|
773
|
+
if !state.renderer().is_plugin_activated()? {
|
|
774
|
+
state
|
|
775
|
+
.update_and_render(ViewConfigUpdate::default())?
|
|
776
|
+
.await?;
|
|
777
|
+
} else {
|
|
778
|
+
state.renderer().resize().await?;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
Ok(())
|
|
782
|
+
})
|
|
589
783
|
}
|
|
590
784
|
|
|
591
785
|
/// Sets the auto-size behavior of this component.
|
|
@@ -614,7 +808,8 @@ impl PerspectiveViewerElement {
|
|
|
614
808
|
let handle = Some(ResizeObserverHandle::new(
|
|
615
809
|
&self.elem,
|
|
616
810
|
&self.renderer,
|
|
617
|
-
self.
|
|
811
|
+
&self.session,
|
|
812
|
+
&self.root,
|
|
618
813
|
));
|
|
619
814
|
*self.resize_handle.borrow_mut() = handle;
|
|
620
815
|
} else {
|
|
@@ -645,9 +840,11 @@ impl PerspectiveViewerElement {
|
|
|
645
840
|
if autopause {
|
|
646
841
|
let handle = Some(IntersectionObserverHandle::new(
|
|
647
842
|
&self.elem,
|
|
843
|
+
&self.presentation,
|
|
648
844
|
&self.session,
|
|
649
845
|
&self.renderer,
|
|
650
846
|
));
|
|
847
|
+
|
|
651
848
|
*self.intersection_handle.borrow_mut() = handle;
|
|
652
849
|
} else {
|
|
653
850
|
*self.intersection_handle.borrow_mut() = None;
|
|
@@ -666,7 +863,7 @@ impl PerspectiveViewerElement {
|
|
|
666
863
|
pub fn setSelection(&self, window: Option<JsViewWindow>) -> ApiResult<()> {
|
|
667
864
|
let window = window.map(|x| x.into_serde_ext()).transpose()?;
|
|
668
865
|
if self.renderer.get_selection() != window {
|
|
669
|
-
self.
|
|
866
|
+
self.custom_events.dispatch_select(window.as_ref())?;
|
|
670
867
|
}
|
|
671
868
|
|
|
672
869
|
self.renderer.set_selection(window);
|
|
@@ -742,8 +939,10 @@ impl PerspectiveViewerElement {
|
|
|
742
939
|
.cloned();
|
|
743
940
|
|
|
744
941
|
changed = presentation.set_theme_name(reset_theme.as_deref()).await? || changed;
|
|
745
|
-
if changed
|
|
746
|
-
|
|
942
|
+
if changed {
|
|
943
|
+
if let Some(view) = session.get_view() {
|
|
944
|
+
return renderer.restyle_all(&view).await;
|
|
945
|
+
}
|
|
747
946
|
}
|
|
748
947
|
|
|
749
948
|
Ok(JsValue::UNDEFINED)
|
|
@@ -789,13 +988,12 @@ impl PerspectiveViewerElement {
|
|
|
789
988
|
let root = self.root.clone();
|
|
790
989
|
ApiFuture::new(async move {
|
|
791
990
|
let force = force.map(SettingsUpdate::Update);
|
|
792
|
-
let
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
.send_message_async(|x| PerspectiveViewerMsg::ToggleSettingsInit(force, Some(x)));
|
|
991
|
+
let (sender, receiver) = channel::<ApiResult<wasm_bindgen::JsValue>>();
|
|
992
|
+
root.borrow().as_ref().into_apierror()?.send_message(
|
|
993
|
+
PerspectiveViewerMsg::ToggleSettingsInit(force, Some(sender)),
|
|
994
|
+
);
|
|
797
995
|
|
|
798
|
-
|
|
996
|
+
receiver.await.map_err(|_| JsValue::from("Cancelled"))?
|
|
799
997
|
})
|
|
800
998
|
}
|
|
801
999
|
|
|
@@ -826,7 +1024,7 @@ impl PerspectiveViewerElement {
|
|
|
826
1024
|
#[doc(hidden)]
|
|
827
1025
|
#[allow(clippy::use_self)]
|
|
828
1026
|
#[wasm_bindgen]
|
|
829
|
-
pub fn
|
|
1027
|
+
pub fn __get_model(&self) -> PerspectiveViewerElement {
|
|
830
1028
|
self.clone()
|
|
831
1029
|
}
|
|
832
1030
|
|
|
@@ -839,18 +1037,18 @@ impl PerspectiveViewerElement {
|
|
|
839
1037
|
#[wasm_bindgen]
|
|
840
1038
|
pub fn toggleColumnSettings(&self, column_name: String) -> ApiFuture<()> {
|
|
841
1039
|
clone!(self.session, self.root);
|
|
842
|
-
ApiFuture::
|
|
843
|
-
let locator = session.
|
|
844
|
-
let
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
.into_apierror()?
|
|
848
|
-
.send_message_async(|sender| PerspectiveViewerMsg::OpenColumnSettings {
|
|
1040
|
+
ApiFuture::new_throttled(async move {
|
|
1041
|
+
let locator = session.get_column_locator(Some(column_name));
|
|
1042
|
+
let (sender, receiver) = channel::<()>();
|
|
1043
|
+
root.borrow().as_ref().into_apierror()?.send_message(
|
|
1044
|
+
PerspectiveViewerMsg::OpenColumnSettings {
|
|
849
1045
|
locator,
|
|
850
1046
|
sender: Some(sender),
|
|
851
1047
|
toggle: true,
|
|
852
|
-
}
|
|
853
|
-
|
|
1048
|
+
},
|
|
1049
|
+
);
|
|
1050
|
+
|
|
1051
|
+
receiver.await.map_err(|_| ApiError::from("Cancelled"))
|
|
854
1052
|
})
|
|
855
1053
|
}
|
|
856
1054
|
|
|
@@ -862,19 +1060,19 @@ impl PerspectiveViewerElement {
|
|
|
862
1060
|
column_name: Option<String>,
|
|
863
1061
|
toggle: Option<bool>,
|
|
864
1062
|
) -> ApiFuture<()> {
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
let
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
.into_apierror()?
|
|
872
|
-
.send_message_async(|sender| PerspectiveViewerMsg::OpenColumnSettings {
|
|
1063
|
+
let locator = self.get_column_locator(column_name);
|
|
1064
|
+
clone!(self.root);
|
|
1065
|
+
ApiFuture::new_throttled(async move {
|
|
1066
|
+
let (sender, receiver) = channel::<()>();
|
|
1067
|
+
root.borrow().as_ref().into_apierror()?.send_message(
|
|
1068
|
+
PerspectiveViewerMsg::OpenColumnSettings {
|
|
873
1069
|
locator,
|
|
874
1070
|
sender: Some(sender),
|
|
875
1071
|
toggle: toggle.unwrap_or_default(),
|
|
876
|
-
}
|
|
877
|
-
|
|
1072
|
+
},
|
|
1073
|
+
);
|
|
1074
|
+
|
|
1075
|
+
receiver.await.map_err(|_| ApiError::from("Cancelled"))
|
|
878
1076
|
})
|
|
879
1077
|
}
|
|
880
1078
|
}
|