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 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: 2
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 ( !prevNode && node.nodeType === 1 ) {
423
- if ( viewDepth++ === 0 ) {
424
- // Add top-level element nodes to view.nodes
425
- currentView.nodes.push( node );
426
- }
427
- if ( linkMarkup = node.getAttribute( jsv.linkAttr ) ) {
428
- linkIndex = currentView._lnk++;
429
- // Compiled linkFn expressions are stored in the tmpl.links array of the template
430
- links = currentView.links || currentView.tmpl.links;
431
- if ( !(link = links[ linkIndex ] )) {
432
- link = links [ linkIndex ] = {};
433
- if ( linkMarkup.charAt(linkMarkup.length-1) !== "}" ) {
434
- // Simplified syntax is used: data-link="expression"
435
- // Convert to data-link="{:expression}", or for inputs, data-link="{:expression:}" for (default) two-way binding
436
- linkMarkup = delimOpen1 + ":" + linkMarkup + ($.nodeName( node, "input" ) ? ":" : "") + delimClose0;
437
- }
438
- while( tokens = rTag.exec( linkMarkup )) { // TODO require } to be followed by whitespace or $, and remove the \}(!\}) option.
439
- // Iterate over the data-link expressions, for different target attrs, e.g. <input data-link="{:firstName:} title{:~description(firstName, lastName)}"
440
- // tokens: [all, attr, tag, converter, colon, html, code, linkedParams]
441
- attr = tokens[ 1 ];
442
- expression = tokens[ 2 ];
443
- if ( tokens[ 5 ]) {
444
- // Only for {:} link"
445
- if ( !attr && (convertBack = /^.*:([\w$]*)$/.exec( tokens[ 8 ] ))) {
446
- // two-way binding
447
- convertBack = convertBack[ 1 ];
448
- if ( cbLength = convertBack.length ) {
449
- // There is a convertBack function
450
- expression = tokens[ 2 ].slice( 0, -cbLength - 1 ) + delimClose0; // Remove the convertBack string from expression.
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
- if ( convertBack === null ) {
454
- convertBack = undefined;
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
- for ( attr in link ) {
467
- bindDataLinkTarget(
468
- currentView.data|| data, //source
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
- while ( node && node !== nextNode ) {
486
- if ( node.nodeType === 1 ) {
487
- linkViews( node, currentView, nextNode, viewDepth, data, context );
488
- } else if ( node.nodeType === 8 && (tokens = rTmplOrItemComment.exec( node.nodeValue ))) {
489
- // tokens: [ all, slash, 'item', 'tmpl', path, index, tmplParam ]
490
- parentNode = node.parentNode;
491
- if ( tokens[ 1 ]) {
492
- // <!--/item--> or <!--/tmpl-->
493
- currentView.nextNode = node;
494
- if ( currentView.ctx.onAfterCreate ) {
495
- currentView.ctx.onAfterCreate.call( currentView, currentView );
496
- }
497
- if ( tokens[ 2 ]) {
498
- // An item close tag: <!--/item-->
499
- currentView = parent;
500
- } else {
501
- // A tmpl close tag: <!--/tmpl-->
502
- return node;
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
- // A tmpl open tag: <!--tmpl(path) name-->
516
- parentElViews.push(
517
- view = linkedView( currentView.views[ tokens[ 5 ]] )
518
- );
519
- view.prevNode = node;
520
- // Jump to the nextNode of the tmpl view
521
- node = linkViews( node, view, nextNode, 0, undefined, undefined, undefined, 0 );
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
- } else if ( viewDepth === 0 ) {
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: 3
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 or html or code
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 ( node[ 0 ] === "*" ) {
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 = new Function( "data, view, j, b, u", fnDeclStr
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
- // If selector is valid and returns at least one element, get first element
630
- elem = value.nodeType > 0 ? value : !rTmplString.test( value ) && jQuery && jQuery( value )[0];
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
@@ -1,5 +1,5 @@
1
1
  module Sprockets
2
2
  module JSRender
3
- VERSION = '0.1.2'
3
+ VERSION = '0.1.3'
4
4
  end
5
5
  end
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.2
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-06 00:00:00.000000000 Z
12
+ date: 2012-04-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: actionpack