Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optional lazy-load monaco-editor #1435

Merged
merged 1 commit into from
Jun 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion packages/perspective-viewer/test/html/superstore.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@
<link rel='stylesheet' href="demo.css">

<style>
perspective-expression-editor{--monaco-cursor--visibility: hidden}
perspective-expression-editor{
--monaco-cursor--visibility: hidden;
--monaco-container--appearance: none;
}
</style>

</head>
Expand Down
89 changes: 46 additions & 43 deletions packages/perspective-viewer/test/js/expressions.spec.js

Large diffs are not rendered by default.

18 changes: 9 additions & 9 deletions packages/perspective-viewer/test/results/linux.docker.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
"Computed_Expressions_On_restore,_computed_expressions_in_classic_syntax_are_parsed_correctly_": "563f8c45e0ec32bc4b07d30ed5f0086e",
"superstore_adds_computed_column_via_attribute": "f2fa526d6f0c168a47ab272bb7ae5771",
"superstore_user_defined_aggregates_maintained_on_computed_columns": "c7aa2902feb512ceb1e1487de80878ff",
"__GIT_COMMIT__": "c77ae83b4a840f9c60ba3da34ea90c1feaee38cd",
"__GIT_COMMIT__": "1eeeea911f9ef08585458fea4a2198c6a57cdc83",
"blank_Handles_reloading_with_a_schema_": "2f23d1416fc97e07a3a21e318411e0d1",
"superstore_doesn_t_leak_tables_": "5bb762b2860eb5af067bb83afbca3264",
"superstore_doesn_t_leak_elements_": "b8a3a84406fede4823cd51e07b817752",
Expand Down Expand Up @@ -94,17 +94,17 @@
"filters_less_than_ISO_string_on_datetime_column": "b7a0f123b4d5dea1b710aeea7e61572a",
"filters_less_than_US_locale_string_on_datetime_column": "13e4f63b1060272bff4f01382e565e82",
"blank_Should_load_a_promise_to_a_table_": "a3841665c5fc438c5e959c9858540744",
"Expressions_click_on_add_column_button_opens_the_expression_UI_": "0eb6fb6312adddde553da66ea779a199",
"Expressions_click_on_add_column_button_opens_the_expression_UI_": "50616a9c0d43b340b36deca1aa69ebd9",
"Expressions_click_on_close_button_closes_the_expression_UI_": "a02605db902dc06ea824fb013117ae6b",
"Expressions_An_expression_with_unknown_symbols_should_disable_the_save_button": "814e9ec49bcc1ef42798e18672fec935",
"Expressions_A_type-invalid_expression_should_disable_the_save_button": "3cc28cf98237a83906f10f43c3b535e7",
"Expressions_An_expression_with_invalid_input_columns_should_disable_the_save_button": "1b8ea24d9852a7c819094f605cdaeaed",
"Expressions_An_expression_with_unknown_symbols_should_disable_the_save_button": "6caf7343204eeb2ede8ffb4fb774b196",
"Expressions_A_type-invalid_expression_should_disable_the_save_button": "999387fecc94a112cefa4de79502bb29",
"Expressions_An_expression_with_invalid_input_columns_should_disable_the_save_button": "bbe27f53050713f77dc5aa5364e7eb64",
"Expressions_Should_show_the_help_panel": "dc16ac2736a46205fa13a30cc2842510",
"Expressions_Non-aliased_expressions_should_have_autogenerated_alias": "0478c89a614c402083c7bf0eca48a66d",
"Expressions_Should_skip_if_trying_to_set_an_expression_without_an_alias": "d13e8556321b0a8bbbf5122ce4f95754",
"Expressions_Should_prevent_saving_a_duplicate_expression_alias": "c81d4acdf520022350547c4840e54cd0",
"Expressions_Should_not_prevent_saving_a_duplicate_expression_with_a_different_alias": "ba4431523a591e5043517e4c21407efb",
"Expressions_Should_prevent_saving_a_duplicate_expression": "81726370ce7b0df8f31ed5ab2bdcb57f",
"Expressions_Should_prevent_saving_a_duplicate_expression_alias": "fe8d36b483dff4c7be193b22157fbc49",
"Expressions_Should_not_prevent_saving_a_duplicate_expression_with_a_different_alias": "4ed53b7ffe61c1e4106c0eac364c85c9",
"Expressions_Should_prevent_saving_a_duplicate_expression": "d872a132fe9d537bbe82e90069ee53b7",
"Expressions_Removing_expressions_should_reset_active_columns,_pivots,_sort,_and_filter_": "e31a7da6f65bf5edc7d6582a4514a069",
"Expressions_Resetting_the_viewer_with_expressions_should_place_columns_in_the_inactive_list_": "17722593bb3bc9564a29edf1859c6951",
"Expressions_Resetting_the_viewer_with_columns_in_active_columns_should_reset_columns_but_not_delete_columns_": "17722593bb3bc9564a29edf1859c6951",
Expand All @@ -114,7 +114,7 @@
"Expressions_saving_without_an_expression_should_fail_as_button_is_disabled_": "462c0e101f72c021987def75335a967c",
"Expressions_saving_a_single_expression_should_add_it_to_inactive_columns_": "28d815bfccfcd54f6f2ed6b683d86055",
"Expressions_saving_multiple_expressions_should_add_it_to_inactive_columns_": "74b4a63079bc47b9809a92967335d3bf",
"Expressions_Expression_columns_should_persist_when_new_views_are_created_": "dc191c6687d9c821fe6932ddcdb8e781",
"Expressions_Expression_columns_should_persist_when_new_views_are_created_": "be86fb256ffd0a0aadc4c793b89e8404",
"Expressions_Expression_columns_should_persist_when_new_columns_are_added_": "951b31155154d97badbda8dea3a28feb",
"Expressions_aggregates_by_expression_column_": "e7ba48d18a68dd96282d79fc0ba609bd",
"Expressions_sets_column_attribute_with_expression_column_": "516a4292d1784b97fe4de8fa37483e4f",
Expand Down
14 changes: 14 additions & 0 deletions packages/perspective-webpack-plugin/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,20 @@ class PerspectiveWebpackPlugin {
if (this.options.inline || this.options.inlineWorker) {
rules[rules.length - 2].use.options.inline = "no-fallback";
rules[rules.length - 1].use.options.inline = "no-fallback";
} else {
rules.push({
test: /\.js$/,
include: /@finos\/perspective\-vieux/,
use: [
{
loader: "string-replace-loader",
options: {
search: /webpackMode:\s*?"eager"/g,
replace: ""
}
}
]
});
}

if (!(this.options.inline || this.options.inlineWasm)) {
Expand Down
1 change: 0 additions & 1 deletion rust/perspective-vieux/src/js/vieux.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

import init, * as internal from "../../pkg/perspective_vieux.js";
import wasm_internal from "../../pkg/perspective_vieux_bg.wasm";
import "./monaco.js";

export const wasm = init(wasm_internal).then(() => {
internal.set_panic_hook();
Expand Down
11 changes: 10 additions & 1 deletion rust/perspective-vieux/src/less/expression-editor.less
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,16 @@
box-shadow: 0 2px 4px 0 rgb(0 0 0 / 10%);
user-select: none;
background-color: white;


#monaco-container {
width:400px;
height:200px;
resize:both;
overflow:auto;
&::-webkit-resizer {
appearance: var(--monaco-container--appearance, auto);
}
}
.monaco-editor .cursors-layer .cursor {
visibility: var(--monaco-cursor--visibility, inherit) !important;
}
Expand Down
110 changes: 66 additions & 44 deletions rust/perspective-vieux/src/rust/components/expression_editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use crate::utils::monaco::*;
use crate::{exprtk::*, session::Session};

use std::rc::Rc;
use std::{cell::RefCell, rc::Rc};

use wasm_bindgen::{prelude::*, JsCast};
use wasm_bindgen_futures::future_to_promise;
Expand All @@ -29,22 +29,25 @@ pub enum ExpressionEditorMsg {

#[derive(Properties, Clone)]
pub struct ExpressionEditorProps {
pub callback: Rc<dyn Fn(JsValue)>,
pub on_save_callback: Rc<dyn Fn(JsValue)>,
pub on_init_callback: Rc<dyn Fn()>,
pub on_validate_callback: Rc<dyn Fn(bool)>,
pub session: Session,
}

/// A label widget which displays a row count and a "projection" count, the number of
/// rows in the `View` which includes aggregate rows.
#[derive(Clone)]
pub struct ExpressionEditor {
top: u32,
left: u32,
container: NodeRef,
editor: Option<MonacoEditor>,
editor: Rc<RefCell<Option<MonacoEditor>>>,
props: ExpressionEditorProps,
link: ComponentLink<Self>,
save_enabled: bool,
on_validate_callback: Closure<dyn Fn(JsValue)>,
on_save_callback: Closure<dyn Fn(JsValue)>,
on_validate_callback: Rc<Closure<dyn Fn(JsValue)>>,
on_save_callback: Rc<Closure<dyn Fn(JsValue)>>,
}

async fn proc(
Expand All @@ -65,20 +68,22 @@ impl Component for ExpressionEditor {

fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
let cb = link.callback(|x| ExpressionEditorMsg::Validate(x));
let on_validate_callback = Closure::wrap(Box::new(move |x| {
let on_validate_callback = Rc::new(Closure::wrap(Box::new(move |x| {
cb.emit(x);
}) as Box<dyn Fn(JsValue)>);
})
as Box<dyn Fn(JsValue)>));

let cb = link.callback(|_| ExpressionEditorMsg::SaveExpr);
let on_save_callback = Closure::wrap(Box::new(move |x| {
let on_save_callback = Rc::new(Closure::wrap(Box::new(move |x| {
cb.emit(x);
}) as Box<dyn Fn(JsValue)>);
})
as Box<dyn Fn(JsValue)>));

ExpressionEditor {
top: 0,
left: 0,
container: NodeRef::default(),
editor: None,
editor: Rc::new(RefCell::new(None)),
props,
link,
save_enabled: false,
Expand All @@ -92,7 +97,7 @@ impl Component for ExpressionEditor {
ExpressionEditorMsg::SetPos(top, left) => {
self.top = top;
self.left = left;
match self.editor.as_ref() {
match self.editor.borrow().as_ref() {
Some(x) => x.set_value(""),
None => {}
}
Expand All @@ -101,7 +106,8 @@ impl Component for ExpressionEditor {
}
ExpressionEditorMsg::Validate(_val) => {
// web_sys::console::log_1(&val);
let expr = self.editor.as_ref().unwrap().get_value();
let expr = self.editor.borrow().as_ref().unwrap().get_value();
(self.props.on_validate_callback)(true);
let callback = self
.link
.callback_once(|x| ExpressionEditorMsg::EnableSave(x));
Expand All @@ -110,16 +116,17 @@ impl Component for ExpressionEditor {
false
}
ExpressionEditorMsg::EnableSave(x) => {
(self.props.on_validate_callback)(false);
self.save_enabled = x;
true
}
ExpressionEditorMsg::SaveExpr => {
if self.save_enabled {
match self.editor.as_ref() {
match self.editor.borrow().as_ref() {
None => {}
Some(x) => {
let expr = x.get_value();
(self.props.callback)(expr);
(self.props.on_save_callback)(expr);
x.set_value("");
}
}
Expand All @@ -135,35 +142,50 @@ impl Component for ExpressionEditor {

fn rendered(&mut self, first_render: bool) {
if first_render {
init_monaco().unwrap();
let args = EditorArgs {
theme: "exprtk-theme",
value: "",
language: "exprtk",
automatic_layout: true,
minimap: MinimapArgs { enabled: false },
};

let container = self.container.cast::<HtmlElement>().unwrap();
let editor = Editor::create(container, JsValue::from_serde(&args).unwrap());
editor.add_command(
(KeyMod::Shift as u32) | (KeyCode::Enter as u32),
self.on_save_callback.as_ref().unchecked_ref(),
);

let model = editor.get_model();
model.on_did_change_content(
self.on_validate_callback.as_ref().unchecked_ref(),
);

self.editor = Some(editor.clone());
let on_init = Closure::once_into_js(move || editor.focus());
web_sys::window()
.unwrap()
.request_animation_frame(on_init.unchecked_ref())
.unwrap();
} else {
self.editor.as_ref().unwrap().focus();
let this = self.clone();
let _ = future_to_promise(async move {
let editor = init_monaco().await.unwrap();
let args = EditorArgs {
theme: "exprtk-theme",
value: "",
language: "exprtk",
automatic_layout: true,
minimap: MinimapArgs { enabled: false },
};

let container = this.container.cast::<HtmlElement>().unwrap();
let editor =
editor.create(container, JsValue::from_serde(&args).unwrap());
editor.add_command(
(KeyMod::Shift as u32) | (KeyCode::Enter as u32),
this.on_save_callback.as_ref().as_ref().unchecked_ref(),
);

let model = editor.get_model();
model.on_did_change_content(
this.on_validate_callback.as_ref().as_ref().unchecked_ref(),
);

*this.editor.borrow_mut() = Some(editor.clone());
let on_init_callback = this.props.on_init_callback.clone();
let on_init = Closure::once_into_js(move || {
editor.focus();
web_sys::window()
.unwrap()
.request_animation_frame(
Closure::once_into_js(move || on_init_callback())
.unchecked_ref(),
)
.unwrap();
});

web_sys::window()
.unwrap()
.request_animation_frame(on_init.unchecked_ref())
.map(JsValue::from)
});
} else if self.editor.borrow().is_some() {
self.editor.borrow().as_ref().unwrap().focus();
}
}

Expand All @@ -175,7 +197,7 @@ impl Component for ExpressionEditor {
{ &CSS }
{ format!(":host{{left:{}px;top:{}px;}}", self.left, self.top) }
</style>
<div ref={ self.container.clone() } style="width:400px;height:200px;resize:both;overflow:auto"></div>
<div id="monaco-container" ref={ self.container.clone() } style=""></div>
<div id="psp-expression-editor-actions">
<button
id="psp-expression-editor-button-save"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,21 @@ impl ResizableMessage for <ExpressionEditor as Component>::Message {

impl PerspectiveExpressionEditorElement {
pub fn new(
target: HtmlElement,
custom_element: HtmlElement,
session: Session,
callback: Rc<dyn Fn(JsValue)>,
on_save_callback: Rc<dyn Fn(JsValue)>,
on_init_callback: Rc<dyn Fn()>,
on_validate_callback: Rc<dyn Fn(bool)>,
) -> PerspectiveExpressionEditorElement {
let props = ExpressionEditorProps { callback, session };
let modal = ModalElement::new(target, props);
PerspectiveExpressionEditorElement {
modal,
}
let props = ExpressionEditorProps {
on_save_callback,
on_init_callback,
on_validate_callback,
session,
};

let modal = ModalElement::new(custom_element, props);
PerspectiveExpressionEditorElement { modal }
}

pub fn open(&mut self, target: HtmlElement) -> Result<(), JsValue> {
Expand Down
Loading