Skip to content

Commit

Permalink
Fixed issue 5 for parenting of {{wrap}} items, and associated issue of
Browse files Browse the repository at this point in the history
double events and potential memory leak.

Also a couple of other minor bug fixes.

Changed samples to always use parens when calling functions as template
tag parameters, since this is better practice. (Implicit function
invocation support only works in certain cases - basically when the
function is the only token in the expression, and not part of a more
complex expression. For this reason support for implicit function calls
may be removed later.)
  • Loading branch information
BorisMoore committed Aug 24, 2010
1 parent 466f1fc commit c09aa5e
Show file tree
Hide file tree
Showing 10 changed files with 40 additions and 46 deletions.
6 changes: 3 additions & 3 deletions demos/samplesCore/Interactive/tabsWrap.html
Expand Up @@ -40,15 +40,15 @@ <h3>Remote</h3>
<script id="tabsWrap" type="text/x-jquery-tmpl">
<table class="tabsView"><tbody>
<tr>
{{each tabs}}
{{each tabs()}}
<th class="${headerClass($index)}">
${$value}
</th>
{{/each}}
</tr>
<tr><td colspan="${tabCount}">
<tr><td colspan="${tabCount()}">
<div class="body">
{{html tabContent}}
{{html tabContent()}}
</div>
</td></tr>
</tbody></table>
Expand Down
2 changes: 1 addition & 1 deletion demos/samplesCore/Interactive/tabsWrapNested.html
Expand Up @@ -55,7 +55,7 @@ <h3>POST</h3>
<script id="tabsWrap" type="text/x-jquery-tmpl">
<table class="tabsView"><tbody>
<tr>
{{each tabs}}
{{each tabs()}}
<th class="${headerClass($index)}">
${$value}
</th>
Expand Down
2 changes: 1 addition & 1 deletion demos/samplesCore/Interactive/treeView.html
Expand Up @@ -18,7 +18,7 @@ <h1>Tree View</h1>

<script id="folderTmpl" type="text/x-jquery-tmpl">
<li class="content_${hasContent($item)}">
<img class="expand" src="resources/${expanderImage}.png" />
<img class="expand" src="resources/${expanderImage()}.png" />
<img class="folder" src="resources/folder.png" />
<span>${name}</span>
</li>
Expand Down
4 changes: 2 additions & 2 deletions demos/samplesCore/composition.html
Expand Up @@ -71,7 +71,7 @@

<script id="tmplPeople" type="text/x-jquery-tmpl">
{{tmpl "#tmplSeparator"}}
<tr class="${alternate(this.data, people)}"><td colspan="2"><a href="${url}">${getName}</a></td></tr>
<tr class="${alternate(this.data, people)}"><td colspan="2"><a href="${url}">${getName()}</a></td></tr>
{{if cities}}
{{tmpl(cities) getTemplate("City")}}
{{/if}}
Expand All @@ -83,7 +83,7 @@

<script id="tmplCity" type="text/x-jquery-tmpl">
{{tmpl "citySeparator"}}
<tr class="${alternate(this.parent.data, people)}"><td colspan="2"><b><i>City ${cityNumber}:</i></b></td></tr>
<tr class="${alternate(this.parent.data, people)}"><td colspan="2"><b><i>City ${cityNumber()}:</i></b></td></tr>
<tr class="${alternate(this.parent.data, people)}"><td><b>${name}</b></td><td>${state}</td></tr>
</script>

Expand Down
2 changes: 1 addition & 1 deletion demos/samplesCore/each.html
Expand Up @@ -64,7 +64,7 @@
</script>

<script id="tmplPeople" type="text/x-jquery-tmpl">
<tr class="${alternate($data, people)}"><td colspan="2"><a href="${url}">${getName}</a></td></tr>
<tr class="${alternate($data, people)}"><td colspan="2"><a href="${url}">${getName()}</a></td></tr>
{{each cities}}
<tr class="cityseparator"><td colspan="2"></td></tr>
<tr class="${alternate($data, people)}"><td colspan="2"><b><i>City ${index($value, cities)}:</i></b></td></tr>
Expand Down
8 changes: 4 additions & 4 deletions demos/samplesCore/parameters.html
Expand Up @@ -71,18 +71,18 @@
</script>

