Helper Proxy & single express-hbs instance (#8225)

refs #8126, #8221, #8223

 New 'Proxy' for all helper requires
- this is not currently enforced, but could be, much like apps
- the proxy object is HUGE
- changed date to use SafeString, this should have been there anyway
- use the proxy for all helpers, including those in apps 😁

 🎨 Single instance of hbs for theme + for errors
- we now have theme/engine instead of requiring express-hbs everywhere
- only error-handler still also requires express-hbs, this is so that we can render errors without extra crud
- TODO: remove the asset helper after #8126 IF it is not needed, or else remove the TODO

🎨 Cleanup visibility utils
🎨 Clean up the proxy a little bit
🚨 Unskip test as it now works!
🎨 Minor amends as per comments
This commit is contained in:
Hannah Wolfe 2017-04-04 17:07:35 +01:00 committed by Katharina Irrgang
parent d4836af18a
commit 243b387063
57 changed files with 467 additions and 413 deletions

View File

@ -7,7 +7,9 @@
// Here's the list of all supported extended components: https://www.ampproject.org/docs/reference/extended.html
// By default supported AMP HTML tags (no additional script tag necessary):
// amp-img, amp-ad, amp-embed, amp-video and amp-pixel.
var hbs = require('express-hbs');
// (less) dirty requires
var proxy = require('../../../../helpers/proxy'),
SafeString = proxy.SafeString;
function ampComponents() {
var components = [],
@ -29,7 +31,7 @@ function ampComponents() {
components.push('<script async custom-element="amp-audio" src="https://cdn.ampproject.org/v0/amp-audio-0.1.js"></script>');
}
return new hbs.handlebars.SafeString(components.join('\n'));
return new SafeString(components.join('\n'));
}
module.exports = ampComponents;

View File

@ -6,16 +6,19 @@
//
// Converts normal HTML into AMP HTML with Amperize module and uses a cache to return it from
// there if available. The cacheId is a combination of `updated_at` and the `slug`.
var hbs = require('express-hbs'),
Promise = require('bluebird'),
moment = require('moment'),
logging = require('../../../../logging'),
i18n = require('../../../../i18n'),
errors = require('../../../../errors'),
makeAbsoluteUrl = require('../../../../utils/make-absolute-urls'),
utils = require('../../../../utils'),
amperizeCache = {},
allowedAMPTags = [],
var Promise = require('bluebird'),
moment = require('moment'),
// (less) dirty requires
proxy = require('../../../../helpers/proxy'),
SafeString = proxy.SafeString,
logging = proxy.logging,
i18n = proxy.i18n,
errors = proxy.errors,
makeAbsoluteUrl = require('../../../../utils/make-absolute-urls'),
utils = require('../../../../utils'),
amperizeCache = {},
allowedAMPTags = [],
allowedAMPAttributes = {},
amperize,
cleanHTML,
@ -190,7 +193,7 @@ function ampContent() {
selfClosing: ['source', 'track']
});
return new hbs.handlebars.SafeString(cleanHTML);
return new SafeString(cleanHTML);
});
}

View File

