@webtides/element-js 1.1.2 → 1.1.3

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/CHANGELOG.md CHANGED
@@ -16,6 +16,15 @@ to [Semantic Versioning](http://semver.org/).
16
16
  <!-- ### Removed -->
17
17
  <!-- ### Fixed -->
18
18
 
19
+
20
+ ## [1.1.3] - 2024-11-11
21
+
22
+ ### FIXED
23
+
24
+ - Fixed unsafeHtml having more than one child ([#135](https://github.com/webtides/element-js/issues/135))
25
+ - Fixed early returns from templates and fixes static html changes not reflecting to DOM ([#132](https://github.com/webtides/element-js/issues/132))
26
+
27
+
19
28
  ## [1.1.2] - 2024-10-30
20
29
 
21
30
  ### FIXED
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webtides/element-js",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "module": "index.js",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -8,6 +8,9 @@ import { TemplatePart } from './TemplatePart.js';
8
8
  * @return {ChildNode}
9
9
  */
10
10
  const removeChildNodes = (node) => {
11
+ if (!Array.isArray(node) && !(node instanceof TemplatePart) && !node.hasChildNodes()) {
12
+ return node;
13
+ }
11
14
  const range = globalThis.document?.createRange();
12
15
  const firstChild = Array.isArray(node)
13
16
  ? node[0]
@@ -48,8 +51,25 @@ const removeNodesBetweenComments = (commentNode) => {
48
51
  * @return {Node[]}
49
52
  */
50
53
  const diffChildNodes = function (parentNode, domChildNodes, templateChildNodes, anchorNode) {
54
+ // We always want to have the two arrays (domChildNodes and templateChildNodes) to have the same length.
55
+ // We also don't ever want to replace/diff the last node of the domChildNodes as it will always be the
56
+ // closing comment marker (/template-part) aka the anchorNode. So we push it to the end by inserting undefined items.
57
+ if (templateChildNodes.length > domChildNodes.length) {
58
+ const nodesToFill = templateChildNodes.length - domChildNodes.length;
59
+ for (let i = 0; i < nodesToFill; i++) {
60
+ domChildNodes.splice(domChildNodes.length - 1, 0, undefined);
61
+ }
62
+ }
63
+
64
+ if (domChildNodes.length > templateChildNodes.length) {
65
+ const nodesToFill = domChildNodes.length - templateChildNodes.length;
66
+ for (let i = 0; i < nodesToFill; i++) {
67
+ templateChildNodes.splice(templateChildNodes.length - 1, 0, undefined);
68
+ }
69
+ }
70
+
71
+ const length = domChildNodes.length;
51
72
  // Diff each node in the child node lists
52
- let length = Math.max(templateChildNodes.length, domChildNodes.length);
53
73
  for (let index = 0; index < length; index++) {
54
74
  let domChildNode = domChildNodes[index];
55
75
  let templateChildNode = templateChildNodes[index];
@@ -58,6 +78,8 @@ const diffChildNodes = function (parentNode, domChildNodes, templateChildNodes,
58
78
  if (!domChildNode) {
59
79
  if (templateChildNode instanceof TemplatePart) {
60
80
  anchorNode.before(...templateChildNode.childNodes);
81
+ } else if (Array.isArray(templateChildNode)) {
82
+ anchorNode.before(...templateChildNode);
61
83
  } else if (typeof templateChildNode === 'object' && 'ELEMENT_NODE' in templateChildNode) {
62
84
  parentNode.insertBefore(templateChildNode, anchorNode);
63
85
  } else {
@@ -75,7 +97,12 @@ const diffChildNodes = function (parentNode, domChildNodes, templateChildNodes,
75
97
  }
76
98
 
77
99
  // If DOM node is equal to the template node, don't do anything
78
- if (domChildNode === templateChildNode) {
100
+ if (
101
+ domChildNode === templateChildNode ||
102
+ (domChildNode.nodeType === COMMENT_NODE &&
103
+ templateChildNode.nodeType === COMMENT_NODE &&
104
+ domChildNode.isEqualNode(templateChildNode))
105
+ ) {
79
106
  continue;
80
107
  }
81
108
 
@@ -91,7 +118,7 @@ const diffChildNodes = function (parentNode, domChildNodes, templateChildNodes,
91
118
  * @return {(function(*): void)|*}
92
119
  */
93
120
  export const processNodePart = (comment, initialValue) => {
94
- let nodes = [];
121
+ let nodes = initialValue instanceof TemplatePart ? [...initialValue.childNodes] : [];
95
122
  let oldValue = initialValue instanceof TemplatePart ? [...initialValue.childNodes] : initialValue;
96
123
  // this is for string values to be inserted into the DOM. A cached TextNode will be used so that we don't have to constantly create new DOM nodes.
97
124
  let cachedTextNode = undefined;
@@ -145,7 +172,7 @@ export const processNodePart = (comment, initialValue) => {
145
172
  oldValue = newValue;
146
173
  nodes = diffChildNodes(comment.parentNode, nodes, [newValue], comment);
147
174
  } else if (newValue instanceof TemplatePart) {
148
- oldValue = newValue;
175
+ oldValue = [...newValue.childNodes];
149
176
  nodes = diffChildNodes(comment.parentNode, nodes, [...newValue.childNodes], comment);
150
177
  } else {
151
178
  console.warn('Could not process value', newValue);
@@ -2,7 +2,7 @@ import { COMMENT_NODE, convertStringToTemplate } from '../util/DOMHelper.js';
2
2
  import { Part } from './Part.js';
3
3
  import { TemplateResult } from './TemplateResult.js';
4
4
  import { AttributePart } from './AttributePart.js';
5
- import { ChildNodePart } from './ChildNodePart.js';
5
+ import { ChildNodePart, processNodePart } from './ChildNodePart.js';
6
6
  import { NodePart } from './NodePart.js';
7
7
 
8
8
  /** @type {Map<TemplateStringsArray, Part[]>} */
@@ -50,8 +50,11 @@ export class TemplatePart extends Part {
50
50
  // if not SSRed, childNodes will only ever have two comment nodes, the start and the end marker
51
51
  if (childNodes.length > 2) {
52
52
  serverSideRendered = true;
53
- this.childNodes = childNodes;
54
53
  }
54
+
55
+ this.childNodes = childNodes;
56
+ this.startNode = startNode;
57
+ this.endNode = endNode;
55
58
  }
56
59
 
57
60
  this.parseValue(value);
@@ -61,6 +64,13 @@ export class TemplatePart extends Part {
61
64
  // We need a childNodes list that is NOT live so that we don't loose elements when they get removed from the dom and we can (re)add them back in later.
62
65
  this.childNodes = [...this.childNodes];
63
66
  }
67
+
68
+ this.startNode = this.childNodes[0];
69
+ this.endNode = this.childNodes[this.childNodes.length - 1];
70
+
71
+ if (this.endNode) {
72
+ this.processor = processNodePart(this.endNode, this);
73
+ }
64
74
  }
65
75
 
66
76
  /**
@@ -69,6 +79,8 @@ export class TemplatePart extends Part {
69
79
  update(value) {
70
80
  this.parseValue(value);
71
81
  this.updateParts(value.values);
82
+ this.childNodes = [...this.childNodes];
83
+ this.processor?.(this);
72
84
  }
73
85
 
74
86
  /**
@@ -85,15 +97,13 @@ export class TemplatePart extends Part {
85
97
  */
86
98
  parseValue(templateResult) {
87
99
  if (this.strings !== templateResult.strings) {
88
- if (this.childNodes.length === 0) {
89
- let fragment = fragmentsCache.get(templateResult.strings);
90
- if (!fragment) {
91
- fragment = this.parseFragment(templateResult);
92
- fragmentsCache.set(templateResult.strings, fragment);
93
- }
94
- const importedFragment = globalThis.document?.importNode(fragment, true);
95
- this.childNodes = importedFragment.childNodes;
100
+ let fragment = fragmentsCache.get(templateResult.strings);
101
+ if (!fragment) {
102
+ fragment = this.parseFragment(templateResult);
103
+ fragmentsCache.set(templateResult.strings, fragment);
96
104
  }
105
+ const importedFragment = globalThis.document?.importNode(fragment, true);
106
+ this.childNodes = importedFragment.childNodes;
97
107
 
98
108
  let parts = partsCache.get(templateResult.strings);
99
109
  if (!parts) {
@@ -121,6 +131,7 @@ export class TemplatePart extends Part {
121
131
  });
122
132
  this.strings = templateResult.strings;
123
133
  }
134
+ return this.childNodes;
124
135
  }
125
136
 
126
137
  /**
@@ -56,15 +56,15 @@ const choose = (value, cases, defaultCase) => {
56
56
  /**
57
57
  * Renders a given string as HTML instead of text or as unescaped string in SSR mode
58
58
  * @param {string} string
59
- * @returns {(function(): Node) | { __unsafeHTML: true, string: string }}
59
+ * @returns {(function(): [Node]) | { __unsafeHTML: true, string: string }}
60
60
  */
61
61
  const unsafeHTML = (string) => {
62
62
  if (!globalThis.DOMParser) {
63
63
  return { __unsafeHTML: true, string };
64
64
  }
65
- const node = convertStringToHTML(string).firstChild;
66
- const importedNode = globalThis.document?.importNode(node, true);
67
- return () => importedNode;
65
+ const body = convertStringToHTML(string);
66
+ const childNodes = [...body.childNodes];
67
+ return () => childNodes;
68
68
  };
69
69
 
70
70
  /**