1#![no_std]
2use js::*;
3#[macro_use]
4extern crate alloc;
5use alloc::string::String;
6use alloc::sync::Arc;
7use alloc::vec::Vec;
8use spin::Mutex;
9
10pub type HTMLElement = f64;
11
12#[derive(Copy, Clone)]
13struct Destructable {
14 function: Option<JSFunction>,
15}
16
17pub trait CustomElement {
18 fn new(element: HTMLElement) -> Self
19 where
20 Self: core::marker::Sized + core::marker::Sync + core::marker::Send + 'static;
21 fn register(name: &str)
22 where
23 Self: core::marker::Sized + core::marker::Sync + core::marker::Send + 'static,
24 {
25 let construct = create_callback_1(|element| {
26 let el = Arc::new(Mutex::new(Self::new(element.into())));
27 let el1 = el.clone();
28 let el2 = el.clone();
29 let el3 = el.clone();
30
31 let destruct_connect = Arc::new(Mutex::new(Destructable { function: None }));
32 let connect = create_callback_0(move || {
33 el1.lock().connected();
34 });
35 destruct_connect.lock().function = Some(connect.into());
36
37 let destruct_attribute_change = Arc::new(Mutex::new(Destructable { function: None }));
38 let attribute_change = create_callback_3(move |name_obj, old_obj, new_obj| {
39 let name = cstr_to_string(name_obj as i32);
40 let old = if old_obj == -1.0 {
41 None
42 } else {
43 Some(cstr_to_string(old_obj as i32))
44 };
45 let new = if new_obj == -1.0 {
46 None
47 } else {
48 Some(cstr_to_string(new_obj as i32))
49 };
50 el3.lock().attribute_changed(name, old, new);
51 });
52
53 destruct_attribute_change.lock().function = Some(connect.into());
54
55 let destruct_disconnect = Arc::new(Mutex::new(Destructable { function: None }));
56 let destruct_disconnect2 = destruct_disconnect.clone();
57 let disconnect = create_callback_0(move || {
58 el2.lock().disconnected();
59 remove_callback(destruct_connect.lock().function.as_ref().unwrap().into());
60 remove_callback(destruct_disconnect.lock().function.as_ref().unwrap().into());
61 remove_callback(
62 destruct_attribute_change
63 .lock()
64 .function
65 .as_ref()
66 .unwrap()
67 .into(),
68 );
69 });
70 destruct_disconnect2.lock().function = Some(disconnect.into());
71
72 lazy_static::lazy_static! {
73 static ref FN: JSFunction= {
74 register_function(
75 r#"function(e,a,b,c){
76 e.addHooks(a,b,c);
77 }"#,
78 )
79 };};
80 FN.invoke_4(element, connect, disconnect, attribute_change);
81 });
82 let attrs = Self::observed_attributes().join(",");
83 lazy_static::lazy_static! {
84 static ref FN: JSFunction= {
85 register_function(
86 r#"function(construct,elementNamePtr, elementNameLen,attrNamesPtr,attrNamesLen){
87 const elementName = this.readUtf8FromMemory(elementNamePtr,elementNameLen);
88 const attrNames = this.readUtf8FromMemory(attrNamesPtr,attrNamesLen);
89 let attrs = attrNames.split(",");
90 class GeneratedCustomElement extends HTMLElement {
91 constructor() {
92 super();
93 construct(this);
94 }
95
96 static get observedAttributes() {
97 return attrs;
98 }
99
100 connectedCallback() {
101 self.connect();
102 }
103
104 disconnectedCallback() {
105 self.disconnect();
106 }
107
108 attributeChangedCallback(attributeName, oldValue, newValue) {
109 self.attributeChange(attributeName,oldValue,newValue)
110 }
111
112 addHooks(connect,disconnect,attributeChange){
113 self.connect = connect;
114 self.disconnect = disconnect;
115 self.attributeChange = attributeChange;
116 }
117 }
118
119 // tell the dom to associate it with an html tag name
120 customElements.define(elementName, GeneratedCustomElement);
121 }"#,
122 )
123 };};
124 FN.invoke_5(
125 construct,
126 name.as_ptr() as u32,
127 name.len() as u32,
128 attrs.as_ptr() as u32,
129 attrs.len() as u32,
130 );
131 }
132
133 fn observed_attributes() -> Vec<&'static str> {
134 vec![]
135 }
136
137 fn created(&mut self) {}
138 fn connected(&mut self) {}
139 fn disconnected(&mut self) {}
140 fn attribute_changed(
141 &mut self,
142 _name: String,
143 _old_value: Option<String>,
144 _new_value: Option<String>,
145 ) {
146 }
147}