diff --git a/demos/demo.html b/demos/demo.html index 5c35e7f..0269713 100644 --- a/demos/demo.html +++ b/demos/demo.html @@ -50,15 +50,20 @@ jQuery(function(){ var tmpl = '
  • ${getName()} {{if $ctx.showCities}}(${cityJoin()}){{/if}}
  • '; + $.templates.myTmpl = $.tmpl('
  • My template: ${getName()} {{if $ctx.showCities}}(${cityJoin()}){{/if}}
  • '); // Appends one LI, filled with data, into the UL $("ul").append( tmpl, dataObject ); + var cityCtxs; // Appends multiple LIs for each item. Use options referenced in tmpl string - $("ul").append( "#sometmpl", arrayOfDataObjects, { array: arrayOfDataObjects, showCities: true } ); + $("ul").prepend( "#sometmpl", arrayOfDataObjects, { array: arrayOfDataObjects, showCities: true, newCtxs: cityCtxs } ); // Example of template that has leading or trailing text - $("div").append( "#leadingOrTrailingText", arrayOfDataObjects ); + $("div").before( "#leadingOrTrailingText", arrayOfDataObjects ); + + // Use template from $.templates. Target wrapped set has more than one element, so rendered template cloned into to places in DOM + $(".multiple").after( "myTmpl", dataObject ); }); @@ -76,6 +81,6 @@ ${firstName} ${lastName}
    - +
    diff --git a/jquery.tmpl.js b/jquery.tmpl.js index c35112e..5c2cbad 100644 --- a/jquery.tmpl.js +++ b/jquery.tmpl.js @@ -7,23 +7,22 @@ (function(jQuery){ // Override the DOM manipulation function var oldManip = jQuery.fn.domManip, tCtxAtt = "_tmplctx", filterAll = "[" + tCtxAtt + "]", itm, ob, - htmlExpr = /^[^<]*(<[\w\W]+>)[^>]*$/, newCtxs = {}, topCtx = newCtx({ key: 0 }), ctxKey = 0; + htmlExpr = /^[^<]*(<[\w\W]+>)[^>]*$/, newCtxs, topCtx = { key: 0 }, ctxKey = 0; function newCtx( options, parentCtx, fn, data ) { // Returns a template context for a new instance of a template. // The content field is a hierarchical array of strings and nested contexts (to be // removed and replaced by nodes field of dom elements, once inserted in DOM). var newCtx = { - index: -1, data: data || null, tmpl: null, parent: parentCtx || null, - nodes: [], - update: update, - remove: remove + nodes: [] + // When we have wrapper/container templates - with a concept of where their 'child content' is, we can also support append and prepend }; if ( options) { jQuery.extend( newCtx, options, { nodes: [], parent: parentCtx } ); + fn = fn || (typeof options.tmpl === "function" ? options.tmpl : null); } if ( fn ) { // Build the hierarchical content to be used during insertion into DOM @@ -35,18 +34,6 @@ newCtxs[ctxKey] = newCtx; } return newCtx; - - function update( context ) { - context = context ? jQuery.extend( this, context ) : this; - var nodes = context.nodes; - jQuery( nodes[0] ).before( context ); - jQuery( nodes ).remove(); - return this; - } - function remove() { - jQuery( this.nodes ).remove(); - return this; - } } jQuery.fn.extend({ @@ -66,13 +53,15 @@ else if ( args.length >= 2 && typeof args[1] === "object" && !args[1].nodeType ) { // args[1] is data, for a template. Eval template to obtain fragment to clone and insert parentCtx = args[3] || topCtx; + newCtxs = {}; dmArgs[0] = [ jQuery.tmpl( args[0], parentCtx, args[1], args[2], true ) ]; } else if ( args.length === 1 && typeof args[0] === "object" && !args[0].nodeType && !(args[0] instanceof jQuery) ) { // args[0] is template context (already inserted in DOM) to be refreshed + newCtxs = {}; parentCtx = args[0]; newCtxs[parentCtx.key] = parentCtx; - dmArgs[0] = [ jQuery.tmpl( parentCtx ) ]; + dmArgs[0] = [ jQuery.tmpl( null, parentCtx ) ]; dmArgs[1] = parentCtx.data; } if ( parentCtx ) { @@ -84,12 +73,17 @@ cloneIndex = -1; // Call onRendered for each inserted template instance. - ctxs = newCtxs; - newCtxs = {}; - for ( itm in ctxs ) { - ob = ctxs[itm]; // Could test for hasOwnProperty... - if ( ob.rendered ) { - ob.rendered( ob ); + if ( newCtxs ) { + ctxs = newCtxs; + newCtxs = null; + for ( itm in ctxs ) { + ob = ctxs[itm]; // Could test for hasOwnProperty... + if ( ob.newCtxs && jQuery.inArray( ob, ob.newCtxs ) === -1 ) { + ob.newCtxs.push( ob ); + } + if ( ob.rendered ) { + ob.rendered( ob ); + } } } return this; @@ -113,13 +107,14 @@ parent = ctx = newCtxs[key]; if ( cloneIndex ) { key = key + keySuffix; - newCtxs[key] = newCtxs[key] || newCtx( ctx, newCtxs[ctx.parent.key + keySuffix] || ctx.parent, true ); + newCtxs[key] = newCtxs[key] || newCtx( ctx, newCtxs[ctx.parent.key + keySuffix] || ctx.parent, null, true ); } parentNodeCtx = jQuery.attr(this.parentNode, tCtxAtt) || 0; while ( parent && parent.key != parentNodeCtx ) { parent.nodes.push( this ); parent = parent.parent; } + delete ctx.content; // Could keep this available. Currently deleting to reduce API surface area, and memory use... jQuery.data( this, "tmplCtx", ctx ); } }).removeAttr( tCtxAtt ); @@ -131,43 +126,38 @@ jQuery.extend({ tmpl: function( tmpl, parentCtx, data, options, domFrag ) { - var fn, targetCtx; - if ( arguments.length === 1 ) { - // Generate a reusable function that will serve as a template - // generator (and which will be cached). - if ( (typeof tmpl === "string") && !htmlExpr.test( tmpl ) ) { - // it is a selector - tmpl = jQuery( tmpl )[0]; - } - else if ( tmpl instanceof jQuery ) { + var fn, targetCtx, coll; + if ( !tmpl && arguments.length === 2) { + // Re-evaluate rendered template for the parentCtx + targetCtx = parentCtx; + tmpl = parentCtx.tmpl; + } + if ( typeof tmpl === "string" ) { + if ( htmlExpr.test( tmpl) ) { // This is an HTML string being passed directly in. // Assume the user doesn't want it cached. // They can stick it in jQuery.templates to cache it. - tmpl = tmpl.get(0); - } - if ( tmpl.nodeType ) { - // Return template context for an element, unless element is a script block template declaration. - if (jQuery.attr( tmpl, "type") !== "text/html" ) { - while ( tmpl && !(tmplCtx = jQuery.data( tmpl, "tmplCtx" )) && (tmpl = tmpl.parentNode) ) {} - return tmplCtx || topCtx; - } + tmpl = tmplFn( tmpl ) + } else if ( fn = jQuery.templates[ tmpl ] ) { + // Use a pre-defined template, if available + tmpl = fn; } else { - // Render an updated template context, already associated with DOM. - targetCtx = tmpl; - tmpl = tmpl.tmpl; - } - } - if ( !tmpl ) { - return topCtx; - } - // If arguments.length > 1 render template against data, and return fragments ready for DOM insertion. - if ( typeof tmpl === "string" ) { - // Use a pre-defined template, if available - fn = jQuery.templates[ tmpl ]; - if ( !fn ) { - fn = tmplFn( jQuery( tmpl )[0].innerHTML ); + // It's a selector + tmpl = jQuery( tmpl )[0]; } - } else if ( typeof tmpl === "function" ) { + } + // Generate a reusable function that will serve as a template + // generator (and which will be cached). + if ( tmpl instanceof jQuery ) { + tmpl = tmpl.get(0); + } + if ( tmpl.nodeType && arguments.length === 1 && jQuery.attr( tmpl, "type") !== "text/html" ) { + // Return template context for an element, unless element is a script block template declaration. + while ( tmpl && !(tmplCtx = jQuery.data( tmpl, "tmplCtx" )) && (tmpl = tmpl.parentNode) ) {} + return tmplCtx || topCtx; + } + // If arguments.length > 2, render template against data, and return fragments ready for DOM insertion. + if ( typeof tmpl === "function" ) { fn = tmpl; } else if ( tmpl.nodeType ) { // If this is a template block, cache @@ -188,6 +178,9 @@ if ( !data ) { return fn; } + if ( !parentCtx ) { + return []; //Could throw... + } if ( typeof data === "function" ) { data = data.call( parentCtx.data || {}, parentCtx ); } @@ -198,7 +191,7 @@ [ newCtx( options, parentCtx, fn, data ) ]; return domFrag ? build( parentCtx ) : parentCtx.content; - + function build( ctx, parent ) { // Convert hierarchical content into flat string array // and finally return array of fragments ready for DOM insertion @@ -267,7 +260,7 @@ : (def["$2"]||"") ) + "_.push('"; - }) + + }) + "');}return _;" ); } diff --git a/jquery.tmplcmd.js b/jquery.tmplcmd.js new file mode 100644 index 0000000..f0d36a6 --- /dev/null +++ b/jquery.tmplcmd.js @@ -0,0 +1,51 @@ +/* + * jQuery Templating Plugin Commands + */ +(function(jQuery){ + jQuery.extend({ + tmplCmd: function( command, data, contexts ) { + var retCtxs = [], before; + data = jQuery.isArray( data ) ? data : [ data ]; + switch ( command ) { + case "find": + return find( data, contexts ); + case "replace": + data.reverse(); + } + jQuery.each( contexts ? find( data, contexts ) : data, function( i, ctx ) { + coll = ctx.nodes; + switch ( command ) { + case "update": + jQuery( coll[0] ).before( ctx ); + jQuery( coll ).remove(); + break; + case "remove": + jQuery( coll ).remove(); + if ( contexts ) { + contexts.splice( jQuery.inArray( ctx, contexts ), 1 ); + } + break; + case "replace": + before = before ? + jQuery( coll ).insertBefore( before )[0] : + jQuery( coll ).appendTo( coll[0].parentNode )[0]; + retCtxs.unshift( ctx ); + } + }); + return retCtxs; + function find( data, ctxs ) { + var found = [], ctx, ci, cl = ctxs.length, dataItem, di = 0, dl = data.length; + for ( ; di < dl; ) { + dataItem = data[di++]; + for ( ci = 0; ci < cl; ) { + ctx = ctxs[ci++]; + if ( ctx.data === dataItem ) { + found.push( ctx ); + } + } + } + return found; + } + } + }); +})(jQuery); diff --git a/movies/movies.css b/movies/movies.css index f817a3d..22e15d9 100644 --- a/movies/movies.css +++ b/movies/movies.css @@ -5,6 +5,16 @@ font-size: 12px; } +#about +{ + text-align:center; + margin: auto; + margin-bottom: 5px; + background-color: #F9F5FA; + padding: 3px; + width: 50%; +} + #pageBody { display: block; @@ -154,12 +164,9 @@ .cart td { height: 30px; - text-align:center; - font-size: 14px; - font-style: italic; - line-height:30px; border: 3px double #00509f; background-color: #F9F5FA; + text-align:center; } .cart .cart-true @@ -167,14 +174,35 @@ background-color: #E8DAEB; } -.cart input +.cart span.text +{ + color: #2F5071; + float:none; + height: 25px; + line-height: 25px; + font-size: 14px; + font-style: italic; + border: none; +} + +#submit, #cancel, #sort { + color: #2F5071; + font-weight: 700; float: right; - height:26px; - margin: 2px 15px 2px; + height: 25px; + line-height: 25px; + font-style: italic; + margin: 0 15px; +} + +#submit, #cancel, #sortBtn +{ + text-decoration: underline; + cursor: pointer; } -#cancel +#submit { float: left; } diff --git a/movies/movies.htm b/movies/movies.htm index 656b94c..7c35dbb 100644 --- a/movies/movies.htm +++ b/movies/movies.htm @@ -6,11 +6,11 @@ +
    + This is a demo of updates to the jQuery templating feature, proposed by Microsoft.
    + The source can be viewed here: NJE Templating Branch on GitHub +
    -

    -This is a demo of updates to the jQuery templating feature being proposed by Microsoft. -
    You can view the source on github, here: NJE Templating Branch on GitHub -

    Netflix: Book a Movie...

    + @@ -43,19 +43,29 @@

    Netflix: Book a Movie...

    ${Name}

    ${Synopsis}

    - +