mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-22 10:21:36 +03:00
597ec51afb
refs https://linear.app/tryghost/issue/CORE-104/decouple-frontend-routing-events-from-urlserver-events - The 'router.created' event should eventually be killed. For now the aim is to create a clear communication pathway between frontend's routing module and the URL service (similar to the frontend bridge concept on the "server" side)
143 lines
4.6 KiB
JavaScript
143 lines
4.6 KiB
JavaScript
const debug = require('@tryghost/debug')('routing:static-routes-router');
|
|
const errors = require('@tryghost/errors');
|
|
const urlUtils = require('../../../shared/url-utils');
|
|
const RSSRouter = require('./RSSRouter');
|
|
const controllers = require('./controllers');
|
|
const middlewares = require('./middlewares');
|
|
const ParentRouter = require('./ParentRouter');
|
|
const bootstrap = require('./bootstrap');
|
|
|
|
/**
|
|
* @description Template routes allow you to map individual URLs to specific template files within a Ghost theme
|
|
*/
|
|
class StaticRoutesRouter extends ParentRouter {
|
|
constructor(mainRoute, object) {
|
|
super('StaticRoutesRouter');
|
|
|
|
this.route = {value: mainRoute};
|
|
this.templates = object.templates || [];
|
|
this.data = object.data || {query: {}, router: {}};
|
|
this.routerName = mainRoute === '/' ? 'index' : mainRoute.replace(/\//g, '');
|
|
|
|
debug(this.route.value, this.templates);
|
|
|
|
// CASE 1: Route is channel (controller: channel) - a stream of posts
|
|
// CASE 2: Route is just a static page e.g. landing page
|
|
if (this.isChannel(object)) {
|
|
this.templates = this.templates.reverse();
|
|
this.rss = object.rss !== false;
|
|
this.filter = object.filter;
|
|
this.limit = object.limit;
|
|
this.order = object.order;
|
|
|
|
this.controller = object.controller;
|
|
|
|
debug(this.route.value, this.templates, this.filter, this.data);
|
|
this._registerChannelRoutes();
|
|
} else {
|
|
this.contentType = object.content_type;
|
|
debug(this.route.value, this.templates);
|
|
this._registerStaticRoute();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @description Register all channel routes of this router (...if the router is a channel)
|
|
* @private
|
|
*/
|
|
_registerChannelRoutes() {
|
|
// REGISTER: prepare context object
|
|
this.router().use(this._prepareChannelContext.bind(this));
|
|
|
|
// REGISTER: is rss enabled?
|
|
if (this.rss) {
|
|
this.rssRouter = new RSSRouter();
|
|
this.mountRouter(this.route.value, this.rssRouter.router());
|
|
}
|
|
|
|
// REGISTER: channel route
|
|
this.mountRoute(this.route.value, controllers[this.controller]);
|
|
|
|
// REGISTER: pagination
|
|
this.router().param('page', middlewares.pageParam);
|
|
this.mountRoute(urlUtils.urlJoin(this.route.value, 'page', ':page(\\d+)'), controllers[this.controller]);
|
|
|
|
bootstrap.internal.routerCreated(this);
|
|
}
|
|
|
|
/**
|
|
* @description Prepare channel context for further middlewares/controllers.
|
|
* @param {Object} req
|
|
* @param {Object} res
|
|
* @param {Function} next
|
|
* @private
|
|
*/
|
|
_prepareChannelContext(req, res, next) {
|
|
res.routerOptions = {
|
|
type: this.controller,
|
|
name: this.routerName,
|
|
context: [this.routerName],
|
|
filter: this.filter,
|
|
limit: this.limit,
|
|
order: this.order,
|
|
data: this.data.query,
|
|
templates: this.templates
|
|
};
|
|
|
|
next();
|
|
}
|
|
|
|
/**
|
|
* @description Register all static routes of this router (...if the router is just a static route)
|
|
* @private
|
|
*/
|
|
_registerStaticRoute() {
|
|
// REGISTER: prepare context object
|
|
this.router().use(this._prepareStaticRouteContext.bind(this));
|
|
|
|
// REGISTER: static route
|
|
this.mountRoute(this.route.value, controllers.static);
|
|
|
|
bootstrap.internal.routerCreated(this);
|
|
}
|
|
|
|
/**
|
|
* @description Prepare static route context for further middlewares/controllers.
|
|
* @param {Object} req
|
|
* @param {Object} res
|
|
* @param {Function} next
|
|
* @private
|
|
*/
|
|
_prepareStaticRouteContext(req, res, next) {
|
|
res.routerOptions = {
|
|
type: 'custom',
|
|
templates: this.templates,
|
|
defaultTemplate: () => {
|
|
throw new errors.IncorrectUsageError({
|
|
message: `Missing template ${res.routerOptions.templates.map(x => `${x}.hbs`).join(', ')} for route "${req.originalUrl}".`
|
|
});
|
|
},
|
|
data: this.data.query,
|
|
context: [this.routerName],
|
|
contentType: this.contentType
|
|
};
|
|
|
|
next();
|
|
}
|
|
|
|
/**
|
|
* @description Helper function to figure out if this router is a channel.
|
|
* @param {Object} object
|
|
* @returns {boolean}
|
|
*/
|
|
isChannel(object) {
|
|
if (object && object.controller && object.controller === 'channel') {
|
|
return true;
|
|
}
|
|
|
|
return this.controller === 'channel';
|
|
}
|
|
}
|
|
|
|
module.exports = StaticRoutesRouter;
|