html-minifier 3.5.15 → 3.5.19
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 +14 -16
- package/cli.js +1 -1
- package/package.json +6 -6
- package/src/htmlminifier.js +53 -47
- package/src/htmlparser.js +40 -10
package/README.md
CHANGED
|
@@ -3,14 +3,12 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/html-minifier)
|
|
4
4
|
[](https://travis-ci.org/kangax/html-minifier)
|
|
5
5
|
[](https://david-dm.org/kangax/html-minifier)
|
|
6
|
-
[](https://david-dm.org/kangax/html-minifier?type=dev)
|
|
7
|
-
[](https://gitter.im/kangax/html-minifier)
|
|
8
6
|
|
|
9
|
-
[HTMLMinifier](
|
|
7
|
+
[HTMLMinifier](https://kangax.github.io/html-minifier/) is a highly **configurable**, **well-tested**, JavaScript-based HTML minifier.
|
|
10
8
|
|
|
11
9
|
See [corresponding blog post](http://perfectionkills.com/experimenting-with-html-minifier/) for all the gory details of [how it works](http://perfectionkills.com/experimenting-with-html-minifier/#how_it_works), [description of each option](http://perfectionkills.com/experimenting-with-html-minifier/#options), [testing results](http://perfectionkills.com/experimenting-with-html-minifier/#field_testing) and [conclusions](http://perfectionkills.com/experimenting-with-html-minifier/#cost_and_benefits).
|
|
12
10
|
|
|
13
|
-
[Test suite is available online](
|
|
11
|
+
[Test suite is available online](https://kangax.github.io/html-minifier/tests/).
|
|
14
12
|
|
|
15
13
|
Also see corresponding [Ruby wrapper](https://github.com/stereobooster/html_minifier), and for Node.js, [Grunt plugin](https://github.com/gruntjs/grunt-contrib-htmlmin), [Gulp module](https://github.com/jonschlinkert/gulp-htmlmin), [Koa middleware wrapper](https://github.com/koajs/html-minifier) and [Express middleware wrapper](https://github.com/melonmanchan/express-minify-html).
|
|
16
14
|
|
|
@@ -22,19 +20,19 @@ How does HTMLMinifier compare to other solutions — [HTML Minifier from Will Pe
|
|
|
22
20
|
|
|
23
21
|
| Site | Original size *(KB)* | HTMLMinifier | minimize | Will Peavy | htmlcompressor.com |
|
|
24
22
|
| ---------------------------------------------------------------------------- |:--------------------:| ------------:| --------:| ----------:| ------------------:|
|
|
25
|
-
| [Google](https://www.google.com/) |
|
|
26
|
-
| [Twitter](https://twitter.com/) |
|
|
27
|
-
| [HTMLMinifier](https://github.com/kangax/html-minifier) |
|
|
28
|
-
| [New York Times](https://www.nytimes.com/) |
|
|
29
|
-
| [Stack Overflow](https://stackoverflow.com/) |
|
|
30
|
-
| [Bootstrap CSS](https://getbootstrap.com/docs/3.3/css/) |
|
|
31
|
-
| [BBC](https://www.bbc.co.uk/) |
|
|
32
|
-
| [Amazon](https://www.amazon.co.uk/) |
|
|
33
|
-
| [Wikipedia](https://en.wikipedia.org/wiki/President_of_the_United_States) |
|
|
34
|
-
| [NBC](https://www.nbc.com/) |
|
|
23
|
+
| [Google](https://www.google.com/) | 46 | **42** | 46 | 48 | 46 |
|
|
24
|
+
| [Twitter](https://twitter.com/) | 143 | **107** | 136 | 157 | 136 |
|
|
25
|
+
| [HTMLMinifier](https://github.com/kangax/html-minifier) | 152 | **119** | 127 | 132 | 127 |
|
|
26
|
+
| [New York Times](https://www.nytimes.com/) | 223 | **152** | 173 | 168 | 156 |
|
|
27
|
+
| [Stack Overflow](https://stackoverflow.com/) | 258 | **201** | 211 | 220 | 208 |
|
|
28
|
+
| [Bootstrap CSS](https://getbootstrap.com/docs/3.3/css/) | 271 | **260** | 269 | 229 | 269 |
|
|
29
|
+
| [BBC](https://www.bbc.co.uk/) | 299 | **242** | 290 | 293 | 283 |
|
|
30
|
+
| [Amazon](https://www.amazon.co.uk/) | 398 | **342** | 385 | 397 | n/a |
|
|
31
|
+
| [Wikipedia](https://en.wikipedia.org/wiki/President_of_the_United_States) | 485 | **452** | 470 | 487 | 469 |
|
|
32
|
+
| [NBC](https://www.nbc.com/) | 679 | **639** | 675 | 678 | n/a |
|
|
35
33
|
| [Eloquent Javascript](https://eloquentjavascript.net/1st_edition/print.html) | 870 | **815** | 840 | 864 | n/a |
|
|
36
|
-
| [ES6 table](https://kangax.github.io/compat-table/es6/) |
|
|
37
|
-
| [ES6 draft](https://tc39.github.io/ecma262/) |
|
|
34
|
+
| [ES6 table](https://kangax.github.io/compat-table/es6/) | 5109 | **4353** | 4834 | n/a | n/a |
|
|
35
|
+
| [ES6 draft](https://tc39.github.io/ecma262/) | 6063 | **5443** | 5607 | n/a | n/a |
|
|
38
36
|
|
|
39
37
|
## Options Quick Reference
|
|
40
38
|
|
package/cli.js
CHANGED
|
@@ -140,7 +140,7 @@ var mainOptionKeys = Object.keys(mainOptions);
|
|
|
140
140
|
mainOptionKeys.forEach(function(key) {
|
|
141
141
|
var option = mainOptions[key];
|
|
142
142
|
if (Array.isArray(option)) {
|
|
143
|
-
key = '--' + paramCase(key);
|
|
143
|
+
key = key === 'minifyURLs' ? '--minify-urls' : '--' + paramCase(key);
|
|
144
144
|
key += option[1] === parseJSON ? ' [value]' : ' <value>';
|
|
145
145
|
program.option(key, option[0], option[1]);
|
|
146
146
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "html-minifier",
|
|
3
3
|
"description": "Highly configurable, well-tested, JavaScript-based HTML minifier.",
|
|
4
|
-
"version": "3.5.
|
|
4
|
+
"version": "3.5.19",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
7
7
|
"compress",
|
|
@@ -23,11 +23,11 @@
|
|
|
23
23
|
"uglifier",
|
|
24
24
|
"uglify"
|
|
25
25
|
],
|
|
26
|
-
"homepage": "
|
|
26
|
+
"homepage": "https://kangax.github.io/html-minifier/",
|
|
27
27
|
"author": "Juriy \"kangax\" Zaytsev",
|
|
28
28
|
"maintainers": [
|
|
29
29
|
"Alex Lam <alexlamsl@gmail.com>",
|
|
30
|
-
"Juriy Zaytsev <kangax@gmail.com> (http://perfectionkills.com)"
|
|
30
|
+
"Juriy Zaytsev <kangax@gmail.com> (http://perfectionkills.com/)"
|
|
31
31
|
],
|
|
32
32
|
"contributors": [
|
|
33
33
|
"Gilmore Davidson (https://github.com/gilmoreorless)",
|
|
@@ -56,11 +56,11 @@
|
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"camel-case": "3.0.x",
|
|
58
58
|
"clean-css": "4.1.x",
|
|
59
|
-
"commander": "2.
|
|
59
|
+
"commander": "2.16.x",
|
|
60
60
|
"he": "1.1.x",
|
|
61
61
|
"param-case": "2.1.x",
|
|
62
62
|
"relateurl": "0.2.x",
|
|
63
|
-
"uglify-js": "3.
|
|
63
|
+
"uglify-js": "3.4.x"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
66
|
"grunt": "1.0.x",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
},
|
|
73
73
|
"benchmarkDependencies": {
|
|
74
74
|
"brotli": "1.3.x",
|
|
75
|
-
"chalk": "2.
|
|
75
|
+
"chalk": "2.4.x",
|
|
76
76
|
"cli-table": "0.3.x",
|
|
77
77
|
"lzma": "2.3.x",
|
|
78
78
|
"minimize": "2.2.x",
|
package/src/htmlminifier.js
CHANGED
|
@@ -9,10 +9,7 @@ var UglifyJS = require('uglify-js');
|
|
|
9
9
|
var utils = require('./utils');
|
|
10
10
|
|
|
11
11
|
function trimWhitespace(str) {
|
|
12
|
-
|
|
13
|
-
return str;
|
|
14
|
-
}
|
|
15
|
-
return str.replace(/^[ \n\r\t\f]+/, '').replace(/[ \n\r\t\f]+$/, '');
|
|
12
|
+
return str && str.replace(/^[ \n\r\t\f]+/, '').replace(/[ \n\r\t\f]+$/, '');
|
|
16
13
|
}
|
|
17
14
|
|
|
18
15
|
function collapseWhitespaceAll(str) {
|
|
@@ -112,7 +109,7 @@ function isEventAttribute(attrName, options) {
|
|
|
112
109
|
}
|
|
113
110
|
|
|
114
111
|
function canRemoveAttributeQuotes(value) {
|
|
115
|
-
//
|
|
112
|
+
// https://mathiasbynens.be/notes/unquoted-attribute-values
|
|
116
113
|
return /^[^ \t\n\f\r"'`=<>]+$/.test(value);
|
|
117
114
|
}
|
|
118
115
|
|
|
@@ -258,7 +255,7 @@ function isSrcset(attrName, tag) {
|
|
|
258
255
|
}
|
|
259
256
|
|
|
260
257
|
function cleanAttributeValue(tag, attrName, attrValue, options, attrs) {
|
|
261
|
-
if (
|
|
258
|
+
if (isEventAttribute(attrName, options)) {
|
|
262
259
|
attrValue = trimWhitespace(attrValue).replace(/^javascript:\s*/i, '');
|
|
263
260
|
return options.minifyJS(attrValue, true);
|
|
264
261
|
}
|
|
@@ -314,7 +311,7 @@ function cleanAttributeValue(tag, attrName, attrValue, options, attrs) {
|
|
|
314
311
|
return (+numString).toString();
|
|
315
312
|
});
|
|
316
313
|
}
|
|
317
|
-
else if (
|
|
314
|
+
else if (options.customAttrCollapse && options.customAttrCollapse.test(attrName)) {
|
|
318
315
|
attrValue = attrValue.replace(/\n+|\r+|\s{2,}/g, '');
|
|
319
316
|
}
|
|
320
317
|
else if (tag === 'script' && attrName === 'type') {
|
|
@@ -377,7 +374,7 @@ function processScript(text, options, currentAttrs) {
|
|
|
377
374
|
// Tag omission rules from https://html.spec.whatwg.org/multipage/syntax.html#optional-tags
|
|
378
375
|
// with the following deviations:
|
|
379
376
|
// - retain <body> if followed by <noscript>
|
|
380
|
-
// - </rb>, </rt>, </rtc>, </rp> & </tfoot> follow
|
|
377
|
+
// - </rb>, </rt>, </rtc>, </rp> & </tfoot> follow https://www.w3.org/TR/html5/syntax.html#optional-tags
|
|
381
378
|
// - retain all tags which are adjacent to non-standard HTML tags
|
|
382
379
|
var optionalStartTags = createMapFromString('html,head,body,colgroup,tbody');
|
|
383
380
|
var optionalEndTags = createMapFromString('html,head,body,li,dt,dd,p,rb,rt,rtc,rp,optgroup,option,colgroup,caption,thead,tbody,tfoot,tr,td,th');
|
|
@@ -522,7 +519,7 @@ function canTrimWhitespace(tag) {
|
|
|
522
519
|
}
|
|
523
520
|
|
|
524
521
|
function normalizeAttr(attr, attrs, tag, options) {
|
|
525
|
-
var attrName = options.
|
|
522
|
+
var attrName = options.name(attr.name),
|
|
526
523
|
attrValue = attr.value;
|
|
527
524
|
|
|
528
525
|
if (options.decodeEntities && attrValue) {
|
|
@@ -538,7 +535,9 @@ function normalizeAttr(attr, attrs, tag, options) {
|
|
|
538
535
|
return;
|
|
539
536
|
}
|
|
540
537
|
|
|
541
|
-
|
|
538
|
+
if (attrValue) {
|
|
539
|
+
attrValue = cleanAttributeValue(tag, attrName, attrValue, options, attrs);
|
|
540
|
+
}
|
|
542
541
|
|
|
543
542
|
if (options.removeEmptyAttributes &&
|
|
544
543
|
canDeleteEmptyAttribute(tag, attrName, attrValue, options)) {
|
|
@@ -615,6 +614,9 @@ function identity(value) {
|
|
|
615
614
|
|
|
616
615
|
function processOptions(values) {
|
|
617
616
|
var options = {
|
|
617
|
+
name: function(name) {
|
|
618
|
+
return name.toLowerCase();
|
|
619
|
+
},
|
|
618
620
|
canCollapseWhitespace: canCollapseWhitespace,
|
|
619
621
|
canTrimWhitespace: canTrimWhitespace,
|
|
620
622
|
html5: true,
|
|
@@ -631,7 +633,12 @@ function processOptions(values) {
|
|
|
631
633
|
};
|
|
632
634
|
Object.keys(values).forEach(function(key) {
|
|
633
635
|
var value = values[key];
|
|
634
|
-
if (key === '
|
|
636
|
+
if (key === 'caseSensitive') {
|
|
637
|
+
if (value) {
|
|
638
|
+
options.name = identity;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
else if (key === 'log') {
|
|
635
642
|
if (typeof value === 'function') {
|
|
636
643
|
options.log = value;
|
|
637
644
|
}
|
|
@@ -732,7 +739,7 @@ function createSortFns(value, options, uidIgnore, uidAttr) {
|
|
|
732
739
|
|
|
733
740
|
function attrNames(attrs) {
|
|
734
741
|
return attrs.map(function(attr) {
|
|
735
|
-
return options.
|
|
742
|
+
return options.name(attr.name);
|
|
736
743
|
});
|
|
737
744
|
}
|
|
738
745
|
|
|
@@ -756,7 +763,7 @@ function createSortFns(value, options, uidIgnore, uidAttr) {
|
|
|
756
763
|
}
|
|
757
764
|
for (var i = 0, len = attrs.length; i < len; i++) {
|
|
758
765
|
var attr = attrs[i];
|
|
759
|
-
if (classChain &&
|
|
766
|
+
if (classChain && attr.value && options.name(attr.name) === 'class') {
|
|
760
767
|
classChain.add(trimWhitespace(attr.value).split(/[ \t\n\f\r]+/).filter(shouldSkipUIDs));
|
|
761
768
|
}
|
|
762
769
|
else if (options.processScripts && attr.name.toLowerCase() === 'type') {
|
|
@@ -946,16 +953,13 @@ function minify(value, options, partialMarkup) {
|
|
|
946
953
|
html5: options.html5,
|
|
947
954
|
|
|
948
955
|
start: function(tag, attrs, unary, unarySlash, autoGenerated) {
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
if (lowerTag === 'svg') {
|
|
956
|
+
if (tag.toLowerCase() === 'svg') {
|
|
952
957
|
options = Object.create(options);
|
|
953
|
-
options.keepClosingSlash = true;
|
|
954
958
|
options.caseSensitive = true;
|
|
959
|
+
options.keepClosingSlash = true;
|
|
960
|
+
options.name = identity;
|
|
955
961
|
}
|
|
956
|
-
|
|
957
|
-
tag = options.caseSensitive ? tag : lowerTag;
|
|
958
|
-
|
|
962
|
+
tag = options.name(tag);
|
|
959
963
|
currentTag = tag;
|
|
960
964
|
charsPrevTag = tag;
|
|
961
965
|
if (!inlineTextTags(tag)) {
|
|
@@ -1035,11 +1039,10 @@ function minify(value, options, partialMarkup) {
|
|
|
1035
1039
|
}
|
|
1036
1040
|
},
|
|
1037
1041
|
end: function(tag, attrs, autoGenerated) {
|
|
1038
|
-
|
|
1039
|
-
if (lowerTag === 'svg') {
|
|
1042
|
+
if (tag.toLowerCase() === 'svg') {
|
|
1040
1043
|
options = Object.getPrototypeOf(options);
|
|
1041
1044
|
}
|
|
1042
|
-
tag = options.
|
|
1045
|
+
tag = options.name(tag);
|
|
1043
1046
|
|
|
1044
1047
|
// check if current tag is in a whitespace stack
|
|
1045
1048
|
if (options.collapseWhitespace) {
|
|
@@ -1217,7 +1220,7 @@ function minify(value, options, partialMarkup) {
|
|
|
1217
1220
|
buffer.push(text);
|
|
1218
1221
|
},
|
|
1219
1222
|
doctype: function(doctype) {
|
|
1220
|
-
buffer.push(options.useShortDoctype ? '<!
|
|
1223
|
+
buffer.push(options.useShortDoctype ? '<!doctype html>' : collapseWhitespaceAll(doctype));
|
|
1221
1224
|
},
|
|
1222
1225
|
customAttrAssign: options.customAttrAssign,
|
|
1223
1226
|
customAttrSurround: options.customAttrSurround
|
|
@@ -1238,10 +1241,8 @@ function minify(value, options, partialMarkup) {
|
|
|
1238
1241
|
squashTrailingWhitespace('br');
|
|
1239
1242
|
}
|
|
1240
1243
|
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
if (uidPattern) {
|
|
1244
|
-
str = str.replace(uidPattern, function(match, prefix, index, suffix) {
|
|
1244
|
+
return joinResultSegments(buffer, options, uidPattern ? function(str) {
|
|
1245
|
+
return str.replace(uidPattern, function(match, prefix, index, suffix) {
|
|
1245
1246
|
var chunk = ignoredCustomMarkupChunks[+index][0];
|
|
1246
1247
|
if (options.collapseWhitespace) {
|
|
1247
1248
|
if (prefix !== '\t') {
|
|
@@ -1257,39 +1258,44 @@ function minify(value, options, partialMarkup) {
|
|
|
1257
1258
|
}
|
|
1258
1259
|
return chunk;
|
|
1259
1260
|
});
|
|
1260
|
-
}
|
|
1261
|
-
|
|
1262
|
-
str = str.replace(new RegExp('<!--' + uidIgnore + '([0-9]+)-->', 'g'), function(match, index) {
|
|
1261
|
+
} : identity, uidIgnore ? function(str) {
|
|
1262
|
+
return str.replace(new RegExp('<!--' + uidIgnore + '([0-9]+)-->', 'g'), function(match, index) {
|
|
1263
1263
|
return ignoredMarkupChunks[+index];
|
|
1264
1264
|
});
|
|
1265
|
-
}
|
|
1266
|
-
|
|
1267
|
-
return str;
|
|
1265
|
+
} : identity);
|
|
1268
1266
|
}
|
|
1269
1267
|
|
|
1270
|
-
function joinResultSegments(results, options) {
|
|
1268
|
+
function joinResultSegments(results, options, restoreCustom, restoreIgnore) {
|
|
1271
1269
|
var str;
|
|
1272
1270
|
var maxLineLength = options.maxLineLength;
|
|
1273
1271
|
if (maxLineLength) {
|
|
1274
|
-
var
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
line += token;
|
|
1272
|
+
var line = '', lines = [];
|
|
1273
|
+
while (results.length) {
|
|
1274
|
+
var len = line.length;
|
|
1275
|
+
var end = results[0].indexOf('\n');
|
|
1276
|
+
if (end < 0) {
|
|
1277
|
+
line += restoreIgnore(restoreCustom(results.shift()));
|
|
1281
1278
|
}
|
|
1282
1279
|
else {
|
|
1283
|
-
|
|
1284
|
-
|
|
1280
|
+
line += restoreIgnore(restoreCustom(results[0].slice(0, end)));
|
|
1281
|
+
results[0] = results[0].slice(end + 1);
|
|
1282
|
+
}
|
|
1283
|
+
if (len > 0 && line.length > maxLineLength) {
|
|
1284
|
+
lines.push(line.slice(0, len));
|
|
1285
|
+
line = line.slice(len);
|
|
1286
|
+
}
|
|
1287
|
+
else if (end >= 0) {
|
|
1288
|
+
lines.push(line);
|
|
1289
|
+
line = '';
|
|
1285
1290
|
}
|
|
1286
1291
|
}
|
|
1287
|
-
|
|
1288
|
-
|
|
1292
|
+
if (line) {
|
|
1293
|
+
lines.push(line);
|
|
1294
|
+
}
|
|
1289
1295
|
str = lines.join('\n');
|
|
1290
1296
|
}
|
|
1291
1297
|
else {
|
|
1292
|
-
str = results.join('');
|
|
1298
|
+
str = restoreIgnore(restoreCustom(results.join('')));
|
|
1293
1299
|
}
|
|
1294
1300
|
return options.collapseWhitespace ? collapseWhitespace(str, options, true, true) : str;
|
|
1295
1301
|
}
|
package/src/htmlparser.js
CHANGED
|
@@ -60,7 +60,7 @@ var singleAttrIdentifier = /([^\s"'<>/=]+)/,
|
|
|
60
60
|
startTagOpen = new RegExp('^<' + qnameCapture),
|
|
61
61
|
startTagClose = /^\s*(\/?)>/,
|
|
62
62
|
endTag = new RegExp('^<\\/' + qnameCapture + '[^>]*>'),
|
|
63
|
-
doctype = /^<!DOCTYPE
|
|
63
|
+
doctype = /^<!DOCTYPE\s[^>]+>/i;
|
|
64
64
|
|
|
65
65
|
var IS_REGEX_CAPTURING_BROKEN = false;
|
|
66
66
|
'x'.replace(/x(.)?/g, function(m, g) {
|
|
@@ -140,7 +140,7 @@ function HTMLParser(html, handler) {
|
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
-
//
|
|
143
|
+
// https://en.wikipedia.org/wiki/Conditional_comment#Downlevel-revealed_conditional_comment
|
|
144
144
|
if (/^<!\[/.test(html)) {
|
|
145
145
|
var conditionalEnd = html.indexOf(']>');
|
|
146
146
|
|
|
@@ -267,12 +267,36 @@ function HTMLParser(html, handler) {
|
|
|
267
267
|
}
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
+
function closeIfFound(tagName) {
|
|
271
|
+
if (findTag(tagName) >= 0) {
|
|
272
|
+
parseEndTag('', tagName);
|
|
273
|
+
return true;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
270
277
|
function handleStartTag(match) {
|
|
271
278
|
var tagName = match.tagName;
|
|
272
279
|
var unarySlash = match.unarySlash;
|
|
273
280
|
|
|
274
|
-
if (handler.html5
|
|
275
|
-
|
|
281
|
+
if (handler.html5) {
|
|
282
|
+
if (lastTag === 'p' && nonPhrasing(tagName)) {
|
|
283
|
+
parseEndTag('', lastTag);
|
|
284
|
+
}
|
|
285
|
+
else if (tagName === 'tbody') {
|
|
286
|
+
closeIfFound('thead');
|
|
287
|
+
}
|
|
288
|
+
else if (tagName === 'tfoot') {
|
|
289
|
+
if (!closeIfFound('tbody')) {
|
|
290
|
+
closeIfFound('thead');
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
if (tagName === 'col' && findTag('colgroup') < 0) {
|
|
294
|
+
lastTag = 'colgroup';
|
|
295
|
+
stack.push({ tag: lastTag, attrs: [] });
|
|
296
|
+
if (handler.start) {
|
|
297
|
+
handler.start(lastTag, [], false, '');
|
|
298
|
+
}
|
|
299
|
+
}
|
|
276
300
|
}
|
|
277
301
|
|
|
278
302
|
if (!handler.html5 && !inline(tagName)) {
|
|
@@ -353,17 +377,23 @@ function HTMLParser(html, handler) {
|
|
|
353
377
|
}
|
|
354
378
|
}
|
|
355
379
|
|
|
380
|
+
function findTag(tagName) {
|
|
381
|
+
var pos;
|
|
382
|
+
var needle = tagName.toLowerCase();
|
|
383
|
+
for (pos = stack.length - 1; pos >= 0; pos--) {
|
|
384
|
+
if (stack[pos].tag.toLowerCase() === needle) {
|
|
385
|
+
break;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
return pos;
|
|
389
|
+
}
|
|
390
|
+
|
|
356
391
|
function parseEndTag(tag, tagName) {
|
|
357
392
|
var pos;
|
|
358
393
|
|
|
359
394
|
// Find the closest opened tag of the same type
|
|
360
395
|
if (tagName) {
|
|
361
|
-
|
|
362
|
-
for (pos = stack.length - 1; pos >= 0; pos--) {
|
|
363
|
-
if (stack[pos].tag.toLowerCase() === needle) {
|
|
364
|
-
break;
|
|
365
|
-
}
|
|
366
|
-
}
|
|
396
|
+
pos = findTag(tagName);
|
|
367
397
|
}
|
|
368
398
|
// If no tag name is provided, clean shop
|
|
369
399
|
else {
|