sprockets-jsrender 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +10 -8
- data/app/assets/javascripts/jquery.views.js +98 -96
- data/app/assets/javascripts/jsrender.js +25 -12
- data/lib/sprockets/jsrender/version.rb +1 -1
- metadata +2 -2
data/README
CHANGED
@@ -3,20 +3,22 @@ Sprockets jsRender/jsViews
|
|
3
3
|
|
4
4
|
This gem adds jsRender/jsViews templates as tilt templates for Sprockets 2 in Rails 3.1.
|
5
5
|
|
6
|
-
Thanks
|
7
|
-
======
|
8
|
-
Inpired by sprockets-jquery-tmpl by Ryan Dy (https://github.com/rdy/sprockets-jquery-tmpl)
|
9
|
-
jsrender and jsviews are created bu Boris Moore (https://github.com/BorisMoore/jsrender)
|
10
|
-
|
11
6
|
Installing
|
12
7
|
==========
|
13
8
|
|
14
9
|
1. Add the gem to bundler or install: `gem install sprockets-jsrender`
|
15
10
|
2. Add to your app/assets/javascripts/application.js the following lines
|
16
11
|
//= require jsrender
|
17
|
-
//= require jquery.observable
|
18
|
-
//= require jquery.views
|
12
|
+
//= require jquery.observable //(optional)
|
13
|
+
//= require jquery.views //(optional)
|
14
|
+
|
15
|
+
Any files in assets/javascripts/jsrender will be automatically added to list of templates using the path from that directory - i.e. assets/javascripts/jsrender/index.jsr will be mapped to $.render ["index"]( obj )
|
16
|
+
|
17
|
+
|
18
|
+
Acknowledgments
|
19
|
+
===============
|
20
|
+
Inspired by sprockets-jquery-tmpl by Ryan Dy (https://github.com/rdy/sprockets-jquery-tmpl)
|
21
|
+
jsrender and jsviews are created bu Boris Moore (https://github.com/BorisMoore/jsrender)
|
19
22
|
|
20
|
-
Any files in assets/javascripts/jsrender will be automatically added to list of templates using the path from that directory (i.e. assets/javascripts/jsrender/examples/index.jsr will be mapped to $.render("examples/index") )
|
21
23
|
|
22
24
|
Copyright (c) 2012 Enrico Rubboli, released under the MIT license
|
@@ -7,7 +7,7 @@
|
|
7
7
|
* Copyright 2012, Boris Moore
|
8
8
|
* Released under the MIT License.
|
9
9
|
*/
|
10
|
-
// informal pre beta commit counter:
|
10
|
+
// informal pre beta commit counter: 3
|
11
11
|
|
12
12
|
this.jQuery && jQuery.link || (function( global, undefined ) {
|
13
13
|
// global is the this object, which is window when running in the usual browser environment.
|
@@ -419,113 +419,115 @@ function linkViews( node, parent, nextNode, depth, data, context, prevNode, inde
|
|
419
419
|
context = context || {};
|
420
420
|
node = prevNode || node;
|
421
421
|
|
422
|
-
if (
|
423
|
-
if (
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
link = links
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
//
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
422
|
+
if ( node ) {
|
423
|
+
if ( !prevNode && node.nodeType === 1 ) {
|
424
|
+
if ( viewDepth++ === 0 ) {
|
425
|
+
// Add top-level element nodes to view.nodes
|
426
|
+
currentView.nodes.push( node );
|
427
|
+
}
|
428
|
+
if ( linkMarkup = node.getAttribute( jsv.linkAttr ) ) {
|
429
|
+
linkIndex = currentView._lnk++;
|
430
|
+
// Compiled linkFn expressions are stored in the tmpl.links array of the template
|
431
|
+
links = currentView.links || currentView.tmpl.links;
|
432
|
+
if ( !(link = links[ linkIndex ] )) {
|
433
|
+
link = links [ linkIndex ] = {};
|
434
|
+
if ( linkMarkup.charAt(linkMarkup.length-1) !== "}" ) {
|
435
|
+
// Simplified syntax is used: data-link="expression"
|
436
|
+
// Convert to data-link="{:expression}", or for inputs, data-link="{:expression:}" for (default) two-way binding
|
437
|
+
linkMarkup = delimOpen1 + ":" + linkMarkup + ($.nodeName( node, "input" ) ? ":" : "") + delimClose0;
|
438
|
+
}
|
439
|
+
while( tokens = rTag.exec( linkMarkup )) { // TODO require } to be followed by whitespace or $, and remove the \}(!\}) option.
|
440
|
+
// Iterate over the data-link expressions, for different target attrs, e.g. <input data-link="{:firstName:} title{:~description(firstName, lastName)}"
|
441
|
+
// tokens: [all, attr, tag, converter, colon, html, code, linkedParams]
|
442
|
+
attr = tokens[ 1 ];
|
443
|
+
expression = tokens[ 2 ];
|
444
|
+
if ( tokens[ 5 ]) {
|
445
|
+
// Only for {:} link"
|
446
|
+
if ( !attr && (convertBack = /^.*:([\w$]*)$/.exec( tokens[ 8 ] ))) {
|
447
|
+
// two-way binding
|
448
|
+
convertBack = convertBack[ 1 ];
|
449
|
+
if ( cbLength = convertBack.length ) {
|
450
|
+
// There is a convertBack function
|
451
|
+
expression = tokens[ 2 ].slice( 0, -cbLength - 1 ) + delimClose0; // Remove the convertBack string from expression.
|
452
|
+
}
|
453
|
+
}
|
454
|
+
if ( convertBack === null ) {
|
455
|
+
convertBack = undefined;
|
451
456
|
}
|
452
457
|
}
|
453
|
-
|
454
|
-
|
458
|
+
// Compile the linkFn expression which evaluates and binds a data-link expression
|
459
|
+
// TODO - optimize for the case of simple data path with no conversion, helpers, etc.:
|
460
|
+
// i.e. data-link="a.b.c". Avoid creating new instances of Function every time. Can use a default function for all of these...
|
461
|
+
link[ attr ] = jsv.tmplFn( delimOpen0 + expression + delimClose1, undefined, TRUE );
|
462
|
+
if ( !attr && convertBack !== undefined ) {
|
463
|
+
link[ attr ].to = convertBack;
|
455
464
|
}
|
456
465
|
}
|
457
|
-
// Compile the linkFn expression which evaluates and binds a data-link expression
|
458
|
-
// TODO - optimize for the case of simple data path with no conversion, helpers, etc.:
|
459
|
-
// i.e. data-link="a.b.c". Avoid creating new instances of Function every time. Can use a default function for all of these...
|
460
|
-
link[ attr ] = jsv.tmplFn( delimOpen0 + expression + delimClose1, undefined, TRUE );
|
461
|
-
if ( !attr && convertBack !== undefined ) {
|
462
|
-
link[ attr ].to = convertBack;
|
463
|
-
}
|
464
466
|
}
|
467
|
+
for ( attr in link ) {
|
468
|
+
bindDataLinkTarget(
|
469
|
+
currentView.data || data, //source
|
470
|
+
node, //target
|
471
|
+
attr, //attr
|
472
|
+
link[ attr ], //compiled link markup expression
|
473
|
+
currentView //view
|
474
|
+
);
|
475
|
+
}
|
476
|
+
// TODO - Add one-way-to-source support
|
477
|
+
// if ( linkMarkup.lastIndexOf( "toSrc{", 0 ) === 0 ) {
|
478
|
+
// linkMarkup = "{toSrc " + linkMarkup.slice(6);
|
479
|
+
// }
|
465
480
|
}
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
node, //target
|
470
|
-
attr, //attr
|
471
|
-
link[ attr ], //compiled link markup expression
|
472
|
-
currentView //view
|
473
|
-
);
|
474
|
-
}
|
475
|
-
// TODO - Add one-way-to-source support
|
476
|
-
// if ( linkMarkup.lastIndexOf( "toSrc{", 0 ) === 0 ) {
|
477
|
-
// linkMarkup = "{toSrc " + linkMarkup.slice(6);
|
478
|
-
// }
|
481
|
+
node = node.firstChild;
|
482
|
+
} else {
|
483
|
+
node = node.nextSibling;
|
479
484
|
}
|
480
|
-
node = node.firstChild;
|
481
|
-
} else {
|
482
|
-
node = node.nextSibling;
|
483
|
-
}
|
484
485
|
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
} else {
|
505
|
-
// <!--item--> or <!--tmpl-->
|
506
|
-
parentElViews = parentElViews || jsViewsData( parentNode, viewStr, TRUE );
|
507
|
-
if ( tokens[ 2 ]) {
|
508
|
-
// An item open tag: <!--item-->
|
509
|
-
parentElViews.push(
|
510
|
-
currentView = linkedView( currentView.views[ index ] )
|
511
|
-
);
|
512
|
-
index++;
|
513
|
-
currentView.prevNode = node;
|
486
|
+
while ( node && node !== nextNode ) {
|
487
|
+
if ( node.nodeType === 1 ) {
|
488
|
+
linkViews( node, currentView, nextNode, viewDepth, data, context );
|
489
|
+
} else if ( node.nodeType === 8 && (tokens = rTmplOrItemComment.exec( node.nodeValue ))) {
|
490
|
+
// tokens: [ all, slash, 'item', 'tmpl', path, index, tmplParam ]
|
491
|
+
parentNode = node.parentNode;
|
492
|
+
if ( tokens[ 1 ]) {
|
493
|
+
// <!--/item--> or <!--/tmpl-->
|
494
|
+
currentView.nextNode = node;
|
495
|
+
if ( currentView.ctx.onAfterCreate ) {
|
496
|
+
currentView.ctx.onAfterCreate.call( currentView, currentView );
|
497
|
+
}
|
498
|
+
if ( tokens[ 2 ]) {
|
499
|
+
// An item close tag: <!--/item-->
|
500
|
+
currentView = parent;
|
501
|
+
} else {
|
502
|
+
// A tmpl close tag: <!--/tmpl-->
|
503
|
+
return node;
|
504
|
+
}
|
514
505
|
} else {
|
515
|
-
//
|
516
|
-
parentElViews
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
506
|
+
// <!--item--> or <!--tmpl-->
|
507
|
+
parentElViews = parentElViews || jsViewsData( parentNode, viewStr, TRUE );
|
508
|
+
if ( tokens[ 2 ]) {
|
509
|
+
// An item open tag: <!--item-->
|
510
|
+
parentElViews.push(
|
511
|
+
currentView = linkedView( currentView.views[ index ] )
|
512
|
+
);
|
513
|
+
index++;
|
514
|
+
currentView.prevNode = node;
|
515
|
+
} else {
|
516
|
+
// A tmpl open tag: <!--tmpl(path) name-->
|
517
|
+
parentElViews.push(
|
518
|
+
view = linkedView( currentView.views[ tokens[ 5 ]] )
|
519
|
+
);
|
520
|
+
view.prevNode = node;
|
521
|
+
// Jump to the nextNode of the tmpl view
|
522
|
+
node = linkViews( node, view, nextNode, 0, undefined, undefined, undefined, 0 );
|
523
|
+
}
|
522
524
|
}
|
525
|
+
} else if ( viewDepth === 0 ) {
|
526
|
+
// Add top-level non-element nodes to view.nodes
|
527
|
+
currentView.nodes.push( node );
|
523
528
|
}
|
524
|
-
|
525
|
-
// Add top-level non-element nodes to view.nodes
|
526
|
-
currentView.nodes.push( node );
|
529
|
+
node = node.nextSibling;
|
527
530
|
}
|
528
|
-
node = node.nextSibling;
|
529
531
|
}
|
530
532
|
}
|
531
533
|
|
@@ -6,7 +6,7 @@
|
|
6
6
|
* Copyright 2012, Boris Moore
|
7
7
|
* Released under the MIT License.
|
8
8
|
*/
|
9
|
-
// informal pre beta commit counter:
|
9
|
+
// informal pre beta commit counter: 6
|
10
10
|
|
11
11
|
this.jsviews || this.jQuery && jQuery.views || (function( window, undefined ) {
|
12
12
|
|
@@ -81,7 +81,7 @@ function setDelimiters( openChars, closeChars ) {
|
|
81
81
|
// Build regex with new delimiters
|
82
82
|
jsv.rTag = rTag // make rTag available to JsViews (or other components) for parsing binding expressions
|
83
83
|
= secondOpenChar
|
84
|
-
// tag (followed by / space or }) or colon
|
84
|
+
// tag (followed by / space or }) or colon or html or code
|
85
85
|
+ "(?:(?:(\\w+(?=[\\/\\s" + firstCloseChar + "]))|(?:(\\w+)?(:)|(>)|(\\*)))"
|
86
86
|
// params
|
87
87
|
+ "\\s*((?:[^" + firstCloseChar + "]|" + firstCloseChar + "(?!" + secondCloseChar + "))*?)"
|
@@ -356,8 +356,8 @@ function renderContent( data, context, parentView, path, index ) {
|
|
356
356
|
// Generate a reusable function that will serve to render a template against data
|
357
357
|
// (Compile AST then build template function)
|
358
358
|
|
359
|
-
function syntaxError() {
|
360
|
-
throw "Syntax error";
|
359
|
+
function syntaxError( message, e ) {
|
360
|
+
throw (e ? (e.name + ': "' + e.message + '"') : "Syntax error") + (message ? (" \n" + message) : "");
|
361
361
|
}
|
362
362
|
|
363
363
|
function tmplFn( markup, tmpl, bind ) {
|
@@ -466,10 +466,10 @@ function tmplFn( markup, tmpl, bind ) {
|
|
466
466
|
for ( i = 0; i < l; i++ ) {
|
467
467
|
// AST nodes: [ tagName, converter, params, content, hash, contentMarkup ]
|
468
468
|
node = astTop[ i ];
|
469
|
-
if (
|
470
|
-
code = code.slice( 0, i ? -1 : -3 ) + ";" + node[ 1 ] + (i + 1 < l ? "ret+=" : "");
|
471
|
-
} else if ( "" + node === node ) { // type string
|
469
|
+
if ( "" + node === node ) { // type string
|
472
470
|
code += '"' + node + '"+';
|
471
|
+
} else if ( node[ 0 ] === "*" ) {
|
472
|
+
code = code.slice( 0, i ? -1 : -3 ) + ";" + node[ 1 ] + (i + 1 < l ? "ret+=" : "");
|
473
473
|
} else {
|
474
474
|
tag = node[ 0 ];
|
475
475
|
converter = node[ 1 ];
|
@@ -498,7 +498,7 @@ function tmplFn( markup, tmpl, bind ) {
|
|
498
498
|
+ ")+";
|
499
499
|
}
|
500
500
|
}
|
501
|
-
code =
|
501
|
+
code = fnDeclStr
|
502
502
|
+ (getsValue ? "v," : "")
|
503
503
|
+ (hasTag ? "t=j.tag," : "")
|
504
504
|
+ (hasConverter ? "c=j.convert," : "")
|
@@ -508,8 +508,13 @@ function tmplFn( markup, tmpl, bind ) {
|
|
508
508
|
+ (allowCode ? 'ret=' : 'return ')
|
509
509
|
+ code.slice( 0, -1 ) + ";\n\n"
|
510
510
|
+ (allowCode ? "return ret;" : "")
|
511
|
-
+ "}catch(e){return j.err(e);}"
|
512
|
-
|
511
|
+
+ "}catch(e){return j.err(e);}";
|
512
|
+
|
513
|
+
try {
|
514
|
+
code = new Function( "data, view, j, b, u", code );
|
515
|
+
} catch(e) {
|
516
|
+
syntaxError( "Error in compiled template code:\n" + code, e );
|
517
|
+
}
|
513
518
|
|
514
519
|
// Include only the var references that are needed in the code
|
515
520
|
if ( tmpl ) {
|
@@ -626,8 +631,16 @@ function compile( name, tmpl, parent, options ) {
|
|
626
631
|
// Return the template object, if already compiled, or the markup string
|
627
632
|
|
628
633
|
if ( ("" + value === value) || value.nodeType > 0 ) {
|
629
|
-
|
630
|
-
|
634
|
+
try {
|
635
|
+
elem = value.nodeType > 0
|
636
|
+
? value
|
637
|
+
: !rTmplString.test( value )
|
638
|
+
// If value is a string and does not contain HTML or tag content, then test as selector
|
639
|
+
&& jQuery && jQuery( value )[0];
|
640
|
+
// If selector is valid and returns at least one element, get first element
|
641
|
+
// If invalid, jQuery will throw. We will stay with the original string.
|
642
|
+
} catch(e) {}
|
643
|
+
|
631
644
|
if ( elem && elem.type ) {
|
632
645
|
// It is a script element
|
633
646
|
// Create a name for data linking if none provided
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sprockets-jsrender
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-04-
|
12
|
+
date: 2012-04-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: actionpack
|