From ceea63d12d53c0e846433bfbb37db7177dd50558 Mon Sep 17 00:00:00 2001 From: Mic Date: Thu, 13 Sep 2012 13:50:14 +0200 Subject: [PATCH] fix OPTGROUP/OPTION when used as template root. jslinted. --- libs/pure.js | 179 ++++++++++++++++++++++++++--------------------- libs/pure_min.js | 48 ++++++------- 2 files changed, 123 insertions(+), 104 deletions(-) diff --git a/libs/pure.js b/libs/pure.js index 258ec54..dc7454d 100644 --- a/libs/pure.js +++ b/libs/pure.js @@ -7,24 +7,47 @@ Copyright (c) 2012 Michael Cvilic - BeeBole.com Thanks to Rog Peppe for the functional JS jump - revision: 2.76 + revision: 2.77 */ -var $p, pure = $p = function(){ - var sel = arguments[0], +var $p = function(){ + var args = arguments, + sel = args[0], ctxt = false; if(typeof sel === 'string'){ - ctxt = arguments[1] || false; + ctxt = args[1] || false; }else if(sel && !sel[0] && !sel.length){ sel = [sel]; } return $p.core(sel, ctxt); -}; +}, +pure = $p; + $p.core = function(sel, ctxt, plugins){ //get an instance of the plugins - var templates = []; + var templates = [], i, ii, + // set the signature string that will be replaced at render time + Sig = '_s' + Math.floor( Math.random() * 1000000 ) + '_', + // another signature to prepend to attributes and avoid checks: style, height, on[events]... + attPfx = '_a' + Math.floor( Math.random() * 1000000 ) + '_', + // rx to parse selectors, e.g. "+tr.foo[class]" + selRx = /^(\+)?([^\@\+]+)?\@?([^\+]+)?(\+)?$/, + // set automatically attributes for some tags + autoAttr = { + IMG:'src', + INPUT:'value' + }, + // check if the argument is an array - thanks salty-horse (Ori Avtalion) + isArray = Array.isArray ? + function(o) { + return Array.isArray(o); + } : + function(o) { + return Object.prototype.toString.call(o) === "[object Array]"; + }; + plugins = plugins || getPlugins(); //search for the template node(s) @@ -42,31 +65,11 @@ $p.core = function(sel, ctxt, plugins){ templates = sel; } - for(var i = 0, ii = templates.length; i < ii; i++){ + for( i = 0, ii = templates.length; i < ii; i++){ plugins[i] = templates[i]; } plugins.length = ii; - // set the signature string that will be replaced at render time - var Sig = '_s' + Math.floor( Math.random() * 1000000 ) + '_', - // another signature to prepend to attributes and avoid checks: style, height, on[events]... - attPfx = '_a' + Math.floor( Math.random() * 1000000 ) + '_', - // rx to parse selectors, e.g. "+tr.foo[class]" - selRx = /^(\+)?([^\@\+]+)?\@?([^\+]+)?(\+)?$/, - // set automatically attributes for some tags - autoAttr = { - IMG:'src', - INPUT:'value' - }, - // check if the argument is an array - thanks salty-horse (Ori Avtalion) - isArray = Array.isArray ? - function(o) { - return Array.isArray(o); - } : - function(o) { - return Object.prototype.toString.call(o) === "[object Array]"; - }; - /* * * * * * * * * * * * * * * * * * * * * * * * * * core functions * * * * * * * * * * * * * * * * * * * * * * * * * */ @@ -76,7 +79,7 @@ $p.core = function(sel, ctxt, plugins){ function error(e){ if(typeof console !== 'undefined'){ console.log(e); - debugger; + //debugger; } throw('pure error: ' + e); } @@ -110,13 +113,13 @@ $p.core = function(sel, ctxt, plugins){ h = div.innerHTML; div = null; return h; - })(node); + }(node)); } // returns the string generator function function wrapquote(qfn, f){ return function(ctxt){ - return qfn('' + f.call(ctxt.item || ctxt.context, ctxt)); + return qfn( String( f.call(ctxt.item || ctxt.context, ctxt) ) ) ; }; } @@ -128,9 +131,10 @@ $p.core = function(sel, ctxt, plugins){ } if(typeof document.querySelectorAll !== 'undefined'){ return (n||document).querySelectorAll( sel ); - }else{ - return error('You can test PURE standalone with: iPhone, FF3.5+, Safari4+ and IE8+\n\nTo run PURE on your browser, you need a JS library/framework with a CSS selector engine'); } + + return error('You can test PURE standalone with: iPhone, FF3.5+, Safari4+ and IE8+\n\nTo run PURE on your browser, you need a JS library/framework with a CSS selector engine'); + } // create a function that concatenates constant string @@ -143,9 +147,9 @@ $p.core = function(sel, ctxt, plugins){ return function(ctxt){ var strs = [ parts[ 0 ] ], n = parts.length, - fnVal, pVal, attLine, pos; + fnVal, pVal, attLine, pos, i; try{ - for(var i = 1; i < n; i++){ + for(i = 1; i < n; i++){ fnVal = fns[i].call( this, ctxt ); pVal = parts[i]; @@ -164,9 +168,9 @@ $p.core = function(sel, ctxt, plugins){ return strs.join(''); }catch(e){ if(console && console.log){ - console.log( e.stack ? - e.stack : - e.message + ' (' + e.type + ', ' + e.arguments.join('-') + '). Use Firefox or Chromium/Chrome to get a full stack of the error. ' ); + console.log( + e.stack || + e.message + ' (' + e.type + ', ' + e['arguments'].join('-') + '). Use Firefox or Chromium/Chrome to get a full stack of the error. ' ); } return ''; } @@ -201,9 +205,10 @@ $p.core = function(sel, ctxt, plugins){ }; } //check for a valid js variable name with hyphen(for properties only), $, _ and : - var m = sel.match(/^[\da-zA-Z\$_\@][\w\$:-]*(\.[\w\$:-]*[^\.])*$/); + var m = sel.match(/^[\da-zA-Z\$_\@][\w\$:\-]*(\.[\w\$:\-]*[^\.])*$/), + found = false, s = sel, parts = [], pfns = [], i = 0, retStr; + if(m === null){ - var found = false, s = sel, parts = [], pfns = [], i = 0, retStr; // check if literal if(/\'|\"/.test( s.charAt(0) )){ if(/\'|\"/.test( s.charAt(s.length-1) )){ @@ -229,24 +234,26 @@ $p.core = function(sel, ctxt, plugins){ return function(ctxt){ var data = ctxt.context || ctxt, v = ctxt[m[0]], - i = 0; + i = 0, + n, + dm; + if(v && typeof v.item !== 'undefined'){ i += 1; if(m[i] === 'pos'){ //allow pos to be kept by string. Tx to Adam Freidin return v.pos; - }else{ - data = v.item; } + data = v.item; } - var n = m.length, - dm; + n = m.length; - for(; i < n; i++){ + while( i < n ){ if(!data){break;} dm = data[ m[i] ]; //if it is a function call it data = typeof dm === 'function' ? data[ m[i] ].call( data ) : dm; + i++; } return (!data && data !== 0) ? '':data; @@ -255,10 +262,11 @@ $p.core = function(sel, ctxt, plugins){ // wrap in an object the target node/attr and their properties function gettarget(dom, sel, isloop){ - var osel, prepend, selector, attr, append, target = []; + var osel, prepend, selector, attr, append, target = [], m, + setstr, getstr, quotefn, isStyle, isClass, attName, setfn; if( typeof sel === 'string' ){ osel = sel; - var m = sel.match(selRx); + m = sel.match(selRx); if( !m ){ error( 'bad selector syntax: ' + sel ); } @@ -293,19 +301,21 @@ $p.core = function(sel, ctxt, plugins){ error('cannot append with loop (sel: ' + osel + ')'); } } - var setstr, getstr, quotefn, isStyle, isClass, attName, setfn; + if(attr){ isStyle = (/^style$/i).test(attr); isClass = (/^class$/i).test(attr); attName = isClass ? 'className' : attr; setstr = function(node, s) { node.setAttribute(attPfx + attr, s); - if (attName in node && !isStyle) { + if ( node.hasOwnProperty(attName) && !isStyle) { try{node[attName] = '';}catch(e){} //FF4 gives an error sometimes } if (node.nodeType === 1) { node.removeAttribute(attr); - isClass && node.removeAttribute(attName); + if(isClass){ + node.removeAttribute(attName); + } } }; if (isStyle || isClass) {//IE no quotes special care @@ -355,8 +365,8 @@ $p.core = function(sel, ctxt, plugins){ } function setsig(target, n){ - var sig = Sig + n + ':'; - for(var i = 0; i < target.nodes.length; i++){ + var sig = Sig + n + ':', i; + for(i = 0; i < target.nodes.length; i++){ // could check for overlapping targets here. target.set( target.nodes[i], sig ); } @@ -380,7 +390,7 @@ $p.core = function(sel, ctxt, plugins){ ctxt.item = temp.item = a[ idx ]; ctxt.items = a; //if array, set a length property - filtered items - typeof len !== 'undefined' && (ctxt.length = len); + if(typeof len !== 'undefined'){ (ctxt.length = len); } //if filter directive if(typeof ftr === 'function' && ftr.call(ctxt.item, ctxt) === false){ filtered++; @@ -391,7 +401,8 @@ $p.core = function(sel, ctxt, plugins){ ctxt.pos = save_pos; ctxt.item = save_item; ctxt.items = save_items; - }; + }, + prop, i, ii; ctxt[name] = temp; if( isArray(a) ){ length = a.length || 0; @@ -400,7 +411,7 @@ $p.core = function(sel, ctxt, plugins){ a.sort(sorter); } //loop on array - for(var i = 0, ii = length; i < ii; i++){ + for(i = 0, ii = length; i < ii; i++){ buildArg(i, temp, filter, length - filtered); } }else{ @@ -408,52 +419,57 @@ $p.core = function(sel, ctxt, plugins){ error('sort is only available on arrays, not objects'); } //loop on collections - for(var prop in a){ - a.hasOwnProperty( prop ) && buildArg(prop, temp, filter); + for( prop in a ){ + if( a.hasOwnProperty( prop ) ){ + buildArg(prop, temp, filter); + } } } - typeof old !== 'undefined' ? ctxt[name] = old : delete ctxt[name]; + if( typeof old !== 'undefined'){ + ctxt[name] = old; + }else{ + delete ctxt[name]; + } return strs.join(''); }; } // generate the template for a loop node function loopgen(dom, sel, loop, fns){ - var already = false, ls, sorter, filter, prop; + var already = false, ls, sorter, filter, prop, dsel, spec, itersel, target, nodes, node, inner; for(prop in loop){ if(loop.hasOwnProperty(prop)){ if(prop === 'sort'){ sorter = loop.sort; - continue; }else if(prop === 'filter'){ filter = loop.filter; - continue; - } - if(already){ + }else if(already){ error('cannot have more than one loop on a target'); + }else{ + ls = prop; + already = true; } - ls = prop; - already = true; } } if(!ls){ error('Error in the selector: ' + sel + '\nA directive action must be a string, a function or a loop(<-)'); } - var dsel = loop[ls]; + dsel = loop[ls]; // if it's a simple data selector then we default to contents, not replacement. if(typeof(dsel) === 'string' || typeof(dsel) === 'function'){ loop = {}; loop[ls] = {root: dsel}; return loopgen(dom, sel, loop, fns); } - var spec = parseloopspec(ls), - itersel = dataselectfn(spec.sel), - target = gettarget(dom, sel, true), - nodes = target.nodes; + + spec = parseloopspec(ls); + itersel = dataselectfn(spec.sel); + target = gettarget(dom, sel, true); + nodes = target.nodes; for(i = 0; i < nodes.length; i++){ - var node = nodes[i], - inner = compiler(node, dsel); + node = nodes[i]; + inner = compiler(node, dsel); fns[fns.length] = wrapquote(target.quotefn, loopfn(spec.name, itersel, inner, sorter, filter)); target.nodes = [node]; // N.B. side effect on target. setsig(target, fns.length - 1); @@ -541,7 +557,7 @@ $p.core = function(sel, ctxt, plugins){ function compiler(dom, directive, data, ans){ var fns = [], j, jj, cspec, n, target, nodes, itersel, node, inner, dsel, sels, sel, sl, i, h, parts, pfns = [], p; // autoRendering nodes parsing -> auto-nodes - ans = ans || data && getAutoNodes(dom, data); + ans = ans || (data && getAutoNodes(dom, data)); if(data){ // for each auto-nodes while(ans.length > 0){ @@ -623,11 +639,10 @@ $p.core = function(sel, ctxt, plugins){ // return an HTML string // should replace the template and return this function render(ctxt, directive){ - var fn = typeof directive === 'function' && directive, i = 0, ii = this.length; - for(; i < ii; i++){ + var fn = typeof directive === 'function' && directive, i, ii; + for(i = 0, ii = this.length; i < ii; i++){ this[i] = replaceWith( this[i], (fn || plugins.compile( directive, false, this[i] ))( ctxt, false )); } - context = null; return this; } @@ -635,18 +650,18 @@ $p.core = function(sel, ctxt, plugins){ // run the template function on the context argument // return an HTML string function autoRender(ctxt, directive){ - var fn = plugins.compile( directive, ctxt, this[0] ); - for(var i = 0, ii = this.length; i < ii; i++){ + var fn = plugins.compile( directive, ctxt, this[0] ), i, ii; + for(i = 0, ii = this.length; i < ii; i++){ this[i] = replaceWith( this[i], fn( ctxt, false)); } - context = null; return this; } function replaceWith(elm, html) { var ne, ep = elm.parentNode, - depth = 0; + depth = 0, + tmp; if(!ep){ //if no parents ep = document.createElement('DIV'); ep.appendChild(elm); @@ -668,6 +683,10 @@ $p.core = function(sel, ctxt, plugins){ html = '' + html + '
'; depth = 3; break; + case 'OPTGROUP': case 'OPTION': + html = ''; + depth = 1; + break; } tmp = document.createElement('SPAN'); tmp.style.display = 'none'; diff --git a/libs/pure_min.js b/libs/pure_min.js index 8ecb3e6..13bd92b 100644 --- a/libs/pure_min.js +++ b/libs/pure_min.js @@ -7,29 +7,29 @@ Copyright (c) 2012 Michael Cvilic - BeeBole.com Thanks to Rog Peppe for the functional JS jump - revision: 2.76 + revision: 2.77 */ -var $p,pure=$p=function(d,h){var n=d,s=false;if(typeof n==="string")s=h||false;else if(n&&!n[0]&&!n.length)n=[n];return $p.core(n,s)}; -$p.core=function(d,h,n){function s(a){if(typeof console!=="undefined"){console.log(a);debugger}throw"pure error: "+a;}function O(){var a=$p.plugins,b=function(){};b.prototype=a;b.prototype.compile=a.compile||P;b.prototype.render=a.render||Q;b.prototype.autoRender=a.autoRender||R;b.prototype.find=a.find||S;b.prototype._compiler=B;b.prototype._error=s;return new b}function G(a){return a.outerHTML||function(b){var f=document.createElement("div");f.appendChild(b.cloneNode(true));return f.innerHTML}(a)} -function C(a,b){return function(f){return a(""+b.call(f.item||f.context,f))}}function S(a,b){if(typeof a==="string"){b=a;a=false}return typeof document.querySelectorAll!=="undefined"?(a||document).querySelectorAll(b):s("You can test PURE standalone with: iPhone, FF3.5+, Safari4+ and IE8+\n\nTo run PURE on your browser, you need a JS library/framework with a CSS selector engine")}function H(a,b){return function(f){var c=[a[0]],g=a.length,i,k,l,e;try{for(var o=1;o-1){c[c.length-1]=l.substring(0,e);k=k.substr(1)}}c[c.length]=i;c[c.length]=k}return c.join("")}catch(m){if(console&&console.log)console.log(m.stack?m.stack:m.message+" ("+m.type+", "+m.arguments.join("-")+"). Use Firefox or Chromium/Chrome to get a full stack of the error. ");return""}}}function T(a){var b=a.match(/^(\w+)\s*<-\s*(\S+)?$/);b===null&&s('bad loop spec: "'+a+'"');b[1]==="item"&&s('"item<-..." is a reserved word for the current running iteration.\n\nPlease choose another name for your loop.'); -if(!b[2]||b[2].toLowerCase()==="context")b[2]=function(f){return f.context};else if(b[2]&&b[2].indexOf("context")===0)b[2]=x(b[2].replace(/^context\.?/,""));return{name:b[1],sel:b[2]}}function x(a){if(typeof a==="function")return function(e){e=a.call(e.item||e.context||e,e);return!e&&e!==0?"":e};var b=a.match(/^[\da-zA-Z\$_\@][\w\$:-]*(\.[\w\$:-]*[^\.])*$/);if(b===null){var f=false,c=a,g=[],i=[],k=0,l;if(/\'|\"/.test(c.charAt(0))){if(/\'|\"/.test(c.charAt(c.length-1))){l=c.substring(1,c.length-1); -return function(){return l}}}else for(;(b=c.match(/#\{([^{}]+)\}/))!==null;){f=true;g[k++]=c.slice(0,b.index);i[k]=x(b[1]);c=c.slice(b.index+b[0].length,c.length)}if(!f)return function(){return a};g[k]=c;return H(g,i)}b=a.split(".");return function(e){var o=e.context||e,m=e[b[0]];e=0;if(m&&typeof m.item!=="undefined"){e+=1;if(b[e]==="pos")return m.pos;else o=m.item}m=b.length;for(var t;e=0;y--){z=i.a[y];v=(v=z.l[0])&&v[p.prop];if(typeof v!=="undefined"){p.prop=z.p+"."+p.prop;if(i.l[p.prop]===true)v=v[0];break}}if(typeof v==="undefined"){v=x(p.prop)(F(b)?b[0]:b);if(v==="")return false}if(F(v)){i.a.push({l:v, -p:p.prop});i.l[p.prop]=true;p.t="loop"}else p.t="str";return p}var c=a.getElementsByTagName("*"),g=[],i={a:[],l:{}},k,l,e,o,m,t,u,q;e=-1;for(o=c.length;e-1?c[e]:a;if(u.nodeType===1&&u.className!==""){q=u.className.split(" ");m=0;for(t=q.length;m-1||l){u.className=u.className.replace("@"+k.attr,"");if(l)k.attr=false}g.push({n:u,cspec:k})}}}}return g}function B(a,b,f,c){var g=[],i,k,l,e,o,m,t, -u,q,j=[];c=c||f&&V(a,f);if(f)for(;c.length>0;){l=c[0].cspec;e=c[0].n;c.splice(0,1);if(l.t==="str"){e=D(e,l,false);E(e,g.length);g[g.length]=C(e.quotefn,x(l.prop))}else{m=x(l.sel);e=D(e,l,true);o=e.nodes;i=0;for(k=o.length;i]+)\s(value\=""|selected)\s?([^>]*)>/ig,"<$1 $3>");a=a.split(J).join("");a=a.split(K);for(f=1;f";g=1;break;case "TR":b=""+b+"
";g=2;break;case "TD":case "TH":b=""+ -b+"
";g=3;break}tmp=document.createElement("SPAN");tmp.style.display="none";document.body.appendChild(tmp);tmp.innerHTML=b;for(f=tmp.firstChild;g--;)f=f.firstChild;c.insertBefore(f,a);c.removeChild(a);document.body.removeChild(tmp);return a=f}var A=[];n=n||O();switch(typeof d){case "string":A=n.find(h||document,d);A.length===0&&s('The template "'+d+'" was not found');break;case "undefined":s("The root of the template is undefined, check your selector");break;default:A=d}var w= -0;for(d=A.length;w-1){c[c.length-1]=l.substring(0,e);k=k.substr(1)}}c[c.length]=h;c[c.length]=k}return c.join("")}catch(n){if(console&&console.log)console.log(n.stack||n.message+" ("+n.type+", "+n.arguments.join("-")+"). Use Firefox or Chromium/Chrome to get a full stack of the error. ");return""}}}function T(a){var b=a.match(/^(\w+)\s*<-\s*(\S+)?$/);b===null&&u('bad loop spec: "'+a+'"');b[1]==="item"&&u('"item<-..." is a reserved word for the current running iteration.\n\nPlease choose another name for your loop.'); +if(!b[2]||b[2].toLowerCase()==="context")b[2]=function(f){return f.context};else if(b[2]&&b[2].indexOf("context")===0)b[2]=x(b[2].replace(/^context\.?/,""));return{name:b[1],sel:b[2]}}function x(a){if(typeof a==="function")return function(e){e=a.call(e.item||e.context||e,e);return!e&&e!==0?"":e};var b=a.match(/^[\da-zA-Z\$_\@][\w\$:\-]*(\.[\w\$:\-]*[^\.])*$/),f=false,c=a,i=[],h=[],k=0,l;if(b===null){if(/\'|\"/.test(c.charAt(0))){if(/\'|\"/.test(c.charAt(c.length-1))){l=c.substring(1,c.length-1);return function(){return l}}}else for(;(b= +c.match(/#\{([^{}]+)\}/))!==null;){f=true;i[k++]=c.slice(0,b.index);h[k]=x(b[1]);c=c.slice(b.index+b[0].length,c.length)}if(!f)return function(){return a};i[k]=c;return H(i,h)}b=a.split(".");return function(e){var m=e.context||e,n=e[b[0]];e=0;var s;if(n&&typeof n.item!=="undefined"){e+=1;if(b[e]==="pos")return n.pos;m=n.item}for(n=b.length;e=0;y--){z=h.a[y];v=(v=z.l[0])&&v[p.prop];if(typeof v!=="undefined"){p.prop=z.p+"."+p.prop;if(h.l[p.prop]===true)v=v[0];break}}if(typeof v==="undefined"){v=x(p.prop)(F(b)?b[0]:b);if(v==="")return false}if(F(v)){h.a.push({l:v,p:p.prop});h.l[p.prop]= +true;p.t="loop"}else p.t="str";return p}var c=a.getElementsByTagName("*"),i=[],h={a:[],l:{}},k,l,e,m,n,s,t,q;e=-1;for(m=c.length;e-1?c[e]:a;if(t.nodeType===1&&t.className!==""){q=t.className.split(" ");n=0;for(s=q.length;n-1||l){t.className=t.className.replace("@"+k.attr,"");if(l)k.attr=false}i.push({n:t,cspec:k})}}}}return i}function B(a,b,f,c){var i=[],h,k,l,e,m,n,s,t,q,j=[];c=c||f&&V(a,f); +if(f)for(;c.length>0;){l=c[0].cspec;e=c[0].n;c.splice(0,1);if(l.t==="str"){e=D(e,l,false);E(e,i.length);i[i.length]=C(e.quotefn,x(l.prop))}else{n=x(l.sel);e=D(e,l,true);m=e.nodes;h=0;for(k=m.length;h]+)\s(value\=""|selected)\s?([^>]*)>/ig,"<$1 $3>");a=a.split(J).join("");a=a.split(K);for(f=1;f";i=1;break;case "TR":b=""+b+"
";i=2;break;case "TD":case "TH":b=""+b+"
"; +i=3;break;case "OPTGROUP":case "OPTION":b="";i=1;break}h=document.createElement("SPAN");h.style.display="none";document.body.appendChild(h);h.innerHTML=b;for(f=h.firstChild;i--;)f=f.firstChild;c.insertBefore(f,a);c.removeChild(a);document.body.removeChild(h);return a=f}var A=[],w,K="_s"+Math.floor(Math.random()*1E6)+"_",J="_a"+Math.floor(Math.random()*1E6)+"_",I=/^(\+)?([^\@\+]+)?\@?([^\+]+)?(\+)?$/,W={IMG:"src",INPUT:"value"},F=Array.isArray?function(a){return Array.isArray(a)}: +function(a){return Object.prototype.toString.call(a)==="[object Array]"};o=o||O();switch(typeof d){case "string":A=o.find(g||document,d);A.length===0&&u('The template "'+d+'" was not found');break;case "undefined":u("The root of the template is undefined, check your selector");break;default:A=d}w=0;for(d=A.length;w