html-minifier 0.7.2 → 1.1.1
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/README.md +38 -15
- package/cli.js +147 -23
- package/dist/htmlminifier.js +59 -55
- package/dist/htmlminifier.min.js +4 -4
- package/package.json +18 -21
- package/src/htmllint.js +168 -0
- package/src/htmlminifier.js +838 -0
- package/src/htmlparser.js +560 -0
|
@@ -0,0 +1,560 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* HTML Parser By John Resig (ejohn.org)
|
|
3
|
+
* Modified by Juriy "kangax" Zaytsev
|
|
4
|
+
* Original code by Erik Arvidsson, Mozilla Public License
|
|
5
|
+
* http://erik.eae.net/simplehtmlparser/simplehtmlparser.js
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
* // Use like so:
|
|
10
|
+
* HTMLParser(htmlString, {
|
|
11
|
+
* start: function(tag, attrs, unary) {},
|
|
12
|
+
* end: function(tag) {},
|
|
13
|
+
* chars: function(text) {},
|
|
14
|
+
* comment: function(text) {}
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* // or to get an XML string:
|
|
18
|
+
* HTMLtoXML(htmlString);
|
|
19
|
+
*
|
|
20
|
+
* // or to get an XML DOM Document
|
|
21
|
+
* HTMLtoDOM(htmlString);
|
|
22
|
+
*
|
|
23
|
+
* // or to inject into an existing document/DOM node
|
|
24
|
+
* HTMLtoDOM(htmlString, document);
|
|
25
|
+
* HTMLtoDOM(htmlString, document.body);
|
|
26
|
+
*
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/* global ActiveXObject, DOMDocument */
|
|
30
|
+
|
|
31
|
+
(function(global) {
|
|
32
|
+
'use strict';
|
|
33
|
+
|
|
34
|
+
// Regular Expressions for parsing tags and attributes
|
|
35
|
+
var singleAttrIdentifier = /([\w:\.-]+)/,
|
|
36
|
+
singleAttrAssign = /=/,
|
|
37
|
+
singleAttrAssigns = [ singleAttrAssign ],
|
|
38
|
+
singleAttrValues = [
|
|
39
|
+
/"((?:\\.|[^"])*)"/.source, // attr value double quotes
|
|
40
|
+
/'((?:\\.|[^'])*)'/.source, // attr value, single quotes
|
|
41
|
+
/([^>\s]+)/.source // attr value, no quotes
|
|
42
|
+
],
|
|
43
|
+
startTagOpen = /^<([\w:-]+)/,
|
|
44
|
+
startTagClose = /\s*(\/?)>/,
|
|
45
|
+
endTag = /^<\/([\w:-]+)[^>]*>/,
|
|
46
|
+
endingSlash = /\/>$/,
|
|
47
|
+
doctype = /^<!DOCTYPE [^>]+>/i;
|
|
48
|
+
|
|
49
|
+
var IS_REGEX_CAPTURING_BROKEN = false;
|
|
50
|
+
'x'.replace(/x(.)?/g, function(m, g) {
|
|
51
|
+
IS_REGEX_CAPTURING_BROKEN = g === '';
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Empty Elements - HTML 4.01
|
|
55
|
+
var empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed,wbr');
|
|
56
|
+
|
|
57
|
+
// Block Elements - HTML 4.01
|
|
58
|
+
// var block = makeMap('address,applet,blockquote,button,center,dd,del,dir,div,dl,dt,fieldset,form,frameset,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,p,pre,script,table,tbody,td,tfoot,th,thead,tr,ul');
|
|
59
|
+
|
|
60
|
+
// Inline Elements - HTML 4.01
|
|
61
|
+
var inline = makeMap('a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,noscript,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,svg,textarea,tt,u,var');
|
|
62
|
+
|
|
63
|
+
// Elements that you can, intentionally, leave open
|
|
64
|
+
// (and which close themselves)
|
|
65
|
+
var closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source');
|
|
66
|
+
|
|
67
|
+
// Attributes that have their values filled in disabled='disabled'
|
|
68
|
+
var fillAttrs = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected');
|
|
69
|
+
|
|
70
|
+
// Special Elements (can contain anything)
|
|
71
|
+
var special = makeMap('script,style');
|
|
72
|
+
|
|
73
|
+
var reCache = {}, stackedTag, reStackedTag, tagMatch;
|
|
74
|
+
|
|
75
|
+
function startTagForHandler( handler ) {
|
|
76
|
+
var customStartTagAttrs;
|
|
77
|
+
|
|
78
|
+
var startTagAttrs = new RegExp(
|
|
79
|
+
'(?:\\s*[\\w:\\.-]+'
|
|
80
|
+
+ '(?:\\s*'
|
|
81
|
+
+ '(?:' + joinSingleAttrAssigns(handler) + ')'
|
|
82
|
+
+ '\\s*(?:(?:"[^"]*")|(?:\'[^\']*\')|[^>\\s]+)'
|
|
83
|
+
+ ')?'
|
|
84
|
+
+ ')*'
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
if ( handler.customAttrSurround ) {
|
|
88
|
+
var attrClauses = [];
|
|
89
|
+
|
|
90
|
+
for ( var i = handler.customAttrSurround.length - 1; i >= 0; i-- ) {
|
|
91
|
+
// Capture the custom attribute opening and closing markup surrounding the standard attribute rules
|
|
92
|
+
attrClauses[i] = '(?:\\s*'
|
|
93
|
+
+ handler.customAttrSurround[i][0].source
|
|
94
|
+
+ startTagAttrs.source
|
|
95
|
+
+ handler.customAttrSurround[i][1].source
|
|
96
|
+
+ ')';
|
|
97
|
+
}
|
|
98
|
+
attrClauses.unshift(startTagAttrs.source);
|
|
99
|
+
|
|
100
|
+
customStartTagAttrs = new RegExp(
|
|
101
|
+
'((?:' + attrClauses.join('|') + ')*)'
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
// No custom attribute wrappers specified, so just capture the standard attribute rules
|
|
106
|
+
customStartTagAttrs = new RegExp('(' + startTagAttrs.source + ')');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return new RegExp(startTagOpen.source + customStartTagAttrs.source + startTagClose.source);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function attrForHandler( handler ) {
|
|
113
|
+
var singleAttr = new RegExp(
|
|
114
|
+
singleAttrIdentifier.source
|
|
115
|
+
+ '(?:\\s*'
|
|
116
|
+
+ '(' + joinSingleAttrAssigns( handler ) + ')'
|
|
117
|
+
+ '\\s*'
|
|
118
|
+
+ '(?:'
|
|
119
|
+
+ singleAttrValues.join('|')
|
|
120
|
+
+ ')'
|
|
121
|
+
+ ')?'
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
if ( handler.customAttrSurround ) {
|
|
125
|
+
var attrClauses = [];
|
|
126
|
+
for ( var i = handler.customAttrSurround.length - 1; i >= 0; i-- ) {
|
|
127
|
+
attrClauses[i] = '(?:'
|
|
128
|
+
+ '(' + handler.customAttrSurround[i][0].source + ')'
|
|
129
|
+
+ singleAttr.source
|
|
130
|
+
+ '(' + handler.customAttrSurround[i][1].source + ')'
|
|
131
|
+
+ ')';
|
|
132
|
+
}
|
|
133
|
+
attrClauses.unshift('(?:' + singleAttr.source + ')');
|
|
134
|
+
|
|
135
|
+
return new RegExp(attrClauses.join('|'), 'g');
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
return new RegExp(singleAttr.source, 'g');
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function joinSingleAttrAssigns( handler ) {
|
|
143
|
+
return singleAttrAssigns.concat(
|
|
144
|
+
handler.customAttrAssign || []
|
|
145
|
+
).map(function (assign) {
|
|
146
|
+
return '(?:' + assign.source + ')';
|
|
147
|
+
}).join('|');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
var HTMLParser = global.HTMLParser = function( html, handler ) {
|
|
151
|
+
var index, chars, match, stack = [], last = html, prevTag, nextTag;
|
|
152
|
+
stack.last = function() {
|
|
153
|
+
var last = this[ this.length - 1 ];
|
|
154
|
+
return last && last.tag;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
var startTag = startTagForHandler(handler);
|
|
158
|
+
var attr = attrForHandler(handler);
|
|
159
|
+
|
|
160
|
+
while ( html ) {
|
|
161
|
+
chars = true;
|
|
162
|
+
|
|
163
|
+
// Make sure we're not in a script or style element
|
|
164
|
+
if ( !stack.last() || !special[ stack.last() ] ) {
|
|
165
|
+
|
|
166
|
+
// Comment:
|
|
167
|
+
if ( /^<!--/.test( html ) ) {
|
|
168
|
+
index = html.indexOf('-->');
|
|
169
|
+
|
|
170
|
+
if ( index >= 0 ) {
|
|
171
|
+
if ( handler.comment ) {
|
|
172
|
+
handler.comment( html.substring( 4, index ) );
|
|
173
|
+
}
|
|
174
|
+
html = html.substring( index + 3 );
|
|
175
|
+
chars = false;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// http://en.wikipedia.org/wiki/Conditional_comment#Downlevel-revealed_conditional_comment
|
|
180
|
+
if ( /^<!\[/.test( html ) ) {
|
|
181
|
+
index = html.indexOf(']>');
|
|
182
|
+
|
|
183
|
+
if (index >= 0) {
|
|
184
|
+
if ( handler.comment ) {
|
|
185
|
+
handler.comment( html.substring(2, index + 1 ), true /* non-standard */ );
|
|
186
|
+
}
|
|
187
|
+
html = html.substring( index + 2 );
|
|
188
|
+
chars = false;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Ignored elements?
|
|
193
|
+
else if ( /^<\?/.test( html ) ) {
|
|
194
|
+
index = html.indexOf( '?>', 2 );
|
|
195
|
+
if ( index >= 0 ) {
|
|
196
|
+
if ( handler.chars ) {
|
|
197
|
+
handler.chars( html.substring( 0, index + 2 ) );
|
|
198
|
+
}
|
|
199
|
+
html = html.substring( index + 2 );
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
else if ( /^<%/.test( html ) ) {
|
|
204
|
+
index = html.indexOf( '%>', 2 );
|
|
205
|
+
if ( index >= 0 ) {
|
|
206
|
+
if ( handler.chars ) {
|
|
207
|
+
handler.chars(html.substring( 0, index + 2) );
|
|
208
|
+
}
|
|
209
|
+
html = html.substring( index + 2 );
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Doctype:
|
|
214
|
+
else if ( (match = doctype.exec( html )) ) {
|
|
215
|
+
if ( handler.doctype ) {
|
|
216
|
+
handler.doctype( match[0] );
|
|
217
|
+
}
|
|
218
|
+
html = html.substring( match[0].length );
|
|
219
|
+
chars = false;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// End tag:
|
|
223
|
+
else if ( /^<\//.test( html ) ) {
|
|
224
|
+
match = html.match( endTag );
|
|
225
|
+
|
|
226
|
+
if ( match ) {
|
|
227
|
+
html = html.substring( match[0].length );
|
|
228
|
+
match[0].replace( endTag, parseEndTag );
|
|
229
|
+
prevTag = '/' + match[1].toLowerCase();
|
|
230
|
+
chars = false;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
}
|
|
234
|
+
// Start tag:
|
|
235
|
+
else if ( /^</.test( html ) ) {
|
|
236
|
+
match = html.match( startTag );
|
|
237
|
+
if ( match ) {
|
|
238
|
+
html = html.substring( match[0].length );
|
|
239
|
+
match[0].replace( startTag, parseStartTag );
|
|
240
|
+
prevTag = match[1].toLowerCase();
|
|
241
|
+
chars = false;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if ( chars ) {
|
|
246
|
+
index = html.indexOf('<');
|
|
247
|
+
|
|
248
|
+
var text = index < 0 ? html : html.substring( 0, index );
|
|
249
|
+
html = index < 0 ? '' : html.substring( index );
|
|
250
|
+
|
|
251
|
+
// next tag
|
|
252
|
+
tagMatch = html.match( startTag );
|
|
253
|
+
if (tagMatch) {
|
|
254
|
+
nextTag = tagMatch[1];
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
tagMatch = html.match( endTag );
|
|
258
|
+
if (tagMatch) {
|
|
259
|
+
nextTag = '/' + tagMatch[1];
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
nextTag = '';
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if ( handler.chars ) {
|
|
267
|
+
handler.chars(text, prevTag, nextTag);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
|
|
275
|
+
stackedTag = stack.last().toLowerCase();
|
|
276
|
+
reStackedTag = reCache[stackedTag] || (reCache[stackedTag] = new RegExp('([\\s\\S]*?)<\/' + stackedTag + '[^>]*>', 'i'));
|
|
277
|
+
|
|
278
|
+
html = html.replace(reStackedTag, function(all, text) {
|
|
279
|
+
if (stackedTag !== 'script' && stackedTag !== 'style' && stackedTag !== 'noscript') {
|
|
280
|
+
text = text
|
|
281
|
+
.replace(/<!--([\s\S]*?)-->/g, '$1')
|
|
282
|
+
.replace(/<!\[CDATA\[([\s\S]*?)\]\]>/g, '$1');
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if ( handler.chars ) {
|
|
286
|
+
handler.chars( text );
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return '';
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
parseEndTag( '', stackedTag );
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if ( html === last ) {
|
|
296
|
+
throw 'Parse Error: ' + html;
|
|
297
|
+
}
|
|
298
|
+
last = html;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Clean up any remaining tags
|
|
302
|
+
parseEndTag();
|
|
303
|
+
|
|
304
|
+
function parseStartTag( tag, tagName, rest, unary ) {
|
|
305
|
+
var unarySlash = false;
|
|
306
|
+
|
|
307
|
+
while ( !handler.html5 && stack.last() && inline[ stack.last() ]) {
|
|
308
|
+
parseEndTag( '', stack.last() );
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if ( closeSelf[ tagName ] && stack.last() === tagName ) {
|
|
312
|
+
parseEndTag( '', tagName );
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
unary = empty[ tagName ] || !!unary;
|
|
316
|
+
|
|
317
|
+
var attrs = [];
|
|
318
|
+
|
|
319
|
+
rest.replace(attr, function () {
|
|
320
|
+
var name, value, fallbackValue, customOpen, customClose, customAssign, quote;
|
|
321
|
+
var ncp = 7; // number of captured parts, scalar
|
|
322
|
+
|
|
323
|
+
// hackish work around FF bug https://bugzilla.mozilla.org/show_bug.cgi?id=369778
|
|
324
|
+
if (IS_REGEX_CAPTURING_BROKEN && arguments[0].indexOf('""') === -1) {
|
|
325
|
+
if (arguments[3] === '') { arguments[3] = undefined; }
|
|
326
|
+
if (arguments[4] === '') { arguments[4] = undefined; }
|
|
327
|
+
if (arguments[5] === '') { arguments[5] = undefined; }
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
name = arguments[1];
|
|
331
|
+
if ( name ) {
|
|
332
|
+
customAssign = arguments[2];
|
|
333
|
+
fallbackValue = arguments[3];
|
|
334
|
+
value = fallbackValue || arguments[4] || arguments[5];
|
|
335
|
+
|
|
336
|
+
if (customAssign) {
|
|
337
|
+
quote = arguments[0].charAt(name.length + customAssign.length);
|
|
338
|
+
quote = (quote === '\'' || quote === '"') ? quote : '';
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
}
|
|
342
|
+
else if ( handler.customAttrSurround ) {
|
|
343
|
+
for ( var i = handler.customAttrSurround.length - 1; i >= 0; i-- ) {
|
|
344
|
+
name = arguments[i * ncp + 7];
|
|
345
|
+
customAssign = arguments[i * ncp + 8];
|
|
346
|
+
if ( name ) {
|
|
347
|
+
fallbackValue = arguments[i * ncp + 9];
|
|
348
|
+
value = fallbackValue
|
|
349
|
+
|| arguments[i * ncp + 10]
|
|
350
|
+
|| arguments[i * ncp + 11];
|
|
351
|
+
customOpen = arguments[i * ncp + 6];
|
|
352
|
+
customClose = arguments[i * ncp + 12];
|
|
353
|
+
break;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if ( value === undefined ) {
|
|
359
|
+
value = fillAttrs[name] ? name : fallbackValue;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
attrs.push({
|
|
363
|
+
name: name,
|
|
364
|
+
value: value,
|
|
365
|
+
escaped: value && value.replace(/(^|.)("+)/g, function(match) {
|
|
366
|
+
return match.replace(/"/g, '"');
|
|
367
|
+
}),
|
|
368
|
+
customAssign: customAssign || '=',
|
|
369
|
+
customOpen: customOpen || '',
|
|
370
|
+
customClose: customClose || '',
|
|
371
|
+
quote: quote || ''
|
|
372
|
+
});
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
if ( !unary ) {
|
|
376
|
+
stack.push( { tag: tagName, attrs: attrs } );
|
|
377
|
+
}
|
|
378
|
+
else {
|
|
379
|
+
unarySlash = tag.match( endingSlash );
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
if ( handler.start ) {
|
|
384
|
+
handler.start( tagName, attrs, unary, unarySlash );
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function parseEndTag( tag, tagName ) {
|
|
389
|
+
var pos;
|
|
390
|
+
|
|
391
|
+
// If no tag name is provided, clean shop
|
|
392
|
+
if ( !tagName ) {
|
|
393
|
+
pos = 0;
|
|
394
|
+
}
|
|
395
|
+
else {
|
|
396
|
+
// Find the closest opened tag of the same type
|
|
397
|
+
var needle = tagName.toLowerCase();
|
|
398
|
+
for ( pos = stack.length - 1; pos >= 0; pos-- ) {
|
|
399
|
+
if ( stack[ pos ].tag.toLowerCase() === needle ) {
|
|
400
|
+
break;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if ( pos >= 0 ) {
|
|
406
|
+
// Close all the open elements, up the stack
|
|
407
|
+
for ( var i = stack.length - 1; i >= pos; i-- ) {
|
|
408
|
+
if ( handler.end ) {
|
|
409
|
+
handler.end( stack[ i ].tag, stack[ i ].attrs );
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// Remove the open elements from the stack
|
|
414
|
+
stack.length = pos;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
global.HTMLtoXML = function( html ) {
|
|
420
|
+
var results = '';
|
|
421
|
+
|
|
422
|
+
new HTMLParser(html, {
|
|
423
|
+
start: function( tag, attrs, unary ) {
|
|
424
|
+
results += '<' + tag;
|
|
425
|
+
|
|
426
|
+
for ( var i = 0; i < attrs.length; i++ ) {
|
|
427
|
+
results += ' ' + attrs[i].name + '="' + attrs[i].escaped + '"';
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
results += (unary ? '/' : '') + '>';
|
|
431
|
+
},
|
|
432
|
+
end: function( tag ) {
|
|
433
|
+
results += '</' + tag + '>';
|
|
434
|
+
},
|
|
435
|
+
chars: function( text ) {
|
|
436
|
+
results += text;
|
|
437
|
+
},
|
|
438
|
+
comment: function( text ) {
|
|
439
|
+
results += '<!--' + text + '-->';
|
|
440
|
+
},
|
|
441
|
+
ignore: function(text) {
|
|
442
|
+
results += text;
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
return results;
|
|
447
|
+
};
|
|
448
|
+
|
|
449
|
+
global.HTMLtoDOM = function( html, doc ) {
|
|
450
|
+
// There can be only one of these elements
|
|
451
|
+
var one = makeMap('html,head,body,title');
|
|
452
|
+
|
|
453
|
+
// Enforce a structure for the document
|
|
454
|
+
var structure = {
|
|
455
|
+
link: 'head',
|
|
456
|
+
base: 'head'
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
if ( !doc ) {
|
|
460
|
+
if ( typeof DOMDocument !== 'undefined' ) {
|
|
461
|
+
doc = new DOMDocument();
|
|
462
|
+
}
|
|
463
|
+
else if ( typeof document !== 'undefined' && document.implementation && document.implementation.createDocument ) {
|
|
464
|
+
doc = document.implementation.createDocument('', '', null);
|
|
465
|
+
}
|
|
466
|
+
else if ( typeof ActiveX !== 'undefined' ) {
|
|
467
|
+
doc = new ActiveXObject('Msxml.DOMDocument');
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
}
|
|
471
|
+
else {
|
|
472
|
+
doc = doc.ownerDocument ||
|
|
473
|
+
doc.getOwnerDocument && doc.getOwnerDocument() ||
|
|
474
|
+
doc;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
var elems = [],
|
|
478
|
+
documentElement = doc.documentElement ||
|
|
479
|
+
doc.getDocumentElement && doc.getDocumentElement();
|
|
480
|
+
|
|
481
|
+
// If we're dealing with an empty document then we
|
|
482
|
+
// need to pre-populate it with the HTML document structure
|
|
483
|
+
if ( !documentElement && doc.createElement ) {
|
|
484
|
+
(function() {
|
|
485
|
+
var html = doc.createElement('html');
|
|
486
|
+
var head = doc.createElement('head');
|
|
487
|
+
head.appendChild( doc.createElement('title') );
|
|
488
|
+
html.appendChild( head );
|
|
489
|
+
html.appendChild( doc.createElement('body') );
|
|
490
|
+
doc.appendChild( html );
|
|
491
|
+
})();
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Find all the unique elements
|
|
495
|
+
if ( doc.getElementsByTagName ) {
|
|
496
|
+
for ( var i in one ) {
|
|
497
|
+
one[ i ] = doc.getElementsByTagName( i )[0];
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// If we're working with a document, inject contents into
|
|
502
|
+
// the body element
|
|
503
|
+
var curParentNode = one.body;
|
|
504
|
+
|
|
505
|
+
new HTMLParser( html, {
|
|
506
|
+
start: function( tagName, attrs, unary ) {
|
|
507
|
+
// If it's a pre-built element, then we can ignore
|
|
508
|
+
// its construction
|
|
509
|
+
if ( one[ tagName ] ) {
|
|
510
|
+
curParentNode = one[ tagName ];
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
var elem = doc.createElement( tagName );
|
|
515
|
+
|
|
516
|
+
for ( var attr in attrs ) {
|
|
517
|
+
elem.setAttribute( attrs[ attr ].name, attrs[ attr ].value );
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
if ( structure[ tagName ] && typeof one[ structure[ tagName ] ] !== 'boolean' ) {
|
|
521
|
+
one[ structure[ tagName ] ].appendChild( elem );
|
|
522
|
+
}
|
|
523
|
+
else if ( curParentNode && curParentNode.appendChild ) {
|
|
524
|
+
curParentNode.appendChild( elem );
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
if ( !unary ) {
|
|
528
|
+
elems.push( elem );
|
|
529
|
+
curParentNode = elem;
|
|
530
|
+
}
|
|
531
|
+
},
|
|
532
|
+
end: function( /* tag */ ) {
|
|
533
|
+
elems.length -= 1;
|
|
534
|
+
|
|
535
|
+
// Init the new parentNode
|
|
536
|
+
curParentNode = elems[ elems.length - 1 ];
|
|
537
|
+
},
|
|
538
|
+
chars: function( text ) {
|
|
539
|
+
curParentNode.appendChild( doc.createTextNode( text ) );
|
|
540
|
+
},
|
|
541
|
+
comment: function( /*text*/ ) {
|
|
542
|
+
// create comment node
|
|
543
|
+
},
|
|
544
|
+
ignore: function( /* text */ ) {
|
|
545
|
+
// What to do here?
|
|
546
|
+
}
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
return doc;
|
|
550
|
+
};
|
|
551
|
+
|
|
552
|
+
function makeMap(str) {
|
|
553
|
+
var obj = {}, items = str.split(',');
|
|
554
|
+
for ( var i = 0; i < items.length; i++ ) {
|
|
555
|
+
obj[ items[i] ] = true;
|
|
556
|
+
obj[ items[i].toUpperCase() ] = true;
|
|
557
|
+
}
|
|
558
|
+
return obj;
|
|
559
|
+
}
|
|
560
|
+
})(typeof exports === 'undefined' ? this : exports);
|