From e55462774ca73adc9261f039b5ac12ef62af57e8 Mon Sep 17 00:00:00 2001 From: Stuart Hinson Date: Sat, 26 Oct 2024 14:40:52 -0400 Subject: [PATCH 1/2] add get_attributes --- src/lib.rs | 28 ++++++++++++++++++++++++++++ src/mesdoc/interface/element.rs | 1 + 2 files changed, 29 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index cb6b53d..569b5a7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -628,6 +628,34 @@ impl IElementTrait for Rc> { None } + fn get_attributes(&self) -> Vec<(String, IAttrValue)> { + let node = &self.borrow(); + let meta = node + .meta + .as_ref() + .expect("Element node must have a meta field."); + + let attrs = &meta.borrow().attrs; + + let attr_map = &meta.borrow().lc_name_map; + + attr_map + .iter() + .map(|(name, index)| { + let attr = &attrs[*index]; + if let Some(value) = &attr.value { + let attr_value = value.content.clone(); + ( + name.clone(), + IAttrValue::Value(attr_value.iter().collect(), attr.quote), + ) + } else { + (name.clone(), IAttrValue::True) + } + }) + .collect() + } + /// impl `set_attribute` fn set_attribute(&mut self, name: &str, value: Option<&str>) { let mut need_quote = false; diff --git a/src/mesdoc/interface/element.rs b/src/mesdoc/interface/element.rs index 283b412..239ea9f 100644 --- a/src/mesdoc/interface/element.rs +++ b/src/mesdoc/interface/element.rs @@ -296,6 +296,7 @@ pub trait IElementTrait: INodeTrait { fn children_by<'a>(&'a self, matcher: Box); // attribute fn get_attribute(&self, name: &str) -> Option; + fn get_attributes(&self) -> Vec<(String, IAttrValue)>; fn set_attribute(&mut self, name: &str, value: Option<&str>); fn remove_attribute(&mut self, name: &str); fn has_attribute(&self, name: &str) -> bool { From 093f16921000670285129ced90060f06a4b92437 Mon Sep 17 00:00:00 2001 From: fefit Date: Sun, 27 Oct 2024 17:44:26 +0800 Subject: [PATCH 2/2] feat: add tests for get_attributes method and keep the attributes order --- src/lib.rs | 21 ++++++++++++--------- tests/attr.rs | 25 ++++++++++++++++++++++--- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 569b5a7..f0a7076 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,6 +35,7 @@ use rphtml::{ }, }; use std::borrow::Cow; +use std::collections::BTreeMap; use std::rc::Rc; use std::{any::Any, cell::RefCell}; // re export `IAttrValue` `IEnumTyped` `INodeType` @@ -634,23 +635,25 @@ impl IElementTrait for Rc> { .meta .as_ref() .expect("Element node must have a meta field."); - let attrs = &meta.borrow().attrs; - - let attr_map = &meta.borrow().lc_name_map; - - attr_map + let attr_map = meta + .borrow() + .lc_name_map .iter() - .map(|(name, index)| { - let attr = &attrs[*index]; + .map(|(name, index)| (*index, name.clone())) + .collect::>(); + attr_map + .into_iter() + .map(|(index, name)| { + let attr = &attrs[index]; if let Some(value) = &attr.value { let attr_value = value.content.clone(); ( - name.clone(), + name, IAttrValue::Value(attr_value.iter().collect(), attr.quote), ) } else { - (name.clone(), IAttrValue::True) + (name, IAttrValue::True) } }) .collect() diff --git a/tests/attr.rs b/tests/attr.rs index 4fa8615..c675c33 100644 --- a/tests/attr.rs +++ b/tests/attr.rs @@ -6,9 +6,9 @@ type Result = StdResult<(), BoxDynError>; #[test] fn test_normal_attr() -> Result { const ATTR_NAME: &str = "contenteditable"; - const HTML: &str = r#"
"#; + const HTML: &str = r#"
"#; let root = Vis::load(HTML)?; - let mut div = root.children("div"); + let mut div = root.children("div.first"); // has attribute assert!(div.has_attr(ATTR_NAME)); assert!(!div.has_attr("content")); @@ -29,12 +29,31 @@ fn test_normal_attr() -> Result { assert!(value.as_ref().unwrap().to_string() == ""); assert!(value.as_ref().unwrap().to_list().is_empty()); // always get the first appeared attribute - let input = div.children("input"); + let mut input = div.children("input"); let value = input.attr("type"); assert!(value.is_some()); assert!(value.as_ref().unwrap().is_str("text")); assert!(value.as_ref().unwrap().to_string() == "text"); assert_eq!(value.as_ref().unwrap().to_list(), vec!["text"]); + input.set_attr("type", Some("file")); + assert!(input.attr("type").unwrap().is_str("file")); + // attributes + let attrs_div = root.children("div.test-attrs"); + let div = attrs_div.get(0).unwrap(); + let attrs = div.get_attributes(); + assert_eq!(attrs.len(), 4); + let attr_1 = &attrs[0]; + assert_eq!(attr_1.0, String::from("class")); + assert!(attr_1.1.is_str("test-attrs")); + let attr_2 = &attrs[1]; + assert_eq!(attr_2.0, String::from("draggable")); + assert!(attr_2.1.is_true()); + let attr_3 = &attrs[2]; + assert_eq!(attr_3.0, String::from("data-type")); + assert!(attr_3.1.is_str("link")); + let attr_4 = &attrs[3]; + assert_eq!(attr_4.0, String::from("name")); + assert!(attr_4.1.is_str("cool")); // ignore attribute cases: issue #2 let html: &str = r#""#; let root = Vis::load(html)?;