Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
81153 views
1
/*
2
Module dependencies
3
*/
4
var ElementType = require('domelementtype');
5
var entities = require('entities');
6
7
/*
8
Boolean Attributes
9
*/
10
var booleanAttributes = {
11
__proto__: null,
12
allowfullscreen: true,
13
async: true,
14
autofocus: true,
15
autoplay: true,
16
checked: true,
17
controls: true,
18
default: true,
19
defer: true,
20
disabled: true,
21
hidden: true,
22
ismap: true,
23
loop: true,
24
multiple: true,
25
muted: true,
26
open: true,
27
readonly: true,
28
required: true,
29
reversed: true,
30
scoped: true,
31
seamless: true,
32
selected: true,
33
typemustmatch: true
34
};
35
36
var unencodedElements = {
37
__proto__: null,
38
style: true,
39
script: true,
40
xmp: true,
41
iframe: true,
42
noembed: true,
43
noframes: true,
44
plaintext: true,
45
noscript: true
46
};
47
48
/*
49
Format attributes
50
*/
51
function formatAttrs(attributes, opts) {
52
if (!attributes) return;
53
54
var output = '',
55
value;
56
57
// Loop through the attributes
58
for (var key in attributes) {
59
value = attributes[key];
60
if (output) {
61
output += ' ';
62
}
63
64
if (!value && booleanAttributes[key]) {
65
output += key;
66
} else {
67
output += key + '="' + (opts.decodeEntities ? entities.encodeXML(value) : value) + '"';
68
}
69
}
70
71
return output;
72
}
73
74
/*
75
Self-enclosing tags (stolen from node-htmlparser)
76
*/
77
var singleTag = {
78
__proto__: null,
79
area: true,
80
base: true,
81
basefont: true,
82
br: true,
83
col: true,
84
command: true,
85
embed: true,
86
frame: true,
87
hr: true,
88
img: true,
89
input: true,
90
isindex: true,
91
keygen: true,
92
link: true,
93
meta: true,
94
param: true,
95
source: true,
96
track: true,
97
wbr: true,
98
};
99
100
101
var render = module.exports = function(dom, opts) {
102
if (!Array.isArray(dom) && !dom.cheerio) dom = [dom];
103
opts = opts || {};
104
105
var output = '';
106
107
for(var i = 0; i < dom.length; i++){
108
var elem = dom[i];
109
110
if (elem.type === 'root')
111
output += render(elem.children, opts);
112
else if (ElementType.isTag(elem))
113
output += renderTag(elem, opts);
114
else if (elem.type === ElementType.Directive)
115
output += renderDirective(elem);
116
else if (elem.type === ElementType.Comment)
117
output += renderComment(elem);
118
else if (elem.type === ElementType.CDATA)
119
output += renderCdata(elem);
120
else
121
output += renderText(elem, opts);
122
}
123
124
return output;
125
};
126
127
function renderTag(elem, opts) {
128
// Handle SVG
129
if (elem.name === "svg") opts = {decodeEntities: opts.decodeEntities, xmlMode: true};
130
131
var tag = '<' + elem.name,
132
attribs = formatAttrs(elem.attribs, opts);
133
134
if (attribs) {
135
tag += ' ' + attribs;
136
}
137
138
if (
139
opts.xmlMode
140
&& (!elem.children || elem.children.length === 0)
141
) {
142
tag += '/>';
143
} else {
144
tag += '>';
145
if (elem.children) {
146
tag += render(elem.children, opts);
147
}
148
149
if (!singleTag[elem.name] || opts.xmlMode) {
150
tag += '</' + elem.name + '>';
151
}
152
}
153
154
return tag;
155
}
156
157
function renderDirective(elem) {
158
return '<' + elem.data + '>';
159
}
160
161
function renderText(elem, opts) {
162
var data = elem.data || '';
163
164
// if entities weren't decoded, no need to encode them back
165
if (opts.decodeEntities && !(elem.parent && elem.parent.name in unencodedElements)) {
166
data = entities.encodeXML(data);
167
}
168
169
return data;
170
}
171
172
function renderCdata(elem) {
173
return '<![CDATA[' + elem.children[0].data + ']]>';
174
}
175
176
function renderComment(elem) {
177
return '<!--' + elem.data + '-->';
178
}
179
180