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