Revert "Export"
[platform/framework/web/web-ui-fw.git] / libs / js / jquery-geo-1.0a4 / js / jsrender.js
1 /*! JsRender v1.0pre - (jsrender.js version: does not require jQuery): http://github.com/BorisMoore/jsrender */
2 /*
3  * Optimized version of jQuery Templates, fosr rendering to string, using 'codeless' markup.
4  *
5  * Copyright 2011, Boris Moore
6  * Released under the MIT License.
7  */
8 window.JsViews || window.jQuery && jQuery.views || (function( window, undefined ) {
9
10 var $, _$, JsViews, viewsNs, tmplEncode, render, rTag, registerTags, registerHelpers, extend,
11         FALSE = false, TRUE = true,
12         jQuery = window.jQuery, document = window.document,
13         htmlExpr = /^[^<]*(<[\w\W]+>)[^>]*$|\{\{\! /,
14         rPath = /^(true|false|null|[\d\.]+)|(\w+|\$(view|data|ctx|(\w+)))([\w\.]*)|((['"])(?:\\\1|.)*\7)$/g,
15         rParams = /(\$?[\w\.\[\]]+)(?:(\()|\s*(===|!==|==|!=|<|>|<=|>=)\s*|\s*(\=)\s*)?|(\,\s*)|\\?(\')|\\?(\")|(\))|(\s+)/g,
16         rNewLine = /\r?\n/g,
17         rUnescapeQuotes = /\\(['"])/g,
18         rEscapeQuotes = /\\?(['"])/g,
19         rBuildHash = /\x08([^\x08]+)\x08/g,
20         autoName = 0,
21         escapeMapForHtml = {
22                 "&": "&amp;",
23                 "<": "&lt;",
24                 ">": "&gt;"
25         },
26         htmlSpecialChar = /[\x00"&'<>]/g,
27         slice = Array.prototype.slice;
28
29 if ( jQuery ) {
30
31         ////////////////////////////////////////////////////////////////////////////////////////////////
32         // jQuery is loaded, so make $ the jQuery object
33         $ = jQuery;
34
35         $.fn.extend({
36                 // Use first wrapped element as template markup.
37                 // Return string obtained by rendering the template against data.
38                 render: function( data, context, parentView, path ) {
39                         return render( data, this[0], context, parentView, path );
40                 },
41
42                 // Consider the first wrapped element as a template declaration, and get the compiled template or store it as a named template.
43                 template: function( name, context ) {
44                         return $.template( name, this[0], context );
45                 }
46         });
47
48 } else {
49
50         ////////////////////////////////////////////////////////////////////////////////////////////////
51         // jQuery is not loaded. Make $ the JsViews object
52
53         // Map over the $ in case of overwrite
54         _$ = window.$;
55
56         window.JsViews = JsViews = window.$ = $ = {
57                 extend: function( target, source ) {
58                         var name;
59                         for ( name in source ) {
60                                 target[ name ] = source[ name ];
61                         }
62                         return target;
63                 },
64                 isArray: Array.isArray || function( obj ) {
65                         return Object.prototype.toString.call( obj ) === "[object Array]";
66                 },
67                 noConflict: function() {
68                         if ( window.$ === JsViews ) {
69                                 window.$ = _$;
70                         }
71                         return JsViews;
72                 }
73         };
74 }
75
76 extend = $.extend;
77
78 //=================
79 // View constructor
80 //=================
81
82 function View( context, path, parentView, data, template ) {
83         // Returns a view data structure for a new rendered instance of a template.
84         // The content field is a hierarchical array of strings and nested views.
85
86         parentView = parentView || { viewsCount:0, ctx: viewsNs.helpers };
87
88         var parentContext = parentView && parentView.ctx;
89
90         return {
91                 jsViews: "v1.0pre",
92                 path: path || "",
93                 // inherit context from parentView, merged with new context.
94                 itemNumber: ++parentView.viewsCount || 1,
95                 viewsCount: 0,
96                 tmpl: template,
97                 data: data || parentView.data || {},
98                 // Set additional context on this view (which will modify the context inherited from the parent, and be inherited by child views)
99                 ctx : context && context === parentContext
100                         ? parentContext
101                         : (parentContext ? extend( extend( {}, parentContext ), context ) : context||{}), 
102                         // If no jQuery, extend does not support chained copies - so limit to two parameters
103                 parent: parentView
104         };
105 }
106 extend( $, {
107         views: viewsNs = {
108                 templates: {},
109                 tags: {
110                         "if": function() {
111                                 var ifTag = this,
112                                         view = ifTag._view;
113                                 view.onElse = function( presenter, args ) {
114                                         var i = 0,
115                                                 l = args.length;
116                                         while ( l && !args[ i++ ]) {
117                                                 // Only render content if args.length === 0 (i.e. this is an else with no condition) or if a condition argument is truey
118                                                 if ( i === l ) {
119                                                         return "";
120                                                 }
121                                         }
122                                         view.onElse = undefined; // If condition satisfied, so won't run 'else'.
123                                         return render( view.data, presenter.tmpl, view.ctx, view);
124                                 };
125                                 return view.onElse( this, arguments );
126                         },
127                         "else": function() {
128                                 var view = this._view;
129                                 return view.onElse ? view.onElse( this, arguments ) : "";
130                         },
131                         each: function() {
132                                 var i, 
133                                         self = this,
134                                         result = "",
135                                         args = arguments,
136                                         l = args.length,
137                                         content = self.tmpl,
138                                         view = self._view;
139                                 for ( i = 0; i < l; i++ ) {
140                                         result += args[ i ] ? render( args[ i ], content, self.ctx || view.ctx, view, self._path, self._ctor ) : "";
141                                 }
142                                 return l ? result 
143                                         // If no data parameter, use the current $data from view, and render once
144                                         :  result + render( view.data, content, view.ctx, view, self._path, self.tag );
145                         },
146                         "=": function( value ) {
147                                 return value;
148                         },
149                         "*": function( value ) {
150                                 return value;
151                         }
152                 },
153                 helpers: {
154                         not: function( value ) {
155                                 return !value;
156                         }
157                 },
158                 allowCode: FALSE,
159                 debugMode: TRUE,
160                 err: function( e ) {
161                         return viewsNs.debugMode ? ("<br/><b>Error:</b> <em> " + (e.message || e) + ". </em>"): '""';
162                 },
163
164 //===============
165 // setDelimiters
166 //===============
167
168                 setDelimiters: function( openTag, closeTag ) {
169                         // Set or modify the delimiter characters for tags: "{{" and "}}"
170                         var firstCloseChar = closeTag.charAt( 0 ),
171                                 secondCloseChar = closeTag.charAt( 1 );
172                         openTag = "\\" + openTag.charAt( 0 ) + "\\" + openTag.charAt( 1 );
173                         closeTag = "\\" + firstCloseChar + "\\" + secondCloseChar;
174
175                         // Build regex with new delimiters
176                         //           {{
177                         rTag = openTag
178                                 //       #      tag    (followed by space,! or })             or equals or  code
179                                 + "(?:(?:(\\#)?(\\w+(?=[!\\s\\" + firstCloseChar + "]))" + "|(?:(\\=)|(\\*)))"
180                                 //     params
181                                 + "\\s*((?:[^\\" + firstCloseChar + "]|\\" + firstCloseChar + "(?!\\" + secondCloseChar + "))*?)"
182                                 //   encoding
183                                 + "(!(\\w*))?"
184                                 //        closeBlock
185                                 + "|(?:\\/([\\w\\$\\.\\[\\]]+)))"
186                         //  }}
187                         + closeTag;
188
189                         // Default rTag:     #    tag              equals code        params         encoding    closeBlock
190                         //      /\{\{(?:(?:(\#)?(\w+(?=[\s\}!]))|(?:(\=)|(\*)))((?:[^\}]|\}(?!\}))*?)(!(\w*))?|(?:\/([\w\$\.\[\]]+)))\}\}/g;
191
192                         rTag = new RegExp( rTag, "g" );
193                 },
194
195
196 //===============
197 // registerTags
198 //===============
199
200                 // Register declarative tag.
201                 registerTags: registerTags = function( name, tagFn ) {
202                         var key;
203                         if ( typeof name === "object" ) {
204                                 for ( key in name ) {
205                                         registerTags( key, name[ key ]);
206                                 }
207                         } else {
208                                 // Simple single property case.
209                                 viewsNs.tags[ name ] = tagFn;
210                         }
211                         return this;
212                 },
213
214 //===============
215 // registerHelpers
216 //===============
217
218                 // Register helper function for use in markup.
219                 registerHelpers: registerHelpers = function( name, helper ) {
220                         if ( typeof name === "object" ) {
221                                 // Object representation where property name is path and property value is value.
222                                 // TODO: We've discussed an "objectchange" event to capture all N property updates here. See TODO note above about propertyChanges.
223                                 var key;
224                                 for ( key in name ) {
225                                         registerHelpers( key, name[ key ]);
226                                 }
227                         } else {
228                                 // Simple single property case.
229                                 viewsNs.helpers[ name ] = helper;
230                         }
231                         return this;
232                 },
233
234 //===============
235 // tmpl.encode
236 //===============
237
238                 encode: function( encoding, text ) {
239                         return text
240                                 ? ( tmplEncode[ encoding || "html" ] || tmplEncode.html)( text ) // HTML encoding is the default
241                                 : "";
242                 },
243
244                 encoders: tmplEncode = {
245                         "none": function( text ) {
246                                 return text;
247                         },
248                         "html": function( text ) {
249                                 // HTML encoding helper: Replace < > & and ' and " by corresponding entities.
250                                 // Implementation, from Mike Samuel <msamuel@google.com>
251                                 return String( text ).replace( htmlSpecialChar, replacerForHtml );
252                         }
253                         //TODO add URL encoding, and perhaps other encoding helpers...
254                 },
255
256 //===============
257 // renderTag
258 //===============
259
260                 renderTag: function( tag, view, encode, content, tagProperties ) {
261                         // This is a tag call, with arguments: "tag", view, encode, content, presenter [, params...]
262                         var ret, ctx, name,
263                                 args = arguments,
264                                 presenters = viewsNs.presenters;
265                                 hash = tagProperties._hash,
266                                 tagFn = viewsNs.tags[ tag ];
267
268                         if ( !tagFn ) {
269                                 return "";
270                         }
271                         
272                         content = content && view.tmpl.nested[ content - 1 ];
273                         tagProperties.tmpl = tagProperties.tmpl || content || undefined;
274                         // Set the tmpl property to the content of the block tag, unless set as an override property on the tag
275                 
276                         if ( presenters && presenters[ tag ]) {
277                                 ctx = extend( extend( {}, tagProperties.ctx ), tagProperties );  
278                                 delete ctx.ctx;  
279                                 delete ctx._path;  
280                                 delete ctx.tmpl;
281                                 tagProperties.ctx = ctx;  
282                                 tagProperties._ctor = tag + (hash ? "=" + hash.slice( 0, -1 ) : "");
283
284                                 tagProperties = extend( extend( {}, tagFn ), tagProperties );
285                                 tagFn = viewsNs.tags.each; // Use each to render the layout template against the data
286                         } 
287
288                         tagProperties._encode = encode;
289                         tagProperties._view = view;
290                         ret = tagFn.apply( tagProperties, args.length > 5 ? slice.call( args, 5 ) : [view.data] );
291                         return ret || (ret === undefined ? "" : ret.toString()); // (If ret is the value 0 or false or null, will render to string) 
292                 }
293         },
294
295 //===============
296 // render
297 //===============
298
299         render: render = function( data, tmpl, context, parentView, path, tagName ) {
300                 // Render template against data as a tree of subviews (nested template), or as a string (top-level template).
301                 // tagName parameter for internal use only. Used for rendering templates registered as tags (which may have associated presenter objects)
302                 var i, l, dataItem, arrayView, content, result = "";
303
304                 if ( arguments.length === 2 && data.jsViews ) {
305                         parentView = data;
306                         context = parentView.ctx;
307                         data = parentView.data;
308                 }
309                 tmpl = $.template( tmpl );
310                 if ( !tmpl ) {
311                         return ""; // Could throw...
312                 }
313
314                 if ( $.isArray( data )) {
315                         // Create a view item for the array, whose child views correspond to each data item.
316                         arrayView = new View( context, path, parentView, data);
317                         l = data.length;
318                         for ( i = 0, l = data.length; i < l; i++ ) {
319                                 dataItem = data[ i ];
320                                 content = dataItem ? tmpl( dataItem, new View( context, path, arrayView, dataItem, tmpl, this )) : "";
321                                 result += viewsNs.activeViews ? "<!--item-->" + content + "<!--/item-->" : content;
322                         }
323                 } else {
324                         result += tmpl( data, new View( context, path, parentView, data, tmpl ));
325                 }
326
327                 return viewsNs.activeViews
328                         // If in activeView mode, include annotations
329                         ? "<!--tmpl(" + (path || "") + ") " + (tagName ? "tag=" + tagName : tmpl._name) + "-->" + result + "<!--/tmpl-->"
330                         // else return just the string result
331                         : result;
332         },
333
334 //===============
335 // template
336 //===============
337
338         template: function( name, tmpl ) {
339                 // Set:
340                 // Use $.template( name, tmpl ) to cache a named template,
341                 // where tmpl is a template string, a script element or a jQuery instance wrapping a script element, etc.
342                 // Use $( "selector" ).template( name ) to provide access by name to a script block template declaration.
343
344                 // Get:
345                 // Use $.template( name ) to access a cached template.
346                 // Also $( selectorToScriptBlock ).template(), or $.template( null, templateString )
347                 // will return the compiled template, without adding a name reference.
348                 // If templateString is not a selector, $.template( templateString ) is equivalent
349                 // to $.template( null, templateString ). To ensure a string is treated as a template,
350                 // include an HTML element, an HTML comment, or a template comment tag.
351
352                 if (tmpl) {
353                         // Compile template and associate with name
354                         if ( "" + tmpl === tmpl ) { // type string
355                                 // This is an HTML string being passed directly in.
356                                 tmpl = compile( tmpl );
357                         } else if ( jQuery && tmpl instanceof $ ) {
358                                 tmpl = tmpl[0];
359                         }
360                         if ( tmpl ) {
361                                 if ( jQuery && tmpl.nodeType ) {
362                                         // If this is a template block, use cached copy, or generate tmpl function and cache.
363                                         tmpl = $.data( tmpl, "tmpl" ) || $.data( tmpl, "tmpl", compile( tmpl.innerHTML ));
364                                 }
365                                 viewsNs.templates[ tmpl._name = tmpl._name || name || "_" + autoName++ ] = tmpl;
366                         }
367                         return tmpl;
368                 }
369                 // Return named compiled template
370                 return name
371                         ? "" + name !== name // not type string
372                                 ? (name._name
373                                         ? name // already compiled
374                                         : $.template( null, name ))
375                                 : viewsNs.templates[ name ] ||
376                                         // If not in map, treat as a selector. (If integrated with core, use quickExpr.exec)
377                                         $.template( null, htmlExpr.test( name ) ? name : try$( name ))
378                         : null;
379         }
380 });
381
382 viewsNs.setDelimiters( "{{", "}}" );
383
384 //=================
385 // compile template
386 //=================
387
388 // Generate a reusable function that will serve to render a template against data
389 // (Compile AST then build template function)
390
391 function parsePath( all, comp, object, viewDataCtx, viewProperty, path, string, quot ) {
392         return object
393                 ? ((viewDataCtx
394                         ? viewProperty
395                                 ? ("$view." + viewProperty)
396                                 : object
397                         :("$data." + object)
398                 )  + ( path || "" ))
399                 : string || (comp || "");
400 }
401
402 function compile( markup ) {
403         var newNode,
404                 loc = 0,
405                 stack = [],
406                 topNode = [],
407                 content = topNode,
408                 current = [,,topNode];
409
410         function pushPreceedingContent( shift ) {
411                 shift -= loc;
412                 if ( shift ) {
413                         content.push( markup.substr( loc, shift ).replace( rNewLine,"\\n"));
414                 }
415         }
416
417         function parseTag( all, isBlock, tagName, equals, code, params, useEncode, encode, closeBlock, index ) {
418                 // rTag    :    #    tagName          equals code        params         encode      closeBlock
419                 // /\{\{(?:(?:(\#)?(\w+(?=[\s\}!]))|(?:(\=)|(\*)))((?:[^\}]|\}(?!\}))*?)(!(\w*))?|(?:\/([\w\$\.\[\]]+)))\}\}/g;
420
421                 // Build abstract syntax tree: [ tagName, params, content, encode ]
422                 var named,
423                         hash = "",
424                         parenDepth = 0,
425                         quoted = FALSE, // boolean for string content in double qoutes
426                         aposed = FALSE; // or in single qoutes
427
428                 function parseParams( all, path, paren, comp, eq, comma, apos, quot, rightParen, space, index ) {
429                         //      path          paren eq      comma   apos   quot  rtPrn  space
430                         // /(\$?[\w\.\[\]]+)(?:(\()|(===)|(\=))?|(\,\s*)|\\?(\')|\\?(\")|(\))|(\s+)/g
431
432                         return aposed
433                                 // within single-quoted string
434                                 ? ( aposed = !apos, (aposed ? all : '"'))
435                                 : quoted
436                                         // within double-quoted string
437                                         ? ( quoted = !quot, (quoted ? all : '"'))
438                                         : comp
439                                                 // comparison
440                                                 ? ( path.replace( rPath, parsePath ) + comp)
441                                                 : eq
442                                                         // named param
443                                                         ? parenDepth ? "" :( named = TRUE, '\b' + path + ':')
444                                                         : paren
445                                                                 // function
446                                                                 ? (parenDepth++, path.replace( rPath, parsePath ) + '(')
447                                                                 : rightParen
448                                                                         // function
449                                                                         ? (parenDepth--, ")")
450                                                                         : path
451                                                                                 // path
452                                                                                 ? path.replace( rPath, parsePath )
453                                                                                 : comma
454                                                                                         ? ","
455                                                                                         : space
456                                                                                                 ? (parenDepth
457                                                                                                         ? ""
458                                                                                                         : named
459                                                                                                                 ? ( named = FALSE, "\b")
460                                                                                                                 : ","
461                                                                                                 )
462                                                                                                 : (aposed = apos, quoted = quot, '"');
463                 }
464
465                 tagName = tagName || equals;
466                 pushPreceedingContent( index );
467                 if ( code ) {
468                         if ( viewsNs.allowCode ) {
469                                 content.push([ "*", params.replace( rUnescapeQuotes, "$1" )]);
470                         }
471                 } else if ( tagName ) {
472                         if ( tagName === "else" ) {
473                                 current = stack.pop();
474                                 content = current[ 2 ];
475                                 isBlock = TRUE;
476                         }
477                         params = (params
478                                 ? (params + " ")
479                                         .replace( rParams, parseParams )
480                                         .replace( rBuildHash, function( all, keyValue, index ) {
481                                                 hash += keyValue + ",";
482                                                 return "";
483                                         })
484                                 : "");
485                         params = params.slice( 0, -1 );
486                         newNode = [
487                                 tagName,
488                                 useEncode ? encode || "none" : "",
489                                 isBlock && [],
490                                 "{" + hash + "_hash:'" +  hash + "',_path:'" + params + "'}",
491                                 params
492                         ];
493
494                         if ( isBlock ) {
495                                 stack.push( current );
496                                 current = newNode;
497                         }
498                         content.push( newNode );
499                 } else if ( closeBlock ) {
500                         current = stack.pop();
501                 }
502                 loc = index + all.length; // location marker - parsed up to here
503                 if ( !current ) {
504                         throw "Expected block tag";
505                 }
506                 content = current[ 2 ];
507         }
508         markup = markup.replace( rEscapeQuotes, "\\$1" );
509         markup.replace( rTag, parseTag );
510         pushPreceedingContent( markup.length );
511         return buildTmplFunction( topNode );
512 }
513
514 // Build javascript compiled template function, from AST
515 function buildTmplFunction( nodes ) {
516         var ret, node, i,
517                 nested = [],
518                 l = nodes.length,
519                 code = "try{var views="
520                         + (jQuery ? "jQuery" : "JsViews")
521                         + '.views,tag=views.renderTag,enc=views.encode,html=views.encoders.html,$ctx=$view && $view.ctx,result=""+\n\n';
522
523         for ( i = 0; i < l; i++ ) {
524                 node = nodes[ i ];
525                 if ( node[ 0 ] === "*" ) {
526                         code = code.slice( 0, i ? -1 : -3 ) + ";" + node[ 1 ] + ( i + 1 < l ? "result+=" : "" );
527                 } else if ( "" + node === node ) { // type string
528                         code += '"' + node + '"+';
529                 } else {
530                         var tag = node[ 0 ],
531                                 encode = node[ 1 ],
532                                 content = node[ 2 ],
533                                 obj = node[ 3 ],
534                                 params = node[ 4 ],
535                                 paramsOrEmptyString = params + '||"")+';
536
537                         if( content ) {
538                                 nested.push( buildTmplFunction( content ));
539                         }
540                         code += tag === "="
541                                 ? (!encode || encode === "html"
542                                         ? "html(" + paramsOrEmptyString
543                                         : encode === "none"
544                                                 ? ("(" + paramsOrEmptyString)
545                                                 : ('enc("' + encode + '",' + paramsOrEmptyString)
546                                 )
547                                 : 'tag("' + tag + '",$view,"' + ( encode || "" ) + '",'
548                                         + (content ? nested.length : '""') // For block tags, pass in the key (nested.length) to the nested content template
549                                         + "," + obj + (params ? "," : "") + params + ")+";
550                 }
551         }
552         ret = new Function( "$data, $view", code.slice( 0, -1) + ";return result;\n\n}catch(e){return views.err(e);}" );
553         ret.nested = nested;
554         return ret;
555 }
556
557 //========================== Private helper functions, used by code above ==========================
558
559 function replacerForHtml( ch ) {
560         // Original code from Mike Samuel <msamuel@google.com>
561         return escapeMapForHtml[ ch ]
562                 // Intentional assignment that caches the result of encoding ch.
563                 || ( escapeMapForHtml[ ch ] = "&#" + ch.charCodeAt( 0 ) + ";" );
564 }
565
566 function try$( selector ) {
567         // If selector is valid, return jQuery object, otherwise return (invalid) selector string
568         try {
569                 return $( selector );
570         } catch( e) {}
571         return selector;
572 }
573 })( window );