Skip to content

Commit

Permalink
Fix for regression in #7.
Browse files Browse the repository at this point in the history
Ongoing work on supporting Presenter pattern.
  • Loading branch information
BorisMoore committed Nov 13, 2011
1 parent 73c3b62 commit ab3fddd
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 67 deletions.
12 changes: 5 additions & 7 deletions README.md
@@ -1,9 +1,7 @@
<h2>JsRender: Next-generation jQuery Templates</h2>

<em>Optimized for high-performance pure string-based rendering, without DOM or jQuery dependency. (Current version - "codeless" tag syntax)</em>

To view demo pages (on gh-branch) navigate to [http://borismoore.github.com/jsrender/demos/index.html](http://borismoore.github.com/jsrender/demos/index.html).
## JsRender: Next-generation jQuery Templates
_Optimized for high-performance pure string-based rendering, without DOM or jQuery dependency._<br/>
To view demo pages (on gh-branch) navigate to [http://borismoore.github.com/jsrender/demos/index.html](http://borismoore.github.com/jsrender/demos/index.html "JsRender Samples").
See also [JsViews step-by-step samples](http://borismoore.github.com/jsviews/demos/index.html)

<b>Warning:</b> JsRender is not yet Beta, and there may be frequent changes to APIs and features in the coming period.

**Warning:** JsRender is not yet Beta, and there may be frequent changes to APIs and features in the coming period.<br/>
<span style="color:red">Recent breaking change:</span> Parameter order change: `$.render( data, template )`
121 changes: 61 additions & 60 deletions jsrender.js
@@ -1,13 +1,13 @@
/*! JsRender v1.0pre - (jsrender.js version: does not require jQuery): http://github.com/BorisMoore/jsrender */
/*
* Optimized version of jQuery Templates, for rendering to string, using 'codeless' markup.
* Optimized version of jQuery Templates, fosr rendering to string, using 'codeless' markup.
*
* Copyright 2011, Boris Moore
* Released under the MIT License.
*/
window.JsViews || window.jQuery && jQuery.views || (function( window, undefined ) {

var $, _$, JsViews, viewsNs, tmplEncode, render, rTag, registerTags, registerHelpers,
var $, _$, JsViews, viewsNs, tmplEncode, render, rTag, registerTags, registerHelpers, extend,
FALSE = false, TRUE = true,
jQuery = window.jQuery, document = window.document,
htmlExpr = /^[^<]*(<[\w\W]+>)[^>]*$|\{\{\! /,
Expand Down Expand Up @@ -56,10 +56,6 @@ if ( jQuery ) {
window.JsViews = JsViews = window.$ = $ = {
extend: function( target, source ) {
var name;
if ( source === undefined ) {
source = target;
target = $;
}
for ( name in source ) {
target[ name ] = source[ name ];
}
Expand All @@ -77,6 +73,8 @@ if ( jQuery ) {
};
}

extend = $.extend;

//=================
// View constructor
//=================
Expand All @@ -100,12 +98,12 @@ function View( context, path, parentView, data, template ) {
// Set additional context on this view (which will modify the context inherited from the parent, and be inherited by child views)
ctx : context && context === parentContext
? parentContext
: (parentContext ? $.extend( {}, parentContext, context ) : context||{}),
: (parentContext ? extend( extend( {}, parentContext ), context ) : context||{}),
// If no jQuery, extend does not support chained copies - so limit to two parameters
parent: parentView
};
}

$.extend({
extend( $, {
views: viewsNs = {
templates: {},
tags: {
Expand All @@ -131,17 +129,19 @@ $.extend({
return view.onElse ? view.onElse( this, arguments ) : "";
},
each: function() {
var i, result = "",
var i,
self = this,
result = "",
args = arguments,
l = args.length,
content = this.tmpl,
view = this._view;
content = self.tmpl,
view = self._view;
for ( i = 0; i < l; i++ ) {
result += args[ i ] ? render( args[ i ], content, view.ctx, view, this._path, this._tag ) : "";
result += args[ i ] ? render( args[ i ], content, self.ctx || view.ctx, view, self._path, self._ctor ) : "";
}
return l ? result
// If no data parameter, use the current $data from view, and render once
: result + render( view.data, content, view.ctx, view, this._path, this._tag );
: result + render( view.data, content, view.ctx, view, self._path, self.tag );
},
"=": function( value ) {
return value;
Expand All @@ -167,8 +167,8 @@ $.extend({

setDelimiters: function( openTag, closeTag ) {
// Set or modify the delimiter characters for tags: "{{" and "}}"
var firstCloseChar = closeTag.charAt( 1 ),
secondCloseChar = closeTag.charAt( 0 );
var firstCloseChar = closeTag.charAt( 0 ),
secondCloseChar = closeTag.charAt( 1 );
openTag = "\\" + openTag.charAt( 0 ) + "\\" + openTag.charAt( 1 );
closeTag = "\\" + firstCloseChar + "\\" + secondCloseChar;

Expand Down Expand Up @@ -198,17 +198,15 @@ $.extend({
//===============

// Register declarative tag.
registerTags: registerTags = function( name, tag ) {
registerTags: registerTags = function( name, tagFn ) {
var key;
if ( typeof name === "object" ) {
// Object representation where property name is path and property value is value.
// TODO: We've discussed an "objectchange" event to capture all N property updates here. See TODO note above about propertyChanges.
for ( key in name ) {
registerTags( key, name[ key ]);
}
} else {
// Simple single property case.
viewsNs.tags[ name ] = tag;
viewsNs.tags[ name ] = tagFn;
}
return this;
},
Expand Down Expand Up @@ -259,29 +257,38 @@ $.extend({
// renderTag
//===============

renderTag: function( tagName, view, encode, content, presenter ) {
// This is a tag call, with arguments: "tagName", view, encode, content[, params...], presenter
var ret,
tagFn = viewsNs.tags[ tagName ];
renderTag: function( tag, view, encode, content, tagProperties ) {
// This is a tag call, with arguments: "tag", view, encode, content, presenter [, params...]
var ret, ctx, name,
args = arguments,
presenters = viewsNs.presenters;
hash = tagProperties._hash,

This comment has been minimized.

Copy link
@danielfagerstrom

danielfagerstrom Dec 13, 2011

Looks like you are introducing hash and tagFn as global variables here, which might be dangerous.

This comment has been minimized.

Copy link
@BorisMoore

BorisMoore Dec 13, 2011

Author Owner

Yes, absolutely. I had already caught that one and fixed it ready for the next commit. Thanks

tagFn = viewsNs.tags[ tag ];

if ( !tagFn ) {
return "";
}
if ( viewsNs.pstrs && viewsNs.pstrs[ tagName ]) {
// This is a presenter tag (from JsViews registerPresenter)
presenter = $.extend( tagFn , presenter );
presenter._tag = tagName;
tagFn = FALSE;
}

presenter._encode = encode;
presenter._view = view;

content = content && view.tmpl.nested[ content - 1 ];
presenter.tmpl = presenter.tmpl || content;
tagFn = tagFn || viewsNs.tags.each;
ret = tagFn && (tagFn.apply( presenter, slice.call( arguments, 5 )));
return ret || (ret === undefined ? "" : ret.toString());
tagProperties.tmpl = tagProperties.tmpl || content || undefined;
// Set the tmpl property to the content of the block tag, unless set as an override property on the tag

if ( presenters && presenters[ tag ]) {
ctx = extend( extend( {}, tagProperties.ctx ), tagProperties );
delete ctx.ctx;
delete ctx._path;
delete ctx.tmpl;
tagProperties.ctx = ctx;
tagProperties._ctor = tag + (hash ? "=" + hash.slice( 0, -1 ) : "");

tagProperties = extend( extend( {}, tagFn ), tagProperties );
tagFn = viewsNs.tags.each; // Use each to render the layout template against the data
}

tagProperties._encode = encode;
tagProperties._view = view;
ret = tagFn.apply( tagProperties, args.length > 5 ? slice.call( args, 5 ) : [view.data] );
return ret || (ret === undefined ? "" : ret.toString()); // (If ret is the value 0 or false or null, will render to string)
}
},

Expand All @@ -291,7 +298,7 @@ $.extend({

render: render = function( data, tmpl, context, parentView, path, tagName ) {
// Render template against data as a tree of subviews (nested template), or as a string (top-level template).
// tagName parameter for internal use only. Used for rendering templates registered as tags (which may have associated context objects)
// tagName parameter for internal use only. Used for rendering templates registered as tags (which may have associated presenter objects)
var i, l, dataItem, arrayView, content, result = "";

if ( arguments.length === 2 && data.jsViews ) {
Expand Down Expand Up @@ -319,7 +326,7 @@ $.extend({

return viewsNs.activeViews
// If in activeView mode, include annotations
? "<!--tmpl(" + (path || "") + ") " + (tagName ? "tag:" + tagName : tmpl._name) + "-->" + result + "<!--/tmpl-->"
? "<!--tmpl(" + (path || "") + ") " + (tagName ? "tag=" + tagName : tmpl._name) + "-->" + result + "<!--/tmpl-->"
// else return just the string result
: result;
},
Expand Down Expand Up @@ -361,7 +368,7 @@ $.extend({
}
// Return named compiled template
return name
? "" + name !== name
? "" + name !== name // not type string
? (name._name
? name // already compiled
: $.template( null, name ))
Expand Down Expand Up @@ -396,9 +403,9 @@ function compile( markup ) {
var newNode,
loc = 0,
stack = [],
top = [],
content = top,
current = [,,top];
topNode = [],
content = topNode,
current = [,,topNode];

function pushPreceedingContent( shift ) {
shift -= loc;
Expand All @@ -408,10 +415,10 @@ function compile( markup ) {
}

function parseTag( all, isBlock, tagName, equals, code, params, useEncode, encode, closeBlock, index ) {
// rTag : # tag equals code params encode closeBlock
// rTag : # tagName equals code params encode closeBlock
// /\{\{(?:(?:(\#)?(\w+(?=[\s\}!]))|(?:(\=)|(\*)))((?:[^\}]|\}(?!\}))*?)(!(\w*))?|(?:\/([\w\$\.\[\]]+)))\}\}/g;

// Build abstract syntax tree: [ tag, params, content, encode ]
// Build abstract syntax tree: [ tagName, params, content, encode ]
var named,
hash = "",
parenDepth = 0,
Expand Down Expand Up @@ -480,7 +487,7 @@ function compile( markup ) {
tagName,
useEncode ? encode || "none" : "",
isBlock && [],
"{" + hash + "_path:'" + params + "'}",
"{" + hash + "_hash:'" + hash + "',_path:'" + params + "'}",
params
];

Expand All @@ -501,7 +508,7 @@ function compile( markup ) {
markup = markup.replace( rEscapeQuotes, "\\$1" );
markup.replace( rTag, parseTag );
pushPreceedingContent( markup.length );
return buildTmplFunction( top );
return buildTmplFunction( topNode );
}

// Build javascript compiled template function, from AST
Expand All @@ -524,30 +531,25 @@ function buildTmplFunction( nodes ) {
encode = node[ 1 ],
content = node[ 2 ],
obj = node[ 3 ],
params = node[ 4 ];
params = node[ 4 ],
paramsOrEmptyString = params + '||"")+';

if( content ) {
nested.push( buildTmplFunction( content ));
}
code += tag === "="
? (!encode || encode === "html"
? "html(" + params + ")+"
? "html(" + paramsOrEmptyString
: encode === "none"
? (params + "+")
: ('enc("' + encode + '",' + params + ")+")
? ("(" + paramsOrEmptyString)
: ('enc("' + encode + '",' + paramsOrEmptyString)
)
: 'tag("' + tag + '",$view,"' + ( encode || "" ) + '",'
+ (content ? nested.length : '""') // For block tags, pass in the key (nested.length) to the nested content template
+ "," + obj + (params ? "," : "") + params + ')+';
+ "," + obj + (params ? "," : "") + params + ")+";
}
}
try {
ret = new Function( "$data, $view", code.slice( 0, -1) + ";return result;\n\n}catch(e){return views.err(e);}" );
} catch(e) {
ret = function() {
return viewsNs.err( e );
};
}
ret = new Function( "$data, $view", code.slice( 0, -1) + ";return result;\n\n}catch(e){return views.err(e);}" );
ret.nested = nested;
return ret;
}
Expand All @@ -568,5 +570,4 @@ function try$( selector ) {
} catch( e) {}
return selector;
}

})( window );

0 comments on commit ab3fddd

Please sign in to comment.