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