@ -6,12 +6,12 @@
// We use the name input_password to match the helper for consistency:
// jscs:disable requireCamelCaseOrUpperCaseIdentifiers
// Dirty requires
var hbs = require('express-hbs'),
utils = require('../../../../helpers/utils'),
input_password;
// (less) dirty requires
var proxy = require('../../../../helpers/proxy'),
SafeString = proxy.SafeString,
templates = proxy.templates;
input_password = function (options) {
module.exports = function input_password(options) {
options = options || {};
options.hash = options.hash || {};
@ -23,14 +23,12 @@ input_password = function (options) {
extras += ' placeholder="' + options.hash.placeholder + '"';
}
output = utils.inputTemplate({
output = templates.input({
type: 'password',
name: 'password',
className: className,
extras: extras
});
return new hbs.handlebars.SafeString(output);
return new SafeString(output);
};
module.exports = input_password;

View File

@ -1,6 +1,6 @@
var _ = require('lodash'),
api = require('../api'),
helpers = require('../helpers'),
helpers = require('../helpers/register'),
filters = require('../filters'),
i18n = require('../i18n'),
generateProxyFunctions;

View File

@ -6,12 +6,12 @@
// We use the name input_email to match the helper for consistency:
// jscs:disable requireCamelCaseOrUpperCaseIdentifiers
// Dirty requires
var hbs = require('express-hbs'),
utils = require('../../../../helpers/utils'),
input_email;
// (less) dirty requires
var proxy = require('../../../../helpers/proxy'),
SafeString = proxy.SafeString,
templates = proxy.templates;
input_email = function (options) {
module.exports = function input_email(options) {
options = options || {};
options.hash = options.hash || {};
@ -31,14 +31,13 @@ input_email = function (options) {
extras += ' value="' + options.hash.value + '"';
}
output = utils.inputTemplate({
output = templates.input({
type: 'email',
name: 'email',
className: className,
extras: extras
});
return new hbs.handlebars.SafeString(output);
return new SafeString(output);
};
module.exports = input_email;

View File

@ -5,20 +5,19 @@
// jscs:disable requireCamelCaseOrUpperCaseIdentifiers
var _ = require('lodash'),
// Dirty requires
hbs = require('express-hbs'),
config = require('../../../../config'),
template = require('../../../../helpers/template'),
utils = require('../../../../helpers/utils'),
globalUtils = require('../../../../utils'),
// (Less) dirty requires
proxy = require('../../../../helpers/proxy'),
templates = proxy.templates,
config = proxy.config,
url = proxy.url,
SafeString = proxy.SafeString,
params = ['error', 'success', 'email'],
subscribe_form,
subscribeScript;
function makeHidden(name, extras) {
return utils.inputTemplate({
return templates.input({
type: 'hidden',
name: name,
className: name,
@ -39,19 +38,17 @@ subscribeScript =
'})(window,document,\'querySelector\',\'value\');' +
'</script>';
subscribe_form = function (options) {
module.exports = function subscribe_form(options) {
var root = options.data.root,
data = _.merge({}, options.hash, _.pick(root, params), {
action: globalUtils.url.urlJoin('/', globalUtils.url.getSubdir(), config.get('routeKeywords').subscribe, '/'),
script: new hbs.handlebars.SafeString(subscribeScript),
hidden: new hbs.handlebars.SafeString(
action: url.urlJoin('/', url.getSubdir(), config.get('routeKeywords').subscribe, '/'),
script: new SafeString(subscribeScript),
hidden: new SafeString(
makeHidden('confirm') +
makeHidden('location', root.subscribed_url ? 'value=' + root.subscribed_url : '') +
makeHidden('referrer', root.subscribed_referrer ? 'value=' + root.subscribed_referrer : '')
)
});
return template.execute('subscribe_form', data, options);
return templates.execute('subscribe_form', data, options);
};
module.exports = subscribe_form;

View File

@ -1,4 +1,4 @@
var visibilityFilter = require('../../utils/visibility-filter');
var visibilityFilter = require('../../utils/visibility').filter;
function getKeywords(data) {
if (data.post && data.post.tags && data.post.tags.length > 0) {

View File

@ -1,7 +1,6 @@
var config = require('../../config'),
hbs = require('express-hbs'),
escapeExpression = require('../../themes/engine').escapeExpression,
socialUrls = require('../../utils/social-urls'),
escapeExpression = hbs.handlebars.Utils.escapeExpression,
_ = require('lodash');
function schemaImageObject(metaDataVal) {

View File

@ -2,12 +2,12 @@
// Usage: `{{asset "css/screen.css"}}`, `{{asset "css/screen.css" ghost="true"}}`
//
// Returns the path to the specified asset. The ghost flag outputs the asset path for the Ghost admin
var proxy = require('./proxy'),
config = proxy.config,
getAssetUrl = proxy.metaData.getAssetUrl,
SafeString = proxy.SafeString;
var config = require('../config'),
getAssetUrl = require('../data/meta/asset_url'),
hbs = require('express-hbs');
function asset(path, options) {
module.exports = function asset(path, options) {
var isAdmin,
minify;
@ -20,9 +20,7 @@ function asset(path, options) {
minify = false;
}
return new hbs.handlebars.SafeString(
return new SafeString(
getAssetUrl(path, isAdmin, minify)
);
}
module.exports = asset;
};

View File

@ -10,15 +10,16 @@
// Block helper: `{{#author}}{{/author}}`
// This is the default handlebars behaviour of dropping into the author object scope
var hbs = require('express-hbs'),
_ = require('lodash'),
utils = require('../utils'),
localUtils = require('./utils'),
author;
var proxy = require('./proxy'),
_ = require('lodash'),
SafeString = proxy.SafeString,
handlebars = proxy.hbs.handlebars,
templates = proxy.templates,
url = proxy.url;
author = function (options) {
module.exports = function author(options) {
if (options.fn) {
return hbs.handlebars.helpers.with.call(this, this.author, options);
return handlebars.helpers.with.call(this, this.author, options);
}
var autolink = _.isString(options.hash.autolink) && options.hash.autolink === 'false' ? false : true,
@ -26,8 +27,8 @@ author = function (options) {
if (this.author && this.author.name) {
if (autolink) {
output = localUtils.linkTemplate({
url: utils.url.urlFor('author', {author: this.author}),
output = templates.link({
url: url.urlFor('author', {author: this.author}),
text: _.escape(this.author.name)
});
} else {
@ -35,7 +36,5 @@ author = function (options) {
}
}
return new hbs.handlebars.SafeString(output);
return new SafeString(output);
};
module.exports = author;

View File

@ -6,11 +6,11 @@
// We use the name body_class to match the helper for consistency:
// jscs:disable requireCamelCaseOrUpperCaseIdentifiers
var hbs = require('express-hbs'),
_ = require('lodash'),
body_class;
var proxy = require('./proxy'),
_ = require('lodash'),
SafeString = proxy.SafeString;
body_class = function (options) {
module.exports = function body_class(options) {
var classes = [],
context = options.data.root.context,
post = this.post,
@ -43,7 +43,6 @@ body_class = function (options) {
}
classes = _.reduce(classes, function (memo, item) { return memo + ' ' + item; }, '');
return new hbs.handlebars.SafeString(classes.trim());
return new SafeString(classes.trim());
};
module.exports = body_class;

View File

@ -6,12 +6,12 @@
//
// Enables tag-safe truncation of content by characters or words.
var hbs = require('express-hbs'),
_ = require('lodash'),
downsize = require('downsize'),
content;
var proxy = require('./proxy'),
_ = require('lodash'),
downsize = require('downsize'),
SafeString = proxy.SafeString;
content = function (options) {
module.exports = function content(options) {
var truncateOptions = (options || {}).hash || {};
truncateOptions = _.pick(truncateOptions, ['words', 'characters']);
_.keys(truncateOptions).map(function (key) {
@ -19,12 +19,10 @@ content = function (options) {
});
if (truncateOptions.hasOwnProperty('words') || truncateOptions.hasOwnProperty('characters')) {
return new hbs.handlebars.SafeString(
return new SafeString(
downsize(this.html, truncateOptions)
);
}
return new hbs.handlebars.SafeString(this.html);
return new SafeString(this.html);
};
module.exports = content;

View File

@ -3,11 +3,13 @@
//
// Formats a date using moment-timezone.js. Formats published_at by default but will also take a date as a parameter
var moment = require('moment-timezone'),
date,
timezone;
var proxy = require('./proxy'),
moment = require('moment-timezone'),
SafeString = proxy.SafeString;
module.exports = function (date, options) {
var timezone, format, timeago, timeNow;
date = function (date, options) {
if (!options && date.hasOwnProperty('hash')) {
options = date;
date = undefined;
@ -23,17 +25,15 @@ date = function (date, options) {
// ensure that context is undefined, not null, as that can cause errors
date = date === null ? undefined : date;
var f = options.hash.format || 'MMM DD, YYYY',
timeago = options.hash.timeago,
timeNow = moment().tz(timezone);
format = options.hash.format || 'MMM DD, YYYY';
timeago = options.hash.timeago;
timeNow = moment().tz(timezone);
if (timeago) {
date = timezone ? moment(date).tz(timezone).from(timeNow) : moment(date).fromNow();
date = timezone ? moment(date).tz(timezone).from(timeNow) : moment(date).fromNow();
} else {
date = timezone ? moment(date).tz(timezone).format(f) : moment(date).format(f);
date = timezone ? moment(date).tz(timezone).format(format) : moment(date).format(format);
}
return date;
return new SafeString(date);
};
module.exports = date;

View File

@ -4,12 +4,10 @@
//
// Returns URI encoded string
var hbs = require('express-hbs'),
encode;
var proxy = require('./proxy'),
SafeString = proxy.SafeString;
encode = function (string, options) {
module.exports = function encode(string, options) {
var uri = string || options;
return new hbs.handlebars.SafeString(encodeURIComponent(uri));
return new SafeString(encodeURIComponent(uri));
};
module.exports = encode;

View File

@ -5,11 +5,12 @@
//
// Defaults to words="50"
var hbs = require('express-hbs'),
_ = require('lodash'),
getMetaDataExcerpt = require('../data/meta/excerpt');
var proxy = require('./proxy'),
_ = require('lodash'),
SafeString = proxy.SafeString,
getMetaDataExcerpt = proxy.metaData.getMetaDataExcerpt;
function excerpt(options) {
module.exports = function excerpt(options) {
var truncateOptions = (options || {}).hash || {};
truncateOptions = _.pick(truncateOptions, ['words', 'characters']);
@ -17,9 +18,7 @@ function excerpt(options) {
truncateOptions[key] = parseInt(truncateOptions[key], 10);
});
return new hbs.handlebars.SafeString(
return new SafeString(
getMetaDataExcerpt(String(this.html), truncateOptions)
);
}
module.exports = excerpt;
};

View File

@ -6,11 +6,11 @@
// We use the name facebook_url to match the helper for consistency:
// jscs:disable requireCamelCaseOrUpperCaseIdentifiers
var socialUrls = require('../utils/social-urls'),
findKey = require('./utils').findKey,
facebook_url;
var proxy = require('./proxy'),
socialUrls = proxy.socialUrls,
findKey = proxy.utils.findKey;
facebook_url = function (username, options) {
module.exports = function facebook_url(username, options) {
if (!options) {
options = username;
username = findKey('facebook', this, options.data.blog);
@ -22,5 +22,3 @@ facebook_url = function (username, options) {
return null;
};
module.exports = facebook_url;

View File

@ -2,23 +2,21 @@
// Usage: `{{#foreach data}}{{/foreach}}`
//
// Block helper designed for looping through posts
var hbs = require('express-hbs'),
_ = require('lodash'),
logging = require('../logging'),
i18n = require('../i18n'),
visibilityFilter = require('../utils/visibility-filter'),
utils = require('./utils'),
hbsUtils = hbs.handlebars.Utils,
foreach;
var proxy = require('./proxy'),
_ = require('lodash'),
logging = proxy.logging,
i18n = proxy.i18n,
visibilityUtils = proxy.visibility,
hbsUtils = proxy.hbs.Utils,
createFrame = proxy.hbs.handlebars.createFrame;
function filterItemsByVisibility(items, options) {
var visibility = utils.parseVisibility(options);
var visibility = visibilityUtils.parser(options);
return visibilityFilter(items, visibility, !!options.hash.visibility);
return visibilityUtils.filter(items, visibility, !!options.hash.visibility);
}
foreach = function (items, options) {
module.exports = function foreach(items, options) {
if (!options) {
logging.warn(i18n.t('warnings.helpers.foreach.iteratorNeeded'));
}
@ -53,7 +51,7 @@ foreach = function (items, options) {
}
if (options.data) {
data = hbs.handlebars.createFrame(options.data);
data = createFrame(options.data);
}
function execIteration(field, index, last) {
@ -73,9 +71,9 @@ foreach = function (items, options) {
}
output = output + fn(items[field], {
data: data,
blockParams: hbsUtils.blockParams([items[field], field], [contextPath + field, null])
});
data: data,
blockParams: hbsUtils.blockParams([items[field], field], [contextPath + field, null])
});
}
function iterateCollection(context) {
@ -109,5 +107,3 @@ foreach = function (items, options) {
return output;
};
module.exports = foreach;

View File

@ -1,15 +1,17 @@
// # Get Helper
// Usage: `{{#get "posts" limit="5"}}`, `{{#get "tags" limit="all"}}`
// Fetches data from the API
var _ = require('lodash'),
hbs = require('express-hbs'),
var proxy = require('./proxy'),
_ = require('lodash'),
Promise = require('bluebird'),
jsonpath = require('jsonpath'),
logging = require('../logging'),
i18n = require('../i18n'),
api = require('../api'),
labs = require('../utils/labs'),
logging = proxy.logging,
i18n = proxy.i18n,
createFrame = proxy.hbs.handlebars.createFrame,
api = proxy.api,
labs = proxy.labs,
resources,
pathAliases,
get;
@ -96,7 +98,7 @@ get = function get(resource, options) {
options.data = options.data || {};
var self = this,
data = hbs.handlebars.createFrame(options.data),
data = createFrame(options.data),
apiOptions = options.hash,
apiMethod;

View File

@ -5,14 +5,13 @@
//
// We use the name ghost_foot to match the helper for consistency:
// jscs:disable requireCamelCaseOrUpperCaseIdentifiers
var hbs = require('express-hbs'),
SafeString = hbs.handlebars.SafeString,
var proxy = require('./proxy'),
_ = require('lodash'),
filters = require('../filters'),
settingsCache = require('../settings/cache'),
ghost_foot;
SafeString = proxy.SafeString,
filters = proxy.filters,
settingsCache = proxy.settingsCache;
ghost_foot = function ghost_foot() {
module.exports = function ghost_foot() {
var foot = [],
codeInjection = settingsCache.get('ghost_foot');
@ -26,5 +25,3 @@ ghost_foot = function ghost_foot() {
return new SafeString(foot.join(' ').trim());
});
};
module.exports = ghost_foot;

View File

@ -6,19 +6,19 @@
// We use the name ghost_head to match the helper for consistency:
// jscs:disable requireCamelCaseOrUpperCaseIdentifiers
var getMetaData = require('../data/meta'),
hbs = require('express-hbs'),
escapeExpression = hbs.handlebars.Utils.escapeExpression,
SafeString = hbs.handlebars.SafeString,
var proxy = require('./proxy'),
_ = require('lodash'),
filters = require('../filters'),
assetHelper = require('./asset'),
config = require('../config'),
Promise = require('bluebird'),
labs = require('../utils/labs'),
utils = require('../utils'),
api = require('../api'),
settingsCache = require('../settings/cache');
getMetaData = proxy.metaData.get,
escapeExpression = proxy.escapeExpression,
SafeString = proxy.SafeString,
filters = proxy.filters,
labs = proxy.labs,
api = proxy.api,
settingsCache = proxy.settingsCache,
config = proxy.config,
url = proxy.url;
function getClient() {
if (labs.isSet('publicAPI') === true) {
@ -66,6 +66,10 @@ function finaliseStructuredData(metaData) {
}
function getAjaxHelper(clientId, clientSecret) {
// @TODO: swap this for a direct utility, rather than using the helper? see #8221
// Note: this is here because the asset helper isn't registered when this file is first loaded
var assetHelper = proxy.hbs.handlebars.helpers.asset;
return '<script type="text/javascript" src="' +
assetHelper('shared/ghost-url.js', {hash: {minifyInProduction: true}}) + '"></script>\n' +
'<script type="text/javascript">\n' +
@ -76,7 +80,7 @@ function getAjaxHelper(clientId, clientSecret) {
'</script>';
}
function ghost_head(options) {
module.exports = function ghost_head(options) {
// if server error page do nothing
if (this.statusCode >= 500) {
return;
@ -97,7 +101,7 @@ function ghost_head(options) {
blogIcon = settingsCache.get('icon'),
// CASE: blog icon is not set in config, we serve the default
iconType = !blogIcon ? 'x-icon' : blogIcon.match(/\/favicon\.ico$/i) ? 'x-icon' : 'png',
favicon = !blogIcon ? '/favicon.ico' : utils.url.urlFor('image', {image: blogIcon});
favicon = !blogIcon ? '/favicon.ico' : url.urlFor('image', {image: blogIcon});
return Promise.props(fetch).then(function (response) {
client = response.client;
@ -162,6 +166,4 @@ function ghost_head(options) {
}).then(function (head) {
return new SafeString(head.join('\n ').trim());
});
}
module.exports = ghost_head;
};

View File

@ -3,12 +3,12 @@
//
// Checks if a post has a particular property
var _ = require('lodash'),
logging = require('../logging'),
i18n = require('../i18n'),
has;
var proxy = require('./proxy'),
_ = require('lodash'),
logging = proxy.logging,
i18n = proxy.i18n;
has = function (options) {
module.exports = function has(options) {
options = options || {};
options.hash = options.hash || {};
@ -33,7 +33,7 @@ has = function (options) {
}
function evaluateAuthorList(expr, author) {
var authorList = expr.split(',').map(function (v) {
var authorList = expr.split(',').map(function (v) {
return v.trim().toLocaleLowerCase();
});
@ -53,5 +53,3 @@ has = function (options) {
}
return options.inverse(this);
};
module.exports = has;

View File

@ -4,15 +4,13 @@
// Returns the URL for the current object scope i.e. If inside a post scope will return image permalink
// `absolute` flag outputs absolute URL, else URL is relative.
var utils = require('../utils'),
image;
var proxy = require('./proxy'),
url = proxy.url;
image = function (options) {
module.exports = function image(options) {
var absolute = options && options.hash.absolute;
if (this.image) {
return utils.url.urlFor('image', {image: this.image}, absolute);
return url.urlFor('image', {image: this.image}, absolute);
}
};
module.exports = image;

View File

@ -1,14 +1,8 @@
var hbs = require('express-hbs'),
Promise = require('bluebird'),
errors = require('../errors'),
config = require('../config'),
coreHelpers = {},
registerHelpers;
// @TODO think about a config option for this e.g. theme.devmode?
if (config.get('env') !== 'production') {
hbs.handlebars.logger.level = 0;
}
var coreHelpers = {},
register = require('./register'),
registerThemeHelper = register.registerThemeHelper,
registerAsyncThemeHelper = register.registerAsyncThemeHelper,
registerAllCoreHelpers;
coreHelpers.asset = require('./asset');
coreHelpers.author = require('./author');
@ -39,38 +33,7 @@ coreHelpers.title = require('./title');
coreHelpers.twitter_url = require('./twitter_url');
coreHelpers.url = require('./url');
// Register an async handlebars helper for a given handlebars instance
function registerAsyncHelper(hbs, name, fn) {
hbs.registerAsyncHelper(name, function (context, options, cb) {
// Handle the case where we only get context and cb
if (!cb) {
cb = options;
options = undefined;
}
// Wrap the function passed in with a when.resolve so it can return either a promise or a value
Promise.resolve(fn.call(this, context, options)).then(function (result) {
cb(result);
}).catch(function (err) {
throw new errors.IncorrectUsageError({
err: err,
context: 'registerAsyncThemeHelper: ' + name
});
});
});
}
// Register a handlebars helper for themes
function registerThemeHelper(name, fn) {
hbs.registerHelper(name, fn);
}
// Register an async handlebars helper for themes
function registerAsyncThemeHelper(name, fn) {
registerAsyncHelper(hbs, name, fn);
}
registerHelpers = function () {
registerAllCoreHelpers = function registerAllCoreHelpers() {
// Register theme helpers
registerThemeHelper('asset', coreHelpers.asset);
registerThemeHelper('author', coreHelpers.author);
@ -105,6 +68,4 @@ registerHelpers = function () {
};
module.exports = coreHelpers;
module.exports.loadCoreHelpers = registerHelpers;
module.exports.registerThemeHelper = registerThemeHelper;
module.exports.registerAsyncThemeHelper = registerAsyncThemeHelper;
module.exports.loadCoreHelpers = registerAllCoreHelpers;

View File

@ -1,12 +1,12 @@
// # Is Helper
// Usage: `{{#is "paged"}}`, `{{#is "index, paged"}}`
// Checks whether we're in a given context.
var _ = require('lodash'),
logging = require('../logging'),
i18n = require('../i18n'),
is;
var proxy = require('./proxy'),
_ = require('lodash'),
logging = proxy.logging,
i18n = proxy.i18n;
is = function (context, options) {
module.exports = function is(context, options) {
options = options || {};
var currentContext = options.data.root.context;
@ -30,4 +30,3 @@ is = function (context, options) {
return options.inverse(this);
};
module.exports = is;

View File

@ -6,7 +6,8 @@
// We use the name meta_description to match the helper for consistency:
// jscs:disable requireCamelCaseOrUpperCaseIdentifiers
var getMetaDataDescription = require('../data/meta/description');
var proxy = require('./proxy'),
getMetaDataDescription = proxy.metaData.getMetaDataDescription;
function meta_description(options) {
options = options || {};

View File

@ -6,7 +6,8 @@
// We use the name meta_title to match the helper for consistency:
// jscs:disable requireCamelCaseOrUpperCaseIdentifiers
var getMetaDataTitle = require('../data/meta/title');
var proxy = require('./proxy'),
getMetaDataTitle = proxy.metaData.getMetaDataTitle;
function meta_title(options) {
return getMetaDataTitle(this, options.data.root);

View File

@ -2,15 +2,14 @@
// `{{navigation}}`
// Outputs navigation menu of static urls
var _ = require('lodash'),
hbs = require('express-hbs'),
i18n = require('../i18n'),
errors = require('../errors'),
template = require('./template'),
navigation;
var proxy = require('./proxy'),
_ = require('lodash'),
SafeString = proxy.SafeString,
i18n = proxy.i18n,
errors = proxy.errors,
templates = proxy.templates;
navigation = function (options) {
/*jshint unused:false*/
module.exports = function navigation(options) {
var navigationData = options.data.blog.navigation,
currentUrl = options.data.root.relativeUrl,
self = this,
@ -58,7 +57,7 @@ navigation = function (options) {
// {{navigation}} should no-op if no data passed in
if (navigationData.length === 0) {
return new hbs.SafeString('');
return new SafeString('');
}
output = navigationData.map(function (e) {
@ -73,7 +72,6 @@ navigation = function (options) {
data = _.merge({}, {navigation: output});
return template.execute('navigation', data, options);
return templates.execute('navigation', data, options);
};
module.exports = navigation;

View File

@ -8,15 +8,13 @@
//
// We use the name page_url to match the helper for consistency:
// jscs:disable requireCamelCaseOrUpperCaseIdentifiers
var getPaginatedUrl = require('../data/meta/paginated_url'),
page_url;
var proxy = require('./proxy'),
getPaginatedUrl = proxy.metaData.getPaginatedUrl;
page_url = function (page, options) {
module.exports = function page_url(page, options) {
if (!options) {
options = page;
page = 1;
}
return getPaginatedUrl(page, options.data.root);
};
module.exports = page_url;

View File

@ -2,10 +2,11 @@
// `{{pagination}}`
// Outputs previous and next buttons, along with info about the current page
var _ = require('lodash'),
errors = require('../errors'),
i18n = require('../i18n'),
template = require('./template'),
var proxy = require('./proxy'),
_ = require('lodash'),
errors = proxy.errors,
i18n = proxy.i18n,
templates = proxy.templates,
pagination;
pagination = function (options) {
@ -37,7 +38,7 @@ pagination = function (options) {
var data = _.merge({}, this.pagination);
return template.execute('pagination', data, options);
return templates.execute('pagination', data, options);
};
module.exports = pagination;

View File

@ -8,13 +8,13 @@
// The 3rd argument is the string that will be output if the variable's value is 1
// The 4th argument is the string that will be output if the variable's value is 2+
var hbs = require('express-hbs'),
errors = require('../errors'),
i18n = require('../i18n'),
_ = require('lodash'),
plural;
var proxy = require('./proxy'),
_ = require('lodash'),
errors = proxy.errors,
i18n = proxy.i18n,
SafeString = proxy.SafeString;
plural = function (number, options) {
module.exports = function plural(number, options) {
if (_.isUndefined(options.hash) || _.isUndefined(options.hash.empty) ||
_.isUndefined(options.hash.singular) || _.isUndefined(options.hash.plural)) {
throw new errors.IncorrectUsageError({
@ -23,12 +23,11 @@ plural = function (number, options) {
}
if (number === 0) {
return new hbs.handlebars.SafeString(options.hash.empty.replace('%', number));
return new SafeString(options.hash.empty.replace('%', number));
} else if (number === 1) {
return new hbs.handlebars.SafeString(options.hash.singular.replace('%', number));
return new SafeString(options.hash.singular.replace('%', number));
} else if (number >= 2) {
return new hbs.handlebars.SafeString(options.hash.plural.replace('%', number));
return new SafeString(options.hash.plural.replace('%', number));
}
};
module.exports = plural;

View File

@ -6,19 +6,20 @@
// We use the name body_class to match the helper for consistency:
// jscs:disable requireCamelCaseOrUpperCaseIdentifiers
var hbs = require('express-hbs'),
_ = require('lodash'),
post_class;
var proxy = require('./proxy'),
_ = require('lodash'),
SafeString = proxy.SafeString;
post_class = function (options) {
/*jshint unused:false*/
module.exports = function post_class() {
var classes = ['post'],
tags = this.post && this.post.tags ? this.post.tags : this.tags || [],
featured = this.post && this.post.featured ? this.post.featured : this.featured || false,
page = this.post && this.post.page ? this.post.page : this.page || false;
if (tags) {
classes = classes.concat(tags.map(function (tag) { return 'tag-' + tag.slug; }));
classes = classes.concat(tags.map(function (tag) {
return 'tag-' + tag.slug;
}));
}
if (featured) {
@ -29,8 +30,8 @@ post_class = function (options) {
classes.push('page');
}
classes = _.reduce(classes, function (memo, item) { return memo + ' ' + item; }, '');
return new hbs.handlebars.SafeString(classes.trim());
classes = _.reduce(classes, function (memo, item) {
return memo + ' ' + item;
}, '');
return new SafeString(classes.trim());
};
module.exports = post_class;

View File

@ -3,12 +3,15 @@
// `{{#prev_post}}<a href ="{{url}}>previous post</a>{{/prev_post}}'
// `{{#next_post}}<a href ="{{url absolute="true">next post</a>{{/next_post}}'
var api = require('../api'),
schema = require('../data/schema').checks,
Promise = require('bluebird'),
fetch, prevNext;
var proxy = require('./proxy'),
Promise = require('bluebird'),
fetch = function (apiOptions, options) {
api = proxy.api,
isPost = proxy.checks.isPost,
fetch;
fetch = function fetch(apiOptions, options) {
return api.posts.read(apiOptions).then(function (result) {
var related = result.posts[0];
@ -25,19 +28,17 @@ fetch = function (apiOptions, options) {
// If prevNext method is called without valid post data then we must return a promise, if there is valid post data
// then the promise is handled in the api call.
prevNext = function (options) {
module.exports = function prevNext(options) {
options = options || {};
var apiOptions = {
include: options.name === 'prev_post' ? 'previous,previous.author,previous.tags' : 'next,next.author,next.tags'
};
if (schema.isPost(this) && this.status === 'published') {
if (isPost(this) && this.status === 'published') {
apiOptions.slug = this.slug;
return fetch(apiOptions, options);
} else {
return Promise.resolve(options.inverse(this));
}
};
module.exports = prevNext;

View File

@ -0,0 +1,81 @@
// This file defines everything that helpers "require"
// With the exception of modules like lodash, Bluebird
// We can later refactor to enforce this something like we do in apps
var hbs = require('../themes/engine'),
_ = require('lodash'),
settingsCache = require('../settings/cache'),
config = require('../config');
// Direct requires:
// - lodash
// - bluebird
// - downsize
// - moment-timezone
// - jsonpath
module.exports = {
hbs: hbs,
SafeString: hbs.SafeString,
escapeExpression: hbs.escapeExpression,
// TODO: Expose less of the API to make this safe
api: require('../api'),
// TODO: Only expose "get"
settingsCache: settingsCache,
// These 3 are kind of core and required all the time
errors: require('../errors'),
i18n: require('../i18n'),
logging: require('../logging'),
// This is used to detect if "isPost" is true in prevNext.
checks: require('../data/schema').checks,
// Config!
// Keys used:
// minifyAssets in asset helper
// isPrivacyDisabled & referrerPolicy used in ghost_head
// Subscribe app uses routeKeywords
config: {
get: config.get.bind(config),
isPrivacyDisabled: config.isPrivacyDisabled.bind(config)
},
// Labs utils for enabling/disabling helpers
labs: require('../utils/labs'),
// System for apps to hook into one day maybe
filters: require('../filters'),
// Things required from data/meta
metaData: {
get: require('../data/meta'), // ghost_head
getAssetUrl: require('../data/meta/asset_url'), // asset
getMetaDataExcerpt: require('../data/meta/excerpt'), // excerpt
getMetaDataDescription: require('../data/meta/description'), // meta_desc
getMetaDataTitle: require('../data/meta/title'), // meta_title
getPaginatedUrl: require('../data/meta/paginated_url'), // page_url
getMetaDataUrl: require('../data/meta/url') // url
},
// The local template thing, should this be merged with the channels one?
templates: require('./template'),
// Various utils, needs cleaning up / simplifying
socialUrls: require('../utils/social-urls'),
url: require('../utils').url,
utils: {
findKey: function findKey(key /* ...objects... */) {
var objects = Array.prototype.slice.call(arguments, 1);
return _.reduceRight(objects, function (result, object) {
if (object && _.has(object, key) && !_.isEmpty(object[key])) {
result = object[key];
}
return result;
}, null);
}
},
visibility: require('../utils/visibility')
};

View File

@ -0,0 +1,34 @@
var hbs = require('../themes/engine'),
Promise = require('bluebird'),
errors = require('../errors');
// Register an async handlebars helper for a given handlebars instance
function asyncHelperWrapper(hbs, name, fn) {
hbs.registerAsyncHelper(name, function returnAsync(context, options, cb) {
// Handle the case where we only get context and cb
if (!cb) {
cb = options;
options = undefined;
}
// Wrap the function passed in with a when.resolve so it can return either a promise or a value
Promise.resolve(fn.call(this, context, options)).then(function (result) {
cb(result);
}).catch(function (err) {
throw new errors.IncorrectUsageError({
err: err,
context: 'registerAsyncThemeHelper: ' + name
});
});
});
}
// Register a handlebars helper for themes
module.exports.registerThemeHelper = function registerThemeHelper(name, fn) {
hbs.registerHelper(name, fn);
};
// Register an async handlebars helper for themes
module.exports.registerAsyncThemeHelper = function registerAsyncThemeHelper(name, fn) {
asyncHelperWrapper(hbs, name, fn);
};

View File

@ -6,14 +6,15 @@
//
// Note that the standard {{#each tags}} implementation is unaffected by this helper
var hbs = require('express-hbs'),
_ = require('lodash'),
utils = require('../utils'),
localUtils = require('./utils'),
visibilityFilter = require('../utils/visibility-filter'),
tags;
var proxy = require('./proxy'),
_ = require('lodash'),
tags = function (options) {
SafeString = proxy.SafeString,
templates = proxy.templates,
url = proxy.url,
visibilityUtils = proxy.visibility;
module.exports = function tags(options) {
options = options || {};
options.hash = options.hash || {};
@ -24,18 +25,18 @@ tags = function (options) {
limit = options.hash.limit ? parseInt(options.hash.limit, 10) : undefined,
from = options.hash.from ? parseInt(options.hash.from, 10) : 1,
to = options.hash.to ? parseInt(options.hash.to, 10) : undefined,
visibility = localUtils.parseVisibility(options),
visibility = visibilityUtils.parser(options),
output = '';
function createTagList(tags) {
function processTag(tag) {
return autolink ? localUtils.linkTemplate({
url: utils.url.urlFor('tag', {tag: tag}),
return autolink ? templates.link({
url: url.urlFor('tag', {tag: tag}),
text: _.escape(tag.name)
}) : _.escape(tag.name);
}
return visibilityFilter(tags, visibility, !!options.hash.visibility, processTag);
return visibilityUtils.filter(tags, visibility, !!options.hash.visibility, processTag);
}
if (this.tags && this.tags.length) {
@ -49,7 +50,5 @@ tags = function (options) {
output = prefix + output + suffix;
}
return new hbs.handlebars.SafeString(output);
return new SafeString(output);
};
module.exports = tags;

View File

@ -1,13 +1,15 @@
var templates = {},
hbs = require('express-hbs'),
errors = require('../errors'),
i18n = require('../i18n');
var templates = {},
_ = require('lodash'),
hbs = require('../themes/engine'),
errors = require('../errors'),
i18n = require('../i18n');
// ## Template utils
// Execute a template helper
// All template helpers are register as partial view.
templates.execute = function (name, context, options) {
templates.execute = function execute(name, context, options) {
var partial = hbs.handlebars.partials[name];
if (partial === undefined) {
@ -21,7 +23,12 @@ templates.execute = function (name, context, options) {
hbs.registerPartial(partial);
}
return new hbs.handlebars.SafeString(partial(context, options));
return new hbs.SafeString(partial(context, options));
};
templates.asset = _.template('<%= source %>?v=<%= version %>');
templates.link = _.template('<a href="<%= url %>"><%= text %></a>');
templates.script = _.template('<script src="<%= source %>?v=<%= version %>"></script>');
templates.input = _.template('<input class="<%= className %>" type="<%= type %>" name="<%= name %>" <%= extras %> />');
module.exports = templates;

View File

@ -3,11 +3,10 @@
//
// Overrides the standard behaviour of `{[title}}` to ensure the content is correctly escaped
var hbs = require('express-hbs'),
title;
var proxy = require('./proxy'),
SafeString = proxy.SafeString,
escapeExpression = proxy.escapeExpression;
title = function () {
return new hbs.handlebars.SafeString(hbs.handlebars.Utils.escapeExpression(this.title || ''));
module.exports = function title() {
return new SafeString(escapeExpression(this.title || ''));
};
module.exports = title;

View File

@ -6,11 +6,11 @@
// We use the name twitter_url to match the helper for consistency:
// jscs:disable requireCamelCaseOrUpperCaseIdentifiers
var socialUrls = require('../utils/social-urls'),
findKey = require('./utils').findKey,
twitter_url;
var proxy = require('./proxy'),
socialUrls = proxy.socialUrls,
findKey = proxy.utils.findKey;
twitter_url = function twitter_url(username, options) {
module.exports = function twitter_url(username, options) {
if (!options) {
options = username;
username = findKey('twitter', this, options.data.blog);
@ -22,5 +22,3 @@ twitter_url = function twitter_url(username, options) {
return null;
};
module.exports = twitter_url;

View File

@ -4,16 +4,15 @@
// Returns the URL for the current object scope i.e. If inside a post scope will return post permalink
// `absolute` flag outputs absolute URL, else URL is relative
var hbs = require('express-hbs'),
getMetaDataUrl = require('../data/meta/url');
var proxy = require('./proxy'),
SafeString = proxy.SafeString,
getMetaDataUrl = proxy.metaData.getMetaDataUrl;
function url(options) {
module.exports = function url(options) {
var absolute = options && options.hash.absolute,
url = getMetaDataUrl(this, absolute);
outputUrl = getMetaDataUrl(this, absolute);
url = encodeURI(decodeURI(url));
outputUrl = encodeURI(decodeURI(outputUrl));
return new hbs.SafeString(url);
}
module.exports = url;
return new SafeString(outputUrl);
};

View File

@ -1,30 +0,0 @@
var _ = require('lodash'),
utils;
utils = {
assetTemplate: _.template('<%= source %>?v=<%= version %>'),
linkTemplate: _.template('<a href="<%= url %>"><%= text %></a>'),
scriptTemplate: _.template('<script src="<%= source %>?v=<%= version %>"></script>'),
inputTemplate: _.template('<input class="<%= className %>" type="<%= type %>" name="<%= name %>" <%= extras %> />'),
// @TODO this can probably be made more generic and used in more places
findKey: function findKey(key, object, data) {
if (object && _.has(object, key) && !_.isEmpty(object[key])) {
return object[key];
}
if (data && _.has(data, key) && !_.isEmpty(data[key])) {
return data[key];
}
return null;
},
parseVisibility: function parseVisibility(options) {
if (!options.hash.visibility) {
return ['public'];
}
return _.map(options.hash.visibility.split(','), _.trim);
}
};
module.exports = utils;

View File

@ -4,9 +4,18 @@ var _ = require('lodash'),
errors = require('../errors'),
i18n = require('../i18n'),
templates = require('../controllers/frontend/templates'),
escapeExpression = hbs.Utils.escapeExpression,
_private = {},
errorHandler = {};
_private.createHbsEngine = function createHbsEngine() {
var engine = hbs.create();
// @TODO get rid of this after #8126
engine.registerHelper('asset', require('../helpers/asset'));
return engine.express4();
};
/**
* This function splits the stack into pieces, that are then rendered using the following handlebars code:
* ```
@ -111,7 +120,7 @@ _private.HTMLErrorRenderer = function HTMLErrorRender(err, req, res, /*jshint un
// 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
if (_.isEmpty(req.app.engines)) {
req.app.engine('hbs', hbs.express3());
req.app.engine('hbs', _private.createHbsEngine());
}
res.render(templates.error(err.statusCode), templateData, function renderResponse(err, html) {
@ -124,9 +133,9 @@ _private.HTMLErrorRenderer = function HTMLErrorRender(err, req, res, /*jshint un
return res.status(500).send(
'<h1>' + i18n.t('errors.errors.oopsErrorTemplateHasError') + '</h1>' +
'<p>' + i18n.t('errors.errors.encounteredError') + '</p>' +
'<pre>' + hbs.handlebars.Utils.escapeExpression(err.message || err) + '</pre>' +
'<pre>' + escapeExpression(err.message || err) + '</pre>' +
'<br ><p>' + i18n.t('errors.errors.whilstTryingToRender') + '</p>' +
err.statusCode + ' ' + '<pre>' + hbs.handlebars.Utils.escapeExpression(err.message || err) + '</pre>'
err.statusCode + ' ' + '<pre>' + escapeExpression(err.message || err) + '</pre>'
);
});
};

View File

@ -20,8 +20,7 @@ var _ = require('lodash'),
join = require('path').join,
themeConfig = require('./config'),
config = require('../config'),
// @TODO: remove this require
hbs = require('express-hbs'),
engine = require('./engine'),
// Current instance of ActiveTheme
currentActiveTheme;
@ -62,17 +61,13 @@ class ActiveTheme {
}
get partialsPath() {
return join(this.path, 'partials');
return this._partials.length > 0 ? join(this.path, 'partials') : null;
}
get mounted() {
return this._mounted;
}
hasPartials() {
return this._partials.length > 0;
}
hasTemplate(templateName) {
return this._templates.indexOf(templateName) > -1;
}
@ -82,17 +77,6 @@ class ActiveTheme {
}
mount(blogApp) {
let hbsOptions = {
partialsDir: [config.get('paths').helperTemplates],
onCompile: function onCompile(exhbs, source) {
return exhbs.handlebars.compile(source, {preventIndent: true});
}
};
if (this.hasPartials()) {
hbsOptions.partialsDir.push(this.partialsPath);
}
// reset the asset hash
// @TODO: set this on the theme instead of globally, or use proper file-based hash
config.set('assetHash', null);
@ -100,7 +84,7 @@ class ActiveTheme {
blogApp.cache = {};
// Set the views and engine
blogApp.set('views', this.path);
blogApp.engine('hbs', hbs.express3(hbsOptions));
blogApp.engine('hbs', engine.configure(this.partialsPath));
this._mounted = true;
}

View File

@ -0,0 +1,27 @@
var hbs = require('express-hbs'),
config = require('../config'),
instance = hbs.create();
// @TODO think about a config option for this e.g. theme.devmode?
if (config.get('env') !== 'production') {
instance.handlebars.logger.level = 0;
}
instance.escapeExpression = instance.handlebars.Utils.escapeExpression;
instance.configure = function configure(partialsPath) {
var hbsOptions = {
partialsDir: [config.get('paths').helperTemplates],
onCompile: function onCompile(exhbs, source) {
return exhbs.handlebars.compile(source, {preventIndent: true});
}
};
if (partialsPath) {
hbsOptions.partialsDir.push(partialsPath);
}
return instance.express4(hbsOptions);
};
module.exports = instance;

View File

@ -1,5 +1,5 @@
var _ = require('lodash'),
hbs = require('express-hbs'),
hbs = require('./engine'),
utils = require('../utils'),
errors = require('../errors'),
i18n = require('../i18n'),

View File

@ -1,7 +1,7 @@
var settingsCache = require('../settings/cache'),
_ = require('lodash'),
Promise = require('bluebird'),
hbs = require('express-hbs'),
SafeString = require('../themes/engine').SafeString,
errors = require('../errors'),
logging = require('../logging'),
i18n = require('../i18n'),
@ -32,7 +32,7 @@ labs.enabledHelper = function enabledHelper(options, callback) {
logging.error(new errors.GhostError(errDetails));
errString = new hbs.handlebars.SafeString(
errString = new SafeString(
'<script>console.error("' + _.values(errDetails).join(' ') + '");</script>'
);

View File

@ -7,7 +7,7 @@ var _ = require('lodash');
* @param {Function} [fn]
* @returns {Array|Object} filtered items
*/
module.exports = function visibilityFilter(items, visibility, explicit, fn) {
module.exports.filter = function visibilityFilter(items, visibility, explicit, fn) {
var memo = _.isArray(items) ? [] : {};
if (_.includes(visibility, 'all')) {
@ -27,3 +27,11 @@ module.exports = function visibilityFilter(items, visibility, explicit, fn) {
return memo;
}, memo);
};
module.exports.parser = function visibilityParser(options) {
if (!options.hash.visibility) {
return ['public'];
}
return _.map(options.hash.visibility.split(','), _.trim);
};

View File

@ -4,7 +4,7 @@ var should = require('should'),
EventEmitter = require('events').EventEmitter,
_ = require('lodash'),
Promise = require('bluebird'),
helpers = require('../../server/helpers'),
helpers = require('../../server/helpers/register'),
filters = require('../../server/filters'),
i18n = require('../../server/i18n'),
@ -218,7 +218,7 @@ describe('Apps', function () {
});
it('allows helper registration with permission', function () {
var registerSpy = sandbox.spy(helpers, 'registerThemeHelper'),
var registerSpy = sandbox.stub(helpers, 'registerThemeHelper'),
appProxy = new AppProxy({
name: 'TestApp',
permissions: {
@ -234,7 +234,7 @@ describe('Apps', function () {
});
it('does not allow helper registration without permission', function () {
var registerSpy = sandbox.spy(helpers, 'registerThemeHelper'),
var registerSpy = sandbox.stub(helpers, 'registerThemeHelper'),
appProxy = new AppProxy({
name: 'TestApp',
permissions: {
@ -255,7 +255,7 @@ describe('Apps', function () {
});
it('does allow INTERNAL app to register helper without permission', function () {
var registerSpy = sandbox.spy(helpers, 'registerThemeHelper'),
var registerSpy = sandbox.stub(helpers, 'registerThemeHelper'),
appProxy = new AppProxy({
name: 'TestApp',
permissions: {},

View File

@ -29,7 +29,7 @@ describe('{{date}} helper', function () {
var rendered = helpers.date.call({published_at: d}, context);
should.exist(rendered);
rendered.should.equal(moment(d).tz(timezones).format(format));
String(rendered).should.equal(moment(d).tz(timezones).format(format));
});
});
@ -57,7 +57,7 @@ describe('{{date}} helper', function () {
var rendered = helpers.date.call({published_at: d}, context);
should.exist(rendered);
rendered.should.equal(moment(d).tz(timezones).from(timeNow));
String(rendered).should.equal(moment(d).tz(timezones).from(timeNow));
});
});
});

View File

@ -3,7 +3,8 @@ var should = require('should'), // jshint ignore:line
_ = require('lodash'),
// Stuff we are testing
helpers = require('../../../server/helpers'),
helpers = require.main.require('core/server/helpers'),
handlebars = require.main.require('core/server/themes/engine').handlebars,
sandbox = sinon.sandbox.create();
@ -250,8 +251,7 @@ describe('{{#foreach}} helper', function () {
});
describe('(compile)', function () {
var handlebars = require('express-hbs').handlebars,
objectHash = {
var objectHash = {
posts: {
first: {title: 'first'},
second: {title: 'second'},

View File

@ -3,7 +3,8 @@ var should = require('should'), // jshint ignore:line
// Stuff we are testing
helpers = require('../../../server/helpers'),
settingsCache = require('../../../server/settings/cache'),
proxy = require('../../../server/helpers/proxy'),
settingsCache = proxy.settingsCache,
sandbox = sinon.sandbox.create();

View File

@ -5,9 +5,10 @@ var should = require('should'), // jshint ignore:line
moment = require('moment'),
configUtils = require('../../utils/configUtils'),
helpers = require('../../../server/helpers'),
api = require('../../../server/api'),
labs = require('../../../server/utils/labs'),
settingsCache = require('../../../server/settings/cache'),
proxy = require('../../../server/helpers/proxy'),
settingsCache = proxy.settingsCache,
api = proxy.api,
labs = proxy.labs,
sandbox = sinon.sandbox.create();

View File

@ -1,5 +1,5 @@
var should = require('should'),
hbs = require('express-hbs'),
hbs = require('../../../server/themes/engine'),
configUtils = require('../../utils/configUtils'),
path = require('path'),

View File

@ -1,5 +1,5 @@
var should = require('should'), // jshint ignore:line
hbs = require('express-hbs'),
hbs = require('../../../server/themes/engine'),
configUtils = require('../../utils/configUtils'),
path = require('path'),

View File

@ -1,7 +1,7 @@
// jscs:disable requireCamelCaseOrUpperCaseIdentifiers
var should = require('should'), // jshint ignore:line
_ = require('lodash'),
hbs = require('express-hbs'),
hbs = require.main.require('core/server/themes/engine'),
// Stuff we are testing
helpers = require.main.require('core/server/helpers');
@ -22,7 +22,7 @@ describe('Helpers', function () {
});
// This will work when we finish refactoring
it.skip('should have exactly the right helpers', function () {
it('should have exactly the right helpers', function () {
var foundHelpers, missingHelpers, unexpectedHelpers;
foundHelpers = _.keys(hbs.handlebars.helpers);

View File

@ -1,8 +1,8 @@
var should = require('should'),
hbs = require('express-hbs'),
hbs = require.main.require('core/server/themes/engine'),
// Stuff we are testing
template = require('../../server/helpers/template');
template = require.main.require('core/server/helpers/template');
describe('Helpers Template', function () {
it('can execute a template', function () {

View File

@ -1,10 +1,10 @@
var should = require('should'), // jshint ignore:line
sinon = require('sinon'),
hbs = require('express-hbs'),
config = require('../../../server/config'),
// is only exposed via themes.getActive()
activeTheme = require('../../../server/themes/active'),
engine = require('../../../server/themes/engine'),
sandbox = sinon.sandbox.create();
@ -15,11 +15,11 @@ describe('Themes', function () {
describe('Active', function () {
describe('Mount', function () {
var hbsStub, configStub,
var engineStub, configStub,
fakeBlogApp, fakeLoadedTheme, fakeCheckedTheme;
beforeEach(function () {
hbsStub = sandbox.stub(hbs, 'express3');
engineStub = sandbox.stub(engine, 'configure');
configStub = sandbox.stub(config, 'set');
fakeBlogApp = {
@ -58,11 +58,9 @@ describe('Themes', function () {
fakeBlogApp.set.calledOnce.should.be.true();
fakeBlogApp.set.calledWith('views', 'my/fake/theme/path').should.be.true();
// Check handlebars was initialised correctly
hbsStub.calledOnce.should.be.true();
hbsStub.firstCall.args[0].should.be.an.Object().and.have.property('partialsDir');
hbsStub.firstCall.args[0].partialsDir.should.be.an.Array().with.lengthOf(2);
hbsStub.firstCall.args[0].partialsDir[1].should.eql('my/fake/theme/path/partials');
// Check handlebars was configured correctly
engineStub.calledOnce.should.be.true();
engineStub.calledWith('my/fake/theme/path/partials').should.be.true();
// Check the theme is now mounted
activeTheme.get().mounted.should.be.true();
@ -91,10 +89,9 @@ describe('Themes', function () {
fakeBlogApp.set.calledOnce.should.be.true();
fakeBlogApp.set.calledWith('views', 'my/fake/theme/path').should.be.true();
// Check handlebars was initialised correctly
hbsStub.calledOnce.should.be.true();
hbsStub.firstCall.args[0].should.be.an.Object().and.have.property('partialsDir');
hbsStub.firstCall.args[0].partialsDir.should.have.lengthOf(1);
// Check handlebars was configured correctly
engineStub.calledOnce.should.be.true();
engineStub.calledWith().should.be.true();
// Check the theme is now mounted
activeTheme.get().mounted.should.be.true();

View File

@ -1,6 +1,6 @@
var should = require('should'), // jshint ignore:line
sinon = require('sinon'),
hbs = require('express-hbs'),
hbs = require('../../../server/themes/engine'),
themes = require('../../../server/themes'),
// is only exposed via themes.getActive()