MDL-54915 templates: Fix async rendering of js blocks
Mustache JS helper can overwrite JS blocks when using nested templates. Each call to render should have it's own scope.
This commit is contained in:
Vendored
+1
-1
@@ -1 +1 @@
|
||||
define(["core/mustache","jquery","core/ajax","core/str","core/notification","core/url","core/config","core/localstorage","core/event","core/yui","core/log"],function(a,b,c,d,e,f,g,h,i,j,k){var l={},m=[],n=[],o=1,p="",q=function(a,d){var e=b.Deferred(),f=a.split("/"),g=f.shift(),i=f.shift(),j=p+"/"+a;if(j in l)return e.resolve(l[j]),e.promise();var k=h.get("core_template/"+j);if(k)return e.resolve(k),l[j]=k,e.promise();var m=c.call([{methodname:"core_output_load_template",args:{component:g,template:i,themename:p}}],d,!1);return m[0].done(function(a){h.set("core_template/"+j,a),l[j]=a,e.resolve(a)}).fail(function(a){e.reject(a)}),e.promise()},r=function(a){var b="";return q(a,!1).done(function(a){b=a}).fail(e.exception),b},s=function(b,c){var d,e=b.split(","),g="",h="",i="";e.length>0&&(g=e.shift().trim()),e.length>0&&(h=e.shift().trim()),e.length>0&&(i=e.join(",").trim());var j=f.imageUrl(g,h),k={attributes:[{name:"src",value:j},{name:"alt",value:c(i)},{name:"class",value:"smallicon"}]},m=l[p+"/core/pix_icon"];return d=a.render(m,k,r),d.trim()},t=function(a,b){return n.push(b(a,this)),""},u=function(a,b){var c=a.split(","),d="",e="",f="";c.length>0&&(d=c.shift().trim()),c.length>0&&(e=c.shift().trim()),c.length>0&&(f=c.join(",").trim()),""!==f&&(f=b(f,this)),0===f.indexOf("{")&&0!==f.indexOf("{{")&&(f=JSON.parse(f));var g=m.length;return m.push({key:d,component:e,param:f}),"{{_s"+g+"}}"},v=function(a,b){var c=b(a.trim(),this);return c=c.replace('"','\\"').replace(/([\{\}]{2,3})/g,"{{=<% %>=}}$1<%={{ }}=%>"),'"'+c+'"'},w=function(a,b){p=b,m=[],n=[],a.uniqid=o++,a.str=function(){return u},a.pix=function(){return s},a.js=function(){return t},a.quote=function(){return v},a.globals={config:g},a.currentTheme=b},x=function(a){var b="";return n.length>0&&(b=n.join(";\n")),y(b,a)},y=function(a,b){var c,d,e,f,g,h,i=/{{_s\d+}}/;do{for(c="",d=a.search(i);d>-1;){c+=a.substring(0,d),a=a.substr(d),e="",f=4,g=a.substr(f,1);do e+=g,f++,g=a.substr(f,1);while("}"!=g);h=b[parseInt(e,10)],"undefined"==typeof h&&(k.debug("Could not find string for pattern {{_s"+e+"}}."),h=""),c+=h,a=a.substr(6+e.length),d=a.search(i)}a=c+a,d=a.search(i)}while(d>-1);return a},z=function(c,e,f){var g=b.Deferred();p=f;var h=q("core/pix_icon",!0);return h.done(function(){w(e,f);var b="";try{b=a.render(c,e,r)}catch(h){g.reject(h)}m.length>0?d.get_strings(m).then(function(a){b=y(b,a),g.resolve(b,x(a))}).fail(g.reject):g.resolve(b.trim(),x([]))}).fail(g.reject),g.promise()},A=function(a){if(""!==a.trim()){var c=b("<script>").attr("type","text/javascript").html(a);b("head").append(c)}},B=function(a,c,d,e){var f=b(a);if(f.length){var g=b(c),h=null;e?(h=new j.NodeList(f.children().get()),h.destroy(!0),f.empty(),f.append(g)):(h=new j.NodeList(f.get()),h.destroy(!0),f.replaceWith(g)),A(d),i.notifyFilterContentUpdated(g)}};return{render:function(a,c,d){var e=b.Deferred();"undefined"==typeof d&&(d=g.theme),p=d;var f=q(a,!0);return f.done(function(a){var b=z(a,c,d);b.done(function(a,b){e.resolve(a,b)}).fail(function(a){e.reject(a)})}).fail(function(a){e.reject(a)}),e.promise()},runTemplateJS:A,replaceNodeContents:function(a,b,c){return B(a,b,c,!0)},replaceNode:function(a,b,c){return B(a,b,c,!1)}}});
|
||||
define(["core/mustache","jquery","core/ajax","core/str","core/notification","core/url","core/config","core/localstorage","core/event","core/yui","core/log"],function(a,b,c,d,e,f,g,h,i,j,k){var l=0,m={},n=function(){this.requiredStrings=[],this.requiredJS=[],this.currentThemeName=""};n.prototype.requiredStrings=null,n.prototype.requiredJS=null,n.prototype.currentThemeName="",n.prototype.getTemplate=function(a,d){var e=b.Deferred(),f=a.split("/"),g=f.shift(),i=f.shift(),j=this.currentThemeName+"/"+a;if(j in m)return e.resolve(m[j]),e.promise();var k=h.get("core_template/"+j);if(k)return e.resolve(k),m[j]=k,e.promise();var l=c.call([{methodname:"core_output_load_template",args:{component:g,template:i,themename:this.currentThemeName}}],d,!1);return l[0].done(function(a){h.set("core_template/"+j,a),m[j]=a,e.resolve(a)}).fail(function(a){e.reject(a)}),e.promise()},n.prototype.partialHelper=function(a){var b="";return this.getTemplate(a,!1).done(function(a){b=a}).fail(e.exception),b},n.prototype.pixHelper=function(b,c,d){var e,g=c.split(","),h="",i="",j="";g.length>0&&(h=g.shift().trim()),g.length>0&&(i=g.shift().trim()),g.length>0&&(j=g.join(",").trim());var k=f.imageUrl(h,i),l={attributes:[{name:"src",value:k},{name:"alt",value:d(j)},{name:"class",value:"smallicon"}]},n=m[this.currentThemeName+"/core/pix_icon"];return e=a.render(n,l,this.partialHelper.bind(this)),e.trim()},n.prototype.jsHelper=function(a,b,c){return this.requiredJS.push(c(b,a)),""},n.prototype.stringHelper=function(a,b,c){var d=b.split(","),e="",f="",g="";d.length>0&&(e=d.shift().trim()),d.length>0&&(f=d.shift().trim()),d.length>0&&(g=d.join(",").trim()),""!==g&&(g=c(g,a)),0===g.indexOf("{")&&0!==g.indexOf("{{")&&(g=JSON.parse(g));var h=this.requiredStrings.length;return this.requiredStrings.push({key:e,component:f,param:g}),"{{_s"+h+"}}"},n.prototype.quoteHelper=function(a,b,c){var d=c(b.trim(),a);return d=d.replace('"','\\"').replace(/([\{\}]{2,3})/g,"{{=<% %>=}}$1<%={{ }}=%>"),'"'+d+'"'},n.prototype.addHelpers=function(a,b){this.currentThemeName=b,this.requiredStrings=[],this.requiredJS=[],a.uniqid=l++,a.str=function(){return this.stringHelper.bind(this,a)}.bind(this),a.pix=function(){return this.pixHelper.bind(this,a)}.bind(this),a.js=function(){return this.jsHelper.bind(this,a)}.bind(this),a.quote=function(){return this.quoteHelper.bind(this,a)}.bind(this),a.globals={config:g},a.currentTheme=b},n.prototype.getJS=function(a){var b="";return this.requiredJS.length>0&&(b=this.requiredJS.join(";\n")),this.treatStringsInContent(b,a)},n.prototype.treatStringsInContent=function(a,b){var c,d,e,f,g,h,i=/{{_s\d+}}/;do{for(c="",d=a.search(i);d>-1;){c+=a.substring(0,d),a=a.substr(d),e="",f=4,g=a.substr(f,1);do e+=g,f++,g=a.substr(f,1);while("}"!=g);h=b[parseInt(e,10)],"undefined"==typeof h&&(k.debug("Could not find string for pattern {{_s"+e+"}}."),h=""),c+=h,a=a.substr(6+e.length),d=a.search(i)}a=c+a,d=a.search(i)}while(d>-1);return a},n.prototype.doRender=function(c,e,f){var g=b.Deferred();this.currentThemeName=f;var h=this.getTemplate("core/pix_icon",!0);return h.done(function(){this.addHelpers(e,f);var b="";try{b=a.render(c,e,this.partialHelper.bind(this))}catch(h){g.reject(h)}this.requiredStrings.length>0?d.get_strings(this.requiredStrings).then(function(a){b=this.treatStringsInContent(b,a),g.resolve(b,this.getJS(a))}.bind(this)).fail(g.reject):g.resolve(b.trim(),this.getJS([]))}.bind(this)).fail(g.reject),g.promise()};var o=function(a){if(""!==a.trim()){var c=b("<script>").attr("type","text/javascript").html(a);b("head").append(c)}},p=function(a,c,d,e){var f=b(a);if(f.length){var g=b(c),h=null;e?(h=new j.NodeList(f.children().get()),h.destroy(!0),f.empty(),f.append(g)):(h=new j.NodeList(f.get()),h.destroy(!0),f.replaceWith(g)),o(d),i.notifyFilterContentUpdated(g)}};return n.prototype.render=function(a,c,d){var e=b.Deferred();"undefined"==typeof d&&(d=g.theme),this.currentThemeName=d;var f=this.getTemplate(a,!0);return f.done(function(a){var b=this.doRender(a,c,d);b.done(function(a,b){e.resolve(a,b)}).fail(function(a){e.reject(a)})}.bind(this)).fail(function(a){e.reject(a)}),e.promise()},{render:function(a,b,c){var d=new n;return d.render(a,b,c)},runTemplateJS:o,replaceNodeContents:function(a,b,c){return p(a,b,c,!0)},replaceNode:function(a,b,c){return p(a,b,c,!1)}}});
|
||||
+123
-82
@@ -37,22 +37,33 @@ define([ 'core/mustache',
|
||||
],
|
||||
function(mustache, $, ajax, str, notification, coreurl, config, storage, event, Y, Log) {
|
||||
|
||||
// Private variables and functions.
|
||||
// Module variables.
|
||||
/** @var {Number} uniqInstances Count of times this constructor has been called. */
|
||||
var uniqInstances = 0;
|
||||
|
||||
/** @var {string[]} templateCache - Cache of already loaded templates */
|
||||
var templateCache = {};
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Each call to templates.render gets it's own instance of this class.
|
||||
*/
|
||||
var Renderer = function() {
|
||||
this.requiredStrings = [];
|
||||
this.requiredJS = [];
|
||||
this.currentThemeName = '';
|
||||
};
|
||||
// Class variables and functions.
|
||||
|
||||
/** @var {string[]} requiredStrings - Collection of strings found during the rendering of one template */
|
||||
var requiredStrings = [];
|
||||
Renderer.prototype.requiredStrings = null;
|
||||
|
||||
/** @var {string[]} requiredJS - Collection of js blocks found during the rendering of one template */
|
||||
var requiredJS = [];
|
||||
|
||||
/** @var {Number} uniqid Incrementing value that is changed for every call to render */
|
||||
var uniqid = 1;
|
||||
Renderer.prototype.requiredJS = null;
|
||||
|
||||
/** @var {String} themeName for the current render */
|
||||
var currentThemeName = '';
|
||||
Renderer.prototype.currentThemeName = '';
|
||||
|
||||
/**
|
||||
* Load a template from the cache or local storage or ajax request.
|
||||
@@ -64,13 +75,13 @@ define([ 'core/mustache',
|
||||
* tool_bananas/yellow (admin/tool/bananas/templates/yellow.mustache)
|
||||
* @return {Promise} JQuery promise object resolved when the template has been fetched.
|
||||
*/
|
||||
var getTemplate = function(templateName, async) {
|
||||
Renderer.prototype.getTemplate = function(templateName, async) {
|
||||
var deferred = $.Deferred();
|
||||
var parts = templateName.split('/');
|
||||
var component = parts.shift();
|
||||
var name = parts.shift();
|
||||
|
||||
var searchKey = currentThemeName + '/' + templateName;
|
||||
var searchKey = this.currentThemeName + '/' + templateName;
|
||||
|
||||
// First try request variables.
|
||||
if (searchKey in templateCache) {
|
||||
@@ -93,7 +104,7 @@ define([ 'core/mustache',
|
||||
args:{
|
||||
component: component,
|
||||
template: name,
|
||||
themename: currentThemeName
|
||||
themename: this.currentThemeName
|
||||
}
|
||||
}], async, false);
|
||||
|
||||
@@ -119,10 +130,10 @@ define([ 'core/mustache',
|
||||
* @param {string} name The partial name to load.
|
||||
* @return {string}
|
||||
*/
|
||||
var partialHelper = function(name) {
|
||||
Renderer.prototype.partialHelper = function(name) {
|
||||
var template = '';
|
||||
|
||||
getTemplate(name, false).done(
|
||||
this.getTemplate(name, false).done(
|
||||
function(source) {
|
||||
template = source;
|
||||
}
|
||||
@@ -136,11 +147,12 @@ define([ 'core/mustache',
|
||||
*
|
||||
* @method pixHelper
|
||||
* @private
|
||||
* @param {object} context The mustache context
|
||||
* @param {string} sectionText The text to parse arguments from.
|
||||
* @param {function} helper Used to render the alt attribute of the text.
|
||||
* @return {string}
|
||||
*/
|
||||
var pixHelper = function(sectionText, helper) {
|
||||
Renderer.prototype.pixHelper = function(context, sectionText, helper) {
|
||||
var parts = sectionText.split(',');
|
||||
var key = '';
|
||||
var component = '';
|
||||
@@ -166,8 +178,8 @@ define([ 'core/mustache',
|
||||
]
|
||||
};
|
||||
// We forced loading of this early, so it will be in the cache.
|
||||
var template = templateCache[currentThemeName + '/core/pix_icon'];
|
||||
result = mustache.render(template, templatecontext, partialHelper);
|
||||
var template = templateCache[this.currentThemeName + '/core/pix_icon'];
|
||||
result = mustache.render(template, templatecontext, this.partialHelper.bind(this));
|
||||
return result.trim();
|
||||
};
|
||||
|
||||
@@ -176,12 +188,13 @@ define([ 'core/mustache',
|
||||
*
|
||||
* @method jsHelper
|
||||
* @private
|
||||
* @param {object} context The current mustache context.
|
||||
* @param {string} sectionText The text to save as a js block.
|
||||
* @param {function} helper Used to render the block.
|
||||
* @return {string}
|
||||
*/
|
||||
var jsHelper = function(sectionText, helper) {
|
||||
requiredJS.push(helper(sectionText, this));
|
||||
Renderer.prototype.jsHelper = function(context, sectionText, helper) {
|
||||
this.requiredJS.push(helper(sectionText, context));
|
||||
return '';
|
||||
};
|
||||
|
||||
@@ -191,11 +204,12 @@ define([ 'core/mustache',
|
||||
*
|
||||
* @method stringHelper
|
||||
* @private
|
||||
* @param {object} context The current mustache context.
|
||||
* @param {string} sectionText The text to parse the arguments from.
|
||||
* @param {function} helper Used to render subsections of the text.
|
||||
* @return {string}
|
||||
*/
|
||||
var stringHelper = function(sectionText, helper) {
|
||||
Renderer.prototype.stringHelper = function(context, sectionText, helper) {
|
||||
var parts = sectionText.split(',');
|
||||
var key = '';
|
||||
var component = '';
|
||||
@@ -212,15 +226,15 @@ define([ 'core/mustache',
|
||||
|
||||
if (param !== '') {
|
||||
// Allow variable expansion in the param part only.
|
||||
param = helper(param, this);
|
||||
param = helper(param, context);
|
||||
}
|
||||
// Allow json formatted $a arguments.
|
||||
if ((param.indexOf('{') === 0) && (param.indexOf('{{') !== 0)) {
|
||||
param = JSON.parse(param);
|
||||
}
|
||||
|
||||
var index = requiredStrings.length;
|
||||
requiredStrings.push({key: key, component: component, param: param});
|
||||
var index = this.requiredStrings.length;
|
||||
this.requiredStrings.push({key: key, component: component, param: param});
|
||||
return '{{_s' + index + '}}';
|
||||
};
|
||||
|
||||
@@ -229,12 +243,13 @@ define([ 'core/mustache',
|
||||
*
|
||||
* @method quoteHelper
|
||||
* @private
|
||||
* @param {object} context The current mustache context.
|
||||
* @param {string} sectionText The text to parse the arguments from.
|
||||
* @param {function} helper Used to render subsections of the text.
|
||||
* @return {string}
|
||||
*/
|
||||
var quoteHelper = function(sectionText, helper) {
|
||||
var content = helper(sectionText.trim(), this);
|
||||
Renderer.prototype.quoteHelper = function(context, sectionText, helper) {
|
||||
var content = helper(sectionText.trim(), context);
|
||||
|
||||
// Escape the {{ and the ".
|
||||
// This involves wrapping {{, and }} in change delimeter tags.
|
||||
@@ -254,16 +269,24 @@ define([ 'core/mustache',
|
||||
* @param {Object} context Simple types used as the context for the template.
|
||||
* @param {String} themeName We set this multiple times, because there are async calls.
|
||||
*/
|
||||
var addHelpers = function(context, themeName) {
|
||||
currentThemeName = themeName;
|
||||
requiredStrings = [];
|
||||
requiredJS = [];
|
||||
context.uniqid = uniqid++;
|
||||
context.str = function() { return stringHelper; };
|
||||
context.pix = function() { return pixHelper; };
|
||||
context.js = function() { return jsHelper; };
|
||||
context.quote = function() { return quoteHelper; };
|
||||
context.globals = { config : config };
|
||||
Renderer.prototype.addHelpers = function(context, themeName) {
|
||||
this.currentThemeName = themeName;
|
||||
this.requiredStrings = [];
|
||||
this.requiredJS = [];
|
||||
context.uniqid = (uniqInstances++);
|
||||
context.str = function() {
|
||||
return this.stringHelper.bind(this, context);
|
||||
}.bind(this);
|
||||
context.pix = function() {
|
||||
return this.pixHelper.bind(this, context);
|
||||
}.bind(this);
|
||||
context.js = function() {
|
||||
return this.jsHelper.bind(this, context);
|
||||
}.bind(this);
|
||||
context.quote = function() {
|
||||
return this.quoteHelper.bind(this, context);
|
||||
}.bind(this);
|
||||
context.globals = {config: config};
|
||||
context.currentTheme = themeName;
|
||||
};
|
||||
|
||||
@@ -275,14 +298,14 @@ define([ 'core/mustache',
|
||||
* @param {string[]} strings Replacement strings.
|
||||
* @return {string}
|
||||
*/
|
||||
var getJS = function(strings) {
|
||||
Renderer.prototype.getJS = function(strings) {
|
||||
var js = '';
|
||||
if (requiredJS.length > 0) {
|
||||
js = requiredJS.join(";\n");
|
||||
if (this.requiredJS.length > 0) {
|
||||
js = this.requiredJS.join(";\n");
|
||||
}
|
||||
|
||||
// Re-render to get the final strings.
|
||||
return treatStringsInContent(js, strings);
|
||||
return this.treatStringsInContent(js, strings);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -302,7 +325,7 @@ define([ 'core/mustache',
|
||||
* @param {Array} strings The strings to replace with.
|
||||
* @return {String} The treated content.
|
||||
*/
|
||||
var treatStringsInContent = function(content, strings) {
|
||||
Renderer.prototype.treatStringsInContent = function(content, strings) {
|
||||
var pattern = /{{_s\d+}}/,
|
||||
treated,
|
||||
index,
|
||||
@@ -364,26 +387,26 @@ define([ 'core/mustache',
|
||||
* @param {String} themeName Name of the current theme.
|
||||
* @return {Promise} object
|
||||
*/
|
||||
var doRender = function(templateSource, context, themeName) {
|
||||
Renderer.prototype.doRender = function(templateSource, context, themeName) {
|
||||
var deferred = $.Deferred();
|
||||
|
||||
currentThemeName = themeName;
|
||||
this.currentThemeName = themeName;
|
||||
|
||||
// Make sure we fetch this first.
|
||||
var loadPixTemplate = getTemplate('core/pix_icon', true);
|
||||
var loadPixTemplate = this.getTemplate('core/pix_icon', true);
|
||||
|
||||
loadPixTemplate.done(
|
||||
function() {
|
||||
addHelpers(context, themeName);
|
||||
this.addHelpers(context, themeName);
|
||||
var result = '';
|
||||
try {
|
||||
result = mustache.render(templateSource, context, partialHelper);
|
||||
result = mustache.render(templateSource, context, this.partialHelper.bind(this));
|
||||
} catch (ex) {
|
||||
deferred.reject(ex);
|
||||
}
|
||||
|
||||
if (requiredStrings.length > 0) {
|
||||
str.get_strings(requiredStrings)
|
||||
if (this.requiredStrings.length > 0) {
|
||||
str.get_strings(this.requiredStrings)
|
||||
.then(function(strings) {
|
||||
|
||||
// Why do we not do another call the render here?
|
||||
@@ -393,14 +416,14 @@ define([ 'core/mustache',
|
||||
// would get inserted in the template in the first pass
|
||||
// and cause the template to die on the second pass (unbalanced).
|
||||
|
||||
result = treatStringsInContent(result, strings);
|
||||
deferred.resolve(result, getJS(strings));
|
||||
})
|
||||
result = this.treatStringsInContent(result, strings);
|
||||
deferred.resolve(result, this.getJS(strings));
|
||||
}.bind(this))
|
||||
.fail(deferred.reject);
|
||||
} else {
|
||||
deferred.resolve(result.trim(), getJS([]));
|
||||
deferred.resolve(result.trim(), this.getJS([]));
|
||||
}
|
||||
}
|
||||
}.bind(this)
|
||||
).fail(deferred.reject);
|
||||
return deferred.promise();
|
||||
};
|
||||
@@ -459,11 +482,58 @@ define([ 'core/mustache',
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Load a template and call doRender on it.
|
||||
*
|
||||
* @method render
|
||||
* @private
|
||||
* @param {string} templateName - should consist of the component and the name of the template like this:
|
||||
* core/menu (lib/templates/menu.mustache) or
|
||||
* tool_bananas/yellow (admin/tool/bananas/templates/yellow.mustache)
|
||||
* @param {Object} context - Could be array, string or simple value for the context of the template.
|
||||
* @param {string} themeName - Name of the current theme.
|
||||
* @return {Promise} JQuery promise object resolved when the template has been rendered.
|
||||
*/
|
||||
Renderer.prototype.render = function(templateName, context, themeName) {
|
||||
var deferred = $.Deferred();
|
||||
|
||||
if (typeof (themeName) === "undefined") {
|
||||
// System context by default.
|
||||
themeName = config.theme;
|
||||
}
|
||||
|
||||
this.currentThemeName = themeName;
|
||||
|
||||
var loadTemplate = this.getTemplate(templateName, true);
|
||||
|
||||
loadTemplate.done(
|
||||
function(templateSource) {
|
||||
var renderPromise = this.doRender(templateSource, context, themeName);
|
||||
|
||||
renderPromise.done(
|
||||
function(result, js) {
|
||||
deferred.resolve(result, js);
|
||||
}
|
||||
).fail(
|
||||
function(ex) {
|
||||
deferred.reject(ex);
|
||||
}
|
||||
);
|
||||
}.bind(this)
|
||||
).fail(
|
||||
function(ex) {
|
||||
deferred.reject(ex);
|
||||
}
|
||||
);
|
||||
return deferred.promise();
|
||||
};
|
||||
|
||||
|
||||
return /** @alias module:core/templates */ {
|
||||
// Public variables and functions.
|
||||
/**
|
||||
* Load a template and call doRender on it.
|
||||
* Every call to render creates a new instance of the class and calls render on it. This
|
||||
* means each render call has it's own class variables.
|
||||
*
|
||||
* @method render
|
||||
* @private
|
||||
@@ -475,37 +545,8 @@ define([ 'core/mustache',
|
||||
* @return {Promise} JQuery promise object resolved when the template has been rendered.
|
||||
*/
|
||||
render: function(templateName, context, themeName) {
|
||||
var deferred = $.Deferred();
|
||||
|
||||
if (typeof (themeName) === "undefined") {
|
||||
// System context by default.
|
||||
themeName = config.theme;
|
||||
}
|
||||
|
||||
currentThemeName = themeName;
|
||||
|
||||
var loadTemplate = getTemplate(templateName, true);
|
||||
|
||||
loadTemplate.done(
|
||||
function(templateSource) {
|
||||
var renderPromise = doRender(templateSource, context, themeName);
|
||||
|
||||
renderPromise.done(
|
||||
function(result, js) {
|
||||
deferred.resolve(result, js);
|
||||
}
|
||||
).fail(
|
||||
function(ex) {
|
||||
deferred.reject(ex);
|
||||
}
|
||||
);
|
||||
}
|
||||
).fail(
|
||||
function(ex) {
|
||||
deferred.reject(ex);
|
||||
}
|
||||
);
|
||||
return deferred.promise();
|
||||
var renderer = new Renderer();
|
||||
return renderer.render(templateName, context, themeName);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user