Skip to content

Commit bde933e

Browse files
Create HTML to DOM helper for the client/browser
The original HTML to DOM helper works in the node environment and it depends on both `htmlparser2` and `domhandler`, which is unnecessary in the browser environment because there is already a DOM provided. As a result, the motivation is to create a helper that if on the client-side, uses the DOM API to prevent bundling the extra node modules in the build. This is to keep the library isomorphic. `formatDOM` ensures that the NodeLists are formatted like the output from `htmlparser2.parseDOM`. The contract is as specified: ```js { type: "tag" || "script" || "style" || "text" || "comment", [ name: [String], ] [ data: [String], ] [ attribs: [Object], ] [ children: [Array], ] next: [Object] || null, prev: [Object] || null, parent: [Circular] || null } ```
1 parent c7af9a9 commit bde933e

File tree

1 file changed

+99
-0
lines changed

1 file changed

+99
-0
lines changed

lib/html-to-dom-client.js

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
'use strict';
2+
3+
/**
4+
* Format the browser DOM attributes.
5+
*
6+
* @param {NamedNodeMap} - The attributes.
7+
* @return {Object}
8+
*/
9+
function formatAttributes(attributes) {
10+
var result = {};
11+
var attribute;
12+
13+
// NamedNodeMap is array-like
14+
for (var i = 0, len = attributes.length; i < len; i++) {
15+
attribute = attributes[i];
16+
result[attribute.name] = attribute.value;
17+
}
18+
19+
return result;
20+
}
21+
22+
/**
23+
* Format the browser DOM nodes to match that of `htmlparser2.parseDOM`.
24+
*
25+
* @param {NodeList} nodes - The DOM nodes.
26+
* @param {Object} [parentNode] - The parent node that's already formatted.
27+
* @return {Object}
28+
*/
29+
function formatDOM(nodes, parentNode) {
30+
var result = [];
31+
var node;
32+
var prevNode;
33+
var nodeObj;
34+
35+
// NodeList is array-like
36+
for (var i = 0, len = nodes.length; i < len; i++) {
37+
node = nodes[i];
38+
// reset
39+
nodeObj = {
40+
next: null,
41+
prev: result[i - 1] || null,
42+
parent: parentNode || null
43+
};
44+
45+
// set the next node for the previous node (if applicable)
46+
if (prevNode = result[i - 1]) {
47+
prevNode.next = nodeObj;
48+
}
49+
50+
// set the node name if it's not "#text" or "#comment"
51+
// e.g., "div"
52+
if (node.nodeName.indexOf('#') !== 0) {
53+
nodeObj.name = node.nodeName.toLowerCase();
54+
55+
// also, type "tag" nodes have"attribs"
56+
nodeObj.attribs = {}; // default
57+
if (node.attributes && node.attributes.length) {
58+
nodeObj.attribs = formatAttributes(node.attributes);
59+
}
60+
}
61+
62+
// set the node type
63+
// e.g., "tag"
64+
switch (node.nodeType) {
65+
// 1 = element
66+
case 1:
67+
if (nodeObj.name === 'script' || nodeObj.name === 'style') {
68+
nodeObj.type = nodeObj.name;
69+
} else {
70+
nodeObj.type = 'tag';
71+
}
72+
// recursively format the children
73+
nodeObj.children = formatDOM(node.childNodes, nodeObj);
74+
break;
75+
// 2 = attribute
76+
// 3 = text
77+
case 3:
78+
nodeObj.type = 'text';
79+
nodeObj.data = node.nodeValue;
80+
break;
81+
// 8 = comment
82+
case 8:
83+
nodeObj.type = 'comment';
84+
nodeObj.data = node.nodeValue;
85+
break;
86+
default:
87+
break;
88+
}
89+
90+
result.push(nodeObj);
91+
}
92+
93+
return result;
94+
}
95+
96+
/**
97+
* Export HTML to DOM client helper.
98+
*/
99+
module.exports = formatDOM;

0 commit comments

Comments
 (0)