use std::str::FromStr; use chrono::Locale; use gloo::utils::{document, window}; use wasm_bindgen::prelude::*; use web_sys::Element; pub trait SelectorExt { fn selector(&self, selectors: &str) -> T where T: JsCast; fn selector_all(&self, selectors: &str) -> Vec where T: JsCast; fn selector_upwards(&self, selector: &str) -> Option where T: JsCast; fn deep_clone(&self) -> Self; } impl SelectorExt for Element { fn selector(&self, selectors: &str) -> T where T: JsCast, { self.query_selector(selectors) .unwrap() .unwrap() .dyn_into::() .unwrap() } fn selector_all(&self, selectors: &str) -> Vec where T: JsCast, { self.query_selector_all(selectors) .unwrap() .values() .into_iter() .map(|e| e.unwrap().dyn_into::().unwrap()) .collect() } fn selector_upwards(&self, selector: &str) -> Option where T: JsCast, { let mut current = self.clone(); // while let Some(parent) = current.parent_element() { loop { if let Ok(true) = current.matches(selector) { return Some(current.dyn_into::().unwrap()); } if let Some(parent) = current.parent_element() { current = parent; } else { return None; } } } fn deep_clone(&self) -> Self { self.clone_node_with_deep(true) .unwrap() .dyn_into::() .unwrap() } } // Not used anymore. // pub trait NodeHelperExt { // fn is_parent(&self, child: &Node) -> bool; // } // impl NodeHelperExt for Node { // fn is_parent(&self, child: &Node) -> bool { // let mut node = child.clone(); // while let Some(parent) = node.parent_node() { // if &parent == self { // return true; // } // node = parent; // } // false // } // } pub fn selector(selectors: &str) -> T where T: JsCast, { document() .query_selector(selectors) .unwrap() .unwrap() .dyn_into::() .unwrap() } pub fn selector_all(selectors: &str) -> Vec where T: JsCast, { document() .query_selector_all(selectors) .unwrap() .values() .into_iter() .map(|e| e.unwrap().dyn_into::().unwrap()) .collect() } pub fn selector_and_clone(selectors: &str) -> T where T: JsCast, { document() .query_selector(selectors) .unwrap() .unwrap() .clone_node_with_deep(true) .unwrap() .dyn_into::() .unwrap() } pub fn by_id(element_id: &str) -> T where T: JsCast, { document() .get_element_by_id(element_id) .unwrap() .dyn_into::() .unwrap() } pub fn get_current_lang() -> String { selector::("html") .get_attribute("lang") .unwrap() .split("-") .next() .unwrap() .to_string() } pub fn get_locale() -> Locale { let lang_and_territory = selector::("html") .get_attribute("lang") .unwrap() .replace("-", "_"); Locale::from_str(&lang_and_territory).unwrap_or_default() } /// Extracts and remove some URL parameters from the current URL. pub fn extract_get_parameters(names: &[&str]) -> Vec<(String, String)> { let mut param_values = vec![]; let location = window().location(); if let Ok(search) = location.search() { if !search.is_empty() && search.starts_with('?') { let mut search_chars = search.chars(); search_chars.next(); // To remove the first character which is '?'. let mut new_search = String::with_capacity(search.len()); for kv in search_chars.as_str().split('&') { match kv.split('=').collect::>()[..] { [key, value] if names.contains(&key) => { param_values.push((key.to_string(), value.to_string())); } _ => { if !new_search.is_empty() { new_search.push('&'); } new_search.push_str(kv); } } } if !param_values.is_empty() { let mut new_url = location.pathname().unwrap(); if !new_search.is_empty() { new_url.push('?'); new_url.push_str(&new_search); } window() .history() .unwrap() .push_state_with_url(&JsValue::null(), "", Some(&new_url)) .unwrap(); } } } param_values }