Resources/Web/js/jquery.tmpl.js
author moel.mich
Sun, 23 Sep 2012 18:37:43 +0000
changeset 380 573f1fff48b2
permissions -rw-r--r--
Fixed Issue 387. The new implementation does not try to start a ring 0 driver that already exists, but could not be opened. It tries to delete the driver and install it new. The driver is now stored temporarily in the application folder. The driver is not correctly removed on system shutdown.
moel@348
     1
/*!
moel@348
     2
 * jQuery Templates Plugin 1.0.0pre
moel@348
     3
 * http://github.com/jquery/jquery-tmpl
moel@348
     4
 * Requires jQuery 1.4.2
moel@348
     5
 *
moel@348
     6
 * Copyright 2011, Software Freedom Conservancy, Inc.
moel@348
     7
 * Dual licensed under the MIT or GPL Version 2 licenses.
moel@348
     8
 * http://jquery.org/license
moel@348
     9
 */
moel@348
    10
(function( jQuery, undefined ){
moel@348
    11
	var oldManip = jQuery.fn.domManip, tmplItmAtt = "_tmplitem", htmlExpr = /^[^<]*(<[\w\W]+>)[^>]*$|\{\{\! /,
moel@348
    12
		newTmplItems = {}, wrappedItems = {}, appendToTmplItems, topTmplItem = { key: 0, data: {} }, itemKey = 0, cloneIndex = 0, stack = [];
moel@348
    13
moel@348
    14
	function newTmplItem( options, parentItem, fn, data ) {
moel@348
    15
		// Returns a template item data structure for a new rendered instance of a template (a 'template item').
moel@348
    16
		// The content field is a hierarchical array of strings and nested items (to be
moel@348
    17
		// removed and replaced by nodes field of dom elements, once inserted in DOM).
moel@348
    18
		var newItem = {
moel@348
    19
			data: data || (data === 0 || data === false) ? data : (parentItem ? parentItem.data : {}),
moel@348
    20
			_wrap: parentItem ? parentItem._wrap : null,
moel@348
    21
			tmpl: null,
moel@348
    22
			parent: parentItem || null,
moel@348
    23
			nodes: [],
moel@348
    24
			calls: tiCalls,
moel@348
    25
			nest: tiNest,
moel@348
    26
			wrap: tiWrap,
moel@348
    27
			html: tiHtml,
moel@348
    28
			update: tiUpdate
moel@348
    29
		};
moel@348
    30
		if ( options ) {
moel@348
    31
			jQuery.extend( newItem, options, { nodes: [], parent: parentItem });
moel@348
    32
		}
moel@348
    33
		if ( fn ) {
moel@348
    34
			// Build the hierarchical content to be used during insertion into DOM
moel@348
    35
			newItem.tmpl = fn;
moel@348
    36
			newItem._ctnt = newItem._ctnt || newItem.tmpl( jQuery, newItem );
moel@348
    37
			newItem.key = ++itemKey;
moel@348
    38
			// Keep track of new template item, until it is stored as jQuery Data on DOM element
moel@348
    39
			(stack.length ? wrappedItems : newTmplItems)[itemKey] = newItem;
moel@348
    40
		}
moel@348
    41
		return newItem;
moel@348
    42
	}
moel@348
    43
moel@348
    44
	// Override appendTo etc., in order to provide support for targeting multiple elements. (This code would disappear if integrated in jquery core).
moel@348
    45
	jQuery.each({
moel@348
    46
		appendTo: "append",
moel@348
    47
		prependTo: "prepend",
moel@348
    48
		insertBefore: "before",
moel@348
    49
		insertAfter: "after",
moel@348
    50
		replaceAll: "replaceWith"
moel@348
    51
	}, function( name, original ) {
moel@348
    52
		jQuery.fn[ name ] = function( selector ) {
moel@348
    53
			var ret = [], insert = jQuery( selector ), elems, i, l, tmplItems,
moel@348
    54
				parent = this.length === 1 && this[0].parentNode;
moel@348
    55
moel@348
    56
			appendToTmplItems = newTmplItems || {};
moel@348
    57
			if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
moel@348
    58
				insert[ original ]( this[0] );
moel@348
    59
				ret = this;
moel@348
    60
			} else {
moel@348
    61
				for ( i = 0, l = insert.length; i < l; i++ ) {
moel@348
    62
					cloneIndex = i;
moel@348
    63
					elems = (i > 0 ? this.clone(true) : this).get();
moel@348
    64
					jQuery( insert[i] )[ original ]( elems );
moel@348
    65
					ret = ret.concat( elems );
moel@348
    66
				}
moel@348
    67
				cloneIndex = 0;
moel@348
    68
				ret = this.pushStack( ret, name, insert.selector );
moel@348
    69
			}
moel@348
    70
			tmplItems = appendToTmplItems;
moel@348
    71
			appendToTmplItems = null;
moel@348
    72
			jQuery.tmpl.complete( tmplItems );
moel@348
    73
			return ret;
moel@348
    74
		};
moel@348
    75
	});
moel@348
    76
moel@348
    77
	jQuery.fn.extend({
moel@348
    78
		// Use first wrapped element as template markup.
moel@348
    79
		// Return wrapped set of template items, obtained by rendering template against data.
moel@348
    80
		tmpl: function( data, options, parentItem ) {
moel@348
    81
			return jQuery.tmpl( this[0], data, options, parentItem );
moel@348
    82
		},
moel@348
    83
moel@348
    84
		// Find which rendered template item the first wrapped DOM element belongs to
moel@348
    85
		tmplItem: function() {
moel@348
    86
			return jQuery.tmplItem( this[0] );
moel@348
    87
		},
moel@348
    88
moel@348
    89
		// Consider the first wrapped element as a template declaration, and get the compiled template or store it as a named template.
moel@348
    90
		template: function( name ) {
moel@348
    91
			return jQuery.template( name, this[0] );
moel@348
    92
		},
moel@348
    93
moel@348
    94
		domManip: function( args, table, callback, options ) {
moel@348
    95
			if ( args[0] && jQuery.isArray( args[0] )) {
moel@348
    96
				var dmArgs = jQuery.makeArray( arguments ), elems = args[0], elemsLength = elems.length, i = 0, tmplItem;
moel@348
    97
				while ( i < elemsLength && !(tmplItem = jQuery.data( elems[i++], "tmplItem" ))) {}
moel@348
    98
				if ( tmplItem && cloneIndex ) {
moel@348
    99
					dmArgs[2] = function( fragClone ) {
moel@348
   100
						// Handler called by oldManip when rendered template has been inserted into DOM.
moel@348
   101
						jQuery.tmpl.afterManip( this, fragClone, callback );
moel@348
   102
					};
moel@348
   103
				}
moel@348
   104
				oldManip.apply( this, dmArgs );
moel@348
   105
			} else {
moel@348
   106
				oldManip.apply( this, arguments );
moel@348
   107
			}
moel@348
   108
			cloneIndex = 0;
moel@348
   109
			if ( !appendToTmplItems ) {
moel@348
   110
				jQuery.tmpl.complete( newTmplItems );
moel@348
   111
			}
moel@348
   112
			return this;
moel@348
   113
		}
moel@348
   114
	});
moel@348
   115
moel@348
   116
	jQuery.extend({
moel@348
   117
		// Return wrapped set of template items, obtained by rendering template against data.
moel@348
   118
		tmpl: function( tmpl, data, options, parentItem ) {
moel@348
   119
			var ret, topLevel = !parentItem;
moel@348
   120
			if ( topLevel ) {
moel@348
   121
				// This is a top-level tmpl call (not from a nested template using {{tmpl}})
moel@348
   122
				parentItem = topTmplItem;
moel@348
   123
				tmpl = jQuery.template[tmpl] || jQuery.template( null, tmpl );
moel@348
   124
				wrappedItems = {}; // Any wrapped items will be rebuilt, since this is top level
moel@348
   125
			} else if ( !tmpl ) {
moel@348
   126
				// The template item is already associated with DOM - this is a refresh.
moel@348
   127
				// Re-evaluate rendered template for the parentItem
moel@348
   128
				tmpl = parentItem.tmpl;
moel@348
   129
				newTmplItems[parentItem.key] = parentItem;
moel@348
   130
				parentItem.nodes = [];
moel@348
   131
				if ( parentItem.wrapped ) {
moel@348
   132
					updateWrapped( parentItem, parentItem.wrapped );
moel@348
   133
				}
moel@348
   134
				// Rebuild, without creating a new template item
moel@348
   135
				return jQuery( build( parentItem, null, parentItem.tmpl( jQuery, parentItem ) ));
moel@348
   136
			}
moel@348
   137
			if ( !tmpl ) {
moel@348
   138
				return []; // Could throw...
moel@348
   139
			}
moel@348
   140
			if ( typeof data === "function" ) {
moel@348
   141
				data = data.call( parentItem || {} );
moel@348
   142
			}
moel@348
   143
			if ( options && options.wrapped ) {
moel@348
   144
				updateWrapped( options, options.wrapped );
moel@348
   145
			}
moel@348
   146
			ret = jQuery.isArray( data ) ?
moel@348
   147
				jQuery.map( data, function( dataItem ) {
moel@348
   148
					return dataItem ? newTmplItem( options, parentItem, tmpl, dataItem ) : null;
moel@348
   149
				}) :
moel@348
   150
				[ newTmplItem( options, parentItem, tmpl, data ) ];
moel@348
   151
			return topLevel ? jQuery( build( parentItem, null, ret ) ) : ret;
moel@348
   152
		},
moel@348
   153
moel@348
   154
		// Return rendered template item for an element.
moel@348
   155
		tmplItem: function( elem ) {
moel@348
   156
			var tmplItem;
moel@348
   157
			if ( elem instanceof jQuery ) {
moel@348
   158
				elem = elem[0];
moel@348
   159
			}
moel@348
   160
			while ( elem && elem.nodeType === 1 && !(tmplItem = jQuery.data( elem, "tmplItem" )) && (elem = elem.parentNode) ) {}
moel@348
   161
			return tmplItem || topTmplItem;
moel@348
   162
		},
moel@348
   163
moel@348
   164
		// Set:
moel@348
   165
		// Use $.template( name, tmpl ) to cache a named template,
moel@348
   166
		// where tmpl is a template string, a script element or a jQuery instance wrapping a script element, etc.
moel@348
   167
		// Use $( "selector" ).template( name ) to provide access by name to a script block template declaration.
moel@348
   168
moel@348
   169
		// Get:
moel@348
   170
		// Use $.template( name ) to access a cached template.
moel@348
   171
		// Also $( selectorToScriptBlock ).template(), or $.template( null, templateString )
moel@348
   172
		// will return the compiled template, without adding a name reference.
moel@348
   173
		// If templateString includes at least one HTML tag, $.template( templateString ) is equivalent
moel@348
   174
		// to $.template( null, templateString )
moel@348
   175
		template: function( name, tmpl ) {
moel@348
   176
			if (tmpl) {
moel@348
   177
				// Compile template and associate with name
moel@348
   178
				if ( typeof tmpl === "string" ) {
moel@348
   179
					// This is an HTML string being passed directly in.
moel@348
   180
					tmpl = buildTmplFn( tmpl );
moel@348
   181
				} else if ( tmpl instanceof jQuery ) {
moel@348
   182
					tmpl = tmpl[0] || {};
moel@348
   183
				}
moel@348
   184
				if ( tmpl.nodeType ) {
moel@348
   185
					// If this is a template block, use cached copy, or generate tmpl function and cache.
moel@348
   186
					tmpl = jQuery.data( tmpl, "tmpl" ) || jQuery.data( tmpl, "tmpl", buildTmplFn( tmpl.innerHTML ));
moel@348
   187
					// Issue: In IE, if the container element is not a script block, the innerHTML will remove quotes from attribute values whenever the value does not include white space.
moel@348
   188
					// This means that foo="${x}" will not work if the value of x includes white space: foo="${x}" -> foo=value of x.
moel@348
   189
					// To correct this, include space in tag: foo="${ x }" -> foo="value of x"
moel@348
   190
				}
moel@348
   191
				return typeof name === "string" ? (jQuery.template[name] = tmpl) : tmpl;
moel@348
   192
			}
moel@348
   193
			// Return named compiled template
moel@348
   194
			return name ? (typeof name !== "string" ? jQuery.template( null, name ):
moel@348
   195
				(jQuery.template[name] ||
moel@348
   196
					// If not in map, and not containing at least on HTML tag, treat as a selector.
moel@348
   197
					// (If integrated with core, use quickExpr.exec)
moel@348
   198
					jQuery.template( null, htmlExpr.test( name ) ? name : jQuery( name )))) : null;
moel@348
   199
		},
moel@348
   200
moel@348
   201
		encode: function( text ) {
moel@348
   202
			// Do HTML encoding replacing < > & and ' and " by corresponding entities.
moel@348
   203
			return ("" + text).split("<").join("&lt;").split(">").join("&gt;").split('"').join("&#34;").split("'").join("&#39;");
moel@348
   204
		}
moel@348
   205
	});
moel@348
   206
moel@348
   207
	jQuery.extend( jQuery.tmpl, {
moel@348
   208
		tag: {
moel@348
   209
			"tmpl": {
moel@348
   210
				_default: { $2: "null" },
moel@348
   211
				open: "if($notnull_1){__=__.concat($item.nest($1,$2));}"
moel@348
   212
				// tmpl target parameter can be of type function, so use $1, not $1a (so not auto detection of functions)
moel@348
   213
				// This means that {{tmpl foo}} treats foo as a template (which IS a function).
moel@348
   214
				// Explicit parens can be used if foo is a function that returns a template: {{tmpl foo()}}.
moel@348
   215
			},
moel@348
   216
			"wrap": {
moel@348
   217
				_default: { $2: "null" },
moel@348
   218
				open: "$item.calls(__,$1,$2);__=[];",
moel@348
   219
				close: "call=$item.calls();__=call._.concat($item.wrap(call,__));"
moel@348
   220
			},
moel@348
   221
			"each": {
moel@348
   222
				_default: { $2: "$index, $value" },
moel@348
   223
				open: "if($notnull_1){$.each($1a,function($2){with(this){",
moel@348
   224
				close: "}});}"
moel@348
   225
			},
moel@348
   226
			"if": {
moel@348
   227
				open: "if(($notnull_1) && $1a){",
moel@348
   228
				close: "}"
moel@348
   229
			},
moel@348
   230
			"else": {
moel@348
   231
				_default: { $1: "true" },
moel@348
   232
				open: "}else if(($notnull_1) && $1a){"
moel@348
   233
			},
moel@348
   234
			"html": {
moel@348
   235
				// Unecoded expression evaluation.
moel@348
   236
				open: "if($notnull_1){__.push($1a);}"
moel@348
   237
			},
moel@348
   238
			"=": {
moel@348
   239
				// Encoded expression evaluation. Abbreviated form is ${}.
moel@348
   240
				_default: { $1: "$data" },
moel@348
   241
				open: "if($notnull_1){__.push($.encode($1a));}"
moel@348
   242
			},
moel@348
   243
			"!": {
moel@348
   244
				// Comment tag. Skipped by parser
moel@348
   245
				open: ""
moel@348
   246
			}
moel@348
   247
		},
moel@348
   248
moel@348
   249
		// This stub can be overridden, e.g. in jquery.tmplPlus for providing rendered events
moel@348
   250
		complete: function( items ) {
moel@348
   251
			newTmplItems = {};
moel@348
   252
		},
moel@348
   253
moel@348
   254
		// Call this from code which overrides domManip, or equivalent
moel@348
   255
		// Manage cloning/storing template items etc.
moel@348
   256
		afterManip: function afterManip( elem, fragClone, callback ) {
moel@348
   257
			// Provides cloned fragment ready for fixup prior to and after insertion into DOM
moel@348
   258
			var content = fragClone.nodeType === 11 ?
moel@348
   259
				jQuery.makeArray(fragClone.childNodes) :
moel@348
   260
				fragClone.nodeType === 1 ? [fragClone] : [];
moel@348
   261
moel@348
   262
			// Return fragment to original caller (e.g. append) for DOM insertion
moel@348
   263
			callback.call( elem, fragClone );
moel@348
   264
moel@348
   265
			// Fragment has been inserted:- Add inserted nodes to tmplItem data structure. Replace inserted element annotations by jQuery.data.
moel@348
   266
			storeTmplItems( content );
moel@348
   267
			cloneIndex++;
moel@348
   268
		}
moel@348
   269
	});
moel@348
   270
moel@348
   271
	//========================== Private helper functions, used by code above ==========================
moel@348
   272
moel@348
   273
	function build( tmplItem, nested, content ) {
moel@348
   274
		// Convert hierarchical content into flat string array
moel@348
   275
		// and finally return array of fragments ready for DOM insertion
moel@348
   276
		var frag, ret = content ? jQuery.map( content, function( item ) {
moel@348
   277
			return (typeof item === "string") ?
moel@348
   278
				// Insert template item annotations, to be converted to jQuery.data( "tmplItem" ) when elems are inserted into DOM.
moel@348
   279
				(tmplItem.key ? item.replace( /(<\w+)(?=[\s>])(?![^>]*_tmplitem)([^>]*)/g, "$1 " + tmplItmAtt + "=\"" + tmplItem.key + "\" $2" ) : item) :
moel@348
   280
				// This is a child template item. Build nested template.
moel@348
   281
				build( item, tmplItem, item._ctnt );
moel@348
   282
		}) :
moel@348
   283
		// 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()}}.
moel@348
   284
		tmplItem;
moel@348
   285
		if ( nested ) {
moel@348
   286
			return ret;
moel@348
   287
		}
moel@348
   288
moel@348
   289
		// top-level template
moel@348
   290
		ret = ret.join("");
moel@348
   291
moel@348
   292
		// Support templates which have initial or final text nodes, or consist only of text
moel@348
   293
		// Also support HTML entities within the HTML markup.
moel@348
   294
		ret.replace( /^\s*([^<\s][^<]*)?(<[\w\W]+>)([^>]*[^>\s])?\s*$/, function( all, before, middle, after) {
moel@348
   295
			frag = jQuery( middle ).get();
moel@348
   296
moel@348
   297
			storeTmplItems( frag );
moel@348
   298
			if ( before ) {
moel@348
   299
				frag = unencode( before ).concat(frag);
moel@348
   300
			}
moel@348
   301
			if ( after ) {
moel@348
   302
				frag = frag.concat(unencode( after ));
moel@348
   303
			}
moel@348
   304
		});
moel@348
   305
		return frag ? frag : unencode( ret );
moel@348
   306
	}
moel@348
   307
moel@348
   308
	function unencode( text ) {
moel@348
   309
		// Use createElement, since createTextNode will not render HTML entities correctly
moel@348
   310
		var el = document.createElement( "div" );
moel@348
   311
		el.innerHTML = text;
moel@348
   312
		return jQuery.makeArray(el.childNodes);
moel@348
   313
	}
moel@348
   314
moel@348
   315
	// Generate a reusable function that will serve to render a template against data
moel@348
   316
	function buildTmplFn( markup ) {
moel@348
   317
		return new Function("jQuery","$item",
moel@348
   318
			// Use the variable __ to hold a string array while building the compiled template. (See https://github.com/jquery/jquery-tmpl/issues#issue/10).
moel@348
   319
			"var $=jQuery,call,__=[],$data=$item.data;" +
moel@348
   320
moel@348
   321
			// Introduce the data as local variables using with(){}
moel@348
   322
			"with($data){__.push('" +
moel@348
   323
moel@348
   324
			// Convert the template into pure JavaScript
moel@348
   325
			jQuery.trim(markup)
moel@348
   326
				.replace( /([\\'])/g, "\\$1" )
moel@348
   327
				.replace( /[\r\t\n]/g, " " )
moel@348
   328
				.replace( /\$\{([^\}]*)\}/g, "{{= $1}}" )
moel@348
   329
				.replace( /\{\{(\/?)(\w+|.)(?:\(((?:[^\}]|\}(?!\}))*?)?\))?(?:\s+(.*?)?)?(\(((?:[^\}]|\}(?!\}))*?)\))?\s*\}\}/g,
moel@348
   330
				function( all, slash, type, fnargs, target, parens, args ) {
moel@348
   331
					var tag = jQuery.tmpl.tag[ type ], def, expr, exprAutoFnDetect;
moel@348
   332
					if ( !tag ) {
moel@348
   333
						throw "Unknown template tag: " + type;
moel@348
   334
					}
moel@348
   335
					def = tag._default || [];
moel@348
   336
					if ( parens && !/\w$/.test(target)) {
moel@348
   337
						target += parens;
moel@348
   338
						parens = "";
moel@348
   339
					}
moel@348
   340
					if ( target ) {
moel@348
   341
						target = unescape( target );
moel@348
   342
						args = args ? ("," + unescape( args ) + ")") : (parens ? ")" : "");
moel@348
   343
						// Support for target being things like a.toLowerCase();
moel@348
   344
						// In that case don't call with template item as 'this' pointer. Just evaluate...
moel@348
   345
						expr = parens ? (target.indexOf(".") > -1 ? target + unescape( parens ) : ("(" + target + ").call($item" + args)) : target;
moel@348
   346
						exprAutoFnDetect = parens ? expr : "(typeof(" + target + ")==='function'?(" + target + ").call($item):(" + target + "))";
moel@348
   347
					} else {
moel@348
   348
						exprAutoFnDetect = expr = def.$1 || "null";
moel@348
   349
					}
moel@348
   350
					fnargs = unescape( fnargs );
moel@348
   351
					return "');" +
moel@348
   352
						tag[ slash ? "close" : "open" ]
moel@348
   353
							.split( "$notnull_1" ).join( target ? "typeof(" + target + ")!=='undefined' && (" + target + ")!=null" : "true" )
moel@348
   354
							.split( "$1a" ).join( exprAutoFnDetect )
moel@348
   355
							.split( "$1" ).join( expr )
moel@348
   356
							.split( "$2" ).join( fnargs || def.$2 || "" ) +
moel@348
   357
						"__.push('";
moel@348
   358
				}) +
moel@348
   359
			"');}return __;"
moel@348
   360
		);
