total5 0.0.1 → 0.0.2
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/LICENSE +211 -0
- package/README.md +32 -0
- package/api.js +297 -0
- package/bin/flow5 +142 -0
- package/bin/total5 +245 -0
- package/builders.js +1770 -0
- package/bundles.js +447 -0
- package/cache.js +58 -0
- package/changelog.txt +5 -0
- package/cluster.js +320 -0
- package/cms.js +759 -0
- package/controller.js +1640 -0
- package/cron.js +99 -0
- package/debug.js +546 -0
- package/edit.js +462 -0
- package/error.html +49 -0
- package/filestorage.js +1109 -0
- package/flow-flowstream.js +3352 -0
- package/flow.js +238 -0
- package/flowstream.js +2061 -0
- package/global.js +274 -0
- package/htmlparser.js +662 -0
- package/http.js +83 -0
- package/image.js +777 -0
- package/images.js +747 -0
- package/index.js +2851 -0
- package/jsonschema.js +699 -0
- package/ldap.js +792 -0
- package/macros.js +222 -0
- package/mail.js +922 -0
- package/markdown.js +762 -0
- package/minificators.js +858 -0
- package/nosql-builder.js +440 -0
- package/nosql-querybuilder.js +320 -0
- package/nosql-reader.js +353 -0
- package/nosql-stream.js +617 -0
- package/nosql.js +782 -0
- package/openclient.js +219 -0
- package/package.json +14 -5
- package/pause.html +67 -0
- package/querybuilder.js +1220 -0
- package/release.js +167 -0
- package/routing.js +1028 -0
- package/sourcemap.js +163 -0
- package/tangular.js +409 -0
- package/templates.js +145 -0
- package/test.js +51 -0
- package/tms.js +380 -0
- package/uibuilder.js +242 -0
- package/utils.js +6432 -0
- package/viewengine.js +891 -0
- package/websocket.js +1944 -0
- package/workers.js +129 -0
package/htmlparser.js
ADDED
|
@@ -0,0 +1,662 @@
|
|
|
1
|
+
// Total.js HTML Parser
|
|
2
|
+
// The MIT License
|
|
3
|
+
// Copyright 2023 (c) Peter Širka <petersirka@gmail.com>
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
function HTMLElement() {
|
|
8
|
+
this.children = [];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
HTMLElement.prototype = {
|
|
12
|
+
get innerHTML() {
|
|
13
|
+
return this.toString();
|
|
14
|
+
},
|
|
15
|
+
get innerText() {
|
|
16
|
+
return this.toString().removeTags();
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function parseRule(selector, output) {
|
|
21
|
+
|
|
22
|
+
var rule = {};
|
|
23
|
+
|
|
24
|
+
rule.attrs = [];
|
|
25
|
+
rule.output = output || [];
|
|
26
|
+
|
|
27
|
+
// div div[name="Peter Sirka"]
|
|
28
|
+
// div > div[name="Peter Sirka"]
|
|
29
|
+
|
|
30
|
+
// for (var c of selector) {
|
|
31
|
+
// if (c === '>')
|
|
32
|
+
// console.log(c);
|
|
33
|
+
// }
|
|
34
|
+
|
|
35
|
+
var cache = [];
|
|
36
|
+
|
|
37
|
+
selector = selector.replace(/\[.*?\]/gi, text => '[' + (cache.push(text) - 1) + ']').replace(/(\s)?>(\s)?/, '>').replace(/\s{2}/g, '');
|
|
38
|
+
|
|
39
|
+
var m = selector.match(/>|\s/);
|
|
40
|
+
if (m) {
|
|
41
|
+
var nested = selector.substring(m.index + 1).trim().replace(/\[\d+\]/g, text => cache[+text.substring(1, text.length - 1)]);
|
|
42
|
+
rule.nested = parseRule(nested, rule.output);
|
|
43
|
+
rule.direct = m[0] === '>';
|
|
44
|
+
selector = selector.substring(0, m.index).trim();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
selector = selector.replace(/\[\d+\]/, text => cache[+text.substring(1, text.length - 1)]);
|
|
48
|
+
|
|
49
|
+
// attribute search
|
|
50
|
+
match = selector.match(/\[.*?\]/i);
|
|
51
|
+
if (match) {
|
|
52
|
+
for (var m of match) {
|
|
53
|
+
var index = m.indexOf('=');
|
|
54
|
+
rule.attrs.push({ id: m.substring(1, index).trim(), value: m.substring(index + 2, m.length - 2).trim() });
|
|
55
|
+
}
|
|
56
|
+
selector = selector.replace(match, '');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// #id or .class
|
|
60
|
+
var match = selector.match(/[#|.][a-z-_0-9]+/i);
|
|
61
|
+
if (match) {
|
|
62
|
+
for (var m of match) {
|
|
63
|
+
var val = m.substring(1);
|
|
64
|
+
rule.attrs.push({ id: m[0] === '#' ? 'id' : 'class', value: val });
|
|
65
|
+
}
|
|
66
|
+
selector = selector.replace(match, '');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
selector = selector.trim();
|
|
70
|
+
rule.tagName = selector[0] === '*' ? '' : selector.toUpperCase();
|
|
71
|
+
|
|
72
|
+
return rule;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
HTMLElement.prototype.browse = function(fn, reverse) {
|
|
76
|
+
|
|
77
|
+
var self = this;
|
|
78
|
+
|
|
79
|
+
var browse = function(children) {
|
|
80
|
+
for (var node of children) {
|
|
81
|
+
if (node && node.tagName) {
|
|
82
|
+
var a = fn(node);
|
|
83
|
+
if (a !== true)
|
|
84
|
+
browse(reverse ? [node.parentNode] : node.children);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
if (reverse && !self.parentNode)
|
|
90
|
+
return;
|
|
91
|
+
|
|
92
|
+
browse(reverse ? [self.parentNode] : self.children);
|
|
93
|
+
return self;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
function extendarr(output) {
|
|
97
|
+
|
|
98
|
+
output.aclass = function(cls) {
|
|
99
|
+
for (var item of this)
|
|
100
|
+
item.aclass(cls);
|
|
101
|
+
return this;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
output.rclass = function(cls) {
|
|
105
|
+
for (var item of this)
|
|
106
|
+
item.rclass(cls);
|
|
107
|
+
return this;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
output.tclass = function(cls, value) {
|
|
111
|
+
for (var item of this)
|
|
112
|
+
item.tclass(cls, value);
|
|
113
|
+
return this;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
output.attr = function(key, value) {
|
|
117
|
+
for (var item of this)
|
|
118
|
+
item.attr(key, value);
|
|
119
|
+
return this;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
output.attrd = function(key, value) {
|
|
123
|
+
for (var item of this)
|
|
124
|
+
item.attrd(key, value);
|
|
125
|
+
return this;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
output.find = function(selector) {
|
|
129
|
+
var arr = [];
|
|
130
|
+
for (var item of this) {
|
|
131
|
+
var result = item.find(selector);
|
|
132
|
+
if (result.length)
|
|
133
|
+
arr.push(result);
|
|
134
|
+
}
|
|
135
|
+
extendarr(arr);
|
|
136
|
+
return this;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
output.toString = output.html = function(formatted) {
|
|
140
|
+
var builder = [];
|
|
141
|
+
for (var item of this)
|
|
142
|
+
builder.push(item.toString(formatted));
|
|
143
|
+
return builder.join(formatted ? '\n' : '');
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
return output;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
HTMLElement.prototype.find = function(selector, reverse) {
|
|
150
|
+
|
|
151
|
+
var self = this;
|
|
152
|
+
var selectors = selector.split(',');
|
|
153
|
+
var rules = [];
|
|
154
|
+
var output = [];
|
|
155
|
+
|
|
156
|
+
for (var sel of selectors)
|
|
157
|
+
rules.push(parseRule(sel.trim()));
|
|
158
|
+
|
|
159
|
+
var browse = function(rule, children, parent) {
|
|
160
|
+
|
|
161
|
+
for (var node of children) {
|
|
162
|
+
|
|
163
|
+
if (!node.tagName)
|
|
164
|
+
continue;
|
|
165
|
+
|
|
166
|
+
var skip = false;
|
|
167
|
+
|
|
168
|
+
if (rule.tagName && rule.tagName !== node.tagName)
|
|
169
|
+
skip = true;
|
|
170
|
+
|
|
171
|
+
if (rule.attrs.length && !skip) {
|
|
172
|
+
for (var attr of rule.attrs) {
|
|
173
|
+
switch (attr.id) {
|
|
174
|
+
|
|
175
|
+
case 'class':
|
|
176
|
+
var tmp = node.attrs[attr.id];
|
|
177
|
+
if (tmp) {
|
|
178
|
+
tmp = tmp.split(' ');
|
|
179
|
+
if (!tmp.includes(attr.value))
|
|
180
|
+
skip = true;
|
|
181
|
+
} else
|
|
182
|
+
skip = true;
|
|
183
|
+
break;
|
|
184
|
+
|
|
185
|
+
default:
|
|
186
|
+
if (attr.value) {
|
|
187
|
+
if (node.attrs[attr.id] !== attr.value)
|
|
188
|
+
skip = true;
|
|
189
|
+
} else if (node.attrs[attr.id] === undefined)
|
|
190
|
+
skip = true;
|
|
191
|
+
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (skip)
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
var next = ((reverse && node.parentNode) || (!reverse && node.children.length));
|
|
201
|
+
|
|
202
|
+
if (parent) {
|
|
203
|
+
if (skip && parent.direct)
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (rule.nested) {
|
|
208
|
+
|
|
209
|
+
if (!skip && next)
|
|
210
|
+
browse(rule.nested, reverse ? [node.parentNode] : node.children, rule);
|
|
211
|
+
|
|
212
|
+
// Again same
|
|
213
|
+
if (!parent)
|
|
214
|
+
browse(rule, reverse ? [node.parentNode] : node.children);
|
|
215
|
+
|
|
216
|
+
} else {
|
|
217
|
+
if (!skip)
|
|
218
|
+
rule.output.push(node);
|
|
219
|
+
if (next)
|
|
220
|
+
browse(rule, reverse ? [node.parentNode] : node.children);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
if (reverse && !self.parentNode)
|
|
226
|
+
return output;
|
|
227
|
+
|
|
228
|
+
for (var rule of rules) {
|
|
229
|
+
browse(rule, reverse ? [self.parentNode] : self.children);
|
|
230
|
+
if (rule.output.length)
|
|
231
|
+
output.push.apply(output, rule.output);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
extendarr(output);
|
|
235
|
+
return output;
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
HTMLElement.prototype.parent = function() {
|
|
239
|
+
return this.parentNode;
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
HTMLElement.prototype.closest = function(selector) {
|
|
243
|
+
return this.find(selector, true);
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
HTMLElement.prototype.attrd = function(name, value) {
|
|
247
|
+
return this.attr('data-' + name, value);
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
HTMLElement.prototype.parsecache = function() {
|
|
251
|
+
|
|
252
|
+
var self = this;
|
|
253
|
+
if (self.cache)
|
|
254
|
+
return self;
|
|
255
|
+
|
|
256
|
+
self.cache = {};
|
|
257
|
+
self.cache.css = {};
|
|
258
|
+
self.cache.cls = {};
|
|
259
|
+
|
|
260
|
+
var tmp = self.attrs.class;
|
|
261
|
+
var arr;
|
|
262
|
+
|
|
263
|
+
if (tmp) {
|
|
264
|
+
arr = tmp.split(' ');
|
|
265
|
+
for (var c of arr)
|
|
266
|
+
self.cache.cls[c] = 1;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
var tmp = self.attrs.style;
|
|
270
|
+
if (tmp) {
|
|
271
|
+
arr = tmp.split(';');
|
|
272
|
+
for (var c of arr) {
|
|
273
|
+
var a = c.split(':');
|
|
274
|
+
self.cache.css[a[0]] = a[1];
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return self;
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
HTMLElement.prototype.stringifycache = function() {
|
|
282
|
+
var self = this;
|
|
283
|
+
self.attrs.class = Object.keys(self.cache.cls).join(' ');
|
|
284
|
+
|
|
285
|
+
var tmp = [];
|
|
286
|
+
|
|
287
|
+
for (var key in self.cache.css)
|
|
288
|
+
self.cache.css[key] && tmp.push(key + ':' + self.cache.css[key]);
|
|
289
|
+
|
|
290
|
+
if (tmp.length)
|
|
291
|
+
self.attrs.style = tmp.join(';');
|
|
292
|
+
else if (self.attrs.style != null)
|
|
293
|
+
delete self.attrs.style;
|
|
294
|
+
|
|
295
|
+
return self;
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
HTMLElement.prototype.attr = function(name, value) {
|
|
299
|
+
|
|
300
|
+
var self = this;
|
|
301
|
+
|
|
302
|
+
if (value === undefined)
|
|
303
|
+
return self.attrs[name];
|
|
304
|
+
|
|
305
|
+
if (value == null || value == '')
|
|
306
|
+
delete self.attrs[name];
|
|
307
|
+
else
|
|
308
|
+
self.attrs[name] = value + '';
|
|
309
|
+
|
|
310
|
+
return self;
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
HTMLElement.prototype.aclass = function(cls) {
|
|
314
|
+
var self = this;
|
|
315
|
+
self.parsecache();
|
|
316
|
+
var arr = cls.split(/\s|,/);
|
|
317
|
+
for (var m of arr)
|
|
318
|
+
self.cache.cls[m] = 1;
|
|
319
|
+
self.stringifycache();
|
|
320
|
+
return self;
|
|
321
|
+
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
HTMLElement.prototype.hclass = function(cls) {
|
|
325
|
+
var self = this;
|
|
326
|
+
self.parsecache();
|
|
327
|
+
return self.cache.cls[cls] === 1;
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
HTMLElement.prototype.tclass = function(cls, value) {
|
|
331
|
+
var self = this;
|
|
332
|
+
self.parsecache();
|
|
333
|
+
var arr = cls.split(/\s|,/);
|
|
334
|
+
for (var m of arr) {
|
|
335
|
+
if (self.cache.cls[m]) {
|
|
336
|
+
if (!value)
|
|
337
|
+
delete self.cache.cls[m];
|
|
338
|
+
} else {
|
|
339
|
+
if (value || value === undefined)
|
|
340
|
+
self.cache.cls[m] = 1;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
self.stringifycache();
|
|
344
|
+
return self;
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
HTMLElement.prototype.rclass = function(cls) {
|
|
348
|
+
var self = this;
|
|
349
|
+
self.parsecache();
|
|
350
|
+
|
|
351
|
+
var arr = cls.split(/\s|,/);
|
|
352
|
+
for (var m of arr)
|
|
353
|
+
delete self.cache.cls[m];
|
|
354
|
+
|
|
355
|
+
self.stringifycache();
|
|
356
|
+
return self;
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
HTMLElement.prototype.css = function(key, value) {
|
|
360
|
+
var self = this;
|
|
361
|
+
self.parsecache();
|
|
362
|
+
if (typeof(key) === 'object') {
|
|
363
|
+
for (var k of Object.keys(key)) {
|
|
364
|
+
value = key[k];
|
|
365
|
+
if (value)
|
|
366
|
+
self.cache.css[k] = value;
|
|
367
|
+
else
|
|
368
|
+
delete self.cache.css[k];
|
|
369
|
+
}
|
|
370
|
+
} else {
|
|
371
|
+
if (value)
|
|
372
|
+
self.cache.css[key] = value;
|
|
373
|
+
else
|
|
374
|
+
delete self.cache.css[key];
|
|
375
|
+
}
|
|
376
|
+
self.stringifycache();
|
|
377
|
+
return self;
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
HTMLElement.prototype.remove = function() {
|
|
381
|
+
var self = this;
|
|
382
|
+
if (self.parentNode) {
|
|
383
|
+
var index = self.parentNode.children.indexOf(self);
|
|
384
|
+
if (index !== -1)
|
|
385
|
+
self.parentNode.children.splice(index, 1);
|
|
386
|
+
}
|
|
387
|
+
return self;
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
HTMLElement.prototype.append = function(str) {
|
|
391
|
+
|
|
392
|
+
var self = this;
|
|
393
|
+
var dom = parseHTML(str, null, null, self.xml);
|
|
394
|
+
|
|
395
|
+
for (var item of dom.children)
|
|
396
|
+
self.children.push(item);
|
|
397
|
+
|
|
398
|
+
return dom.children.length === 1 ? dom.children[0] : dom.children;
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
HTMLElement.prototype.prepend = function(str) {
|
|
402
|
+
|
|
403
|
+
var self = this;
|
|
404
|
+
var dom = parseHTML(str, null, null, self.xml);
|
|
405
|
+
|
|
406
|
+
for (var item of dom.children)
|
|
407
|
+
self.children.unshift(item);
|
|
408
|
+
|
|
409
|
+
return dom;
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
HTMLElement.prototype.text = function() {
|
|
413
|
+
return this.html().removeTags();
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
HTMLElement.prototype.toString = HTMLElement.prototype.html = function(formatted) {
|
|
417
|
+
|
|
418
|
+
var self = this;
|
|
419
|
+
var builder = [];
|
|
420
|
+
|
|
421
|
+
var browse = function(children, level) {
|
|
422
|
+
|
|
423
|
+
for (var item of children) {
|
|
424
|
+
|
|
425
|
+
var indent = formatted && level ? ''.padLeft(level, '\t') : '';
|
|
426
|
+
var tag = item.tagName.toLowerCase();
|
|
427
|
+
var attrs = [];
|
|
428
|
+
|
|
429
|
+
for (var key in item.attrs) {
|
|
430
|
+
var val = item.attrs[key];
|
|
431
|
+
if (!val && (key === 'class' || key.substring(0, 5) === 'data-' || key === 'id'))
|
|
432
|
+
continue;
|
|
433
|
+
attrs.push(key + (val ? ('="' + (val || '') + '"') : ''));
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
switch (item.tagName) {
|
|
437
|
+
case 'TEXT':
|
|
438
|
+
if (item.textContent)
|
|
439
|
+
builder.push(indent + item.textContent);
|
|
440
|
+
break;
|
|
441
|
+
default:
|
|
442
|
+
if (item.unpair) {
|
|
443
|
+
builder.push(indent + '<' + tag + (attrs.length ? (' ' + attrs.join(' ')) : '') + ' />');
|
|
444
|
+
} else {
|
|
445
|
+
builder.push(indent + '<' + tag + (attrs.length ? (' ' + attrs.join(' ')) : '') + '>' + (item.children.length ? '' : ('</' + tag + '>')));
|
|
446
|
+
if (item.children.length) {
|
|
447
|
+
browse(item.children, level + 1);
|
|
448
|
+
builder.push(indent + '</' + tag + '>');
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
break;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
browse(self.tagName ? [self] : self.children, 0);
|
|
457
|
+
return builder.join(formatted ? '\n' : '');
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
function removeComments(html) {
|
|
461
|
+
var tagBeg = '<!--';
|
|
462
|
+
var tagEnd = '-->';
|
|
463
|
+
var beg = html.indexOf(tagBeg);
|
|
464
|
+
var end = 0;
|
|
465
|
+
while (beg !== -1) {
|
|
466
|
+
end = html.indexOf(tagEnd, beg + 4);
|
|
467
|
+
|
|
468
|
+
if (end === -1)
|
|
469
|
+
break;
|
|
470
|
+
|
|
471
|
+
var comment = html.substring(beg, end + 3);
|
|
472
|
+
html = html.replaceAll(comment, '');
|
|
473
|
+
beg = html.indexOf(tagBeg, beg);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
return html;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
function parseHTML(html, trim, onerror, isxml) {
|
|
480
|
+
|
|
481
|
+
var makeText = function(parent, str) {
|
|
482
|
+
var obj = new HTMLElement();
|
|
483
|
+
obj.xml = isxml;
|
|
484
|
+
obj.tagName = 'TEXT';
|
|
485
|
+
obj.children = [];
|
|
486
|
+
obj.attrs = {};
|
|
487
|
+
obj.textContent = str;
|
|
488
|
+
obj.parentNode = parent;
|
|
489
|
+
return obj;
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
var parseAttrs = function(str) {
|
|
493
|
+
var attrs = str.match(/[a-z-0-9A-Z\:]+(=("|').*?("|'))?/g);
|
|
494
|
+
var obj = {};
|
|
495
|
+
if (attrs) {
|
|
496
|
+
for (var m of attrs) {
|
|
497
|
+
m = m.trim();
|
|
498
|
+
var index = m.indexOf('=');
|
|
499
|
+
var key, val;
|
|
500
|
+
key = (index === -1 ? m : m.substring(0, index)).trim();
|
|
501
|
+
val = index === -1 ? '' : m.substring(m.indexOf('"', index) + 1, m.lastIndexOf('"')).trim();
|
|
502
|
+
obj[key] = val;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
return obj;
|
|
506
|
+
};
|
|
507
|
+
|
|
508
|
+
var parseElements = function(str, parent) {
|
|
509
|
+
|
|
510
|
+
var counter = 0;
|
|
511
|
+
var count = 0;
|
|
512
|
+
var beg = str.indexOf('<');
|
|
513
|
+
var end = -1;
|
|
514
|
+
var tmp;
|
|
515
|
+
|
|
516
|
+
if (beg !== -1)
|
|
517
|
+
end = str.indexOf('>', beg + 1);
|
|
518
|
+
|
|
519
|
+
if (beg === -1 || end === -1) {
|
|
520
|
+
if (parent) {
|
|
521
|
+
tmp = str;
|
|
522
|
+
if (trim)
|
|
523
|
+
tmp = tmp.trim();
|
|
524
|
+
tmp && parent.children.push(makeText(parent, tmp));
|
|
525
|
+
}
|
|
526
|
+
return '';
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
if (beg > 0) {
|
|
531
|
+
tmp = str.substring(0, beg);
|
|
532
|
+
|
|
533
|
+
if (trim)
|
|
534
|
+
tmp = tmp.trim();
|
|
535
|
+
|
|
536
|
+
if (tmp)
|
|
537
|
+
parent.children.push(makeText(parent, tmp));
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
var node = str.substring(beg + 1, end);
|
|
541
|
+
var dom = new HTMLElement();
|
|
542
|
+
|
|
543
|
+
dom.xml = isxml;
|
|
544
|
+
|
|
545
|
+
// Doctype or xml?
|
|
546
|
+
if (node[0] === '!' || node[0] === '?')
|
|
547
|
+
return str.substring(end + 1);
|
|
548
|
+
|
|
549
|
+
if (node[node.length - 1] === '/') {
|
|
550
|
+
node = node.substring(0, node.length - 1);
|
|
551
|
+
dom.unpair = true;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
var tag = node;
|
|
555
|
+
var index = tag.indexOf(' ');
|
|
556
|
+
|
|
557
|
+
if (index > 0) {
|
|
558
|
+
tag = tag.substring(0, index);
|
|
559
|
+
node = node.substring(index + 1);
|
|
560
|
+
} else
|
|
561
|
+
node = '';
|
|
562
|
+
|
|
563
|
+
if (tag.indexOf('/') !== -1) {
|
|
564
|
+
onerror && onerror(tag);
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
dom.tagName = tag.toUpperCase();
|
|
569
|
+
dom.children = [];
|
|
570
|
+
dom.attrs = node ? parseAttrs(node) : {};
|
|
571
|
+
dom.raw = tag;
|
|
572
|
+
dom.parentNode = parent;
|
|
573
|
+
|
|
574
|
+
parent.children.push(dom);
|
|
575
|
+
str = str.substring(end + 1);
|
|
576
|
+
|
|
577
|
+
// Unpair tags
|
|
578
|
+
if (!isxml) {
|
|
579
|
+
switch (dom.tagName) {
|
|
580
|
+
case 'BR':
|
|
581
|
+
case 'HR':
|
|
582
|
+
case 'IMG':
|
|
583
|
+
case 'META':
|
|
584
|
+
case 'LINK':
|
|
585
|
+
case 'INPUT':
|
|
586
|
+
dom.unpair = true;
|
|
587
|
+
return str;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
var pos = 0;
|
|
592
|
+
var tagBeg = '<' + dom.raw;
|
|
593
|
+
var tagEnd = '</' + dom.raw + '>';
|
|
594
|
+
|
|
595
|
+
while (true) {
|
|
596
|
+
|
|
597
|
+
if (counter++ > 10000)
|
|
598
|
+
break;
|
|
599
|
+
|
|
600
|
+
beg = str.indexOf(tagBeg, pos);
|
|
601
|
+
end = str.indexOf(tagEnd, pos);
|
|
602
|
+
|
|
603
|
+
// Fallback for the non-exists end tag
|
|
604
|
+
if (end === -1) {
|
|
605
|
+
end = str.length;
|
|
606
|
+
pos = end;
|
|
607
|
+
break;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
if (beg !== -1 && beg < end) {
|
|
611
|
+
count++;
|
|
612
|
+
pos = str.indexOf('>', beg);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
if (beg === -1 || end < beg) {
|
|
616
|
+
|
|
617
|
+
pos = end + tagEnd.length;
|
|
618
|
+
|
|
619
|
+
if (count) {
|
|
620
|
+
count--;
|
|
621
|
+
continue;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
break;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
var inner = str.substring(0, pos - tagEnd.length);
|
|
629
|
+
if (inner.indexOf('<') === -1 || (/\<(script|style|template)/).test(tag)) {
|
|
630
|
+
if (trim)
|
|
631
|
+
inner = inner.trim();
|
|
632
|
+
if (inner)
|
|
633
|
+
dom.children.push(makeText(dom, inner));
|
|
634
|
+
} else {
|
|
635
|
+
while (inner)
|
|
636
|
+
inner = parseElements(inner, dom);
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
str = str.substring(end + tagEnd.length, str.length);
|
|
640
|
+
|
|
641
|
+
if (str && str.indexOf('<') === -1) {
|
|
642
|
+
if (trim)
|
|
643
|
+
str = str.trim();
|
|
644
|
+
if (str)
|
|
645
|
+
parent.children.push(makeText(parent, str));
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
return str;
|
|
649
|
+
};
|
|
650
|
+
|
|
651
|
+
html = removeComments(html);
|
|
652
|
+
|
|
653
|
+
var dom = new HTMLElement();
|
|
654
|
+
dom.xml = isxml;
|
|
655
|
+
|
|
656
|
+
while (html)
|
|
657
|
+
html = parseElements(html, dom);
|
|
658
|
+
|
|
659
|
+
return dom;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
exports.parseHTML = parseHTML;
|