<script id="tmplPeople" type="text/x-jquery-tmpl">
<tr class="${alternate}"><td colspan="3"><a href="${url}">${getName}</a></td></tr>
<tr class="${alternate()}"><td colspan="3"><a href="${url}">${getName()}</a></td></tr>
{{tmpl "#tmplSeparator"}}
{{if getCityCount(startIndex, endIndex)}}
<tr class="${alternate}"><td colspan="3"><i>Favorite Cities</i></td></tr>
<tr class="${alternate()}"><td colspan="3"><i>Favorite Cities</i></td></tr>
{{each getCities(startIndex, endIndex)}}
{{tmpl(null, {type:"city"}) "#tmplSeparator"}}
<tr class="${alternate}">
<tr class="${alternate()}">
<td>${$index + 1}</td>
<td><b>${name}</b></td>
<td>${state}</td>
</tr>
<tr class="${alternate}"><td colspan="3"><i>${weather}...</i></td></tr>
<tr class="${alternate()}"><td colspan="3"><i>${weather}...</i></td></tr>
{{/each}}
{{tmpl "#tmplSeparator"}}
{{/if}}
Expand Down
4 changes: 2 additions & 2 deletions demos/samplesTmplPlus/composition.html
Expand Up @@ -67,7 +67,7 @@

<script id="tmplPeople" type="text/x-jquery-tmpl">
{{tmpl "#tmplSeparator"}}
<tr class="${alternate($data, people)}"><td colspan="2"><a href="${url}">${getName}</a></td></tr>
<tr class="${alternate($data, people)}"><td colspan="2"><a href="${url}">${getName()}</a></td></tr>
{{if cities}}
{{tmpl(cities) getTemplate("City")}}
{{/if}}
Expand All @@ -83,7 +83,7 @@

<script id="tmplCity" type="text/x-jquery-tmpl">
{{tmpl "#tmplCitySeparator"}}
<tr class="${alternate(this.parent.data, people)}"><td colspan="2"><b><i>City ${cityNumber}:</i></b></td></tr>
<tr class="${alternate(this.parent.data, people)}"><td colspan="2"><b><i>City ${cityNumber()}:</i></b></td></tr>
<tr class="${alternate(this.parent.data, people)}"><td><b>${name}</b></td><td>${state}</td></tr>
</script>

Expand Down
2 changes: 1 addition & 1 deletion demos/samplesTmplPlus/each.html
Expand Up @@ -65,7 +65,7 @@
</script>

<script id="tmplPeople" type="text/x-jquery-tmpl">
<tr class="${alternate($data, people)}"><td colspan="2"><a href="${url}">${getName}</a></td></tr>
<tr class="${alternate($data, people)}"><td colspan="2"><a href="${url}">${getName()}</a></td></tr>
{{each cities}}
<tr class="cityseparator"><td colspan="2"></td></tr>
<tr class="${alternate($data, people)}"><td colspan="2"><b><i>City ${index($value, cities)}:</i></b></td></tr>
Expand Down
8 changes: 4 additions & 4 deletions demos/samplesTmplPlus/parameters.html
Expand Up @@ -71,18 +71,18 @@
</script>

