From 7d6d6f601004eee1ad64a8b7f168c96a4f88dbe5 Mon Sep 17 00:00:00 2001 From: Chris Blake Date: Tue, 22 Mar 2016 15:43:20 -0400 Subject: [PATCH] Allows non-array, non-string values to be `node.class` values. `node.class` is always an array, so if we're a string, we split on spaces, like how classes are specified when creating HTML strings, or if we're a non-array, non-string value, we wrap ourselves into single-element array. Includes the following patch-level changes: - Moves the location of the `isBooleanAttribute` function. This is a minor change. --- dist/lmth.min.js | 14 +++++++------- lib/index.js | 18 ++++++++++++------ package.json | 2 +- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/dist/lmth.min.js b/dist/lmth.min.js index d30a98d..01bec1a 100644 --- a/dist/lmth.min.js +++ b/dist/lmth.min.js @@ -5,22 +5,22 @@ default:return!1}}function n(e){return"[object Object]"===toString.call(e)}funct r?r.push(t):n[e]=[].concat(t)}function o(e){var t={id:null,"class":[],style:null,listeners:{}} if(i(e)){var r=e.split(/([#\.][^#\.]+)/) r.forEach(function(e){e.startsWith("#")?t.id=e.substring(1):e.startsWith(".")&&t["class"].push(e.substring(1))})}else n(e)&&(Object.keys(e).forEach(function(n){var r=e[n] -n.startsWith("on")&&("function"==typeof r||Array.isArray(r))?s(n.slice(2),r,t.listeners):t[n]=r}),Array.isArray(t["class"])||(t["class"]=t["class"].split(" "))) +n.startsWith("on")&&("function"==typeof r||Array.isArray(r))?s(n.slice(2),r,t.listeners):t[n]=r}),i(t["class"])?t["class"]=t["class"].split(" "):Array.isArray(t["class"])||(t["class"]=[t["class"]])) return t}function a(e){return String(e).replace(/&|<|>|"|'/g,function(e){switch(e){case"&":return"&" case"<":return"<" case">":return">" case'"':return""" -case"'":return"'"}})}function c(e,t){var n=l(e) -return n&&t===!0?e+'="'+e+'"':n&&t===!1?"":e+'="'+a(t)+'"'}function l(e){return/^(?:allowFullscreen|async|autofocus|autoplay|checked|compact|controls|declare|default|defaultChecked|defaultMuted|defaultSelected|defer|disabled|draggable|enabled|formNoValidate|hidden|indeterminate|inert|isMap|itemScope|loop|multiple|muted|noHref|noResize|noShade|noValidate|noWrap|open|pauseOnExit|readOnly|required|reversed|scoped|seamless|selected|sortable|spellcheck|translate|trueSpeed|typeMustMatch|visible)$/.test(e)}function u(e){return Object.keys(e).reduce(function(t,n){return t+n+":"+e[n]+";"},"")}return e.prototype.toString=function(){return JSON.stringify(this)},e["new"]=function(t,n,r,i,s,o,a,c,l){return new e(t,n,r,i,s,o,a,c,l)},e.createElement=function(t,n){var s=n.isVoid||!1 +case"'":return"'"}})}function c(e){return/^(?:allowfullscreen|async|autofocus|autoplay|checked|compact|controls|declare|default|defaultchecked|defaultmuted|defaultselected|defer|disabled|draggable|enabled|formnovalidate|hidden|indeterminate|inert|ismap|itemscope|loop|multiple|muted|nohref|noresize|noshade|novalidate|nowrap|open|pauseonexit|readonly|required|reversed|scoped|seamless|selected|sortable|spellcheck|translate|truespeed|typemustmatch|visible)$/i.test(e)}function l(e,t){var n=c(e) +return n&&t===!0?e+'="'+e+'"':n&&t===!1?"":e+'="'+a(t)+'"'}function u(e){return Object.keys(e).reduce(function(t,n){return t+n+":"+e[n]+";"},"")}return e.prototype.toString=function(){return JSON.stringify(this)},e["new"]=function(t,n,r,i,s,o,a,c,l){return new e(t,n,r,i,s,o,a,c,l)},e.createElement=function(t,n){var s=n.isVoid||!1 return function(n,a,c){var l="",u={},d=[],f=r(n),h=r(a) i(n)||"object"===f?u=n:"array"===f&&(d=n),"primitive"===h?l=a:"object"===h?u=a:"array"===h&&(d=a),"array"===r(c)&&(d=c) -var p=o(u),m=p.id,y=p["class"],b=p.style,g=p.listeners -return delete p.id,delete p["class"],delete p.style,delete p.listeners,e["new"](t,s,m,y,b,g,p,l,d)}},e.addElement=function(t,n){e[t]=e.createElement(t,n)},e.elements=["a","abbr","acronym","address","applet","article","aside","audio","b","basefont","bdi","bdo","bgsound","big","blink","blockquote","body","button","canvas","caption","center","cite","code","colgroup","command","content","data","datalist","dd","del","details","dfn","dialog","dir","div","dl","dt","element","em","fieldset","figcaption","figure","font","footer","form","frame","frameset","h1","h2","h3","h4","h5","h6","head","header","hgroup","html","i","iframe","image","ins","isindex","kbd","label","legend","li","listing","main","map","mark","marquee","menu","menuitem","meter","multicol","nav","nobr","noembed","noframes","noscript","object","ol","optgroup","option","output","p","picture","plaintext","pre","progress","q","rp","rt","rtc","ruby","s","samp","script","section","select","shadow","small","spacer","span","strike","strong","style","sub","summary","sup","table","tbody","td","template","textarea","tfoot","th","thead","time","title","tr","tt","u","ul","var","video","xmp"],e.voidElements=["area","base","br","col","embed","hr","img","input","keygen","link","meta","param","source","track","wbr"],e.elements.forEach(function(t){e.addElement(t,{isVoid:!1})}),e.voidElements.forEach(function(t){e.addElement(t,{isVoid:!0})}),e.prototype.on=function(e,t){var n=this +var p=o(u),m=p.id,y=p["class"],b=p.style,v=p.listeners +return delete p.id,delete p["class"],delete p.style,delete p.listeners,e["new"](t,s,m,y,b,v,p,l,d)}},e.addElement=function(t,n){e[t]=e.createElement(t,n)},e.elements=["a","abbr","acronym","address","applet","article","aside","audio","b","basefont","bdi","bdo","bgsound","big","blink","blockquote","body","button","canvas","caption","center","cite","code","colgroup","command","content","data","datalist","dd","del","details","dfn","dialog","dir","div","dl","dt","element","em","fieldset","figcaption","figure","font","footer","form","frame","frameset","h1","h2","h3","h4","h5","h6","head","header","hgroup","html","i","iframe","image","ins","isindex","kbd","label","legend","li","listing","main","map","mark","marquee","menu","menuitem","meter","multicol","nav","nobr","noembed","noframes","noscript","object","ol","optgroup","option","output","p","picture","plaintext","pre","progress","q","rp","rt","rtc","ruby","s","samp","script","section","select","shadow","small","spacer","span","strike","strong","style","sub","summary","sup","table","tbody","td","template","textarea","tfoot","th","thead","time","title","tr","tt","u","ul","var","video","xmp"],e.voidElements=["area","base","br","col","embed","hr","img","input","keygen","link","meta","param","source","track","wbr"],e.elements.forEach(function(t){e.addElement(t,{isVoid:!1})}),e.voidElements.forEach(function(t){e.addElement(t,{isVoid:!0})}),e.prototype.on=function(e,t){var n=this return s(e,t,n.listeners),n},e.freeze=function(t){return e["new"](t.name,t.isVoid,t.id,t["class"],t.style,t.listeners,t.attributes,t.content,[])},e.prototype.transform=function(t){var n=this,r=[t(e.freeze(n))],i=n.children.map(function(e){return e.transform(t)}) return r.concat(i)},e.prototype.toList=function(){var e=this return e.transform(function(e){return e})},e.prototype.traverse=function(t){var n=this,r=t(e.freeze(n)),i=n.children.map(function(e){return e.traverse(t)}) -return r.children=i,r},e.prototype.render=function(){var e=this,t=Object.keys(e.attributes).reduce(function(t,n){return t+" "+c(n,e.attributes[n])},""),n=a(e.content)+e.children.reduce(function(e,t){return e+(i(t)?a(t):t.render())},"") +return r.children=i,r},e.prototype.render=function(){var e=this,t=Object.keys(e.attributes).reduce(function(t,n){return t+" "+l(n,e.attributes[n])},""),n=a(e.content)+e.children.reduce(function(e,t){return e+(i(t)?a(t):t.render())},"") return"<"+e.name+(e.id?' id="'+e.id+'"':"")+(0!==e["class"].length?' class="'+e["class"].join(" ")+'"':"")+(e.style?' style="'+u(e.style)+'"':"")+t+">"+(e.isVoid&&0===e.children.length?"":n+"")},e.renderList=function(e){return e.map(function(e){return e.render()}).join("")},e.prototype.toDOM=function(e){e=e||document var t=this,n=e.createElement(t.name) -return Object.keys(t.attributes).forEach(function(e){var r=t.attributes[e],i=l(e) +return Object.keys(t.attributes).forEach(function(e){var r=t.attributes[e],i=c(e) i&&r===!0?n.setAttribute(e,e):i&&r===!1||n.setAttribute(e,r)}),t.id&&(n.id=t.id),t["class"].length>0&&(n.className=t["class"].join(" ")),t.style&&n.setAttribute("style",u(t.style)),t.listeners&&Object.keys(t.listeners).forEach(function(e){t.listeners[e].forEach(function(t){n.addEventListener(e,t)})}),null!=t.content&&n.appendChild(e.createTextNode(t.content)),t.children.forEach(function(t){n.appendChild(i(t)?e.createTextNode(t):t.toDOM(e))}),n},e.appendListToDOM=function(e,t,n){t.forEach(function(t){e.appendChild(t.toDOM(n))})},e}) diff --git a/lib/index.js b/lib/index.js index 2d9e449..4cd4a2b 100644 --- a/lib/index.js +++ b/lib/index.js @@ -123,8 +123,14 @@ function parseAttributes(attributes) { } }); - if (!Array.isArray(nodeAttributes.class)) { + // `node.class` is always an array, so if we're a string, we + // split on spaces, like how classes are specified when + // creating HTML strings, or if we're a non-array, non-string + // value, we wrap ourselves into single-element array. + if (isString(nodeAttributes.class)) { nodeAttributes.class = nodeAttributes.class.split(' '); + } else if (!Array.isArray(nodeAttributes.class)) { + nodeAttributes.class = [nodeAttributes.class]; } } @@ -289,6 +295,11 @@ function htmlEscape(content) { }); } +// https://github.com/kangax/html-minifier/issues/63#issuecomment-37763316 +function isBooleanAttribute(attribute) { + return (/^(?:allowfullscreen|async|autofocus|autoplay|checked|compact|controls|declare|default|defaultchecked|defaultmuted|defaultselected|defer|disabled|draggable|enabled|formnovalidate|hidden|indeterminate|inert|ismap|itemscope|loop|multiple|muted|nohref|noresize|noshade|novalidate|nowrap|open|pauseonexit|readonly|required|reversed|scoped|seamless|selected|sortable|spellcheck|translate|truespeed|typemustmatch|visible)$/i).test(attribute); +} + /* Renders a singleton attribute key, or a key-value attribute pair, * HTML-escaping the value. */ function renderAttribute(key, value) { @@ -303,11 +314,6 @@ function renderAttribute(key, value) { } } -// https://github.com/kangax/html-minifier/issues/63#issuecomment-37763316 -function isBooleanAttribute(attribute) { - return (/^(?:allowfullscreen|async|autofocus|autoplay|checked|compact|controls|declare|default|defaultchecked|defaultmuted|defaultselected|defer|disabled|draggable|enabled|formnovalidate|hidden|indeterminate|inert|ismap|itemscope|loop|multiple|muted|nohref|noresize|noshade|novalidate|nowrap|open|pauseonexit|readonly|required|reversed|scoped|seamless|selected|sortable|spellcheck|translate|truespeed|typemustmatch|visible)$/i).test(attribute); -} - function renderStyle(style) { return Object.keys(style).reduce(function styler(styleString, property) { return styleString + property + ':' + style[property] + ';'; diff --git a/package.json b/package.json index 059455d..94bfd1a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lmth", - "version": "6.1.0", + "version": "6.2.0", "description": "A \"type-safe\" HTML DSL for JavaScript environments.", "main": "lib/index.js", "scripts": {