Permalink
Browse files

Design change for #index, fix for

issue #96.
#key corresponds to what was #index, and #index is now the inherited
integer index from what the nearest parent view that has an integer index.
So #index is now unchanged when you wrap {{:#index}} in and {{if}} block.

Signed-off-by: Boris Moore <borismoore@gmail.com>
  • Loading branch information...
BorisMoore committed May 10, 2012
1 parent 53c8de7 commit 4264cd73b10976fbef683f21f62686adfc06ca74
Showing with 90 additions and 61 deletions.
  1. +1 −0 README.md
  2. +2 −0 demos/index.html
  3. +70 −60 jsrender.js
  4. +17 −1 test/unit/jsrender-tests-no-jquery.js
View
@@ -4,5 +4,6 @@ To view demo pages (on gh-branch) navigate to [http://borismoore.github.com/jsre
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/>
+See also [JsRender Fundamentals](http://johnpapa.net/new-course-on-jsrender-templating-fundamentals-with-javascript) training course from John Papa on [Pluralsight](http://pluralsight.net)</br>
**Warning:** JsRender is close to beta, but not yet officially beta, so there may still be changes to APIs and features in the coming period.<br/>
View
@@ -39,6 +39,8 @@ <h2>JsRender: Next-generation jQuery Templates</h2>
<div class="box">
<div><a href="http://www.slideshare.net/BorisMoore/jsviews-next-generation-jquery-templates" >Slide deck: jQuery Conference October 2011</a></div>
<div><a href="http://msdn.microsoft.com/en-us/magazine/hh882454.aspx" >MSDN 'Client Insight' article on JsRender</a></div>
+ <div>Training course: <a href="http://johnpapa.net/new-course-on-jsrender-templating-fundamentals-with-javascript" >JsRender Fundamentals</a> from John Papa on <a href="http://pluralsight.net/" >Pluralsight</a> (3 hours of video)</div>
+
</div>
</body>
View
@@ -6,7 +6,7 @@
* Copyright 2012, Boris Moore
* Released under the MIT License.
*/
-// informal pre beta commit counter: 7
+// informal pre beta commit counter: 8
this.jsviews || this.jQuery && jQuery.views || (function( window, undefined ) {
@@ -159,30 +159,38 @@ function renderTag( tag, parentView, converter, content, tagObject ) {
// View constructor
//=================
-function View( context, path, parentView, data, template, index ) {
+function View( context, path, parentView, data, template, key ) {
// Constructor for view object in view hierarchy. (Augmented by JsViews if JsViews is loaded)
var views = parentView.views,
// TODO: add this, as part of smart re-linking on existing content ($.link method), or remove completely
-// self = parentView.views[ index ];
+// self = parentView.views[ key ];
// if ( !self ) { ... }
self = {
tmpl: template,
path: path,
parent: parentView,
data: data,
ctx: context,
+ // If the data is an array, this is an 'Array View' with a views array for each child 'Instance View'
+ // If the data is not an array, this is an 'Instance View' with a views 'map' object for any child nested views
views: $.isArray( data ) ? [] : {},
hlp: getHelper
};
- if ( $.isArray( views )) {
+ if ( $.isArray( views ) ) {
+ // Parent is an 'Array View'. Add this view to its views array
views.splice(
- self.index = index !== undefined
- ? index
- : views.length, 0, self
- );
+ // self.key = self.key - the index in the parent view array
+ self.key = self.index = key !== undefined
+ ? key
+ : views.length,
+ 0, self);
} else {
- views[ self.index = "_" + autoViewKey++ ] = self;
+ // Parent is an 'Instance View'. Add this view to its views object
+ // self.key = is the key in the parent view map
+ views[ self.key = "_" + autoViewKey++ ] = self;
+ // self.index = is index of the parent
+ self.index = parentView.index;
}
return self;
}
@@ -264,11 +272,11 @@ function converters( name, converterFn ) {
// renderContent
//=================
-function renderContent( data, context, path, index, parentView ) {
+function renderContent( data, context, path, key, parentView ) {
// 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 presenter objects)
var i, l, dataItem, newView, itemWrap, itemsWrap, itemResult, parentContext, tmpl, layout, onRender, props,
- swapContent = index === TRUE,
+ swapContent = key === TRUE,
self = this,
result = "";
@@ -284,62 +292,64 @@ function renderContent( data, context, path, index, parentView ) {
context = self.ctx || context;
parentView = parentView || self.view;
path = path || self.path;
- index = index || self.index;
+ key = key || self.key;
props = self.props;
} else {
tmpl = self.jquery && self[0] // This is a call $.fn.render
|| self; // This is a call from tmpl.render
}
parentView = parentView || jsv.topView;
parentContext = parentView.ctx;
- layout = tmpl.layout;
- if ( data === parentView ) {
- // Inherit the data from the parent view.
- // This may be the contents of an {{if}} block
- data = parentView.data;
- layout = TRUE;
- }
-
- // Set additional context on views created here, (as modified context inherited from the parent, and be inherited by child views)
- // Note: If no jQuery, extend does not support chained copies - so limit extend() to two parameters
- // TODO make this reusable also for use in JsViews, for adding context passed in with the link() method.
- context = (context && context === parentContext)
- ? parentContext
- : context
- // if context, make copy
- // If context, merge context with copied parentContext
- ? extend( extend( {}, parentContext ), context )
- : parentContext;
-
- if ( context.link === FALSE ) {
- // Override inherited value of link by an explicit setting in props: link=false
- // The child views of an unlinked view are also unlinked. So setting child back to true will not have any effect.
- context.onRender = FALSE;
- }
- if ( !tmpl.fn ) {
- tmpl = templates[ tmpl ] || templates( tmpl );
- }
- onRender = context.onRender;
-
if ( tmpl ) {
- if ( $.isArray( data ) && !layout ) {
- // Create a view for the array, whose child views correspond to each data item.
- // (Note: if index and parentView are passed in along with parent view, treat as
- // insert -e.g. from view.addViews - so parentView is already the view item for array)
- newView = swapContent ? parentView : (index !== undefined && parentView) || View( context, path, parentView, data, tmpl, index );
- for ( i = 0, l = data.length; i < l; i++ ) {
- // Create a view for each data item.
- dataItem = data[ i ];
- itemResult = tmpl.fn( dataItem, View( context, path, newView, dataItem, tmpl, (index||0) + i ), jsv );
- result += onRender ? onRender( itemResult, tmpl, props ) : itemResult;
+ layout = tmpl.layout;
+ if ( data === parentView ) {
+ // Inherit the data from the parent view.
+ // This may be the contents of an {{if}} block
+ data = parentView.data;
+ layout = TRUE;
+ }
+
+ // Set additional context on views created here, (as modified context inherited from the parent, and be inherited by child views)
+ // Note: If no jQuery, extend does not support chained copies - so limit extend() to two parameters
+ // TODO make this reusable also for use in JsViews, for adding context passed in with the link() method.
+ context = (context && context === parentContext)
+ ? parentContext
+ : context
+ // if context, make copy
+ // If context, merge context with copied parentContext
+ ? extend( extend( {}, parentContext ), context )
+ : parentContext;
+
+ if ( context.link === FALSE ) {
+ // Override inherited value of link by an explicit setting in props: link=false
+ // The child views of an unlinked view are also unlinked. So setting child back to true will not have any effect.
+ context.onRender = FALSE;
+ }
+ if ( !tmpl.fn ) {
+ tmpl = templates[ tmpl ] || templates( tmpl );
+ }
+ onRender = context.onRender;
+
+ if ( tmpl ) {
+ if ( $.isArray( data ) && !layout ) {
+ // Create a view for the array, whose child views correspond to each data item.
+ // (Note: if key and parentView are passed in along with parent view, treat as
+ // insert -e.g. from view.addViews - so parentView is already the view item for array)
+ newView = swapContent ? parentView : (key !== undefined && parentView) || View( context, path, parentView, data, tmpl, key );
+ for ( i = 0, l = data.length; i < l; i++ ) {
+ // Create a view for each data item.
+ dataItem = data[ i ];
+ itemResult = tmpl.fn( dataItem, View( context, path, newView, dataItem, tmpl, (key||0) + i ), jsv );
+ result += onRender ? onRender( itemResult, tmpl, props ) : itemResult;
+ }
+ } else {
+ // Create a view for singleton data object.
+ newView = swapContent ? parentView : View( context, path, parentView, data, tmpl, key );
+ result += (data || layout) ? tmpl.fn( data, newView, jsv ) : "";
}
- } else {
- // Create a view for singleton data object.
- newView = swapContent ? parentView : View( context, path, parentView, data, tmpl, index );
- result += (data || layout) ? tmpl.fn( data, newView, jsv ) : "";
+ parentView.topKey = newView.key;
+ return onRender ? onRender( result, tmpl, props, newView.key, path ) : result;
}
- parentView.topKey = newView.index;
- return onRender ? onRender( result, tmpl, props, newView.index, path ) : result;
}
return ""; // No tmpl. Could throw...
}
@@ -714,7 +724,7 @@ function compile( name, tmpl, parent, options ) {
}
//==== /end of function compile ====
-function TmplObject( markup, options, parent, index ) {
+function TmplObject( markup, options, parent, key ) {
// Template object constructor
// nested helper function
@@ -737,8 +747,8 @@ function TmplObject( markup, options, parent, index ) {
tmpl.templates = extend( extend( {}, parent.templates ), options.templates );
}
tmpl.parent = parent;
- tmpl.name = parent.name + "[" + index + "]";
- tmpl.index = index;
+ tmpl.name = parent.name + "[" + key + "]";
+ tmpl.key = key;
}
extend( tmpl, options );
@@ -257,7 +257,7 @@ test("templates", function() {
});
test("render", function() {
- expect(14);
+ expect(17);
var tmpl1 = jsviews.templates( "myTmpl8", tmplString );
jsviews.templates( {
simple: "Content",
@@ -274,6 +274,22 @@ test("render", function() {
jsviews.templates( "myTmpl9", "A_{{for #data}}inner{{:name}}content{{/for}}_B" );
equal( jsviews.templates.myTmpl9.tmpls[0].render( person ), "innerJocontent", 'Access nested templates: jsviews.templates["myTmpl9[0]"];' );
+ jsviews.templates( "myTmpl10", "top index:{{:#index}}|{{for 1}}nested index:{{:#index}}|{{if #index===0}}nested if index:{{:#index}}|{{else}}nested else index:{{:#index}}|{{/if}}{{/for}}" );
+ equal( jsviews.render.myTmpl10(people), "top index:0|nested index:0|nested if index:0|top index:1|nested index:1|nested else index:1|",
+ '#index gives the integer index even in nested blocks' );
+ jsviews.templates( "myTmpl11", "top index:{{:#index}}|{{for people}}nested index:{{:#index}}|{{if #index===0}}nested if index:{{:#index}}|{{else}}nested else index:{{:#index}}|{{/if}}{{/for}}" );
+
+ equal( jsviews.render.myTmpl11({ people: people }), "top index:|nested index:0|nested if index:0|nested index:1|nested else index:1|",
+ '#index gives the integer index even in nested blocks' );
+
+ jsviews.helpers({ myKeyIsCorrect: function() {
+ return this.parent.views[this.key] === this;
+ }});
+ jsviews.templates( "myTmpl12", "top key:{{:~myKeyIsCorrect()}}|{{for people}}nested {{:~myKeyIsCorrect()}}|{{if #index===0}}nested if {{:~myKeyIsCorrect()}}|{{else}}nested else {{:~myKeyIsCorrect()}}|{{/if}}{{/for}}" );
+
+ equal( jsviews.render.myTmpl12({ people: people }), "top key:true|nested true|nested if true|nested true|nested else true|",
+ '#key gives the key of this view in the parent views collection/object' );
+
equal( jsviews.templates( tmplString ).render( person ), "A_Jo_B", 'Compile from string: var html = jsviews.templates( tmplString ).render( data );' );
equal( jsviews.render.myTmpl8( people ), "A_Jo_BA_Bill_B", 'jsviews.render.myTmpl( array );' );
equal( jsviews.render.simple([]), "", 'Empty array renders empty string' );

0 comments on commit 4264cd7

Please sign in to comment.