mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-10 23:36:14 -05:00
Directory scanning on contents/themes and plugins
This implements #106. * Added require-tree which is based off of @ricardobeat's module. Fully async. * I've moved active theme and active directory to settings from config as well. * Modified settings.hbs and settings.js to display the raw json under Settings/Appearance
This commit is contained in:
parent
1df9b6e90a
commit
e271c6402f
6 changed files with 143 additions and 18 deletions
24
app.js
24
app.js
|
@ -45,13 +45,7 @@
|
||||||
ghost.app().use(ghost.initTheme(ghost.app()));
|
ghost.app().use(ghost.initTheme(ghost.app()));
|
||||||
ghost.app().use(flash());
|
ghost.app().use(flash());
|
||||||
// bind locals - options which appear in every view - perhaps this should be admin only
|
// bind locals - options which appear in every view - perhaps this should be admin only
|
||||||
ghost.app().use(function (req, res, next) {
|
|
||||||
res.locals.messages = req.flash();
|
|
||||||
res.locals.siteTitle = ghostGlobals.title;
|
|
||||||
res.locals.siteDescription = ghostGlobals.description;
|
|
||||||
res.locals.siteUrl = ghostGlobals.url;
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -88,6 +82,8 @@
|
||||||
// Make sure we have a locals value.
|
// Make sure we have a locals value.
|
||||||
res.locals = res.locals || {};
|
res.locals = res.locals || {};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Extend it with nav data and ghostGlobals
|
// Extend it with nav data and ghostGlobals
|
||||||
_.extend(res.locals, navData, {
|
_.extend(res.locals, navData, {
|
||||||
ghostGlobals: ghost.globals()
|
ghostGlobals: ghost.globals()
|
||||||
|
@ -101,10 +97,22 @@
|
||||||
ghost.loaded = loading.promise;
|
ghost.loaded = loading.promise;
|
||||||
|
|
||||||
when.all([ghost.init(), filters.loadCoreFilters(ghost), helpers.loadCoreHelpers(ghost)]).then(function () {
|
when.all([ghost.init(), filters.loadCoreFilters(ghost), helpers.loadCoreHelpers(ghost)]).then(function () {
|
||||||
|
|
||||||
// Assign the globals we have loaded
|
// Assign the globals we have loaded
|
||||||
ghostGlobals = ghost.globals();
|
ghostGlobals = ghost.globals();
|
||||||
|
|
||||||
|
ghost.app().use(function (req, res, next) {
|
||||||
|
res.locals.messages = req.flash();
|
||||||
|
res.locals.siteTitle = ghostGlobals.title;
|
||||||
|
res.locals.siteDescription = ghostGlobals.description;
|
||||||
|
res.locals.siteUrl = ghostGlobals.url;
|
||||||
|
res.locals.activeTheme = ghostGlobals.activeTheme;
|
||||||
|
res.locals.activePlugin = ghostGlobals.activePlugin;
|
||||||
|
res.locals.availableThemes = ghost.paths().availableThemes;
|
||||||
|
res.locals.availablePlugins = ghost.paths().availablePlugins;
|
||||||
|
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* API routes..
|
* API routes..
|
||||||
* @todo auth should be public auth not user auth
|
* @todo auth should be public auth not user auth
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
<li class="general active"><a href="#general">General</a></li>
|
<li class="general active"><a href="#general">General</a></li>
|
||||||
<li class="publishing"><a href="#content">Content</a></li>
|
<li class="publishing"><a href="#content">Content</a></li>
|
||||||
<li class="users"><a href="#users">Users</a></li>
|
<li class="users"><a href="#users">Users</a></li>
|
||||||
<li class="appearance"><a href="#">Appearance</a></li>
|
<li class="appearance"><a href="#appearance">Appearance</a></li>
|
||||||
<li class="services"><a href="#">Connected Services</a></li>
|
<li class="services"><a href="#">Connected Services</a></li>
|
||||||
<li class="plugins"><a href="#">Plugins</a></li>
|
<li class="plugins"><a href="#">Plugins</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -200,4 +200,17 @@
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
<section id="appearance" class="settings-content">
|
||||||
|
<header>
|
||||||
|
<h2 class="title">Appearance</h2>
|
||||||
|
</header>
|
||||||
|
<section class="content">
|
||||||
|
<h6 class="sub">Raw json be here</h6>
|
||||||
|
<p>Active theme: {{json settings.activeTheme}}</p>
|
||||||
|
<p>Available themes: {{json availableThemes}}</p>
|
||||||
|
<p>Available plugins: {{json availablePlugins}}</p>
|
||||||
|
|
||||||
|
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
|
@ -40,6 +40,10 @@
|
||||||
return output;
|
return output;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ghost.registerThemeHelper('json', function (object, options) {
|
||||||
|
return JSON.stringify(object);
|
||||||
|
});
|
||||||
|
|
||||||
return when.all([
|
return when.all([
|
||||||
// Just one async helper for now, but could be more in the future
|
// Just one async helper for now, but could be more in the future
|
||||||
navHelper.registerWithGhost(ghost)
|
navHelper.registerWithGhost(ghost)
|
||||||
|
|
|
@ -16,6 +16,11 @@
|
||||||
|
|
||||||
models = require('./shared/models'),
|
models = require('./shared/models'),
|
||||||
ExampleFilter = require('../content/plugins/exampleFilters'),
|
ExampleFilter = require('../content/plugins/exampleFilters'),
|
||||||
|
|
||||||
|
requireTree = require('./shared/require-tree'),
|
||||||
|
themeDirectories = requireTree('content/themes'),
|
||||||
|
pluginDirectories = requireTree('content/plugins'),
|
||||||
|
|
||||||
Ghost,
|
Ghost,
|
||||||
instance,
|
instance,
|
||||||
defaults,
|
defaults,
|
||||||
|
@ -59,10 +64,17 @@
|
||||||
instance = this;
|
instance = this;
|
||||||
|
|
||||||
// Holds the filters
|
// Holds the filters
|
||||||
this.filterCallbacks = [];
|
instance.filterCallbacks = [];
|
||||||
|
|
||||||
// Holds the filter hooks (that are built in to Ghost Core)
|
// Holds the filter hooks (that are built in to Ghost Core)
|
||||||
this.filters = [];
|
instance.filters = [];
|
||||||
|
|
||||||
|
// Holds the theme directories temporarily
|
||||||
|
instance.themeDirectories = {};
|
||||||
|
|
||||||
|
// Holds the plugin directories temporarily
|
||||||
|
instance.pluginDirectories = {};
|
||||||
|
|
||||||
|
|
||||||
plugin = new ExampleFilter(instance).init();
|
plugin = new ExampleFilter(instance).init();
|
||||||
|
|
||||||
|
@ -74,32 +86,44 @@
|
||||||
// load Plugins...
|
// load Plugins...
|
||||||
// var f = new FancyFirstChar(ghost).init();
|
// var f = new FancyFirstChar(ghost).init();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
_.extend(instance, {
|
_.extend(instance, {
|
||||||
app: function () { return app; },
|
app: function () { return app; },
|
||||||
config: function () { return config; },
|
config: function () { return config; },
|
||||||
globals: function () { return instance.globalConfig; }, // there's no management here to be sure this has loaded
|
|
||||||
|
// there's no management here to be sure this has loaded
|
||||||
|
globals: function () { return instance.globalConfig; },
|
||||||
dataProvider: models,
|
dataProvider: models,
|
||||||
statuses: function () { return statuses; },
|
statuses: function () { return statuses; },
|
||||||
polyglot: function () { return polyglot; },
|
polyglot: function () { return polyglot; },
|
||||||
plugin: function () { return plugin; },
|
plugin: function () { return plugin; },
|
||||||
|
getPaths: function () {
|
||||||
|
return when.all([themeDirectories, pluginDirectories]).then(function (paths) {
|
||||||
|
instance.themeDirectories = paths[0];
|
||||||
|
instance.pluginDirectories = paths[1];
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
},
|
||||||
paths: function () {
|
paths: function () {
|
||||||
return {
|
return {
|
||||||
'activeTheme': __dirname + '/../content/' + config.themeDir + '/' + config.activeTheme + '/',
|
'activeTheme': __dirname + '/../content/' + config.themeDir + '/' + config.activeTheme + '/',
|
||||||
'adminViews': __dirname + '/admin/views/',
|
'adminViews': __dirname + '/admin/views/',
|
||||||
'frontendViews': __dirname + '/frontend/views/',
|
'frontendViews': __dirname + '/frontend/views/',
|
||||||
'lang': __dirname + '/lang/'
|
'lang': __dirname + '/lang/',
|
||||||
|
'availableThemes': instance.themeDirectories,
|
||||||
|
'availablePlugins': instance.pluginDirectories
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
return instance;
|
return instance;
|
||||||
};
|
};
|
||||||
|
|
||||||
Ghost.prototype.init = function () {
|
Ghost.prototype.init = function () {
|
||||||
this.globalConfig = config.blogData;
|
this.globalConfig = config.blogData;
|
||||||
return when.all([instance.dataProvider.init()]);
|
|
||||||
|
return when.all([instance.dataProvider.init(), instance.getPaths()]);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -186,7 +210,6 @@
|
||||||
var self = this;
|
var self = this;
|
||||||
return function initTheme(req, res, next) {
|
return function initTheme(req, res, next) {
|
||||||
app.set('view engine', 'hbs');
|
app.set('view engine', 'hbs');
|
||||||
|
|
||||||
if (/(^\/ghost$|^\/ghost\/)/.test(req.url) === false) {
|
if (/(^\/ghost$|^\/ghost\/)/.test(req.url) === false) {
|
||||||
app.engine('hbs', hbs.express3(
|
app.engine('hbs', hbs.express3(
|
||||||
{partialsDir: self.paths().activeTheme + 'partials'}
|
{partialsDir: self.paths().activeTheme + 'partials'}
|
||||||
|
@ -199,7 +222,6 @@
|
||||||
}
|
}
|
||||||
app.use(express['static'](self.paths().activeTheme));
|
app.use(express['static'](self.paths().activeTheme));
|
||||||
app.use('/content/images', express['static'](path.join(__dirname, '/../content/images')));
|
app.use('/content/images', express['static'](path.join(__dirname, '/../content/images')));
|
||||||
|
|
||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -60,6 +60,20 @@ module.exports = {
|
||||||
"created_by": 1,
|
"created_by": 1,
|
||||||
"updated_by": 1,
|
"updated_by": 1,
|
||||||
"type": "general"
|
"type": "general"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "activePlugins",
|
||||||
|
"value": "",
|
||||||
|
"created_by": 1,
|
||||||
|
"updated_by": 1,
|
||||||
|
"type": "general"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "activeTheme",
|
||||||
|
"value": "content/themes/casper",
|
||||||
|
"created_by": 1,
|
||||||
|
"updated_by": 1,
|
||||||
|
"type": "general"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
64
core/shared/require-tree.js
Normal file
64
core/shared/require-tree.js
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
(function() {
|
||||||
|
"use strict";
|
||||||
|
var when = require('when'),
|
||||||
|
keys = require('when/keys'),
|
||||||
|
fs = require('fs'),
|
||||||
|
path = require('path'),
|
||||||
|
extend = function (obj, source) {
|
||||||
|
var key;
|
||||||
|
for (key in source) {
|
||||||
|
if (source.hasOwnProperty(key)) {
|
||||||
|
obj[key] = source[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
},
|
||||||
|
readDir = function (dir, options, depth) {
|
||||||
|
depth = depth || 0;
|
||||||
|
|
||||||
|
options = extend({
|
||||||
|
index: true
|
||||||
|
}, options);
|
||||||
|
|
||||||
|
if (depth > 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var subtree = {},
|
||||||
|
treeDeferred = when.defer(),
|
||||||
|
treePromise = treeDeferred.promise;
|
||||||
|
|
||||||
|
fs.readdir(dir, function (error, files) {
|
||||||
|
files.forEach(function (file) {
|
||||||
|
var fileDeferred = when.defer(),
|
||||||
|
filePromise = fileDeferred.promise,
|
||||||
|
ext = path.extname(file),
|
||||||
|
name = path.basename(file, ext),
|
||||||
|
fpath = path.join(dir, file);
|
||||||
|
subtree[name] = filePromise;
|
||||||
|
fs.lstat(fpath, function (error, result) {
|
||||||
|
if (result.isDirectory()) {
|
||||||
|
fileDeferred.resolve(readDir(fpath, options, depth + 1));
|
||||||
|
} else {
|
||||||
|
fileDeferred.resolve(fpath);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return keys.all(subtree).then(function(theFiles) {
|
||||||
|
return treeDeferred.resolve(theFiles);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return when(treePromise).then(function (prom) {
|
||||||
|
return prom;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
readAll = function (dir, options, depth) {
|
||||||
|
return when(readDir(dir, options, depth)).then(function (paths) {
|
||||||
|
return paths;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = readAll;
|
||||||
|
}());
|
Loading…
Add table
Reference in a new issue