Add xhr support for render file in browser.

This commit is contained in:
ChenL
2018-01-12 10:53:43 +08:00
committed by Jun Yang
parent eee5649a47
commit c55f0234eb
10 changed files with 531 additions and 130 deletions
+1
View File
@@ -0,0 +1 @@
access time: {{date|date: "%Y-%m-%d %H:%M:%S"}}
+1
View File
@@ -0,0 +1 @@
<h2>Welcome to {{ name | capitalize}}, {% include 'date.html' %}</h2>
+12 -6
View File
@@ -8,19 +8,25 @@
</head> </head>
<body> <body>
<h2 id="header"></h2>
<script> <script>
var engine = window.Liquid(); var engine = window.Liquid({
// root: './',
var src = 'Welcome to {{ name | capitalize}}, ' + extname: '.html',
'access time: {{date|date: "%Y-%m-%d %H:%M:%S"}}'; cache: true
});
var src = '<h2>Welcome to {{ name | capitalize}}, ' +
'access time: {{date|date: "%Y-%m-%d %H:%M:%S"}}</h2>';
var ctx = { var ctx = {
name: 'Liquid', name: 'Liquid',
date: new Date() date: new Date()
}; };
engine.parseAndRender(src, ctx) engine.parseAndRender(src, ctx)
.then(function(html) { .then(function(html) {
document.getElementById('header').innerHTML = html; document.body.innerHTML += html
return engine.renderFile('hello', ctx);
})
.then(function(html) {
document.body.innerHTML += html
}); });
</script> </script>
</body> </body>
+237 -120
View File
@@ -215,7 +215,7 @@ function isValidDate(date) {
registerAll.filters = filters; registerAll.filters = filters;
module.exports = registerAll; module.exports = registerAll;
},{"./src/syntax.js":14,"./src/util/strftime.js":21,"./src/util/underscore.js":22}],2:[function(require,module,exports){ },{"./src/syntax.js":15,"./src/util/strftime.js":22,"./src/util/underscore.js":23}],2:[function(require,module,exports){
'use strict'; 'use strict';
var Scope = require('./src/scope'); var Scope = require('./src/scope');
@@ -225,6 +225,7 @@ var tokenizer = require('./src/tokenizer.js');
var statFileAsync = require('./src/util/fs.js').statFileAsync; var statFileAsync = require('./src/util/fs.js').statFileAsync;
var readFileAsync = require('./src/util/fs.js').readFileAsync; var readFileAsync = require('./src/util/fs.js').readFileAsync;
var path = require('path'); var path = require('path');
var url = require('./src/util/url.js');
var Render = require('./src/render.js'); var Render = require('./src/render.js');
var lexical = require('./src/lexical.js'); var lexical = require('./src/lexical.js');
var Tag = require('./src/tag.js'); var Tag = require('./src/tag.js');
@@ -305,6 +306,9 @@ var _engine = {
}); });
}, },
getTemplate: function getTemplate(filepath, root) { getTemplate: function getTemplate(filepath, root) {
return typeof XMLHttpRequest === 'undefined' ? this.getTemplateFromFile(filepath, root) : this.getTemplateFromUrl(filepath, root);
},
getTemplateFromFile: function getTemplateFromFile(filepath, root) {
var _this3 = this; var _this3 = this;
if (!path.extname(filepath)) { if (!path.extname(filepath)) {
@@ -328,6 +332,44 @@ var _engine = {
} }
}); });
}, },
getTemplateFromUrl: function getTemplateFromUrl(filepath, root) {
var _this4 = this;
var fullUrl;
if (url.valid(filepath)) {
fullUrl = filepath;
} else {
if (!url.extname(filepath)) {
filepath += this.options.extname;
}
fullUrl = url.resolve(root || this.options.root, filepath);
}
if (this.options.cache) {
var tpl = this.cache[filepath];
if (tpl) {
return Promise.resolve(tpl);
}
}
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.onload = function () {
if (xhr.status >= 200 && xhr.status < 300) {
var tpl = _this4.parse(xhr.responseText);
if (_this4.options.cache) {
_this4.cache[filepath] = tpl;
}
resolve(tpl);
} else {
reject(new Error(xhr.statusText));
}
};
xhr.onerror = function () {
reject(new Error(xhr.statusText));
};
xhr.open('GET', fullUrl);
xhr.send();
});
},
express: function express(opts) { express: function express(opts) {
opts = opts || {}; opts = opts || {};
var self = this; var self = this;
@@ -384,7 +426,7 @@ factory.Types = {
module.exports = factory; module.exports = factory;
},{"./filters":1,"./src/filter.js":8,"./src/lexical.js":9,"./src/parser":11,"./src/render.js":12,"./src/scope":13,"./src/syntax.js":14,"./src/tag.js":15,"./src/tokenizer.js":16,"./src/util/assert.js":17,"./src/util/error.js":18,"./src/util/fs.js":19,"./src/util/promise.js":20,"./src/util/underscore.js":22,"./tags":34,"any-promise":3,"path":7}],3:[function(require,module,exports){ },{"./filters":1,"./src/filter.js":9,"./src/lexical.js":10,"./src/parser":12,"./src/render.js":13,"./src/scope":14,"./src/syntax.js":15,"./src/tag.js":16,"./src/tokenizer.js":17,"./src/util/assert.js":18,"./src/util/error.js":19,"./src/util/fs.js":20,"./src/util/promise.js":21,"./src/util/underscore.js":23,"./src/util/url.js":24,"./tags":36,"any-promise":3,"path":7}],3:[function(require,module,exports){
'use strict'; 'use strict';
module.exports = require('./register')().Promise; module.exports = require('./register')().Promise;
@@ -494,6 +536,58 @@ function loadImplementation() {
"use strict"; "use strict";
},{}],8:[function(require,module,exports){ },{}],8:[function(require,module,exports){
"use strict";
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
// Copyright 2014 Simon Lydell
// X11 (“MIT”) Licensed. (See LICENSE.)
void function (root, factory) {
if (typeof define === "function" && define.amd) {
define(factory);
} else if ((typeof exports === "undefined" ? "undefined" : _typeof(exports)) === "object") {
module.exports = factory();
} else {
root.resolveUrl = factory();
}
}(undefined, function () {
function resolveUrl() /* ...urls */{
var numUrls = arguments.length;
if (numUrls === 0) {
throw new Error("resolveUrl requires at least one argument; got none.");
}
var base = document.createElement("base");
base.href = arguments[0];
if (numUrls === 1) {
return base.href;
}
var head = document.getElementsByTagName("head")[0];
head.insertBefore(base, head.firstChild);
var a = document.createElement("a");
var resolved;
for (var index = 1; index < numUrls; index++) {
a.href = arguments[index];
resolved = a.href;
base.href = resolved;
}
head.removeChild(base);
return resolved;
}
return resolveUrl;
});
},{}],9:[function(require,module,exports){
'use strict'; 'use strict';
var lexical = require('./lexical.js'); var lexical = require('./lexical.js');
@@ -567,7 +661,7 @@ module.exports = function (options) {
}; };
}; };
},{"./lexical.js":9,"./syntax.js":14,"./util/assert.js":17,"./util/underscore.js":22}],9:[function(require,module,exports){ },{"./lexical.js":10,"./syntax.js":15,"./util/assert.js":18,"./util/underscore.js":23}],10:[function(require,module,exports){
'use strict'; 'use strict';
// quote related // quote related
@@ -683,7 +777,7 @@ module.exports = {
isInteger: isInteger isInteger: isInteger
}; };
},{}],10:[function(require,module,exports){ },{}],11:[function(require,module,exports){
'use strict'; 'use strict';
module.exports = function (isTruthy) { module.exports = function (isTruthy) {
@@ -720,7 +814,7 @@ module.exports = function (isTruthy) {
}; };
}; };
},{}],11:[function(require,module,exports){ },{}],12:[function(require,module,exports){
'use strict'; 'use strict';
var lexical = require('./lexical.js'); var lexical = require('./lexical.js');
@@ -831,7 +925,7 @@ module.exports = function (Tag, Filter) {
}; };
}; };
},{"./lexical.js":9,"./util/assert.js":17,"./util/error.js":18}],12:[function(require,module,exports){ },{"./lexical.js":10,"./util/assert.js":18,"./util/error.js":19}],13:[function(require,module,exports){
'use strict'; 'use strict';
var Syntax = require('./syntax.js'); var Syntax = require('./syntax.js');
@@ -913,7 +1007,7 @@ function stringify(val) {
module.exports = factory; module.exports = factory;
},{"./syntax.js":14,"./util/assert.js":17,"./util/error.js":18,"./util/promise.js":20,"any-promise":3}],13:[function(require,module,exports){ },{"./syntax.js":15,"./util/assert.js":18,"./util/error.js":19,"./util/promise.js":21,"any-promise":3}],14:[function(require,module,exports){
'use strict'; 'use strict';
var _ = require('./util/underscore.js'); var _ = require('./util/underscore.js');
@@ -1106,7 +1200,7 @@ exports.factory = function (ctx, opts) {
return scope; return scope;
}; };
},{"./lexical.js":9,"./util/assert.js":17,"./util/underscore.js":22}],14:[function(require,module,exports){ },{"./lexical.js":10,"./util/assert.js":18,"./util/underscore.js":23}],15:[function(require,module,exports){
'use strict'; 'use strict';
var operators = require('./operators.js')(isTruthy); var operators = require('./operators.js')(isTruthy);
@@ -1166,7 +1260,7 @@ module.exports = {
evalExp: evalExp, evalValue: evalValue, isTruthy: isTruthy, isFalsy: isFalsy evalExp: evalExp, evalValue: evalValue, isTruthy: isTruthy, isFalsy: isFalsy
}; };
},{"../src/util/assert.js":17,"./lexical.js":9,"./operators.js":10}],15:[function(require,module,exports){ },{"../src/util/assert.js":18,"./lexical.js":10,"./operators.js":11}],16:[function(require,module,exports){
'use strict'; 'use strict';
var lexical = require('./lexical.js'); var lexical = require('./lexical.js');
@@ -1235,7 +1329,7 @@ module.exports = function () {
}; };
}; };
},{"./lexical.js":9,"./syntax.js":14,"./util/assert.js":17,"any-promise":3}],16:[function(require,module,exports){ },{"./lexical.js":10,"./syntax.js":15,"./util/assert.js":18,"any-promise":3}],17:[function(require,module,exports){
'use strict'; 'use strict';
var lexical = require('./lexical.js'); var lexical = require('./lexical.js');
@@ -1328,7 +1422,7 @@ function LineNumber(html) {
exports.parse = parse; exports.parse = parse;
exports.whiteSpaceCtrl = whiteSpaceCtrl; exports.whiteSpaceCtrl = whiteSpaceCtrl;
},{"./lexical.js":9,"./util/assert.js":17,"./util/error.js":18,"./util/underscore.js":22,"./whitespace-ctrl.js":23}],17:[function(require,module,exports){ },{"./lexical.js":10,"./util/assert.js":18,"./util/error.js":19,"./util/underscore.js":23,"./whitespace-ctrl.js":25}],18:[function(require,module,exports){
'use strict'; 'use strict';
var AssertionError = require('./error.js').AssertionError; var AssertionError = require('./error.js').AssertionError;
@@ -1342,7 +1436,7 @@ function assert(predicate, message) {
module.exports = assert; module.exports = assert;
},{"./error.js":18}],18:[function(require,module,exports){ },{"./error.js":19}],19:[function(require,module,exports){
'use strict'; 'use strict';
var _ = require('./underscore.js'); var _ = require('./underscore.js');
@@ -1446,7 +1540,7 @@ module.exports = {
RenderError: RenderError RenderError: RenderError
}; };
},{"./underscore.js":22}],19:[function(require,module,exports){ },{"./underscore.js":23}],20:[function(require,module,exports){
'use strict'; 'use strict';
var fs = require('fs'); var fs = require('fs');
@@ -1472,7 +1566,7 @@ module.exports = {
statFileAsync: statFileAsync statFileAsync: statFileAsync
}; };
},{"fs":6}],20:[function(require,module,exports){ },{"fs":6}],21:[function(require,module,exports){
'use strict'; 'use strict';
var Promise = require('any-promise'); var Promise = require('any-promise');
@@ -1517,7 +1611,7 @@ function mapSeries(iterable, iteratee) {
exports.anySeries = anySeries; exports.anySeries = anySeries;
exports.mapSeries = mapSeries; exports.mapSeries = mapSeries;
},{"any-promise":3}],21:[function(require,module,exports){ },{"any-promise":3}],22:[function(require,module,exports){
'use strict'; 'use strict';
var monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; var monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
@@ -1711,7 +1805,7 @@ var strftime = function strftime(d, format) {
module.exports = strftime; module.exports = strftime;
},{}],22:[function(require,module,exports){ },{}],23:[function(require,module,exports){
'use strict'; 'use strict';
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
@@ -1853,7 +1947,34 @@ exports.forOwn = forOwn;
exports.assign = assign; exports.assign = assign;
exports.uniq = uniq; exports.uniq = uniq;
},{}],23:[function(require,module,exports){ },{}],24:[function(require,module,exports){
'use strict';
var resolve = require('resolve-url');
var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^/]+?|)(\.[^./]*|))(?:[/]*)$/;
var urlRe = /^(?:\w+:)?\/\/([^\s.]+\.\S{2}|localhost[:?\d]*)\S*$/;
// https://github.com/jinder/path/blob/master/path.js#L567
exports.extname = function (path) {
return splitPathRe.exec(path).slice(1)[3];
};
// https://www.npmjs.com/package/is-url
exports.valid = function (path) {
return urlRe.test(path);
};
exports.resolve = function (root, path) {
if (Object.prototype.toString.call(root) === '[object Array]') {
root = root[0];
}
if (root && root.charAt(root.length - 1) !== '/') {
root += '/';
}
return resolve(root, path);
};
},{"resolve-url":8}],25:[function(require,module,exports){
'use strict'; 'use strict';
var _ = require('./util/underscore.js'); var _ = require('./util/underscore.js');
@@ -1904,7 +2025,7 @@ function trimRight(token, greedy) {
module.exports = whiteSpaceCtrl; module.exports = whiteSpaceCtrl;
},{"./util/underscore.js":22}],24:[function(require,module,exports){ },{"./util/underscore.js":23}],26:[function(require,module,exports){
'use strict'; 'use strict';
var Liquid = require('..'); var Liquid = require('..');
@@ -1928,7 +2049,7 @@ module.exports = function (liquid) {
}); });
}; };
},{"..":2,"../src/util/assert.js":17,"any-promise":3}],25:[function(require,module,exports){ },{"..":2,"../src/util/assert.js":18,"any-promise":3}],27:[function(require,module,exports){
'use strict'; 'use strict';
var Liquid = require('..'); var Liquid = require('..');
@@ -1937,38 +2058,37 @@ var re = new RegExp('(' + lexical.identifier.source + ')');
var assert = require('../src/util/assert.js'); var assert = require('../src/util/assert.js');
module.exports = function (liquid) { module.exports = function (liquid) {
liquid.registerTag('capture', {
parse: function parse(tagToken, remainTokens) {
var _this = this;
liquid.registerTag('capture', { var match = tagToken.args.match(re);
parse: function parse(tagToken, remainTokens) { assert(match, tagToken.args + ' not valid identifier');
var _this = this;
var match = tagToken.args.match(re); this.variable = match[1];
assert(match, tagToken.args + ' not valid identifier'); this.templates = [];
this.variable = match[1]; var stream = liquid.parser.parseStream(remainTokens);
this.templates = []; stream.on('tag:endcapture', function (token) {
return stream.stop();
}).on('template', function (tpl) {
return _this.templates.push(tpl);
}).on('end', function (x) {
throw new Error('tag ' + tagToken.raw + ' not closed');
});
stream.start();
},
render: function render(scope, hash) {
var _this2 = this;
var stream = liquid.parser.parseStream(remainTokens); return liquid.renderer.renderTemplates(this.templates, scope).then(function (html) {
stream.on('tag:endcapture', function (token) { scope.set(_this2.variable, html);
return stream.stop(); });
}).on('template', function (tpl) { }
return _this.templates.push(tpl); });
}).on('end', function (x) {
throw new Error('tag ' + tagToken.raw + ' not closed');
});
stream.start();
},
render: function render(scope, hash) {
var _this2 = this;
return liquid.renderer.renderTemplates(this.templates, scope).then(function (html) {
scope.set(_this2.variable, html);
});
}
});
}; };
},{"..":2,"../src/util/assert.js":17}],26:[function(require,module,exports){ },{"..":2,"../src/util/assert.js":18}],28:[function(require,module,exports){
'use strict'; 'use strict';
var Liquid = require('..'); var Liquid = require('..');
@@ -2016,25 +2136,24 @@ module.exports = function (liquid) {
}); });
}; };
},{"..":2}],27:[function(require,module,exports){ },{"..":2}],29:[function(require,module,exports){
'use strict'; 'use strict';
module.exports = function (liquid) { module.exports = function (liquid) {
liquid.registerTag('comment', {
liquid.registerTag('comment', { parse: function parse(tagToken, remainTokens) {
parse: function parse(tagToken, remainTokens) { var stream = liquid.parser.parseStream(remainTokens);
var stream = liquid.parser.parseStream(remainTokens); stream.on('token', function (token) {
stream.on('token', function (token) { if (token.name === 'endcomment') stream.stop();
if (token.name === 'endcomment') stream.stop(); }).on('end', function (x) {
}).on('end', function (x) { throw new Error('tag ' + tagToken.raw + ' not closed');
throw new Error('tag ' + tagToken.raw + ' not closed'); });
}); stream.start();
stream.start(); }
} });
});
}; };
},{}],28:[function(require,module,exports){ },{}],30:[function(require,module,exports){
'use strict'; 'use strict';
var Liquid = require('..'); var Liquid = require('..');
@@ -2082,7 +2201,7 @@ module.exports = function (liquid) {
}); });
}; };
},{"..":2,"../src/util/assert.js":17,"any-promise":3}],29:[function(require,module,exports){ },{"..":2,"../src/util/assert.js":18,"any-promise":3}],31:[function(require,module,exports){
'use strict'; 'use strict';
var Liquid = require('..'); var Liquid = require('..');
@@ -2090,22 +2209,21 @@ var lexical = Liquid.lexical;
var assert = require('../src/util/assert.js'); var assert = require('../src/util/assert.js');
module.exports = function (liquid) { module.exports = function (liquid) {
liquid.registerTag('decrement', {
liquid.registerTag('decrement', { parse: function parse(token) {
parse: function parse(token) { var match = token.args.match(lexical.identifier);
var match = token.args.match(lexical.identifier); assert(match, 'illegal identifier ' + token.args);
assert(match, 'illegal identifier ' + token.args); this.variable = match[0];
this.variable = match[0]; },
}, render: function render(scope, hash) {
render: function render(scope, hash) { var v = scope.get(this.variable);
var v = scope.get(this.variable); if (typeof v !== 'number') v = 0;
if (typeof v !== 'number') v = 0; scope.set(this.variable, v - 1);
scope.set(this.variable, v - 1); }
} });
});
}; };
},{"..":2,"../src/util/assert.js":17}],30:[function(require,module,exports){ },{"..":2,"../src/util/assert.js":18}],32:[function(require,module,exports){
'use strict'; 'use strict';
var Liquid = require('..'); var Liquid = require('..');
@@ -2216,7 +2334,7 @@ module.exports = function (liquid) {
}); });
}; };
},{"..":2,"../src/util/assert.js":17,"../src/util/promise.js":20,"../src/util/underscore.js":22}],31:[function(require,module,exports){ },{"..":2,"../src/util/assert.js":18,"../src/util/promise.js":21,"../src/util/underscore.js":23}],33:[function(require,module,exports){
'use strict'; 'use strict';
var Liquid = require('..'); var Liquid = require('..');
@@ -2267,7 +2385,7 @@ module.exports = function (liquid) {
}); });
}; };
},{"..":2}],32:[function(require,module,exports){ },{"..":2}],34:[function(require,module,exports){
'use strict'; 'use strict';
var Liquid = require('..'); var Liquid = require('..');
@@ -2314,7 +2432,7 @@ module.exports = function (liquid) {
}); });
}; };
},{"..":2,"../src/util/assert.js":17}],33:[function(require,module,exports){ },{"..":2,"../src/util/assert.js":18}],35:[function(require,module,exports){
'use strict'; 'use strict';
var Liquid = require('..'); var Liquid = require('..');
@@ -2322,22 +2440,21 @@ var assert = require('../src/util/assert.js');
var lexical = Liquid.lexical; var lexical = Liquid.lexical;
module.exports = function (liquid) { module.exports = function (liquid) {
liquid.registerTag('increment', {
liquid.registerTag('increment', { parse: function parse(token) {
parse: function parse(token) { var match = token.args.match(lexical.identifier);
var match = token.args.match(lexical.identifier); assert(match, 'illegal identifier ' + token.args);
assert(match, 'illegal identifier ' + token.args); this.variable = match[0];
this.variable = match[0]; },
}, render: function render(scope, hash) {
render: function render(scope, hash) { var v = scope.get(this.variable);
var v = scope.get(this.variable); if (typeof v !== 'number') v = 0;
if (typeof v !== 'number') v = 0; scope.set(this.variable, v + 1);
scope.set(this.variable, v + 1); }
} });
});
}; };
},{"..":2,"../src/util/assert.js":17}],34:[function(require,module,exports){ },{"..":2,"../src/util/assert.js":18}],36:[function(require,module,exports){
'use strict'; 'use strict';
module.exports = function (engine) { module.exports = function (engine) {
@@ -2357,7 +2474,7 @@ module.exports = function (engine) {
require('./unless.js')(engine); require('./unless.js')(engine);
}; };
},{"./assign.js":24,"./capture.js":25,"./case.js":26,"./comment.js":27,"./cycle.js":28,"./decrement.js":29,"./for.js":30,"./if.js":31,"./include.js":32,"./increment.js":33,"./layout.js":35,"./raw.js":36,"./tablerow.js":37,"./unless.js":38}],35:[function(require,module,exports){ },{"./assign.js":26,"./capture.js":27,"./case.js":28,"./comment.js":29,"./cycle.js":30,"./decrement.js":31,"./for.js":32,"./if.js":33,"./include.js":34,"./increment.js":35,"./layout.js":37,"./raw.js":38,"./tablerow.js":39,"./unless.js":40}],37:[function(require,module,exports){
'use strict'; 'use strict';
var Liquid = require('..'); var Liquid = require('..');
@@ -2441,7 +2558,7 @@ module.exports = function (liquid) {
}); });
}; };
},{"..":2,"../src/util/assert.js":17,"any-promise":3}],36:[function(require,module,exports){ },{"..":2,"../src/util/assert.js":18,"any-promise":3}],38:[function(require,module,exports){
'use strict'; 'use strict';
var Promise = require('any-promise'); var Promise = require('any-promise');
@@ -2470,7 +2587,7 @@ module.exports = function (liquid) {
}); });
}; };
},{"any-promise":3}],37:[function(require,module,exports){ },{"any-promise":3}],39:[function(require,module,exports){
'use strict'; 'use strict';
var Liquid = require('..'); var Liquid = require('..');
@@ -2558,40 +2675,40 @@ module.exports = function (liquid) {
}); });
}; };
},{"..":2,"../src/util/assert.js":17,"../src/util/promise.js":20}],38:[function(require,module,exports){ },{"..":2,"../src/util/assert.js":18,"../src/util/promise.js":21}],40:[function(require,module,exports){
'use strict'; 'use strict';
var Liquid = require('..'); var Liquid = require('..');
module.exports = function (liquid) { module.exports = function (liquid) {
liquid.registerTag('unless', { liquid.registerTag('unless', {
parse: function parse(tagToken, remainTokens) { parse: function parse(tagToken, remainTokens) {
var _this = this; var _this = this;
this.templates = []; this.templates = [];
this.elseTemplates = []; this.elseTemplates = [];
var p, var p;
stream = liquid.parser.parseStream(remainTokens).on('start', function (x) { var stream = liquid.parser.parseStream(remainTokens).on('start', function (x) {
p = _this.templates; p = _this.templates;
_this.cond = tagToken.args; _this.cond = tagToken.args;
}).on('tag:else', function (token) { }).on('tag:else', function () {
return p = _this.elseTemplates; return p = _this.elseTemplates;
}).on('tag:endunless', function (token) { }).on('tag:endunless', function (token) {
return stream.stop(); return stream.stop();
}).on('template', function (tpl) { }).on('template', function (tpl) {
return p.push(tpl); return p.push(tpl);
}).on('end', function (x) { }).on('end', function (x) {
throw new Error('tag ' + tagToken.raw + ' not closed'); throw new Error('tag ' + tagToken.raw + ' not closed');
}); });
stream.start(); stream.start();
}, },
render: function render(scope, hash) { render: function render(scope, hash) {
var cond = Liquid.evalExp(this.cond, scope); var cond = Liquid.evalExp(this.cond, scope);
return Liquid.isFalsy(cond) ? liquid.renderer.renderTemplates(this.templates, scope) : liquid.renderer.renderTemplates(this.elseTemplates, scope); return Liquid.isFalsy(cond) ? liquid.renderer.renderTemplates(this.templates, scope) : liquid.renderer.renderTemplates(this.elseTemplates, scope);
} }
}); });
}; };
},{"..":2}]},{},[2])(2) },{"..":2}]},{},[2])(2)
+1 -1
View File
File diff suppressed because one or more lines are too long
+42
View File
@@ -5,6 +5,7 @@ const tokenizer = require('./src/tokenizer.js')
const statFileAsync = require('./src/util/fs.js').statFileAsync const statFileAsync = require('./src/util/fs.js').statFileAsync
const readFileAsync = require('./src/util/fs.js').readFileAsync const readFileAsync = require('./src/util/fs.js').readFileAsync
const path = require('path') const path = require('path')
const url = require('./src/util/url.js')
const Render = require('./src/render.js') const Render = require('./src/render.js')
const lexical = require('./src/lexical.js') const lexical = require('./src/lexical.js')
const Tag = require('./src/tag.js') const Tag = require('./src/tag.js')
@@ -73,6 +74,11 @@ var _engine = {
}) })
}, },
getTemplate: function (filepath, root) { getTemplate: function (filepath, root) {
return typeof XMLHttpRequest === 'undefined'
? this.getTemplateFromFile(filepath, root)
: this.getTemplateFromUrl(filepath, root)
},
getTemplateFromFile: function (filepath, root) {
if (!path.extname(filepath)) { if (!path.extname(filepath)) {
filepath += this.options.extname filepath += this.options.extname
} }
@@ -92,6 +98,42 @@ var _engine = {
} }
}) })
}, },
getTemplateFromUrl: function (filepath, root) {
var fullUrl
if (url.valid(filepath)) {
fullUrl = filepath
} else {
if (!url.extname(filepath)) {
filepath += this.options.extname
}
fullUrl = url.resolve(root || this.options.root, filepath)
}
if (this.options.cache) {
var tpl = this.cache[filepath]
if (tpl) {
return Promise.resolve(tpl)
}
}
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest()
xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 300) {
var tpl = this.parse(xhr.responseText)
if (this.options.cache) {
this.cache[filepath] = tpl
}
resolve(tpl)
} else {
reject(new Error(xhr.statusText))
}
}
xhr.onerror = () => {
reject(new Error(xhr.statusText))
}
xhr.open('GET', fullUrl)
xhr.send()
})
},
express: function (opts) { express: function (opts) {
opts = opts || {} opts = opts || {}
var self = this var self = this
+7 -3
View File
@@ -17,7 +17,9 @@
"type": "git", "type": "git",
"url": "git+https://github.com/harttle/liquidjs.git" "url": "git+https://github.com/harttle/liquidjs.git"
}, },
"engines": { "node" : ">=4.8.7" }, "engines": {
"node": ">=4.8.7"
},
"keywords": [ "keywords": [
"liquid", "liquid",
"template engine", "template engine",
@@ -32,14 +34,15 @@
}, },
"homepage": "https://github.com/harttle/liquidjs#readme", "homepage": "https://github.com/harttle/liquidjs#readme",
"dependencies": { "dependencies": {
"any-promise": "^1.3.0" "any-promise": "^1.3.0",
"resolve-url": "^0.2.1"
}, },
"browser": { "browser": {
"fs": false "fs": false
}, },
"devDependencies": { "devDependencies": {
"babel-preset-es2015": "^6.24.1",
"babel-core": "^6.26.0", "babel-core": "^6.26.0",
"babel-preset-es2015": "^6.24.1",
"babelify": "^8.0.0", "babelify": "^8.0.0",
"browserify": "^14.4.0", "browserify": "^14.4.0",
"chai": "^4.1.2", "chai": "^4.1.2",
@@ -54,6 +57,7 @@
"eslint-plugin-standard": "^3.0.1", "eslint-plugin-standard": "^3.0.1",
"express": "^4.16.1", "express": "^4.16.1",
"istanbul": "^0.4.5", "istanbul": "^0.4.5",
"jsdom": "^11.5.1",
"mocha": "^4.0.0", "mocha": "^4.0.0",
"mock-fs": "^4.4.1", "mock-fs": "^4.4.1",
"sinon": "^4.0.1", "sinon": "^4.0.1",
+23
View File
@@ -0,0 +1,23 @@
const resolve = require('resolve-url')
const splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^/]+?|)(\.[^./]*|))(?:[/]*)$/
const urlRe = /^(?:\w+:)?\/\/([^\s.]+\.\S{2}|localhost[:?\d]*)\S*$/
// https://github.com/jinder/path/blob/master/path.js#L567
exports.extname = function (path) {
return splitPathRe.exec(path).slice(1)[3]
}
// https://www.npmjs.com/package/is-url
exports.valid = function (path) {
return urlRe.test(path)
}
exports.resolve = function (root, path) {
if (Object.prototype.toString.call(root) === '[object Array]') {
root = root[0]
}
if (root && root.charAt(root.length - 1) !== '/') {
root += '/'
}
return resolve(root, path)
}
+61
View File
@@ -0,0 +1,61 @@
const chai = require('chai')
const expect = chai.expect
const url = require('../../src/util/url.js')
const { JSDOM } = require('jsdom')
describe('util/url', function () {
var dom
beforeEach(function () {
dom = new JSDOM(``, {
url: 'https://example.com/foo/bar/',
contentType: 'text/html',
includeNodeLocations: true
})
global.document = dom.window.document
})
afterEach(function () {
delete global.document
})
describe('resolve', function () {
describe('root', function () {
it('should support width relative path', function () {
expect(url.resolve('./views', 'foo'))
.to.equal('https://example.com/foo/bar/views/foo')
expect(url.resolve('./views/', 'foo'))
.to.equal('https://example.com/foo/bar/views/foo')
})
it('should support width absolute path', function () {
expect(url.resolve('/views', 'foo'))
.to.equal('https://example.com/views/foo')
expect(url.resolve('/views/', 'foo'))
.to.equal('https://example.com/views/foo')
})
it('should support with empty', function () {
expect(url.resolve('', 'page.html'))
.to.equal('https://example.com/foo/bar/page.html')
})
it('should support with url', function () {
expect(url.resolve('https://example.com/views', 'page.html'))
.to.equal('https://example.com/views/page.html')
expect(url.resolve('https://example.com/views/', 'page.html'))
.to.equal('https://example.com/views/page.html')
})
it('should get the first value when argument is array', function () {
expect(url.resolve(['https://example.com/views', 'https://google.com/views'], 'page.html'))
.to.equal('https://example.com/views/page.html')
expect(url.resolve(['https://example.com/views/', 'https://google.com/views'], 'page.html'))
.to.equal('https://example.com/views/page.html')
})
})
describe('path', function () {
it('should support width relative path', function () {
expect(url.resolve('./views/', 'page.html'))
.to.equal('https://example.com/foo/bar/views/page.html')
})
it('should support with absolute path', function () {
expect(url.resolve('/views/', '/page.html'))
.to.equal('https://example.com/page.html')
})
})
})
})
+146
View File
@@ -0,0 +1,146 @@
const Liquid = require('..')
const sinon = require('sinon')
const { JSDOM } = require('jsdom')
const chai = require('chai')
const expect = chai.expect
describe('xhr', () => {
var server, engine, dom
beforeEach(() => {
server = sinon.fakeServer.create()
server.autoRespond = true
server.respondWith('GET', 'https://example.com/views/hello.html',
[200, {'Content-Type': 'text/plain'}, 'hello {{name}}'])
global.XMLHttpRequest = sinon.useFakeXMLHttpRequest()
dom = new JSDOM(``, {
url: 'https://example.com/',
referrer: 'https://example.com/',
contentType: 'text/html',
includeNodeLocations: true
})
global.document = dom.window.document
engine = Liquid({
root: 'https://example.com/views',
extname: '.html'
})
})
afterEach(() => {
server.restore()
delete global.XMLHttpRequest
delete global.document
})
describe('#renderFile()', () => {
it('should support without extname', () => {
return expect(engine.renderFile('hello', {name: 'alice1'}))
.to.eventually.equal('hello alice1')
})
it('should support with extname', () => {
return expect(engine.renderFile('hello.html', {name: 'alice2'}))
.to.eventually.equal('hello alice2')
})
it('should support with absolute path', () => {
server.respondWith('GET', 'https://example.com/foo.html',
[200, {'Content-Type': 'text/plain'}, 'foo'])
return expect(engine.renderFile('/foo.html'))
.to.eventually.equal('foo')
})
it('should support with url', () => {
return expect(engine.renderFile('https://example.com/views/hello.html', {name: 'alice4'}))
.to.eventually.equal('hello alice4')
})
it('should support include', () => {
server.respondWith('GET', 'https://example.com/views/hello.html',
[200, {'Content-Type': 'text/plain'}, "hello {% include 'name.html' %}"])
server.respondWith('GET', 'https://example.com/views/name.html',
[200, {'Content-Type': 'text/plain'}, '{{name}}'])
return expect(engine.renderFile('hello.html', {name: 'alice5'}))
.to.eventually.equal('hello alice5')
})
it('should throw 404', () => {
return expect(engine.renderFile('/not/exist.html'))
.to.be.rejectedWith('Not Found')
})
})
describe('root', () => {
it('should support with null', () => {
dom = new JSDOM(``, {
url: 'https://example.com/bar/',
referrer: 'https://example.com/bar/',
contentType: 'text/html',
includeNodeLocations: true
})
global.document = dom.window.document
engine = Liquid({
extname: '.html'
})
server.respondWith('GET', 'https://example.com/bar/hello.html',
[200, {'Content-Type': 'text/plain'}, 'hello {{name}}'])
return expect(engine.renderFile('hello.html', {name: 'alice5'}))
.to.eventually.equal('hello alice5')
})
it('should support with empty', () => {
dom = new JSDOM(``, {
url: 'https://example.com/foo/',
referrer: 'https://example.com/foo/',
contentType: 'text/html',
includeNodeLocations: true
})
global.document = dom.window.document
engine = Liquid({
root: '',
extname: '.html'
})
server.respondWith('GET', 'https://example.com/foo/hello.html',
[200, {'Content-Type': 'text/plain'}, 'hello {{name}}'])
return expect(engine.renderFile('hello.html', {name: 'alice5'}))
.to.eventually.equal('hello alice5')
})
it('should support with relative path', () => {
dom = new JSDOM(``, {
url: 'https://example.com/foo/',
referrer: 'https://example.com/foo/',
contentType: 'text/html',
includeNodeLocations: true
})
global.document = dom.window.document
engine = Liquid({
root: './views/',
extname: '.html'
})
server.respondWith('GET', 'https://example.com/foo/views/hello.html',
[200, {'Content-Type': 'text/plain'}, 'hello {{name}}'])
return expect(engine.renderFile('hello.html', {name: 'alice5'}))
.to.eventually.equal('hello alice5')
})
it('should support with absolute path', () => {
dom = new JSDOM(``, {
url: 'https://example.com/foo/',
referrer: 'https://example.com/foo/',
contentType: 'text/html',
includeNodeLocations: true
})
global.document = dom.window.document
engine = Liquid({
root: '/views/',
extname: '.html'
})
server.respondWith('GET', 'https://example.com/views/hello.html',
[200, {'Content-Type': 'text/plain'}, 'hello {{name}}'])
return expect(engine.renderFile('hello.html', {name: 'alice5'}))
.to.eventually.equal('hello alice5')
})
it('should support with url', () => {
engine = Liquid({
root: 'https://foo.com/bar/',
extname: '.html'
})
server.respondWith('GET', 'https://foo.com/bar/hello.html',
[200, {'Content-Type': 'text/plain'}, 'hello {{name}}'])
return expect(engine.renderFile('hello.html', {name: 'alice5'}))
.to.eventually.equal('hello alice5')
})
})
})