Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

code conformity per jslint specifications.

  • Loading branch information...
commit 2071180cfb3eaf9f67ac88f92c805de9c8275913 1 parent aa848fa
Paul Armstrong authored
8 README.md
View
@@ -23,7 +23,7 @@ Node-T is a templating engine inspired by the django syntax. It has a few extens
var template = require('node-t');
var tmpl = template.fromFile("/path/to/template.html");
- console.log( tmpl.render({names: ["Duke", "Django", "Louis"]}) );
+ console.log(tmpl.render({names: ["Duke", "Django", "Louis"]}));
### How it works
@@ -139,13 +139,13 @@ Node.js code
}
context.widgets = {
- analytics: function(context){
+ analytics: function (context) {
// this inside widget functions is bound to the widget object
return "<script>..." + this.uaCode + "...</script>";
},
- navigation: function(context){
+ navigation: function (context) {
var i, html = "";
- for( i=0; i<this.links; i++ )
+ for (i=0; i<this.links; i++)
html += "<a href='" + links[i] + "'>" + links[i] + "</a>";
return html;
}
193 helpers.js
View
@@ -14,119 +14,132 @@ var KEYWORDS = /^(Array|RegExpt|Object|String|Number|Math|Error|break|continue|d
var VALID_BLOCK_NAME = /^[A-Za-z]+[A-Za-z_0-9]*$/;
// Returns TRUE if the passed string is a valid javascript number or string literal
-function isLiteral( string ){
- var literal = false;
- // Check if it's a number literal
- if( NUMBER_LITERAL.test( string ) ){
- literal = true;
- }
-
- // Check if it's a valid string literal (throw exception otherwise)
- else if( (string[0] === string[string.length-1]) && (string[0] === "'" || string[0] === '"') ) {
- var teststr = string.substr( 1, string.length-2 ).split("").reverse().join("");
- if( string[0] === "'" && UNESCAPED_QUOTE.test( teststr ) || string[1] === '"' && UNESCAPED_DQUOTE.test( teststr ) ){
- throw new Error("Invalid string literal. Unescaped quote (" + string[0] + ") found.");
+function isLiteral(string) {
+ var literal = false,
+ teststr;
+
+ // Check if it's a number literal
+ if (NUMBER_LITERAL.test(string)) {
+ literal = true;
+ } else if ((string[0] === string[string.length - 1]) && (string[0] === "'" || string[0] === '"')) {
+ // Check if it's a valid string literal (throw exception otherwise)
+ teststr = string.substr(1, string.length - 2).split("").reverse().join("");
+
+ if (string[0] === "'" && UNESCAPED_QUOTE.test(teststr) || string[1] === '"' && UNESCAPED_DQUOTE.test(teststr)) {
+ throw new Error("Invalid string literal. Unescaped quote (" + string[0] + ") found.");
+ }
+
+ literal = true;
}
- literal = true;
- }
- return literal;
+ return literal;
}
// Returns TRUE if the passed string is a valid javascript string literal
-function isStringLiteral( string ){
- // Check if it's a valid string literal (throw exception otherwise)
- if( (string[0] === string[string.length-1]) && (string[0] === "'" || string[0] === '"') ) {
- var teststr = string.substr( 1, string.length-2 ).split("").reverse().join("");
- if( string[0] === "'" && UNESCAPED_QUOTE.test( teststr ) || string[1] === '"' && UNESCAPED_DQUOTE.test( teststr ) ){
- throw new Error("Invalid string literal. Unescaped quote (" + string[0] + ") found.");
+function isStringLiteral(string) {
+ // Check if it's a valid string literal (throw exception otherwise)
+ if ((string[0] === string[string.length - 1]) && (string[0] === "'" || string[0] === '"')) {
+ var teststr = string.substr(1, string.length - 2).split("").reverse().join("");
+
+ if (string[0] === "'" && UNESCAPED_QUOTE.test(teststr) || string[1] === '"' && UNESCAPED_DQUOTE.test(teststr)) {
+ throw new Error("Invalid string literal. Unescaped quote (" + string[0] + ") found.");
+ }
+
+ return true;
}
- return true;
- }
- return false;
+
+ return false;
}
// Variable names starting with __ are reserved.
-function isValidName( string ){
- return VALID_NAME.test(string) && !KEYWORDS.test(string) && string.substr(0,2) !== "__";
+function isValidName(string) {
+ return VALID_NAME.test(string) && !KEYWORDS.test(string) && string.substr(0, 2) !== "__";
}
// Variable names starting with __ are reserved.
-function isValidShortName( string ){
- return VALID_SHORT_NAME.test(string) && !KEYWORDS.test(string) && string.substr(0,2) !== "__";
+function isValidShortName(string) {
+ return VALID_SHORT_NAME.test(string) && !KEYWORDS.test(string) && string.substr(0, 2) !== "__";
}
// Checks if a name is a vlaid block name
-function isValidBlockName( string ){
- return VALID_BLOCK_NAME.test(string);
+function isValidBlockName(string) {
+ return VALID_BLOCK_NAME.test(string);
}
/**
- * Returns a valid javascript code that will
- * check if a variable (or property chain) exists
- * in the evaled context. For example:
- * check( "foo.bar.baz" )
- * will return the following string:
- * "typeof foo !== 'undefined' && typeof foo.bar !== 'undefined' && typeof foo.bar.baz !== 'undefined'"
- */
-exports.check = function( variable, context ){
- /* 'this' inside of the render function is bound to the tag closure which is meaningless, so we can't use it.
- * '__this' is bound to the original template whose render function we called.
- * Using 'this' in the HTML templates will result in '__this.__currentContext'. This is an additional context
- * for binding data to a specific template - e.g. binding widget data.
- */
- variable = variable.replace(/^this/, '__this.__currentContext');
-
- if( isLiteral( variable ) )
- return "(true)";
-
- var props = variable.split("."), chain = "", output = [];
-
- if( typeof context === 'string' && context.length )
- props.unshift( context );
-
- props.forEach(function(prop){
- chain += (chain ? (isNaN(prop) ? "." + prop : "[" + prop + "]") : prop);
- output.push( "typeof " + chain + " !== 'undefined'" )
- });
- return "(" + output.join(" && ") + ")";
-}
+* Returns a valid javascript code that will
+* check if a variable (or property chain) exists
+* in the evaled context. For example:
+* check("foo.bar.baz")
+* will return the following string:
+* "typeof foo !== 'undefined' && typeof foo.bar !== 'undefined' && typeof foo.bar.baz !== 'undefined'"
+*/
+exports.check = function (variable, context) {
+ /* 'this' inside of the render function is bound to the tag closure which is meaningless, so we can't use it.
+ * '__this' is bound to the original template whose render function we called.
+ * Using 'this' in the HTML templates will result in '__this.__currentContext'. This is an additional context
+ * for binding data to a specific template - e.g. binding widget data.
+ */
+ variable = variable.replace(/^this/, '__this.__currentContext');
+
+ if (isLiteral(variable)) {
+ return "(true)";
+ }
+
+ var props = variable.split("."), chain = "", output = [];
+
+ if (typeof context === 'string' && context.length) {
+ props.unshift(context);
+ }
+
+ props.forEach(function (prop) {
+ chain += (chain ? (isNaN(prop) ? "." + prop : "[" + prop + "]") : prop);
+ output.push("typeof " + chain + " !== 'undefined'");
+ });
+ return "(" + output.join(" && ") + ")";
+};
/**
- * Returns an escaped string (safe for evaling). If context is passed
- * then returns a concatenation of context and the escaped variable name.
- */
-exports.escape = function( variable, context ){
- /* 'this' inside of the render function is bound to the tag closure which is meaningless, so we can't use it.
- * '__this' is bound to the original template whose render function we called.
- * Using 'this' in the HTML templates will result in '__this.__currentContext'. This is an additional context
- * for binding data to a specific template - e.g. binding widget data.
- */
- variable = variable.replace(/^this/, '__this.__currentContext');
-
- if( isLiteral( variable ) )
- variable = "(" + variable + ")";
-
- else if( typeof context === 'string' && context.length )
- variable = context + '.' + variable;
-
- var chain = "", props = variable.split(".");
- props.forEach(function(prop){
- chain += (chain ? (isNaN(prop) ? "." + prop : "[" + prop + "]") : prop);
- });
-
- return chain.replace(/\n/g, '\\n').replace(/\r/g, '\\r');
-}
+* Returns an escaped string (safe for evaling). If context is passed
+* then returns a concatenation of context and the escaped variable name.
+*/
+exports.escape = function (variable, context) {
+ /* 'this' inside of the render function is bound to the tag closure which is meaningless, so we can't use it.
+ * '__this' is bound to the original template whose render function we called.
+ * Using 'this' in the HTML templates will result in '__this.__currentContext'. This is an additional context
+ * for binding data to a specific template - e.g. binding widget data.
+ */
+ variable = variable.replace(/^this/, '__this.__currentContext');
+
+ if (isLiteral(variable)) {
+ variable = "(" + variable + ")";
+ } else if (typeof context === 'string' && context.length) {
+ variable = context + '.' + variable;
+ }
+
+ var chain = "", props = variable.split(".");
+ props.forEach(function (prop) {
+ chain += (chain ? (isNaN(prop) ? "." + prop : "[" + prop + "]") : prop);
+ });
+
+ return chain.replace(/\n/g, '\\n').replace(/\r/g, '\\r');
+};
/**
- * Merges b into a and returns a
- */
-exports.merge = function(a, b){
- if (a && b)
- for (var key in b) {
- a[key] = b[key];
+* Merges b into a and returns a
+*/
+exports.merge = function (a, b) {
+ var key;
+
+ if (a && b) {
+ for (key in b) {
+ if (b.hasOwnProperty(key)) {
+ a[key] = b[key];
+ }
+ }
}
- return a;
+
+ return a;
};
exports.isLiteral = isLiteral;
206 index.js
View
@@ -1,113 +1,127 @@
-var fs = require("fs");
-var util = require("util");
-var path = require("path");
-var crypto = require("crypto");
-var tags = require("./tags");
-var parser = require("./parser");
-var widgets = require("./widgets");
-
-var CACHE = {};
-var DEBUG = false;
-var ROOT = "/";
+var fs = require("fs"),
+ util = require("util"),
+ path = require("path"),
+ crypto = require("crypto"),
+ tags = require("./tags"),
+ parser = require("./parser"),
+ widgets = require("./widgets"),
+
+ CACHE = {},
+ DEBUG = false,
+ ROOT = "/",
+
+ fromString, fromFile, createTemplate;
// Call this before using the templates
-exports.init = function(root, debug){
- DEBUG = debug
- ROOT = root;
-}
-
-function createTemplate( data, id ){
- var tokens;
- var template = {
- // Allows us to include templates from the compiled code
- fromFile: fromFile,
- // These are the blocks inside the template
- blocks: {},
- // Distinguish from other tokens
- type: parser.TEMPLATE,
- // Allows us to print debug info from the compiled code
- util: util,
- // The template ID (path relative to tempalte dir)
- id: id
- };
-
- // The template token tree before compiled into javascript
- template.tokens = parser.parse.call( template, data, tags );
-
- // The raw template code - can be inserted into other templates
- // We don't need this in production
- var code = parser.compile.call( template );
-
- if( DEBUG )
- template.code = code;
-
- // The compiled render function - this is all we need
- var render = new Function("__context", "__parents", "__widgets",
- [ '__parents = __parents ? __parents.slice() : [];'
- // Prevents circular includes (which will crash node without warning)
- , 'for(var i=0, j=__parents.length; i<j; ++i){'
- , ' if( __parents[i] === this.id ){'
- , ' return "Circular import of template " + this.id + " in " + __parents[__parents.length-1];'
- , ' }'
- , '}'
- // Add this template as a parent to all includes in its scope
- , '__parents.push( this.id );'
- , 'var __output = [];'
- , 'var __this = this;'
- , code
- , 'return __output.join("");'].join("\n")
- );
-
- template.render = function(context, parents){
- return render.call(this, context, parents, widgets);
- }
-
- return template;
-}
+exports.init = function (root, debug) {
+ DEBUG = debug;
+ ROOT = root;
+};
+
+createTemplate = function (data, id) {
+ var template = {
+ // Allows us to include templates from the compiled code
+ fromFile: fromFile,
+ // These are the blocks inside the template
+ blocks: {},
+ // Distinguish from other tokens
+ type: parser.TEMPLATE,
+ // Allows us to print debug info from the compiled code
+ util: util,
+ // The template ID (path relative to tempalte dir)
+ id: id
+ },
+ tokens,
+ code,
+ render;
+
+ // The template token tree before compiled into javascript
+ template.tokens = parser.parse.call(template, data, tags);
+
+ // The raw template code - can be inserted into other templates
+ // We don't need this in production
+ code = parser.compile.call(template);
+
+ if (DEBUG) {
+ template.code = code;
+ }
+
+ // The compiled render function - this is all we need
+ render = new Function("__context", "__parents", "__widgets",
+ [ '__parents = __parents ? __parents.slice() : [];'
+ // Prevents circular includes (which will crash node without warning)
+ , 'for (var i=0, j=__parents.length; i<j; ++i) {'
+ , ' if (__parents[i] === this.id) {'
+ , ' return "Circular import of template " + this.id + " in " + __parents[__parents.length-1];'
+ , ' }'
+ , '}'
+ // Add this template as a parent to all includes in its scope
+ , '__parents.push(this.id);'
+ , 'var __output = [];'
+ , 'var __this = this;'
+ , code
+ , 'return __output.join("");'].join("\n")
+ );
+
+ template.render = function (context, parents) {
+ return render.call(this, context, parents, widgets);
+ };
+
+ return template;
+};
/*
- * Returns a template object from the given filepath.
- * The filepath needs to be relative to the template directory.
- */
-function fromFile( filepath ){
-
- if( filepath[0] == '/' )
- filepath = filepath.substr(1);
-
- if( filepath in CACHE && !DEBUG )
- return CACHE[filepath];
-
- var data = fs.readFileSync( ROOT + "/" + filepath, 'utf8' );
- // TODO: see what error readFileSync returns and warn about it
- if( data )
- return CACHE[filepath] = createTemplate(data, filepath);
-}
+* Returns a template object from the given filepath.
+* The filepath needs to be relative to the template directory.
+*/
+fromFile = function (filepath) {
+
+ if (filepath[0] === '/') {
+ filepath = filepath.substr(1);
+ }
+
+ if (filepath in CACHE && !DEBUG) {
+ return CACHE[filepath];
+ }
+
+ var data = fs.readFileSync(ROOT + "/" + filepath, 'utf8');
+ // TODO: see what error readFileSync returns and warn about it
+ if (data) {
+ CACHE[filepath] = createTemplate(data, filepath);
+ return CACHE[filepath];
+ }
+};
/*
- * Returns a template object from the given string.
- */
-function fromString( string ){
- var hash = crypto.createHash('md5').update(string).digest('hex');
-
- if( hash in CACHE && !DEBUG )
- return CACHE[hash];
+* Returns a template object from the given string.
+*/
+fromString = function (string) {
+ var hash = crypto.createHash('md5').update(string).digest('hex');
- return CACHE[hash] = createTemplate(string, hash);
-}
+ if (!(hash in CACHE && !DEBUG)) {
+ CACHE[hash] = createTemplate(string, hash);
+ }
+
+ return CACHE[hash];
+};
module.exports = {
init: exports.init,
- fromFile: fromFile,
- fromString: fromString,
+ fromFile: fromFile,
+ fromString: fromString,
compile: function (source, options, callback) {
- self = this;
- if (typeof source == 'string') {
- return function(options) {
+ var self = this;
+ if (typeof source === 'string') {
+ return function (options) {
+ var tmpl = fromString(source);
+
options.locals = options.locals || {};
options.partials = options.partials || {};
- if (options.body) // for express.js > v1.0
+
+ if (options.body) { // for express.js > v1.0
options.locals.body = options.body;
- var tmpl = fromString(source);
+ }
+
return tmpl.render(options.locals);
};
} else {
295 parser.js
View
@@ -1,157 +1,162 @@
-var helpers = require('./helpers');
-
-var check = helpers.check;
-var escape = helpers.escape;
-
-var variableRegexp = /^\{\{.*?\}\}$/;
-var logicRegexp = /^\{%.*?%\}$/;
-var commentRegexp = /^\{#.*?#\}$/;
-
-var TEMPLATE = exports.TEMPLATE = 0;
-var LOGIC_TOKEN = 1;
-var VAR_TOKEN = 2;
-
-exports.parse = function(data, tags){
- var rawtokens = data.trim().replace( /(^\n+)|(\n+$)/, "" ).split( /(\{%.*?%\}|\{\{.*?\}\}|\{#.*?#\})/ );
- var stack = [ [] ], index = 0, token, parts, names, matches, tagname;
-
- for( var i=0, j=rawtokens.length; i<j; ++i ) {
- token = rawtokens[i];
+var helpers = require('./helpers'),
+
+ check = helpers.check,
+ escape = helpers.escape,
+
+ variableRegexp = /^\{\{.*?\}\}$/,
+ logicRegexp = /^\{%.*?%\}$/,
+ commentRegexp = /^\{#.*?#\}$/,
+
+ TEMPLATE = exports.TEMPLATE = 0,
+ LOGIC_TOKEN = 1,
+ VAR_TOKEN = 2;
+
+exports.parse = function (data, tags) {
+ var rawtokens = data.trim().replace(/(^\n+)|(\n+$)/, "").split(/(\{%.*?%\}|\{\{.*?\}\}|\{#.*?#\})/),
+ stack = [[]],
+ index = 0,
+ i = 0, j = rawtokens.length,
+ varname, token, parts, names, matches, tagname;
+
+ for (i, j; i < j; i += 1) {
+ token = rawtokens[i];
+
+ // Ignore empty strings and comments
+ if (token.length === 0 || commentRegexp.test(token)) {
+ continue;
+ } else if (/^(\s|\n)+$/.test(token)) {
+ token = token.replace(/ +/, " ").replace(/\n+/, "\n");
+ } else if (variableRegexp.test(token)) {
+ parts = token.replace(/^\{\{ *| *\}\}$/g, "").split(" ");
+ varname = parts.shift();
+
+ token = {
+ type: VAR_TOKEN,
+ name: varname,
+ args: parts.length ? parts : []
+ };
+ } else if (logicRegexp.test(token)) {
+ parts = token.replace(/^\{% *| *%\}$/g, "").split(" ");
+ tagname = parts.shift();
+
+ if (tagname === 'end') {
+ stack.pop();
+ index--;
+ continue;
+ }
+
+ if (!(tagname in tags)) {
+ throw new Error("Unknown logic tag: " + tagname);
+ }
+
+ token = {
+ type: LOGIC_TOKEN,
+ name: tagname,
+ args: parts.length ? parts : [],
+ compile: tags[tagname]
+ };
+
+ if (tags[tagname].ends) {
+ stack[index].push(token);
+ stack.push(token.tokens = []);
+ index++;
+ continue;
+ }
+ }
- // Ignore empty strings and comments
- if( token.length === 0 || commentRegexp.test( token ) ) {
- continue;
- }
- else if( /^(\s|\n)+$/.test(token) ){
- token = token.replace( / +/, " " ).replace( /\n+/, "\n" );
+ // Everything else is treated as a string
+ stack[index].push(token);
}
- else if( variableRegexp.test(token) ){
- parts = token.replace(/^\{\{ *| *\}\}$/g, "").split(" ");
- var varname = parts.shift();
-
- token = {
- type: VAR_TOKEN,
- name: varname,
- args: parts.length ? parts : []
- };
+
+ if (index !== 0) {
+ throw new Error('Some tags have not been closed');
}
- else if( logicRegexp.test(token) ){
- parts = token.replace(/^\{% *| *%\}$/g, "").split(" ");
- tagname = parts.shift();
-
- if( tagname === 'end' ) {
- stack.pop();
- index--;
- continue;
- }
-
- if( !(tagname in tags) ) {
- throw new Error( "Unknown logic tag: " + tagname );
- }
-
- token = {
- type: LOGIC_TOKEN,
- name: tagname,
- args: parts.length ? parts : [],
- compile: tags[tagname]
- };
-
- if( tags[tagname].ends ) {
- stack[ index ].push( token );
- stack.push( token.tokens = [] );
- index++;
- continue;
- }
+ return stack[index];
+};
+
+
+exports.compile = function compile(indent) {
+ var code = [''],
+ tokens = [],
+ parent, filepath, blockname;
+
+ indent = indent || '';
+
+ // Precompile - extract blocks and create hierarchy based on 'extends' tags
+ // TODO: make block and extends tags accept context variables
+ if (this.type === TEMPLATE) {
+ this.tokens.forEach(function (token, index) {
+ // TODO: Check for circular extends
+ // Load the parent template
+ if (token.name === 'extends') {
+ filepath = token.args[0];
+ if (!helpers.isStringLiteral(filepath) || token.args.length > 1) {
+ throw new Error("Extends tag accepts exactly one strings literal as an argument.");
+ }
+ if (index > 0) {
+ throw new Error("Extends tag must be the first tag in the template.");
+ }
+ token.template = this.fromFile(filepath.replace(/['"]/g, ''));
+ } else if (token.name === 'block') { // Make a list of blocks
+ blockname = token.args[0];
+ if (!helpers.isValidBlockName(blockname) || token.args.length > 1) {
+ throw new Error("Invalid block tag syntax.");
+ }
+ if (this.type !== TEMPLATE) {
+ throw new Error("Block tag found inside another tag.");
+ }
+ this.blocks[blockname] = compile.call(token, indent + ' ');
+ }
+ tokens.push(token);
+ }, this);
+
+ if (tokens[0].name === 'extends') {
+ parent = tokens[0].template;
+ this.blocks = helpers.merge(parent.blocks, this.blocks);
+ this.tokens = parent.tokens;
+ }
}
- // Everything else is treated as a string
- stack[ index ].push( token );
- }
-
- if( index !== 0 ) {
- throw new Error('Some tags have not been closed');
- }
-
- return stack[index];
-}
-
-
-exports.compile = function compile( indent ){
- var code = [''], tokens = [], indent = indent || '';
- // Precompile - extract blocks and create hierarchy based on 'extends' tags
- // TODO: make block and extends tags accept context variables
- if( this.type === TEMPLATE ){
- this.tokens.forEach(function(token, index){
- // TODO: Check for circular extends
- // Load the parent template
- if( token.name === 'extends' ) {
- var filepath = token.args[0];
- if( !helpers.isStringLiteral( filepath ) || token.args.length > 1 ){
- throw new Error("Extends tag accepts exactly one strings literal as an argument.");
+ // If this is not a template then just iterate through its tokens
+ this.tokens.forEach(function (token, index) {
+ if (typeof token === 'string') {
+ return code.push('__output.push("' + token.replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/"/g, '\\"') + '");');
}
- if( index > 0 ){
- throw new Error("Extends tag must be the first tag in the template.");
+
+ if (typeof token !== 'object') {
+ return; // Tokens can be either strings or objects
}
- token.template = this.fromFile( filepath.replace(/['"]/g, '') );
- }
- // Make a list of blocks
- else if( token.name === 'block' ) {
- var blockname = token.args[0];
- if( !helpers.isValidBlockName( blockname ) || token.args.length > 1 ){
- throw new Error("Invalid block tag syntax.");
+
+ if (token.type === VAR_TOKEN) {
+ return code.push(
+ 'if (' + check(token.name) + ') {'
+ , ' __output.push(' + escape(token.name) + ');'
+ , '} else if (' + check(token.name, '__context') + ') {'
+ , ' __output.push(' + escape(token.name, '__context') + ');'
+ , '}'
+ );
}
- if( this.type !== TEMPLATE ){
- throw new Error("Block tag found inside another tag.");
+
+ if (token.type !== LOGIC_TOKEN) {
+ return; // Tokens can be either VAR_TOKEN or LOGIC_TOKEN
}
- this.blocks[ blockname ] = compile.call( token, indent + ' ' );
- }
- tokens.push(token);
- }, this);
- if( tokens[0].name === 'extends' ){
- var parent = tokens[0].template;
- this.blocks = helpers.merge( parent.blocks, this.blocks );
- this.tokens = parent.tokens;
- }
- }
-
- // If this is not a template then just iterate through its tokens
- this.tokens.forEach(function(token, index) {
- if( typeof token === 'string' )
- return code.push( '__output.push("' + token.replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/"/g, '\\"') + '");' );
-
- if( typeof token !== 'object')
- return; // Tokens can be either strings or objects
-
- if( token.type === VAR_TOKEN )
- return code.push(
- 'if( ' + check(token.name) + ' ){'
- , ' __output.push(' + escape( token.name ) + ');'
- , '} else if( ' + check( token.name, '__context' ) + ' ){'
- , ' __output.push(' + escape( token.name, '__context' ) + ');'
- , '}'
- );
-
- if( token.type !== LOGIC_TOKEN )
- return; // Tokens can be either VAR_TOKEN or LOGIC_TOKEN
-
- if( token.name === 'extends' ) {
- if( this.type !== TEMPLATE )
- throw new Error("Extends tag must be the first tag in the template.");
- }
-
- else if( token.name === 'block' ) {
- if( this.type !== TEMPLATE )
- throw new Error("You can not nest block tags into other tags.");
+ if (token.name === 'extends') {
+ if (this.type !== TEMPLATE) {
+ throw new Error("Extends tag must be the first tag in the template.");
+ }
+ } else if (token.name === 'block') {
+ if (this.type !== TEMPLATE) {
+ throw new Error("You can not nest block tags into other tags.");
+ }
+
+ code.push(this.blocks[token.args[0]]); // Blocks are already compiled in the precompile part
+ } else {
+ code.push(token.compile(indent + ' '));
+ }
- code.push( this.blocks[ token.args[0] ] ); // Blocks are already compiled in the precompile part
- }
-
- else
- code.push( token.compile( indent + ' ' ) );
-
- }, this);
-
- return code.join("\n" + indent);
-}
+ }, this);
+
+ return code.join("\n" + indent);
+};
4 scripts/config-lint.js
View
@@ -27,11 +27,11 @@ var options = {
onevar: true,
passfail: false,
plusplus: false,
- predef: ['util', 'require', 'process', 'exports', 'escape', '__dirname', 'setTimeout'],
+ predef: ['module', 'util', 'require', 'process', 'exports', 'escape', '__dirname', 'setTimeout'],
regexp: false,
rhino: false,
safe: false,
- strict: true,
+ strict: false,
sub: false,
undef: true,
white: true,
2  scripts/runlint.js
View
@@ -4,7 +4,7 @@ var util = require('util'),
child_process = require('child_process'),
configFile = __dirname + '/config-lint',
ignore = '',
- root, i;
+ config, root, i;
process.argv.forEach(function (val, index, array) {
if (index < 2) {
437 tags.js
View
@@ -6,234 +6,241 @@ var escape = helpers.escape;
var compile = parser.compile;
/**
- * Inheritance inspired by Django templates
- * The 'extends' and 'block' logic is hardwired in parser.compile
- * These are dummy tags.
- */
-exports['extends'] = {};
-exports['block'] = { ends: true };
+* Inheritance inspired by Django templates
+* The 'extends' and 'block' logic is hardwired in parser.compile
+* These are dummy tags.
+*/
+exports.extends = {};
+exports.block = { ends: true };
/**
- * TODO: This tag is tightly coupled with the context stricture of a specific project.
- * It is not part of the Django template specification.
- * Example slot data structure
- * slots: {
- * main_content: [
- *
- * { tagname: 'h1',
- * style: 'width:200px',
- * class: 'wm-page-element',
- * content: 'This is a heading <a href="http://example.com">with a link</a>'},
- *
- * "<p>This is a paragraph as a normal string.</p>",
- *
- * "<p>Normal strings get echoed into the template directly.</p>",
- *
- * { tagname: 'p',
- * style: '',
- * class: 'wm-page-element',
- * content: 'This is some text.'}],
- *
- * sidebar_content: [
- * { tagname: 'image',
- * style: '',
- * class: '',
- * content: '<img src="/static/uploads/image.jpg" title="Image Jpeg">'}]
- * }
-*/
-exports['slot'] = function( indent ) {
- var slot = this.args[0];
- var indent = indent || "";
-
- return ['(function(){'
- , ' if( ' + check( slot, '__context.slots' ) + ' ){'
- , ' var __widget, __slot = ' + escape( slot, '__context.slots' ) + '.content || [];'
- , ' for( var __i=0, __j = (+__slot.length) || 0; __i < __j; ++__i ){'
- , ' __widget = __slot[__i];'
- , ' if( __widget === undefined || __widget === null || __widget === false )'
- , ' continue;'
- , ' if( typeof __widget === "string" )'
- , ' __output.push(__widget)'
- , ' else if( __widget.tagname && __widgets && typeof __widgets[__widget.tagname] === "function" )'
- , ' __output.push( __widgets[__widget.tagname].call( __widget, __context, __parents ) );'
- , ' }'
- , ' }'
- , '})();'].join("\n" + indent);
-}
+* TODO: This tag is tightly coupled with the context stricture of a specific project.
+* It is not part of the Django template specification.
+* Example slot data structure
+* slots: {
+* main_content: [
+*
+* { tagname: 'h1',
+* style: 'width:200px',
+* class: 'wm-page-element',
+* content: 'This is a heading <a href="http://example.com">with a link</a>'},
+*
+* "<p>This is a paragraph as a normal string.</p>",
+*
+* "<p>Normal strings get echoed into the template directly.</p>",
+*
+* { tagname: 'p',
+* style: '',
+* class: 'wm-page-element',
+* content: 'This is some text.'}],
+*
+* sidebar_content: [
+* { tagname: 'image',
+* style: '',
+* class: '',
+* content: '<img src="/static/uploads/image.jpg" title="Image Jpeg">'}]
+* }
+*/
+exports.slot = function (indent) {
+ var slot = this.args[0];
+
+ indent = indent || "";
+
+ return ['(function () {'
+ , ' if (' + check(slot, '__context.slots') + ') {'
+ , ' var __widget, __slot = ' + escape(slot, '__context.slots') + '.content || [];'
+ , ' for (var __i=0, __j = (+__slot.length) || 0; __i < __j; ++__i) {'
+ , ' __widget = __slot[__i];'
+ , ' if (__widget === undefined || __widget === null || __widget === false)'
+ , ' continue;'
+ , ' if (typeof __widget === "string")'
+ , ' __output.push(__widget)'
+ , ' else if (__widget.tagname && __widgets && typeof __widgets[__widget.tagname] === "function")'
+ , ' __output.push(__widgets[__widget.tagname].call(__widget, __context, __parents));'
+ , ' }'
+ , ' }'
+ , '})();'].join("\n" + indent);
+};
/**
- * Includes another template. The included template will have access to the
- * context, but won't have access to the variables defined in the parent template,
- * like for loop counters.
- *
- * Usage:
- * {% include context_variable %}
- * or
- * {% include "template_name.html" %}
- */
-exports['include'] = function( indent ) {
- var template = this.args[0];
- var indent = indent || "";
-
- if( !helpers.isLiteral( template ) && !helpers.isValidName( template ) ){
- throw new Error("Invalid arguments passed to 'include' tag.");
- }
-
- // Circular includes are VERBOTTEN. This will crash the server.
- return ['(function(){'
- , ' if( ' + check( template ) + ' ){'
- , ' var __template = ' + escape( template ) + ";"
- , ' }'
- , ' else if( ' + check( template, '__context' ) + ' ){'
- , ' var __template = ' + escape( template, '__context' ) + ";"
- , ' }'
- , ' if( typeof __template === "string"){'
- , ' __output.push( __this.fromFile( __template ).render( __context, __parents ) );'
- , ' }'
- , ' else if( typeof __template === "object" && __template.render ){'
- , ' __output.push( __template.render( __context, __parents ) );'
- , ' }'
- , '})();'].join("\n" + indent);
-}
+* Includes another template. The included template will have access to the
+* context, but won't have access to the variables defined in the parent template,
+* like for loop counters.
+*
+* Usage:
+* {% include context_variable %}
+* or
+* {% include "template_name.html" %}
+*/
+exports.include = function (indent) {
+ var template = this.args[0];
+
+ indent = indent || "";
+
+ if (!helpers.isLiteral(template) && !helpers.isValidName(template)) {
+ throw new Error("Invalid arguments passed to 'include' tag.");
+ }
+
+ // Circular includes are VERBOTTEN. This will crash the server.
+ return ['(function () {'
+ , ' if (' + check(template) + ') {'
+ , ' var __template = ' + escape(template) + ";"
+ , ' }'
+ , ' else if (' + check(template, '__context') + ') {'
+ , ' var __template = ' + escape(template, '__context') + ";"
+ , ' }'
+ , ' if (typeof __template === "string") {'
+ , ' __output.push(__this.fromFile(__template).render(__context, __parents));'
+ , ' }'
+ , ' else if (typeof __template === "object" && __template.render) {'
+ , ' __output.push(__template.render(__context, __parents));'
+ , ' }'
+ , '})();'].join("\n" + indent);
+};
/**
- * This is the 'if' tag compiler
- * Example 'If' tag syntax:
- * {% if x %}
- * <p>{{x}}</p>
- * {% end %}
- *
- * {% if !x %}
- * <p>No x found</p>
- * {% else %}
- * <p>{{x}}</p>
- * {% end %}
- *
- * {% if x == y %}, {% if x < y %}, {% if x in y %}, {% if x != y %}
- */
-exports['if'] = function( indent ){
- var operand1 = this.args[0];
- var operator = this.args[1];
- var operand2 = this.args[2];
- var indent = indent || "";
- var negation = false;
-
- // Check if there is negation
- if( operand1[0] === "!" ){
- negation = true;
- operand1 = operand1.substr(1);
- }
- // "!something == else" - this syntax is forbidden. Use "something != else" instead
- if( negation && operator ){
- throw new Error("Invalid syntax for 'if' tag");
- }
- // Check for valid argument
- if( !helpers.isLiteral( operand1 ) && !helpers.isValidName( operand1 ) )
- throw new Error( "Invalid arguments (" + operand1 + ") passed to 'if' tag" );
-
- // Check for valid operator
- if( operator && ["==", "<", ">", "!=", "<=", ">=", "===", "!==", "in"].indexOf(operator) === -1 ){
- throw new Error("Invalid operator (" + operator + ") passed to 'if' tag");
- }
- // Check for presence of operand 2 if operator is present
- if( operator && typeof operand2 === 'undefined' ){
- throw new Error("Missing argument in 'if' tag");
- }
- // Check for valid argument
-
- if( operator && !helpers.isLiteral( operand2 ) && !helpers.isValidName( operand2 ) ){
- throw new Error("Invalid arguments (" + operand2 + ") passed to 'if' tag");
- }
-
- var out = ['(function(){'];
- out.push(' var __op1;');
- out.push(' if( ' + check( operand1 ) + ' ){');
- out.push(' __op1 = ' + escape(operand1) + ';');
- out.push(' }');
- out.push(' else if( ' + check(operand1, '__context') + ' ){');
- out.push(' __op1 = ' + escape(operand1, '__context') + ';');
- out.push(' }');
- if( typeof operand2 === 'undefined' ){
- out.push(' if( ' + (negation ? '!' : '!!') + '__op1 ){');
- out.push( compile.call( this, indent + ' ' ) );
- out.push(' }');
- }
- else {
- out.push(' var __op2;');
- out.push(' if( ' + check(operand2) + ' ){');
- out.push(' __op2 = ' + escape(operand2) + ';');
+* This is the 'if' tag compiler
+* Example 'If' tag syntax:
+* {% if x %}
+* <p>{{x}}</p>
+* {% end %}
+*
+* {% if !x %}
+* <p>No x found</p>
+* {% else %}
+* <p>{{x}}</p>
+* {% end %}
+*
+* {% if x == y %}, {% if x < y %}, {% if x in y %}, {% if x != y %}
+*/
+exports['if'] = function (indent) {
+ var operand1 = this.args[0],
+ operator = this.args[1],
+ operand2 = this.args[2],
+ negation = false,
+ out;
+
+ indent = indent || "";
+
+ // Check if there is negation
+ if (operand1[0] === "!") {
+ negation = true;
+ operand1 = operand1.substr(1);
+ }
+ // "!something == else" - this syntax is forbidden. Use "something != else" instead
+ if (negation && operator) {
+ throw new Error("Invalid syntax for 'if' tag");
+ }
+ // Check for valid argument
+ if (!helpers.isLiteral(operand1) && !helpers.isValidName(operand1)) {
+ throw new Error("Invalid arguments (" + operand1 + ") passed to 'if' tag");
+ }
+ // Check for valid operator
+ if (operator && ["==", "<", ">", "!=", "<=", ">=", "===", "!==", "in"].indexOf(operator) === -1) {
+ throw new Error("Invalid operator (" + operator + ") passed to 'if' tag");
+ }
+ // Check for presence of operand 2 if operator is present
+ if (operator && typeof operand2 === 'undefined') {
+ throw new Error("Missing argument in 'if' tag");
+ }
+ // Check for valid argument
+ if (operator && !helpers.isLiteral(operand2) && !helpers.isValidName(operand2)) {
+ throw new Error("Invalid arguments (" + operand2 + ") passed to 'if' tag");
+ }
+
+ out = ['(function () {'];
+ out.push(' var __op1;');
+ out.push(' if (' + check(operand1) + ') {');
+ out.push(' __op1 = ' + escape(operand1) + ';');
out.push(' }');
- out.push(' else if( ' + check(operand2, '__context') + ' ){');
- out.push(' __op2 = ' + escape(operand2, '__context') + ';');
+ out.push(' else if (' + check(operand1, '__context') + ') {');
+ out.push(' __op1 = ' + escape(operand1, '__context') + ';');
out.push(' }');
-
- if( operator === 'in' ){
- out.push(' if((Array.isArray(__op2) && __op2.indexOf(__op1) > -1) ||');
- out.push(' (typeof __op2 === "string" && __op2.indexOf(__op1) > -1) ||');
- out.push(' (!Array.isArray(__op2) && typeof __op2 === "object" && __op1 in __op2)){');
+ if (typeof operand2 === 'undefined') {
+ out.push(' if (' + (negation ? '!' : '!!') + '__op1) {');
+ out.push(compile.call(this, indent + ' '));
+ out.push(' }');
}
else {
- out.push(' if( __op1 ' + escape(operator) + ' __op2 ){');
+ out.push(' var __op2;');
+ out.push(' if (' + check(operand2) + ') {');
+ out.push(' __op2 = ' + escape(operand2) + ';');
+ out.push(' }');
+ out.push(' else if (' + check(operand2, '__context') + ') {');
+ out.push(' __op2 = ' + escape(operand2, '__context') + ';');
+ out.push(' }');
+
+ if (operator === 'in') {
+ out.push(' if ((Array.isArray(__op2) && __op2.indexOf(__op1) > -1) ||');
+ out.push(' (typeof __op2 === "string" && __op2.indexOf(__op1) > -1) ||');
+ out.push(' (!Array.isArray(__op2) && typeof __op2 === "object" && __op1 in __op2)) {');
+ }
+ else {
+ out.push(' if (__op1 ' + escape(operator) + ' __op2) {');
+ }
+ out.push(compile.call(this, indent + ' '));
+ out.push(' }');
}
- out.push( compile.call( this, indent + ' ' ) );
- out.push(' }');
- }
- out.push('})();');
- return out.join("\n" + indent);
-}
+ out.push('})();');
+ return out.join("\n" + indent);
+};
exports['if'].ends = true;
/**
- * This is the 'for' tag compiler
- * Example 'For' tag syntax:
- * {% for x in y.some.items %}
- * <p>{{x}}</p>
- * {% end %}
- */
-exports['for'] = function( indent ){
- var operand1 = this.args[0];
- var operator = this.args[1];
- var operand2 = this.args[2];
- var indent = indent || "";
-
- if( typeof operator !== 'undefined' && operator !== 'in' )
- throw new Error("Invalid syntax in 'for' tag");
-
- if( !helpers.isValidShortName( operand1 ) )
- throw new Error("Invalid arguments (" + operand1 + ") passed to 'for' tag");
-
- if( !helpers.isValidName( operand2 ) )
- throw new Error("Invalid arguments (" + operand2 + ") passed to 'for' tag");
-
- return ['(function(){'
- , ' if( ' + check( operand2 ) + ' ){'
- , ' var __forloopIter = ' + escape( operand2 ) + ";"
- , ' }'
- , ' else if( ' + check( operand2, '__context' ) + ' ){'
- , ' var __forloopIter = ' + escape( operand2, '__context' ) + ";"
- , ' }'
- , ' else {'
- , ' return;'
- , ' }'
- , ' var ' + escape( operand1 ) + ';'
- , ' var forloop = {};'
- , ' if( Array.isArray(__forloopIter) ){'
- , ' var __forloopIndex, __forloopLength;'
- , ' for(var __forloopIndex=0, __forloopLength=__forloopIter.length; __forloopIndex<__forloopLength; ++__forloopIndex){'
- , ' forloop.index = __forloopIndex;'
- , ' ' + escape( operand1 ) + ' = __forloopIter[__forloopIndex];'
- , compile.call( this, indent + ' ' )
- , ' }'
- , ' }'
- , ' else if(typeof __forloopIter === "object"){'
- , ' var __forloopIndex;'
- , ' for(__forloopIndex in __forloopIter){'
- , ' forloop.index = __forloopIndex;'
- , ' ' + escape( operand1 ) + ' = __forloopIter[__forloopIndex];'
- , compile.call( this, indent + ' ' )
- , ' }'
- , ' }'
- , '})();'].join("\n" + indent);
-}
+* This is the 'for' tag compiler
+* Example 'For' tag syntax:
+* {% for x in y.some.items %}
+* <p>{{x}}</p>
+* {% end %}
+*/
+exports['for'] = function (indent) {
+ var operand1 = this.args[0],
+ operator = this.args[1],
+ operand2 = this.args[2];
+
+ indent = indent || "";
+
+ if (typeof operator !== 'undefined' && operator !== 'in') {
+ throw new Error("Invalid syntax in 'for' tag");
+ }
+
+ if (!helpers.isValidShortName(operand1)) {
+ throw new Error("Invalid arguments (" + operand1 + ") passed to 'for' tag");
+ }
+
+ if (!helpers.isValidName(operand2)) {
+ throw new Error("Invalid arguments (" + operand2 + ") passed to 'for' tag");
+ }
+
+ return ['(function () {'
+ , ' if (' + check(operand2) + ') {'
+ , ' var __forloopIter = ' + escape(operand2) + ";"
+ , ' }'
+ , ' else if (' + check(operand2, '__context') + ') {'
+ , ' var __forloopIter = ' + escape(operand2, '__context') + ";"
+ , ' }'
+ , ' else {'
+ , ' return;'
+ , ' }'
+ , ' var ' + escape(operand1) + ';'
+ , ' var forloop = {};'
+ , ' if (Array.isArray(__forloopIter)) {'
+ , ' var __forloopIndex, __forloopLength;'
+ , ' for (var __forloopIndex=0, __forloopLength=__forloopIter.length; __forloopIndex<__forloopLength; ++__forloopIndex) {'
+ , ' forloop.index = __forloopIndex;'
+ , ' ' + escape(operand1) + ' = __forloopIter[__forloopIndex];'
+ , compile.call(this, indent + ' ')
+ , ' }'
+ , ' }'
+ , ' else if (typeof __forloopIter === "object") {'
+ , ' var __forloopIndex;'
+ , ' for (__forloopIndex in __forloopIter) {'
+ , ' forloop.index = __forloopIndex;'
+ , ' ' + escape(operand1) + ' = __forloopIter[__forloopIndex];'
+ , compile.call(this, indent + ' ')
+ , ' }'
+ , ' }'
+ , '})();'].join("\n" + indent);
+};
exports['for'].ends = true;
48 tests/tests.js
View
@@ -1,40 +1,40 @@
-var template = require('../index');
+var template = require('../index'),
+ tplF, tplS, array, output, d, i;
template.init(__dirname, false);
-var print = require('util').puts;
-var tplF, tplS, array;
-
tplS = template.fromString(
"{% for v in array %}"
- + "{% if 1 %}"
- + "{% for k in v %}"
- + "\n{{forloop.index}} {{k}}: "
- + "{% if forloop.index in 'msafas' %}"
- + "<p>Hello World {{k}}{{foo}}{{k}}{{foo}}{{k}}{{foo}}</p>"
- + "{% end %}"
- + "{% end %}"
- + "{% end %}"
- + "{% end %}"
+ + "{% if 1 %}"
+ + "{% for k in v %}"
+ + "\n{{forloop.index}} {{k}}: "
+ + "{% if forloop.index in 'msafas' %}"
+ + "<p>Hello World {{k}}{{foo}}{{k}}{{foo}}{{k}}{{foo}}</p>"
+ + "{% end %}"
+ + "{% end %}"
+ + "{% end %}"
+ + "{% end %}"
);
-array = [[1,2,3,4,5,6,7,8,9,10], [1,2,3,4,5,6,7,8,9,10], [1,2,3,4,5,6,7,8,9,10], {af:"s", baz:"d", d:"f"}, "zeus"];
+array = [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], { af: "s", baz: "d", d: "f" }, "zeus"];
tplF = template.fromFile("include_base.html");
template.fromFile("included_2.html");
template.fromFile("included.html");
-print("\nTesting includes");
-var d = new Date();
-for( var i=0; i<1000; ++i )
- output = tplF.render( { array: array, foo: "baz", "included": "included.html" } );
-print( "====\n~" + 1000000 / (new Date() - d) + " renders per sec." );
+console.log("Testing includes");
+d = new Date();
+for (i = 0; i < 1000; i += 1) {
+ output = tplF.render({ array: array, foo: "baz", "included": "included.html" });
+}
+console.log("====\n~" + 1000000 / (new Date() - d) + " renders per sec.");
template.fromFile("extends_base.html");
template.fromFile("extends_1.html");
tplF = template.fromFile("extends_2.html");
-print("\nTesting extends");
-var d = new Date();
-for( var i=0; i<1000; ++i )
- tplF.render({});
-print( "====\n~" + 1000000 / (new Date() - d) + " renders per sec." );
+console.log("\nTesting extends");
+d = new Date();
+for (i = 0; i < 1000; i += 1) {
+ tplF.render({});
+}
+console.log("====\n~" + 1000000 / (new Date() - d) + " renders per sec.");
125 widgets.js
View
@@ -1,77 +1,94 @@
-var textWidgetGenerator = function( tagname ){
- return function(){
- var i, output = ["<", tagname];
- for( i in this ){
- if(this.hasOwnProperty(i) && i !== "content" && 1 !== "tagname")
- output.push(" ", i, "='", this[i], "'");
- }
- output.push(">", this.content, "</", tagname, ">");
- return output.join("");
- }
-}
+var textWidgetGenerator = function (tagname) {
+ return function () {
+ var output = ["<", tagname],
+ i;
+
+ for (i in this) {
+ if (this.hasOwnProperty(i) && i !== "content" && 1 !== "tagname") {
+ output.push(" ", i, "='", this[i], "'");
+ }
+ }
+
+ output.push(">", this.content, "</", tagname, ">");
+ return output.join("");
+ };
+};
/**
- * Renders a paragraph. This is fairly simple.
- */
+* Renders a paragraph. This is fairly simple.
+*/
exports.p = textWidgetGenerator("p");
/**
- * Renders a paragraph. This is fairly simple.
- */
+* Renders a paragraph. This is fairly simple.
+*/
exports.h1 = textWidgetGenerator("h1");
/**
- * Renders a paragraph. This is fairly simple.
- */
+* Renders a paragraph. This is fairly simple.
+*/
exports.h2 = textWidgetGenerator("h2");
/**
- * Renders a paragraph. This is fairly simple.
- */
-exports.h3 = textWidgetGenerator("h3")
+* Renders a paragraph. This is fairly simple.
+*/
+exports.h3 = textWidgetGenerator("h3");
/**
- * Renders an oredered list. This is fairly simple.
- */
+* Renders an oredered list. This is fairly simple.
+*/
exports.ol = textWidgetGenerator("ol");
/**
- * Renders an unoredered list. This is fairly simple.
- */
+* Renders an unoredered list. This is fairly simple.
+*/
exports.ul = textWidgetGenerator("ul");
/**
- * Renders a blockquote. This is fairly simple.
- */
+* Renders a blockquote. This is fairly simple.
+*/
exports.q = textWidgetGenerator("q");
/**
- * Renders a simple composite widget.
- */
-exports.list = exports.image = function( context ){
- var i, output = ["<div"];
- for( i in this ){
- if(this.hasOwnProperty(i) && i !== "content" && 1 !== "tagname")
- output.push(" ", i, "='", this[i], "'");
- }
- output.push(" data-tagname='", this.tagname, "'");
- output.push(">", this.content, "</div>");
- return output.join("");
-}
+* Renders a simple composite widget.
+*/
+exports.list = exports.image = function (context) {
+ var output = ["<div"],
+ i;
+
+ for (i in this) {
+ if (this.hasOwnProperty(i) && i !== "content" && 1 !== "tagname") {
+ output.push(" ", i, "='", this[i], "'");
+ }
+ }
+
+ output.push(" data-tagname='", this.tagname, "'");
+ output.push(">", this.content, "</div>");
+
+ return output.join("");
+};
/**
- * This helper renders a slot independently from a template.
- */
-exports.renderSlot = function(slotContent, context){
- var widget, slot = slotContent || [], output = [];
- for( var i=0, j=slot.length; i<j; ++i){
- widget = slot[i];
- if( widget === undefined || widget === null || widget === false )
- continue;
- if( typeof widget == 'string' )
- output.push(widget)
- else if(widget.tagname && typeof exports[widget.tagname] === "function")
- output.push(exports[widget.tagname].call(widget, context));
- }
-
- return output.join("");
-}
+* This helper renders a slot independently from a template.
+*/
+exports.renderSlot = function (slotContent, context) {
+ var slot = slotContent || [],
+ output = [],
+ widget,
+ i = 0,
+ j = slot.length;
+
+ for (i, j; i < j; i += 1) {
+ widget = slot[i];
+ if (widget === undefined || widget === null || widget === false) {
+ continue;
+ }
+
+ if (typeof widget === 'string') {
+ output.push(widget);
+ } else if (widget.tagname && typeof exports[widget.tagname] === "function") {
+ output.push(exports[widget.tagname].call(widget, context));
+ }
+ }
+
+ return output.join("");
+};
Please sign in to comment.
Something went wrong with that request. Please try again.