Skip to content

Adding support for handlebar partials #683

Closed
wants to merge 12 commits into from
+354 −161
View
1 lib/app/addons/ac/composite.common.js
@@ -338,7 +338,6 @@ callback({
}, '0.1.0', {requires: [
'mojito',
'mojito-util',
- 'mojito-perf',
'mojito-assets-addon',
'mojito-params-addon'
]});
View
72 lib/app/addons/ac/models.common.js
@@ -4,6 +4,7 @@
* See the accompanying LICENSE file for terms.
*/
+/*jslint nomen:true*/
/*global YUI*/
/**
@@ -13,6 +14,8 @@ YUI.add('mojito-models-addon', function (Y, NAME) {
'use strict';
+ var _clientCache = {};
+
// TODO:
// - update tests
// - update fixtures
@@ -24,52 +27,79 @@ YUI.add('mojito-models-addon', function (Y, NAME) {
* Addon that provides access to the models collection
* @class Models.common
*/
- function Addon(command) {
+ function Addon(command, adapter) {
+ this._models = {};
+ this._adapter = adapter;
+ this._instance = command.instance;
+ }
+
+ Addon.prototype = {
- var models = {};
+ namespace: 'models',
/**
* Gets model instance
* @method get
* @param {string} modelName The name of the model.
* @return {object} model instance, or null.
*/
- // this is an experiment where "get" method uses the closure
- // rather than be directly attached, to avoid storing
- // a instance.config or models reference in the addon instance.
- this.get = Y.bind(function (config, modelName) {
+ get: function (modelName) {
- var modelInstance;
+ var model = this._models[modelName] ||
+ (this._adapter.req && this._adapter.req.models &&
+ this._adapter.req.models[modelName]);
// instantanting the model once during the lifetime of
// the ac object, this acts like an internal cache.
- if (Y.mojito.models[modelName] && !models[modelName]) {
+ if (!model) {
// We have to heir() otherwise this.something in the model
// will pollute other instances of the model.
- modelInstance = Y.mojito.util.heir(Y.mojito.models[modelName]);
+ model = Y.mojito.util.heir(Y.mojito.models[modelName]);
- if (Y.Lang.isFunction(modelInstance.init)) {
+ if (Y.Lang.isFunction(model.init)) {
// NOTE that we use the same config here that we use to
// config the controller
- modelInstance.init(config);
+ model.init(this.instance.config);
}
- models[modelName] = modelInstance;
+ this._models[modelName] = model;
}
// returning from cache if exists
- return models[modelName];
-
- }, this,
- command.instance.config /* config (first arg) */
- );
-
- }
+ return model;
- Addon.prototype = {
+ },
- namespace: 'models'
+ /**
+ * Set a model instance as global. On the server side
+ * this means any mojit instance under a particular request
+ * will have access to the model. On the client, any
+ * mojit instance on the page will have access to
+ * the model as well.
+ * @method get
+ * @param {string} name The model name.
+ * @param {object} model The model instance
+ */
+ registerGlobal: function (name, model) {
+ if (this._adapter.req) {
+ // server side routine to store on the request
+ // to avoid leaks.
+ // NOTE: models on req object will be destroyed
+ // with the request lifecycle.
+ this._adapter.req.models = this._adapter.req.models || {};
+ this._adapter.req.models[name] = model;
+ Y.log('Storing a global model on the server: ' + name, 'info', NAME);
+ } else {
+ // client side routine to store on a global
+ // cache structure.
+ // NOTE: there is no way to destroy this model at
+ // the moment, it is now tied to the page
+ // life cycle.
+ _clientCache[name] = model;
+ Y.log('Storing a global model on the client: ' + name, 'info', NAME);
+ }
+ }
};
View
3 lib/app/addons/ac/partial.common.js
@@ -54,7 +54,8 @@ YUI.add('mojito-partial-addon', function(Y, NAME) {
mojitView = instance.views[view];
data = data || {}; // default null data to empty view template
- renderer = new Y.mojito.ViewRenderer(mojitView.engine);
+ renderer = Y.mojito.ViewRenderer(mojitView.engine,
+ this.ac.staticAppConfig.viewEngine);
Y.log('Rendering "' + view + '" view for "' + (instance.id || '@' +
instance.type) + '"', 'debug', NAME);
View
123 lib/app/addons/view-engines/hb.client.js
@@ -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;
@@ -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);
+ }
},
/**
View
132 lib/app/addons/view-engines/hb.server.js
@@ -9,7 +9,7 @@
/*global YUI*/
-YUI.add('mojito-hb', function(Y, NAME) {
+YUI.add('mojito-hb', function (Y, NAME) {
'use strict';
@@ -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);
},
/**
@@ -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);
+ }
},
/**
@@ -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']});
View
34 lib/app/addons/view-engines/mu.client.js
@@ -375,29 +375,47 @@ YUI.add('mojito-mu', function(Y, NAME) {
/**
- * Class text.
+ * Mustache Adapter for Client runtime.
* @class MuAdapterClient
+ * @constructor
+ * @param {object} options View engine configuration.
* @private
*/
- function MuAdapter() {}
+ function MuAdapter(options) {
+ this.options = options || {};
+ }
/**
* Renders the mustache 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|string} instance The expanded mojit instance or the instance type.
+ * @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 will be more content later.
*/
- MuAdapter.prototype.render = function(data,
- mojitType, tmpl, adapter, meta, more) {
+ MuAdapter.prototype.render = function(data, instance, template, adapter, meta, more) {
- var handler,
+ var cacheTemplates = (this.options.cacheTemplates === false ? false : true),
+ handler,
useCompiled = true,
handlerArgs,
- ns = mojitType.replace(/\./g, '_');
+ ns = ((instance && instance.type) || instance).replace(/\./g, '_'),
+ tmpl;
+
+
+ // 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
+ };
+ }
+ tmpl = template['content-path'];
+
+ // TODO: use cacheTemplates to avoid caching
handler = function(id, obj) {
var i,
View
30 lib/app/addons/view-engines/mu.server.js
@@ -19,12 +19,13 @@ YUI.add('mojito-mu', function(Y, NAME) {
/**
- * Class text.
+ * Mustache Adapter for the server runtime.
* @class MuAdapterServer
+ * @constructor
+ * @param {object} options View engine configuration.
* @private
*/
- function MuAdapter(viewId, options) {
- this.viewId = viewId;
+ function MuAdapter(options) {
this.options = options || {};
}
@@ -35,14 +36,16 @@ YUI.add('mojito-mu', function(Y, NAME) {
* Renders the mustache template using the data provided.
* @method render
* @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 will be more content later.
*/
- render: function(data, mojitType, tmpl, adapter, meta, more) {
- var me = this,
+ render: function(data, instance, template, adapter, meta, more) {
+ var cacheTemplates = (this.options.cacheTemplates === false ? false : true),
+ me = this,
buffer = '',
bufferOutput = (this.options.mu && this.options.mu.bufferOutput) || false,
handleRender = function(err, output) {
@@ -70,15 +73,24 @@ YUI.add('mojito-mu', function(Y, NAME) {
}
}
});
+ },
+ tmpl;
+
+ // 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
};
-
+ }
+ tmpl = template['content-path'];
/*
* We can't use pre-compiled Mu templates on the server :(
*/
// If we don't have a compliled template, make one.
Y.log('Rendering template "' + tmpl + '"', 'mojito', NAME);
- mu.render(tmpl, data, {cached: meta.view.cacheTemplates},
+ mu.render(tmpl, data, {cached: cacheTemplates},
handleRender);
},
View
47 lib/app/autoload/action-context.common.js
@@ -282,7 +282,6 @@ YUI.add('mojito-action-context', function(Y, NAME) {
actionFunction,
perf = Y.mojito.perf.timeline('mojito', 'ac:init', 'set up AC object', command),
error,
- staticAppConfig = store.getAppConfig(store.getStaticContext()),
my;
my = this;
@@ -304,13 +303,8 @@ YUI.add('mojito-action-context', function(Y, NAME) {
this.instance = command.instance;
this._adapter = opts.adapter;
- // in here we should whitelist the stuff we need
- this.staticAppConfig = {
- actionTimeout: staticAppConfig.actionTimeout,
- pathToRoot: staticAppConfig.pathToRoot,
- cacheViewTemplates: staticAppConfig.cacheViewTemplates,
- viewEngineOptions: staticAppConfig.viewEngine
- };
+ // pathToRoot, viewEngine, amoung others will be available through this.
+ this.staticAppConfig = store.getAppConfig(store.getStaticContext());
// Create a function which will properly delegate to the dispatcher to
// perform the actual processing.
@@ -404,12 +398,6 @@ YUI.add('mojito-action-context', function(Y, NAME) {
mojitView,
renderer = null,
contentType,
- contentPath,
-
- // static app configuration options
- pathToRoot = this.staticAppConfig.pathToRoot,
- cacheViewTemplates = this.staticAppConfig.cacheViewTemplates,
- viewEngineOptions = this.staticAppConfig.viewEngine || {},
perf = Y.mojito.perf.timeline('mojito', 'ac.done',
'time to execute ac.done process', this.command);
@@ -436,9 +424,6 @@ YUI.add('mojito-action-context', function(Y, NAME) {
meta.http.headers = meta.http.headers || {};
meta.view = meta.view || {};
- // Cache all templates by default
- meta.view.cacheTemplates = (cacheViewTemplates === false ? false : true);
-
// Check to see we need to serialize the data
if (meta.serialize && serializer[meta.serialize]) {
// Warning: this metod can change the "meta" object
@@ -549,30 +534,10 @@ YUI.add('mojito-action-context', function(Y, NAME) {
// Y.log('Rendering "' + meta.view.name + '" view for "' +
// (instance.id || '@' + instance.type) + '"', 'info', NAME);
- contentPath = mojitView['content-path'];
- // this is mainly used by html5app
- if (pathToRoot) {
- contentPath = pathToRoot + contentPath;
- }
-
- // optimize for server only
- if ('server' === context.runtime) {
- renderer = CACHE.renderers[mojitView.engine];
- if (!renderer) {
- // viewEngineOptions are app level
- CACHE.renderers[mojitView.engine] = renderer =
- new (Y.mojito.addons.viewEngines[mojitView.engine])('', viewEngineOptions);
- }
- renderer.viewId = meta.view.id;
- renderer.render(data, instance.type, contentPath, adapter, meta, more);
- } else {
- renderer = new Y.mojito.ViewRenderer(
- mojitView.engine,
- meta.view.id,
- viewEngineOptions
- );
- renderer.render(data, instance.type, contentPath, adapter, meta, more);
- }
+ // we use the view renderer factory
+ // because it provides caching capabilities for better performance
+ renderer = Y.mojito.ViewRenderer(mojitView.engine, this.staticAppConfig.viewEngine);
+ renderer.render(data, instance, mojitView, adapter, meta, more);
} else {
View
4 lib/app/autoload/dispatch.client.js
@@ -213,6 +213,10 @@ YUI.add('mojito-dispatcher', function (Y, NAME) {
Y.log('Cannot expand instance "' + (command.instance.base || '@' +
command.instance.type) + '". Trying with the tunnel in case ' +
'it is a remote mojit.', 'info', NAME);
+ if (err) {
+ // logging the error
+ Y.log(err, 'warn', NAME);
+ }
my.rpc(command, adapter);
return;
View
10 lib/app/autoload/mojito-client.client.js
@@ -57,7 +57,7 @@ YUI.add('mojito-client', function(Y, NAME) {
// this is the heart of mojitProxy.render(), but it needs to be a separate
// function called once we have mojit type details
- function privateRender(mp, data, view, cb) {
+ function privateRender(mp, data, view, viewEngine, cb) {
var mojitView,
renderer;
@@ -71,7 +71,8 @@ YUI.add('mojito-client', function(Y, NAME) {
data.mojit_assets = data.mojit_assets || mp._assetsRoot;
mojitView = mp._views[view];
- renderer = new Y.mojito.ViewRenderer(mojitView.engine);
+ renderer = Y.mojito.ViewRenderer(mojitView.engine, viewEngine);
+
Y.log('Rendering "' + view + '" in Binder', 'debug', NAME);
renderer.render(data, mp.type, mojitView['content-path'], {
buffer: '',
@@ -631,6 +632,7 @@ YUI.add('mojito-client', function(Y, NAME) {
doRender: function(mp, data, view, cb) {
+ var viewEngine = this.appConfig.viewEngine;
if (!mp._views || !mp._assetsRoot) {
this.resourceStore.expandInstance({type: mp.type}, mp.context,
function(err, typeInfo) {
@@ -643,10 +645,10 @@ YUI.add('mojito-client', function(Y, NAME) {
}
mp._views = typeInfo.views;
mp._assetsRoot = typeInfo.assetsRoot;
- privateRender(mp, data, view, cb);
+ privateRender(mp, data, view, viewEngine, cb);
});
} else {
- privateRender(mp, data, view, cb);
+ privateRender(mp, data, view, viewEngine, cb);
}
},
View
35 lib/app/autoload/store.server.js
@@ -622,9 +622,11 @@ YUI.add('mojito-resource-store', function(Y, NAME) {
var ress,
r,
res,
+ template,
engine,
engines = {}, // view engines
posl = this.selector.getPOSLFromContext(ctx),
+ staticAppConfig = this.getStaticAppConfig(),
ctxKey,
module;
@@ -648,6 +650,9 @@ YUI.add('mojito-resource-store', function(Y, NAME) {
if (!dest.models) {
dest.models = {};
}
+ if (!dest.partials) {
+ dest.partials = {};
+ }
if (!dest.views) {
dest.views = {};
}
@@ -696,16 +701,23 @@ YUI.add('mojito-resource-store', function(Y, NAME) {
}
if (res.type === 'view') {
- if (!dest.views[res.name]) {
- dest.views[res.name] = {};
- }
- if (env === 'client') {
- dest.views[res.name]['content-path'] = res.url;
+ template = {
+ 'content-path': (env === 'client' ?
+ this._libs.path.join(staticAppConfig.pathToRoot || '', res.url) :
+ res.source.fs.fullPath),
+ 'content': res.content,
+ 'engine': res.view.engine
+ };
+ // we want to separate partials from actual templates
+ // in case the engine supports partials
+ if (res.name.indexOf('partials/') === 0) {
+ // removing the "partials/" prefix
+ dest.partials[libs.path.basename(res.name)] = template;
} else {
- dest.views[res.name]['content-path'] = res.source.fs.fullPath;
+ dest.views[res.name] = template;
+ dest.views[res.name].assets = res.view.assets;
+ dest.views[res.name].engine = res.view.engine;
}
- dest.views[res.name].assets = res.view.assets;
- dest.views[res.name].engine = res.view.engine;
engines[res.view.engine] = true;
}
}
@@ -1381,6 +1393,13 @@ YUI.add('mojito-resource-store', function(Y, NAME) {
}
res.name = this._libs.path.join(fs.subDirArray.join('/'), baseParts.join('.'));
res.id = [res.type, res.subtype, res.name].join('-');
+ // for performance reasons, we might want to preload all
+ // views in memory, for that, we can use:
+ // application.json->viewEngine->preloadTemplates
+ // TODO: should this be set to true by default?
+ if (this._appConfigStatic.viewEngine && this._appConfigStatic.viewEngine.preloadTemplates) {
+ res.content = this._libs.fs.readFileSync(source.fs.fullPath, 'utf8');
+ }
return res;
}
View
24 lib/app/autoload/view-renderer.common.js
@@ -11,19 +11,30 @@
YUI.add('mojito-view-renderer', function(Y) {
+
+ var cache = {};
+
+
/*
* Mojito's view renderer abstraction. Will plugin in the specified view
- * plugin to do the rendering, depending on the 'type' specified.
+ * plugin to do the rendering, depending on the 'type' specified. This Class
+ * can also be used as a factory to avoid creating renderer objects, and to
+ * do so, you just need to call `Y.mojito.ViewRenderer('hb', {});` and it will
+ * return the cached engine instead of creating a facade for it.
* @class ViewRenderer
- * @namespace Y.mojit
+ * @namespace Y.mojito
* @constructor
* @param {String} type view engine addon type to use
- * @param {String} viewId
- * @param {Object} options
+ * @param {Object} options View engines configuration.
*/
- function Renderer(type, viewId, options) {
+ function Renderer(type, options) {
type = type || 'hb';
- this._renderer = new (Y.mojito.addons.viewEngines[type])(viewId, options);
+ if (!cache[type]) {
+ this._renderer = cache[type] = new (Y.mojito.addons.viewEngines[type])(options);
+ } else {
+ this._renderer = cache[type];
+ }
+ return cache[type];
}
@@ -44,6 +55,7 @@ YUI.add('mojito-view-renderer', function(Y) {
render: function(data, mojitType, tmpl, adapter, meta, more) {
this._renderer.render(data, mojitType, tmpl, adapter, meta, more);
}
+
};
Y.namespace('mojito').ViewRenderer = Renderer;
Something went wrong with that request. Please try again.