solarite 0.7.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/Path.js CHANGED
@@ -39,6 +39,23 @@ export default class Path {
39
39
  * @type {Node[]} Cached result of getNodes() */
40
40
  nodesCache;
41
41
 
42
+ /** @type {boolean|undefined} True when this path provides an attribute of a web component
43
+ * (a -solarite-placeholder element). Only attribute paths ever set it true, but it's
44
+ * declared here on every Path because clone() and cloneWithNodes() copy it to every clone;
45
+ * declaring it keeps those stores from transitioning the clone's hidden class. */
46
+ isComponentAttrib;
47
+
48
+ /** @type {boolean} True when re-applying an expression identical to the one already
49
+ * applied is provably a no-op, so a re-render can skip this path entirely. Only event
50
+ * bindings qualify: binding the same handler to the same node again changes nothing,
51
+ * while an attribute or a child expression may have been altered outside the template. */
52
+ skipIfSame = false;
53
+
54
+ /** @type {boolean|undefined} True when the attribute is a live HTML property
55
+ * (checked/value/selected — Util.isHtmlProp), which users can flip underneath the
56
+ * template. Declared here for the same hidden-class reason as isComponentAttrib. */
57
+ isHtmlProperty;
58
+
42
59
  // Set only on Shell paths, never on cloned instances, so they're not declared as
43
60
  // class fields; that would cost a store per field on every clone:
44
61
  // nodeBeforeIndex {int} Index of nodeBefore among its parentNode's children.
@@ -52,7 +69,7 @@ export default class Path {
52
69
  constructor(nodeBefore, nodeMarker) {
53
70
  this.nodeBefore = nodeBefore;
54
71
  this.nodeMarker = nodeMarker;
55
- /*#IFDEV*/this.verify();/*#ENDIF*/
72
+ /*#IFDEBUG*/this.verify();/*#ENDIF*/
56
73
  }
57
74
 
58
75
  /**
@@ -74,7 +91,12 @@ export default class Path {
74
91
  * [[expr5], [expr6, expr7]] // arguments to second my-component constructor.
75
92
  * [expr5] // user attribute value.
76
93
  * [expr6, expr7] // role attribute value. */
77
- apply(exprs) {}
94
+ applyAll(exprs) {
95
+ //#IFDEBUG
96
+ assert(Array.isArray(exprs));
97
+ //#ENDIF
98
+ this.applySingle(exprs[0]);
99
+ }
78
100
 
79
101
  /**
80
102
  * Fast path used by NodeGroup.applyExprs() when every path consumes exactly one expression.
@@ -84,26 +106,12 @@ export default class Path {
84
106
 
85
107
  getExpressionCount() { return 1 }
86
108
 
87
-
88
109
  /**
89
- * Resolve nodeMarkerPath to new root.
90
- * TODO: Make clone() use this.*/
91
- getNewNodeMarker(newRoot, pathOffset) {
92
- let root = newRoot;
93
- let path = this.nodeMarkerPath;
94
- let pathLength = path.length - pathOffset;
95
- for (let i=pathLength-1; i>0; i--) { // Resolve the path.
96
- //#IFDEV
97
- assert(root.childNodes[path[i]]);
98
- //#ENDIF
99
- root = root.childNodes[path[i]];
100
- }
101
- let childNodes = root.childNodes;
102
-
103
- return pathLength
104
- ? childNodes[path[0]]
105
- : newRoot;
106
- }
110
+ * The value a path hands to a component constructor, for the single-expression paths.
111
+ * PathToAttribValue overrides this to join its surrounding static strings.
112
+ * @param exprs {Expr[]}
113
+ * @return {Expr} */
114
+ getValue(exprs) { return exprs[0] }
107
115
 
108
116
 
109
117
  /**
@@ -113,7 +121,7 @@ export default class Path {
113
121
  * @param nodeMarker {Node}
114
122
  * @return {Path} */
115
123
  cloneWithNodes(nodeBefore, nodeMarker) {
116
- let result = new this.constructor(nodeBefore, nodeMarker, this.attrName, this.attrValue);
124
+ let result = new this.constructor(nodeBefore, nodeMarker, this.attribName, this.attrValue);
117
125
  result.isComponentAttrib = this.isComponentAttrib;
118
126
  result.wholeParent = this.wholeParent;
119
127
  result.isHtmlProperty = this.isHtmlProperty;
@@ -125,41 +133,25 @@ export default class Path {
125
133
  * @param pathOffset {int}
126
134
  * @return {Path} */
127
135
  clone(newRoot, pathOffset=0) {
128
- /*#IFDEV*/this.verify();/*#ENDIF*/
129
-
130
- // Resolve node paths.
131
- let nodeMarker, nodeBefore;
132
- let root = newRoot;
133
- let path = this.nodeMarkerPath;
134
- let pathLength = path.length - pathOffset;
135
- for (let i=pathLength-1; i>0; i--) { // Resolve the path.
136
- //#IFDEV
137
- assert(root.childNodes[path[i]]);
138
- //#ENDIF
139
- root = root.childNodes[path[i]];
140
- }
141
- let childNodes = root.childNodes;
142
-
143
- nodeMarker = pathLength
144
- ? childNodes[path[0]]
145
- : newRoot;
136
+ /*#IFDEBUG*/this.verify();/*#ENDIF*/
137
+
138
+ // Resolve node paths. nodeBefore is always a sibling of nodeMarker (Shell builds it from
139
+ // nodeMarker.previousSibling, or inserts a comment immediately before it), so the list
140
+ // nodeBeforeIndex counts within is the marker's own parent's childNodes. An empty path
141
+ // leaves the marker as newRoot itself, and then that list is newRoot's children.
142
+ let nodeBefore;
143
+ let nodeMarker = Path.resolve(newRoot, this.nodeMarkerPath, pathOffset);
146
144
  if (this.nodeBefore) {
147
- //#IFDEV
145
+ let childNodes = (nodeMarker === newRoot ? newRoot : nodeMarker.parentNode).childNodes;
146
+ //#IFDEBUG
148
147
  assert(childNodes[this.nodeBeforeIndex]);
149
148
  //#ENDIF
150
149
  nodeBefore = childNodes[this.nodeBeforeIndex];
151
-
152
150
  }
153
151
 
154
- let result = new this.constructor(nodeBefore, nodeMarker, this.attrName, this.attrValue);
155
-
156
- result.isComponentAttrib = this.isComponentAttrib;
157
- result.wholeParent = this.wholeParent;
158
-
159
- // TODO: Put this in PathToAttribValue.clone().
160
- result.isHtmlProperty = this.isHtmlProperty;
152
+ let result = this.cloneWithNodes(nodeBefore, nodeMarker);
161
153
 
162
- //#IFDEV
154
+ //#IFDEBUG
163
155
  result.verify();
164
156
  //#ENDIF
165
157
 
@@ -183,14 +175,21 @@ export default class Path {
183
175
  * Note that the path is backward, with the outermost element at the end.
184
176
  * @param root {HTMLElement|Document|DocumentFragment|ParentNode}
185
177
  * @param path {int[]}
178
+ * @param skip {int} How many of the outermost steps to leave off, for when root is
179
+ * already that many levels down from where the path was recorded. An empty walk
180
+ * (skip === path.length) returns root itself.
186
181
  * @returns {Node|HTMLElement|HTMLStyleElement} */
187
- static resolve(root, path) {
188
- for (let i=path.length-1; i>=0; i--)
182
+ static resolve(root, path, skip=0) {
183
+ for (let i=path.length-1-skip; i>=0; i--) {
184
+ //#IFDEBUG
185
+ assert(root.childNodes[path[i]]);
186
+ //#ENDIF
189
187
  root = root.childNodes[path[i]];
188
+ }
190
189
  return root;
191
190
  }
192
191
 
193
- //#IFDEV
192
+ //#IFDEBUG
194
193
 
195
194
  /** @return {HTMLElement|ParentNode} */
196
195
  getParentNode() {