<script id="tmplPeople" type="text/x-jquery-tmpl">
<tr class="${alternate}"><td colspan="3"><a href="${url}">${getName}</a></td></tr>
<tr class="${alternate()}"><td colspan="3"><a href="${url}">${getName()}</a></td></tr>
{{tmpl "#tmplSeparator"}}
{{if getCityCount(startIndex, endIndex)}}
<tr class="${alternate}"><td colspan="3"><i>Favorite Cities</i></td></tr>
<tr class="${alternate()}"><td colspan="3"><i>Favorite Cities</i></td></tr>
{{each getCities(startIndex, endIndex)}}
{{tmpl(null, {type:"city"}) "#tmplSeparator"}}
<tr class="${alternate}">
<tr class="${alternate()}">
<td>${$index + 1}</td>
<td><b>${name}</b></td>
<td>${state}</td>
</tr>
<tr class="${alternate}"><td colspan="3"><i>${weather}...</i></td></tr>
<tr class="${alternate()}"><td colspan="3"><i>${weather}...</i></td></tr>
{{/each}}
{{tmpl "#tmplSeparator"}}
{{/if}}
Expand Down
48 changes: 21 additions & 27 deletions jquery.tmpl.js
Expand Up @@ -122,13 +122,16 @@
// This is a top-level tmpl call (not from a nested template using {{tmpl}})
parentItem = topTmplItem;
tmpl = jQuery.template[tmpl] || jQuery.template( null, tmpl );
wrappedItems = {}; // Any wrapped items will be rebuilt, since this is top level
} else if ( !tmpl ) {
// The template item is already associated with DOM - this is a refresh.
// Re-evaluate rendered template for the parentItem
tmpl = parentItem.tmpl;
newTmplItems[parentItem.key] = parentItem;
parentItem.nodes = [];
updateWrapped( parentItem );
if ( parentItem.wrapped ) {
updateWrapped( parentItem, parentItem.wrapped );
}
// Rebuild, without creating a new template item
return jQuery( build( parentItem, null, parentItem.tmpl( jQuery, parentItem ) ));
}
Expand All @@ -139,12 +142,7 @@
data = data.call( parentItem || {} );
}
if ( options && options.wrapped ) {
// Create template item for wrapped content, without rendering template
parentItem = newTmplItem( options, parentItem, null, data );
parentItem.key = ++itemKey;
wrappedItems[itemKey] = parentItem;
parentItem.tmpl = tmpl;
updateWrapped( parentItem );
updateWrapped( options, options.wrapped );
}
ret = jQuery.isArray( data ) ?
jQuery.map( data, function( dataItem ) {
Expand Down Expand Up @@ -266,16 +264,19 @@
function build( tmplItem, nested, content ) {
// Convert hierarchical content into flat string array
// and finally return array of fragments ready for DOM insertion
var frag, ret = jQuery.map( content, function( item ) {
var frag, ret = content ? jQuery.map( content, function( item ) {
return (typeof item === "string") ?
// Insert template item annotations, to be converted to jQuery.data( "tmplItem" ) when elems are inserted into DOM.
item.replace( /(<\w+)(?=[\s>])(?![^>]*_tmplitem)([^>]*)/g, "$1 " + tmplItmAtt + "=\"" + tmplItem.key + "\" $2" ) :
(tmplItem.key ? item.replace( /(<\w+)(?=[\s>])(?![^>]*_tmplitem)([^>]*)/g, "$1 " + tmplItmAtt + "=\"" + tmplItem.key + "\" $2" ) : item) :
// This is a child template item. Build nested template.
build( item, tmplItem, item._ctnt );
});
}) :
// If content is not defined, insert tmplItem directly. Not a template item. May be a string, or a string array, e.g. from {{html $item.html()}}.
tmplItem;
if ( nested ) {
return ret;
}

// top-level template
ret = ret.join("");

Expand Down Expand Up @@ -305,7 +306,7 @@
// Generate a reusable function that will serve to render a template against data
function buildTmplFn( markup ) {
return new Function("jQuery","$item",
"var $=jQuery,_=[],$data=$item.data;" +
"var $=jQuery,call,_=[],$data=$item.data;" +

// Introduce the data as local variables using with(){}
"with($data){_.push('" +
Expand Down Expand Up @@ -355,16 +356,14 @@
);
}

function updateWrapped( tmplItem ) {
if ( tmplItem.wrapped ) {
var wrapped = tmplItem.wrapped;
// Build the wrapped content
tmplItem._wrap = build( tmplItem, true,
jQuery.isArray( wrapped ) ? wrapped : [htmlExpr.test( wrapped ) ? wrapped : jQuery( wrapped ).html()]
).join("");
}
function updateWrapped( options, wrapped ) {
// Build the wrapped content.
options._wrap = build( options, true,
// Suport imperative scenario in which options.wrapped can be set to a selector or an HTML string.
jQuery.isArray( wrapped ) ? wrapped : [htmlExpr.test( wrapped ) ? wrapped : jQuery( wrapped ).html()]
).join("");
}

function unescape( args ) {
return args ? args.replace( /\\'/g, "'").replace(/\\\\/g, "\\" ) : null;
}
Expand All @@ -387,9 +386,6 @@
}
processItemKey( elem );
}
// Cannot remove temporary wrappedItem objects, since needed during updating of nested items. //wrappedItems = {};
// TODO - ensure no memory leaks

function processItemKey( el ) {
var pntKey, pntNode = el, pntItem, tmplItem, key;
// Ensure that each rendered template inserted into the DOM has its own template item,
Expand All @@ -404,8 +400,6 @@
tmplItem = wrappedItems[key];
tmplItem = newTmplItem( tmplItem, newTmplItems[pntNode]||wrappedItems[pntNode], null, true );
tmplItem.key = ++itemKey;
// Note that there is a remaining issue on parenting of wrappedItems.
// ...Currently there may be additional newTmplItems items wrapped contexts, leading to duplicate rendered events.
newTmplItems[itemKey] = tmplItem;
}
if ( cloneIndex ) {
Expand Down Expand Up @@ -451,7 +445,7 @@
return stack.pop();
}
var l = stack.length;
stack.push({ _: content, tmpl: tmpl, parent: l ? stack[l - 1].item : this, item:this, data: data, options: options });
stack.push({ _: content, tmpl: tmpl, item:this, data: data, options: options });
}

function tiNest( tmpl, data, options ) {
Expand All @@ -464,7 +458,7 @@
var options = call.options || {};
options.wrapped = wrapped;
// Apply the template, which may incorporate wrapped content,
return jQuery.tmpl( jQuery.template( call.tmpl ), call.data, options, call.parent );
return jQuery.tmpl( jQuery.template( call.tmpl ), call.data, options, call.item );
}

function tiHtml( filter, textOnly ) {
Expand Down

0 comments on commit c09aa5e

Please sign in to comment.