-
-
Notifications
You must be signed in to change notification settings - Fork 135
/
Copy pathhtml-to-dom-client.js
126 lines (110 loc) Β· 3.28 KB
/
html-to-dom-client.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
'use strict';
/**
* Format the browser DOM attributes.
*
* @param {NamedNodeMap} - The attributes.
* @return {Object}
*/
function formatAttributes(attributes) {
var result = {};
var attribute;
// NamedNodeMap is array-like
for (var i = 0, len = attributes.length; i < len; i++) {
attribute = attributes[i];
result[attribute.name] = attribute.value;
}
return result;
}
/**
* Format the browser DOM nodes to match that of `htmlparser2.parseDOM`.
*
* @param {NodeList} nodes - The DOM nodes.
* @param {Object} [parentNode] - The parent node that's already formatted.
* @return {Object}
*/
function formatDOM(nodes, parentNode) {
var result = [];
var node;
var prevNode;
var nodeObj;
// NodeList is array-like
for (var i = 0, len = nodes.length; i < len; i++) {
node = nodes[i];
// reset
nodeObj = {
next: null,
prev: result[i - 1] || null,
parent: parentNode || null
};
// set the next node for the previous node (if applicable)
prevNode = result[i - 1];
if (prevNode) {
prevNode.next = nodeObj;
}
// set the node name if it's not "#text" or "#comment"
// e.g., "div"
if (node.nodeName.indexOf('#') !== 0) {
nodeObj.name = node.nodeName.toLowerCase();
// also, type "tag" nodes have"attribs"
nodeObj.attribs = {}; // default
if (node.attributes && node.attributes.length) {
nodeObj.attribs = formatAttributes(node.attributes);
}
}
// set the node type
// e.g., "tag"
switch (node.nodeType) {
// 1 = element
case 1:
if (nodeObj.name === 'script' || nodeObj.name === 'style') {
nodeObj.type = nodeObj.name;
} else {
nodeObj.type = 'tag';
}
// recursively format the children
nodeObj.children = formatDOM(node.childNodes, nodeObj);
break;
// 2 = attribute
// 3 = text
case 3:
nodeObj.type = 'text';
nodeObj.data = node.nodeValue;
break;
// 8 = comment
case 8:
nodeObj.type = 'comment';
nodeObj.data = node.nodeValue;
break;
default:
break;
}
result.push(nodeObj);
}
return result;
}
/**
* Parse HTML string to DOM nodes.
* This uses the browser DOM API.
*
* @param {String} html - The HTML.
* @return {Object} - The DOM nodes.
*/
function htmlToDOMClient(html) {
var root;
// `DOMParser` can parse full HTML
// https://developer.mozilla.org/en-US/docs/Web/API/DOMParser
if (window.DOMParser) {
var parser = new window.DOMParser();
root = parser.parseFromString(html, 'text/html');
// otherwise, use `innerHTML`
// but this will strip out tags like <html> and <body>
} else {
root = document.createElement('div');
root.innerHTML = html;
}
return formatDOM(root.childNodes);
}
/**
* Export HTML to DOM parser (client).
*/
module.exports = htmlToDOMClient;