Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plugin API Refactor: Filter and Theme Helpers #931

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 55 additions & 23 deletions core/ghost.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ var config = require('../config'),
instance,
defaults;

when.pipeline = require('when/pipeline');

// ## Default values
/**
* A hash of default values to use instead of 'magic' numbers/strings.
Expand Down Expand Up @@ -182,8 +184,6 @@ Ghost.prototype.init = function () {
return when.join(
// Check for or initialise a dbHash.
initDbHashAndFirstRun(),
// Initialize plugins
self.initPlugins(),
// Initialize the permissions actions and objects
permissions.init()
);
Expand Down Expand Up @@ -282,6 +282,19 @@ Ghost.prototype.registerThemeHelper = function (name, fn) {
hbs.registerHelper(name, fn);
};

// Register an async handlebars helper for themes
Ghost.prototype.registerAsyncThemeHelper = function (name, fn) {
hbs.registerAsyncHelper(name, function (options, cb) {
// Wrap the function passed in with a when.resolve so it can
// return either a promise or a value
when.resolve(fn(options)).then(function (result) {
cb(result);
}).otherwise(function (err) {
errors.logAndThrowError(err, "registerAsyncThemeHelper: " + name);
});
});
};

// Register a new filter callback function
Ghost.prototype.registerFilter = function (name, priority, fn) {
// Curry the priority optional parameter to a default of 5
Expand Down Expand Up @@ -312,43 +325,62 @@ Ghost.prototype.unregisterFilter = function (name, priority, fn) {
};

// Execute filter functions in priority order
Ghost.prototype.doFilter = function (name, args, callback) {
var callbacks = this.filterCallbacks[name];
Ghost.prototype.doFilter = function (name, args) {
var callbacks = this.filterCallbacks[name],
priorityCallbacks = [];

// Bug out early if no callbacks by that name
if (!callbacks) {
return callback(args);
return when.resolve(args);
}

// For each priorityLevel
_.times(defaults.maxPriority + 1, function (priority) {
// Bug out if no handlers on this priority
if (!_.isArray(callbacks[priority])) {
return;
}

// Call each handler for this priority level
_.each(callbacks[priority], function (filterHandler) {
try {
args = filterHandler(args);
} catch (e) {
// If a filter causes an error, we log it so that it can be debugged, but do not throw the error
errors.logError(e);
// Add a function that runs its priority level callbacks in a pipeline
priorityCallbacks.push(function (currentArgs) {
// Bug out if no handlers on this priority
if (!_.isArray(callbacks[priority])) {
return when.resolve(currentArgs);
}

// Call each handler for this priority level, allowing for promises or values
return when.pipeline(callbacks[priority], currentArgs);
});
});

callback(args);
return when.pipeline(priorityCallbacks, args);
};

// Initialise plugins. Will load from config.activePlugins by default
Ghost.prototype.initPlugins = function (pluginsToLoad) {
pluginsToLoad = pluginsToLoad || models.Settings.activePlugins;
pluginsToLoad = pluginsToLoad || JSON.parse(this.settings('activePlugins'));

var self = this;

return plugins.init(this, pluginsToLoad).then(function (loadedPlugins) {
// Extend the loadedPlugins onto the available plugins
_.extend(self.availablePlugins, loadedPlugins);
// If no activePlugins defined in config settings, look in database settings.
if (!_.isArray(pluginsToLoad)) {
// The value will be resolved in the promise
pluginsToLoad = models.Settings.read("activePlugins").then(function (activePluginsSetting) {
var settingValue = activePluginsSetting.get('value') || '[]';

try {
// We have to parse the value because it's a string
settingValue = JSON.parse(settingValue) || [];
} catch (e) {
return when.reject(new Error("Failed to parse activePlugins setting value: " + e.message));
}

// Resolve with the array value
return when.resolve(settingValue);
});
}

return when(pluginsToLoad).then(function (pluginsToLoadValue) {
return plugins.init(self, pluginsToLoad).then(function (loadedPlugins) {
// Extend the loadedPlugins onto the available plugins
_.extend(self.availablePlugins, loadedPlugins);
});
}, errors.logAndThrowError);
};

module.exports = Ghost;
module.exports = Ghost;
36 changes: 22 additions & 14 deletions core/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -445,22 +445,30 @@ when(ghost.init()).then(function () {
loading.resolve();
}

// ## Start Ghost App
if (getSocket()) {
// Make sure the socket is gone before trying to create another
fs.unlink(getSocket(), function (err) {
// Expose the express server on the ghost instance.
ghost.server = server;

// Initialize plugins then start the server
ghost.initPlugins().then(function () {

This comment was marked as abuse.


// ## Start Ghost App
if (getSocket()) {
// Make sure the socket is gone before trying to create another
fs.unlink(getSocket(), function (err) {
server.listen(
getSocket(),
startGhost
);
fs.chmod(getSocket(), '0744');
});

} else {
server.listen(
getSocket(),
ghost.config().server.port,
ghost.config().server.host,
startGhost
);
fs.chmod(getSocket(), '0744');
});
}

} else {
server.listen(
ghost.config().server.port,
ghost.config().server.host,
startGhost
);
}
});
}, errors.logAndThrowError);
8 changes: 3 additions & 5 deletions core/server/controllers/frontend.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ frontendControllers = {
}

api.posts.browse(options).then(function (page) {

var maxPage = page.pages;

// A bit of a hack for situations with no content.
Expand All @@ -56,7 +55,7 @@ frontendControllers = {
}

// Render the page of posts
ghost.doFilter('prePostsRender', page.posts, function (posts) {
ghost.doFilter('prePostsRender', page.posts).then(function (posts) {
res.render('index', {posts: posts, pagination: {page: page.page, prev: page.prev, next: page.next, limit: page.limit, total: page.total, pages: page.pages}});
});
}).otherwise(function (err) {
Expand All @@ -66,7 +65,7 @@ frontendControllers = {
'single': function (req, res, next) {
api.posts.read({'slug': req.params.slug}).then(function (post) {
if (post) {
ghost.doFilter('prePostsRender', post, function (post) {
ghost.doFilter('prePostsRender', post).then(function (post) {
res.render('post', {post: post});
});
} else {
Expand Down Expand Up @@ -117,7 +116,7 @@ frontendControllers = {
return res.redirect('/rss/' + maxPage + '/');
}

ghost.doFilter('prePostsRender', page.posts, function (posts) {
ghost.doFilter('prePostsRender', page.posts).then(function (posts) {
posts.forEach(function (post) {
var item = {
title: _.escape(post.title),
Expand Down Expand Up @@ -148,7 +147,6 @@ frontendControllers = {
return next(new Error(err));
});
}

};

module.exports = frontendControllers;
Loading