Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added preliminary mixin block support. Closes #310

and the new + mixin invocation syntax
to disambiguate between calling and defining
  • Loading branch information...
commit ae8e8b7d3a8f06ddf7988154b231a8702d8067a9 1 parent fe0d309
TJ Holowaychuk tj authored
25 lib/compiler.js
View
@@ -279,16 +279,31 @@ Compiler.prototype = {
var name = mixin.name.replace(/-/g, '_') + '_mixin'
, args = mixin.args || '';
- if (mixin.block) {
+ if (mixin.call) {
+ if (this.pp) this.buf.push("__indent.push('" + Array(this.indents + 1).join(' ') + "');")
+ if (mixin.block) {
+ if (args) {
+ this.buf.push(name + '(' + args + ', function(){');
+ } else {
+ this.buf.push(name + '(function(){');
+ }
+ this.buf.push('var buf = [];');
+ this.visit(mixin.block);
+ this.buf.push('return buf.join("");');
+ this.buf.push('}());\n');
+ } else {
+ this.buf.push(name + '(' + args + ');');
+ }
+ if (this.pp) this.buf.push("__indent.pop();")
+ } else {
+ args = args
+ ? args.split(/ *, */).concat('content').join(', ')
+ : 'content';
this.buf.push('var ' + name + ' = function(' + args + '){');
if (this.pp) this.parentIndents++;
this.visit(mixin.block);
if (this.pp) this.parentIndents--;
this.buf.push('}');
- } else {
- if (this.pp) this.buf.push("__indent.push('" + Array(this.indents + 1).join(' ') + "');")
- this.buf.push(name + '(' + args + ');');
- if (this.pp) this.buf.push("__indent.pop();")
}
},
15 lib/lexer.js
View
@@ -364,6 +364,20 @@ Lexer.prototype = {
},
/**
+ * Call mixin.
+ */
+
+ call: function() {
+ var captures;
+ if (captures = /^\+([-\w]+)(?: *\((.*)\))?/.exec(this.input)) {
+ this.consume(captures[0].length);
+ var tok = this.tok('call', captures[1]);
+ tok.args = captures[2];
+ return tok;
+ }
+ },
+
+ /**
* Mixin.
*/
@@ -710,6 +724,7 @@ Lexer.prototype = {
|| this.block()
|| this.include()
|| this.mixin()
+ || this.call()
|| this.conditional()
|| this.each()
|| this["while"]()
15 lib/nodes/block.js
View
@@ -104,3 +104,18 @@ Block.prototype.includeBlock = function(){
return ret;
};
+/**
+ * Return a clone of this block.
+ *
+ * @return {Block}
+ * @api private
+ */
+
+Block.prototype.clone = function(){
+ var clone = new Block;
+ for (var i = 0, len = this.nodes.length; i < len; ++i) {
+ clone.push(this.nodes[i].clone());
+ }
+ return clone;
+};
+
3  lib/nodes/mixin.js
View
@@ -20,10 +20,11 @@ var Node = require('./node');
* @api public
*/
-var Mixin = module.exports = function Mixin(name, args, block){
+var Mixin = module.exports = function Mixin(name, args, block, call){
this.name = name;
this.args = args;
this.block = block;
+ this.call = call;
};
/**
13 lib/nodes/node.js
View
@@ -11,4 +11,15 @@
* @api public
*/
-var Node = module.exports = function Node(){};
+var Node = module.exports = function Node(){};
+
+/**
+ * Clone this node (return itself)
+ *
+ * @return {Node}
+ * @api private
+ */
+
+Node.prototype.clone = function(){
+ return this;
+};
15 lib/nodes/tag.js
View
@@ -34,6 +34,21 @@ var Tag = module.exports = function Tag(name, block) {
Tag.prototype.__proto__ = Node.prototype;
/**
+ * Clone this tag.
+ *
+ * @return {Tag}
+ * @api private
+ */
+
+Tag.prototype.clone = function(){
+ var clone = new Tag(this.name, this.block.clone());
+ clone.line = this.line;
+ clone.attrs = this.attrs;
+ clone.textOnly = this.textOnly;
+ return clone;
+};
+
+/**
* Set attribute `name` to `val`, keep in mind these become
* part of a raw js object literal, so to quote a value you must
* '"quote me"', otherwise or example 'user.name' is literal JavaScript.
37 lib/parser.js
View
@@ -26,6 +26,7 @@ var Parser = exports = module.exports = function Parser(str, filename, options){
this.lexer = new Lexer(str, options);
this.filename = filename;
this.blocks = {};
+ this.mixins = {};
this.options = options;
this.contexts = [this];
};
@@ -213,6 +214,8 @@ Parser.prototype = {
return this.parseEach();
case 'code':
return this.parseCode();
+ case 'call':
+ return this.parseCall();
case 'yield':
this.advance();
var block = new nodes.Block;
@@ -486,17 +489,41 @@ Parser.prototype = {
},
/**
- * mixin block
+ * call ident block
*/
- parseMixin: function(){
- var tok = this.expect('mixin')
+ parseCall: function(){
+ var tok = this.expect('call')
, name = tok.val
- , args = tok.args;
+ , args = tok.args
+ , mixin = this.mixins[name];
+
var block = 'indent' == this.peek().type
? this.block()
: null;
- return new nodes.Mixin(name, args, block);
+
+ return new nodes.Mixin(name, args, block, true);
+ },
+
+ /**
+ * mixin block
+ */
+
+ parseMixin: function(){
+ var tok = this.expect('mixin')
+ , name = tok.val
+ , args = tok.args
+ , mixin;
+
+ // definition
+ if ('indent' == this.peek().type) {
+ mixin = new nodes.Mixin(name, args, this.block(), false);
+ this.mixins[name] = mixin;
+ return mixin;
+ // call
+ } else {
+ return new nodes.Mixin(name, args, null, true);
+ }
},
/**
31 test/cases/mixin.blocks.html
View
@@ -0,0 +1,31 @@
+<html>
+ <body>
+ <form method="GET" action="/search">
+ <input type="hidden" name="_csrf" value="hey"/>
+ <input type="text" name="query" placeholder="Search"/>
+ <input type="submit" value="Search"/>
+ </form>
+ </body>
+</html>
+<html>
+ <body>
+ <form method="POST" action="/search">
+ <input type="hidden" name="_csrf" value="hey"/>
+ <input type="text" name="query" placeholder="Search"/>
+ <input type="submit" value="Search"/>
+ </form>
+ </body>
+</html>
+<html>
+ <body>
+ <form method="POST" action="/search">
+ <input type="hidden" name="_csrf" value="hey"/>
+ </form>
+ </body>
+</html>
+<div id="foo">
+ <div id="bar">
+<p>one</p>
+<p>two</p>
+<p>three</p></div>
+</div>
35 test/cases/mixin.blocks.jade
View
@@ -0,0 +1,35 @@
+
+
+mixin form(method, action)
+ form(method=method, action=action)
+ csrf_token_from_somewhere = 'hey'
+ input(type='hidden', name='_csrf', value=csrf_token_from_somewhere)
+ != content
+
+html
+ body
+ +form('GET', '/search')
+ input(type='text', name='query', placeholder='Search')
+ input(type='submit', value='Search')
+
+html
+ body
+ +form('POST', '/search')
+ input(type='text', name='query', placeholder='Search')
+ input(type='submit', value='Search')
+
+html
+ body
+ +form('POST', '/search')
+
+mixin bar(html)
+ #bar!= html
+
+mixin foo()
+ #foo
+ +bar(content)
+
++foo
+ p one
+ p two
+ p three
Please sign in to comment.
Something went wrong with that request. Please try again.