Skip to content

Commit 427e99c

Browse files
committed
Load components from within JS
1 parent ed0f166 commit 427e99c

File tree

5 files changed

+60
-17
lines changed

5 files changed

+60
-17
lines changed

src/class.rs

+23-2
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,31 @@ impl JsClassStorage {
4646
out
4747
})
4848
}
49+
pub(crate) fn preloaded(&mut self, name: &str) -> Option<JsClassHandle> {
50+
if let Some(class) = self.find_by_name(name) {
51+
return Some(class);
52+
}
53+
if svelte_component_exists(name) {
54+
let index = self.data.len();
55+
let class = JsClass {
56+
name: name.to_string(),
57+
};
58+
self.data.push(class);
59+
let class_handle = JsClassHandle { index };
60+
return Some(class_handle);
61+
}
62+
None
63+
}
64+
fn find_by_name(&self, name: &str) -> Option<JsClassHandle> {
65+
self.data
66+
.iter()
67+
.position(|ch| ch.name == name)
68+
.map(|index| JsClassHandle { index })
69+
}
4970
}
5071

5172
impl JsClass {
52-
pub fn attach_new_instance(&self, node: &HtmlElement) {
53-
instantiate_class(&self.name, node);
73+
pub(crate) fn attach_new_instance(&self, node: &HtmlElement) {
74+
instantiate_svelte_component(&self.name, node);
5475
}
5576
}

src/class/class_loader.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export function instantiate_svelte_component(className, target) {
2+
new window.__div_rs.svcom[className]({ target, props: {} });
3+
}
4+
export function loading_progress() {
5+
return window.__div_rs.loaded || 0;
6+
}
7+
export function init_div_rs() {
8+
window.__div_rs = window.__div_rs || { svcom: {}, loaded: 0 };
9+
}
10+
11+
export function svelte_component_exists(name) {
12+
return window.__div_rs.svcom[name] !== undefined;
13+
}

src/class/load.rs

+9-6
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,24 @@ use wasm_bindgen::prelude::*;
66
use wasm_bindgen::JsCast;
77
use web_sys::{HtmlElement, HtmlScriptElement};
88

9-
#[wasm_bindgen(module = "/src/class_loader.js")]
9+
#[wasm_bindgen(module = "/src/class/class_loader.js")]
1010
extern "C" {
11-
pub(super) fn instantiate_class(a: &str, node: &HtmlElement);
11+
pub(super) fn instantiate_svelte_component(a: &str, node: &HtmlElement);
1212
fn loading_progress() -> i32;
13+
pub(super) fn svelte_component_exists(name: &str) -> bool;
14+
pub fn init_div_rs();
1315
}
1416

1517
static LOADED: AtomicI32 = AtomicI32::new(0);
1618

1719
pub(super) fn build_class_loading_module(classes: &[&str], src: &str) -> String {
1820
let mut code = format!(
19-
"import {{{}}} from '{}';\nwindow.panes = window.panes || {{}};",
21+
"import {{{}}} from '{}';\nwindow.__div_rs = window.__div_rs || {{svcom: {{}}, loaded: 0}};",
2022
classes.join(", "),
2123
src
2224
);
2325
for class_name in classes {
24-
code += "\nwindow.panes.";
26+
code += "\nwindow.__div_rs.svcom.";
2527
code += class_name;
2628
code += " = classes.";
2729
code += class_name;
@@ -30,6 +32,7 @@ pub(super) fn build_class_loading_module(classes: &[&str], src: &str) -> String
3032
code
3133
}
3234

35+
/// **Experimental: This API is experimental and my not be included in later versions**
3336
/// Asynchronously loads a JS module by appending a script tag to the head with th e provided string as content.
3437
/// Poll the future until it resolves to know when the script has been loaded for sure.
3538
/// In contrast to the more conventional Future design, the JS module will be loaded even if the Future is not polled.
@@ -42,8 +45,8 @@ pub fn load_js_module(mut code: String) -> Result<PendingScript, PanesError> {
4245
.dyn_into()
4346
.map_err(|_| PanesError::JsCastError)?;
4447
script.set_attribute("type", "module")?;
45-
code += "\nwindow.panes = window.panes || {};";
46-
code += "\nwindow.panes.____loaded = (window.panes.____loaded || 0) + 1;";
48+
code += "\nwindow.__div_rs = window.__div_rs || {};";
49+
code += "\nwindow.__div_rs.loaded = (window.panes.loaded || 0) + 1;";
4750
script.set_text(&code)?;
4851

4952
let head = doc.head().ok_or(PanesError::MissingHead)?;

src/class_loader.js

-7
This file was deleted.

src/lib.rs

+15-2
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ pub fn init_ex(
4848
zoom: (1.0, 1.0),
4949
classes: JsClassStorage::default(),
5050
})?;
51-
add_panes_styles_to_document()
51+
add_panes_styles_to_document()?;
52+
init_div_rs();
53+
Ok(())
5254
}
5355

5456
fn get_root(id: Option<&str>) -> Result<Element, PanesError> {
@@ -122,9 +124,11 @@ where
122124
state::exec_mut(|state| state.new_pane(x, y, w, h, html, &classes_str, &css_str))
123125
}
124126

127+
/// **Experimental: This API is experimental and my not be included in later versions**
125128
/// Load a class named `name` from a JS file accessible at `src`.
126129
///
127-
/// Returns a Vanilla Future that will have to be handled in one way or another.
130+
/// Returns a Future because the script is loaded asynchronously.
131+
/// That future will have to be handled in one way or another.
128132
/// The most direct way would be to use `wasm_bindgen_futures::spawn_local`
129133
/// ## Example
130134
/// ```rust
@@ -146,6 +150,7 @@ pub fn load_js_class(
146150
Ok(async { classes.await[0] })
147151
}
148152

153+
/// **Experimental: This API is experimental and my not be included in later versions**
149154
/// Attempts to load a JS module by its source path and loads the classes exported by it, as named by the classes parameter.
150155
/// Usage is equivalent to `load_js_class`.
151156
pub fn load_js_classes(
@@ -170,3 +175,11 @@ pub fn from_js_class(
170175
class.attach_new_instance(&node);
171176
Ok(ph)
172177
}
178+
179+
impl JsClass {
180+
/// Load a JS class that has already been registered, usually by JS code.
181+
/// Return None if no such class has been registered.
182+
pub fn preregistered(name: &str) -> Option<JsClassHandle> {
183+
state::exec_mut(|state| Ok(state.classes.preloaded(name))).unwrap()
184+
}
185+
}

0 commit comments

Comments
 (0)