Merge branch 'MDL-54915-30' of http://github.com/damyon/moodle into MOODLE_30_STABLE

This commit is contained in:
Dan Poltawski
2016-07-19 09:39:09 +01:00
2 changed files with 289 additions and 181 deletions
+1 -1
View File
@@ -1 +1 @@
define(["core/mustache","jquery","core/ajax","core/str","core/notification","core/url","core/config","core/localstorage","core/event"],function(a,b,c,d,e,f,g,h,i){var j={},k=[],l=[],m=1,n="",o=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 k=f.imageUrl(g,h),l={attributes:[{name:"src",value:k},{name:"alt",value:c(i)},{name:"class",value:"smallicon"}]},m=j[n+"/core/pix_icon"];return d=a.render(m,l,p),d.trim()},p=function(a){var b="";return w(a,!1).done(function(a){b=a}).fail(e.exception),b},q=function(a,b){return l.push(b(a,this)),""},r=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=k.length;return k.push({key:d,component:e,param:f}),"{{_s"+g+"}}"},s=function(a,b){var c=b(a.trim(),this);return c=c.replace('"','\\"').replace(/([\{\}]{2,3})/g,"{{=<% %>=}}$1<%={{ }}=%>"),'"'+c+'"'},t=function(a,b){n=b,k=[],l=[],a.uniqid=m++,a.str=function(){return r},a.pix=function(){return o},a.js=function(){return q},a.quote=function(){return s},a.globals={config:g},a.currentTheme=b},u=function(a){var b="";l.length>0&&(b=l.join(";\n"));var c=0;for(c=0;c<a.length;c++)b=b.replace("{{_s"+c+"}}",a[c]);return b},v=function(c,e,f){var g=b.Deferred();n=f;var h=w("core/pix_icon",!0);return h.done(function(){t(e,f);var b="";try{b=a.render(c,e,p)}catch(h){g.reject(h)}k.length>0?d.get_strings(k).done(function(a){var c;for(c=0;c<a.length;c++)b=b.replace("{{_s"+c+"}}",a[c]);g.resolve(b.trim(),u(a))}).fail(function(a){g.reject(a)}):g.resolve(b.trim(),u([]))}).fail(function(a){g.reject(a)}),g.promise()},w=function(a,d){var e=b.Deferred(),f=a.split("/"),g=f.shift(),i=f.shift(),k=n+"/"+a;if(k in j)return e.resolve(j[k]),e.promise();var l=h.get("core_template/"+k);if(l)return e.resolve(l),j[k]=l,e.promise();var m=c.call([{methodname:"core_output_load_template",args:{component:g,template:i,themename:n}}],d,!1);return m[0].done(function(a){h.set("core_template/"+k,a),j[k]=a,e.resolve(a)}).fail(function(a){e.reject(a)}),e.promise()},x=function(a){if(""!==a.trim()){var c=b("<script>").attr("type","text/javascript").html(a);b("head").append(c)}},y=function(a,c,d,e){var f=b(a);if(f.length){var g=b(c);e?(f.empty(),f.append(g)):f.replaceWith(g),x(d),i.notifyFilterContentUpdated(g)}};return{render:function(a,c,d){var e=b.Deferred();"undefined"==typeof d&&(d=g.theme),n=d;var f=w(a,!0);return f.done(function(a){var b=v(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:x,replaceNodeContents:function(a,b,c){return y(a,b,c,!0)},replaceNode:function(a,b,c){return y(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)}}});
+288 -180
View File
@@ -31,37 +31,128 @@ define([ 'core/mustache',
'core/url',
'core/config',
'core/localstorage',
'core/event'
'core/event',
'core/yui',
'core/log'
],
function(mustache, $, ajax, str, notification, coreurl, config, storage, event) {
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.
*
* @method getTemplate
* @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)
* @return {Promise} JQuery promise object resolved when the template has been fetched.
*/
Renderer.prototype.getTemplate = function(templateName, async) {
var deferred = $.Deferred();
var parts = templateName.split('/');
var component = parts.shift();
var name = parts.shift();
var searchKey = this.currentThemeName + '/' + templateName;
// First try request variables.
if (searchKey in templateCache) {
deferred.resolve(templateCache[searchKey]);
return deferred.promise();
}
// Now try local storage.
var cached = storage.get('core_template/' + searchKey);
if (cached) {
deferred.resolve(cached);
templateCache[searchKey] = cached;
return deferred.promise();
}
// Oh well - load via ajax.
var promises = ajax.call([{
methodname: 'core_output_load_template',
args:{
component: component,
template: name,
themename: this.currentThemeName
}
}], async, false);
promises[0].done(
function (templateSource) {
storage.set('core_template/' + searchKey, templateSource);
templateCache[searchKey] = templateSource;
deferred.resolve(templateSource);
}
).fail(
function (ex) {
deferred.reject(ex);
}
);
return deferred.promise();
};
/**
* Load a partial from the cache or ajax.
*
* @method partialHelper
* @private
* @param {string} name The partial name to load.
* @return {string}
*/
Renderer.prototype.partialHelper = function(name) {
var template = '';
this.getTemplate(name, false).done(
function(source) {
template = source;
}
).fail(notification.exception);
return template;
};
/**
* Render image icons.
*
* @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 = '';
@@ -87,42 +178,23 @@ 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();
};
/**
* Load a partial from the cache or ajax.
*
* @method partialHelper
* @private
* @param {string} name The partial name to load.
* @return {string}
*/
var partialHelper = function(name) {
var template = '';
getTemplate(name, false).done(
function(source) {
template = source;
}
).fail(notification.exception);
return template;
};
/**
* Render blocks of javascript and save them in an array.
*
* @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 '';
};
@@ -132,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 = '';
@@ -153,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 + '}}';
};
@@ -170,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.
@@ -195,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;
};
@@ -216,19 +298,83 @@ 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");
}
var i = 0;
for (i = 0; i < strings.length; i++) {
js = js.replace('{{_s' + i + '}}', strings[i]);
}
// Re-render to get the final strings.
return js;
return this.treatStringsInContent(js, strings);
};
/**
* Treat strings in content.
*
* The purpose of this method is to replace the placeholders found in a string
* with the their respective translated strings.
*
* Previously we were relying on String.replace() but the complexity increased with
* the numbers of strings to replace. Now we manually walk the string and stop at each
* placeholder we find, only then we replace it. Most of the time we will
* replace all the placeholders in a single run, at times we will need a few
* more runs when placeholders are replaced with strings that contain placeholders
* themselves.
*
* @param {String} content The content in which string placeholders are to be found.
* @param {Array} strings The strings to replace with.
* @return {String} The treated content.
*/
Renderer.prototype.treatStringsInContent = function(content, strings) {
var pattern = /{{_s\d+}}/,
treated,
index,
strIndex,
walker,
char,
strFinal;
do {
treated = '';
index = content.search(pattern);
while (index > -1) {
// Copy the part prior to the placeholder to the treated string.
treated += content.substring(0, index);
content = content.substr(index);
strIndex = '';
walker = 4; // 4 is the length of '{{_s'.
// Walk the characters to manually extract the index of the string from the placeholder.
char = content.substr(walker, 1);
do {
strIndex += char;
walker++;
char = content.substr(walker, 1);
} while (char != '}');
// Get the string, add it to the treated result, and remove the placeholder from the content to treat.
strFinal = strings[parseInt(strIndex, 10)];
if (typeof strFinal === 'undefined') {
Log.debug('Could not find string for pattern {{_s' + strIndex + '}}.');
strFinal = '';
}
treated += strFinal;
content = content.substr(6 + strIndex.length); // 6 is the length of the placeholder without the index: '{{_s}}'.
// Find the next placeholder.
index = content.search(pattern);
}
// The content becomes the treated part with the rest of the content.
content = treated + content;
// Check if we need to walk the content again, in case strings contained placeholders.
index = content.search(pattern);
} while (index > -1);
return content;
};
/**
@@ -241,111 +387,44 @@ 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).done(
function(strings) {
var i;
if (this.requiredStrings.length > 0) {
str.get_strings(this.requiredStrings)
.then(function(strings) {
// Why do we not do another call the render here?
//
// Because that would expose DOS holes. E.g.
// I create an assignment called "{{fish" which
// would get inserted in the template in the first pass
// and cause the template to die on the second pass (unbalanced).
for (i = 0; i < strings.length; i++) {
result = result.replace('{{_s' + i + '}}', strings[i]);
}
deferred.resolve(result.trim(), getJS(strings));
}
).fail(
function(ex) {
deferred.reject(ex);
}
);
// Why do we not do another call the render here?
//
// Because that would expose DOS holes. E.g.
// I create an assignment called "{{fish" which
// would get inserted in the template in the first pass
// and cause the template to die on the second pass (unbalanced).
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([]));
}
}
).fail(
function(ex) {
deferred.reject(ex);
}
);
return deferred.promise();
};
/**
* Load a template from the cache or local storage or ajax request.
*
* @method getTemplate
* @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)
* @return {Promise} JQuery promise object resolved when the template has been fetched.
*/
var getTemplate = function(templateName, async) {
var deferred = $.Deferred();
var parts = templateName.split('/');
var component = parts.shift();
var name = parts.shift();
var searchKey = currentThemeName + '/' + templateName;
// First try request variables.
if (searchKey in templateCache) {
deferred.resolve(templateCache[searchKey]);
return deferred.promise();
}
// Now try local storage.
var cached = storage.get('core_template/' + searchKey);
if (cached) {
deferred.resolve(cached);
templateCache[searchKey] = cached;
return deferred.promise();
}
// Oh well - load via ajax.
var promises = ajax.call([{
methodname: 'core_output_load_template',
args:{
component: component,
template: name,
themename: currentThemeName
}
}], async, false);
promises[0].done(
function (templateSource) {
storage.set('core_template/' + searchKey, templateSource);
templateCache[searchKey] = templateSource;
deferred.resolve(templateSource);
}
).fail(
function (ex) {
deferred.reject(ex);
}
);
}.bind(this)
).fail(deferred.reject);
return deferred.promise();
};
@@ -378,11 +457,22 @@ define([ 'core/mustache',
if (replaceNode.length) {
// First create the dom nodes so we have a reference to them.
var newNodes = $(newHTML);
var yuiNodes = null;
// Do the replacement in the page.
if (replaceChildNodes) {
// Cleanup any YUI event listeners attached to any of these nodes.
yuiNodes = new Y.NodeList(replaceNode.children().get());
yuiNodes.destroy(true);
// JQuery will cleanup after itself.
replaceNode.empty();
replaceNode.append(newNodes);
} else {
// Cleanup any YUI event listeners attached to any of these nodes.
yuiNodes = new Y.NodeList(replaceNode.get());
yuiNodes.destroy(true);
// JQuery will cleanup after itself.
replaceNode.replaceWith(newNodes);
}
// Run any javascript associated with the new HTML.
@@ -392,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
@@ -408,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);
},
/**