mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-03 23:00:14 -05:00
Introduced renderer to DRY up controllers (#9235)
refs #5091, #9192 - Renderer figures out templates, contexts, and does a render call - Templating is now handled with a single function - Context call is made in the renderer Note: to make this work, all controllers now define a little bit of config, currently stored in res._route. (That's a totally temporary location, as is res._template... when a sensible naming convention reveals itself I'll get rid of the weird _). This exposes a type and for custom routes a template name & default.
This commit is contained in:
parent
e41d0c76fb
commit
98f5ae00fc
12 changed files with 359 additions and 154 deletions
|
@ -5,14 +5,20 @@ var path = require('path'),
|
|||
|
||||
// Dirty requires
|
||||
errors = require('../../../errors'),
|
||||
templates = require('../../../controllers/frontend/templates'),
|
||||
postLookup = require('../../../controllers/frontend/post-lookup'),
|
||||
setResponseContext = require('../../../controllers/frontend/context'),
|
||||
renderer = require('../../../controllers/frontend/renderer'),
|
||||
|
||||
templateName = 'amp',
|
||||
defaultTemplate = path.resolve(__dirname, 'views', templateName + '.hbs');
|
||||
templateName = 'amp';
|
||||
|
||||
function _renderer(req, res, next) {
|
||||
// Note: this is super similar to the config middleware used in channels
|
||||
// @TODO refactor into to something explicit & DRY this up
|
||||
res._route = {
|
||||
type: 'custom',
|
||||
templateName: templateName,
|
||||
defaultTemplate: path.resolve(__dirname, 'views', templateName + '.hbs')
|
||||
};
|
||||
|
||||
// Renderer begin
|
||||
// Format data
|
||||
var data = req.body || {};
|
||||
|
@ -22,14 +28,8 @@ function _renderer(req, res, next) {
|
|||
return next(new errors.NotFoundError({message: i18n.t('errors.errors.pageNotFound')}));
|
||||
}
|
||||
|
||||
// Context
|
||||
setResponseContext(req, res, data);
|
||||
|
||||
// Template
|
||||
res.template = templates.pickTemplate(templateName, defaultTemplate);
|
||||
|
||||
// Render Call
|
||||
return res.render(res.template, data);
|
||||
return renderer(req, res, data);
|
||||
}
|
||||
|
||||
// This here is a controller.
|
||||
|
@ -49,7 +49,8 @@ function getPostData(req, res, next) {
|
|||
}
|
||||
|
||||
// AMP frontend route
|
||||
ampRouter.route('/')
|
||||
ampRouter
|
||||
.route('/')
|
||||
.get(
|
||||
getPostData,
|
||||
_renderer
|
||||
|
|
|
@ -2,16 +2,22 @@ var path = require('path'),
|
|||
express = require('express'),
|
||||
middleware = require('./middleware'),
|
||||
bodyParser = require('body-parser'),
|
||||
templates = require('../../../controllers/frontend/templates'),
|
||||
setResponseContext = require('../../../controllers/frontend/context'),
|
||||
renderer = require('../../../controllers/frontend/renderer'),
|
||||
brute = require('../../../middleware/brute'),
|
||||
|
||||
templateName = 'private',
|
||||
defaultTemplate = path.resolve(__dirname, 'views', templateName + '.hbs'),
|
||||
|
||||
privateRouter = express.Router();
|
||||
|
||||
function _renderer(req, res) {
|
||||
// Note: this is super similar to the config middleware used in channels
|
||||
// @TODO refactor into to something explicit & DRY this up
|
||||
res._route = {
|
||||
type: 'custom',
|
||||
templateName: templateName,
|
||||
defaultTemplate: path.resolve(__dirname, 'views', templateName + '.hbs')
|
||||
};
|
||||
|
||||
// Renderer begin
|
||||
// Format data
|
||||
var data = {};
|
||||
|
@ -20,18 +26,13 @@ function _renderer(req, res) {
|
|||
data.error = res.error;
|
||||
}
|
||||
|
||||
// Context
|
||||
setResponseContext(req, res);
|
||||
|
||||
// Template
|
||||
res.template = templates.pickTemplate(templateName, defaultTemplate);
|
||||
|
||||
// Render Call
|
||||
return res.render(res.template, data);
|
||||
return renderer(req, res, data);
|
||||
}
|
||||
|
||||
// password-protected frontend route
|
||||
privateRouter.route('/')
|
||||
privateRouter
|
||||
.route('/')
|
||||
.get(
|
||||
middleware.isPrivateSessionAuth,
|
||||
_renderer
|
||||
|
|
|
@ -8,27 +8,26 @@ var path = require('path'),
|
|||
api = require('../../../api'),
|
||||
errors = require('../../../errors'),
|
||||
validator = require('../../../data/validation').validator,
|
||||
templates = require('../../../controllers/frontend/templates'),
|
||||
postLookup = require('../../../controllers/frontend/post-lookup'),
|
||||
setResponseContext = require('../../../controllers/frontend/context'),
|
||||
renderer = require('../../../controllers/frontend/renderer'),
|
||||
|
||||
templateName = 'subscribe',
|
||||
defaultTemplate = path.resolve(__dirname, 'views', templateName + '.hbs');
|
||||
templateName = 'subscribe';
|
||||
|
||||
// In future we'd have a more complex controller here - showing if someone already subscribed?!
|
||||
function _renderer(req, res) {
|
||||
// Note: this is super similar to the config middleware used in channels
|
||||
// @TODO refactor into to something explicit & DRY this up
|
||||
res._route = {
|
||||
type: 'custom',
|
||||
templateName: templateName,
|
||||
defaultTemplate: path.resolve(__dirname, 'views', templateName + '.hbs')
|
||||
};
|
||||
|
||||
// Renderer begin
|
||||
// Format data
|
||||
var data = req.body;
|
||||
|
||||
// Context
|
||||
setResponseContext(req, res);
|
||||
|
||||
// Template
|
||||
res.template = templates.pickTemplate(templateName, defaultTemplate);
|
||||
|
||||
// Render Call
|
||||
return res.render(res.template, data);
|
||||
return renderer(req, res, data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -106,7 +105,8 @@ function storeSubscriber(req, res, next) {
|
|||
}
|
||||
|
||||
// subscribe frontend route
|
||||
subscribeRouter.route('/')
|
||||
subscribeRouter
|
||||
.route('/')
|
||||
.get(
|
||||
_renderer
|
||||
)
|
||||
|
|
|
@ -9,6 +9,12 @@ var utils = require('../utils'),
|
|||
// It renders entries = individual posts or pages
|
||||
// The "route" is handled in site/routes.js
|
||||
module.exports = function entryController(req, res, next) {
|
||||
// Note: this is super similar to the config middleware used in channels
|
||||
// @TODO refactor into to something explicit
|
||||
res._route = {
|
||||
type: 'entry'
|
||||
};
|
||||
|
||||
// Query database to find post
|
||||
return postLookup(req.path).then(function then(lookup) {
|
||||
// Format data 1
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
var debug = require('ghost-ignition').debug('channels:render'),
|
||||
formatResponse = require('./format-response'),
|
||||
setResponseContext = require('./context'),
|
||||
templates = require('./templates');
|
||||
renderer = require('./renderer');
|
||||
|
||||
module.exports = function renderChannel(req, res) {
|
||||
debug('renderChannel called');
|
||||
|
@ -9,16 +8,9 @@ module.exports = function renderChannel(req, res) {
|
|||
// Renderer begin
|
||||
// Format data 2
|
||||
// Do final data formatting and then render
|
||||
result = formatResponse.channel(result);
|
||||
|
||||
// Context
|
||||
setResponseContext(req, res);
|
||||
|
||||
// Template
|
||||
res.template = templates.channel(res.locals.channel);
|
||||
var data = formatResponse.channel(result);
|
||||
|
||||
// Render Call
|
||||
debug('Rendering view: ' + res.template);
|
||||
res.render(res.template, result);
|
||||
return renderer(req, res, data);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
var debug = require('ghost-ignition').debug('channels:render-post'),
|
||||
templates = require('./templates'),
|
||||
formatResponse = require('./format-response'),
|
||||
setResponseContext = require('./context');
|
||||
renderer = require('./renderer');
|
||||
/*
|
||||
* Sets the response context around an entry (post or page)
|
||||
* and renders it with the correct template.
|
||||
|
@ -13,16 +12,9 @@ module.exports = function renderEntry(req, res) {
|
|||
return function renderEntry(entry) {
|
||||
// Renderer begin
|
||||
// Format data 2 - 1 is in preview/entry
|
||||
var response = formatResponse.entry(entry);
|
||||
|
||||
// Context
|
||||
setResponseContext(req, res, response);
|
||||
|
||||
// Template
|
||||
res.template = templates.entry(entry);
|
||||
var data = formatResponse.entry(entry);
|
||||
|
||||
// Render Call
|
||||
debug('Rendering view: ' + res.template);
|
||||
res.render(res.template, response);
|
||||
return renderer(req, res, data);
|
||||
};
|
||||
};
|
||||
|
|
16
core/server/controllers/frontend/renderer.js
Normal file
16
core/server/controllers/frontend/renderer.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
var debug = require('ghost-ignition').debug('renderer'),
|
||||
setContext = require('./context'),
|
||||
templates = require('./templates');
|
||||
|
||||
module.exports = function renderer(req, res, data) {
|
||||
// Context
|
||||
setContext(req, res, data);
|
||||
|
||||
// Template
|
||||
templates.setTemplate(req, res, data);
|
||||
|
||||
// Render Call
|
||||
debug('Rendering template: ' + res._template + ' for: ' + req.originalUrl);
|
||||
debug('res.locals', res.locals);
|
||||
res.render(res._template, data);
|
||||
};
|
|
@ -6,7 +6,8 @@
|
|||
var _ = require('lodash'),
|
||||
path = require('path'),
|
||||
config = require('../../config'),
|
||||
themes = require('../../themes');
|
||||
themes = require('../../themes'),
|
||||
_private = {};
|
||||
|
||||
/**
|
||||
* ## Get Error Template Hierarchy
|
||||
|
@ -18,7 +19,7 @@ var _ = require('lodash'),
|
|||
* @param {integer} statusCode
|
||||
* @returns {String[]}
|
||||
*/
|
||||
function getErrorTemplateHierarchy(statusCode) {
|
||||
_private.getErrorTemplateHierarchy = function getErrorTemplateHierarchy(statusCode) {
|
||||
var errorCode = _.toString(statusCode),
|
||||
templateList = ['error'];
|
||||
|
||||
|
@ -29,7 +30,7 @@ function getErrorTemplateHierarchy(statusCode) {
|
|||
templateList.unshift('error-' + errorCode);
|
||||
|
||||
return templateList;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* ## Get Channel Template Hierarchy
|
||||
|
@ -43,7 +44,7 @@ function getErrorTemplateHierarchy(statusCode) {
|
|||
* @param {Object} channelOpts
|
||||
* @returns {String[]}
|
||||
*/
|
||||
function getChannelTemplateHierarchy(channelOpts) {
|
||||
_private.getChannelTemplateHierarchy = function getChannelTemplateHierarchy(channelOpts) {
|
||||
var templateList = ['index'];
|
||||
|
||||
if (channelOpts.name && channelOpts.name !== 'index') {
|
||||
|
@ -59,7 +60,7 @@ function getChannelTemplateHierarchy(channelOpts) {
|
|||
}
|
||||
|
||||
return templateList;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* ## Get Entry Template Hierarchy
|
||||
|
@ -72,7 +73,7 @@ function getChannelTemplateHierarchy(channelOpts) {
|
|||
* @param {Object} postObject
|
||||
* @returns {String[]}
|
||||
*/
|
||||
function getEntryTemplateHierarchy(postObject) {
|
||||
_private.getEntryTemplateHierarchy = function getEntryTemplateHierarchy(postObject) {
|
||||
var templateList = ['post'],
|
||||
slugTemplate = 'post-' + postObject.slug;
|
||||
|
||||
|
@ -88,7 +89,7 @@ function getEntryTemplateHierarchy(postObject) {
|
|||
templateList.unshift(slugTemplate);
|
||||
|
||||
return templateList;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* ## Pick Template
|
||||
|
@ -99,7 +100,7 @@ function getEntryTemplateHierarchy(postObject) {
|
|||
* @param {Array|String} templateList
|
||||
* @param {String} fallback - a fallback template
|
||||
*/
|
||||
function pickTemplate(templateList, fallback) {
|
||||
_private.pickTemplate = function pickTemplate(templateList, fallback) {
|
||||
var template;
|
||||
|
||||
if (!_.isArray(templateList)) {
|
||||
|
@ -119,29 +120,49 @@ function pickTemplate(templateList, fallback) {
|
|||
}
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
function getTemplateForEntry(postObject) {
|
||||
var templateList = getEntryTemplateHierarchy(postObject),
|
||||
fallback = templateList[templateList.length - 1];
|
||||
return pickTemplate(templateList, fallback);
|
||||
}
|
||||
|
||||
function getTemplateForChannel(channelOpts) {
|
||||
var templateList = getChannelTemplateHierarchy(channelOpts),
|
||||
fallback = templateList[templateList.length - 1];
|
||||
return pickTemplate(templateList, fallback);
|
||||
}
|
||||
|
||||
function getTemplateForError(statusCode) {
|
||||
var templateList = getErrorTemplateHierarchy(statusCode),
|
||||
fallback = path.resolve(config.get('paths').defaultViews, 'error.hbs');
|
||||
return pickTemplate(templateList, fallback);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
channel: getTemplateForChannel,
|
||||
entry: getTemplateForEntry,
|
||||
error: getTemplateForError,
|
||||
pickTemplate: pickTemplate
|
||||
};
|
||||
|
||||
_private.getTemplateForEntry = function getTemplateForEntry(postObject) {
|
||||
var templateList = _private.getEntryTemplateHierarchy(postObject),
|
||||
fallback = templateList[templateList.length - 1];
|
||||
return _private.pickTemplate(templateList, fallback);
|
||||
};
|
||||
|
||||
_private.getTemplateForChannel = function getTemplateForChannel(channelOpts) {
|
||||
var templateList = _private.getChannelTemplateHierarchy(channelOpts),
|
||||
fallback = templateList[templateList.length - 1];
|
||||
return _private.pickTemplate(templateList, fallback);
|
||||
};
|
||||
|
||||
_private.getTemplateForError = function getTemplateForError(statusCode) {
|
||||
var templateList = _private.getErrorTemplateHierarchy(statusCode),
|
||||
fallback = path.resolve(config.get('paths').defaultViews, 'error.hbs');
|
||||
return _private.pickTemplate(templateList, fallback);
|
||||
};
|
||||
|
||||
module.exports.setTemplate = function setTemplate(req, res, data) {
|
||||
var routeConfig = res._route || {};
|
||||
|
||||
if (res._template) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.err) {
|
||||
res._template = _private.getTemplateForError(res.statusCode);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (routeConfig.type) {
|
||||
case 'custom':
|
||||
res._template = _private.pickTemplate(routeConfig.templateName, routeConfig.defaultTemplate);
|
||||
break;
|
||||
case 'channel':
|
||||
res._template = _private.getTemplateForChannel(res.locals.channel);
|
||||
break;
|
||||
case 'entry':
|
||||
res._template = _private.getTemplateForEntry(data.post);
|
||||
break;
|
||||
default:
|
||||
res._template = 'index';
|
||||
}
|
||||
};
|
||||
|
|
|
@ -14,6 +14,12 @@ module.exports = function previewController(req, res, next) {
|
|||
include: 'author,tags'
|
||||
};
|
||||
|
||||
// Note: this is super similar to the config middleware used in channels
|
||||
// @TODO refactor into to something explicit
|
||||
res._route = {
|
||||
type: 'entry'
|
||||
};
|
||||
|
||||
api.posts.read(params).then(function then(result) {
|
||||
// Format data 1
|
||||
var post = result.posts[0];
|
||||
|
|
|
@ -71,7 +71,7 @@ _private.JSONErrorRenderer = function JSONErrorRenderer(err, req, res, next) { /
|
|||
});
|
||||
};
|
||||
|
||||
// @TODO: differenciate properly between rendering errors for theme templates, and other situations
|
||||
// @TODO: differentiate properly between rendering errors for theme templates, and other situations
|
||||
_private.HTMLErrorRenderer = function HTMLErrorRender(err, req, res, next) {
|
||||
// If the error code is explicitly set to STATIC_FILE_NOT_FOUND,
|
||||
// Skip trying to render an HTML error, and move on to the basic error renderer
|
||||
|
@ -83,7 +83,7 @@ _private.HTMLErrorRenderer = function HTMLErrorRender(err, req, res, next) {
|
|||
|
||||
// Renderer begin
|
||||
// Format Data
|
||||
var templateData = {
|
||||
var data = {
|
||||
message: err.message,
|
||||
// @deprecated
|
||||
code: err.statusCode,
|
||||
|
@ -95,20 +95,21 @@ _private.HTMLErrorRenderer = function HTMLErrorRender(err, req, res, next) {
|
|||
// We don't do context for errors?!
|
||||
|
||||
// Template
|
||||
res.template = templates.error(err.statusCode);
|
||||
templates.setTemplate(req, res);
|
||||
|
||||
// It can be that something went wrong with the theme or otherwise loading handlebars
|
||||
// This ensures that no matter what res.render will work here
|
||||
// @TODO: split the error handler for assets, admin & theme to refactor this away
|
||||
if (_.isEmpty(req.app.engines)) {
|
||||
res.template = 'error';
|
||||
res._template = 'error';
|
||||
req.app.engine('hbs', _private.createHbsEngine());
|
||||
req.app.set('view engine', 'hbs');
|
||||
req.app.set('views', config.get('paths').defaultViews);
|
||||
}
|
||||
|
||||
// @TODO use renderer here?!
|
||||
// Render Call - featuring an error handler for what happens if rendering fails
|
||||
res.render(res.template, templateData, function renderResponse(err, html) {
|
||||
res.render(res._template, data, function renderResponse(err, html) {
|
||||
if (!err) {
|
||||
return res.send(html);
|
||||
}
|
||||
|
|
|
@ -40,6 +40,8 @@ function rssConfigMiddleware(req, res, next) {
|
|||
function channelConfigMiddleware(channel) {
|
||||
return function doChannelConfig(req, res, next) {
|
||||
res.locals.channel = _.cloneDeep(channel);
|
||||
// @TODO refactor into to something explicit
|
||||
res._route = {type: 'channel'};
|
||||
next();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -9,14 +9,15 @@ var should = require('should'),
|
|||
sandbox = sinon.sandbox.create();
|
||||
|
||||
describe('templates', function () {
|
||||
var getActiveThemeStub, hasTemplateStub;
|
||||
var getActiveThemeStub, hasTemplateStub,
|
||||
_private = templates.__get__('_private');
|
||||
|
||||
afterEach(function () {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
describe('[private] getChannelTemplateHierarchy', function () {
|
||||
var channelTemplateList = templates.__get__('getChannelTemplateHierarchy');
|
||||
var channelTemplateList = _private.getChannelTemplateHierarchy;
|
||||
|
||||
it('should return just index for empty channelOpts', function () {
|
||||
channelTemplateList({}).should.eql(['index']);
|
||||
|
@ -61,7 +62,7 @@ describe('templates', function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe('pickTemplate', function () {
|
||||
describe('[private] pickTemplate', function () {
|
||||
beforeEach(function () {
|
||||
hasTemplateStub = sandbox.stub().returns(false);
|
||||
|
||||
|
@ -73,13 +74,13 @@ describe('templates', function () {
|
|||
it('returns fallback if there is no active_theme', function () {
|
||||
getActiveThemeStub.returns(undefined);
|
||||
|
||||
templates.pickTemplate(['tag-test', 'tag', 'index'], 'fallback').should.eql('fallback');
|
||||
templates.pickTemplate(['page-my-post', 'page', 'post'], 'fallback').should.eql('fallback');
|
||||
_private.pickTemplate(['tag-test', 'tag', 'index'], 'fallback').should.eql('fallback');
|
||||
_private.pickTemplate(['page-my-post', 'page', 'post'], 'fallback').should.eql('fallback');
|
||||
});
|
||||
|
||||
it('returns fallback if active_theme has no templates', function () {
|
||||
templates.pickTemplate(['tag-test', 'tag', 'index'], 'fallback').should.eql('fallback');
|
||||
templates.pickTemplate(['page-about', 'page', 'post'], 'fallback').should.eql('fallback');
|
||||
_private.pickTemplate(['tag-test', 'tag', 'index'], 'fallback').should.eql('fallback');
|
||||
_private.pickTemplate(['page-about', 'page', 'post'], 'fallback').should.eql('fallback');
|
||||
});
|
||||
|
||||
describe('with many templates', function () {
|
||||
|
@ -94,20 +95,20 @@ describe('templates', function () {
|
|||
});
|
||||
|
||||
it('returns first matching template', function () {
|
||||
templates.pickTemplate(['page-about', 'page', 'post'], 'fallback').should.eql('page-about');
|
||||
templates.pickTemplate(['page-magic', 'page', 'post'], 'fallback').should.eql('page');
|
||||
templates.pickTemplate(['page', 'post'], 'fallback').should.eql('page');
|
||||
_private.pickTemplate(['page-about', 'page', 'post'], 'fallback').should.eql('page-about');
|
||||
_private.pickTemplate(['page-magic', 'page', 'post'], 'fallback').should.eql('page');
|
||||
_private.pickTemplate(['page', 'post'], 'fallback').should.eql('page');
|
||||
});
|
||||
|
||||
it('returns correctly if template list is a string', function () {
|
||||
templates.pickTemplate('amp', 'fallback').should.eql('amp');
|
||||
templates.pickTemplate('subscribe', 'fallback').should.eql('fallback');
|
||||
templates.pickTemplate('post', 'fallback').should.eql('post');
|
||||
_private.pickTemplate('amp', 'fallback').should.eql('amp');
|
||||
_private.pickTemplate('subscribe', 'fallback').should.eql('fallback');
|
||||
_private.pickTemplate('post', 'fallback').should.eql('post');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('entry', function () {
|
||||
describe('[private] getTemplateForEntry', function () {
|
||||
beforeEach(function () {
|
||||
hasTemplateStub = sandbox.stub().returns(false);
|
||||
|
||||
|
@ -127,7 +128,7 @@ describe('templates', function () {
|
|||
});
|
||||
|
||||
it('post without custom slug template', function () {
|
||||
var view = templates.entry({
|
||||
var view = _private.getTemplateForEntry({
|
||||
page: 0,
|
||||
slug: 'test-post'
|
||||
});
|
||||
|
@ -137,7 +138,7 @@ describe('templates', function () {
|
|||
|
||||
it('post with custom slug template', function () {
|
||||
hasTemplateStub.withArgs('post-welcome-to-ghost').returns(true);
|
||||
var view = templates.entry({
|
||||
var view = _private.getTemplateForEntry({
|
||||
page: 0,
|
||||
slug: 'welcome-to-ghost'
|
||||
});
|
||||
|
@ -146,7 +147,7 @@ describe('templates', function () {
|
|||
});
|
||||
|
||||
it('page without custom slug template', function () {
|
||||
var view = templates.entry({
|
||||
var view = _private.getTemplateForEntry({
|
||||
page: 1,
|
||||
slug: 'contact'
|
||||
});
|
||||
|
@ -155,7 +156,7 @@ describe('templates', function () {
|
|||
});
|
||||
|
||||
it('page with custom slug template', function () {
|
||||
var view = templates.entry({
|
||||
var view = _private.getTemplateForEntry({
|
||||
page: 1,
|
||||
slug: 'about'
|
||||
});
|
||||
|
@ -166,7 +167,7 @@ describe('templates', function () {
|
|||
it('post with custom template', function () {
|
||||
hasTemplateStub.withArgs('custom-about').returns(true);
|
||||
|
||||
var view = templates.entry({
|
||||
var view = _private.getTemplateForEntry({
|
||||
page: 0,
|
||||
custom_template: 'custom-about'
|
||||
});
|
||||
|
@ -177,7 +178,7 @@ describe('templates', function () {
|
|||
it('page with custom template', function () {
|
||||
hasTemplateStub.withArgs('custom-about').returns(true);
|
||||
|
||||
var view = templates.entry({
|
||||
var view = _private.getTemplateForEntry({
|
||||
page: 1,
|
||||
custom_template: 'custom-about'
|
||||
});
|
||||
|
@ -188,7 +189,7 @@ describe('templates', function () {
|
|||
it('post with custom template configured, but the template is missing', function () {
|
||||
hasTemplateStub.withArgs('custom-about').returns(false);
|
||||
|
||||
var view = templates.entry({
|
||||
var view = _private.getTemplateForEntry({
|
||||
page: 0,
|
||||
custom_template: 'custom-about'
|
||||
});
|
||||
|
@ -199,7 +200,7 @@ describe('templates', function () {
|
|||
it('page with custom template configured, but the template is missing', function () {
|
||||
hasTemplateStub.withArgs('custom-about').returns(false);
|
||||
|
||||
var view = templates.entry({
|
||||
var view = _private.getTemplateForEntry({
|
||||
page: 1,
|
||||
custom_template: 'custom-about'
|
||||
});
|
||||
|
@ -211,7 +212,7 @@ describe('templates', function () {
|
|||
hasTemplateStub.withArgs('custom-about').returns(true);
|
||||
hasTemplateStub.withArgs('post-about').returns(true);
|
||||
|
||||
var view = templates.entry({
|
||||
var view = _private.getTemplateForEntry({
|
||||
page: 0,
|
||||
slug: 'about',
|
||||
custom_template: 'custom-about'
|
||||
|
@ -224,7 +225,7 @@ describe('templates', function () {
|
|||
hasTemplateStub.withArgs('custom-about').returns(false);
|
||||
hasTemplateStub.withArgs('post-about').returns(false);
|
||||
|
||||
var view = templates.entry({
|
||||
var view = _private.getTemplateForEntry({
|
||||
page: 0,
|
||||
slug: 'about',
|
||||
custom_template: 'custom-about'
|
||||
|
@ -237,13 +238,13 @@ describe('templates', function () {
|
|||
it('will fall back to post even if no index.hbs', function () {
|
||||
hasTemplateStub.returns(false);
|
||||
|
||||
var view = templates.entry({page: 1});
|
||||
var view = _private.getTemplateForEntry({page: 1});
|
||||
should.exist(view);
|
||||
view.should.eql('post');
|
||||
});
|
||||
});
|
||||
|
||||
describe('channel', function () {
|
||||
describe('[private] getTemplateForChannel', function () {
|
||||
beforeEach(function () {
|
||||
hasTemplateStub = sandbox.stub().returns(false);
|
||||
|
||||
|
@ -259,7 +260,7 @@ describe('templates', function () {
|
|||
});
|
||||
|
||||
it('will return correct view for a tag', function () {
|
||||
var view = templates.channel({name: 'tag', slugParam: 'development', slugTemplate: true});
|
||||
var view = _private.getTemplateForChannel({name: 'tag', slugParam: 'development', slugTemplate: true});
|
||||
should.exist(view);
|
||||
view.should.eql('index');
|
||||
});
|
||||
|
@ -274,26 +275,26 @@ describe('templates', function () {
|
|||
});
|
||||
|
||||
it('will return correct view for a tag', function () {
|
||||
var view = templates.channel({name: 'tag', slugParam: 'design', slugTemplate: true});
|
||||
var view = _private.getTemplateForChannel({name: 'tag', slugParam: 'design', slugTemplate: true});
|
||||
should.exist(view);
|
||||
view.should.eql('tag-design');
|
||||
});
|
||||
|
||||
it('will return correct view for a tag', function () {
|
||||
var view = templates.channel({name: 'tag', slugParam: 'development', slugTemplate: true});
|
||||
var view = _private.getTemplateForChannel({name: 'tag', slugParam: 'development', slugTemplate: true});
|
||||
should.exist(view);
|
||||
view.should.eql('tag');
|
||||
});
|
||||
});
|
||||
|
||||
it('will fall back to index even if no index.hbs', function () {
|
||||
var view = templates.channel({name: 'tag', slugParam: 'development', slugTemplate: true});
|
||||
var view = _private.getTemplateForChannel({name: 'tag', slugParam: 'development', slugTemplate: true});
|
||||
should.exist(view);
|
||||
view.should.eql('index');
|
||||
});
|
||||
});
|
||||
|
||||
describe('error', function () {
|
||||
describe('[private] getTemplateForError', function () {
|
||||
beforeEach(function () {
|
||||
hasTemplateStub = sandbox.stub().returns(false);
|
||||
|
||||
|
@ -305,33 +306,33 @@ describe('templates', function () {
|
|||
it('will fall back to default if there is no active_theme', function () {
|
||||
getActiveThemeStub.returns(undefined);
|
||||
|
||||
templates.error(500).should.match(/core\/server\/views\/error.hbs$/);
|
||||
_private.getTemplateForError(500).should.match(/core\/server\/views\/error.hbs$/);
|
||||
});
|
||||
|
||||
it('will fall back to default for all statusCodes with no custom error templates', function () {
|
||||
templates.error(500).should.match(/core\/server\/views\/error.hbs$/);
|
||||
templates.error(503).should.match(/core\/server\/views\/error.hbs$/);
|
||||
templates.error(422).should.match(/core\/server\/views\/error.hbs$/);
|
||||
templates.error(404).should.match(/core\/server\/views\/error.hbs$/);
|
||||
_private.getTemplateForError(500).should.match(/core\/server\/views\/error.hbs$/);
|
||||
_private.getTemplateForError(503).should.match(/core\/server\/views\/error.hbs$/);
|
||||
_private.getTemplateForError(422).should.match(/core\/server\/views\/error.hbs$/);
|
||||
_private.getTemplateForError(404).should.match(/core\/server\/views\/error.hbs$/);
|
||||
});
|
||||
|
||||
it('will use custom error.hbs for all statusCodes if there are no other templates', function () {
|
||||
hasTemplateStub.withArgs('error').returns(true);
|
||||
|
||||
templates.error(500).should.eql('error');
|
||||
templates.error(503).should.eql('error');
|
||||
templates.error(422).should.eql('error');
|
||||
templates.error(404).should.eql('error');
|
||||
_private.getTemplateForError(500).should.eql('error');
|
||||
_private.getTemplateForError(503).should.eql('error');
|
||||
_private.getTemplateForError(422).should.eql('error');
|
||||
_private.getTemplateForError(404).should.eql('error');
|
||||
});
|
||||
|
||||
it('will use more specific error-4xx.hbs for all 4xx statusCodes if available', function () {
|
||||
hasTemplateStub.withArgs('error').returns(true);
|
||||
hasTemplateStub.withArgs('error-4xx').returns(true);
|
||||
|
||||
templates.error(500).should.eql('error');
|
||||
templates.error(503).should.eql('error');
|
||||
templates.error(422).should.eql('error-4xx');
|
||||
templates.error(404).should.eql('error-4xx');
|
||||
_private.getTemplateForError(500).should.eql('error');
|
||||
_private.getTemplateForError(503).should.eql('error');
|
||||
_private.getTemplateForError(422).should.eql('error-4xx');
|
||||
_private.getTemplateForError(404).should.eql('error-4xx');
|
||||
});
|
||||
|
||||
it('will use explicit error-404.hbs for 404 statusCode if available', function () {
|
||||
|
@ -339,10 +340,10 @@ describe('templates', function () {
|
|||
hasTemplateStub.withArgs('error-4xx').returns(true);
|
||||
hasTemplateStub.withArgs('error-404').returns(true);
|
||||
|
||||
templates.error(500).should.eql('error');
|
||||
templates.error(503).should.eql('error');
|
||||
templates.error(422).should.eql('error-4xx');
|
||||
templates.error(404).should.eql('error-404');
|
||||
_private.getTemplateForError(500).should.eql('error');
|
||||
_private.getTemplateForError(503).should.eql('error');
|
||||
_private.getTemplateForError(422).should.eql('error-4xx');
|
||||
_private.getTemplateForError(404).should.eql('error-404');
|
||||
});
|
||||
|
||||
it('cascade works the same for 500 errors', function () {
|
||||
|
@ -350,10 +351,10 @@ describe('templates', function () {
|
|||
hasTemplateStub.withArgs('error-5xx').returns(true);
|
||||
hasTemplateStub.withArgs('error-503').returns(true);
|
||||
|
||||
templates.error(500).should.eql('error-5xx');
|
||||
templates.error(503).should.eql('error-503');
|
||||
templates.error(422).should.eql('error');
|
||||
templates.error(404).should.eql('error');
|
||||
_private.getTemplateForError(500).should.eql('error-5xx');
|
||||
_private.getTemplateForError(503).should.eql('error-503');
|
||||
_private.getTemplateForError(422).should.eql('error');
|
||||
_private.getTemplateForError(404).should.eql('error');
|
||||
});
|
||||
|
||||
it('cascade works with many specific templates', function () {
|
||||
|
@ -363,12 +364,178 @@ describe('templates', function () {
|
|||
hasTemplateStub.withArgs('error-4xx').returns(true);
|
||||
hasTemplateStub.withArgs('error-404').returns(true);
|
||||
|
||||
templates.error(500).should.eql('error-5xx');
|
||||
templates.error(503).should.eql('error-503');
|
||||
templates.error(422).should.eql('error-4xx');
|
||||
templates.error(404).should.eql('error-404');
|
||||
templates.error(401).should.eql('error-4xx');
|
||||
templates.error(501).should.eql('error-5xx');
|
||||
_private.getTemplateForError(500).should.eql('error-5xx');
|
||||
_private.getTemplateForError(503).should.eql('error-503');
|
||||
_private.getTemplateForError(422).should.eql('error-4xx');
|
||||
_private.getTemplateForError(404).should.eql('error-404');
|
||||
_private.getTemplateForError(401).should.eql('error-4xx');
|
||||
_private.getTemplateForError(501).should.eql('error-5xx');
|
||||
});
|
||||
});
|
||||
|
||||
describe('setTemplate', function () {
|
||||
var stubs = {}, req, res, data;
|
||||
|
||||
beforeEach(function () {
|
||||
req = {};
|
||||
res = {
|
||||
locals: {}
|
||||
};
|
||||
data = {};
|
||||
|
||||
stubs.pickTemplate = sandbox.stub(_private, 'pickTemplate').returns('testFromPickTemplate');
|
||||
stubs.getTemplateForEntry = sandbox.stub(_private, 'getTemplateForEntry').returns('testFromEntry');
|
||||
stubs.getTemplateForChannel = sandbox.stub(_private, 'getTemplateForChannel').returns('testFromChannel');
|
||||
stubs.getTemplateForError = sandbox.stub(_private, 'getTemplateForError').returns('testFromError');
|
||||
});
|
||||
|
||||
it('does nothing if template is already set', function () {
|
||||
// Pre-set template
|
||||
res._template = 'thing';
|
||||
|
||||
// Call setTemplate
|
||||
templates.setTemplate(req, res, data);
|
||||
|
||||
// It hasn't changed
|
||||
res._template.should.eql('thing');
|
||||
|
||||
// And nothing got called
|
||||
stubs.pickTemplate.called.should.be.false();
|
||||
stubs.getTemplateForEntry.called.should.be.false();
|
||||
stubs.getTemplateForChannel.called.should.be.false();
|
||||
stubs.getTemplateForError.called.should.be.false();
|
||||
});
|
||||
|
||||
it('defaults to index', function () {
|
||||
// No route or template config here!!!
|
||||
|
||||
// Call setTemplate
|
||||
templates.setTemplate(req, res, data);
|
||||
|
||||
// It should be index
|
||||
res._template.should.eql('index');
|
||||
|
||||
// And nothing got called
|
||||
stubs.pickTemplate.called.should.be.false();
|
||||
stubs.getTemplateForEntry.called.should.be.false();
|
||||
stubs.getTemplateForChannel.called.should.be.false();
|
||||
stubs.getTemplateForError.called.should.be.false();
|
||||
});
|
||||
|
||||
it('calls pickTemplate for custom routes', function () {
|
||||
res._route = {
|
||||
type: 'custom',
|
||||
templateName: 'test',
|
||||
defaultTemplate: 'path/to/local/test.hbs'
|
||||
};
|
||||
|
||||
// Call setTemplate
|
||||
templates.setTemplate(req, res, data);
|
||||
|
||||
// should be testFromPickTemplate
|
||||
res._template.should.eql('testFromPickTemplate');
|
||||
|
||||
// Only pickTemplate got called
|
||||
stubs.pickTemplate.called.should.be.true();
|
||||
stubs.getTemplateForEntry.called.should.be.false();
|
||||
stubs.getTemplateForChannel.called.should.be.false();
|
||||
stubs.getTemplateForError.called.should.be.false();
|
||||
|
||||
stubs.pickTemplate.calledWith('test', 'path/to/local/test.hbs').should.be.true();
|
||||
});
|
||||
|
||||
it('calls pickTemplate for custom routes', function () {
|
||||
res._route = {
|
||||
type: 'custom',
|
||||
templateName: 'test',
|
||||
defaultTemplate: 'path/to/local/test.hbs'
|
||||
};
|
||||
|
||||
// Call setTemplate
|
||||
templates.setTemplate(req, res, data);
|
||||
|
||||
// should be testFromPickTemplate
|
||||
res._template.should.eql('testFromPickTemplate');
|
||||
|
||||
// Only pickTemplate got called
|
||||
stubs.pickTemplate.called.should.be.true();
|
||||
stubs.getTemplateForEntry.called.should.be.false();
|
||||
stubs.getTemplateForChannel.called.should.be.false();
|
||||
stubs.getTemplateForError.called.should.be.false();
|
||||
|
||||
stubs.pickTemplate.calledWith('test', 'path/to/local/test.hbs').should.be.true();
|
||||
});
|
||||
|
||||
it('calls getTemplateForEntry for entry routes', function () {
|
||||
res._route = {
|
||||
type: 'entry'
|
||||
};
|
||||
|
||||
// Requires a post to be set
|
||||
data = {post: {slug: 'test'}};
|
||||
|
||||
// Call setTemplate
|
||||
templates.setTemplate(req, res, data);
|
||||
|
||||
// should be getTemplateForEntry
|
||||
res._template.should.eql('testFromEntry');
|
||||
|
||||
// Only pickTemplate got called
|
||||
stubs.pickTemplate.called.should.be.false();
|
||||
stubs.getTemplateForEntry.called.should.be.true();
|
||||
stubs.getTemplateForChannel.called.should.be.false();
|
||||
stubs.getTemplateForError.called.should.be.false();
|
||||
|
||||
stubs.getTemplateForEntry.calledWith({slug: 'test'}).should.be.true();
|
||||
});
|
||||
|
||||
it('calls getTemplateForChannel for channel routes', function () {
|
||||
res._route = {
|
||||
type: 'channel'
|
||||
};
|
||||
|
||||
res.locals.channel = {testChannel: 'test'};
|
||||
|
||||
// Call setTemplate
|
||||
templates.setTemplate(req, res, data);
|
||||
|
||||
// should be testFromChannel
|
||||
res._template.should.eql('testFromChannel');
|
||||
|
||||
// Only pickTemplate got called
|
||||
stubs.pickTemplate.called.should.be.false();
|
||||
stubs.getTemplateForEntry.called.should.be.false();
|
||||
stubs.getTemplateForChannel.called.should.be.true();
|
||||
stubs.getTemplateForError.called.should.be.false();
|
||||
|
||||
stubs.getTemplateForChannel.calledWith({testChannel: 'test'}).should.be.true();
|
||||
});
|
||||
|
||||
it('calls getTemplateForError if there is an error', function () {
|
||||
// Make the config look like a custom route
|
||||
res._route = {
|
||||
type: 'custom',
|
||||
templateName: 'test',
|
||||
defaultTemplate: 'path/to/local/test.hbs'
|
||||
};
|
||||
|
||||
// Setup an error
|
||||
res.statusCode = 404;
|
||||
req.err = new Error();
|
||||
|
||||
// Call setTemplate
|
||||
templates.setTemplate(req, res, data);
|
||||
|
||||
// should be testFromError
|
||||
res._template.should.eql('testFromError');
|
||||
|
||||
// Only pickTemplate got called
|
||||
stubs.pickTemplate.called.should.be.false();
|
||||
stubs.getTemplateForEntry.called.should.be.false();
|
||||
stubs.getTemplateForChannel.called.should.be.false();
|
||||
stubs.getTemplateForError.called.should.be.true();
|
||||
|
||||
stubs.getTemplateForError.calledWith(404).should.be.true();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue