2017-03-13 23:13:17 +03:00
|
|
|
/**
|
|
|
|
* # Active Theme
|
|
|
|
*
|
|
|
|
* This file defines a class of active theme, and also controls the getting and setting a single instance, as there
|
|
|
|
* can only ever be one active theme. Unlike a singleton, the active theme can change, however only in a controlled way.
|
|
|
|
*
|
|
|
|
* There are several different patterns available for keeping data private. Elsewhere in Ghost we use the
|
|
|
|
* naming convention of the _ prefix. Even though this has the downside of not being truly private, it is still one
|
|
|
|
* of the preferred options for keeping data private with the new class syntax, therefore I have kept it.
|
|
|
|
*
|
|
|
|
* No properties marked with an _ should be used directly.
|
|
|
|
*
|
|
|
|
*/
|
2020-04-29 18:44:27 +03:00
|
|
|
const join = require('path').join;
|
|
|
|
|
|
|
|
const _ = require('lodash');
|
2021-04-23 15:22:45 +03:00
|
|
|
const themeConfig = require('./config');
|
|
|
|
const themeEngines = require('./engines');
|
2020-05-27 20:47:53 +03:00
|
|
|
const config = require('../../../shared/config');
|
2021-04-23 15:22:45 +03:00
|
|
|
const engine = require('./engine');
|
2021-04-26 13:53:15 +03:00
|
|
|
const themeI18n = require('./i18n');
|
2020-04-29 18:44:27 +03:00
|
|
|
|
|
|
|
// Current instance of ActiveTheme
|
|
|
|
let currentActiveTheme;
|
2017-03-13 23:13:17 +03:00
|
|
|
|
|
|
|
class ActiveTheme {
|
|
|
|
/**
|
|
|
|
* @TODO this API needs to be simpler, but for now should work!
|
|
|
|
* @param {object} loadedTheme - the loaded theme object from the theme list
|
|
|
|
* @param {object} checkedTheme - the result of gscan.format for the theme we're activating
|
2017-05-31 19:42:42 +03:00
|
|
|
* @param {object} error - bootstrap validates the active theme, we would like to remember this error
|
2017-03-13 23:13:17 +03:00
|
|
|
*/
|
2017-05-31 19:42:42 +03:00
|
|
|
constructor(loadedTheme, checkedTheme, error) {
|
2017-03-13 23:13:17 +03:00
|
|
|
// Assign some data, mark it all as pseudo-private
|
|
|
|
this._name = loadedTheme.name;
|
|
|
|
this._path = loadedTheme.path;
|
2017-03-21 12:03:09 +03:00
|
|
|
this._mounted = false;
|
2017-05-31 19:42:42 +03:00
|
|
|
this._error = error;
|
2017-03-13 23:13:17 +03:00
|
|
|
|
|
|
|
// @TODO: get gscan to return validated, useful package.json fields for us!
|
|
|
|
this._packageInfo = loadedTheme['package.json'];
|
2018-09-17 21:49:30 +03:00
|
|
|
this._partials = checkedTheme.partials;
|
2017-05-31 19:42:42 +03:00
|
|
|
|
2017-10-10 15:36:35 +03:00
|
|
|
// all custom .hbs templates (e.g. custom-about)
|
|
|
|
this._customTemplates = checkedTheme.templates.custom;
|
|
|
|
|
|
|
|
// all .hbs templates
|
|
|
|
this._templates = checkedTheme.templates.all;
|
2017-03-14 20:03:36 +03:00
|
|
|
|
2017-03-22 09:52:58 +03:00
|
|
|
// Create a theme config object
|
|
|
|
this._config = themeConfig.create(this._packageInfo);
|
2018-10-17 10:23:56 +03:00
|
|
|
|
|
|
|
// Create a theme engines object
|
|
|
|
this._engines = themeEngines.create(this._packageInfo);
|
2021-04-26 13:53:15 +03:00
|
|
|
|
|
|
|
this.initI18n();
|
2017-03-13 23:13:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
get name() {
|
|
|
|
return this._name;
|
|
|
|
}
|
|
|
|
|
2017-10-10 15:36:35 +03:00
|
|
|
get customTemplates() {
|
|
|
|
return this._customTemplates;
|
|
|
|
}
|
|
|
|
|
2017-03-13 23:13:17 +03:00
|
|
|
get path() {
|
|
|
|
return this._path;
|
|
|
|
}
|
|
|
|
|
|
|
|
get partialsPath() {
|
2017-04-04 19:07:35 +03:00
|
|
|
return this._partials.length > 0 ? join(this.path, 'partials') : null;
|
2017-03-13 23:13:17 +03:00
|
|
|
}
|
|
|
|
|
2017-03-21 12:03:09 +03:00
|
|
|
get mounted() {
|
|
|
|
return this._mounted;
|
|
|
|
}
|
|
|
|
|
2017-05-31 19:42:42 +03:00
|
|
|
get error() {
|
|
|
|
return this._error;
|
|
|
|
}
|
|
|
|
|
2017-03-13 23:13:17 +03:00
|
|
|
hasTemplate(templateName) {
|
|
|
|
return this._templates.indexOf(templateName) > -1;
|
|
|
|
}
|
2017-03-14 20:03:36 +03:00
|
|
|
|
2018-06-24 01:32:06 +03:00
|
|
|
updateTemplateOptions(options) {
|
2019-04-03 13:22:22 +03:00
|
|
|
engine.updateTemplateOptions(_.merge({}, engine.getTemplateOptions(), options));
|
2018-06-24 01:32:06 +03:00
|
|
|
}
|
|
|
|
|
2017-03-14 20:03:36 +03:00
|
|
|
config(key) {
|
|
|
|
return this._config[key];
|
|
|
|
}
|
2017-03-21 12:03:09 +03:00
|
|
|
|
2018-10-17 10:23:56 +03:00
|
|
|
engine(key) {
|
|
|
|
return this._engines[key];
|
|
|
|
}
|
|
|
|
|
2021-04-26 13:53:15 +03:00
|
|
|
initI18n() {
|
|
|
|
themeI18n.init(this._name);
|
|
|
|
}
|
|
|
|
|
2017-10-26 19:24:08 +03:00
|
|
|
mount(siteApp) {
|
2017-03-21 12:03:09 +03:00
|
|
|
// reset the asset hash
|
|
|
|
// @TODO: set this on the theme instead of globally, or use proper file-based hash
|
|
|
|
config.set('assetHash', null);
|
|
|
|
// clear the view cache
|
2017-10-26 19:24:08 +03:00
|
|
|
siteApp.cache = {};
|
2017-03-21 12:03:09 +03:00
|
|
|
// Set the views and engine
|
2017-10-26 19:24:08 +03:00
|
|
|
siteApp.set('views', this.path);
|
|
|
|
siteApp.engine('hbs', engine.configure(this.partialsPath));
|
2017-03-21 12:03:09 +03:00
|
|
|
|
|
|
|
this._mounted = true;
|
|
|
|
}
|
2017-03-13 23:13:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
get() {
|
|
|
|
return currentActiveTheme;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Set theme
|
|
|
|
*
|
|
|
|
* At this point we trust that the theme has been validated.
|
|
|
|
* Any handling for invalid themes should happen before we get here
|
|
|
|
*
|
|
|
|
* @TODO this API needs to be simpler, but for now should work!
|
|
|
|
* @param {object} loadedTheme - the loaded theme object from the theme list
|
|
|
|
* @param {object} checkedTheme - the result of gscan.format for the theme we're activating
|
|
|
|
* @return {ActiveTheme}
|
|
|
|
*/
|
2017-05-31 19:42:42 +03:00
|
|
|
set(loadedTheme, checkedTheme, error) {
|
|
|
|
currentActiveTheme = new ActiveTheme(loadedTheme, checkedTheme, error);
|
2017-03-13 23:13:17 +03:00
|
|
|
return currentActiveTheme;
|
|
|
|
}
|
|
|
|
};
|