Skip to content

Commit

Permalink
Added custom templates in lib/template/templates/, these templates …
Browse files Browse the repository at this point in the history
…handle

special cases like empty layouts, etc.

Made it so controller.respond's options are more consistent, and added more
stability for different path cases.

ex: this.respond(params, {template: 'index'}) // Takes current controller
ex: this.respond(params, {template: 'app/views/main/index'})
ex: this.respond(params, {template: 'main.index'})
All the above examples also apply to `layout` option.

Fixed a bug where the options object is a string and sets as the response type.
Now setting the `layout` option to false will respond with only the template
  • Loading branch information
larzconwell committed Jul 21, 2012
1 parent 16f960f commit 018c001
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 38 deletions.
77 changes: 52 additions & 25 deletions lib/app.js
Expand Up @@ -235,38 +235,65 @@ var App = function () {
// Register template-paths
// ==================
, _registerTemplatePaths = function (next) {
var viewsPath = path.normalize('app/views');
// May be running entirely viewless
if (!existsSync(viewsPath)) {
var viewsPath = path.normalize('app/views')
, geddyTemplatesPath = path.join(__dirname, 'template', 'templates');

// If viewsPath doesn't exist they're running viewless
if(!existsSync(viewsPath)) {
this.templateRegistry = {};
next();
}
else {
var templates = {}
, files
} else {
var files = fileUtils.readdirR(viewsPath)
, geddyTemplatesFiles = fileUtils.readdirR(geddyTemplatesPath)
, pat = /\.(ejs|jade|hbs|mustache|ms|mu)$/
, templates = {}
, file
, origFile
, noExtFile
, fileExt
, fileBaseName
, pat = /\.(ejs|jade|hbs|mustache|ms|mu)$/;
files = fileUtils.readdirR(viewsPath);
for (var i = 0; i < files.length; i++) {
file = files[i];
fileExt = path.extname(file);
fileBaseName = path.basename(file, fileExt).replace(/\.html$/, '');

if (pat.test(file)) {
// Strip .html and extension for easier detecting when rendering
noExtFile = file.replace(/\.html.*$/, '');
templates[noExtFile] = {
registered: true
, file: file
, ext: fileExt
, baseName: fileBaseName
, baseNamePath: noExtFile
};
, addTemplate
, createTemplates;

// Adds a template object to templates
addTemplate = function(noExtFile, file, origFile, fileExt, fileBaseName) {
if(!origFile) origFile = noExtFile;

templates[origFile] = {
registered: true
, file: file
, ext: fileExt
, baseName: fileBaseName
, baseNamePath: noExtFile
};
};

// Read dir list and create template objects from each file
createTemplates = function(dir, isGeddy) {
for (var i = 0; i < dir.length; i++) {
file = dir[i];
fileExt = path.extname(file);
fileBaseName = path.basename(file, fileExt).replace(/\.html$/, '');

if(isGeddy) origFile = 'geddy/' + fileBaseName;

if(pat.test(file)) {
// Strip .html and extension for easier detecting when rendering
if(isGeddy) {
noExtFile = 'geddy/' + fileBaseName;
} else noExtFile = file.replace(/\.html.*$/, '');

addTemplate(noExtFile, file, origFile, fileExt, fileBaseName);
}
}
}
};

// Loop through template files and add it them to registry
createTemplates(files);

// Add custom templates from `lib/template/templates`
createTemplates(geddyTemplatesFiles, true);

this.templateRegistry = templates;
next();
}
Expand Down
66 changes: 53 additions & 13 deletions lib/base_controller.js
Expand Up @@ -505,7 +505,7 @@ controller.BaseController.prototype = new (function () {
@function
@description Performs content-negotiation, and renders a response.
@param {Object|String} content The content to use in the response.
@param {Object} [opts] Options.
@param {Object} [options] Options.
@param {String} [options.format] The desired format for the response.
@param {String} [options.template] The path (without file extensions)
to the template to use to render this response.
Expand All @@ -514,7 +514,7 @@ controller.BaseController.prototype = new (function () {
*/
var self = this
, options = options || {}
, formatParam = typeof opts == 'string' ? options : options.format
, formatParam = typeof options == 'string' ? options : options.format
, negotiated = _negotiateContent.call(this, formatParam)
, format
, contentType
Expand All @@ -531,18 +531,53 @@ controller.BaseController.prototype = new (function () {
format = negotiated.format;
contentType = negotiated.contentType;

// If no content type could be found we can't use it
if(!contentType) {
var err = new geddy.errors.NotAcceptableError('Not an acceptable media type.');
this.error(err);
return;
}

if(!format) {
_throwUndefinedFormatError.call(this);
return;
}

if(options.template) this.template = options.template;
if(options.layout) this.layout = 'app/views/' + options.layout;
// Set template and layout paths
if(options.template) {
if(options.template.match('app/views/')) {
// If template includes full views path just use it
this.template = options.template;
}
else if(options.template.match('/')) {
// If it includes a '/' and it isn't the full path
// Assume they are using the `controller/action` style
this.template = 'app/views/' + options.template;
}
else {
// Assume they only included the action, so add the controller path
this.template = 'app/views/' + geddy.string.decapitalize(this.params.controller) +
'/' + options.template;
}
}
if(options.layout) {
if(options.layout.match('app/views')) {
// If layout includes `app/views` just return it
this.layout = options.layout;
}
else if(options.layout.match('/')) {
// If it includes a '/' and it isn't the full path
// Assume they are using the `controller/action` style
this.layout = 'app/views/' + options.layout;
}
else {
// Assume they only included the action, so add the controller path
this.layout = 'app/views/layouts/' + options.layout;
}
}

// If options.layout is set to `false` just set it
if(typeof options.layout === 'boolean' && !options.layout) this.layout = options.layout;

// Hand content off to formatting along with callback for writing out
// the formatted respnse
Expand All @@ -553,19 +588,24 @@ controller.BaseController.prototype = new (function () {
this.renderTemplate = function(data, callback) {
var self = this
, templater = new Templater()
, content = ''
, dirName;
, content = '';

// Format directory name
dirName = geddy.inflection.pluralize(this.name);
dirName = geddy.string.snakeize(dirName);
if(!this.template || !this.layout) {
// Format directory names
var dirName = geddy.inflection.pluralize(this.name);
dirName = geddy.string.snakeize(dirName);
}

// Get template if not set
this.template = this.template ||
'app/views/' + dirName + '/' + this.params.action;
this.template = this.template || 'app/views/' + dirName + '/' + this.params.action;

// Get layout if not set
this.layout = this.layout || 'app/views/layouts/' + dirName;
// Get layout if not set or set empty layout if `false`
if(typeof this.layout === 'boolean' && !this.layout) {
// Use custom Geddy empty template in `lib/template/templates`
this.layout = 'geddy/empty';
} else {
this.layout = this.layout || 'app/views/layouts/' + dirName;
}

templater.addListener('data', function(data) {
// Buffer for now, but we could stream
Expand Down
1 change: 1 addition & 0 deletions lib/template/templates/empty.html.ejs
@@ -0,0 +1 @@
<%- yield(); %>

0 comments on commit 018c001

Please sign in to comment.