on master help sign in
Smarter way of deciding namespaces
commitc725015039834500d1bbe1ae679bc725a784d179 authorRyan Levick <ryan.levick@gmail.com> dateSat 16 Mar 2019, 13:44 (8 years ago) parentf5d3d53
6 files changed+132−37
.gitignore+1 js/change-list.js+2−2 src/builder.rs+53−8 src/change_list.rs+5−5 src/node.rs+24−3 src/vdom.rs+47−19
.gitignore+1
@@ -1,3 +1,4 @@
11/target
22**/*.rs.bk
33wasm-pack.log
4+/.vscode
js/change-list.js+2−2
@@ -247,7 +247,7 @@ class ChangeList {
247247
248248 applyChangeRange(mem8, mem32, start, len) {
249249 const end = (start + len) / 4;
250− for (let i = start / 4; i < end;) {
250+ for (let i = start / 4; i < end; ) {
251251 const op = mem32[i++];
252252 i = OP_TABLE[op](this, mem8, mem32, i);
253253 }
@@ -268,7 +268,7 @@ class ChangeList {
268268 initEventsTrampoline(trampoline) {
269269 this.trampoline = trampoline;
270270 trampoline.mounted = true;
271− this.eventHandler = function (event) {
271+ this.eventHandler = function(event) {
272272 if (!trampoline.mounted) {
273273 throw new Error("invocation of listener after VDOM has been unmounted");
274274 }
src/builder.rs+53−8
@@ -20,6 +20,7 @@ where
2020 listeners: Listeners,
2121 attributes: Attributes,
2222 children: Children,
23+ namespace: Option<&'a str>,
2324}
2425
2526impl<'a>
@@ -60,6 +61,19 @@ impl<'a>
6061 listeners: bumpalo::collections::Vec::new_in(bump),
6162 attributes: bumpalo::collections::Vec::new_in(bump),
6263 children: bumpalo::collections::Vec::new_in(bump),
64+ namespace: None,
65+ }
66+ }
67+
68+ /// FIX ME
69+ pub fn new_with_namespace(bump: &'a Bump, tag_name: &'a str, namespace: &'a str) -> Self {
70+ ElementBuilder {
71+ bump,
72+ tag_name,
73+ listeners: bumpalo::collections::Vec::new_in(bump),
74+ attributes: bumpalo::collections::Vec::new_in(bump),
75+ children: bumpalo::collections::Vec::new_in(bump),
76+ namespace: Some(namespace),
6377 }
6478 }
6579}
@@ -108,6 +122,7 @@ where
108122 listeners,
109123 attributes: self.attributes,
110124 children: self.children,
125+ namespace: self.namespace,
111126 }
112127 }
113128
@@ -145,6 +160,7 @@ where
145160 listeners: self.listeners,
146161 attributes,
147162 children: self.children,
163+ namespace: self.namespace,
148164 }
149165 }
150166
@@ -182,6 +198,7 @@ where
182198 listeners: self.listeners,
183199 attributes: self.attributes,
184200 children,
201+ namespace: self.namespace,
185202 }
186203 }
187204
@@ -202,13 +219,17 @@ where
202219 /// ```
203220 #[inline]
204221 pub fn finish(self) -> Node<'a> {
205− Node::element(
222+ let element = Node::element_node(
206223 self.bump,
207224 self.tag_name,
208225 self.listeners,
209226 self.attributes,
210227 self.children,
211− )
228+ );
229+ match self.namespace {
230+ Some(namespace) => Node::NamespacedElement(namespace, element),
231+ None => Node::Element(element),
232+ }
212233 }
213234}
214235
@@ -357,6 +378,25 @@ macro_rules! builder_constructors {
357378 ElementBuilder::new(bump, stringify!($name))
358379 }
359380 )*
381+ };
382+ ( $(
383+ $(#[$attr:meta])*
384+ $name:ident <> $namespace:tt;
385+ )* ) => {
386+ $(
387+ $(#[$attr])*
388+ #[inline]
389+ pub fn $name<'a>(
390+ bump: &'a Bump,
391+ ) -> ElementBuilder<
392+ 'a,
393+ bumpalo::collections::Vec<'a, Listener<'a>>,
394+ bumpalo::collections::Vec<'a, Attribute<'a>>,
395+ bumpalo::collections::Vec<'a, Node<'a>>,
396+ > {
397+ ElementBuilder::new_with_namespace(bump, stringify!($name), stringify!(namespace))
398+ }
399+ )*
360400 }
361401}
362402
@@ -856,17 +896,22 @@ builder_constructors! {
856896 /// element.
857897 slot;
858898 /// Build a
859− /// [`<svg>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/svg)
899+ /// [`<template>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template)
860900 /// element.
861− svg;
901+ template;
902+}
903+
904+builder_constructors! {
905+ // SVG components
906+
862907 /// Build a
863− /// [`<path>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path)
908+ /// [`<svg>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/svg)
864909 /// element.
865− path;
910+ svg <> "http://www.w3.org/2000/svg" ;
866911 /// Build a
867− /// [`<template>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template)
912+ /// [`<path>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path)
868913 /// element.
869− template;
914+ path <> "http://www.w3.org/2000/svg";
870915}
871916
872917/// Construct a text node.
src/change_list.rs+5−5
@@ -268,21 +268,21 @@ enum ChangeDiscriminant {
268268 /// ```
269269 DropString = 15,
270270
271− /// Immediates: `(pointer, length)`
271+ /// Immediates: `(pointer1, length1, pointer2, length2)`
272272 ///
273273 /// Stack: `[...] -> [... Node]`
274274 ///
275275 /// ```text
276− /// stack.push(createElement(String(pointer, length))
276+ /// stack.push(createElementNS(String(pointer1, length1), String(pointer2, length2))
277277 /// ```
278278 CreateElementNS = 16,
279279
280− /// Immediates: `(pointer, length)`
280+ /// Immediates: `(pointer1, length1, pointer2, length2, pointer3, length3)`
281281 ///
282− /// Stack: `[...] -> [... Node]`
282+ /// Stack: `[... Node] -> [... Node]`
283283 ///
284284 /// ```text
285− /// stack.push(createElement(String(pointer, length))
285+ /// stack.top().setAttributeNS(String(pointer1, length1), String(pointer2, length2), String(pointer3, length3))
286286 /// ```
287287 SetAttributeNS = 17,
288288}
src/node.rs+24−3
@@ -11,6 +11,9 @@ pub enum Node<'a> {
1111
1212 /// An element potentially with attributes and children.
1313 Element(ElementNode<'a>),
14+
15+ /// An element with a namespace and potentially with attributes and children.
16+ NamespacedElement(&'a str, ElementNode<'a>),
1417}
1518
1619/// Text nodes are just a string of text. They cannot have attributes or
@@ -95,7 +98,7 @@ impl<'a> Attribute<'a> {
9598}
9699
97100impl<'a> Node<'a> {
98− /// Construct a new element node with the given tag name and children.
101+ // Construct a new Node of type element with given tag name and children
99102 #[inline]
100103 pub(crate) fn element<Listeners, Attributes, Children>(
101104 bump: &'a Bump,
@@ -104,6 +107,24 @@ impl<'a> Node<'a> {
104107 attributes: Attributes,
105108 children: Children,
106109 ) -> Node<'a>
110+ where
111+ Listeners: 'a + AsRef<[Listener<'a>]>,
112+ Attributes: 'a + AsRef<[Attribute<'a>]>,
113+ Children: 'a + AsRef<[Node<'a>]>,
114+ {
115+ let element_node = Node::element_node(bump, tag_name, listeners, attributes, children);
116+ Node::Element(element_node)
117+ }
118+
119+ /// Construct a new element node with the given tag name and children.
120+ #[inline]
121+ pub(crate) fn element_node<Listeners, Attributes, Children>(
122+ bump: &'a Bump,
123+ tag_name: &'a str,
124+ listeners: Listeners,
125+ attributes: Attributes,
126+ children: Children,
127+ ) -> ElementNode<'a>
107128 where
108129 Listeners: 'a + AsRef<[Listener<'a>]>,
109130 Attributes: 'a + AsRef<[Attribute<'a>]>,
@@ -118,12 +139,12 @@ impl<'a> Node<'a> {
118139 let attributes: &'a Attributes = bump.alloc(attributes);
119140 let attributes: &'a [Attribute<'a>] = attributes.as_ref();
120141
121− Node::Element(ElementNode {
142+ ElementNode {
122143 tag_name,
123144 listeners,
124145 attributes,
125146 children,
126− })
147+ }
127148 }
128149
129150 /// Is this node a text node?
src/vdom.rs+47−19
@@ -287,30 +287,43 @@ impl VdomInnerExclusive {
287287 self.change_list.emit_set_text(new_text);
288288 }
289289 }
290− (&Node::Text(TextNode { .. }), Node::Element(ElementNode { .. })) => {
290+ (&Node::Text(_), Node::Element(_))
291+ | (&Node::Text(_), Node::NamespacedElement(_, _)) => {
291292 debug!(" replacing a text node with an element");
292293 self.create(registry, new);
293294 self.change_list.emit_replace_with();
294295 }
295− (&Node::Element(ElementNode { .. }), Node::Text(TextNode { .. })) => {
296+ (&Node::Element(_), Node::Text(_))
297+ | (&Node::NamespacedElement(_, _), Node::Text(_)) => {
296298 debug!(" replacing an element with a text node");
297299 self.create(registry, new);
298300 self.change_list.emit_replace_with();
299301 }
300− (
301− &Node::Element(ElementNode {
302+ (&Node::Element(ref new_element_node), Node::Element(ref old_element_node))
303+ | (
304+ &Node::NamespacedElement(_, ref new_element_node),
305+ Node::Element(ref old_element_node),
306+ )
307+ | (
308+ &Node::Element(ref new_element_node),
309+ Node::NamespacedElement(_, ref old_element_node),
310+ )
311+ | (
312+ &Node::NamespacedElement(_, ref new_element_node),
313+ Node::NamespacedElement(_, ref old_element_node),
314+ ) => {
315+ let ElementNode {
302316 tag_name: new_tag_name,
303317 listeners: new_listeners,
304318 attributes: new_attributes,
305319 children: new_children,
306− }),
307− Node::Element(ElementNode {
320+ } = new_element_node;
321+ let ElementNode {
308322 tag_name: old_tag_name,
309323 listeners: old_listeners,
310324 attributes: old_attributes,
311325 children: old_children,
312− }),
313− ) => {
326+ } = old_element_node;
314327 debug!(" updating an element");
315328 if new_tag_name != old_tag_name {
316329 debug!(" different tag names; creating new element and replacing old element");
@@ -463,12 +476,7 @@ impl VdomInnerExclusive {
463476 attributes,
464477 children,
465478 }) => {
466− if ["svg", "path"].contains(&tag_name) {
467− self.change_list
468− .emit_create_element_ns(tag_name, "http://www.w3.org/2000/svg");
469− } else {
470− self.change_list.emit_create_element(tag_name);
471− }
479+ self.change_list.emit_create_element(tag_name);
472480 for l in listeners {
473481 unsafe {
474482 registry.add(l);
@@ -476,12 +484,32 @@ impl VdomInnerExclusive {
476484 self.change_list.emit_new_event_listener(l);
477485 }
478486 for attr in attributes {
479− if ["svg", "path"].contains(&tag_name) && attr.name != "xmlns" {
480− self.change_list
481− .emit_set_attribute_ns(&attr.name, &attr.value);
482− } else {
483− self.change_list.emit_set_attribute(&attr.name, &attr.value);
487+ self.change_list.emit_set_attribute(&attr.name, &attr.value);
488+ }
489+ for child in children {
490+ self.create(registry, child.clone());
491+ self.change_list.emit_append_child();
492+ }
493+ }
494+ Node::NamespacedElement(
495+ namepsace,
496+ ElementNode {
497+ tag_name,
498+ listeners,
499+ attributes,
500+ children,
501+ },
502+ ) => {
503+ self.change_list.emit_create_element_ns(tag_name, namepsace);
504+ for l in listeners {
505+ unsafe {
506+ registry.add(l);
484507 }
508+ self.change_list.emit_new_event_listener(l);
509+ }
510+ for attr in attributes {
511+ self.change_list
512+ .emit_set_attribute_ns(&attr.name, &attr.value);
485513 }
486514 for child in children {
487515 self.create(registry, child.clone());