on master help sign in
Smarter way of deciding namespaces
c725015Ryan Levick
.gitignore+1
@@ -1,3 +1,4 @@
1/target
1/target
2**/*.rs.bk
2**/*.rs.bk
3wasm-pack.log
3wasm-pack.log
4+/.vscode
js/change-list.js+2−2
@@ -247,7 +247,7 @@ class ChangeList {
247
247
248 applyChangeRange(mem8, mem32, start, len) {
248 applyChangeRange(mem8, mem32, start, len) {
249 const end = (start + len) / 4;
249 const end = (start + len) / 4;
250− for (let i = start / 4; i < end;) {
250+ for (let i = start / 4; i < end; ) {
251 const op = mem32[i++];
251 const op = mem32[i++];
252 i = OP_TABLE[op](this, mem8, mem32, i);
252 i = OP_TABLE[op](this, mem8, mem32, i);
253 }
253 }
@@ -268,7 +268,7 @@ class ChangeList {
268 initEventsTrampoline(trampoline) {
268 initEventsTrampoline(trampoline) {
269 this.trampoline = trampoline;
269 this.trampoline = trampoline;
270 trampoline.mounted = true;
270 trampoline.mounted = true;
271− this.eventHandler = function (event) {
271+ this.eventHandler = function(event) {
272 if (!trampoline.mounted) {
272 if (!trampoline.mounted) {
273 throw new Error("invocation of listener after VDOM has been unmounted");
273 throw new Error("invocation of listener after VDOM has been unmounted");
274 }
274 }
src/builder.rs+53−8
@@ -20,6 +20,7 @@ where
20 listeners: Listeners,
20 listeners: Listeners,
21 attributes: Attributes,
21 attributes: Attributes,
22 children: Children,
22 children: Children,
23+ namespace: Option<&'a str>,
23}
24}
24
25
25impl<'a>
26impl<'a>
@@ -60,6 +61,19 @@ impl<'a>
60 listeners: bumpalo::collections::Vec::new_in(bump),
61 listeners: bumpalo::collections::Vec::new_in(bump),
61 attributes: bumpalo::collections::Vec::new_in(bump),
62 attributes: bumpalo::collections::Vec::new_in(bump),
62 children: bumpalo::collections::Vec::new_in(bump),
63 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),
63 }
77 }
64 }
78 }
65}
79}
@@ -108,6 +122,7 @@ where
108 listeners,
122 listeners,
109 attributes: self.attributes,
123 attributes: self.attributes,
110 children: self.children,
124 children: self.children,
125+ namespace: self.namespace,
111 }
126 }
112 }
127 }
113
128
@@ -145,6 +160,7 @@ where
145 listeners: self.listeners,
160 listeners: self.listeners,
146 attributes,
161 attributes,
147 children: self.children,
162 children: self.children,
163+ namespace: self.namespace,
148 }
164 }
149 }
165 }
150
166
@@ -182,6 +198,7 @@ where
182 listeners: self.listeners,
198 listeners: self.listeners,
183 attributes: self.attributes,
199 attributes: self.attributes,
184 children,
200 children,
201+ namespace: self.namespace,
185 }
202 }
186 }
203 }
187
204
@@ -202,13 +219,17 @@ where
202 /// ```
219 /// ```
203 #[inline]
220 #[inline]
204 pub fn finish(self) -> Node<'a> {
221 pub fn finish(self) -> Node<'a> {
205− Node::element(
222+ let element = Node::element_node(
206 self.bump,
223 self.bump,
207 self.tag_name,
224 self.tag_name,
208 self.listeners,
225 self.listeners,
209 self.attributes,
226 self.attributes,
210 self.children,
227 self.children,
211− )
228+ );
229+ match self.namespace {
230+ Some(namespace) => Node::NamespacedElement(namespace, element),
231+ None => Node::Element(element),
232+ }
212 }
233 }
213}
234}
214
235
@@ -357,6 +378,25 @@ macro_rules! builder_constructors {
357 ElementBuilder::new(bump, stringify!($name))
378 ElementBuilder::new(bump, stringify!($name))
358 }
379 }
359 )*
380 )*
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+ )*
360 }
400 }
361}
401}
362
402
@@ -856,17 +896,22 @@ builder_constructors! {
856 /// element.
896 /// element.
857 slot;
897 slot;
858 /// Build a
898 /// 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)
860 /// element.
900 /// element.
861− svg;
901+ template;
902+}
903+
904+builder_constructors! {
905+ // SVG components
906+
862 /// Build a
907 /// 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)
864 /// element.
909 /// element.
865− path;
910+ svg <> "http://www.w3.org/2000/svg" ;
866 /// Build a
911 /// 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)
868 /// element.
913 /// element.
869− template;
914+ path <> "http://www.w3.org/2000/svg";
870}
915}
871
916
872/// Construct a text node.
917/// Construct a text node.
src/change_list.rs+5−5
@@ -268,21 +268,21 @@ enum ChangeDiscriminant {
268 /// ```
268 /// ```
269 DropString = 15,
269 DropString = 15,
270
270
271− /// Immediates: `(pointer, length)`
271+ /// Immediates: `(pointer1, length1, pointer2, length2)`
272 ///
272 ///
273 /// Stack: `[...] -> [... Node]`
273 /// Stack: `[...] -> [... Node]`
274 ///
274 ///
275 /// ```text
275 /// ```text
276− /// stack.push(createElement(String(pointer, length))
276+ /// stack.push(createElementNS(String(pointer1, length1), String(pointer2, length2))
277 /// ```
277 /// ```
278 CreateElementNS = 16,
278 CreateElementNS = 16,
279
279
280− /// Immediates: `(pointer, length)`
280+ /// Immediates: `(pointer1, length1, pointer2, length2, pointer3, length3)`
281 ///
281 ///
282− /// Stack: `[...] -> [... Node]`
282+ /// Stack: `[... Node] -> [... Node]`
283 ///
283 ///
284 /// ```text
284 /// ```text
285− /// stack.push(createElement(String(pointer, length))
285+ /// stack.top().setAttributeNS(String(pointer1, length1), String(pointer2, length2), String(pointer3, length3))
286 /// ```
286 /// ```
287 SetAttributeNS = 17,
287 SetAttributeNS = 17,
288}
288}
src/node.rs+24−3
@@ -11,6 +11,9 @@ pub enum Node<'a> {
11
11
12 /// An element potentially with attributes and children.
12 /// An element potentially with attributes and children.
13 Element(ElementNode<'a>),
13 Element(ElementNode<'a>),
14+
15+ /// An element with a namespace and potentially with attributes and children.
16+ NamespacedElement(&'a str, ElementNode<'a>),
14}
17}
15
18
16/// Text nodes are just a string of text. They cannot have attributes or
19/// Text nodes are just a string of text. They cannot have attributes or
@@ -95,7 +98,7 @@ impl<'a> Attribute<'a> {
95}
98}
96
99
97impl<'a> Node<'a> {
100impl<'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
99 #[inline]
102 #[inline]
100 pub(crate) fn element<Listeners, Attributes, Children>(
103 pub(crate) fn element<Listeners, Attributes, Children>(
101 bump: &'a Bump,
104 bump: &'a Bump,
@@ -104,6 +107,24 @@ impl<'a> Node<'a> {
104 attributes: Attributes,
107 attributes: Attributes,
105 children: Children,
108 children: Children,
106 ) -> Node<'a>
109 ) -> 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>
107 where
128 where
108 Listeners: 'a + AsRef<[Listener<'a>]>,
129 Listeners: 'a + AsRef<[Listener<'a>]>,
109 Attributes: 'a + AsRef<[Attribute<'a>]>,
130 Attributes: 'a + AsRef<[Attribute<'a>]>,
@@ -118,12 +139,12 @@ impl<'a> Node<'a> {
118 let attributes: &'a Attributes = bump.alloc(attributes);
139 let attributes: &'a Attributes = bump.alloc(attributes);
119 let attributes: &'a [Attribute<'a>] = attributes.as_ref();
140 let attributes: &'a [Attribute<'a>] = attributes.as_ref();
120
141
121− Node::Element(ElementNode {
142+ ElementNode {
122 tag_name,
143 tag_name,
123 listeners,
144 listeners,
124 attributes,
145 attributes,
125 children,
146 children,
126− })
147+ }
127 }
148 }
128
149
129 /// Is this node a text node?
150 /// Is this node a text node?
src/vdom.rs+47−19
@@ -287,30 +287,43 @@ impl VdomInnerExclusive {
287 self.change_list.emit_set_text(new_text);
287 self.change_list.emit_set_text(new_text);
288 }
288 }
289 }
289 }
290− (&Node::Text(TextNode { .. }), Node::Element(ElementNode { .. })) => {
290+ (&Node::Text(_), Node::Element(_))
291+ | (&Node::Text(_), Node::NamespacedElement(_, _)) => {
291 debug!(" replacing a text node with an element");
292 debug!(" replacing a text node with an element");
292 self.create(registry, new);
293 self.create(registry, new);
293 self.change_list.emit_replace_with();
294 self.change_list.emit_replace_with();
294 }
295 }
295− (&Node::Element(ElementNode { .. }), Node::Text(TextNode { .. })) => {
296+ (&Node::Element(_), Node::Text(_))
297+ | (&Node::NamespacedElement(_, _), Node::Text(_)) => {
296 debug!(" replacing an element with a text node");
298 debug!(" replacing an element with a text node");
297 self.create(registry, new);
299 self.create(registry, new);
298 self.change_list.emit_replace_with();
300 self.change_list.emit_replace_with();
299 }
301 }
300− (
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+ ) => {
301− &Node::Element(ElementNode {
315+ let ElementNode {
302 tag_name: new_tag_name,
316 tag_name: new_tag_name,
303 listeners: new_listeners,
317 listeners: new_listeners,
304 attributes: new_attributes,
318 attributes: new_attributes,
305 children: new_children,
319 children: new_children,
306− }),
320+ } = new_element_node;
307− Node::Element(ElementNode {
321+ let ElementNode {
308 tag_name: old_tag_name,
322 tag_name: old_tag_name,
309 listeners: old_listeners,
323 listeners: old_listeners,
310 attributes: old_attributes,
324 attributes: old_attributes,
311 children: old_children,
325 children: old_children,
312− }),
326+ } = old_element_node;
313− ) => {
314 debug!(" updating an element");
327 debug!(" updating an element");
315 if new_tag_name != old_tag_name {
328 if new_tag_name != old_tag_name {
316 debug!(" different tag names; creating new element and replacing old element");
329 debug!(" different tag names; creating new element and replacing old element");
@@ -463,12 +476,7 @@ impl VdomInnerExclusive {
463 attributes,
476 attributes,
464 children,
477 children,
465 }) => {
478 }) => {
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);
479+ self.change_list.emit_create_element(tag_name);
471− }
472 for l in listeners {
480 for l in listeners {
473 unsafe {
481 unsafe {
474 registry.add(l);
482 registry.add(l);
@@ -476,12 +484,32 @@ impl VdomInnerExclusive {
476 self.change_list.emit_new_event_listener(l);
484 self.change_list.emit_new_event_listener(l);
477 }
485 }
478 for attr in attributes {
486 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);
484 }
507 }
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);
485 }
513 }
486 for child in children {
514 for child in children {
487 self.create(registry, child.clone());
515 self.create(registry, child.clone());