mirror of
https://github.com/harttle/liquidjs.git
synced 2026-09-18 22:10:41 -07:00
fix include scope.blocks bleeding
This commit is contained in:
+1
-1
@@ -8,7 +8,7 @@ var engine = Liquid({
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.engine('liquid', engine.express()); // register liquid engine
|
app.engine('liquid', engine.express()); // register liquid engine
|
||||||
app.set('views', __dirname); // specify the views directory
|
app.set('views', ['./partials', './views']); // specify the views directory
|
||||||
app.set('view engine', 'liquid'); // set to default
|
app.set('view engine', 'liquid'); // set to default
|
||||||
|
|
||||||
app.get('/', function (req, res) {
|
app.get('/', function (req, res) {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
"description": "Express Demo Using Shopify-Liquid",
|
"description": "Express Demo Using Shopify-Liquid",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"start": "node index.js",
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
},
|
},
|
||||||
"author": "harttle",
|
"author": "harttle",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "shopify-liquid",
|
"name": "shopify-liquid",
|
||||||
"version": "1.3.0",
|
"version": "1.3.1",
|
||||||
"description": "Liquid template engine for JavaScript, Node.js and Browser",
|
"description": "Liquid template engine for JavaScript, Node.js and Browser",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ const Promise = require('any-promise');
|
|||||||
const mapSeries = require('./util/promise.js').mapSeries;
|
const mapSeries = require('./util/promise.js').mapSeries;
|
||||||
const RenderBreak = require('./util/error.js').RenderBreak;
|
const RenderBreak = require('./util/error.js').RenderBreak;
|
||||||
const assert = require('./util/assert.js');
|
const assert = require('./util/assert.js');
|
||||||
|
const _ = require('./util/underscore.js');
|
||||||
|
|
||||||
var render = {
|
var render = {
|
||||||
|
|
||||||
|
|||||||
+7
-3
@@ -147,13 +147,17 @@ function matchRightBracket(str, begin) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.factory = function(_ctx, opts) {
|
exports.factory = function(ctx, opts) {
|
||||||
opts = _.assign({
|
opts = _.assign({
|
||||||
strict: false
|
strict: false,
|
||||||
|
blocks: {}
|
||||||
}, opts);
|
}, opts);
|
||||||
|
ctx = _.assign(ctx, {
|
||||||
|
liquid: opts
|
||||||
|
});
|
||||||
|
|
||||||
var scope = Object.create(Scope);
|
var scope = Object.create(Scope);
|
||||||
scope.opts = opts;
|
scope.opts = opts;
|
||||||
scope.scopes = [_ctx || {}];
|
scope.scopes = [ctx];
|
||||||
return scope;
|
return scope;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -37,7 +37,15 @@ function isArray(value) {
|
|||||||
return value instanceof Array;
|
return value instanceof Array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function echo(prefix){
|
||||||
|
return v => {
|
||||||
|
console.log('[' + prefix + ']', v);
|
||||||
|
return v;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
exports.isString = isString;
|
exports.isString = isString;
|
||||||
exports.isArray = isArray;
|
exports.isArray = isArray;
|
||||||
exports.forOwn = forOwn;
|
exports.forOwn = forOwn;
|
||||||
exports.assign = assign;
|
exports.assign = assign;
|
||||||
|
exports.echo = echo;
|
||||||
|
|||||||
+6
-1
@@ -17,8 +17,12 @@ module.exports = function(liquid) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
render: function(scope, hash, register) {
|
render: function(scope, hash, register) {
|
||||||
console.log('include', register.root);
|
|
||||||
var filepath = Liquid.evalValue(this.value, scope);
|
var filepath = Liquid.evalValue(this.value, scope);
|
||||||
|
|
||||||
|
var reg = scope.get('liquid');
|
||||||
|
var originBlocks = reg.blocks;
|
||||||
|
reg.blocks = {};
|
||||||
|
|
||||||
if(this.with){
|
if(this.with){
|
||||||
hash[filepath] = Liquid.evalValue(this.with, scope);
|
hash[filepath] = Liquid.evalValue(this.with, scope);
|
||||||
}
|
}
|
||||||
@@ -29,6 +33,7 @@ module.exports = function(liquid) {
|
|||||||
})
|
})
|
||||||
.then((html) => {
|
.then((html) => {
|
||||||
scope.pop();
|
scope.pop();
|
||||||
|
reg.blocks = originBlocks;
|
||||||
return html;
|
return html;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-22
@@ -13,24 +13,20 @@ module.exports = function(liquid) {
|
|||||||
this.layout = match[0];
|
this.layout = match[0];
|
||||||
this.tpls = liquid.parser.parse(remainTokens);
|
this.tpls = liquid.parser.parse(remainTokens);
|
||||||
},
|
},
|
||||||
render: function(scope) {
|
render: function(scope, hash, register) {
|
||||||
var layout = Liquid.evalValue(this.layout, scope);
|
var layout = Liquid.evalValue(this.layout, scope);
|
||||||
|
var reg = scope.get('liquid');
|
||||||
|
|
||||||
var html = '';
|
// render the remaining tokens immediately
|
||||||
scope.push({});
|
|
||||||
// not sure if this first one is needed, since the results are ignored
|
|
||||||
return liquid.renderer.renderTemplates(this.tpls, scope)
|
return liquid.renderer.renderTemplates(this.tpls, scope)
|
||||||
.then((partial) => {
|
// now register.blocks contains rendered blocks
|
||||||
html += partial;
|
.then(() => liquid.getTemplate(layout, register.root))
|
||||||
return liquid.getTemplate(layout);
|
// push the hash
|
||||||
})
|
.then(templates => (scope.push(hash), templates))
|
||||||
.then((templates) => {
|
// render the parent
|
||||||
return liquid.renderer.renderTemplates(templates, scope);
|
.then(templates => liquid.renderer.renderTemplates(templates, scope))
|
||||||
})
|
// pop the hash
|
||||||
.then((partial) => {
|
.then(partial => (scope.pop(), partial));
|
||||||
scope.pop();
|
|
||||||
return partial;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -49,20 +45,21 @@ module.exports = function(liquid) {
|
|||||||
stream.start();
|
stream.start();
|
||||||
},
|
},
|
||||||
render: function(scope){
|
render: function(scope){
|
||||||
var html = scope.get(`_liquid.blocks.${this.block}`);
|
var register = scope.get('liquid');
|
||||||
var promise = Promise.resolve('');
|
var html = register.blocks[this.block];
|
||||||
|
// if not defined yet
|
||||||
if (html === undefined) {
|
if (html === undefined) {
|
||||||
promise = liquid.renderer.renderTemplates(this.tpls, scope)
|
return liquid.renderer.renderTemplates(this.tpls, scope)
|
||||||
.then((partial) => {
|
.then((partial) => {
|
||||||
scope.set(`_liquid.blocks.${this.block}`, partial);
|
register.blocks[this.block] = partial;
|
||||||
return partial;
|
return partial;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// if already defined by desendents
|
||||||
else {
|
else {
|
||||||
scope.set(`_liquid.blocks.${this.block}`, html);
|
register.blocks[this.block] = html;
|
||||||
promise = Promise.resolve(html);
|
return Promise.resolve(html);
|
||||||
}
|
}
|
||||||
return promise;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+51
-24
@@ -12,43 +12,70 @@ describe('tags/layout', function() {
|
|||||||
extname: '.html'
|
extname: '.html'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
beforeEach(function() {
|
|
||||||
mock({
|
|
||||||
'/default-layout.html': 'foo{% block %}Default{% endblock %}foo',
|
|
||||||
'/multi-blocks-layout.html': 'foo{% block "a"%}{% endblock %}{% block b%}{%endblock%}foo',
|
|
||||||
'/multi-blocks.html': '{% layout "multi-blocks-layout" %}{%block a%}aaa{%endblock%},{%block b%};{%block c%}ccc{%endblock%};{%endblock%}',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
afterEach(function() {
|
afterEach(function() {
|
||||||
mock.restore();
|
mock.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw when block not closed', function() {
|
it('should throw when block not closed', function() {
|
||||||
src = '{% layout "default-layout" %}{%block%}bar';
|
mock({
|
||||||
|
'/parent.html': 'parent',
|
||||||
|
});
|
||||||
|
src = '{% layout "parent" %}{%block%}A';
|
||||||
return expect(liquid.parseAndRender(src)).to
|
return expect(liquid.parseAndRender(src)).to
|
||||||
.be.rejectedWith(/tag {%block%} not closed/);
|
.be.rejectedWith(/tag {%block%} not closed/);
|
||||||
});
|
});
|
||||||
it('should support layout', function() {
|
it('should handle anonymous block', function() {
|
||||||
src = '{% layout "default-layout" %}{%block%}bar{%endblock%}';
|
mock({
|
||||||
|
'/parent.html': 'X{%block%}{%endblock%}Y',
|
||||||
|
});
|
||||||
|
src = '{% layout "parent.html" %}{%block%}A{%endblock%}';
|
||||||
return expect(liquid.parseAndRender(src)).to
|
return expect(liquid.parseAndRender(src)).to
|
||||||
.eventually.equal('foobarfoo');
|
.eventually.equal('XAY');
|
||||||
});
|
});
|
||||||
it('should support layout: multiple blocks', function() {
|
it('should handle named blocks', function() {
|
||||||
src = '{% layout "multi-blocks-layout" %}' +
|
mock({
|
||||||
'{%block a%}bara{%endblock%}' +
|
'/parent.html': 'X{% block "a"%}{% endblock %}Y{% block b%}{%endblock%}Z',
|
||||||
'{%block b%}barb{%endblock%}';
|
});
|
||||||
|
src = '{% layout "parent.html" %}' +
|
||||||
|
'{%block a%}A{%endblock%}' +
|
||||||
|
'{%block b%}B{%endblock%}';
|
||||||
return expect(liquid.parseAndRender(src)).to
|
return expect(liquid.parseAndRender(src)).to
|
||||||
.eventually.equal('foobarabarbfoo');
|
.eventually.equal('XAYBZ');
|
||||||
});
|
});
|
||||||
it('should support layout: nested 1', function() {
|
it('should support default block content', function() {
|
||||||
src = '{% layout "multi-blocks" %}{% block a%}A{%endblock%}{%block c%}C{%endblock%}';
|
mock({
|
||||||
|
'/parent.html': 'X{% block "a"%}A{% endblock %}Y{% block b%}B{%endblock%}Z',
|
||||||
|
});
|
||||||
|
src = '{% layout "parent.html" %}{%block a%}a{%endblock%}';
|
||||||
return expect(liquid.parseAndRender(src)).to
|
return expect(liquid.parseAndRender(src)).to
|
||||||
.eventually.equal('fooA;C;foo');
|
.eventually.equal('XaYBZ');
|
||||||
});
|
});
|
||||||
it('should support layout: nested 2', function() {
|
it('should handle nested block', function() {
|
||||||
src = '{% layout "multi-blocks" %}{%block c%}C{%endblock%}';
|
mock({
|
||||||
return expect(liquid.parseAndRender(src)).to
|
'/grand.html': 'X{%block a%}G{%endblock%}Y',
|
||||||
.eventually.equal('fooaaa;C;foo');
|
'/parent.html': '{%layout "grand" %}{%block a%}P{%endblock%}',
|
||||||
|
'/main.html': '{%layout "parent"%}{%block a%}A{%endblock%}'
|
||||||
|
})
|
||||||
|
return expect(liquid.renderFile('/main.html')).to
|
||||||
|
.eventually.equal('XAY');
|
||||||
|
});
|
||||||
|
it('should not bleed scope into included layout', function() {
|
||||||
|
mock({
|
||||||
|
'/parent.html': 'X{%block a%}{%endblock%}Y{%block b%}{%endblock%}Z',
|
||||||
|
'/main.html': '{%layout "parent"%}'+
|
||||||
|
'{%block a%}A{%endblock%}' +
|
||||||
|
'{%block b%}I{%include "included"%}J{%endblock%}',
|
||||||
|
'/included.html': '{%layout "parent"%}{%block a%}a{%endblock%}'
|
||||||
|
})
|
||||||
|
return expect(liquid.renderFile('main')).to
|
||||||
|
.eventually.equal('XAYIXaYZJZ');
|
||||||
|
});
|
||||||
|
it('should support hash list', function() {
|
||||||
|
mock({
|
||||||
|
'/parent.html': '{{color}}{%block%}{%endblock%}',
|
||||||
|
'/main.html': '{% layout "parent.html" color:"black"%}{%block%}A{%endblock%}'
|
||||||
|
});
|
||||||
|
return expect(liquid.renderFile('/main.html')).to.
|
||||||
|
eventually.equal('blackA');
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user