Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Helper functions now have the 'this' pointer as the current view,

hence providing full access to context, e.g. this.data or this.index etc.
The tag helper function 'this' pointer is a tagObject which has this.view
to provide the current view context, and this.props to get named tag parameters, etc.
$.views.helpers/tags/converters each return $.views when used as setters,
so can be chained. Similarly $.templates returns $ when used as a setter.
  • Loading branch information...
commit efdb2cb0a7bed1b54024cd839e3ee2b095d9cf40 1 parent ac145e0
@BorisMoore authored
View
5 demos/step-by-step/03_no-encoding.html
@@ -25,15 +25,14 @@
</ul><br />
<script id="movieTemplate" type="text/x-jsrender">
- {{if true}}<tr>
+ <tr>
<td>{{loc:title}}</td>
<td class="synopsis">{{:synopsis}}</td>
<td class="synopsis">{{>synopsis}}</td>
</tr>
- {{/if}}
</script>
-<table><tbody class="header"><tr><th>title</th><th>No Convert</th><th>HTML Encode</th></tr></tbody>
+<table><tr class="header"><th>title</th><th>No Convert</th><th>HTML Encode</th></tr>
<tbody id="movieList"></tbody>
</table>
View
2  demos/step-by-step/05_for-tag.html
@@ -25,7 +25,7 @@
</tr>
</script>
-<table><tbody class="header"><tr><th>Title</th><th>Languages</th></tr></tbody>
+<table><tr class="header"><th>Title</th><th>Languages</th></tr>
<tbody id="movieList"></tbody>
</table>
View
2  demos/step-by-step/06_template-composition.html
@@ -36,7 +36,7 @@
</span>
</script>
-<table><tbody class="header"><tr><th>Synopsis</th><th>Fixed Template</th><th>Template specified in data</th></tr></tbody>
+<table><tr class="header"><th>Synopsis</th><th>Fixed Template</th><th>Template specified in data</th></tr>
<tbody id="movieList"></tbody>
</table>
View
4 demos/step-by-step/08_custom-tags.html
@@ -34,6 +34,8 @@
});
</pre>
+<!--================ Demo ================-->
+
<script id="movieTemplate" type="text/x-jsrender">
<tr>
<td>{{:title}}</td>
@@ -51,7 +53,7 @@
<div>{{:name}}</div>
</script>
-<table><tbody class="header"><tr><th>Title</th><th>Orginal order</th><th>Reverse order</th></tr></tbody>
+<table><tr class="header"><th>Title</th><th>Orginal order</th><th>Reverse order</th></tr>
<tbody id="movieList"></tbody>
</table>
View
47 demos/step-by-step/09_helper-functions.html
@@ -12,31 +12,21 @@
<h3>Helper functions</h3>
-<script id="movieTemplate" type="text/x-jsrender">
- <tr>
- <td>{{:title}}</td>
- <td>
- {{for languages}}
- {{:~format(name, "upper")}}{{if ~nextToLast(#view)}} and {{else ~notLast(#view)}}, {{/if}}
- {{/for}}
- </td>
- </tr>
-</script>
-
<pre>
{{:~format(name, "upper")}}
-{{if ~nextToLast(#view)}}...
+{{if ~nextToLast()}}...{{/if}}
$.views.helpers({
format: function( val, format ){
...
- return val.toUpperCase();
- ...
+ return val.toUpperCase();
+ ...
},
- nextToLast: function( view ) {
+ nextToLast: function() {
+ var view = this;
return view.index === view.parent.data.length - 2;
},
@@ -44,10 +34,27 @@
});
</pre>
-<table><tbody class="header"><tr><th>Title</th><th>Languages</th></tr></tbody>
+<!--=================== Demo ===================-->
+
+<!------------------ Templates ------------------>
+
+<script id="movieTemplate" type="text/x-jsrender">
+ <tr>
+ <td>{{:~format(title, "upper")}}</td>
+ <td>
+ {{for languages}}
+ {{:name}}{{if ~nextToLast()}} and {{else ~notLast()}}, {{/if}}
+ {{/for}}
+ </td>
+ </tr>
+</script>
+
+<table><tr class="header"><th>Title</th><th>Languages</th></tr></tbody>
<tbody id="movieList"></tbody>
</table>
+<!------------------ Script ------------------>
+
<script type="text/javascript">
$.views.helpers({
@@ -57,15 +64,17 @@
case "upper":
return val.toUpperCase();
case "lower":
- return val.toLowerCase();
+ return val.toLowerCase();
}
},
- nextToLast: function( view ) {
+ nextToLast: function() {
+ var view = this;
return view.index === view.parent.data.length - 2;
},
- notLast: function( view ) {
+ notLast: function() {
+ var view = this;
return view.index !== view.parent.data.length - 1;
}
});
View
16 demos/step-by-step/10_comparison-tests.html
@@ -12,6 +12,14 @@
<h3>Helper functions and comparison tests</h3>
+<pre>
+{{if !(languages && languages.length)}}...{{/if}}
+
+{{if languages==null}}...{{/if}}
+</pre>
+
+<!--================ Demo ================-->
+
<script id="movieTemplate" type="text/x-jsrender">
<tr>
<td>{{:title}}</td>
@@ -28,13 +36,7 @@
<b>Warning:</b> <em>No alternate languages</em>
</script>
-<pre>
-{{if !(languages && languages.length)}}...{{/if}}
-
-{{if languages==null}}...{{/if}}
-</pre>
-
-<table><tbody class="header"><tr><th>Title</th><th>{{if !(languages && languages.length)}}</th><th>{{if a==null}}</th></tr></tbody>
+<table><tr class="header"><th>Title</th><th>{{if !(languages && languages.length)}}</th><th>{{if a==null}}</th></tr>
<tbody id="movieList"></tbody>
</table>
View
54 demos/step-by-step/11_default-values-scenario.html
@@ -22,19 +22,10 @@
{{:languages||'Languages unavailable'}}
</pre>
-<table><tbody class="header"><tr><th>Title</th><th>{{:path}}</th></tr></tbody>
+<table><tr class="header"><th>Title</th><th>{{:path}}</th></tr>
<tbody id="movieList1"></tbody>
</table>
-<script id="movieTemplate1" type="text/x-jsrender">
- <tr>
- <td>{{:title}}</td>
- <td>
- {{:languages||'Languages unavailable'}}
- </td>
- </tr>
-</script>
-
<!---------------------- Second Example ---------------------->
<div class="subhead">Creating a special custom tag:</div>
@@ -48,19 +39,6 @@
});
</pre>
-<table><tbody class="header"><tr><th>Title</th><th>{{get path default="..."}}</th></tr></tbody>
- <tbody id="movieList2"></tbody>
-</table>
-
-<script id="movieTemplate2" type="text/x-jsrender">
- <tr>
- <td>{{:title}}</td>
- <td>
- {{get languages defaultValue="No languages!"/}}
- </td>
- </tr>
-</script>
-
<!---------------------- Third Example ---------------------->
<div class="subhead">Creating a multi-purpose utility tag:</div>
@@ -74,10 +52,36 @@
});
</pre>
-<table><tbody class="header"><tr><th>Title</th><th>{{yesNo path yes="..." no="..."}}</th></tr></tbody>
+<table><tr class="header"><th>Title</th><th>{{yesNo path yes="..." no="..."}}</th></tr>
<tbody id="movieList3"></tbody>
</table>
+<!--=================== Demo ===================-->
+
+<!------------------ Templates ------------------>
+
+<table><tr class="header"><th>Title</th><th>{{get path default="..."}}</th></tr></tbody>
+ <tbody id="movieList2"></tbody>
+</table>
+
+<script id="movieTemplate1" type="text/x-jsrender">
+ <tr>
+ <td>{{:title}}</td>
+ <td>
+ {{:languages||'Languages unavailable'}}
+ </td>
+ </tr>
+</script>
+
+<script id="movieTemplate2" type="text/x-jsrender">
+ <tr>
+ <td>{{:title}}</td>
+ <td>
+ {{get languages defaultValue="No languages!"/}}
+ </td>
+ </tr>
+</script>
+
<script id="movieTemplate3" type="text/x-jsrender">
<tr>
<td>{{:title}}</td>
@@ -88,7 +92,7 @@
</tr>
</script>
-<!---------------------- Code ---------------------->
+<!------------------ Script ------------------>
<script type="text/javascript">
View
3  demos/step-by-step/12_layout-templates.html
@@ -30,7 +30,6 @@
footer
</pre>
-
<div class="subhead">Nested layout:</div>
<pre>
{{for languages layout=true}}
@@ -42,6 +41,8 @@
{{/for}}
</pre>
+<!--================ Demo ================-->
+
<script id="movieTemplate" type="text/x-jsrender">
<tbody class="header">
<tr><th colspan="2">{{:length}} movies available:</th></tr>
View
4 demos/step-by-step/13_allow-code.html
@@ -27,6 +27,8 @@
}}
</pre>
+<!--================ Demo ================-->
+
<script id="movieTemplate" type="text/x-jsrender">
<tr>
<td>{{:title}}</td>
@@ -46,7 +48,7 @@
</tr>
</script>
-<table><tbody class="header"><tr><th>Title</th><th>Languages</th></tr></tbody>
+<table><tr class="header"><th>Title</th><th>Languages</th></tr>
<tbody id="movieList"></tbody>
</table>
View
4 demos/step-by-step/13b_allow-code.html
@@ -26,6 +26,8 @@
}}
</pre>
+<!--================ Demo ================-->
+
<script id="movieTemplate" type="text/x-jsrender">
<tr>
<td>{{:title}}</td>
@@ -45,7 +47,7 @@
</tr>
</script>
-<table><tbody class="header"><tr><th>Title</th><th>Languages</th></tr></tbody>
+<table><tr class="header"><th>Title</th><th>Languages</th></tr>
<tbody id="movieList"></tbody>
</table>
View
52 jsrender.js
@@ -6,6 +6,7 @@
* Copyright 2012, Boris Moore
* Released under the MIT License.
*/
+// informal pre beta commit counter: 0
this.jsviews || this.jQuery && jQuery.views || (function( window, undefined ) {
@@ -60,7 +61,6 @@ var versionNumber = "v1.0pre",
converters: converters,
View: View,
convert: convert,
- ctx: getContext,
delimiters: setDelimiters,
tag: renderTag
};
@@ -100,13 +100,17 @@ function setDelimiters( openChars, closeChars ) {
}
//=================
-// jsviews.ctx
+// View.hlp
//=================
-function getContext( view, helper ) {
- var tmplHelpers = view.tmpl.helpers || {};
- tmplHelpers = (view.ctx[ helper ] ? view.ctx : tmplHelpers[ helper ] ? tmplHelpers : helpers[ helper ] ? helpers : {});
- return tmplHelpers[ helper ];
+function getHelper( helper ) {
+ // Helper method called as view.hlp() from compiled template, for helper functions or template parameters ~foo
+ var view = this,
+ tmplHelpers = view.tmpl.helpers || {};
+ helper = (view.ctx[ helper ] ? view.ctx : tmplHelpers[ helper ] ? tmplHelpers : helpers[ helper ] ? helpers : {})[ helper ];
+ return typeof helper !== "function" ? helper : function() {
+ return helper.apply(view, arguments);
+ };
}
//=================
@@ -147,7 +151,7 @@ function renderTag( tag, parentView, converter, content, tagObject ) {
tagObject.isTag = TRUE;
tagObject.converter = converter;
- tagObject.parent = parentView;
+ tagObject.view = parentView;
tagObject.renderContent = renderContent;
if ( parentView.ctx ) {
extend( tagObject.ctx, parentView.ctx);
@@ -158,7 +162,7 @@ function renderTag( tag, parentView, converter, content, tagObject ) {
}
//=================
-// View constuctor
+// View constructor
//=================
function View( context, path, parentView, data, template, index ) {
@@ -173,7 +177,8 @@ function View( context, path, parentView, data, template, index ) {
parent: parentView,
data: data,
ctx: context,
- views: $.isArray( data ) ? [] : {}
+ views: $.isArray( data ) ? [] : {},
+ hlp: getHelper
};
if ( $.isArray( views )) {
@@ -192,7 +197,7 @@ function View( context, path, parentView, data, template, index ) {
// Registration
//=================
-function addToStore( store, name, item, process ) {
+function addToStore( self, store, name, item, process ) {
// Add item to named store such as templates, helpers, converters...
var key, onStore;
if ( name && typeof name === "object" && !name.nodeType ) {
@@ -200,7 +205,7 @@ function addToStore( store, name, item, process ) {
for ( key in name ) {
store( key, name[ key ]);
}
- return jsv;
+ return self;
}
if ( !name || item === undefined ) {
if ( process ) {
@@ -229,7 +234,7 @@ function templates( name, tmpl ) {
// When registering for {{foo a b c==d e=f}}, tagFn should be a function with the signature:
// function(a,b). The 'this' pointer will be a hash with properties c and e.
- return addToStore( templates, name, tmpl, compile );
+ return addToStore( this, templates, name, tmpl, compile );
}
function tags( name, tagFn ) {
@@ -240,7 +245,7 @@ function tags( name, tagFn ) {
// When registering for {{foo a b c==d e=f}}, tagFn should be a function with the signature:
// function(a,b). The 'this' pointer will be a hash with properties c and e.
- return addToStore( tags, name, tagFn );
+ return addToStore( this, tags, name, tagFn );
}
function helpers( name, helperFn ) {
@@ -249,7 +254,7 @@ function helpers( name, helperFn ) {
// Getter: Use var helperFn = $.views.helpers( name ) or $.views.helpers[name] or $.views.helpers.name to return the function.
// Remove: Use $.view.helpers( name, null ) to remove a registered helper function from $.view.helpers.
// Within a template, access the helper using the syntax: {{... ~myHelper(...) ...}}.
- return addToStore( helpers, name, helperFn );
+ return addToStore( this, helpers, name, helperFn );
}
function converters( name, converterFn ) {
@@ -258,7 +263,7 @@ function converters( name, converterFn ) {
// Getter: Use var converterFn = $.views.converters( name ) or $.views.converters[name] or $.views.converters.name to return the converter function.
// Remove: Use $.view.converters( name, null ) to remove a registered converter from $.view.converters.
// Within a template, access the converter using the syntax: {{myConverter:...}}.
- return addToStore( converters, name, converterFn );
+ return addToStore( this, converters, name, converterFn );
}
//=================
@@ -278,7 +283,7 @@ function renderContent( data, context, parentView, path, index ) {
// This is a call from renderTag
tmpl = self.tmpl;
context = context || self.ctx;
- parentView = parentView || self.parent;
+ parentView = parentView || self.view;
path = path || self.path;
index = index || self.index;
props = self.props;
@@ -478,7 +483,7 @@ function tmplFn( markup, tmpl, bind ) {
tmplFn( markup, nestedTmpl);
nested.push( nestedTmpl );
}
- hasHelperPath = hasHelperPath || params.indexOf( 'h(view,"' ) > -1;
+ hasHelperPath = hasHelperPath || params.indexOf( 'view.hlp("' ) > -1;
hasViewPath = hasViewPath || params.indexOf( "view" ) > -1;
code += (tag === ":"
? (converter === "html"
@@ -498,7 +503,6 @@ function tmplFn( markup, tmpl, bind ) {
+ (hasTag ? "t=j.tag," : "")
+ (hasConverter ? "c=j.convert," : "")
+ (hasEncoder ? "e=j.converters.html," : "")
- + (hasHelperPath ? "h=j.ctx," : "")
+ "ret; try{\n\n"
+ (tmplOptions.debug ? "debugger;" : "")
+ (allowCode ? 'ret=' : 'return ')
@@ -535,10 +539,10 @@ function parseParams( params, bind ) {
// val object helper view viewProperty pathTokens leafToken string quot
if ( object ) {
val = (helper
- ? 'h(view,"' + helper + '")'
+ ? 'view.hlp("' + helper + '")'
: view
? "view"
- :"data")
+ : "data")
+ (leafToken
? (viewProperty
? "." + viewProperty
@@ -595,7 +599,7 @@ function parseParams( params, bind ) {
: "")
)
: comma
- ? (fnCall[ parenDepth ] || syntaxError(), ",")
+ ? (fnCall[ parenDepth ] || syntaxError(), ",") // We don't allow top-level literal arrays or objects
: (aposed = apos, quoted = quot, '"')
);
}
@@ -753,7 +757,7 @@ if ( jQuery ) {
extend = $.extend;
-jsv.topView = { views: {}, tmpl: {}, ctx: jsv.helpers };
+jsv.topView = { views: {}, tmpl: {}, hlp: getHelper, ctx: jsv.helpers };
function replacerForHtml( ch ) {
// Original code from Mike Samuel <msamuel@google.com>
@@ -767,7 +771,7 @@ function replacerForHtml( ch ) {
tags({
"if": function() {
var ifTag = this,
- view = ifTag.parent;
+ view = ifTag.view;
view.onElse = function( tagObject, args ) {
var i = 0,
@@ -789,7 +793,7 @@ tags({
return view.onElse( this, arguments );
},
"else": function() {
- var view = this.parent;
+ var view = this.view;
return view.onElse ? view.onElse( this, arguments ) : "";
},
"for": function() {
View
2  test/unit/jsrender-tests-no-jquery.js
@@ -437,5 +437,5 @@ test("template encapsulation", function() {
equal( jsviews.render.tmplWithNestedResources({ a: "aVal" }), "aval aValbtrue% (double:aVal&aVal) (override outer double:AVAL|AVAL)", 'Access nested resources from template' );
equal( jsviews.render.useLower({ a: "aVal" }), "", 'Cannot access nested resources from a different template' );
equal( jsviews.render.tmplWithNestedResources({ a: "aVal" }, context), "aval aValbcontextualNot2true% (double:aVal&aVal) (override outer double:contextualUpperAVAL|contextualUpperAVAL)", 'Resources passed in with context override nested resources' );
- equal( jsviews.templates.tmplWithNestedResources.templates.templateWithDebug.fn.toString().indexOf("debugger;"), 90, 'Can set debug=true on nested template' );
+ equal( jsviews.templates.tmplWithNestedResources.templates.templateWithDebug.fn.toString().indexOf("debugger;"), 82, 'Can set debug=true on nested template' );
});
Please sign in to comment.
Something went wrong with that request. Please try again.