Permalink
Browse files

Merge branch 'master' into help_with_bad_expansion

  • Loading branch information...
2 parents 7966ca7 + ac492d1 commit 9fac2072acadd50d94e9fdb1d198f289108ed1ed @patmoore committed Apr 7, 2012
View
2 README.md
@@ -1,7 +1,7 @@
## 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").<br/>
-JsRender integrates with [JsViews](http://borismoore.github.com/jsviews), to provide interactive data-driven views. See [JsViews step-by-step samples](http://borismoore.github.com/jsviews/demos/index.html).<br/>
+JsRender integrates with [JsViews](https://github.com/BorisMoore/jsviews), to provide interactive data-driven views. See [JsViews step-by-step samples](http://borismoore.github.com/jsviews/demos/index.html).<br/>
See [Approaching Beta: What's changing in JsRender and JsViews](http://www.borismoore.com/2012/03/approaching-beta-whats-changing-in_06.html) for documentation of changes.<br/>
View
2 demos/resources/movielist.css
@@ -3,5 +3,5 @@ table tr { color: blue; height: 25px; }
.header { color: #009; border-bottom: solid #77c 2px; background-color: #E8E8F7; }
.header th { padding:5px; border: 1px solid #77c; }
#movieList tr td:first-child { width: 130px; }
-table { border: 2px solid blue; width: 480px; margin: 4px 0 24px 4px; padding: 2px; background-color: #f8f8f8; }
+table { border: 2px solid blue; width: 520px; margin: 4px 0 24px 4px; padding: 2px; background-color: #f8f8f8; }
table td { padding: 3px; margin: 3px; border: solid #77c 1px; }
View
2 demos/step-by-step/02_compiling-templates-from-strings.html
@@ -41,7 +41,7 @@
/* Render using the other named template */
var templateName = details ? "detailTemplate" : "titleTemplate";
- $( "#movieList" ).html( $.render [templateName ]( movies ));
+ $( "#movieList" ).html( $.render [ templateName ]( movies ));
}
$( "#switchBtn" ).click( switchTemplates );
View
13 demos/step-by-step/08_custom-tags.html
@@ -10,13 +10,15 @@
<body>
<a href="index.html">Home</a><br />
-<h3>Providing a custom tag</h3>
+<h3>Custom tags</h3>
<pre>
-<td>{{sort languages reverse=true}}...{{/sort}}</td>
+&lt;td>{{sort languages reverse=true}}...{{/sort}}&lt;/td>
$.views.tags({
+ // Tag to reverse-sort an array
+
sort: function( array ){
var ret = "";
if ( this.props.reverse ) {
@@ -40,27 +42,30 @@
<tr>
<td>{{:title}}</td>
<td>{{sort languages tmpl="#sortedTemplate"/}}</td>
- <td>{{sort languages reverse=true}}
+ <td>
+ {{sort languages reverse=true}}
<div>
<b>{{:name}}</b>
</div>
{{/sort}}
</td>
+
</tr>
</script>
<script id="sortedTemplate" type="text/x-jsrender">
<div>{{:name}}</div>
</script>
-<table><tr class="header"><th>Title</th><th>Orginal order</th><th>Reverse order</th></tr>
+<table><tr class="header"><th>Title</th><th>Languages</th><th>Reverse order</th></tr>
<tbody id="movieList"></tbody>
</table>
<script type="text/javascript">
$.views.tags({
+ // Tag to reverse-sort an array
sort: function( array ){
var ret = "";
if ( this.props.reverse ) {
View
19 demos/step-by-step/09_helper-functions.html
@@ -15,8 +15,6 @@
<pre>
{{:~format(name, "upper")}}
-{{if ~nextToLast()}}...{{/if}}
-
$.views.helpers({
format: function( val, format ){
@@ -25,11 +23,6 @@
...
},
- nextToLast: function() {
- var view = this;
- return view.index === view.parent.data.length - 2;
- },
-
...
});
</pre>
@@ -43,7 +36,7 @@
<td>{{:~format(title, "upper")}}</td>
<td>
{{for languages}}
- {{:name}}{{if ~nextToLast()}} and {{else ~notLast()}}, {{/if}}
+ {{:~format(name, "lower")}}
{{/for}}
</td>
</tr>
@@ -66,16 +59,6 @@
case "lower":
return val.toLowerCase();
}
- },
-
- nextToLast: function() {
- var view = this;
- return view.index === view.parent.data.length - 2;
- },
-
- notLast: function() {
- var view = this;
- return view.index !== view.parent.data.length - 1;
}
});
View
142 demos/step-by-step/12_iterating-through-fields-scenario.html
@@ -0,0 +1,142 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script src="http://code.jquery.com/jquery.js" type="text/javascript"></script>
+ <script src="../../jsrender.js" type="text/javascript"></script>
+ <link href="../resources/demos.css" rel="stylesheet" type="text/css" />
+
+ <link href="../resources/movielist.css" rel="stylesheet" type="text/css" />
+</head>
+<body>
+<a href="index.html">Home</a><br />
+
+<h3>Example Scenario: Creating custom helpers to iterate through fields</h3>
+
+<!---------------------- First Example ---------------------->
+
+<div class="subhead">Using a custom {{forFields}} tag:</div>
+
+<pre>
+ {{forFields details}}
+ &lt;b>{{:~key}}&lt;/b>: {{:#data}}
+ {{/forFields}}
+</pre>
+
+<table><tr class="header"><th>Title</th><th>Details</th></tr></tbody>
+ <tbody id="movieList1"></tbody>
+</table>
+
+<!---------------------- Second Example ---------------------->
+
+<div class="subhead">Using a custom ~getFields() helper function:</div>
+
+<pre>
+ {{for ~getFields(details)}}
+ &lt;b>{{:key}}&lt;/b>: {{:value}}
+ {{/for}}
+</pre>
+
+<table><tr class="header"><th>Title</th><th>Details</th></tr></tbody>
+ <tbody id="movieList2"></tbody>
+</table>
+
+
+<!--=================== Demo ===================-->
+
+<!------------------ Templates ------------------>
+
+<script id="movieTemplate1" type="text/x-jsrender">
+ <tr>
+ <td>{{:title}}</td>
+ <td>
+ {{forFields details}}
+ <div>
+ <b>{{:~key}}</b>: {{:#data}}
+ </div>
+ {{/forFields}}
+ </td>
+ </tr>
+</script>
+
+<script id="movieTemplate2" type="text/x-jsrender">
+ <tr>
+ <td>{{:title}}</td>
+ <td>
+ {{for ~getFields(details)}}
+ <div>
+ <b>{{:key}}</b>: {{:value}}
+ </div>
+ {{/for}}
+ </td>
+ </tr>
+</script>
+
+<!------------------ Script ------------------>
+
+<script type="text/javascript">
+
+ $.views.tags({
+ forFields: function( object ) {
+ var key,
+ ret = "";
+ for ( key in object ) {
+ if ( object.hasOwnProperty( key )) {
+ // For each property/field, render the content of the {{fields object}} tag, with "~key" as template parameter
+ ret += this.renderContent( object[ key ], { key: key });
+ }
+ }
+ // Return the array, to be rendered used {{for ~fields(object)}}
+ return ret;
+ }
+ });
+
+ //Define a custom getFields helper function to iterate over fields and return
+ $.views.helpers({
+ getFields: function( object ) {
+ var key, value,
+ fieldsArray = [];
+ for ( key in object ) {
+ if ( object.hasOwnProperty( key )) {
+ value = object[ key ];
+ // For each property/field add an object to the array, with key and value
+ fieldsArray.push({
+ key: key,
+ value: value
+ });
+ }
+ }
+ // Return the array, to be rendered using {{for ~fields(object)}}
+ return fieldsArray;
+ }
+ });
+
+ var movies = [
+ {
+ title: "Meet Joe Black",
+ details: {
+ director: "John",
+ date: "1996",
+ language: "English"
+ }
+ },
+ {
+ title: "Eyes Wide Shut",
+ details: {
+ type: "Comedy",
+ date: "1940"
+ }
+ }
+ ];
+
+ $( "#movieList1" ).html(
+ $( "#movieTemplate1" ).render( movies )
+ );
+
+ $( "#movieList2" ).html(
+ $( "#movieTemplate2" ).render( movies )
+ );
+
+</script>
+
+</body>
+</html>
View
95 demos/step-by-step/13_allow-code.html
@@ -1,95 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <script src="http://code.jquery.com/jquery.js" type="text/javascript"></script>
- <script src="../../jsrender.js" type="text/javascript"></script>
- <link href="../resources/demos.css" rel="stylesheet" type="text/css" />
-
- <link href="../resources/movielist.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<a href="index.html">Home</a><br />
-
-<h3>Allowing code within templates: program flow</h3>
-
-<pre>
-$.templates( "movieTmpl", {
- markup: "#movieTemplate",
- allowCode: true
-});
-
-{{*
- if ( myexpression ) {
-}}
- ...
-{{*
- }
-}}
-</pre>
-
-<!--================ Demo ================-->
-
-<script id="movieTemplate" type="text/x-jsrender">
- <tr>
- <td>{{:title}}</td>
- <td>
- {{for languages}}
- {{:name}}{{*
-
- if ( view.index === view.parent.data.length - 2 ) {
-
- }} and {{*
-
- } else if ( view.index < view.parent.data.length - 2 ) {
-
- }}, {{* } }}
- {{/for}}
- </td>
- </tr>
-</script>
-
-<table><tr class="header"><th>Title</th><th>Languages</th></tr>
- <tbody id="movieList"></tbody>
-</table>
-
-<script type="text/javascript">
-
- var movies = [
- {
- title: "Meet Joe Black",
- languages: [
- { name: "English" },
- { name: "French" }
- ],
- subtitles: [
- { name: "English" },
- { name: "French" },
- { name: "Chinese" }
- ]
- },
- {
- title: "Eyes Wide Shut",
- languages: [
- { name: "French" },
- { name: "German" },
- { name: "Spanish" }
- ],
- subtitles: [
- { name: "English" }
- ]
- }
- ];
-
- $.templates( "movieTmpl", {
- markup: "#movieTemplate",
- allowCode: true
- });
-
- $( "#movieList" ).html(
- $.render.movieTmpl( movies )
- );
-
-</script>
-
-</body>
-</html>
View
236 demos/step-by-step/13_separators-scenario.html
@@ -0,0 +1,236 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script src="http://code.jquery.com/jquery.js" type="text/javascript"></script>
+ <script src="../../jsrender.js" type="text/javascript"></script>
+ <link href="../resources/demos.css" rel="stylesheet" type="text/css" />
+
+ <link href="../resources/movielist.css" rel="stylesheet" type="text/css" />
+</head>
+<body>
+<a href="index.html">Home</a><br />
+
+<h3>Example Scenario: Inserting "and" and "," separators between words</h3>
+
+<!---------------------- First Example ---------------------->
+
+<div class="subhead">Example 1: Expressions in tags, and template parameters:</div>
+
+<pre>
+ {{for languages ~count=languages.length}}
+ ...
+ {{if #index === ~count-2}} and {{else #index < ~count-2}}, {{/if}}
+ ...
+ {{/for}}
+</pre>
+
+<script id="movieTemplate1" type="text/x-jsrender">
+ <tr>
+ <td>{{:title}}</td>
+ <td>
+ {{for languages ~count=languages.length}}
+ {{:name}}{{if #index === ~count-2}} and {{else #index < ~count-2}}, {{/if}}
+ {{/for}}
+ </td>
+ </tr>
+</script>
+
+<table><tr class="header"><th>Title</th><th>Languages</th></tr>
+ <tbody id="movieList1"></tbody>
+</table>
+
+<!---------------------- Second Example ---------------------->
+
+<div class="subhead">Example 2: Custom helper functions:</div>
+
+<pre>
+ {{for languages}}
+ ...
+ {{if ~nextToLast()}} and {{else ~notLast()}}, {{/if}}
+ ...
+ {{/for}}
+</pre>
+
+<script id="movieTemplate2" type="text/x-jsrender">
+ <tr>
+ <td>{{:title}}</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 id="movieList2"></tbody>
+</table>
+<br />
+
+<!---------------------- Third Example ---------------------->
+
+<h3>Using "allowCode"</h3>
+
+<div class="subhead">Note: <em>The allowCode feature is powerful, but leads to poor separation of concerns, and poor maintainability.
+<br />It is therefore only available as an opt-in feature on a per template basis.
+<br /><br />The following two examples illustrate its use, but are not the recommended approach. The built-in expression support,
+<br />custom tags, helper functions etc. provide a better solution for almost all scenarios, as in the two examples above.</em></div>
+<br />
+
+<div class="subhead">Example 3: allowCode, for program flow:</div>
+
+<pre>
+$.templates( "movieTmpl", {
+ markup: "#movieTemplate",
+ allowCode: true
+});
+
+{{*
+ if ( myexpression ) {
+}}
+ ...
+{{*
+ }
+}}
+</pre>
+
+<script id="movieTemplate3" type="text/x-jsrender">
+ <tr>
+ <td>{{:title}}</td>
+ <td>
+ {{for languages}}
+ {{:name}}{{*
+
+ if ( view.index === view.parent.data.length - 2 ) {
+
+ }} and {{*
+
+ } else if ( view.index < view.parent.data.length - 2 ) {
+
+ }}, {{* } }}
+ {{/for}}
+ </td>
+ </tr>
+</script>
+
+<table><tr class="header"><th>Title</th><th>Languages</th></tr>
+ <tbody id="movieList3"></tbody>
+</table>
+
+<!---------------------- Fourth Example ---------------------->
+
+<div class="subhead">Example 4: allowCode, for returning content:</div>
+
+<pre>
+$.templates( "movieTmpl", {
+ markup: "#movieTemplate",
+ allowCode: true
+});
+
+{{*
+ if ( myexpression ) {
+ ret += ...;
+ ...
+ }
+}}
+</pre>
+
+<script id="movieTemplate4" type="text/x-jsrender">
+ <tr>
+ <td>{{:title}}</td>
+ <td>
+ {{for languages}}
+ {{:name}}{{*
+
+ if ( view.index === view.parent.data.length - 2 ) {
+ ret += " and";
+ } else if ( view.index < view.parent.data.length - 2 ) {
+ ret+= ",";
+ }
+
+ }}
+ {{/for}}
+ </td>
+ </tr>
+</script>
+
+<table><tr class="header"><th>Title</th><th>Languages</th></tr>
+ <tbody id="movieList4"></tbody>
+</table>
+
+
+<script type="text/javascript">
+
+ $.views.helpers({
+
+ nextToLast: function() {
+ var view = this;
+ return view.index === view.parent.data.length - 2;
+ },
+
+ notLast: function() {
+ var view = this;
+ return view.index !== view.parent.data.length - 1;
+ }
+ });
+
+ var movies = [
+ {
+ title: "Meet Joe Black",
+ languages: [
+ { name: "English" },
+ { name: "French" }
+ ],
+ subtitles: [
+ { name: "English" },
+ { name: "French" },
+ { name: "Chinese" }
+ ]
+ },
+ {
+ title: "Eyes Wide Shut",
+ languages: [
+ { name: "French" },
+ { name: "German" },
+ { name: "Spanish" }
+ ],
+ subtitles: [
+ { name: "English" }
+ ]
+ }
+ ];
+
+ $.templates({
+ movieTmpl1: "#movieTemplate1",
+ movieTmpl2: "#movieTemplate2",
+ movieTmpl3: {
+ markup: "#movieTemplate3",
+ allowCode: true
+ },
+ movieTmpl4: {
+ markup: "#movieTemplate4",
+ allowCode: true
+ }
+ });
+
+ $( "#movieList1" ).html(
+ $.render.movieTmpl1( movies )
+ );
+
+ $( "#movieList2" ).html(
+ $.render.movieTmpl2( movies )
+ );
+
+ $( "#movieList3" ).html(
+ $.render.movieTmpl3( movies )
+ );
+
+ $( "#movieList4" ).html(
+ $.render.movieTmpl4( movies )
+ );
+
+</script>
+
+</body>
+</html>
View
94 demos/step-by-step/13b_allow-code.html
@@ -1,94 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <script src="http://code.jquery.com/jquery.js" type="text/javascript"></script>
- <script src="../../jsrender.js" type="text/javascript"></script>
- <link href="../resources/demos.css" rel="stylesheet" type="text/css" />
-
- <link href="../resources/movielist.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<a href="index.html">Home</a><br />
-
-<h3>Allowing code within templates: returning content</h3>
-
-<pre>
-$.templates( "movieTmpl", {
- markup: "#movieTemplate",
- allowCode: true
-});
-
-{{*
- if ( myexpression ) {
- ret += ...;
- ...
- }
-}}
-</pre>
-
-<!--================ Demo ================-->
-
-<script id="movieTemplate" type="text/x-jsrender">
- <tr>
- <td>{{:title}}</td>
- <td>
- {{for languages}}
- {{:name}}{{*
-
- if ( view.index === view.parent.data.length - 2 ) {
- ret += " and";
- } else if ( view.index < view.parent.data.length - 2 ) {
- ret+= ",";
- }
-
- }}
- {{/for}}
- </td>
- </tr>
-</script>
-
-<table><tr class="header"><th>Title</th><th>Languages</th></tr>
- <tbody id="movieList"></tbody>
-</table>
-
-<script type="text/javascript">
-
- var movies = [
- {
- title: "Meet Joe Black",
- languages: [
- { name: "English" },
- { name: "French" }
- ],
- subtitles: [
- { name: "English" },
- { name: "French" },
- { name: "Chinese" }
- ]
- },
- {
- title: "Eyes Wide Shut",
- languages: [
- { name: "French" },
- { name: "German" },
- { name: "Spanish" }
- ],
- subtitles: [
- { name: "English" }
- ]
- }
- ];
-
- $.templates( "movieTmpl", {
- markup: "#movieTemplate",
- allowCode: true
- });
-
- $( "#movieList" ).html(
- $.render.movieTmpl( movies )
- );
-
-</script>
-
-</body>
-</html>
View
0 demos/step-by-step/12_layout-templates.html → demos/step-by-step/14_layout-templates.html
File renamed without changes.
View
9 demos/step-by-step/14_without-jquery.html → demos/step-by-step/15_without-jquery.html
@@ -11,6 +11,15 @@
<h3>JsRender without jQuery</h3>
+<pre>
+ jsviews.templates({
+ movieTemplate: document.getElementById( "movieTemplate" ).innerHTML,
+ ...
+ });
+
+ document.getElementById( "movieList" ).innerHTML = jsviews.render.movieTemplate( movies );
+</pre>
+
<script id="movieTemplate" type="text/x-jsrender">
<tr>
<td>{{:title}}</td>
View
10 demos/step-by-step/index.html
@@ -20,10 +20,10 @@
<a href="08_custom-tags.html">Custom tags</a><br />
<a href="09_helper-functions.html">'Helper' functions</a><br />
<a href="10_comparison-tests.html">Comparison tests</a><br />
-<a href="11_default-values-scenario.html">Default values scenario</a><br />
-<a href="12_layout-templates.html">Layout templates</a><br />
-<a href="13_allow-code.html">Allowing code - program flow</a><br />
-<a href="13b_allow-code.html">Allowing code - returning content</a><br />
-<a href="14_without-jquery.html">JsRender without jQuery</a><br />
+<a href="11_default-values-scenario.html">'Default values' scenario</a><br />
+<a href="12_iterating-through-fields-scenario.html">'Iterating through fields' scenario</a><br />
+<a href="13_separators-scenario.html">'Separators' scenario</a><br />
+<a href="14_layout-templates.html">Layout templates</a><br />
+<a href="15_without-jquery.html">JsRender without jQuery</a><br />
</body>
</html>
View
9 jsrender.js
@@ -6,7 +6,7 @@
* Copyright 2012, Boris Moore
* Released under the MIT License.
*/
-// informal pre beta commit counter: 3
+// informal pre beta commit counter: 4
this.jsviews || this.jQuery && jQuery.views || (function( window, undefined ) {
@@ -269,6 +269,7 @@ function converters( name, converterFn ) {
//=================
// renderContent
//=================
+var foo = /\{\{(?:(?:(\w+(?=[\/\s\}]))|(?:(\w+)?(:)|(>)|(\*)))\s*((?:[^\}]|\}(?!\}))*?)(\/)?|(?:\/(\w+)))\}\}/g
function renderContent( data, context, parentView, path, index ) {
// Render template against data as a tree of subviews (nested template), or as a string (top-level template).
@@ -466,10 +467,10 @@ function tmplFn( markup, tmpl, bind ) {
for ( i = 0; i < l; i++ ) {
// AST nodes: [ tagName, converter, params, content, hash, contentMarkup ]
node = astTop[ i ];
- if ( node[ 0 ] === "*" ) {
- code = code.slice( 0, i ? -1 : -3 ) + ";" + node[ 1 ] + (i + 1 < l ? "ret+=" : "");
- } else if ( "" + node === node ) { // type string
+ if ( "" + node === node ) { // type string
code += '"' + node + '"+';
+ } else if ( node[ 0 ] === "*" ) {
+ code = code.slice( 0, i ? -1 : -3 ) + ";" + node[ 1 ] + (i + 1 < l ? "ret+=" : "");
} else {
tag = node[ 0 ];
converter = node[ 1 ];
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;"), 82, 'Can set debug=true on nested template' );
+ equal( jsviews.templates.tmplWithNestedResources.templates.templateWithDebug.fn.toString().indexOf("debugger;") > 0, true, 'Can set debug=true on nested template' );
});
View
2 test/unit/jsrender-tests-with-jquery.js
@@ -84,7 +84,7 @@ test("templates", function() {
debug:true
}
});
- equal( $.templates.tmplFromString.fn.toString().indexOf("debugger;") + $.templates.scriptTmpl.fn.toString().indexOf("debugger;"), 152, 'Debug a template: set debug:true on object' );
+ equal( $.templates.tmplFromString.fn.toString().indexOf("debugger;") > 0 && $.templates.scriptTmpl.fn.toString().indexOf("debugger;") > 0, true, 'Debug a template: set debug:true on object' );
});
test("render", function() {

0 comments on commit 9fac207

Please sign in to comment.