From 0eaa36b39cd536d7468f00981417cd1f6ea8aba5 Mon Sep 17 00:00:00 2001 From: Vitaliy Filippov Date: Tue, 14 May 2019 18:00:55 +0300 Subject: [PATCH] Sync with htmLawed 1.2.4.1 --- .eslintrc.js | 5 +- README.md | 6 +- htmLawed.js | 1465 +++++++++++++++++++++++++++++------- htmLawed.src.js | 1467 ++++++++++++++++++++++++++++++------- htmLawed_TESTCASE.txt | 8 +- htmLawed_TESTCASE_out.htm | 50 +- package.json | 5 +- 7 files changed, 2417 insertions(+), 589 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 74aa7ae..cd8e82c 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -10,7 +10,7 @@ module.exports = { } }, "plugins": [ - "no-regex-dot" + "no-regex-dot" ], "rules": { "indent": [ @@ -31,6 +31,9 @@ module.exports = { "no-empty": [ "off" ], + "no-useless-escape": [ + "off" + ], "no-regex-dot/no-regex-dot": [ "error" ] diff --git a/README.md b/README.md index 406f63f..7426f83 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,13 @@ # htmLawed -This is a JS rewrite of a very good and safe htmLawed HTML sanitizer, http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/ +This is a JS rewrite of a safe HTML sanitizer "htmLawed", http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/ It is safe against almost all possible XSS vectors; see test cases in htmLawed_TESTCASE.txt and rsnake_xss.txt. +Code is awful, but it works :D + +Version corresponds to 1.2.4.1 + ## Install `npm install htmlawed` diff --git a/htmLawed.js b/htmLawed.js index 0c21e6f..c78a237 100644 --- a/htmLawed.js +++ b/htmLawed.js @@ -1,4 +1,4 @@ -var _slicedToArray = function () {function sliceIterator(arr, i) {var _arr = [];var _n = true;var _d = false;var _e = undefined;try {for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {_arr.push(_s.value);if (i && _arr.length === i) break;}} catch (err) {_d = true;_e = err;} finally {try {if (!_n && _i["return"]) _i["return"]();} finally {if (_d) throw _e;}}return _arr;}return function (arr, i) {if (Array.isArray(arr)) {return arr;} else if (Symbol.iterator in Object(arr)) {return sliceIterator(arr, i);} else {throw new TypeError("Invalid attempt to destructure non-iterable instance");}};}();var _extends = Object.assign || function (target) {for (var i = 1; i < arguments.length; i++) {var source = arguments[i];for (var key in source) {if (Object.prototype.hasOwnProperty.call(source, key)) {target[key] = source[key];}}}return target;}; // JS rewrite of http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/ +var _slicedToArray = function () {function sliceIterator(arr, i) {var _arr = [];var _n = true;var _d = false;var _e = undefined;try {for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {_arr.push(_s.value);if (i && _arr.length === i) break;}} catch (err) {_d = true;_e = err;} finally {try {if (!_n && _i["return"]) _i["return"]();} finally {if (_d) throw _e;}}return _arr;}return function (arr, i) {if (Array.isArray(arr)) {return arr;} else if (Symbol.iterator in Object(arr)) {return sliceIterator(arr, i);} else {throw new TypeError("Invalid attempt to destructure non-iterable instance");}};}();var _extends = Object.assign || function (target) {for (var i = 1; i < arguments.length; i++) {var source = arguments[i];for (var key in source) {if (Object.prototype.hasOwnProperty.call(source, key)) {target[key] = source[key];}}}return target;}; // JS rewrite of http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/ 1.2.4.1 var htmLawed = module.exports = { @@ -22,6 +22,12 @@ var htmLawed = module.exports = r.push(i);} return r; }, + _nonempty: function (h) + { + for (var i in h) { + return true;} + return false; + }, _htmlspecialchars: function (t) { return t.replace(/&/g, '&'). @@ -37,19 +43,22 @@ var htmLawed = module.exports = if (!S) S = {}; if (C.valid_xhtml) { - C.elements = C.elements || '*-center-dir-font-isindex-menu-s-strike-u'; + C.elements = C.elements || '*-acronym-big-center-dir-font-isindex-s-strike-tt'; C.make_tag_strict = C.make_tag_strict !== undefined ? C.make_tag_strict : 2; C['xml:lang'] = C['xml:lang'] !== undefined ? C['xml:lang'] : 2; } // config eles - var e = { 'a': 1, 'abbr': 1, 'acronym': 1, 'address': 1, 'applet': 1, 'area': 1, 'b': 1, 'bdo': 1, 'big': 1, 'blockquote': 1, 'br': 1, 'button': 1, 'caption': 1, 'center': 1, 'cite': 1, 'code': 1, 'col': 1, 'colgroup': 1, 'dd': 1, 'del': 1, 'dfn': 1, 'dir': 1, 'div': 1, 'dl': 1, 'dt': 1, 'em': 1, 'embed': 1, 'fieldset': 1, 'font': 1, 'form': 1, 'h1': 1, 'h2': 1, 'h3': 1, 'h4': 1, 'h5': 1, 'h6': 1, 'hr': 1, 'i': 1, 'iframe': 1, 'img': 1, 'input': 1, 'ins': 1, 'isindex': 1, 'kbd': 1, 'label': 1, 'legend': 1, 'li': 1, 'map': 1, 'menu': 1, 'noscript': 1, 'object': 1, 'ol': 1, 'optgroup': 1, 'option': 1, 'p': 1, 'param': 1, 'pre': 1, 'q': 1, 'rb': 1, 'rbc': 1, 'rp': 1, 'rt': 1, 'rtc': 1, 'ruby': 1, 's': 1, 'samp': 1, 'script': 1, 'select': 1, 'small': 1, 'span': 1, 'strike': 1, 'strong': 1, 'sub': 1, 'sup': 1, 'table': 1, 'tbody': 1, 'td': 1, 'textarea': 1, 'tfoot': 1, 'th': 1, 'thead': 1, 'tr': 1, 'tt': 1, 'u': 1, 'ul': 1, 'var': 1 }; // 86/deprecated+embed+ruby + var e = { 'a': 1, 'abbr': 1, 'acronym': 1, 'address': 1, 'applet': 1, 'area': 1, 'article': 1, 'aside': 1, 'audio': 1, 'b': 1, 'bdi': 1, 'bdo': 1, 'big': 1, 'blockquote': 1, 'br': 1, 'button': 1, 'canvas': 1, 'caption': 1, 'center': 1, 'cite': 1, 'code': 1, 'col': 1, 'colgroup': 1, 'command': 1, 'data': 1, 'datalist': 1, 'dd': 1, 'del': 1, 'details': 1, 'dfn': 1, 'dir': 1, 'div': 1, 'dl': 1, 'dt': 1, 'em': 1, 'embed': 1, 'fieldset': 1, 'figcaption': 1, 'figure': 1, 'font': 1, 'footer': 1, 'form': 1, 'h1': 1, 'h2': 1, 'h3': 1, 'h4': 1, 'h5': 1, 'h6': 1, 'header': 1, 'hgroup': 1, 'hr': 1, 'i': 1, 'iframe': 1, 'img': 1, 'input': 1, 'ins': 1, 'isindex': 1, 'kbd': 1, 'keygen': 1, 'label': 1, 'legend': 1, 'li': 1, 'link': 1, 'main': 1, 'map': 1, 'mark': 1, 'menu': 1, 'meta': 1, 'meter': 1, 'nav': 1, 'noscript': 1, 'object': 1, 'ol': 1, 'optgroup': 1, 'option': 1, 'output': 1, 'p': 1, 'param': 1, 'pre': 1, 'progress': 1, 'q': 1, 'rb': 1, 'rbc': 1, 'rp': 1, 'rt': 1, 'rtc': 1, 'ruby': 1, 's': 1, 'samp': 1, 'script': 1, 'section': 1, 'select': 1, 'small': 1, 'source': 1, 'span': 1, 'strike': 1, 'strong': 1, 'style': 1, 'sub': 1, 'summary': 1, 'sup': 1, 'table': 1, 'tbody': 1, 'td': 1, 'textarea': 1, 'tfoot': 1, 'th': 1, 'thead': 1, 'time': 1, 'tr': 1, 'track': 1, 'tt': 1, 'u': 1, 'ul': 1, 'var': 1, 'video': 1, 'wbr': 1 }; if (C.safe) { delete e.applet; + delete e.audio; + delete e.canvas; delete e.embed; delete e.iframe; delete e.object; delete e.script; + delete e.video; } var x = C.elements ? C.elements.replace(/\s+/g, '') : '*'; var v, m, i; @@ -73,8 +82,12 @@ var htmLawed = module.exports = } C.elements = e; // config attrs - x = C.deny_attribute ? C.deny_attribute.replace(/\s+/g, '') : ''; - x = htmLawed._flip(x[0] == '*' ? x.split(/-/) : (x + (C.safe ? ',on*' : '')).split(',')); + x = C.deny_attribute ? C.deny_attribute.replace(/\s+/g, '').toLowerCase() : ''; + x = htmLawed._flip( + x[0] == '*' ? + x.replace(/data-/g, '/').split('-').map(function (s) {return s.replace('/', 'data-');}) : + (x + (C.safe ? ',on*' : '')).split(',')); + if (x['on*']) { delete x['on*']; @@ -83,8 +96,10 @@ var htmLawed = module.exports = x[i] = true;} } C.deny_attribute = x; - // config URL - x = C.schemes && C.schemes.length > 2 && C.schemes.indexOf(':') > 0 ? C.schemes.toLowerCase() : 'href: aim, feed, file, ftp, gopher, http, https, irc, mailto, news, nntp, sftp, ssh, telnet; *:file, http, https'; + // config URLs + x = C.schemes && C.schemes.length > 2 && C.schemes.indexOf(':') > 0 ? C.schemes.toLowerCase() : + 'href: aim, feed, file, ftp, gopher, http, https, irc, mailto, news, nntp, sftp, ssh, tel, telnet' + ( + !C.safe ? ', app, javascript; *: data, javascript, ' : '; *:') + 'file, http, https'; C.schemes = {}; m = x.replace(/\s+/g, '').split(';'); for (v in m) @@ -94,7 +109,14 @@ var htmLawed = module.exports = C.schemes[x[0]] = htmLawed._flip(x[1].split(',')); } if (!C.schemes['*']) - C.schemes['*'] = { file: 1, http: 1, https: 1 }; + { + C.schemes['*'] = { file: 1, http: 1, https: 1 }; + if (!C.safe) + { + C.schemes['*'].data = 1; + C.schemes['*'].javascript = 1; + } + } if (C.safe && !C.schemes.style) C.schemes.style = { '!': 1 }; C.abs_url = C.abs_url !== undefined ? C.abs_url : 0; @@ -124,7 +146,7 @@ var htmLawed = module.exports = C.show_setting = C.show_setting ? C.show_setting : 0; C.style_pass = !C.style_pass ? 0 : 1; C.tidy = !C.tidy ? 0 : C.tidy; - C.unique_ids = C.unique_ids !== undefined ? C.unique_ids : 1; + C.unique_ids = C.unique_ids !== undefined && !/\W/u.exec(C.unique_ids) ? C.unique_ids : 1; C['xml:lang'] = C['xml:lang'] !== undefined ? C['xml:lang'] : 0; S = typeof S == 'object' ? S : htmLawed.hl_spec(S); @@ -161,14 +183,13 @@ var htmLawed = module.exports = t = htmLawed._strtr(t, { "\x01": '', "\x02": '', "\x03": '&', "\x04": '<', "\x05": '>' }); if (C.tidy) t = htmLawed.hl_tidy(t, C.tidy, C.parent); - // eof return t; }, hl_attrval: function (a, t, p) { // check attr val against S - var ma = { accesskey: 1, class: 1, rel: 1 }; - var s = ma[a] ? ' ' : ''; + var ma = { accesskey: 1, class: 1, itemtype: 1, rel: 1 }; + var s = ma[a] ? ' ' : a == 'srcset' ? ',' : ''; var r = []; var i; t = s ? t.split(s) : [t]; @@ -176,37 +197,41 @@ var htmLawed = module.exports = { var tv = t[tk]; var o = 1; - var l = tv.length; - for (var k in p) + if (tv.trim().length) { - var v = p[k]; - switch (k) { + var l = tv.length; + for (var k in p) + { + var v = p[k]; + switch (k) { - case 'maxlen':if (l > v) {o = 0;}break; - case 'minlen':if (l < v) {o = 0;}break; - case 'maxval':if (parseFloat(tv) > v) {o = 0;}break; - case 'minval':if (parseFloat(tv) < v) {o = 0;}break; - case 'match':if (!v.exec(tv)) {o = 0;}break; - case 'nomatch':if (v.exec(tv)) {o = 0;}break; - case 'oneof': - v = v.split('|'); - for (i = 0; i < v.length && v[i] != tv; i++) {} - o = i < v.length; - break; - case 'noneof': - v = v.split('|'); - for (i = 0; i < v.length && v[i] != tv; i++) {} - o = i >= v.length; - break;} + case 'maxlen':if (l > v) {o = 0;}break; + case 'minlen':if (l < v) {o = 0;}break; + case 'maxval':if (parseFloat(tv) > v) {o = 0;}break; + case 'minval':if (parseFloat(tv) < v) {o = 0;}break; + case 'match':if (!v.exec(tv)) {o = 0;}break; + case 'nomatch':if (v.exec(tv)) {o = 0;}break; + case 'oneof': + v = v.split('|'); + for (i = 0; i < v.length && v[i] != tv; i++) {} + o = i < v.length; + break; + case 'noneof': + v = v.split('|'); + for (i = 0; i < v.length && v[i] != tv; i++) {} + o = i >= v.length; + break;} - if (!o) - break; + if (!o) + break; + } } if (o) r.push(tv); } + if (s == ',') + s = ', '; return r.length > 0 ? r.join(s) : p['default'] || 0; - // eof }, hl_bal: function (t, keep_bad, intag) { @@ -217,23 +242,26 @@ var htmLawed = module.exports = // by content var cont = {}; cont.B = { 'blockquote': 1, 'form': 1, 'map': 1, 'noscript': 1 }; // Block - cont.E = { 'area': 1, 'br': 1, 'col': 1, 'embed': 1, 'hr': 1, 'img': 1, 'input': 1, 'isindex': 1, 'param': 1 }; // Empty - cont.F = { 'button': 1, 'del': 1, 'div': 1, 'dd': 1, 'fieldset': 1, 'iframe': 1, 'ins': 1, 'li': 1, 'noscript': 1, 'object': 1, 'td': 1, 'th': 1 }; // Flow; later context-wise dynamic move of ins & del to cont.I - cont.I = { 'style': 1, 'a': 1, 'abbr': 1, 'acronym': 1, 'address': 1, 'b': 1, 'bdo': 1, 'big': 1, 'caption': 1, 'cite': 1, 'code': 1, 'dfn': 1, 'dt': 1, 'em': 1, 'font': 1, 'h1': 1, 'h2': 1, 'h3': 1, 'h4': 1, 'h5': 1, 'h6': 1, 'i': 1, 'kbd': 1, 'label': 1, 'legend': 1, 'p': 1, 'pre': 1, 'q': 1, 'rb': 1, 'rt': 1, 's': 1, 'samp': 1, 'small': 1, 'span': 1, 'strike': 1, 'strong': 1, 'sub': 1, 'sup': 1, 'tt': 1, 'u': 1, 'var': 1 }; // Inline - cont.N = { 'style': 1, 'a': { 'a': 1 }, 'button': { 'a': 1, 'button': 1, 'fieldset': 1, 'form': 1, 'iframe': 1, 'input': 1, 'label': 1, 'select': 1, 'textarea': 1 }, 'fieldset': { 'fieldset': 1 }, 'form': { 'form': 1 }, 'label': { 'label': 1 }, 'noscript': { 'script': 1 }, 'pre': { 'big': 1, 'font': 1, 'img': 1, 'object': 1, 'script': 1, 'small': 1, 'sub': 1, 'sup': 1 }, 'rb': { 'ruby': 1 }, 'rt': { 'ruby': 1 } }; // Illegal - cont.R = { 'blockquote': 1, 'dir': 1, 'dl': 1, 'form': 1, 'map': 1, 'menu': 1, 'noscript': 1, 'ol': 1, 'optgroup': 1, 'rbc': 1, 'rtc': 1, 'ruby': 1, 'select': 1, 'table': 1, 'tbody': 1, 'tfoot': 1, 'thead': 1, 'tr': 1, 'ul': 1 }; - cont.S = { 'colgroup': { 'col': 1 }, 'dir': { 'li': 1 }, 'dl': { 'dd': 1, 'dt': 1 }, 'menu': { 'li': 1 }, 'ol': { 'li': 1 }, 'optgroup': { 'option': 1 }, 'option': { '#pcdata': 1 }, 'rbc': { 'rb': 1 }, 'rp': { '#pcdata': 1 }, 'rtc': { 'rt': 1 }, 'ruby': { 'rb': 1, 'rbc': 1, 'rp': 1, 'rt': 1, 'rtc': 1 }, 'select': { 'optgroup': 1, 'option': 1 }, 'script': { '#pcdata': 1 }, 'table': { 'caption': 1, 'col': 1, 'colgroup': 1, 'tfoot': 1, 'tbody': 1, 'tr': 1, 'thead': 1 }, 'tbody': { 'tr': 1 }, 'tfoot': { 'tr': 1 }, 'textarea': { '#pcdata': 1 }, 'thead': { 'tr': 1 }, 'tr': { 'td': 1, 'th': 1 }, 'ul': { 'li': 1 } }; // Specific - immediate parent-child + cont.E = { 'area': 1, 'br': 1, 'col': 1, 'command': 1, 'embed': 1, 'hr': 1, 'img': 1, 'input': 1, 'isindex': 1, 'keygen': 1, 'link': 1, 'meta': 1, 'param': 1, 'source': 1, 'track': 1, 'wbr': 1 }; // Empty + cont.F = { 'a': 1, 'article': 1, 'aside': 1, 'audio': 1, 'button': 1, 'canvas': 1, 'del': 1, 'details': 1, 'div': 1, 'dd': 1, 'fieldset': 1, 'figure': 1, 'footer': 1, 'header': 1, 'iframe': 1, 'ins': 1, 'li': 1, 'main': 1, 'menu': 1, 'nav': 1, 'noscript': 1, 'object': 1, 'section': 1, 'style': 1, 'td': 1, 'th': 1, 'video': 1 }; // Flow; later context-wise dynamic move of ins & del to cont.I + cont.I = { 'abbr': 1, 'acronym': 1, 'address': 1, 'b': 1, 'bdi': 1, 'bdo': 1, 'big': 1, 'caption': 1, 'cite': 1, 'code': 1, 'data': 1, 'datalist': 1, 'dfn': 1, 'dt': 1, 'em': 1, 'figcaption': 1, 'font': 1, 'h1': 1, 'h2': 1, 'h3': 1, 'h4': 1, 'h5': 1, 'h6': 1, 'hgroup': 1, 'i': 1, 'kbd': 1, 'label': 1, 'legend': 1, 'mark': 1, 'meter': 1, 'output': 1, 'p': 1, 'pre': 1, 'progress': 1, 'q': 1, 'rb': 1, 'rt': 1, 's': 1, 'samp': 1, 'small': 1, 'span': 1, 'strike': 1, 'strong': 1, 'sub': 1, 'summary': 1, 'sup': 1, 'time': 1, 'tt': 1, 'u': 1, 'var': 1 }; // Inline + cont.N = { 'a': { 'a': 1, 'address': 1, 'button': 1, 'details': 1, 'embed': 1, 'keygen': 1, 'label': 1, 'select': 1, 'textarea': 1 }, 'address': { 'address': 1, 'article': 1, 'aside': 1, 'header': 1, 'keygen': 1, 'footer': 1, 'nav': 1, 'section': 1 }, 'button': { 'a': 1, 'address': 1, 'button': 1, 'details': 1, 'embed': 1, 'fieldset': 1, 'form': 1, 'iframe': 1, 'input': 1, 'keygen': 1, 'label': 1, 'select': 1, 'textarea': 1 }, 'fieldset': { 'fieldset': 1 }, 'footer': { 'header': 1, 'footer': 1 }, 'form': { 'form': 1 }, 'header': { 'header': 1, 'footer': 1 }, 'label': { 'label': 1 }, 'main': { 'main': 1 }, 'meter': { 'meter': 1 }, 'noscript': { 'script': 1 }, 'pre': { 'big': 1, 'font': 1, 'img': 1, 'object': 1, 'script': 1, 'small': 1, 'sub': 1, 'sup': 1 }, 'progress': { 'progress': 1 }, 'rb': { 'ruby': 1 }, 'rt': { 'ruby': 1 }, 'time': { 'time': 1 } }; // Illegal + cont.S = { "colgroup": { "col": 1 }, "datalist": { "option": 1 }, "dir": { "li": 1 }, "dl": { "dd": 1, "dt": 1 }, "hgroup": { "h1": 1, "h2": 1, "h3": 1, "h4": 1, "h5": 1, "h6": 1 }, "menu": { "li": 1 }, "ol": { "li": 1 }, "optgroup": { "option": 1 }, "option": { "#pcdata": 1 }, "rbc": { "rb": 1 }, "rp": { "#pcdata": 1 }, "rtc": { "rt": 1 }, "ruby": { "rb": 1, "rbc": 1, "rp": 1, "rt": 1, "rtc": 1 }, "select": { "optgroup": 1, "option": 1 }, "script": { "#pcdata": 1 }, "table": { "caption": 1, "col": 1, "colgroup": 1, "tfoot": 1, "tbody": 1, "tr": 1, "thead": 1 }, "tbody": { "tr": 1 }, "tfoot": { "tr": 1 }, "textarea": { "#pcdata": 1 }, "thead": { "tr": 1 }, "tr": { "td": 1, "th": 1 }, "ul": { "li": 1 } }; // Specific - immediate parent-child if (htmLawed.C.direct_list_nest) - cont.S['ol']['ol'] = cont.S['ul']['ol'] = cont.S['ol']['ul'] = cont.S['ul']['ul'] = 1; - cont.O = { 'address': { 'p': 1 }, 'applet': { 'param': 1 }, 'blockquote': { 'script': 1 }, 'fieldset': { 'legend': 1, '#pcdata': 1 }, 'form': { 'script': 1 }, 'map': { 'area': 1 }, 'object': { 'param': 1, 'embed': 1 } }; // Other + { + cont.S['ol']['ol'] = cont.S['ol']['ul'] = cont.S['ol']['menu'] = 1; + cont.S['ul']['ol'] = cont.S['ul']['ul'] = cont.S['ul']['menu'] = 1; + cont.S['menu']['ol'] = cont.S['menu']['ul'] = cont.S['menu']['menu'] = 1; + } + cont.O = { "address": { "p": 1 }, "applet": { "param": 1 }, "audio": { "source": 1, "track": 1 }, "blockquote": { "script": 1 }, "details": { "summary": 1 }, "fieldset": { "legend": 1, "#pcdata": 1 }, "figure": { "figcaption": 1 }, "form": { "script": 1 }, "map": { "area": 1 }, "object": { "param": 1, "embed": 1 }, "video": { "source": 1, "track": 1 } }; // Other cont.T = { 'colgroup': 1, 'dd': 1, 'dt': 1, 'li': 1, 'option': 1, 'p': 1, 'td': 1, 'tfoot': 1, 'th': 1, 'thead': 1, 'tr': 1 }; // Omitable closing - // block/inline type; ins & del both type; #pcdata: text + // block/inline type; a/ins/del both type; #pcdata: text var el = {}; - el.B = { 'address': 1, 'blockquote': 1, 'center': 1, 'del': 1, 'dir': 1, 'dl': 1, 'div': 1, 'fieldset': 1, 'form': 1, 'ins': 1, 'h1': 1, 'h2': 1, 'h3': 1, 'h4': 1, 'h5': 1, 'h6': 1, 'hr': 1, 'isindex': 1, 'menu': 1, 'noscript': 1, 'ol': 1, 'p': 1, 'pre': 1, 'table': 1, 'ul': 1 }; - el.I = { 'style': 1, '#pcdata': 1, 'a': 1, 'abbr': 1, 'acronym': 1, 'applet': 1, 'b': 1, 'bdo': 1, 'big': 1, 'br': 1, 'button': 1, 'cite': 1, 'code': 1, 'del': 1, 'dfn': 1, 'em': 1, 'embed': 1, 'font': 1, 'i': 1, 'iframe': 1, 'img': 1, 'input': 1, 'ins': 1, 'kbd': 1, 'label': 1, 'map': 1, 'object': 1, 'q': 1, 'ruby': 1, 's': 1, 'samp': 1, 'select': 1, 'script': 1, 'small': 1, 'span': 1, 'strike': 1, 'strong': 1, 'sub': 1, 'sup': 1, 'textarea': 1, 'tt': 1, 'u': 1, 'var': 1 }; - el.N = { 'a': 1, 'big': 1, 'button': 1, 'fieldset': 1, 'font': 1, 'form': 1, 'iframe': 1, 'img': 1, 'input': 1, 'label': 1, 'object': 1, 'ruby': 1, 'script': 1, 'select': 1, 'small': 1, 'sub': 1, 'sup': 1, 'textarea': 1 }; // Exclude from specific ele; cont.N values - el.O = { 'area': 1, 'caption': 1, 'col': 1, 'colgroup': 1, 'dd': 1, 'dt': 1, 'legend': 1, 'li': 1, 'optgroup': 1, 'option': 1, 'param': 1, 'rb': 1, 'rbc': 1, 'rp': 1, 'rt': 1, 'rtc': 1, 'script': 1, 'tbody': 1, 'td': 1, 'tfoot': 1, 'thead': 1, 'th': 1, 'tr': 1 }; // Missing in el.B & el.I - el.F = _extends({}, el.B, el.I); // FIXME <=> Object.assign({}, el.B, el.I) + el.B = { "a": 1, "address": 1, "article": 1, "aside": 1, "blockquote": 1, "center": 1, "del": 1, "details": 1, "dir": 1, "dl": 1, "div": 1, "fieldset": 1, "figure": 1, "footer": 1, "form": 1, "ins": 1, "h1": 1, "h2": 1, "h3": 1, "h4": 1, "h5": 1, "h6": 1, "header": 1, "hr": 1, "isindex": 1, "main": 1, "menu": 1, "nav": 1, "noscript": 1, "ol": 1, "p": 1, "pre": 1, "section": 1, "style": 1, "table": 1, "ul": 1 }; + el.I = { "#pcdata": 1, "a": 1, "abbr": 1, "acronym": 1, "applet": 1, "audio": 1, "b": 1, "bdi": 1, "bdo": 1, "big": 1, "br": 1, "button": 1, "canvas": 1, "cite": 1, "code": 1, "command": 1, "data": 1, "datalist": 1, "del": 1, "dfn": 1, "em": 1, "embed": 1, "figcaption": 1, "font": 1, "i": 1, "iframe": 1, "img": 1, "input": 1, "ins": 1, "kbd": 1, "label": 1, "link": 1, "map": 1, "mark": 1, "meta": 1, "meter": 1, "object": 1, "output": 1, "progress": 1, "q": 1, "ruby": 1, "s": 1, "samp": 1, "select": 1, "script": 1, "small": 1, "span": 1, "strike": 1, "strong": 1, "sub": 1, "summary": 1, "sup": 1, "textarea": 1, "time": 1, "tt": 1, "u": 1, "var": 1, "video": 1, "wbr": 1 }; + el.N = { "a": 1, "address": 1, "article": 1, "aside": 1, "big": 1, "button": 1, "details": 1, "embed": 1, "fieldset": 1, "font": 1, "footer": 1, "form": 1, "header": 1, "iframe": 1, "img": 1, "input": 1, "keygen": 1, "label": 1, "meter": 1, "nav": 1, "object": 1, "progress": 1, "ruby": 1, "script": 1, "select": 1, "small": 1, "sub": 1, "sup": 1, "textarea": 1, "time": 1 }; + el.O = { "area": 1, "caption": 1, "col": 1, "colgroup": 1, "command": 1, "dd": 1, "dt": 1, "hgroup": 1, "keygen": 1, "legend": 1, "li": 1, "optgroup": 1, "option": 1, "param": 1, "rb": 1, "rbc": 1, "rp": 1, "rt": 1, "rtc": 1, "script": 1, "source": 1, "tbody": 1, "td": 1, "tfoot": 1, "thead": 1, "th": 1, "tr": 1, "track": 1 }; + el.F = _extends({}, el.B, el.I); function getCont(intag) { @@ -474,7 +502,6 @@ var htmLawed = module.exports = while (e = q.pop()) { _ob += '';} return _ob; - // eof }, hl_cmtcd: function (t) { @@ -483,7 +510,7 @@ var htmLawed = module.exports = var v = htmLawed.C[n]; if (!v) return t; if (v == 1) return ''; - if (n == 'comment') + if (n == 'comment' && v < 4) { t = t.substr(4, t.length - 3 - 4).replace(/--+/g, '-'); if (t.substr(t.length - 1) != ' ') @@ -494,7 +521,6 @@ var htmLawed = module.exports = t = v == 2 ? htmLawed._strtr(t, { '&': '&', '<': '<', '>': '>' }) : t; t = n == 'comment' ? "\x01\x02\x04!--" + t + "--\x05\x02\x01" : "\x01\x01\x04" + t + "\x05\x01\x01"; return htmLawed._strtr(t, { '&': "\x03", '<': "\x04", '>': "\x05" }); - // eof }, ENT: { 'fnof': '402', 'Alpha': '913', 'Beta': '914', 'Gamma': '915', 'Delta': '916', 'Epsilon': '917', 'Zeta': '918', 'Eta': '919', 'Theta': '920', 'Iota': '921', 'Kappa': '922', 'Lambda': '923', 'Mu': '924', 'Nu': '925', 'Xi': '926', 'Omicron': '927', 'Pi': '928', 'Rho': '929', 'Sigma': '931', 'Tau': '932', 'Upsilon': '933', 'Phi': '934', 'Chi': '935', 'Psi': '936', 'Omega': '937', 'alpha': '945', 'beta': '946', 'gamma': '947', 'delta': '948', 'epsilon': '949', 'zeta': '950', 'eta': '951', 'theta': '952', 'iota': '953', 'kappa': '954', 'lambda': '955', 'mu': '956', 'nu': '957', 'xi': '958', 'omicron': '959', 'pi': '960', 'rho': '961', 'sigmaf': '962', 'sigma': '963', 'tau': '964', 'upsilon': '965', 'phi': '966', 'chi': '967', 'psi': '968', 'omega': '969', 'thetasym': '977', 'upsih': '978', 'piv': '982', 'bull': '8226', 'hellip': '8230', 'prime': '8242', 'Prime': '8243', 'oline': '8254', 'frasl': '8260', 'weierp': '8472', 'image': '8465', 'real': '8476', 'trade': '8482', 'alefsym': '8501', 'larr': '8592', 'uarr': '8593', 'rarr': '8594', 'darr': '8595', 'harr': '8596', 'crarr': '8629', 'lArr': '8656', 'uArr': '8657', 'rArr': '8658', 'dArr': '8659', 'hArr': '8660', 'forall': '8704', 'part': '8706', 'exist': '8707', 'empty': '8709', 'nabla': '8711', 'isin': '8712', 'notin': '8713', 'ni': '8715', 'prod': '8719', 'sum': '8721', 'minus': '8722', 'lowast': '8727', 'radic': '8730', 'prop': '8733', 'infin': '8734', 'ang': '8736', 'and': '8743', 'or': '8744', 'cap': '8745', 'cup': '8746', 'int': '8747', 'there4': '8756', 'sim': '8764', 'cong': '8773', 'asymp': '8776', 'ne': '8800', 'equiv': '8801', 'le': '8804', 'ge': '8805', 'sub': '8834', 'sup': '8835', 'nsub': '8836', 'sube': '8838', 'supe': '8839', 'oplus': '8853', 'otimes': '8855', 'perp': '8869', 'sdot': '8901', 'lceil': '8968', 'rceil': '8969', 'lfloor': '8970', 'rfloor': '8971', 'lang': '9001', 'rang': '9002', 'loz': '9674', 'spades': '9824', 'clubs': '9827', 'hearts': '9829', 'diams': '9830', 'apos': '39', 'OElig': '338', 'oelig': '339', 'Scaron': '352', 'scaron': '353', 'Yuml': '376', 'circ': '710', 'tilde': '732', 'ensp': '8194', 'emsp': '8195', 'thinsp': '8201', 'zwnj': '8204', 'zwj': '8205', 'lrm': '8206', 'rlm': '8207', 'ndash': '8211', 'mdash': '8212', 'lsquo': '8216', 'rsquo': '8217', 'sbquo': '8218', 'ldquo': '8220', 'rdquo': '8221', 'bdquo': '8222', 'dagger': '8224', 'Dagger': '8225', 'permil': '8240', 'lsaquo': '8249', 'rsaquo': '8250', 'euro': '8364', 'nbsp': '160', 'iexcl': '161', 'cent': '162', 'pound': '163', 'curren': '164', 'yen': '165', 'brvbar': '166', 'sect': '167', 'uml': '168', 'copy': '169', 'ordf': '170', 'laquo': '171', 'not': '172', 'shy': '173', 'reg': '174', 'macr': '175', 'deg': '176', 'plusmn': '177', 'sup2': '178', 'sup3': '179', 'acute': '180', 'micro': '181', 'para': '182', 'middot': '183', 'cedil': '184', 'sup1': '185', 'ordm': '186', 'raquo': '187', 'frac14': '188', 'frac12': '189', 'frac34': '190', 'iquest': '191', 'Agrave': '192', 'Aacute': '193', 'Acirc': '194', 'Atilde': '195', 'Auml': '196', 'Aring': '197', 'AElig': '198', 'Ccedil': '199', 'Egrave': '200', 'Eacute': '201', 'Ecirc': '202', 'Euml': '203', 'Igrave': '204', 'Iacute': '205', 'Icirc': '206', 'Iuml': '207', 'ETH': '208', 'Ntilde': '209', 'Ograve': '210', 'Oacute': '211', 'Ocirc': '212', 'Otilde': '213', 'Ouml': '214', 'times': '215', 'Oslash': '216', 'Ugrave': '217', 'Uacute': '218', 'Ucirc': '219', 'Uuml': '220', 'Yacute': '221', 'THORN': '222', 'szlig': '223', 'agrave': '224', 'aacute': '225', 'acirc': '226', 'atilde': '227', 'auml': '228', 'aring': '229', 'aelig': '230', 'ccedil': '231', 'egrave': '232', 'eacute': '233', 'ecirc': '234', 'euml': '235', 'igrave': '236', 'iacute': '237', 'icirc': '238', 'iuml': '239', 'eth': '240', 'ntilde': '241', 'ograve': '242', 'oacute': '243', 'ocirc': '244', 'otilde': '245', 'ouml': '246', 'divide': '247', 'oslash': '248', 'ugrave': '249', 'uacute': '250', 'ucirc': '251', 'uuml': '252', 'yacute': '253', 'thorn': '254', 'yuml': '255' }, ENT_U: { 'quot': 1, 'amp': 1, 'lt': 1, 'gt': 1 }, @@ -516,7 +542,6 @@ var htmLawed = module.exports = return (C.and_mark ? "\x06" : '&') + "amp;#" + t + ";"; } return (C.and_mark ? "\x06" : '&') + '#' + (/^\d+$/.exec(t) && C.hexdec_entity < 2 || !C.hexdec_entity ? n : 'x' + n.toString(16)) + ';'; - // eof }, hl_prot: function (p, c) { @@ -566,7 +591,6 @@ var htmLawed = module.exports = } } return b + p + a; - // eof }, hl_regex: function (p) { @@ -635,18 +659,7 @@ var htmLawed = module.exports = if (y[x].nomatch && !htmLawed.hl_regex(y[x].nomatch)) delete y[x].nomatch; } - var _y = 0; - for (_i in y) - { - _y = 1; - break; - } - var _n = 0; - for (_i in n) - { - _n = 1; - break; - } + var _y = this._nonempty(y),_n = this._nonempty(n); if (!_y && !_n) continue; w = w.substr(0, e); @@ -656,202 +669,1091 @@ var htmLawed = module.exports = if (v === '') continue; if (_y) - s[v] = y; + s[v] = s[v] ? _extends({}, s[v], y) : y; if (_n) - s[v].n = n; + s[v].n = s[v].n ? _extends({}, s[v].n, n) : n; } } return s; - // eof }, TAG: { - D: { 'applet': 1, 'center': 1, 'dir': 1, 'embed': 1, 'font': 1, 'isindex': 1, 'menu': 1, 's': 1, 'strike': 1, 'u': 1 }, // Deprecated - E: { 'area': 1, 'br': 1, 'col': 1, 'embed': 1, 'hr': 1, 'img': 1, 'input': 1, 'isindex': 1, 'param': 1 }, // Empty ele - N: { // Ele-specific - 'abbr': { 'td': 1, 'th': 1 }, - 'accept-charset': { 'form': 1 }, - 'accept': { 'form': 1, 'input': 1 }, - 'accesskey': { 'a': 1, 'area': 1, 'button': 1, 'input': 1, 'label': 1, 'legend': 1, 'textarea': 1 }, - 'action': { 'form': 1 }, - 'align': { - 'caption': 1, 'embed': 1, 'applet': 1, 'iframe': 1, 'img': 1, 'input': 1, 'object': 1, 'legend': 1, 'table': 1, - 'hr': 1, 'div': 1, 'h1': 1, 'h2': 1, 'h3': 1, 'h4': 1, 'h5': 1, 'h6': 1, 'p': 1, 'col': 1, 'colgroup': 1, 'tbody': 1, - 'td': 1, 'tfoot': 1, 'th': 1, 'thead': 1, 'tr': 1 }, + D: { 'acronym': 1, 'applet': 1, 'big': 1, 'center': 1, 'dir': 1, 'font': 1, 'isindex': 1, 's': 1, 'strike': 1, 'tt': 1 }, // Deprecated + E: { 'area': 1, 'br': 1, 'col': 1, 'command': 1, 'embed': 1, 'hr': 1, 'img': 1, 'input': 1, 'isindex': 1, 'keygen': 1, 'link': 1, 'meta': 1, 'param': 1, 'source': 1, 'track': 1, 'wbr': 1 }, // Empty ele + // Ele-specific + N: { + "abbr": { + "td": 1, + "th": 1 }, - 'allowfullscreen': { 'iframe': 1 }, - 'alt': { 'applet': 1, 'area': 1, 'img': 1, 'input': 1 }, - 'archive': { 'applet': 1, 'object': 1 }, - 'axis': { 'td': 1, 'th': 1 }, - 'bgcolor': { 'embed': 1, 'table': 1, 'tr': 1, 'td': 1, 'th': 1 }, - 'border': { 'table': 1, 'img': 1, 'object': 1 }, - 'bordercolor': { 'table': 1, 'td': 1, 'tr': 1 }, - 'cellpadding': { 'table': 1 }, - 'cellspacing': { 'table': 1 }, - 'char': { 'col': 1, 'colgroup': 1, 'tbody': 1, 'td': 1, 'tfoot': 1, 'th': 1, 'thead': 1, 'tr': 1 }, - 'charoff': { 'col': 1, 'colgroup': 1, 'tbody': 1, 'td': 1, 'tfoot': 1, 'th': 1, 'thead': 1, 'tr': 1 }, - 'charset': { 'a': 1, 'script': 1 }, - 'checked': { 'input': 1 }, - 'cite': { 'blockquote': 1, 'q': 1, 'del': 1, 'ins': 1 }, - 'classid': { 'object': 1 }, - 'clear': { 'br': 1 }, - 'code': { 'applet': 1 }, - 'codebase': { 'object': 1, 'applet': 1 }, - 'codetype': { 'object': 1 }, - 'color': { 'font': 1 }, - 'cols': { 'textarea': 1 }, - 'colspan': { 'td': 1, 'th': 1 }, - 'compact': { 'dir': 1, 'dl': 1, 'menu': 1, 'ol': 1, 'ul': 1 }, - 'coords': { 'area': 1, 'a': 1 }, - 'data': { 'object': 1 }, - 'datetime': { 'del': 1, 'ins': 1 }, - 'declare': { 'object': 1 }, - 'defer': { 'script': 1 }, - 'dir': { 'bdo': 1 }, - 'disabled': { 'button': 1, 'input': 1, 'optgroup': 1, 'option': 1, 'select': 1, 'textarea': 1 }, - 'enctype': { 'form': 1 }, - 'face': { 'font': 1 }, - 'flashvars': { 'embed': 1 }, - 'for': { 'label': 1 }, - 'frame': { 'table': 1 }, - 'frameborder': { 'iframe': 1 }, - 'headers': { 'td': 1, 'th': 1 }, - 'height': { 'embed': 1, 'iframe': 1, 'td': 1, 'th': 1, 'img': 1, 'object': 1, 'applet': 1 }, - 'href': { 'a': 1, 'area': 1 }, - 'hreflang': { 'a': 1 }, - 'hspace': { 'applet': 1, 'img': 1, 'object': 1 }, - 'ismap': { 'img': 1, 'input': 1 }, - 'label': { 'option': 1, 'optgroup': 1 }, - 'language': { 'script': 1 }, - 'longdesc': { 'img': 1, 'iframe': 1 }, - 'marginheight': { 'iframe': 1 }, - 'marginwidth': { 'iframe': 1 }, - 'maxlength': { 'input': 1 }, - 'method': { 'form': 1 }, - 'model': { 'embed': 1 }, - 'multiple': { 'select': 1 }, - 'name': { - 'button': 1, 'embed': 1, 'textarea': 1, 'applet': 1, 'select': 1, 'form': 1, 'iframe': 1, 'img': 1, - 'a': 1, 'input': 1, 'object': 1, 'map': 1, 'param': 1 }, + "accept": { + "form": 1, + "input": 1 }, - 'nohref': { 'area': 1 }, - 'noshade': { 'hr': 1 }, - 'nowrap': { 'td': 1, 'th': 1 }, - 'object': { 'applet': 1 }, - 'onblur': { 'a': 1, 'area': 1, 'button': 1, 'input': 1, 'label': 1, 'select': 1, 'textarea': 1 }, - 'onchange': { 'input': 1, 'select': 1, 'textarea': 1 }, - 'onfocus': { 'a': 1, 'area': 1, 'button': 1, 'input': 1, 'label': 1, 'select': 1, 'textarea': 1 }, - 'onreset': { 'form': 1 }, - 'onselect': { 'input': 1, 'textarea': 1 }, - 'onsubmit': { 'form': 1 }, - 'pluginspage': { 'embed': 1 }, - 'pluginurl': { 'embed': 1 }, - 'prompt': { 'isindex': 1 }, - 'readonly': { 'textarea': 1, 'input': 1 }, - 'rel': { 'a': 1 }, - 'rev': { 'a': 1 }, - 'rows': { 'textarea': 1 }, - 'rowspan': { 'td': 1, 'th': 1 }, - 'rules': { 'table': 1 }, - 'scope': { 'td': 1, 'th': 1 }, - 'scrolling': { 'iframe': 1 }, - 'selected': { 'option': 1 }, - 'shape': { 'area': 1, 'a': 1 }, - 'size': { 'hr': 1, 'font': 1, 'input': 1, 'select': 1 }, - 'span': { 'col': 1, 'colgroup': 1 }, - 'src': { 'embed': 1, 'script': 1, 'input': 1, 'iframe': 1, 'img': 1 }, - 'standby': { 'object': 1 }, - 'start': { 'ol': 1 }, - 'summary': { 'table': 1 }, - 'tabindex': { 'a': 1, 'area': 1, 'button': 1, 'input': 1, 'object': 1, 'select': 1, 'textarea': 1 }, // FIXME not specific! allowed everywhere - 'target': { 'a': 1, 'area': 1, 'form': 1 }, - 'type': { 'a': 1, 'embed': 1, 'object': 1, 'param': 1, 'script': 1, 'input': 1, 'li': 1, 'ol': 1, 'ul': 1, 'button': 1 }, - 'usemap': { 'img': 1, 'input': 1, 'object': 1 }, - 'valign': { 'col': 1, 'colgroup': 1, 'tbody': 1, 'td': 1, 'tfoot': 1, 'th': 1, 'thead': 1, 'tr': 1 }, - 'value': { 'input': 1, 'option': 1, 'param': 1, 'button': 1, 'li': 1 }, - 'valuetype': { 'param': 1 }, - 'vspace': { 'applet': 1, 'img': 1, 'object': 1 }, - 'width': { 'embed': 1, 'hr': 1, 'iframe': 1, 'img': 1, 'object': 1, 'table': 1, 'td': 1, 'th': 1, 'applet': 1, 'col': 1, 'colgroup': 1, 'pre': 1 }, - 'wmode': { 'embed': 1 }, - 'xml:space': { 'pre': 1, 'script': 1, 'style': 1 } }, + "accept-charset": { + "form": 1 }, - NE: { // Empty - 'allowfullscreen': 1, 'checked': 1, 'compact': 1, 'declare': 1, 'defer': 1, 'disabled': 1, - 'ismap': 1, 'multiple': 1, 'nohref': 1, 'noresize': 1, 'noshade': 1, 'nowrap': 1, 'readonly': 1, 'selected': 1 }, + "action": { + "form": 1 }, - NP: { // Need scheme check; excludes style, on* & src - 'action': 1, 'cite': 1, 'classid': 1, 'codebase': 1, 'data': 1, 'href': 1, - 'longdesc': 1, 'model': 1, 'pluginspage': 1, 'pluginurl': 1, 'usemap': 1 }, + "align": { + "applet": 1, + "caption": 1, + "col": 1, + "colgroup": 1, + "div": 1, + "embed": 1, + "h1": 1, + "h2": 1, + "h3": 1, + "h4": 1, + "h5": 1, + "h6": 1, + "hr": 1, + "iframe": 1, + "img": 1, + "input": 1, + "legend": 1, + "object": 1, + "p": 1, + "table": 1, + "tbody": 1, + "td": 1, + "tfoot": 1, + "th": 1, + "thead": 1, + "tr": 1 }, - NU: { // Univ & exceptions - 'class': { 'param': 1, 'script': 1 }, - 'dir': { 'applet': 1, 'bdo': 1, 'br': 1, 'iframe': 1, 'param': 1, 'script': 1 }, - 'id': { 'script': 1 }, - 'lang': { 'applet': 1, 'br': 1, 'iframe': 1, 'param': 1, 'script': 1 }, - 'xml:lang': { 'applet': 1, 'br': 1, 'iframe': 1, 'param': 1, 'script': 1 }, - 'onclick': { 'applet': 1, 'bdo': 1, 'br': 1, 'font': 1, 'iframe': 1, 'isindex': 1, 'param': 1, 'script': 1 }, - 'ondblclick': { 'applet': 1, 'bdo': 1, 'br': 1, 'font': 1, 'iframe': 1, 'isindex': 1, 'param': 1, 'script': 1 }, - 'onkeydown': { 'applet': 1, 'bdo': 1, 'br': 1, 'font': 1, 'iframe': 1, 'isindex': 1, 'param': 1, 'script': 1 }, - 'onkeypress': { 'applet': 1, 'bdo': 1, 'br': 1, 'font': 1, 'iframe': 1, 'isindex': 1, 'param': 1, 'script': 1 }, - 'onkeyup': { 'applet': 1, 'bdo': 1, 'br': 1, 'font': 1, 'iframe': 1, 'isindex': 1, 'param': 1, 'script': 1 }, - 'onmousedown': { 'applet': 1, 'bdo': 1, 'br': 1, 'font': 1, 'iframe': 1, 'isindex': 1, 'param': 1, 'script': 1 }, - 'onmousemove': { 'applet': 1, 'bdo': 1, 'br': 1, 'font': 1, 'iframe': 1, 'isindex': 1, 'param': 1, 'script': 1 }, - 'onmouseout': { 'applet': 1, 'bdo': 1, 'br': 1, 'font': 1, 'iframe': 1, 'isindex': 1, 'param': 1, 'script': 1 }, - 'onmouseover': { 'applet': 1, 'bdo': 1, 'br': 1, 'font': 1, 'iframe': 1, 'isindex': 1, 'param': 1, 'script': 1 }, - 'onmouseup': { 'applet': 1, 'bdo': 1, 'br': 1, 'font': 1, 'iframe': 1, 'isindex': 1, 'param': 1, 'script': 1 }, - 'style': { 'param': 1, 'script': 1 }, - 'title': { 'param': 1, 'script': 1 } }, + "allowfullscreen": { + "iframe": 1 }, + + "alt": { + "applet": 1, + "area": 1, + "img": 1, + "input": 1 }, + + "archive": { + "applet": 1, + "object": 1 }, + + "async": { + "script": 1 }, + + "autocomplete": { + "form": 1, + "input": 1 }, + + "autofocus": { + "button": 1, + "input": 1, + "keygen": 1, + "select": 1, + "textarea": 1 }, + + "autoplay": { + "audio": 1, + "video": 1 }, + + "axis": { + "td": 1, + "th": 1 }, + + "bgcolor": { + "embed": 1, + "table": 1, + "td": 1, + "th": 1, + "tr": 1 }, + + "border": { + "img": 1, + "object": 1, + "table": 1 }, + + "bordercolor": { + "table": 1, + "td": 1, + "tr": 1 }, + + "cellpadding": { + "table": 1 }, + + "cellspacing": { + "table": 1 }, + + "challenge": { + "keygen": 1 }, + + "char": { + "col": 1, + "colgroup": 1, + "tbody": 1, + "td": 1, + "tfoot": 1, + "th": 1, + "thead": 1, + "tr": 1 }, + + "charoff": { + "col": 1, + "colgroup": 1, + "tbody": 1, + "td": 1, + "tfoot": 1, + "th": 1, + "thead": 1, + "tr": 1 }, + + "charset": { + "a": 1, + "script": 1 }, + + "checked": { + "command": 1, + "input": 1 }, + + "cite": { + "blockquote": 1, + "del": 1, + "ins": 1, + "q": 1 }, + + "classid": { + "object": 1 }, + + "clear": { + "br": 1 }, + + "code": { + "applet": 1 }, + + "codebase": { + "applet": 1, + "object": 1 }, + + "codetype": { + "object": 1 }, + + "color": { + "font": 1 }, + + "cols": { + "textarea": 1 }, + + "colspan": { + "td": 1, + "th": 1 }, + + "compact": { + "dir": 1, + "dl": 1, + "menu": 1, + "ol": 1, + "ul": 1 }, + + "content": { + "meta": 1 }, + + "controls": { + "audio": 1, + "video": 1 }, + + "coords": { + "a": 1, + "area": 1 }, + + "crossorigin": { + "img": 1 }, + + "data": { + "object": 1 }, + + "datetime": { + "del": 1, + "ins": 1, + "time": 1 }, + + "declare": { + "object": 1 }, + + "default": { + "track": 1 }, + + "defer": { + "script": 1 }, + + "dirname": { + "input": 1, + "textarea": 1 }, + + "disabled": { + "button": 1, + "command": 1, + "fieldset": 1, + "input": 1, + "keygen": 1, + "optgroup": 1, + "option": 1, + "select": 1, + "textarea": 1 }, + + "download": { + "a": 1 }, + + "enctype": { + "form": 1 }, + + "face": { + "font": 1 }, + + "flashvars": { + "embed": 1 }, + + "for": { + "label": 1, + "output": 1 }, + + "form": { + "button": 1, + "fieldset": 1, + "input": 1, + "keygen": 1, + "label": 1, + "object": 1, + "output": 1, + "select": 1, + "textarea": 1 }, + + "formaction": { + "button": 1, + "input": 1 }, + + "formenctype": { + "button": 1, + "input": 1 }, + + "formmethod": { + "button": 1, + "input": 1 }, + + "formnovalidate": { + "button": 1, + "input": 1 }, + + "formtarget": { + "button": 1, + "input": 1 }, + + "frame": { + "table": 1 }, + + "frameborder": { + "iframe": 1 }, + + "headers": { + "td": 1, + "th": 1 }, + + "height": { + "applet": 1, + "canvas": 1, + "embed": 1, + "iframe": 1, + "img": 1, + "input": 1, + "object": 1, + "td": 1, + "th": 1, + "video": 1 }, + + "high": { + "meter": 1 }, + + "href": { + "a": 1, + "area": 1, + "link": 1 }, + + "hreflang": { + "a": 1, + "area": 1, + "link": 1 }, + + "hspace": { + "applet": 1, + "embed": 1, + "img": 1, + "object": 1 }, + + "icon": { + "command": 1 }, + + "ismap": { + "img": 1, + "input": 1 }, + + "keyparams": { + "keygen": 1 }, + + "keytype": { + "keygen": 1 }, + + "kind": { + "track": 1 }, + + "label": { + "command": 1, + "menu": 1, + "option": 1, + "optgroup": 1, + "track": 1 }, + + "language": { + "script": 1 }, + + "list": { + "input": 1 }, + + "longdesc": { + "img": 1, + "iframe": 1 }, + + "loop": { + "audio": 1, + "video": 1 }, + + "low": { + "meter": 1 }, + + "marginheight": { + "iframe": 1 }, + + "marginwidth": { + "iframe": 1 }, + + "max": { + "input": 1, + "meter": 1, + "progress": 1 }, + + "maxlength": { + "input": 1, + "textarea": 1 }, + + "media": { + "a": 1, + "area": 1, + "link": 1, + "source": 1, + "style": 1 }, + + "mediagroup": { + "audio": 1, + "video": 1 }, + + "method": { + "form": 1 }, + + "min": { + "input": 1, + "meter": 1 }, + + "model": { + "embed": 1 }, + + "multiple": { + "input": 1, + "select": 1 }, + + "muted": { + "audio": 1, + "video": 1 }, + + "name": { + "a": 1, + "applet": 1, + "button": 1, + "embed": 1, + "fieldset": 1, + "form": 1, + "iframe": 1, + "img": 1, + "input": 1, + "keygen": 1, + "map": 1, + "object": 1, + "output": 1, + "param": 1, + "select": 1, + "textarea": 1 }, + + "nohref": { + "area": 1 }, + + "noshade": { + "hr": 1 }, + + "novalidate": { + "form": 1 }, + + "nowrap": { + "td": 1, + "th": 1 }, + + "object": { + "applet": 1 }, + + "open": { + "details": 1 }, + + "optimum": { + "meter": 1 }, + + "pattern": { + "input": 1 }, + + "ping": { + "a": 1, + "area": 1 }, + + "placeholder": { + "input": 1, + "textarea": 1 }, + + "pluginspage": { + "embed": 1 }, + + "pluginurl": { + "embed": 1 }, + + "poster": { + "video": 1 }, + + "pqg": { + "keygen": 1 }, + + "preload": { + "audio": 1, + "video": 1 }, + + "prompt": { + "isindex": 1 }, + + "pubdate": { + "time": 1 }, + + "radiogroup": { + "command": 1 }, + + "readonly": { + "input": 1, + "textarea": 1 }, + + "rel": { + "a": 1, + "area": 1, + "link": 1 }, + + "required": { + "input": 1, + "select": 1, + "textarea": 1 }, + + "rev": { + "a": 1 }, + + "reversed": { + "ol": 1 }, + + "rows": { + "textarea": 1 }, + + "rowspan": { + "td": 1, + "th": 1 }, + + "rules": { + "table": 1 }, + + "sandbox": { + "iframe": 1 }, + + "scope": { + "td": 1, + "th": 1 }, + + "scoped": { + "style": 1 }, + + "scrolling": { + "iframe": 1 }, + + "seamless": { + "iframe": 1 }, + + "selected": { + "option": 1 }, + + "shape": { + "a": 1, + "area": 1 }, + + "size": { + "font": 1, + "hr": 1, + "input": 1, + "select": 1 }, + + "sizes": { + "link": 1 }, + + "span": { + "col": 1, + "colgroup": 1 }, + + "src": { + "audio": 1, + "embed": 1, + "iframe": 1, + "img": 1, + "input": 1, + "script": 1, + "source": 1, + "track": 1, + "video": 1 }, + + "srcdoc": { + "iframe": 1 }, + + "srclang": { + "track": 1 }, + + "srcset": { + "img": 1 }, + + "standby": { + "object": 1 }, + + "start": { + "ol": 1 }, + + "step": { + "input": 1 }, + + "summary": { + "table": 1 }, + + "target": { + "a": 1, + "area": 1, + "form": 1 }, + + "type": { + "a": 1, + "area": 1, + "button": 1, + "command": 1, + "embed": 1, + "input": 1, + "li": 1, + "link": 1, + "menu": 1, + "object": 1, + "ol": 1, + "param": 1, + "script": 1, + "source": 1, + "style": 1, + "ul": 1 }, + + "typemustmatch": { + "object": 1 }, + + "usemap": { + "img": 1, + "input": 1, + "object": 1 }, + + "valign": { + "col": 1, + "colgroup": 1, + "tbody": 1, + "td": 1, + "tfoot": 1, + "th": 1, + "thead": 1, + "tr": 1 }, + + "value": { + "button": 1, + "data": 1, + "input": 1, + "li": 1, + "meter": 1, + "option": 1, + "param": 1, + "progress": 1 }, + + "valuetype": { + "param": 1 }, + + "vspace": { + "applet": 1, + "embed": 1, + "img": 1, + "object": 1 }, + + "width": { + "applet": 1, + "canvas": 1, + "col": 1, + "colgroup": 1, + "embed": 1, + "hr": 1, + "iframe": 1, + "img": 1, + "input": 1, + "object": 1, + "pre": 1, + "table": 1, + "td": 1, + "th": 1, + "video": 1 }, + + "wmode": { + "embed": 1 }, + + "wrap": { + "textarea": 1 } }, + + + // ARIA + NA: { + "aria-activedescendant": 1, + "aria-atomic": 1, + "aria-autocomplete": 1, + "aria-busy": 1, + "aria-checked": 1, + "aria-controls": 1, + "aria-describedby": 1, + "aria-disabled": 1, + "aria-dropeffect": 1, + "aria-expanded": 1, + "aria-flowto": 1, + "aria-grabbed": 1, + "aria-haspopup": 1, + "aria-hidden": 1, + "aria-invalid": 1, + "aria-label": 1, + "aria-labelledby": 1, + "aria-level": 1, + "aria-live": 1, + "aria-multiline": 1, + "aria-multiselectable": 1, + "aria-orientation": 1, + "aria-owns": 1, + "aria-posinset": 1, + "aria-pressed": 1, + "aria-readonly": 1, + "aria-relevant": 1, + "aria-required": 1, + "aria-selected": 1, + "aria-setsize": 1, + "aria-sort": 1, + "aria-valuemax": 1, + "aria-valuemin": 1, + "aria-valuenow": 1, + "aria-valuetext": 1 }, + + // NE = Empty + NE: { + "allowfullscreen": 1, + "checkbox": 1, + "checked": 1, + "command": 1, + "compact": 1, + "declare": 1, + "defer": 1, + "default": 1, + "disabled": 1, + "hidden": 1, + "inert": 1, + "ismap": 1, + "itemscope": 1, + "multiple": 1, + "nohref": 1, + "noresize": 1, + "noshade": 1, + "nowrap": 1, + "open": 1, + "radio": 1, + "readonly": 1, + "required": 1, + "reversed": 1, + "selected": 1 }, + + // NO = Event + NO: { + "onabort": 1, + "onblur": 1, + "oncanplay": 1, + "oncanplaythrough": 1, + "onchange": 1, + "onclick": 1, + "oncontextmenu": 1, + "oncopy": 1, + "oncuechange": 1, + "oncut": 1, + "ondblclick": 1, + "ondrag": 1, + "ondragend": 1, + "ondragenter": 1, + "ondragleave": 1, + "ondragover": 1, + "ondragstart": 1, + "ondrop": 1, + "ondurationchange": 1, + "onemptied": 1, + "onended": 1, + "onerror": 1, + "onfocus": 1, + "onformchange": 1, + "onforminput": 1, + "oninput": 1, + "oninvalid": 1, + "onkeydown": 1, + "onkeypress": 1, + "onkeyup": 1, + "onload": 1, + "onloadeddata": 1, + "onloadedmetadata": 1, + "onloadstart": 1, + "onlostpointercapture": 1, + "onmousedown": 1, + "onmousemove": 1, + "onmouseout": 1, + "onmouseover": 1, + "onmouseup": 1, + "onmousewheel": 1, + "onpaste": 1, + "onpause": 1, + "onplay": 1, + "onplaying": 1, + "onpointercancel": 1, + "ongotpointercapture": 1, + "onpointerdown": 1, + "onpointerenter": 1, + "onpointerleave": 1, + "onpointermove": 1, + "onpointerout": 1, + "onpointerover": 1, + "onpointerup": 1, + "onprogress": 1, + "onratechange": 1, + "onreadystatechange": 1, + "onreset": 1, + "onsearch": 1, + "onscroll": 1, + "onseeked": 1, + "onseeking": 1, + "onselect": 1, + "onshow": 1, + "onstalled": 1, + "onsubmit": 1, + "onsuspend": 1, + "ontimeupdate": 1, + "ontoggle": 1, + "ontouchcancel": 1, + "ontouchend": 1, + "ontouchmove": 1, + "ontouchstart": 1, + "onvolumechange": 1, + "onwaiting": 1, + "onwheel": 1 }, + + // NP = Need scheme check; excludes style, on* & src + NP: { + "action": 1, + "cite": 1, + "classid": 1, + "codebase": 1, + "data": 1, + "href": 1, + "itemtype": 1, + "longdesc": 1, + "model": 1, + "pluginspage": 1, + "pluginurl": 1, + "src": 1, + "srcset": 1, + "usemap": 1 }, + + // NU = Univ & exceptions + NU: { + "accesskey": 1, + "class": 1, + "contenteditable": 1, + "contextmenu": 1, + "dir": 1, + "draggable": 1, + "dropzone": 1, + "hidden": 1, + "id": 1, + "inert": 1, + "itemid": 1, + "itemprop": 1, + "itemref": 1, + "itemscope": 1, + "itemtype": 1, + "lang": 1, + "role": 1, + "spellcheck": 1, + "style": 1, + "tabindex": 1, + "title": 1, + "translate": 1, + "xmlns": 1, + "xml:base": 1, + "xml:lang": 1, + "xml:space": 1 }, // predef attr vals for $eAL & $aNE ele NL: { - 'all': 1, 'baseline': 1, 'bottom': 1, 'button': 1, 'center': 1, 'char': 1, 'checkbox': 1, 'circle': 1, 'col': 1, - 'colgroup': 1, 'cols': 1, 'data': 1, 'default': 1, 'file': 1, 'get': 1, 'groups': 1, 'hidden': 1, 'image': 1, - 'justify': 1, 'left': 1, 'ltr': 1, 'middle': 1, 'none': 1, 'object': 1, 'password': 1, 'poly': 1, 'post': 1, - 'preserve': 1, 'radio': 1, 'rect': 1, 'ref': 1, 'reset': 1, 'right': 1, 'row': 1, 'rowgroup': 1, - 'rows': 1, 'rtl': 1, 'submit': 1, 'text': 1, 'top': 1 }, + "all": 1, + "auto": 1, + "baseline": 1, + "bottom": 1, + "button": 1, + "captions": 1, + "center": 1, + "chapters": 1, + "char": 1, + "checkbox": 1, + "circle": 1, + "col": 1, + "colgroup": 1, + "color": 1, + "cols": 1, + "data": 1, + "date": 1, + "datetime": 1, + "datetime-local": 1, + "default": 1, + "descriptions": 1, + "email": 1, + "file": 1, + "get": 1, + "groups": 1, + "hidden": 1, + "image": 1, + "justify": 1, + "left": 1, + "ltr": 1, + "metadata": 1, + "middle": 1, + "month": 1, + "none": 1, + "number": 1, + "object": 1, + "password": 1, + "poly": 1, + "post": 1, + "preserve": 1, + "radio": 1, + "range": 1, + "rect": 1, + "ref": 1, + "reset": 1, + "right": 1, + "row": 1, + "rowgroup": 1, + "rows": 1, + "rtl": 1, + "search": 1, + "submit": 1, + "subtitles": 1, + "tel": 1, + "text": 1, + "time": 1, + "top": 1, + "url": 1, + "week": 1 }, AL: { - 'a': 1, 'area': 1, 'bdo': 1, 'button': 1, 'col': 1, 'form': 1, 'img': 1, 'input': 1, 'object': 1, 'optgroup': 1, - 'option': 1, 'param': 1, 'script': 1, 'select': 1, 'table': 1, 'td': 1, 'tfoot': 1, 'th': 1, 'thead': 1, 'tr': 1, 'xml:space': 1 }, + "a": 1, + "area": 1, + "bdo": 1, + "button": 1, + "col": 1, + "fieldset": 1, + "form": 1, + "img": 1, + "input": 1, + "object": 1, + "ol": 1, + "optgroup": 1, + "option": 1, + "param": 1, + "script": 1, + "select": 1, + "table": 1, + "td": 1, + "textarea": 1, + "tfoot": 1, + "th": 1, + "thead": 1, + "tr": 1, + "track": 1, + "xml:space": 1 }, // dep attr:applicable ele ND: { - 'align': { - 'caption': 1, 'div': 1, 'h1': 1, 'h2': 1, 'h3': 1, 'h4': 1, 'h5': 1, 'h6': 1, 'hr': 1, 'img': 1, - 'input': 1, 'legend': 1, 'object': 1, 'p': 1, 'table': 1 }, + "align": { + "caption": 1, + "div": 1, + "h1": 1, + "h2": 1, + "h3": 1, + "h4": 1, + "h5": 1, + "h6": 1, + "hr": 1, + "img": 1, + "input": 1, + "legend": 1, + "object": 1, + "p": 1, + "table": 1 }, + + "bgcolor": { + "table": 1, + "td": 1, + "th": 1, + "tr": 1 }, + + "border": { + "object": 1 }, + + "bordercolor": { + "table": 1, + "td": 1, + "tr": 1 }, + + "cellspacing": { + "table": 1 }, + + "clear": { + "br": 1 }, + + "compact": { + "dl": 1, + "ol": 1, + "ul": 1 }, + + "height": { + "td": 1, + "th": 1 }, + + "hspace": { + "img": 1, + "object": 1 }, + + "language": { + "script": 1 }, + + "name": { + "a": 1, + "form": 1, + "iframe": 1, + "img": 1, + "map": 1 }, + + "noshade": { + "hr": 1 }, + + "nowrap": { + "td": 1, + "th": 1 }, + + "size": { + "hr": 1 }, + + "vspace": { + "img": 1, + "object": 1 }, + + "width": { + "hr": 1, + "pre": 1, + "table": 1, + "td": 1, + "th": 1 } }, - 'bgcolor': { 'table': 1, 'td': 1, 'th': 1, 'tr': 1 }, - 'border': { 'img': 1, 'object': 1 }, - 'bordercolor': { 'table': 1, 'td': 1, 'tr': 1 }, - 'clear': { 'br': 1 }, - 'compact': { 'dl': 1, 'ol': 1, 'ul': 1 }, - 'height': { 'td': 1, 'th': 1 }, - 'hspace': { 'img': 1, 'object': 1 }, - 'language': { 'script': 1 }, - 'name': { 'a': 1, 'form': 1, 'iframe': 1, 'img': 1, 'map': 1 }, - 'noshade': { 'hr': 1 }, - 'nowrap': { 'td': 1, 'th': 1 }, - 'size': { 'hr': 1 }, - 'start': { 'ol': 1 }, - 'type': { 'li': 1, 'ol': 1, 'ul': 1 }, - 'value': { 'li': 1 }, - 'vspace': { 'img': 1, 'object': 1 }, - 'width': { 'hr': 1, 'pre': 1, 'td': 1, 'th': 1 } }, AD: { - 'a': 1, 'br': 1, 'caption': 1, 'div': 1, 'dl': 1, 'form': 1, 'h1': 1, 'h2': 1, 'h3': 1, 'h4': 1, 'h5': 1, - 'h6': 1, 'hr': 1, 'iframe': 1, 'img': 1, 'input': 1, 'legend': 1, 'li': 1, 'map': 1, 'object': 1, 'ol': 1, - 'p': 1, 'pre': 1, 'script': 1, 'table': 1, 'td': 1, 'th': 1, 'tr': 1, 'ul': 1 }, + "a": 1, + "br": 1, + "caption": 1, + "div": 1, + "dl": 1, + "form": 1, + "h1": 1, + "h2": 1, + "h3": 1, + "h4": 1, + "h5": 1, + "h6": 1, + "hr": 1, + "iframe": 1, + "img": 1, + "input": 1, + "legend": 1, + "map": 1, + "object": 1, + "ol": 1, + "p": 1, + "pre": 1, + "script": 1, + "table": 1, + "td": 1, + "th": 1, + "tr": 1, + "ul": 1 }, + + // rqd attr + AR: { + "area": { + "alt": "area" }, + + "bdo": { + "dir": "ltr" }, + + "command": { + "label": "" }, + + "form": { + "action": "" }, + + "img": { + "src": "", + "alt": "image" }, + + "map": { + "name": "" }, + + "optgroup": { + "label": "" }, + + "param": { + "name": "" }, + + "style": { + "scoped": "" }, + + "textarea": { + "rows": "10", + "cols": "50" } } }, - AR: { // rqd attr - 'area': { 'alt': 'area' }, - 'bdo': { 'dir': 'ltr' }, - 'form': { 'action': '' }, - 'img': { 'src': '', 'alt': 'image' }, - 'map': { 'name': '' }, - 'optgroup': { 'label': '' }, - 'param': { 'name': '' }, - 'script': { 'type': 'text/javascript' }, - 'textarea': { 'rows': '10', 'cols': '50' } } }, STYLE_ENT: { @@ -935,7 +1837,7 @@ var htmLawed = module.exports = switch (mode) { case 0: // Name - m = /^[a-zA-Z][\-a-zA-Z:]+/.exec(a); + m = /^[a-zA-Z][^\s=/]+/.exec(a); if (m) { nm = m[0].toLowerCase(); @@ -990,7 +1892,11 @@ var htmLawed = module.exports = { v = aA[k]; if ((C.deny_attribute['*'] ? C.deny_attribute[k] : !C.deny_attribute[k]) && ( - TAG.N[k] && TAG.N[k][e] || TAG.NU[k] && !TAG.NU[k][e]) && ( + TAG.N[k] && TAG.N[k][e] || + TAG.NU[k] || + TAG.NO[k] && !C.deny_attribute['on*'] || + TAG.NA[k] && !C.deny_attribute['aria*'] || + !C.deny_attribute['data*'] && /data-((?!xml)[^:]+$)/.exec(k)) && ( !rl.n || !rl.n[k] && !rl.n['*']) || rl[k]) { if (TAG.NE[k]) @@ -1011,11 +1917,26 @@ var htmLawed = module.exports = }); v = !C.css_expression ? v.replace(/\\\S|(\/|(%2f))(\*|(%2a))/gi, ' ').replace(/expression/gi, ' ') : v; } else - if (TAG.NP[k] || k.indexOf('src') >= 0 || k[0] == 'o') + if (TAG.NP[k] || TAG.NO[k]) { - // double-quoted char is soft-hyphen; appears here as "­" or hyphen or something else depending on viewing software - v = (v.indexOf('&') >= 0 ? v.replace(/­|­|­/g, ' ') : v).replace(/­/g, ' '); - v = htmLawed.hl_prot(v, k); + // double-quoted char: soft-hyphen; appears here as "\xAD" or hyphen or something else depending on viewing software + v = (v.indexOf('&') >= 0 ? v.replace(/­|­|­/g, ' ') : v).replace(/\xAD/g, ' '); + if (k == 'srcset') + { + v = v.trim().split(/\s*,\s*/).map(function (v1) {return ( + v1.split(/\s+/, 2).map(function (v2, k2) {return ( + k2 == 0 ? htmLawed.hl_prot(v2, k) : v2.trim());}). + join(' '));}). + join(', '); + } + if (k == 'itemtype') + { + v = v.trim().split(/\s+/).map(function (v1) {return htmLawed.hl_prot(v1, k);}).join(' '); + } else + + { + v = htmLawed.hl_prot(v, k); + } if (k == 'href') { // X-spam @@ -1061,7 +1982,7 @@ var htmLawed = module.exports = a[k] = TAG.AR[e][k] || k;} } - // depr attrs + // depr attr if (depTr) { var c = []; @@ -1070,6 +1991,7 @@ var htmLawed = module.exports = v = a[k]; if (k == 'style' || !TAG.ND[k] || !TAG.ND[k][e]) continue; + v = v.replace(/(\\|:|;|&#)/g, ''); if (k == 'align') { delete a[k]; @@ -1086,6 +2008,8 @@ var htmLawed = module.exports = c.push('border: ' + v + 'px');else if (k == 'bordercolor') c.push('border-color: ' + v);else + if (k == 'cellspacing') + c.push('border-spacing: ' + v + 'px');else if (k == 'clear') c.push('clear: ' + (v != 'all' ? v : 'both'));else if (k == 'compact') @@ -1098,7 +2022,7 @@ var htmLawed = module.exports = a.type = 'text/' + v.toLowerCase();else if (k == 'name') { - if (!a.id && /^[a-zA-Z][a-zA-Z\d\.:_\-]*$/.exec(v)) + if (!a.id && !/\W/.exec(v)) a.id = v; if (!(C.no_deprecated_attr == 2 || e != 'a' && e != 'map')) { @@ -1112,15 +2036,6 @@ var htmLawed = module.exports = c.push('white-space: nowrap');else if (k == 'size') c.push('size: ' + v + 'px');else - if (k == 'start' || k == 'value') - { - // just delete - } else - if (k == 'type') - { - var ol_type = { 'i': 'lower-roman', 'I': 'upper-roman', 'a': 'lower-latin', 'A': 'upper-latin', '1': 'decimal' }; - c.push('list-style-type: ' + (ol_type[v] || 'decimal')); - } else if (k == 'vspace') c.push('margin-top: ' + v + 'px; margin-bottom: ' + v + 'px');else @@ -1137,7 +2052,7 @@ var htmLawed = module.exports = // unique ID if (C.unique_ids && a.id) { - if (!/^[A-Za-z][A-Za-z0-9_\-\.:]*$/.exec(a.id) || + if (/\s/.exec(a.id) || htmLawed.hl_Ids[a.id] && C.unique_ids == 1) delete a.id;else @@ -1169,7 +2084,6 @@ var htmLawed = module.exports = return '<' + e + aA + (TAG.E[e] ? ' /' : '') + '>'; } return C.hook_tag(e, a); - // eof }, hl_tag2: function (e, a, t) { @@ -1178,12 +2092,16 @@ var htmLawed = module.exports = // transform tag if (e == 'center') return ['div', a, 'text-align: center;'];else - if (e == 'dir' || e == 'menu') + if (e == 'acronym') + return ['abbr', a, ''];else + if (e == 'dir') return ['ul', a, ''];else + if (e == 'big') + return ['span', a, 'font-size: larger;'];else if (e == 's' || e == 'strike') return ['span', a, 'text-decoration: line-through;'];else - if (e == 'u') - return ['span', a, 'text-decoration: underline;'];else + if (e == 'tt') + return ['code', a, ''];else if (e == 'font') { var a2 = ''; @@ -1207,34 +2125,28 @@ var htmLawed = module.exports = if (t == 2) return [0, a, 0]; return [e, a, '']; - // eof }, TIDY: { a: { 'br': 1 }, - b: { 'button': 1, 'input': 1, 'option': 1, 'param': 1 }, - c: { - 'caption': 1, 'dd': 1, 'dt': 1, 'h1': 1, 'h2': 1, 'h3': 1, 'h4': 1, 'h5': 1, 'h6': 1, 'isindex': 1, - 'label': 1, 'legend': 1, 'li': 1, 'object': 1, 'p': 1, 'pre': 1, 'td': 1, 'textarea': 1, 'th': 1 }, - - d: { - 'address': 1, 'blockquote': 1, 'center': 1, 'colgroup': 1, 'dir': 1, 'div': 1, 'dl': 1, 'fieldset': 1, - 'form': 1, 'hr': 1, 'iframe': 1, 'map': 1, 'menu': 1, 'noscript': 1, 'ol': 1, 'optgroup': 1, 'rbc': 1, - 'rtc': 1, 'ruby': 1, 'script': 1, 'select': 1, 'table': 1, 'tbody': 1, 'tfoot': 1, 'thead': 1, 'tr': 1, 'ul': 1 } }, - + b: { 'button': 1, 'command': 1, 'input': 1, 'option': 1, 'param': 1, 'track': 1 }, + c: { 'audio': 1, 'canvas': 1, 'caption': 1, 'dd': 1, 'dt': 1, 'figcaption': 1, 'h1': 1, 'h2': 1, 'h3': 1, 'h4': 1, 'h5': 1, 'h6': 1, 'isindex': 1, 'label': 1, 'legend': 1, 'li': 1, 'object': 1, 'p': 1, 'pre': 1, 'style': 1, 'summary': 1, 'td': 1, 'textarea': 1, 'th': 1, 'video': 1 }, + d: { 'address': 1, 'article': 1, 'aside': 1, 'blockquote': 1, 'center': 1, 'colgroup': 1, 'datalist': 1, 'details': 1, 'dir': 1, 'div': 1, 'dl': 1, 'fieldset': 1, 'figure': 1, 'footer': 1, 'form': 1, 'header': 1, 'hgroup': 1, 'hr': 1, 'iframe': 1, 'main': 1, 'map': 1, 'menu': 1, 'nav': 1, 'noscript': 1, 'ol': 1, 'optgroup': 1, 'rbc': 1, 'rtc': 1, 'ruby': 1, 'script': 1, 'section': 1, 'select': 1, 'table': 1, 'tbody': 1, 'tfoot': 1, 'thead': 1, 'tr': 1, 'ul': 1 } }, hl_tidy: function (t, w, p) { // Tidy/compact HTM if (' pre,script,textarea'.indexOf("$p,") >= 0) return t; - var _repl = function (m) + var _repl = function (m, m1, m2, m3, m4) { - return m[1] + htmLawed._strtr(m[3], { '<': "\x01", '>': "\x02", "\n": "\x03", "\r": "\x04", "\t": "\x05", ' ': "\x07" }) + m[4]; + return m1 + htmLawed._strtr(m3, { '<': "\x01", '>': "\x02", "\n": "\x03", "\r": "\x04", "\t": "\x05", ' ': "\x07" }) + m4; }; t = t.replace(/(<(!\[CDATA\[))([\s\S]+?)(\]\]>)/g, _repl). replace(/(<(!--))([\s\S]+?)(-->)/g, _repl). replace(/(<(pre|script|textarea)[^>]*?>)([\s\S]+?)(<\/\2>)/g, _repl). - replace(/\s+/g, ' '); + replace(/(<\w[^>]*(?)\s+/g, ' $1'). + replace(/\s+/g, ' '). + replace(/(<\w[^>]*(?) /g, '$1'); if (w == -1) return htmLawed._strtr(t, { "\x01": '<', "\x02": '>', "\x03": "\n", "\x04": "\r", "\x05": "\t", "\x07": ' ' }); w = w.toLowerCase(); @@ -1309,10 +2221,9 @@ var htmLawed = module.exports = if (l) t = t.replace(/\n/g, l); return htmLawed._strtr(t, { "\x01": '<', "\x02": '>', "\x03": "\n", "\x04": "\r", "\x05": "\t", "\x07": ' ' }); - // eof }, hl_version: function () { - return '1.1.22'; + return '1.2.4.1'; } }; diff --git a/htmLawed.src.js b/htmLawed.src.js index 6091476..d58372f 100644 --- a/htmLawed.src.js +++ b/htmLawed.src.js @@ -1,4 +1,4 @@ -// JS rewrite of http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/ +// JS rewrite of http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/ 1.2.4.1 var htmLawed = module.exports = { @@ -22,6 +22,12 @@ var htmLawed = module.exports = r.push(i); return r; }, + _nonempty: function(h) + { + for (var i in h) + return true; + return false; + }, _htmlspecialchars: function(t) { return t.replace(/&/g, '&') @@ -37,19 +43,22 @@ var htmLawed = module.exports = if (!S) S = {}; if (C.valid_xhtml) { - C.elements = C.elements || '*-center-dir-font-isindex-menu-s-strike-u'; + C.elements = C.elements || '*-acronym-big-center-dir-font-isindex-s-strike-tt'; C.make_tag_strict = C.make_tag_strict !== undefined ? C.make_tag_strict : 2; C['xml:lang'] = C['xml:lang'] !== undefined ? C['xml:lang'] : 2; } // config eles - var e = { 'a':1, 'abbr':1, 'acronym':1, 'address':1, 'applet':1, 'area':1, 'b':1, 'bdo':1, 'big':1, 'blockquote':1, 'br':1, 'button':1, 'caption':1, 'center':1, 'cite':1, 'code':1, 'col':1, 'colgroup':1, 'dd':1, 'del':1, 'dfn':1, 'dir':1, 'div':1, 'dl':1, 'dt':1, 'em':1, 'embed':1, 'fieldset':1, 'font':1, 'form':1, 'h1':1, 'h2':1, 'h3':1, 'h4':1, 'h5':1, 'h6':1, 'hr':1, 'i':1, 'iframe':1, 'img':1, 'input':1, 'ins':1, 'isindex':1, 'kbd':1, 'label':1, 'legend':1, 'li':1, 'map':1, 'menu':1, 'noscript':1, 'object':1, 'ol':1, 'optgroup':1, 'option':1, 'p':1, 'param':1, 'pre':1, 'q':1, 'rb':1, 'rbc':1, 'rp':1, 'rt':1, 'rtc':1, 'ruby':1, 's':1, 'samp':1, 'script':1, 'select':1, 'small':1, 'span':1, 'strike':1, 'strong':1, 'sub':1, 'sup':1, 'table':1, 'tbody':1, 'td':1, 'textarea':1, 'tfoot':1, 'th':1, 'thead':1, 'tr':1, 'tt':1, 'u':1, 'ul':1, 'var':1 }; // 86/deprecated+embed+ruby + var e = { 'a': 1, 'abbr': 1, 'acronym': 1, 'address': 1, 'applet': 1, 'area': 1, 'article': 1, 'aside': 1, 'audio': 1, 'b': 1, 'bdi': 1, 'bdo': 1, 'big': 1, 'blockquote': 1, 'br': 1, 'button': 1, 'canvas': 1, 'caption': 1, 'center': 1, 'cite': 1, 'code': 1, 'col': 1, 'colgroup': 1, 'command': 1, 'data': 1, 'datalist': 1, 'dd': 1, 'del': 1, 'details': 1, 'dfn': 1, 'dir': 1, 'div': 1, 'dl': 1, 'dt': 1, 'em': 1, 'embed': 1, 'fieldset': 1, 'figcaption': 1, 'figure': 1, 'font': 1, 'footer': 1, 'form': 1, 'h1': 1, 'h2': 1, 'h3': 1, 'h4': 1, 'h5': 1, 'h6': 1, 'header': 1, 'hgroup': 1, 'hr': 1, 'i': 1, 'iframe': 1, 'img': 1, 'input': 1, 'ins': 1, 'isindex': 1, 'kbd': 1, 'keygen': 1, 'label': 1, 'legend': 1, 'li': 1, 'link': 1, 'main': 1, 'map': 1, 'mark': 1, 'menu': 1, 'meta': 1, 'meter': 1, 'nav': 1, 'noscript': 1, 'object': 1, 'ol': 1, 'optgroup': 1, 'option': 1, 'output': 1, 'p': 1, 'param': 1, 'pre': 1, 'progress': 1, 'q': 1, 'rb': 1, 'rbc': 1, 'rp': 1, 'rt': 1, 'rtc': 1, 'ruby': 1, 's': 1, 'samp': 1, 'script': 1, 'section': 1, 'select': 1, 'small': 1, 'source': 1, 'span': 1, 'strike': 1, 'strong': 1, 'style': 1, 'sub': 1, 'summary': 1, 'sup': 1, 'table': 1, 'tbody': 1, 'td': 1, 'textarea': 1, 'tfoot': 1, 'th': 1, 'thead': 1, 'time': 1, 'tr': 1, 'track': 1, 'tt': 1, 'u': 1, 'ul': 1, 'var': 1, 'video': 1, 'wbr': 1 }; if (C.safe) { delete e.applet; + delete e.audio; + delete e.canvas; delete e.embed; delete e.iframe; delete e.object; delete e.script; + delete e.video; } var x = C.elements ? C.elements.replace(/\s+/g, '') : '*'; var v, m, i; @@ -73,8 +82,12 @@ var htmLawed = module.exports = } C.elements = e; // config attrs - x = C.deny_attribute ? C.deny_attribute.replace(/\s+/g, '') : ''; - x = htmLawed._flip(x[0] == '*' ? x.split(/-/) : (x+(C.safe ? ',on*' : '')).split(',')); + x = C.deny_attribute ? C.deny_attribute.replace(/\s+/g, '').toLowerCase() : ''; + x = htmLawed._flip( + x[0] == '*' + ? x.replace(/data-/g, '/').split('-').map(s => s.replace('/', 'data-')) + : (x+(C.safe ? ',on*' : '')).split(',') + ); if (x['on*']) { delete x['on*']; @@ -83,8 +96,10 @@ var htmLawed = module.exports = x[i] = true; } C.deny_attribute = x; - // config URL - x = C.schemes && C.schemes.length > 2 && C.schemes.indexOf(':') > 0 ? C.schemes.toLowerCase() : 'href: aim, feed, file, ftp, gopher, http, https, irc, mailto, news, nntp, sftp, ssh, telnet; *:file, http, https'; + // config URLs + x = C.schemes && C.schemes.length > 2 && C.schemes.indexOf(':') > 0 ? C.schemes.toLowerCase() : + 'href: aim, feed, file, ftp, gopher, http, https, irc, mailto, news, nntp, sftp, ssh, tel, telnet'+ + (!C.safe ? ', app, javascript; *: data, javascript, ' : '; *:')+'file, http, https'; C.schemes = {}; m = x.replace(/\s+/g, '').split(';'); for (v in m) @@ -94,7 +109,14 @@ var htmLawed = module.exports = C.schemes[x[0]] = htmLawed._flip(x[1].split(',')); } if (!C.schemes['*']) + { C.schemes['*'] = { file: 1, http: 1, https: 1 }; + if (!C.safe) + { + C.schemes['*'].data = 1; + C.schemes['*'].javascript = 1; + } + } if (C.safe && !C.schemes.style) C.schemes.style = { '!': 1 }; C.abs_url = C.abs_url !== undefined ? C.abs_url : 0; @@ -124,7 +146,7 @@ var htmLawed = module.exports = C.show_setting = C.show_setting ? C.show_setting : 0; C.style_pass = !C.style_pass ? 0 : 1; C.tidy = !C.tidy ? 0 : C.tidy; - C.unique_ids = C.unique_ids !== undefined ? C.unique_ids : 1; + C.unique_ids = C.unique_ids !== undefined && !/\W/u.exec(C.unique_ids) ? C.unique_ids : 1; C['xml:lang'] = C['xml:lang'] !== undefined ? C['xml:lang'] : 0; S = typeof S == 'object' ? S : htmLawed.hl_spec(S); @@ -161,14 +183,13 @@ var htmLawed = module.exports = t = htmLawed._strtr(t, { "\x01": '', "\x02": '', "\x03": '&', "\x04": '<', "\x05": '>' }); if (C.tidy) t = htmLawed.hl_tidy(t, C.tidy, C.parent); - // eof return t; }, hl_attrval: function(a, t, p) { // check attr val against S - var ma = { accesskey: 1, class: 1, rel: 1 }; - var s = ma[a] ? ' ' : ''; + var ma = { accesskey: 1, class: 1, itemtype: 1, rel: 1 }; + var s = ma[a] ? ' ' : (a == 'srcset' ? ',' : ''); var r = []; var i; t = s ? t.split(s) : [ t ]; @@ -176,37 +197,41 @@ var htmLawed = module.exports = { var tv = t[tk]; var o = 1; - var l = tv.length; - for (var k in p) + if (tv.trim().length) { - var v = p[k]; - switch (k) + var l = tv.length; + for (var k in p) { - case 'maxlen': if(l > v){o = 0;} break; - case 'minlen': if(l < v){o = 0;} break; - case 'maxval': if(parseFloat(tv) > v){o = 0;} break; - case 'minval': if(parseFloat(tv) < v){o = 0;} break; - case 'match': if(!v.exec(tv)){o = 0;} break; - case 'nomatch': if(v.exec(tv)){o = 0;} break; - case 'oneof': - v = v.split('|'); - for (i = 0; i < v.length && v[i] != tv; i++) {} - o = (i < v.length); - break; - case 'noneof': - v = v.split('|'); - for (i = 0; i < v.length && v[i] != tv; i++) {} - o = (i >= v.length); - break; + var v = p[k]; + switch (k) + { + case 'maxlen': if(l > v){o = 0;} break; + case 'minlen': if(l < v){o = 0;} break; + case 'maxval': if(parseFloat(tv) > v){o = 0;} break; + case 'minval': if(parseFloat(tv) < v){o = 0;} break; + case 'match': if(!v.exec(tv)){o = 0;} break; + case 'nomatch': if(v.exec(tv)){o = 0;} break; + case 'oneof': + v = v.split('|'); + for (i = 0; i < v.length && v[i] != tv; i++) {} + o = (i < v.length); + break; + case 'noneof': + v = v.split('|'); + for (i = 0; i < v.length && v[i] != tv; i++) {} + o = (i >= v.length); + break; + } + if (!o) + break; } - if (!o) - break; } if (o) r.push(tv); } + if (s == ',') + s = ', '; return (r.length > 0 ? r.join(s) : (p['default'] || 0)); - // eof }, hl_bal: function(t, keep_bad, intag) { @@ -217,23 +242,26 @@ var htmLawed = module.exports = // by content var cont = {}; cont.B = { 'blockquote':1, 'form':1, 'map':1, 'noscript':1 }; // Block - cont.E = { 'area':1, 'br':1, 'col':1, 'embed':1, 'hr':1, 'img':1, 'input':1, 'isindex':1, 'param':1 }; // Empty - cont.F = { 'button':1, 'del':1, 'div':1, 'dd':1, 'fieldset':1, 'iframe':1, 'ins':1, 'li':1, 'noscript':1, 'object':1, 'td':1, 'th':1 }; // Flow; later context-wise dynamic move of ins & del to cont.I - cont.I = { 'style':1, 'a':1, 'abbr':1, 'acronym':1, 'address':1, 'b':1, 'bdo':1, 'big':1, 'caption':1, 'cite':1, 'code':1, 'dfn':1, 'dt':1, 'em':1, 'font':1, 'h1':1, 'h2':1, 'h3':1, 'h4':1, 'h5':1, 'h6':1, 'i':1, 'kbd':1, 'label':1, 'legend':1, 'p':1, 'pre':1, 'q':1, 'rb':1, 'rt':1, 's':1, 'samp':1, 'small':1, 'span':1, 'strike':1, 'strong':1, 'sub':1, 'sup':1, 'tt':1, 'u':1, 'var':1 }; // Inline - cont.N = { 'style':1, 'a':{'a':1}, 'button':{'a':1, 'button':1, 'fieldset':1, 'form':1, 'iframe':1, 'input':1, 'label':1, 'select':1, 'textarea':1}, 'fieldset':{'fieldset':1}, 'form':{'form':1}, 'label':{'label':1}, 'noscript':{'script':1}, 'pre':{'big':1, 'font':1, 'img':1, 'object':1, 'script':1, 'small':1, 'sub':1, 'sup':1}, 'rb':{'ruby':1}, 'rt':{'ruby':1} }; // Illegal - cont.R = { 'blockquote':1, 'dir':1, 'dl':1, 'form':1, 'map':1, 'menu':1, 'noscript':1, 'ol':1, 'optgroup':1, 'rbc':1, 'rtc':1, 'ruby':1, 'select':1, 'table':1, 'tbody':1, 'tfoot':1, 'thead':1, 'tr':1, 'ul':1 }; - cont.S = { 'colgroup':{'col':1}, 'dir':{'li':1}, 'dl':{'dd':1, 'dt':1}, 'menu':{'li':1}, 'ol':{'li':1}, 'optgroup':{'option':1}, 'option':{'#pcdata':1}, 'rbc':{'rb':1}, 'rp':{'#pcdata':1}, 'rtc':{'rt':1}, 'ruby':{'rb':1, 'rbc':1, 'rp':1, 'rt':1, 'rtc':1}, 'select':{'optgroup':1, 'option':1}, 'script':{'#pcdata':1}, 'table':{'caption':1, 'col':1, 'colgroup':1, 'tfoot':1, 'tbody':1, 'tr':1, 'thead':1}, 'tbody':{'tr':1}, 'tfoot':{'tr':1}, 'textarea':{'#pcdata':1}, 'thead':{'tr':1}, 'tr':{'td':1, 'th':1}, 'ul':{'li':1} }; // Specific - immediate parent-child + cont.E = { 'area': 1, 'br': 1, 'col': 1, 'command': 1, 'embed': 1, 'hr': 1, 'img': 1, 'input': 1, 'isindex': 1, 'keygen': 1, 'link': 1, 'meta': 1, 'param': 1, 'source': 1, 'track': 1, 'wbr': 1 }; // Empty + cont.F = { 'a': 1, 'article': 1, 'aside': 1, 'audio': 1, 'button': 1, 'canvas': 1, 'del': 1, 'details': 1, 'div': 1, 'dd': 1, 'fieldset': 1, 'figure': 1, 'footer': 1, 'header': 1, 'iframe': 1, 'ins': 1, 'li': 1, 'main': 1, 'menu': 1, 'nav': 1, 'noscript': 1, 'object': 1, 'section': 1, 'style': 1, 'td': 1, 'th': 1, 'video': 1 }; // Flow; later context-wise dynamic move of ins & del to cont.I + cont.I = { 'abbr': 1, 'acronym': 1, 'address': 1, 'b': 1, 'bdi': 1, 'bdo': 1, 'big': 1, 'caption': 1, 'cite': 1, 'code': 1, 'data': 1, 'datalist': 1, 'dfn': 1, 'dt': 1, 'em': 1, 'figcaption': 1, 'font': 1, 'h1': 1, 'h2': 1, 'h3': 1, 'h4': 1, 'h5': 1, 'h6': 1, 'hgroup': 1, 'i': 1, 'kbd': 1, 'label': 1, 'legend': 1, 'mark': 1, 'meter': 1, 'output': 1, 'p': 1, 'pre': 1, 'progress': 1, 'q': 1, 'rb': 1, 'rt': 1, 's': 1, 'samp': 1, 'small': 1, 'span': 1, 'strike': 1, 'strong': 1, 'sub': 1, 'summary': 1, 'sup': 1, 'time': 1, 'tt': 1, 'u': 1, 'var': 1 }; // Inline + cont.N = { 'a': { 'a': 1, 'address': 1, 'button': 1, 'details': 1, 'embed': 1, 'keygen': 1, 'label': 1, 'select': 1, 'textarea': 1 }, 'address': { 'address': 1, 'article': 1, 'aside': 1, 'header': 1, 'keygen': 1, 'footer': 1, 'nav': 1, 'section': 1 }, 'button': { 'a': 1, 'address': 1, 'button': 1, 'details': 1, 'embed': 1, 'fieldset': 1, 'form': 1, 'iframe': 1, 'input': 1, 'keygen': 1, 'label': 1, 'select': 1, 'textarea': 1 }, 'fieldset': { 'fieldset': 1 }, 'footer': { 'header': 1, 'footer': 1 }, 'form': { 'form': 1 }, 'header': { 'header': 1, 'footer': 1 }, 'label': { 'label': 1 }, 'main': { 'main': 1 }, 'meter': { 'meter': 1 }, 'noscript': { 'script': 1 }, 'pre': { 'big': 1, 'font': 1, 'img': 1, 'object': 1, 'script': 1, 'small': 1, 'sub': 1, 'sup': 1 }, 'progress': { 'progress': 1 }, 'rb': { 'ruby': 1 }, 'rt': { 'ruby': 1 }, 'time': { 'time': 1 }, }; // Illegal + cont.S = {"colgroup":{"col":1},"datalist":{"option":1},"dir":{"li":1},"dl":{"dd":1,"dt":1},"hgroup":{"h1":1,"h2":1,"h3":1,"h4":1,"h5":1,"h6":1},"menu":{"li":1},"ol":{"li":1},"optgroup":{"option":1},"option":{"#pcdata":1},"rbc":{"rb":1},"rp":{"#pcdata":1},"rtc":{"rt":1},"ruby":{"rb":1,"rbc":1,"rp":1,"rt":1,"rtc":1},"select":{"optgroup":1,"option":1},"script":{"#pcdata":1},"table":{"caption":1,"col":1,"colgroup":1,"tfoot":1,"tbody":1,"tr":1,"thead":1},"tbody":{"tr":1},"tfoot":{"tr":1},"textarea":{"#pcdata":1},"thead":{"tr":1},"tr":{"td":1,"th":1},"ul":{"li":1}}; // Specific - immediate parent-child if (htmLawed.C.direct_list_nest) - cont.S['ol']['ol'] = cont.S['ul']['ol'] = cont.S['ol']['ul'] = cont.S['ul']['ul'] = 1; - cont.O = { 'address':{'p':1}, 'applet':{'param':1}, 'blockquote':{'script':1}, 'fieldset':{'legend':1, '#pcdata':1}, 'form':{'script':1}, 'map':{'area':1}, 'object':{'param':1, 'embed':1} }; // Other + { + cont.S['ol']['ol'] = cont.S['ol']['ul'] = cont.S['ol']['menu'] = 1; + cont.S['ul']['ol'] = cont.S['ul']['ul'] = cont.S['ul']['menu'] = 1; + cont.S['menu']['ol'] = cont.S['menu']['ul'] = cont.S['menu']['menu'] = 1; + } + cont.O = {"address":{"p":1},"applet":{"param":1},"audio":{"source":1,"track":1},"blockquote":{"script":1},"details":{"summary":1},"fieldset":{"legend":1,"#pcdata":1},"figure":{"figcaption":1},"form":{"script":1},"map":{"area":1},"object":{"param":1,"embed":1},"video":{"source":1,"track":1}}; // Other cont.T = { 'colgroup':1, 'dd':1, 'dt':1, 'li':1, 'option':1, 'p':1, 'td':1, 'tfoot':1, 'th':1, 'thead':1, 'tr':1 }; // Omitable closing - // block/inline type; ins & del both type; #pcdata: text + // block/inline type; a/ins/del both type; #pcdata: text var el = {}; - el.B = { 'address':1, 'blockquote':1, 'center':1, 'del':1, 'dir':1, 'dl':1, 'div':1, 'fieldset':1, 'form':1, 'ins':1, 'h1':1, 'h2':1, 'h3':1, 'h4':1, 'h5':1, 'h6':1, 'hr':1, 'isindex':1, 'menu':1, 'noscript':1, 'ol':1, 'p':1, 'pre':1, 'table':1, 'ul':1 }; - el.I = { 'style':1, '#pcdata':1, 'a':1, 'abbr':1, 'acronym':1, 'applet':1, 'b':1, 'bdo':1, 'big':1, 'br':1, 'button':1, 'cite':1, 'code':1, 'del':1, 'dfn':1, 'em':1, 'embed':1, 'font':1, 'i':1, 'iframe':1, 'img':1, 'input':1, 'ins':1, 'kbd':1, 'label':1, 'map':1, 'object':1, 'q':1, 'ruby':1, 's':1, 'samp':1, 'select':1, 'script':1, 'small':1, 'span':1, 'strike':1, 'strong':1, 'sub':1, 'sup':1, 'textarea':1, 'tt':1, 'u':1, 'var':1 }; - el.N = { 'a':1, 'big':1, 'button':1, 'fieldset':1, 'font':1, 'form':1, 'iframe':1, 'img':1, 'input':1, 'label':1, 'object':1, 'ruby':1, 'script':1, 'select':1, 'small':1, 'sub':1, 'sup':1, 'textarea':1 }; // Exclude from specific ele; cont.N values - el.O = { 'area':1, 'caption':1, 'col':1, 'colgroup':1, 'dd':1, 'dt':1, 'legend':1, 'li':1, 'optgroup':1, 'option':1, 'param':1, 'rb':1, 'rbc':1, 'rp':1, 'rt':1, 'rtc':1, 'script':1, 'tbody':1, 'td':1, 'tfoot':1, 'thead':1, 'th':1, 'tr':1 }; // Missing in el.B & el.I - el.F = { ...el.B, ...el.I }; // FIXME <=> Object.assign({}, el.B, el.I) + el.B = {"a":1,"address":1,"article":1,"aside":1,"blockquote":1,"center":1,"del":1,"details":1,"dir":1,"dl":1,"div":1,"fieldset":1,"figure":1,"footer":1,"form":1,"ins":1,"h1":1,"h2":1,"h3":1,"h4":1,"h5":1,"h6":1,"header":1,"hr":1,"isindex":1,"main":1,"menu":1,"nav":1,"noscript":1,"ol":1,"p":1,"pre":1,"section":1,"style":1,"table":1,"ul":1}; + el.I = {"#pcdata":1,"a":1,"abbr":1,"acronym":1,"applet":1,"audio":1,"b":1,"bdi":1,"bdo":1,"big":1,"br":1,"button":1,"canvas":1,"cite":1,"code":1,"command":1,"data":1,"datalist":1,"del":1,"dfn":1,"em":1,"embed":1,"figcaption":1,"font":1,"i":1,"iframe":1,"img":1,"input":1,"ins":1,"kbd":1,"label":1,"link":1,"map":1,"mark":1,"meta":1,"meter":1,"object":1,"output":1,"progress":1,"q":1,"ruby":1,"s":1,"samp":1,"select":1,"script":1,"small":1,"span":1,"strike":1,"strong":1,"sub":1,"summary":1,"sup":1,"textarea":1,"time":1,"tt":1,"u":1,"var":1,"video":1,"wbr":1}; + el.N = {"a":1,"address":1,"article":1,"aside":1,"big":1,"button":1,"details":1,"embed":1,"fieldset":1,"font":1,"footer":1,"form":1,"header":1,"iframe":1,"img":1,"input":1,"keygen":1,"label":1,"meter":1,"nav":1,"object":1,"progress":1,"ruby":1,"script":1,"select":1,"small":1,"sub":1,"sup":1,"textarea":1,"time":1}; + el.O = {"area":1,"caption":1,"col":1,"colgroup":1,"command":1,"dd":1,"dt":1,"hgroup":1,"keygen":1,"legend":1,"li":1,"optgroup":1,"option":1,"param":1,"rb":1,"rbc":1,"rp":1,"rt":1,"rtc":1,"script":1,"source":1,"tbody":1,"td":1,"tfoot":1,"thead":1,"th":1,"tr":1,"track":1}; + el.F = { ...el.B, ...el.I }; function getCont(intag) { @@ -474,7 +502,6 @@ var htmLawed = module.exports = while ((e = q.pop())) _ob += ''; return _ob; - // eof }, hl_cmtcd: function(t) { @@ -483,7 +510,7 @@ var htmLawed = module.exports = var v = htmLawed.C[n]; if (!v) return t; if (v == 1) return ''; - if (n == 'comment') + if (n == 'comment' && v < 4) { t = t.substr(4, t.length-3-4).replace(/--+/g, '-'); if (t.substr(t.length-1) != ' ') @@ -494,7 +521,6 @@ var htmLawed = module.exports = t = v == 2 ? htmLawed._strtr(t, { '&': '&', '<' : '<', '>': '>' }) : t; t = (n == 'comment' ? "\x01\x02\x04!--"+t+"--\x05\x02\x01" : "\x01\x01\x04"+t+"\x05\x01\x01"); return htmLawed._strtr(t, { '&': "\x03", '<' : "\x04", '>': "\x05" }); - // eof }, ENT: { 'fnof':'402', 'Alpha':'913', 'Beta':'914', 'Gamma':'915', 'Delta':'916', 'Epsilon':'917', 'Zeta':'918', 'Eta':'919', 'Theta':'920', 'Iota':'921', 'Kappa':'922', 'Lambda':'923', 'Mu':'924', 'Nu':'925', 'Xi':'926', 'Omicron':'927', 'Pi':'928', 'Rho':'929', 'Sigma':'931', 'Tau':'932', 'Upsilon':'933', 'Phi':'934', 'Chi':'935', 'Psi':'936', 'Omega':'937', 'alpha':'945', 'beta':'946', 'gamma':'947', 'delta':'948', 'epsilon':'949', 'zeta':'950', 'eta':'951', 'theta':'952', 'iota':'953', 'kappa':'954', 'lambda':'955', 'mu':'956', 'nu':'957', 'xi':'958', 'omicron':'959', 'pi':'960', 'rho':'961', 'sigmaf':'962', 'sigma':'963', 'tau':'964', 'upsilon':'965', 'phi':'966', 'chi':'967', 'psi':'968', 'omega':'969', 'thetasym':'977', 'upsih':'978', 'piv':'982', 'bull':'8226', 'hellip':'8230', 'prime':'8242', 'Prime':'8243', 'oline':'8254', 'frasl':'8260', 'weierp':'8472', 'image':'8465', 'real':'8476', 'trade':'8482', 'alefsym':'8501', 'larr':'8592', 'uarr':'8593', 'rarr':'8594', 'darr':'8595', 'harr':'8596', 'crarr':'8629', 'lArr':'8656', 'uArr':'8657', 'rArr':'8658', 'dArr':'8659', 'hArr':'8660', 'forall':'8704', 'part':'8706', 'exist':'8707', 'empty':'8709', 'nabla':'8711', 'isin':'8712', 'notin':'8713', 'ni':'8715', 'prod':'8719', 'sum':'8721', 'minus':'8722', 'lowast':'8727', 'radic':'8730', 'prop':'8733', 'infin':'8734', 'ang':'8736', 'and':'8743', 'or':'8744', 'cap':'8745', 'cup':'8746', 'int':'8747', 'there4':'8756', 'sim':'8764', 'cong':'8773', 'asymp':'8776', 'ne':'8800', 'equiv':'8801', 'le':'8804', 'ge':'8805', 'sub':'8834', 'sup':'8835', 'nsub':'8836', 'sube':'8838', 'supe':'8839', 'oplus':'8853', 'otimes':'8855', 'perp':'8869', 'sdot':'8901', 'lceil':'8968', 'rceil':'8969', 'lfloor':'8970', 'rfloor':'8971', 'lang':'9001', 'rang':'9002', 'loz':'9674', 'spades':'9824', 'clubs':'9827', 'hearts':'9829', 'diams':'9830', 'apos':'39', 'OElig':'338', 'oelig':'339', 'Scaron':'352', 'scaron':'353', 'Yuml':'376', 'circ':'710', 'tilde':'732', 'ensp':'8194', 'emsp':'8195', 'thinsp':'8201', 'zwnj':'8204', 'zwj':'8205', 'lrm':'8206', 'rlm':'8207', 'ndash':'8211', 'mdash':'8212', 'lsquo':'8216', 'rsquo':'8217', 'sbquo':'8218', 'ldquo':'8220', 'rdquo':'8221', 'bdquo':'8222', 'dagger':'8224', 'Dagger':'8225', 'permil':'8240', 'lsaquo':'8249', 'rsaquo':'8250', 'euro':'8364', 'nbsp':'160', 'iexcl':'161', 'cent':'162', 'pound':'163', 'curren':'164', 'yen':'165', 'brvbar':'166', 'sect':'167', 'uml':'168', 'copy':'169', 'ordf':'170', 'laquo':'171', 'not':'172', 'shy':'173', 'reg':'174', 'macr':'175', 'deg':'176', 'plusmn':'177', 'sup2':'178', 'sup3':'179', 'acute':'180', 'micro':'181', 'para':'182', 'middot':'183', 'cedil':'184', 'sup1':'185', 'ordm':'186', 'raquo':'187', 'frac14':'188', 'frac12':'189', 'frac34':'190', 'iquest':'191', 'Agrave':'192', 'Aacute':'193', 'Acirc':'194', 'Atilde':'195', 'Auml':'196', 'Aring':'197', 'AElig':'198', 'Ccedil':'199', 'Egrave':'200', 'Eacute':'201', 'Ecirc':'202', 'Euml':'203', 'Igrave':'204', 'Iacute':'205', 'Icirc':'206', 'Iuml':'207', 'ETH':'208', 'Ntilde':'209', 'Ograve':'210', 'Oacute':'211', 'Ocirc':'212', 'Otilde':'213', 'Ouml':'214', 'times':'215', 'Oslash':'216', 'Ugrave':'217', 'Uacute':'218', 'Ucirc':'219', 'Uuml':'220', 'Yacute':'221', 'THORN':'222', 'szlig':'223', 'agrave':'224', 'aacute':'225', 'acirc':'226', 'atilde':'227', 'auml':'228', 'aring':'229', 'aelig':'230', 'ccedil':'231', 'egrave':'232', 'eacute':'233', 'ecirc':'234', 'euml':'235', 'igrave':'236', 'iacute':'237', 'icirc':'238', 'iuml':'239', 'eth':'240', 'ntilde':'241', 'ograve':'242', 'oacute':'243', 'ocirc':'244', 'otilde':'245', 'ouml':'246', 'divide':'247', 'oslash':'248', 'ugrave':'249', 'uacute':'250', 'ucirc':'251', 'uuml':'252', 'yacute':'253', 'thorn':'254', 'yuml':'255' }, ENT_U: { 'quot':1, 'amp':1, 'lt':1, 'gt':1 }, @@ -516,7 +542,6 @@ var htmLawed = module.exports = return (C.and_mark ? "\x06" : '&')+"amp;#"+t+";"; } return (C.and_mark ? "\x06" : '&')+'#'+(((/^\d+$/.exec(t) && C.hexdec_entity < 2) || !C.hexdec_entity) ? n : 'x'+n.toString(16))+';'; - // eof }, hl_prot: function(p, c) { @@ -566,7 +591,6 @@ var htmLawed = module.exports = } } return b+p+a; - // eof }, hl_regex: function(p) { @@ -635,18 +659,7 @@ var htmLawed = module.exports = if (y[x].nomatch && !htmLawed.hl_regex(y[x].nomatch)) delete y[x].nomatch; } - var _y = 0; - for (_i in y) - { - _y = 1; - break; - } - var _n = 0; - for (_i in n) - { - _n = 1; - break; - } + var _y = this._nonempty(y), _n = this._nonempty(n); if (!_y && !_n) continue; w = w.substr(0, e); @@ -656,203 +669,1092 @@ var htmLawed = module.exports = if (v === '') continue; if (_y) - s[v] = y; + s[v] = s[v] ? { ...s[v], ...y } : y; if (_n) - s[v].n = n; + s[v].n = s[v].n ? { ...s[v].n, ...n } : n; } } return s; - // eof }, TAG: { - D: { 'applet':1, 'center':1, 'dir':1, 'embed':1, 'font':1, 'isindex':1, 'menu':1, 's':1, 'strike':1, 'u':1 }, // Deprecated - E: { 'area':1, 'br':1, 'col':1, 'embed':1, 'hr':1, 'img':1, 'input':1, 'isindex':1, 'param':1 }, // Empty ele - N: { // Ele-specific - 'abbr':{'td':1, 'th':1}, - 'accept-charset':{'form':1}, - 'accept':{'form':1, 'input':1}, - 'accesskey':{'a':1, 'area':1, 'button':1, 'input':1, 'label':1, 'legend':1, 'textarea':1}, - 'action':{'form':1}, - 'align':{ - 'caption':1, 'embed':1, 'applet':1, 'iframe':1, 'img':1, 'input':1, 'object':1, 'legend':1, 'table':1, - 'hr':1, 'div':1, 'h1':1, 'h2':1, 'h3':1, 'h4':1, 'h5':1, 'h6':1, 'p':1, 'col':1, 'colgroup':1, 'tbody':1, - 'td':1, 'tfoot':1, 'th':1, 'thead':1, 'tr':1 + D: { 'acronym':1, 'applet':1, 'big':1, 'center':1, 'dir':1, 'font':1, 'isindex':1, 's':1, 'strike':1, 'tt':1 }, // Deprecated + E: { 'area':1, 'br':1, 'col':1, 'command':1, 'embed':1, 'hr':1, 'img':1, 'input':1, 'isindex':1, 'keygen':1, 'link':1, 'meta':1, 'param':1, 'source':1, 'track':1, 'wbr':1 }, // Empty ele + // Ele-specific + N: { + "abbr": { + "td": 1, + "th": 1 }, - 'allowfullscreen':{'iframe':1}, - 'alt':{'applet':1, 'area':1, 'img':1, 'input':1}, - 'archive':{'applet':1, 'object':1}, - 'axis':{'td':1, 'th':1}, - 'bgcolor':{'embed':1, 'table':1, 'tr':1, 'td':1, 'th':1}, - 'border':{'table':1, 'img':1, 'object':1}, - 'bordercolor':{'table':1, 'td':1, 'tr':1}, - 'cellpadding':{'table':1}, - 'cellspacing':{'table':1}, - 'char':{'col':1, 'colgroup':1, 'tbody':1, 'td':1, 'tfoot':1, 'th':1, 'thead':1, 'tr':1}, - 'charoff':{'col':1, 'colgroup':1, 'tbody':1, 'td':1, 'tfoot':1, 'th':1, 'thead':1, 'tr':1}, - 'charset':{'a':1, 'script':1}, - 'checked':{'input':1}, - 'cite':{'blockquote':1, 'q':1, 'del':1, 'ins':1}, - 'classid':{'object':1}, - 'clear':{'br':1}, - 'code':{'applet':1}, - 'codebase':{'object':1, 'applet':1}, - 'codetype':{'object':1}, - 'color':{'font':1}, - 'cols':{'textarea':1}, - 'colspan':{'td':1, 'th':1}, - 'compact':{'dir':1, 'dl':1, 'menu':1, 'ol':1, 'ul':1}, - 'coords':{'area':1, 'a':1}, - 'data':{'object':1}, - 'datetime':{'del':1, 'ins':1}, - 'declare':{'object':1}, - 'defer':{'script':1}, - 'dir':{'bdo':1}, - 'disabled':{'button':1, 'input':1, 'optgroup':1, 'option':1, 'select':1, 'textarea':1}, - 'enctype':{'form':1}, - 'face':{'font':1}, - 'flashvars':{'embed':1}, - 'for':{'label':1}, - 'frame':{'table':1}, - 'frameborder':{'iframe':1}, - 'headers':{'td':1, 'th':1}, - 'height':{'embed':1, 'iframe':1, 'td':1, 'th':1, 'img':1, 'object':1, 'applet':1}, - 'href':{'a':1, 'area':1}, - 'hreflang':{'a':1}, - 'hspace':{'applet':1, 'img':1, 'object':1}, - 'ismap':{'img':1, 'input':1}, - 'label':{'option':1, 'optgroup':1}, - 'language':{'script':1}, - 'longdesc':{'img':1, 'iframe':1}, - 'marginheight':{'iframe':1}, - 'marginwidth':{'iframe':1}, - 'maxlength':{'input':1}, - 'method':{'form':1}, - 'model':{'embed':1}, - 'multiple':{'select':1}, - 'name':{ - 'button':1, 'embed':1, 'textarea':1, 'applet':1, 'select':1, 'form':1, 'iframe':1, 'img':1, - 'a':1, 'input':1, 'object':1, 'map':1, 'param':1 + "accept": { + "form": 1, + "input": 1 }, - 'nohref':{'area':1}, - 'noshade':{'hr':1}, - 'nowrap':{'td':1, 'th':1}, - 'object':{'applet':1}, - 'onblur':{'a':1, 'area':1, 'button':1, 'input':1, 'label':1, 'select':1, 'textarea':1}, - 'onchange':{'input':1, 'select':1, 'textarea':1}, - 'onfocus':{'a':1, 'area':1, 'button':1, 'input':1, 'label':1, 'select':1, 'textarea':1}, - 'onreset':{'form':1}, - 'onselect':{'input':1, 'textarea':1}, - 'onsubmit':{'form':1}, - 'pluginspage':{'embed':1}, - 'pluginurl':{'embed':1}, - 'prompt':{'isindex':1}, - 'readonly':{'textarea':1, 'input':1}, - 'rel':{'a':1}, - 'rev':{'a':1}, - 'rows':{'textarea':1}, - 'rowspan':{'td':1, 'th':1}, - 'rules':{'table':1}, - 'scope':{'td':1, 'th':1}, - 'scrolling':{'iframe':1}, - 'selected':{'option':1}, - 'shape':{'area':1, 'a':1}, - 'size':{'hr':1, 'font':1, 'input':1, 'select':1}, - 'span':{'col':1, 'colgroup':1}, - 'src':{'embed':1, 'script':1, 'input':1, 'iframe':1, 'img':1}, - 'standby':{'object':1}, - 'start':{'ol':1}, - 'summary':{'table':1}, - 'tabindex':{'a':1, 'area':1, 'button':1, 'input':1, 'object':1, 'select':1, 'textarea':1}, // FIXME not specific! allowed everywhere - 'target':{'a':1, 'area':1, 'form':1}, - 'type':{'a':1, 'embed':1, 'object':1, 'param':1, 'script':1, 'input':1, 'li':1, 'ol':1, 'ul':1, 'button':1}, - 'usemap':{'img':1, 'input':1, 'object':1}, - 'valign':{'col':1, 'colgroup':1, 'tbody':1, 'td':1, 'tfoot':1, 'th':1, 'thead':1, 'tr':1}, - 'value':{'input':1, 'option':1, 'param':1, 'button':1, 'li':1}, - 'valuetype':{'param':1}, - 'vspace':{'applet':1, 'img':1, 'object':1}, - 'width':{'embed':1, 'hr':1, 'iframe':1, 'img':1, 'object':1, 'table':1, 'td':1, 'th':1, 'applet':1, 'col':1, 'colgroup':1, 'pre':1}, - 'wmode':{'embed':1}, - 'xml:space':{'pre':1, 'script':1, 'style':1} + "accept-charset": { + "form": 1 + }, + "action": { + "form": 1 + }, + "align": { + "applet": 1, + "caption": 1, + "col": 1, + "colgroup": 1, + "div": 1, + "embed": 1, + "h1": 1, + "h2": 1, + "h3": 1, + "h4": 1, + "h5": 1, + "h6": 1, + "hr": 1, + "iframe": 1, + "img": 1, + "input": 1, + "legend": 1, + "object": 1, + "p": 1, + "table": 1, + "tbody": 1, + "td": 1, + "tfoot": 1, + "th": 1, + "thead": 1, + "tr": 1 + }, + "allowfullscreen": { + "iframe": 1 + }, + "alt": { + "applet": 1, + "area": 1, + "img": 1, + "input": 1 + }, + "archive": { + "applet": 1, + "object": 1 + }, + "async": { + "script": 1 + }, + "autocomplete": { + "form": 1, + "input": 1 + }, + "autofocus": { + "button": 1, + "input": 1, + "keygen": 1, + "select": 1, + "textarea": 1 + }, + "autoplay": { + "audio": 1, + "video": 1 + }, + "axis": { + "td": 1, + "th": 1 + }, + "bgcolor": { + "embed": 1, + "table": 1, + "td": 1, + "th": 1, + "tr": 1 + }, + "border": { + "img": 1, + "object": 1, + "table": 1 + }, + "bordercolor": { + "table": 1, + "td": 1, + "tr": 1 + }, + "cellpadding": { + "table": 1 + }, + "cellspacing": { + "table": 1 + }, + "challenge": { + "keygen": 1 + }, + "char": { + "col": 1, + "colgroup": 1, + "tbody": 1, + "td": 1, + "tfoot": 1, + "th": 1, + "thead": 1, + "tr": 1 + }, + "charoff": { + "col": 1, + "colgroup": 1, + "tbody": 1, + "td": 1, + "tfoot": 1, + "th": 1, + "thead": 1, + "tr": 1 + }, + "charset": { + "a": 1, + "script": 1 + }, + "checked": { + "command": 1, + "input": 1 + }, + "cite": { + "blockquote": 1, + "del": 1, + "ins": 1, + "q": 1 + }, + "classid": { + "object": 1 + }, + "clear": { + "br": 1 + }, + "code": { + "applet": 1 + }, + "codebase": { + "applet": 1, + "object": 1 + }, + "codetype": { + "object": 1 + }, + "color": { + "font": 1 + }, + "cols": { + "textarea": 1 + }, + "colspan": { + "td": 1, + "th": 1 + }, + "compact": { + "dir": 1, + "dl": 1, + "menu": 1, + "ol": 1, + "ul": 1 + }, + "content": { + "meta": 1 + }, + "controls": { + "audio": 1, + "video": 1 + }, + "coords": { + "a": 1, + "area": 1 + }, + "crossorigin": { + "img": 1 + }, + "data": { + "object": 1 + }, + "datetime": { + "del": 1, + "ins": 1, + "time": 1 + }, + "declare": { + "object": 1 + }, + "default": { + "track": 1 + }, + "defer": { + "script": 1 + }, + "dirname": { + "input": 1, + "textarea": 1 + }, + "disabled": { + "button": 1, + "command": 1, + "fieldset": 1, + "input": 1, + "keygen": 1, + "optgroup": 1, + "option": 1, + "select": 1, + "textarea": 1 + }, + "download": { + "a": 1 + }, + "enctype": { + "form": 1 + }, + "face": { + "font": 1 + }, + "flashvars": { + "embed": 1 + }, + "for": { + "label": 1, + "output": 1 + }, + "form": { + "button": 1, + "fieldset": 1, + "input": 1, + "keygen": 1, + "label": 1, + "object": 1, + "output": 1, + "select": 1, + "textarea": 1 + }, + "formaction": { + "button": 1, + "input": 1 + }, + "formenctype": { + "button": 1, + "input": 1 + }, + "formmethod": { + "button": 1, + "input": 1 + }, + "formnovalidate": { + "button": 1, + "input": 1 + }, + "formtarget": { + "button": 1, + "input": 1 + }, + "frame": { + "table": 1 + }, + "frameborder": { + "iframe": 1 + }, + "headers": { + "td": 1, + "th": 1 + }, + "height": { + "applet": 1, + "canvas": 1, + "embed": 1, + "iframe": 1, + "img": 1, + "input": 1, + "object": 1, + "td": 1, + "th": 1, + "video": 1 + }, + "high": { + "meter": 1 + }, + "href": { + "a": 1, + "area": 1, + "link": 1 + }, + "hreflang": { + "a": 1, + "area": 1, + "link": 1 + }, + "hspace": { + "applet": 1, + "embed": 1, + "img": 1, + "object": 1 + }, + "icon": { + "command": 1 + }, + "ismap": { + "img": 1, + "input": 1 + }, + "keyparams": { + "keygen": 1 + }, + "keytype": { + "keygen": 1 + }, + "kind": { + "track": 1 + }, + "label": { + "command": 1, + "menu": 1, + "option": 1, + "optgroup": 1, + "track": 1 + }, + "language": { + "script": 1 + }, + "list": { + "input": 1 + }, + "longdesc": { + "img": 1, + "iframe": 1 + }, + "loop": { + "audio": 1, + "video": 1 + }, + "low": { + "meter": 1 + }, + "marginheight": { + "iframe": 1 + }, + "marginwidth": { + "iframe": 1 + }, + "max": { + "input": 1, + "meter": 1, + "progress": 1 + }, + "maxlength": { + "input": 1, + "textarea": 1 + }, + "media": { + "a": 1, + "area": 1, + "link": 1, + "source": 1, + "style": 1 + }, + "mediagroup": { + "audio": 1, + "video": 1 + }, + "method": { + "form": 1 + }, + "min": { + "input": 1, + "meter": 1 + }, + "model": { + "embed": 1 + }, + "multiple": { + "input": 1, + "select": 1 + }, + "muted": { + "audio": 1, + "video": 1 + }, + "name": { + "a": 1, + "applet": 1, + "button": 1, + "embed": 1, + "fieldset": 1, + "form": 1, + "iframe": 1, + "img": 1, + "input": 1, + "keygen": 1, + "map": 1, + "object": 1, + "output": 1, + "param": 1, + "select": 1, + "textarea": 1 + }, + "nohref": { + "area": 1 + }, + "noshade": { + "hr": 1 + }, + "novalidate": { + "form": 1 + }, + "nowrap": { + "td": 1, + "th": 1 + }, + "object": { + "applet": 1 + }, + "open": { + "details": 1 + }, + "optimum": { + "meter": 1 + }, + "pattern": { + "input": 1 + }, + "ping": { + "a": 1, + "area": 1 + }, + "placeholder": { + "input": 1, + "textarea": 1 + }, + "pluginspage": { + "embed": 1 + }, + "pluginurl": { + "embed": 1 + }, + "poster": { + "video": 1 + }, + "pqg": { + "keygen": 1 + }, + "preload": { + "audio": 1, + "video": 1 + }, + "prompt": { + "isindex": 1 + }, + "pubdate": { + "time": 1 + }, + "radiogroup": { + "command": 1 + }, + "readonly": { + "input": 1, + "textarea": 1 + }, + "rel": { + "a": 1, + "area": 1, + "link": 1 + }, + "required": { + "input": 1, + "select": 1, + "textarea": 1 + }, + "rev": { + "a": 1 + }, + "reversed": { + "ol": 1 + }, + "rows": { + "textarea": 1 + }, + "rowspan": { + "td": 1, + "th": 1 + }, + "rules": { + "table": 1 + }, + "sandbox": { + "iframe": 1 + }, + "scope": { + "td": 1, + "th": 1 + }, + "scoped": { + "style": 1 + }, + "scrolling": { + "iframe": 1 + }, + "seamless": { + "iframe": 1 + }, + "selected": { + "option": 1 + }, + "shape": { + "a": 1, + "area": 1 + }, + "size": { + "font": 1, + "hr": 1, + "input": 1, + "select": 1 + }, + "sizes": { + "link": 1 + }, + "span": { + "col": 1, + "colgroup": 1 + }, + "src": { + "audio": 1, + "embed": 1, + "iframe": 1, + "img": 1, + "input": 1, + "script": 1, + "source": 1, + "track": 1, + "video": 1 + }, + "srcdoc": { + "iframe": 1 + }, + "srclang": { + "track": 1 + }, + "srcset": { + "img": 1 + }, + "standby": { + "object": 1 + }, + "start": { + "ol": 1 + }, + "step": { + "input": 1 + }, + "summary": { + "table": 1 + }, + "target": { + "a": 1, + "area": 1, + "form": 1 + }, + "type": { + "a": 1, + "area": 1, + "button": 1, + "command": 1, + "embed": 1, + "input": 1, + "li": 1, + "link": 1, + "menu": 1, + "object": 1, + "ol": 1, + "param": 1, + "script": 1, + "source": 1, + "style": 1, + "ul": 1 + }, + "typemustmatch": { + "object": 1 + }, + "usemap": { + "img": 1, + "input": 1, + "object": 1 + }, + "valign": { + "col": 1, + "colgroup": 1, + "tbody": 1, + "td": 1, + "tfoot": 1, + "th": 1, + "thead": 1, + "tr": 1 + }, + "value": { + "button": 1, + "data": 1, + "input": 1, + "li": 1, + "meter": 1, + "option": 1, + "param": 1, + "progress": 1 + }, + "valuetype": { + "param": 1 + }, + "vspace": { + "applet": 1, + "embed": 1, + "img": 1, + "object": 1 + }, + "width": { + "applet": 1, + "canvas": 1, + "col": 1, + "colgroup": 1, + "embed": 1, + "hr": 1, + "iframe": 1, + "img": 1, + "input": 1, + "object": 1, + "pre": 1, + "table": 1, + "td": 1, + "th": 1, + "video": 1 + }, + "wmode": { + "embed": 1 + }, + "wrap": { + "textarea": 1 + } }, - NE: { // Empty - 'allowfullscreen':1, 'checked':1, 'compact':1, 'declare':1, 'defer':1, 'disabled':1, - 'ismap':1, 'multiple':1, 'nohref':1, 'noresize':1, 'noshade':1, 'nowrap':1, 'readonly':1, 'selected':1 + // ARIA + NA: { + "aria-activedescendant": 1, + "aria-atomic": 1, + "aria-autocomplete": 1, + "aria-busy": 1, + "aria-checked": 1, + "aria-controls": 1, + "aria-describedby": 1, + "aria-disabled": 1, + "aria-dropeffect": 1, + "aria-expanded": 1, + "aria-flowto": 1, + "aria-grabbed": 1, + "aria-haspopup": 1, + "aria-hidden": 1, + "aria-invalid": 1, + "aria-label": 1, + "aria-labelledby": 1, + "aria-level": 1, + "aria-live": 1, + "aria-multiline": 1, + "aria-multiselectable": 1, + "aria-orientation": 1, + "aria-owns": 1, + "aria-posinset": 1, + "aria-pressed": 1, + "aria-readonly": 1, + "aria-relevant": 1, + "aria-required": 1, + "aria-selected": 1, + "aria-setsize": 1, + "aria-sort": 1, + "aria-valuemax": 1, + "aria-valuemin": 1, + "aria-valuenow": 1, + "aria-valuetext": 1 }, - NP: { // Need scheme check; excludes style, on* & src - 'action':1, 'cite':1, 'classid':1, 'codebase':1, 'data':1, 'href':1, - 'longdesc':1, 'model':1, 'pluginspage':1, 'pluginurl':1, 'usemap':1 + // NE = Empty + NE: { + "allowfullscreen": 1, + "checkbox": 1, + "checked": 1, + "command": 1, + "compact": 1, + "declare": 1, + "defer": 1, + "default": 1, + "disabled": 1, + "hidden": 1, + "inert": 1, + "ismap": 1, + "itemscope": 1, + "multiple": 1, + "nohref": 1, + "noresize": 1, + "noshade": 1, + "nowrap": 1, + "open": 1, + "radio": 1, + "readonly": 1, + "required": 1, + "reversed": 1, + "selected": 1 }, - NU: { // Univ & exceptions - 'class':{'param':1, 'script':1}, - 'dir':{'applet':1, 'bdo':1, 'br':1, 'iframe':1, 'param':1, 'script':1}, - 'id':{'script':1}, - 'lang':{'applet':1, 'br':1, 'iframe':1, 'param':1, 'script':1}, - 'xml:lang':{'applet':1, 'br':1, 'iframe':1, 'param':1, 'script':1}, - 'onclick':{'applet':1, 'bdo':1, 'br':1, 'font':1, 'iframe':1, 'isindex':1, 'param':1, 'script':1}, - 'ondblclick':{'applet':1, 'bdo':1, 'br':1, 'font':1, 'iframe':1, 'isindex':1, 'param':1, 'script':1}, - 'onkeydown':{'applet':1, 'bdo':1, 'br':1, 'font':1, 'iframe':1, 'isindex':1, 'param':1, 'script':1}, - 'onkeypress':{'applet':1, 'bdo':1, 'br':1, 'font':1, 'iframe':1, 'isindex':1, 'param':1, 'script':1}, - 'onkeyup':{'applet':1, 'bdo':1, 'br':1, 'font':1, 'iframe':1, 'isindex':1, 'param':1, 'script':1}, - 'onmousedown':{'applet':1, 'bdo':1, 'br':1, 'font':1, 'iframe':1, 'isindex':1, 'param':1, 'script':1}, - 'onmousemove':{'applet':1, 'bdo':1, 'br':1, 'font':1, 'iframe':1, 'isindex':1, 'param':1, 'script':1}, - 'onmouseout':{'applet':1, 'bdo':1, 'br':1, 'font':1, 'iframe':1, 'isindex':1, 'param':1, 'script':1}, - 'onmouseover':{'applet':1, 'bdo':1, 'br':1, 'font':1, 'iframe':1, 'isindex':1, 'param':1, 'script':1}, - 'onmouseup':{'applet':1, 'bdo':1, 'br':1, 'font':1, 'iframe':1, 'isindex':1, 'param':1, 'script':1}, - 'style':{'param':1, 'script':1}, - 'title':{'param':1, 'script':1} + // NO = Event + NO: { + "onabort": 1, + "onblur": 1, + "oncanplay": 1, + "oncanplaythrough": 1, + "onchange": 1, + "onclick": 1, + "oncontextmenu": 1, + "oncopy": 1, + "oncuechange": 1, + "oncut": 1, + "ondblclick": 1, + "ondrag": 1, + "ondragend": 1, + "ondragenter": 1, + "ondragleave": 1, + "ondragover": 1, + "ondragstart": 1, + "ondrop": 1, + "ondurationchange": 1, + "onemptied": 1, + "onended": 1, + "onerror": 1, + "onfocus": 1, + "onformchange": 1, + "onforminput": 1, + "oninput": 1, + "oninvalid": 1, + "onkeydown": 1, + "onkeypress": 1, + "onkeyup": 1, + "onload": 1, + "onloadeddata": 1, + "onloadedmetadata": 1, + "onloadstart": 1, + "onlostpointercapture": 1, + "onmousedown": 1, + "onmousemove": 1, + "onmouseout": 1, + "onmouseover": 1, + "onmouseup": 1, + "onmousewheel": 1, + "onpaste": 1, + "onpause": 1, + "onplay": 1, + "onplaying": 1, + "onpointercancel": 1, + "ongotpointercapture": 1, + "onpointerdown": 1, + "onpointerenter": 1, + "onpointerleave": 1, + "onpointermove": 1, + "onpointerout": 1, + "onpointerover": 1, + "onpointerup": 1, + "onprogress": 1, + "onratechange": 1, + "onreadystatechange": 1, + "onreset": 1, + "onsearch": 1, + "onscroll": 1, + "onseeked": 1, + "onseeking": 1, + "onselect": 1, + "onshow": 1, + "onstalled": 1, + "onsubmit": 1, + "onsuspend": 1, + "ontimeupdate": 1, + "ontoggle": 1, + "ontouchcancel": 1, + "ontouchend": 1, + "ontouchmove": 1, + "ontouchstart": 1, + "onvolumechange": 1, + "onwaiting": 1, + "onwheel": 1 + }, + // NP = Need scheme check; excludes style, on* & src + NP: { + "action": 1, + "cite": 1, + "classid": 1, + "codebase": 1, + "data": 1, + "href": 1, + "itemtype": 1, + "longdesc": 1, + "model": 1, + "pluginspage": 1, + "pluginurl": 1, + "src": 1, + "srcset": 1, + "usemap": 1 + }, + // NU = Univ & exceptions + NU: { + "accesskey": 1, + "class": 1, + "contenteditable": 1, + "contextmenu": 1, + "dir": 1, + "draggable": 1, + "dropzone": 1, + "hidden": 1, + "id": 1, + "inert": 1, + "itemid": 1, + "itemprop": 1, + "itemref": 1, + "itemscope": 1, + "itemtype": 1, + "lang": 1, + "role": 1, + "spellcheck": 1, + "style": 1, + "tabindex": 1, + "title": 1, + "translate": 1, + "xmlns": 1, + "xml:base": 1, + "xml:lang": 1, + "xml:space": 1 }, // predef attr vals for $eAL & $aNE ele NL: { - 'all':1, 'baseline':1, 'bottom':1, 'button':1, 'center':1, 'char':1, 'checkbox':1, 'circle':1, 'col':1, - 'colgroup':1, 'cols':1, 'data':1, 'default':1, 'file':1, 'get':1, 'groups':1, 'hidden':1, 'image':1, - 'justify':1, 'left':1, 'ltr':1, 'middle':1, 'none':1, 'object':1, 'password':1, 'poly':1, 'post':1, - 'preserve':1, 'radio':1, 'rect':1, 'ref':1, 'reset':1, 'right':1, 'row':1, 'rowgroup':1, - 'rows':1, 'rtl':1, 'submit':1, 'text':1, 'top':1 + "all": 1, + "auto": 1, + "baseline": 1, + "bottom": 1, + "button": 1, + "captions": 1, + "center": 1, + "chapters": 1, + "char": 1, + "checkbox": 1, + "circle": 1, + "col": 1, + "colgroup": 1, + "color": 1, + "cols": 1, + "data": 1, + "date": 1, + "datetime": 1, + "datetime-local": 1, + "default": 1, + "descriptions": 1, + "email": 1, + "file": 1, + "get": 1, + "groups": 1, + "hidden": 1, + "image": 1, + "justify": 1, + "left": 1, + "ltr": 1, + "metadata": 1, + "middle": 1, + "month": 1, + "none": 1, + "number": 1, + "object": 1, + "password": 1, + "poly": 1, + "post": 1, + "preserve": 1, + "radio": 1, + "range": 1, + "rect": 1, + "ref": 1, + "reset": 1, + "right": 1, + "row": 1, + "rowgroup": 1, + "rows": 1, + "rtl": 1, + "search": 1, + "submit": 1, + "subtitles": 1, + "tel": 1, + "text": 1, + "time": 1, + "top": 1, + "url": 1, + "week": 1 }, AL: { - 'a':1, 'area':1, 'bdo':1, 'button':1, 'col':1, 'form':1, 'img':1, 'input':1, 'object':1, 'optgroup':1, - 'option':1, 'param':1, 'script':1, 'select':1, 'table':1, 'td':1, 'tfoot':1, 'th':1, 'thead':1, 'tr':1, 'xml:space':1 + "a": 1, + "area": 1, + "bdo": 1, + "button": 1, + "col": 1, + "fieldset": 1, + "form": 1, + "img": 1, + "input": 1, + "object": 1, + "ol": 1, + "optgroup": 1, + "option": 1, + "param": 1, + "script": 1, + "select": 1, + "table": 1, + "td": 1, + "textarea": 1, + "tfoot": 1, + "th": 1, + "thead": 1, + "tr": 1, + "track": 1, + "xml:space": 1 }, // dep attr:applicable ele ND: { - 'align':{ - 'caption':1, 'div':1, 'h1':1, 'h2':1, 'h3':1, 'h4':1, 'h5':1, 'h6':1, 'hr':1, 'img':1, - 'input':1, 'legend':1, 'object':1, 'p':1, 'table':1 + "align": { + "caption": 1, + "div": 1, + "h1": 1, + "h2": 1, + "h3": 1, + "h4": 1, + "h5": 1, + "h6": 1, + "hr": 1, + "img": 1, + "input": 1, + "legend": 1, + "object": 1, + "p": 1, + "table": 1 }, - 'bgcolor':{'table':1, 'td':1, 'th':1, 'tr':1}, - 'border':{'img':1, 'object':1}, - 'bordercolor':{'table':1, 'td':1, 'tr':1}, - 'clear':{'br':1}, - 'compact':{'dl':1, 'ol':1, 'ul':1}, - 'height':{'td':1, 'th':1}, - 'hspace':{'img':1, 'object':1}, - 'language':{'script':1}, - 'name':{'a':1, 'form':1, 'iframe':1, 'img':1, 'map':1}, - 'noshade':{'hr':1}, - 'nowrap':{'td':1, 'th':1}, - 'size':{'hr':1}, - 'start':{'ol':1}, - 'type':{'li':1, 'ol':1, 'ul':1}, - 'value':{'li':1}, - 'vspace':{'img':1, 'object':1}, - 'width':{'hr':1, 'pre':1, 'td':1, 'th':1} + "bgcolor": { + "table": 1, + "td": 1, + "th": 1, + "tr": 1 + }, + "border": { + "object": 1 + }, + "bordercolor": { + "table": 1, + "td": 1, + "tr": 1 + }, + "cellspacing": { + "table": 1 + }, + "clear": { + "br": 1 + }, + "compact": { + "dl": 1, + "ol": 1, + "ul": 1 + }, + "height": { + "td": 1, + "th": 1 + }, + "hspace": { + "img": 1, + "object": 1 + }, + "language": { + "script": 1 + }, + "name": { + "a": 1, + "form": 1, + "iframe": 1, + "img": 1, + "map": 1 + }, + "noshade": { + "hr": 1 + }, + "nowrap": { + "td": 1, + "th": 1 + }, + "size": { + "hr": 1 + }, + "vspace": { + "img": 1, + "object": 1 + }, + "width": { + "hr": 1, + "pre": 1, + "table": 1, + "td": 1, + "th": 1 + } }, AD: { - 'a':1, 'br':1, 'caption':1, 'div':1, 'dl':1, 'form':1, 'h1':1, 'h2':1, 'h3':1, 'h4':1, 'h5':1, - 'h6':1, 'hr':1, 'iframe':1, 'img':1, 'input':1, 'legend':1, 'li':1, 'map':1, 'object':1, 'ol':1, - 'p':1, 'pre':1, 'script':1, 'table':1, 'td':1, 'th':1, 'tr':1, 'ul':1 + "a": 1, + "br": 1, + "caption": 1, + "div": 1, + "dl": 1, + "form": 1, + "h1": 1, + "h2": 1, + "h3": 1, + "h4": 1, + "h5": 1, + "h6": 1, + "hr": 1, + "iframe": 1, + "img": 1, + "input": 1, + "legend": 1, + "map": 1, + "object": 1, + "ol": 1, + "p": 1, + "pre": 1, + "script": 1, + "table": 1, + "td": 1, + "th": 1, + "tr": 1, + "ul": 1 + }, + // rqd attr + AR: { + "area": { + "alt": "area" + }, + "bdo": { + "dir": "ltr" + }, + "command": { + "label": "" + }, + "form": { + "action": "" + }, + "img": { + "src": "", + "alt": "image" + }, + "map": { + "name": "" + }, + "optgroup": { + "label": "" + }, + "param": { + "name": "" + }, + "style": { + "scoped": "" + }, + "textarea": { + "rows": "10", + "cols": "50" + } }, - AR: { // rqd attr - 'area':{'alt':'area'}, - 'bdo':{'dir':'ltr'}, - 'form':{'action':''}, - 'img':{'src':'', 'alt':'image'}, - 'map':{'name':''}, - 'optgroup':{'label':''}, - 'param':{'name':''}, - 'script':{'type':'text/javascript'}, - 'textarea':{'rows':'10', 'cols':'50'} - } }, STYLE_ENT: { ' ':' ', ' ':' ', @@ -935,7 +1837,7 @@ var htmLawed = module.exports = switch (mode) { case 0: // Name - m = /^[a-zA-Z][\-a-zA-Z:]+/.exec(a); + m = /^[a-zA-Z][^\s=/]+/.exec(a); if (m) { nm = m[0].toLowerCase(); @@ -990,8 +1892,12 @@ var htmLawed = module.exports = { v = aA[k]; if (((C.deny_attribute['*'] ? C.deny_attribute[k] : !C.deny_attribute[k]) && - (TAG.N[k] && TAG.N[k][e] || (TAG.NU[k] && !TAG.NU[k][e])) && - (!rl.n || !rl.n[k] && !rl.n['*'])) || rl[k]) + (TAG.N[k] && TAG.N[k][e] || + TAG.NU[k] || + TAG.NO[k] && !C.deny_attribute['on*'] || + TAG.NA[k] && !C.deny_attribute['aria*'] || + !C.deny_attribute['data*'] && /data-((?!xml)[^:]+$)/.exec(k) + ) && (!rl.n || !rl.n[k] && !rl.n['*'])) || rl[k]) { if (TAG.NE[k]) v = k; @@ -1011,11 +1917,26 @@ var htmLawed = module.exports = }); v = !C.css_expression ? v.replace(/\\\S|(\/|(%2f))(\*|(%2a))/gi, ' ').replace(/expression/gi, ' ') : v; } - else if (TAG.NP[k] || k.indexOf('src') >= 0 || k[0] == 'o') + else if (TAG.NP[k] || TAG.NO[k]) { - // double-quoted char is soft-hyphen; appears here as "­" or hyphen or something else depending on viewing software - v = (v.indexOf('&') >= 0 ? v.replace(/­|­|­/g, ' ') : v).replace(/­/g, ' '); - v = htmLawed.hl_prot(v, k); + // double-quoted char: soft-hyphen; appears here as "\xAD" or hyphen or something else depending on viewing software + v = (v.indexOf('&') >= 0 ? v.replace(/­|­|­/g, ' ') : v).replace(/\xAD/g, ' '); + if (k == 'srcset') + { + v = v.trim().split(/\s*,\s*/).map(v1 => ( + v1.split(/\s+/, 2).map((v2, k2) => ( + k2 == 0 ? htmLawed.hl_prot(v2, k) : v2.trim() + )).join(' ') + )).join(', '); + } + if (k == 'itemtype') + { + v = v.trim().split(/\s+/).map(v1 => htmLawed.hl_prot(v1, k)).join(' '); + } + else + { + v = htmLawed.hl_prot(v, k); + } if (k == 'href') { // X-spam @@ -1061,7 +1982,7 @@ var htmLawed = module.exports = a[k] = TAG.AR[e][k] || k; } - // depr attrs + // depr attr if (depTr) { var c = []; @@ -1070,6 +1991,7 @@ var htmLawed = module.exports = v = a[k]; if (k == 'style' || !TAG.ND[k] || !TAG.ND[k][e]) continue; + v = v.replace(/(\\|:|;|&#)/g, ''); if (k == 'align') { delete a[k]; @@ -1086,6 +2008,8 @@ var htmLawed = module.exports = c.push('border: '+v+'px'); else if (k == 'bordercolor') c.push('border-color: '+v); + else if (k == 'cellspacing') + c.push('border-spacing: '+v+'px'); else if (k == 'clear') c.push('clear: '+(v != 'all' ? v : 'both')); else if (k == 'compact') @@ -1098,7 +2022,7 @@ var htmLawed = module.exports = a.type = 'text/'+v.toLowerCase(); else if (k == 'name') { - if (!a.id && /^[a-zA-Z][a-zA-Z\d\.:_\-]*$/.exec(v)) + if (!a.id && !/\W/.exec(v)) a.id = v; if (!(C.no_deprecated_attr == 2 || (e != 'a' && e != 'map'))) { @@ -1112,15 +2036,6 @@ var htmLawed = module.exports = c.push('white-space: nowrap'); else if (k == 'size') c.push('size: '+v+'px'); - else if (k == 'start' || k == 'value') - { - // just delete - } - else if (k == 'type') - { - var ol_type = { 'i':'lower-roman', 'I':'upper-roman', 'a':'lower-latin', 'A':'upper-latin', '1':'decimal' }; - c.push('list-style-type: '+(ol_type[v] || 'decimal')); - } else if (k == 'vspace') c.push('margin-top: '+v+'px; margin-bottom: '+v+'px'); else @@ -1137,7 +2052,7 @@ var htmLawed = module.exports = // unique ID if (C.unique_ids && a.id) { - if (!/^[A-Za-z][A-Za-z0-9_\-\.:]*$/.exec(a.id) || + if (/\s/.exec(a.id) || htmLawed.hl_Ids[a.id] && C.unique_ids == 1) delete a.id; else @@ -1169,7 +2084,6 @@ var htmLawed = module.exports = return '<'+e+aA+(TAG.E[e] ? ' /' : '')+'>'; } return C.hook_tag(e, a); - // eof }, hl_tag2: function(e, a, t) { @@ -1178,12 +2092,16 @@ var htmLawed = module.exports = // transform tag if (e == 'center') return [ 'div', a, 'text-align: center;' ]; - else if (e == 'dir' || e == 'menu') + else if (e == 'acronym') + return [ 'abbr', a, '' ]; + else if (e == 'dir') return [ 'ul', a, '' ]; + else if (e == 'big') + return [ 'span', a, 'font-size: larger;' ]; else if (e == 's' || e == 'strike') return [ 'span', a, 'text-decoration: line-through;' ]; - else if (e == 'u') - return [ 'span', a, 'text-decoration: underline;' ]; + else if (e == 'tt') + return [ 'code', a, '' ]; else if (e == 'font') { var a2 = ''; @@ -1207,34 +2125,28 @@ var htmLawed = module.exports = if (t == 2) return [ 0, a, 0 ]; return [ e, a, '' ]; - // eof }, TIDY: { a: {'br':1}, - b: {'button':1, 'input':1, 'option':1, 'param':1}, - c: { - 'caption':1, 'dd':1, 'dt':1, 'h1':1, 'h2':1, 'h3':1, 'h4':1, 'h5':1, 'h6':1, 'isindex':1, - 'label':1, 'legend':1, 'li':1, 'object':1, 'p':1, 'pre':1, 'td':1, 'textarea':1, 'th':1 - }, - d: { - 'address':1, 'blockquote':1, 'center':1, 'colgroup':1, 'dir':1, 'div':1, 'dl':1, 'fieldset':1, - 'form':1, 'hr':1, 'iframe':1, 'map':1, 'menu':1, 'noscript':1, 'ol':1, 'optgroup':1, 'rbc':1, - 'rtc':1, 'ruby':1, 'script':1, 'select':1, 'table':1, 'tbody':1, 'tfoot':1, 'thead':1, 'tr':1, 'ul':1 - } + b: {'button':1, 'command':1, 'input':1, 'option':1, 'param':1, 'track':1}, + c: {'audio':1, 'canvas':1, 'caption':1, 'dd':1, 'dt':1, 'figcaption':1, 'h1':1, 'h2':1, 'h3':1, 'h4':1, 'h5':1, 'h6':1, 'isindex':1, 'label':1, 'legend':1, 'li':1, 'object':1, 'p':1, 'pre':1, 'style':1, 'summary':1, 'td':1, 'textarea':1, 'th':1, 'video':1}, + d: {'address':1, 'article':1, 'aside':1, 'blockquote':1, 'center':1, 'colgroup':1, 'datalist':1, 'details':1, 'dir':1, 'div':1, 'dl':1, 'fieldset':1, 'figure':1, 'footer':1, 'form':1, 'header':1, 'hgroup':1, 'hr':1, 'iframe':1, 'main':1, 'map':1, 'menu':1, 'nav':1, 'noscript':1, 'ol':1, 'optgroup':1, 'rbc':1, 'rtc':1, 'ruby':1, 'script':1, 'section':1, 'select':1, 'table':1, 'tbody':1, 'tfoot':1, 'thead':1, 'tr':1, 'ul':1}, }, hl_tidy: function(t, w, p) { // Tidy/compact HTM if (' pre,script,textarea'.indexOf("$p,") >= 0) return t; - var _repl = function(m) + var _repl = function(m, m1, m2, m3, m4) { - return m[1]+htmLawed._strtr(m[3], {'<': "\x01", '>':"\x02", "\n":"\x03", "\r":"\x04", "\t":"\x05", ' ':"\x07"})+m[4]; + return m1 + htmLawed._strtr(m3, {'<': "\x01", '>':"\x02", "\n":"\x03", "\r":"\x04", "\t":"\x05", ' ':"\x07"}) + m4; }; t = t.replace(/(<(!\[CDATA\[))([\s\S]+?)(\]\]>)/g, _repl) .replace(/(<(!--))([\s\S]+?)(-->)/g, _repl) .replace(/(<(pre|script|textarea)[^>]*?>)([\s\S]+?)(<\/\2>)/g, _repl) - .replace(/\s+/g, ' '); + .replace(/(<\w[^>]*(?)\s+/g, ' $1') + .replace(/\s+/g, ' ') + .replace(/(<\w[^>]*(?) /g, '$1'); if (w == -1) return htmLawed._strtr(t, {"\x01":'<', "\x02":'>', "\x03":"\n", "\x04":"\r", "\x05":"\t", "\x07":' '}); w = w.toLowerCase(); @@ -1309,10 +2221,9 @@ var htmLawed = module.exports = if (l) t = t.replace(/\n/g, l); return htmLawed._strtr(t, {"\x01":'<', "\x02":'>', "\x03":"\n", "\x04":"\r", "\x05":"\t", "\x07":' '}); - // eof }, hl_version: function() { - return '1.1.22'; + return '1.2.4.1'; } }; diff --git a/htmLawed_TESTCASE.txt b/htmLawed_TESTCASE.txt index 63ad9a3..c658d28 100644 --- a/htmLawed_TESTCASE.txt +++ b/htmLawed_TESTCASE.txt @@ -1,9 +1,9 @@ /* -htmLawed_TESTCASE.txt, 27 February 2016 -htmLawed 1.1.22, 5 March 2016 +htmLawed_TESTCASE.txt, 11 February 2017 +To test htmLawed Copyright Santosh Patnaik Dual licensed with LGPL 3 and GPL 2+ -A PHP Labware internal utility - http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed +A PHP Labware internal utility - www.bioinformatics.org/phplabware/internal_utilities/htmLawed */ This file has UTF-8-encoded text with both correct and incorrect/malformed HTML/XHTML code snippets to test htmLawed (test cases/samples). The entire text may also be used as a unit. @@ -28,7 +28,7 @@ character encoding to Unicode/UTF-8 Deprecated: a,

Casing:
Custom: image
-Data-*: a
+Data-*: a
Admin-restricted?:
Attribute values
diff --git a/htmLawed_TESTCASE_out.htm b/htmLawed_TESTCASE_out.htm index 906f663..ce2514a 100644 --- a/htmLawed_TESTCASE_out.htm +++ b/htmLawed_TESTCASE_out.htm @@ -1,9 +1,9 @@ /* -htmLawed_TESTCASE.txt, 27 February 2016 -htmLawed 1.1.22, 5 March 2016 +htmLawed_TESTCASE.txt, 11 February 2017 +To test htmLawed Copyright Santosh Patnaik Dual licensed with LGPL 3 and GPL 2+ -A PHP Labware internal utility - http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed +A PHP Labware internal utility - www.bioinformatics.org/phplabware/internal_utilities/htmLawed */ This file has UTF-8-encoded text with both correct and incorrect/malformed HTML/XHTML code snippets to test htmLawed (test cases/samples). The entire text may also be used as a unit. @@ -28,7 +28,7 @@ character encoding to Unicode/UTF-8 Deprecated: a,

Casing:
Custom: image
-Data-*: a
+Data-*: a
Admin-restricted?:
Attribute values
@@ -65,7 +65,7 @@ abc
def
ghi
Complex-1: deprecated elements
-The PHP software script used for this web-page webpage is htmLawedTest.php, from PHP Labware. +The PHP software script used for this web-page webpage is htmLawedTest.php, from PHP Labware.
Complex-2: deprecated attributes
@@ -73,18 +73,18 @@ The PHP software script used aa

-image - +image +

Section

Para

-
  1. First item
+
  1. First item
-
  1. First item
+
  1. First item
@@ -159,13 +159,13 @@ A c o m m e n t --> <![CDATA[ code ]]> -</script><!-- comment --><![CDATA[ cdata ]]> text</b> text<pre id="none">p r e</pre> - text text
<hr /> + text text

text none text text none t e x t -
text none t e x t + text none t e x t text none t e x t <script>script</script> @@ -207,10 +207,10 @@ Invalid: >comment in tag content, <!--check-->
HTML5
-figure and figcaption: <figure>picture<figcaption>Caption for the awesome picture</figcaption></figure> -article:

A

B

<article>

C

</article><article>

E

F

G

</article> -meter:

Heat <meter min="100" max="200" value="150">150</meter>.

-datalist: <datalist id="b"><option value="c"><option value="d"></datalist> +figure and figcaption:
picture
Caption for the awesome picture
+article:

A

B

C

E

F

G

+meter:

Heat 150.

+datalist:
Ins-Del
@@ -267,21 +267,21 @@ Invalid: >comment in tag content, <!--check-->

- +
</li></ul> </td></tr></table></li></ol> -Menu: +
  • <button type="button">Cut...</button>
  • +
    Microdata
    -
    -I am X but people call me Y. -Find me at www.xy.com +
    +I am X but people call me Y. +Find me at
    Microsoft Word
    @@ -292,7 +292,7 @@ Find me at www.xy.com
    Nesting
    -Block or inline a:

    text

    <div>hi</div>
    +Block or inline a:

    text

    hi

    Non-English text-1
    diff --git a/package.json b/package.json index 1b635cf..3e3915b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "htmlawed", - "version": "1.0.1", + "version": "1.0.2", "author": { "name": "Vitaliy Filippov", "email": "vitalif@yourcmc.ru", @@ -22,8 +22,7 @@ "bugs": { "url": "https://github.com/vitalif/htmlawed/issues" }, - "dependencies": { - }, + "dependencies": {}, "devDependencies": { "babel-cli": "latest", "babel-plugin-transform-es2015-destructuring": "latest",