Commit a49ec95
More callbacks
Changed files (1)
Diff
@@ -44,6 +44,7 @@ pub fn component_impl(attr: pm::TokenStream, item: pm::TokenStream) -> pm::Token let attach_js = format!("attachComponent{}", struct_name_ident); let detach_js = format!("detachComponent{}", struct_name_ident); let observed_js = format!("observedComponentAttribute{}", struct_name_ident);+ let changed_js = format!("changedComponentAttribute{}", struct_name_ident); let create_class_js_indent = Ident::new(&create_class_js, Span::call_site()); let init_self_js_ident = Ident::new(&init_self_js, Span::call_site());@@ -55,21 +56,26 @@ pub fn component_impl(attr: pm::TokenStream, item: pm::TokenStream) -> pm::Token attach_js.as_str(), detach_js.as_str(), observed_js.as_str(),+ changed_js.as_str(), ); let rs_self = gen_rust_self(component_struct_item.clone(), init_self_js_ident); let attach_fn = attach_quote(&attach_js, struct_name_ident); let detach_fn = detach_quote(&detach_js, struct_name_ident); let observed_fn = observed_quote(&observed_js, struct_name_ident);+ let changed_fn = changed_quote(&changed_js, struct_name_ident);+ let self_from_id = component_from_id(component_struct_item.clone()); let expanded = quote! { #global_store #rs_self #component_struct_item #create_js_class_fn- #attach_fn- #detach_fn- #observed_fn+ #attach_fn+ #detach_fn+ #observed_fn+ #self_from_id+ #changed_fn }; expanded.into()@@ -85,8 +91,8 @@ fn attach_quote(atach_state_js_fn: &str, struct_name: &Ident) -> proc_macro2::To let expanded = quote! { #[callback(#js_callback_ident)]- fn #rs_name_ident(element: HtmlElement, wasm_id: u32) {- gloo::console::log!("componentConnect generated wasm_id: {}", wasm_id);+ fn #rs_name_ident(element: HtmlElement, wasm_id: String) {+ gloo::console::log!("componentConnect generated wasm_id: {}", wasm_id.clone()); let mut store = #store_ident.write().unwrap(); @@ -100,7 +106,7 @@ fn attach_quote(atach_state_js_fn: &str, struct_name: &Ident) -> proc_macro2::To if let Some(component) = store_map.get_mut(&wasm_id) { component.connected(element); } else {- error!("Component id {} not found in connect.", wasm_id);+ error!("Component id {} not found in connect.", wasm_id.clone()); } } };@@ -118,7 +124,7 @@ fn detach_quote(detach_state_js_fn: &str, struct_name: &Ident) -> proc_macro2::T let expanded = quote! { #[callback(#js_callback_ident)]- fn #rs_name_ident(element: HtmlElement, wasm_id: u32) {+ fn #rs_name_ident(element: HtmlElement, wasm_id: String) { let mut store = #store_ident.write().unwrap(); if store.is_none() {@@ -131,7 +137,7 @@ fn detach_quote(detach_state_js_fn: &str, struct_name: &Ident) -> proc_macro2::T if let Some(component) = store_map.get_mut(&wasm_id) { component.disconnected(element); } else {- error!("Component id {} not found in disconnected.", wasm_id);+ error!("Component id {} not found in disconnected.", wasm_id.clone()); } store_map.remove(&wasm_id);@@ -141,6 +147,40 @@ fn detach_quote(detach_state_js_fn: &str, struct_name: &Ident) -> proc_macro2::T expanded } +fn changed_quote(changed_state_js_fn: &str, struct_name: &Ident) -> proc_macro2::TokenStream {+ let js_callback_ident = Ident::new(changed_state_js_fn, Span::call_site());+ let rs_name_str = from_pascal_to_snake(changed_state_js_fn);+ let rs_name_ident = Ident::new(&rs_name_str, Span::call_site());++ let store_name_str = store_name(struct_name);+ let store_ident = Ident::new(&store_name_str, Span::call_site());++ let expanded = quote! {+ #[callback(#js_callback_ident)]+ fn #rs_name_ident(element: HtmlElement, wasm_id: String, key: String, from: String, to: String) {+ let mut store = #store_ident.write().unwrap();++ if store.is_none() {+ error!("Component not found in connect.");+ return;+ }++ let store_map = store.as_mut().unwrap();++ if let Some(component) = store_map.get_mut(&wasm_id) {+ let name = key.as_str();+ let old_value = ::wasm_bindgen::JsValue::from_str(&from);+ let new_value = ::wasm_bindgen::JsValue::from_str(&to);+ component.attribute_changed(element, name, &old_value, &new_value);+ } else {+ error!("Component id {} not found in changed attribute.", wasm_id.clone());+ }+ }+ };++ expanded+}+ fn observed_quote(observed_js_fn: &str, struct_name: &Ident) -> proc_macro2::TokenStream { let js_callback_ident = Ident::new(observed_js_fn, Span::call_site()); let rs_name_str = from_pascal_to_snake(observed_js_fn);@@ -169,7 +209,7 @@ fn generate_component_store(struct_name: Ident) -> proc_macro2::TokenStream { let store_ident = Ident::new(&store_name, Span::call_site()); let expanded = quote! {- pub static #store_ident: std::sync::RwLock<Option<std::collections::HashMap<u32, #struct_name>>> = std::sync::RwLock::new(None);+ pub static #store_ident: std::sync::RwLock<Option<std::collections::HashMap<String, #struct_name>>> = std::sync::RwLock::new(None); }; expanded@@ -193,6 +233,18 @@ fn from_pascal_to_snake(fn_name: &str) -> String { result } +fn component_from_id(struct_item: ItemStruct) -> proc_macro2::TokenStream {+ let struct_ident = &struct_item.ident;+ let expanded = quote! {+ pub fn get_counter() -> #struct_ident { // returns an instance of the component+ log!("Get counter");+ #struct_ident::default()+ }+ };++ expanded+}+ fn gen_rust_self(struct_item: ItemStruct, js_name: Ident) -> proc_macro2::TokenStream { let struct_ident = &struct_item.ident; let store_name_str = store_name(struct_ident);@@ -208,7 +260,7 @@ fn gen_rust_self(struct_item: ItemStruct, js_name: Ident) -> proc_macro2::TokenS let expanded = quote! { #[callback(#js_name)] #[allow(non_snake_case)]- pub fn #rust_ident() -> u32 { // init_component_state_struct_name, returns id for the instance of the element+ pub fn #rust_ident() -> String { // init_component_state_struct_name, returns id for the instance of the element log!("Run counter init rs state."); let mut counter = #struct_ident::default(); let wasm_id = ::kaja_web::NEXT_COMPONENT_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed); let mut store = #store_ident.write().expect("failed to acquire write lock");@@ -217,9 +269,10 @@ fn gen_rust_self(struct_item: ItemStruct, js_name: Ident) -> proc_macro2::TokenS *store = Some(std::collections::HashMap::new()); } + let key = wasm_id.to_string(); let store_map = store.as_mut().unwrap();- store_map.insert(wasm_id, counter);- wasm_id+ store_map.insert(key.clone(), counter);+ key } }; @@ -233,6 +286,7 @@ fn create_class( attach_state_fn: &str, detach_state_fn: &str, observed_fn: &str,+ change_fn: &str, ) -> proc_macro2::TokenStream { let name_str_lit = LitStr::new(&class_creator.to_string(), Span::call_site()); @@ -254,23 +308,30 @@ fn create_class( return class extends HTMLElement { constructor() { super();- this.kajaComponentId = -1;+ this.setAttribute("componentId", "-1"); } connectedCallback() {- if (this.kajaComponentId === -1) {- this.kajaComponentId = __INIT_CALLBACK();+ let componentId = this.getAttribute("componentId");++ if (componentId === "-1") {+ let id = __INIT_CALLBACK();+ this.setAttribute("componentId", id);+ componentId = id; } - __ATTACH_CALLBACK(this, this.kajaComponentId);+ __ATTACH_CALLBACK(this, componentId); } disconnectedCallback() {- __DETACH_CALLBACK(this, this.kajaComponentId);+ let componentId = this.getAttribute("componentId");+ __DETACH_CALLBACK(this, componentId); } attributeChangedCallback(name, oldValue, newValue) {- //callbacks.attributeChanged(this, name, oldValue, newValue);+ let componentId = this.getAttribute("componentId");+ console.log(componentId, name, oldValue, newValue);+ __ATTRIBUTE_CHANGED_CALLBACK(this, componentId, name, oldValue === null ? "" : String(oldValue), newValue === null ? "" : String(newValue)); } static get observedAttributes() {@@ -283,6 +344,7 @@ fn create_class( let js_init_with_state = js_init.replace("__INIT_CALLBACK", #init_self_fn); let js_init_with_state = js_init_with_state.replace("__ATTACH_CALLBACK", #attach_state_fn); let js_init_with_state = js_init_with_state.replace("__DETACH_CALLBACK", #detach_state_fn);+ let js_init_with_state = js_init_with_state.replace("__ATTRIBUTE_CHANGED_CALLBACK", #change_fn); let js_init_with_state = js_init_with_state.replace("__OBSERVED_CALLBACK", #observed_fn); let component = js_sys::Function::new_no_args(js_init_with_state.as_str());