moel@348
   361
	}
moel@348
   362
	function updateWrapped( options, wrapped ) {
moel@348
   363
		// Build the wrapped content.
moel@348
   364
		options._wrap = build( options, true,
moel@348
   365
			// Suport imperative scenario in which options.wrapped can be set to a selector or an HTML string.
moel@348
   366
			jQuery.isArray( wrapped ) ? wrapped : [htmlExpr.test( wrapped ) ? wrapped : jQuery( wrapped ).html()]
moel@348
   367
		).join("");
moel@348
   368
	}
moel@348
   369
moel@348
   370
	function unescape( args ) {
moel@348
   371
		return args ? args.replace( /\\'/g, "'").replace(/\\\\/g, "\\" ) : null;
moel@348
   372
	}
moel@348
   373
	function outerHtml( elem ) {
moel@348
   374
		var div = document.createElement("div");
moel@348
   375
		div.appendChild( elem.cloneNode(true) );
moel@348
   376
		return div.innerHTML;
moel@348
   377
	}
moel@348
   378
moel@348
   379
	// Store template items in jQuery.data(), ensuring a unique tmplItem data data structure for each rendered template instance.
moel@348
   380
	function storeTmplItems( content ) {
moel@348
   381
		var keySuffix = "_" + cloneIndex, elem, elems, newClonedItems = {}, i, l, m;
moel@348
   382
		for ( i = 0, l = content.length; i < l; i++ ) {
moel@348
   383
			if ( (elem = content[i]).nodeType !== 1 ) {
moel@348
   384
				continue;
moel@348
   385
			}
moel@348
   386
			elems = elem.getElementsByTagName("*");
moel@348
   387
			for ( m = elems.length - 1; m >= 0; m-- ) {
moel@348
   388
				processItemKey( elems[m] );
moel@348
   389
			}
moel@348
   390
			processItemKey( elem );
moel@348
   391
		}
moel@348
   392
		function processItemKey( el ) {
moel@348
   393
			var pntKey, pntNode = el, pntItem, tmplItem, key;
moel@348
   394
			// Ensure that each rendered template inserted into the DOM has its own template item,
moel@348
   395
			if ( (key = el.getAttribute( tmplItmAtt ))) {
moel@348
   396
				while ( pntNode.parentNode && (pntNode = pntNode.parentNode).nodeType === 1 && !(pntKey = pntNode.getAttribute( tmplItmAtt ))) { }
moel@348
   397
				if ( pntKey !== key ) {
moel@348
   398
					// The next ancestor with a _tmplitem expando is on a different key than this one.
moel@348
   399
					// So this is a top-level element within this template item
moel@348
   400
					// Set pntNode to the key of the parentNode, or to 0 if pntNode.parentNode is null, or pntNode is a fragment.
moel@348
   401
					pntNode = pntNode.parentNode ? (pntNode.nodeType === 11 ? 0 : (pntNode.getAttribute( tmplItmAtt ) || 0)) : 0;
moel@348
   402
					if ( !(tmplItem = newTmplItems[key]) ) {
moel@348
   403
						// The item is for wrapped content, and was copied from the temporary parent wrappedItem.
moel@348
   404
						tmplItem = wrappedItems[key];
moel@348
   405
						tmplItem = newTmplItem( tmplItem, newTmplItems[pntNode]||wrappedItems[pntNode] );
moel@348
   406
						tmplItem.key = ++itemKey;
moel@348
   407
						newTmplItems[itemKey] = tmplItem;
moel@348
   408
					}
moel@348
   409
					if ( cloneIndex ) {
moel@348
   410
						cloneTmplItem( key );
moel@348
   411
					}
moel@348
   412
				}
moel@348
   413
				el.removeAttribute( tmplItmAtt );
moel@348
   414
			} else if ( cloneIndex && (tmplItem = jQuery.data( el, "tmplItem" )) ) {
moel@348
   415
				// This was a rendered element, cloned during append or appendTo etc.
moel@348
   416
				// TmplItem stored in jQuery data has already been cloned in cloneCopyEvent. We must replace it with a fresh cloned tmplItem.
moel@348
   417
				cloneTmplItem( tmplItem.key );
moel@348
   418
				newTmplItems[tmplItem.key] = tmplItem;
moel@348
   419
				pntNode = jQuery.data( el.parentNode, "tmplItem" );
moel@348
   420
				pntNode = pntNode ? pntNode.key : 0;
moel@348
   421
			}
moel@348
   422
			if ( tmplItem ) {
moel@348
   423
				pntItem = tmplItem;
moel@348
   424
				// Find the template item of the parent element.
moel@348
   425
				// (Using !=, not !==, since pntItem.key is number, and pntNode may be a string)
moel@348
   426
				while ( pntItem && pntItem.key != pntNode ) {
moel@348
   427
					// Add this element as a top-level node for this rendered template item, as well as for any
moel@348
   428
					// ancestor items between this item and the item of its parent element
moel@348
   429
					pntItem.nodes.push( el );
moel@348
   430
					pntItem = pntItem.parent;
moel@348
   431
				}
moel@348
   432
				// Delete content built during rendering - reduce API surface area and memory use, and avoid exposing of stale data after rendering...
moel@348
   433
				delete tmplItem._ctnt;
moel@348
   434
				delete tmplItem._wrap;
moel@348
   435
				// Store template item as jQuery data on the element
moel@348
   436
				jQuery.data( el, "tmplItem", tmplItem );
moel@348
   437
			}
moel@348
   438
			function cloneTmplItem( key ) {
moel@348
   439
				key = key + keySuffix;
moel@348
   440
				tmplItem = newClonedItems[key] =
moel@348
   441
					(newClonedItems[key] || newTmplItem( tmplItem, newTmplItems[tmplItem.parent.key + keySuffix] || tmplItem.parent ));
moel@348
   442
			}
moel@348
   443
		}
moel@348
   444
	}
moel@348
   445
moel@348
   446
	//---- Helper functions for template item ----
moel@348
   447
moel@348
   448
	function tiCalls( content, tmpl, data, options ) {
moel@348
   449
		if ( !content ) {
moel@348
   450
			return stack.pop();
moel@348
   451
		}
moel@348
   452
		stack.push({ _: content, tmpl: tmpl, item:this, data: data, options: options });
moel@348
   453
	}
moel@348
   454
moel@348
   455
	function tiNest( tmpl, data, options ) {
moel@348
   456
		// nested template, using {{tmpl}} tag
moel@348
   457
		return jQuery.tmpl( jQuery.template( tmpl ), data, options, this );
moel@348
   458
	}
moel@348
   459
moel@348
   460
	function tiWrap( call, wrapped ) {
moel@348
   461
		// nested template, using {{wrap}} tag
moel@348
   462
		var options = call.options || {};
moel@348
   463
		options.wrapped = wrapped;
moel@348
   464
		// Apply the template, which may incorporate wrapped content,
moel@348
   465
		return jQuery.tmpl( jQuery.template( call.tmpl ), call.data, options, call.item );
moel@348
   466
	}
moel@348
   467
moel@348
   468
	function tiHtml( filter, textOnly ) {
moel@348
   469
		var wrapped = this._wrap;
moel@348
   470
		return jQuery.map(
moel@348
   471
			jQuery( jQuery.isArray( wrapped ) ? wrapped.join("") : wrapped ).filter( filter || "*" ),
moel@348
   472
			function(e) {
moel@348
   473
				return textOnly ?
moel@348
   474
					e.innerText || e.textContent :
moel@348
   475
					e.outerHTML || outerHtml(e);
moel@348
   476
			});
moel@348
   477
	}
moel@348
   478
moel@348
   479
	function tiUpdate() {
moel@348
   480
		var coll = this.nodes;
moel@348
   481
		jQuery.tmpl( null, null, null, this).insertBefore( coll[0] );
moel@348
   482
		jQuery( coll ).remove();
moel@348
   483
	}
moel@348
   484
})( jQuery );