Skip to content

Commit

Permalink
consolidating application.json->viewEngine->cacheTemplates as a stati…
Browse files Browse the repository at this point in the history
…c config across the board. Adding support for preloadTemplates for HB client and server to avoid loading the template if is is part of the expanded instance. Adding support for partials on hb client and server.
  • Loading branch information
caridy committed Oct 30, 2012
1 parent 374826d commit 9a40739
Show file tree
Hide file tree
Showing 4 changed files with 240 additions and 79 deletions.
123 changes: 95 additions & 28 deletions lib/app/addons/view-engines/hb.client.js
Expand Up @@ -16,25 +16,30 @@ YUI.add('mojito-hb', function(Y, NAME) {
cache = Y.namespace('Env.Mojito.Handlebars');

/**
* Class text.
* @class HandleBarsAdapterServer
* HandlerBars Adapter for the client runtime.
* @class HandleBarsAdapterClient
* @constructor
* @param {object} options View engine configuration.
* @private
*/
function HandleBarsAdapter() {}
function HandleBarsAdapter(options) {
this.options = options || {};
}

HandleBarsAdapter.prototype = {

/**
* Renders the handlebars template using the data provided.
* @param {object} data The data to render.
* @param {string} mojitType The name of the mojit type.
* @param {string} tmpl The name of the template to render.
* @param {object} instance The expanded mojit instance.
* @param {object} template The view object from RS to render with format:
* {'content-path': 'path to view', content: 'cached string'}.
* @param {object} adapter The output adapter to use.
* @param {object} meta Optional metadata.
* @param {boolean} more Whether there is more to be rendered
*/
render: function (data, mojitType, tmpl, adapter, meta, more) {
var cacheTemplates = meta && meta.view && meta.view.cacheTemplates,
render: function (data, instance, template, adapter, meta, more) {
var cacheTemplates = (this.options.cacheTemplates === false ? false : true),
handler = function (err, obj) {
var output;

Expand All @@ -43,44 +48,106 @@ YUI.add('mojito-hb', function(Y, NAME) {
return;
}

output = obj.compiled(data);
output = obj.compiled(data, {
partials: obj.partials
});

if (more) {
adapter.flush(output, meta);
} else {
adapter.done(output, meta);
}
},
stack,
cacheKey,
fn,
partial,
partials;

// support for legacy url instead of a view object
if (Y.Lang.isString(template)) {
Y.log('[view] argument in [render] method should be an object', 'warn', NAME);
template = {
'content-path': template
};
}

this._getTemplateObj(tmpl, !cacheTemplates, handler);
},
cacheKey = template['content-path'];

/**
* Cache the reference to a compiled handlebar template, plus
* a raw string representation of the template.
* @private
* @param {string} tmpl The name of the template to render.
* @param {boolean} bypassCache Whether or not we should rely on the cached content.
* @param {function} callback The function that is called with the compiled template
* @return {object} literal object with the "raw" and "template" references.
*/
_getTemplateObj: function (tmpl, bypassCache, callback) {
if (cache[tmpl] && !bypassCache) {
callback(null, cache[tmpl]);
if (cacheTemplates && cache[cacheKey]) {
handler(null, cache[cacheKey]);
return;
}

this._loadTemplate(tmpl, function (err, str) {
stack = new Y.Parallel();
partials = {};

// first item in the asyc queue is the actual view
this._getTemplateObj(template, stack.add(function (err, obj) {
if (err) {
callback(err);
Y.log('Error trying to compile view ' + cacheKey, 'error', NAME);
Y.log(err, 'error', NAME);
return;
}
cache[tmpl] = {
raw: str,
compiled: HB.compile(str)
cache[cacheKey] = obj;
}));

// after the first item, we just add any partial
if (instance && instance.partials && Y.Object.keys(instance.partials).length > 0) {
fn = function (partial, err, obj) {
if (err) {
Y.log('Error trying to compile partial [' + partial + '] on view ' +
cacheKey, 'error', NAME);
Y.log(err, 'error', NAME);
return;
}
partials[partial] = obj.compiled;
};
callback(null, cache[tmpl]);
for (partial in instance.partials) {
if (instance.partials.hasOwnProperty(partial)) {
this._getTemplateObj(instance.partials[partial],
stack.add(Y.bind(fn, this, partial)));
}
}
}

// finally, let's just put the compiled view and partials together
stack.done(function () {
if (!cache[cacheKey]) {
handler(new Error("Error trying to render view " + cacheKey));
return;
}
cache[cacheKey].partials = partials;
handler(null, cache[cacheKey]);
});

},

/**
* Build a compiled handlebar template, plus
* a raw string representation of the template.
* @private
* @param {object} template The view object from RS to render with format:
* {'content-path': 'path to view', content: 'cached string'}.
* @param {function} callback The function that is called with the compiled template
* @return {object} literal object with the "raw" and "template" references.
*/
_getTemplateObj: function (template, callback) {
var fn = function (err, str) {
if (err) {
callback(err);
return;
}
callback(null, {
raw: str,
compiled: HB.compile(str)
});
};
if (template.content) {
fn(null, template.content);
} else {
this._loadTemplate(template['content-path'], fn);
}
},

/**
Expand Down
132 changes: 98 additions & 34 deletions lib/app/addons/view-engines/hb.server.js
Expand Up @@ -9,7 +9,7 @@
/*global YUI*/


YUI.add('mojito-hb', function(Y, NAME) {
YUI.add('mojito-hb', function (Y, NAME) {

'use strict';

Expand All @@ -18,49 +18,115 @@ YUI.add('mojito-hb', function(Y, NAME) {
cache = YUI.namespace('Env.Mojito.Handlebars');

/**
* Class text.
* HandlerBars Adapter for the server runtime.
* @class HandleBarsAdapterServer
* @constructor
* @param {object} options View engine configuration.
* @private
*/
function HandleBarsAdapter(viewId) {
this.viewId = viewId;
function HandleBarsAdapter(options) {
this.options = options || {};
}

HandleBarsAdapter.prototype = {

/**
* Renders the handlebars template using the data provided.
* @param {object} data The data to render.
* @param {string} mojitType The name of the mojit type.
* @param {string} tmpl The name of the template to render.
* @param {object} instance The expanded mojit instance.
* @param {object} template The view object from RS to render with format:
* {'content-path': 'path to view', content: 'cached string'}.
* @param {object} adapter The output adapter to use.
* @param {object} meta Optional metadata.
* @param {boolean} more Whether there is more to be rendered
*/
render: function (data, mojitType, tmpl, adapter, meta, more) {
var cacheTemplates = meta && meta.view && meta.view.cacheTemplates,
render: function (data, instance, template, adapter, meta, more) {
var cacheTemplates = (this.options.cacheTemplates === false ? false : true),
perf = Y.mojito.perf.timeline('mojito', 'hb:render',
'time to render a template', tmpl),
'time to render a template', {instance: instance}),
handler = function (err, obj) {
var output;

perf.done(); // closing the 'hb:render' timeline

if (err) {
adapter.error(err);
return;
}

output = obj.compiled(data);

perf.done(); // closing the 'hb:render' timeline
output = obj.compiled(data, {
partials: obj.partials
});

if (more) {
adapter.flush(output, meta);
} else {
adapter.done(output, meta);
}
},
stack,
cacheKey,
fn,
partial,
partials;

// support for legacy url instead of a view object
if (Y.Lang.isString(template)) {
Y.log('[view] argument in [render] method should be an object', 'warn', NAME);
template = {
'content-path': template
};
}

cacheKey = template['content-path'];

if (cacheTemplates && cache[cacheKey]) {
handler(null, cache[cacheKey]);
return;
}

stack = new Y.Parallel();
partials = {};

// first item in the asyc queue is the actual view
this._getTemplateObj(template, stack.add(function (err, obj) {
if (err) {
Y.log('Error trying to compile view ' + cacheKey, 'error', NAME);
Y.log(err, 'error', NAME);
return;
}
cache[cacheKey] = obj;
}));

// after the first item, we just add any partial
if (instance && instance.partials && Y.Object.keys(instance.partials).length > 0) {
fn = function (partial, err, obj) {
if (err) {
Y.log('Error trying to compile partial [' + partial + '] on view ' +
cacheKey, 'error', NAME);
Y.log(err, 'error', NAME);
return;
}
partials[partial] = obj.compiled;
};
for (partial in instance.partials) {
if (instance.partials.hasOwnProperty(partial)) {
this._getTemplateObj(instance.partials[partial],
stack.add(Y.bind(fn, this, partial)));
}
}
}

// finally, let's just put the compiled view and partials together
stack.done(function () {
if (!cache[cacheKey]) {
handler(new Error("Error trying to render view " + cacheKey));
return;
}
cache[cacheKey].partials = partials;
handler(null, cache[cacheKey]);
});

this._getTemplateObj(tmpl, !cacheTemplates, handler);
},

/**
Expand All @@ -87,30 +153,29 @@ YUI.add('mojito-hb', function(Y, NAME) {
},

/**
* Cache the reference to a compiled handlebar template, plus
* Build a compiled handlebar template, plus
* a raw string representation of the template.
* @private
* @param {string} tmpl The name of the template to render.
* @param {boolean} bypassCache Whether or not we should rely on the cached content.
* @param {object} template The view object from RS to render with format:
* {'content-path': 'path to view', content: 'cached string'}.
* @param {function} callback The function that is called with the compiled template
*/
_getTemplateObj: function (tmpl, bypassCache, callback) {
if (cache[tmpl] && !bypassCache) {
callback(null, cache[tmpl]);
return;
}

this._loadTemplate(tmpl, function (err, str) {
if (err) {
callback(err);
return;
}
cache[tmpl] = {
raw: str,
compiled: HB.compile(str)
_getTemplateObj: function (template, callback) {
var fn = function (err, str) {
if (err) {
callback(err);
return;
}
callback(null, {
raw: str,
compiled: HB.compile(str)
});
};
callback(null, cache[tmpl]);
});
if (template.content) {
fn(null, template.content);
} else {
this._loadTemplate(template['content-path'], fn);
}
},

/**
Expand All @@ -128,5 +193,4 @@ YUI.add('mojito-hb', function(Y, NAME) {

Y.namespace('mojito.addons.viewEngines').hb = HandleBarsAdapter;

}, '0.1.0', {requires: [
'mojito-perf']});
}, '0.1.0', {requires: ['parallel']});

0 comments on commit 9a40739

Please sign in to comment.