Created
February 2, 2016 00:38
-
-
Save createvibe/73948b67f8ef60f4d09c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Twig.extend(function(Twig) { | |
'use strict'; | |
var placeholders = {}; | |
Twig.Templates.registerLoader('async', async_loader); | |
// overloaded to handle logic output promises | |
Twig.parse = function (tokens, context) { | |
try { | |
var output = [], | |
// Track logic chains | |
chain = true, | |
that = this, | |
promises = []; | |
Twig.forEach(tokens, function parseToken(token) { | |
Twig.log.debug("Twig.parse: ", "Parsing token: ", token); | |
switch (token.type) { | |
case Twig.token.type.raw: | |
output.push(Twig.filters.raw(token.value)); | |
break; | |
case Twig.token.type.logic: | |
var logic_token = token.token, | |
logic = Twig.logic.parse.apply(that, [logic_token, context, chain]); | |
if (logic.chain !== undefined) { | |
chain = logic.chain; | |
} | |
if (logic.context !== undefined) { | |
context = logic.context; | |
} | |
if (logic.output !== undefined) { | |
if (logic.output instanceof Promise) { | |
(function(idx) { | |
output.push(null); | |
logic.output.then(function(data) { | |
output[idx] = data; | |
}); | |
promises.push(logic.output); | |
}(output.length)); | |
} else { | |
output.push(logic.output); | |
} | |
} | |
break; | |
case Twig.token.type.comment: | |
// Do nothing, comments should be ignored | |
break; | |
//Fall through whitespace to output | |
case Twig.token.type.output_whitespace_pre: | |
case Twig.token.type.output_whitespace_post: | |
case Twig.token.type.output_whitespace_both: | |
case Twig.token.type.output: | |
Twig.log.debug("Twig.parse: ", "Output token: ", token.stack); | |
// Parse the given expression in the given context | |
output.push(Twig.expression.parse.apply(that, [token.stack, context])); | |
break; | |
} | |
}); | |
if (promises.length !== 0) { | |
var self = this; | |
return new Promise(function(resolve, reject) { | |
Promise.all(promises).then(function(results) { | |
resolve(Twig.output.apply(self, [output])); | |
}); | |
}); | |
} | |
return Twig.output.apply(this, [output]); | |
} catch (ex) { | |
Twig.log.error("Error parsing twig template " + this.id + ": "); | |
if (ex.stack) { | |
Twig.log.error(ex.stack); | |
} else { | |
Twig.log.error(ex.toString()); | |
} | |
if (this.options.rethrow) throw ex; | |
if (Twig.debug) { | |
return ex.toString(); | |
} | |
} | |
}; | |
function async_loader(location, params, callback, error_callback) { | |
var p, | |
resolve, | |
reject, | |
template, | |
pid = Object.keys(placeholders).length; | |
p = placeholders[pid] = { | |
id: pid, | |
parentId: null, | |
loaded: false, | |
data: null, | |
promise: new Promise(function(res, rej) { | |
resolve = res; | |
reject = rej; | |
}) | |
}; | |
p.promise.placeholderId = pid; | |
p.xhr = load_file(location, params, function(data) { | |
p.loaded = true; | |
p.data = data; | |
resolve(data); | |
}, reject); | |
params.url = location; | |
template = new AsyncTemplate({ | |
id: location, | |
pid: pid, | |
async: false, | |
method: 'async', | |
href: location | |
}); | |
if (typeof callback === 'function') { | |
callback(template); | |
} | |
return template; | |
} | |
function load_file(location, params, callback, error_callback) { | |
var xhr = new XMLHttpRequest; | |
xhr.onreadystatechange = function() { | |
var data; | |
if (xhr.readyState === 4) { | |
if (xhr.status === 200) { | |
if (params.precompiled) { | |
data = JSON.parse(xhr.responseText); | |
} else { | |
data = xhr.responseText; | |
} | |
if (typeof callback === 'function') { | |
callback(data); | |
} | |
} else { | |
if (typeof error_callback === 'function') { | |
error_callback(xhr); | |
} | |
} | |
} | |
}; | |
// aways async! | |
xhr.open('GET', location, true); | |
xhr.send(); | |
return xhr; | |
} | |
function AsyncTemplate(params) { | |
Twig.Template.apply(this, arguments); | |
if (!this.options) { | |
this.options = {}; | |
} | |
this.placeholderId = params.pid; | |
this.options.placeholderId = this.placeholderId; | |
} | |
AsyncTemplate.prototype = Object.create(Twig.Template.prototype, { | |
placeholderId: { | |
value: null, | |
writable: true | |
}, | |
render: { | |
value: function render(context, params) { | |
var self = this, | |
p = placeholders[this.placeholderId]; | |
return new Promise(function(resolve, reject) { | |
p.promise.then(function(data) { | |
if (typeof data === 'string') { | |
self.tokens = Twig.prepare.call(self, data); | |
} else { | |
self.tokens = data; | |
} | |
var promise = Twig.Template.prototype.render.call(self, context, params); | |
if (!(promise instanceof Promise)) { | |
var deferred_output = promise; | |
promise = new Promise(function(resolve, reject) { | |
resolve(deferred_output); | |
}); | |
} | |
promise.then(resolve).catch(reject); | |
}).catch(reject); | |
}); | |
} | |
} | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment