mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-23 22:11:09 +03:00
Added package.js support for themes (and plugins)
Closes #2081 * Amended require-tree to populate availableThemes and availablePlugins to use full file names (`basename.ext`) as keys instead of just basename. This way `image.jpg`, `image.png`, `image.gif` won't overwrite the `image` key. * Amended require-tree to allow package.json file parsing to return the contents of the file as json on the `package.json` key. * settings api populates theme data `package` if it exists. Otherwise it assigns `false` to it * `general.hbs` (salute) was reworked to if there is the package key on the theme is not false, it will use the `name` and `version` keys of that. You can break it by not having a `name` or `version` in the package.json file. * Added error and warning messages for package.json file parse errors and misses
This commit is contained in:
parent
6b82bebd90
commit
212711d896
@ -69,7 +69,8 @@
|
||||
<label for="activeTheme">Theme</label>
|
||||
<select id="activeTheme" name="general[activeTheme]">
|
||||
{{#each availableThemes}}
|
||||
<option value="{{name}}" {{#if active}}selected{{/if}}>{{name}}</option>
|
||||
<option value="{{name}}" {{#if active}}selected{{/if}}>{{#if package}}{{package.name}} - {{package.version}}{{else}}{{name}}{{/if}}</option>
|
||||
{{#unless package}}<script>console.log('Hi! The theme named "{{name}}" does not have a package.json file or it\' malformed. This will be required in the future. For more info, see http://docs.ghost.org/themes/.');</script>{{/unless}}
|
||||
{{/each}}
|
||||
</select>
|
||||
<p>Select a theme for your blog</p>
|
||||
|
@ -83,10 +83,15 @@ readSettingsResult = function (result) {
|
||||
i,
|
||||
item;
|
||||
for (i = 0; i < themeKeys.length; i += 1) {
|
||||
//do not include hidden files
|
||||
if (themeKeys[i].indexOf('.') !== 0) {
|
||||
//do not include hidden files or _messages
|
||||
if (themeKeys[i].indexOf('.') !== 0 && themeKeys[i] !== '_messages') {
|
||||
item = {};
|
||||
item.name = themeKeys[i];
|
||||
if (themes[themeKeys[i]].hasOwnProperty('package.json')) {
|
||||
item.package = themes[themeKeys[i]]['package.json'];
|
||||
} else {
|
||||
item.package = false;
|
||||
}
|
||||
//data about files currently not used
|
||||
//item.details = themes[themeKeys[i]];
|
||||
if (themeKeys[i] === settings.activeTheme.value) {
|
||||
|
@ -118,7 +118,7 @@ frontendControllers = {
|
||||
filters.doFilter('prePostsRender', post).then(function (post) {
|
||||
api.settings.read('activeTheme').then(function (activeTheme) {
|
||||
var paths = config().paths.availableThemes[activeTheme.value],
|
||||
view = post.page && paths.hasOwnProperty('page') ? 'page' : 'post';
|
||||
view = post.page && paths.hasOwnProperty('page.hbs') ? 'page' : 'post';
|
||||
res.render(view, {post: post});
|
||||
});
|
||||
});
|
||||
|
@ -71,7 +71,7 @@ function initDbHashAndFirstRun() {
|
||||
}
|
||||
|
||||
// Checks for the existence of the "built" javascript files from grunt concat.
|
||||
// Returns a promise that will be resolved if all files exist or rejected if
|
||||
// Returns a promise that will be resolved if all files exist or rejected if
|
||||
// any are missing.
|
||||
function builtFilesExist() {
|
||||
var deferreds = [],
|
||||
@ -262,7 +262,12 @@ function setup(server) {
|
||||
startGhost
|
||||
);
|
||||
}
|
||||
|
||||
_.each(config().paths.availableThemes._messages.errors, function (error) {
|
||||
errors.logError(error.message, error.context);
|
||||
});
|
||||
_.each(config().paths.availableThemes._messages.warns, function (warn) {
|
||||
errors.logWarn(warn.message, warn.context);
|
||||
});
|
||||
});
|
||||
}, function (err) {
|
||||
errors.logErrorAndExit(err, err.context, err.help);
|
||||
|
@ -1,8 +1,10 @@
|
||||
var when = require('when'),
|
||||
keys = require('when/keys'),
|
||||
fs = require('fs'),
|
||||
path = require('path'),
|
||||
extend = function (obj, source) {
|
||||
var when = require('when'),
|
||||
keys = require('when/keys'),
|
||||
fs = require('fs'),
|
||||
path = require('path'),
|
||||
_ = require('lodash'),
|
||||
messages = {errors: [], warns: []},
|
||||
extend = function (obj, source) {
|
||||
var key;
|
||||
for (key in source) {
|
||||
if (source.hasOwnProperty(key)) {
|
||||
@ -11,6 +13,32 @@ var when = require('when'),
|
||||
}
|
||||
return obj;
|
||||
},
|
||||
parsePackageJson = function (path) {
|
||||
var packageDeferred = when.defer(),
|
||||
packagePromise = packageDeferred.promise,
|
||||
jsonContainer;
|
||||
|
||||
fs.readFile(path, function (error, data) {
|
||||
if (error) {
|
||||
messages.errors.push({message: 'Could not read package.json file', context: path});
|
||||
packageDeferred.resolve(false);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
jsonContainer = JSON.parse(data);
|
||||
if (jsonContainer.hasOwnProperty('name') && jsonContainer.hasOwnProperty('version')) {
|
||||
packageDeferred.resolve(jsonContainer);
|
||||
} else {
|
||||
messages.errors.push({message: '"name" or "version" is missing from theme package.json file.', context: path});
|
||||
packageDeferred.resolve(false);
|
||||
}
|
||||
} catch (e) {
|
||||
messages.errors.push({message: 'Theme package.json file is malformed', context: path});
|
||||
packageDeferred.resolve(false);
|
||||
}
|
||||
});
|
||||
return when(packagePromise);
|
||||
},
|
||||
readDir = function (dir, options, depth) {
|
||||
depth = depth || 0;
|
||||
|
||||
@ -36,14 +64,14 @@ var when = require('when'),
|
||||
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;
|
||||
subtree[file] = filePromise;
|
||||
fs.lstat(fpath, function (error, result) {
|
||||
/*jslint unparam:true*/
|
||||
if (result.isDirectory()) {
|
||||
fileDeferred.resolve(readDir(fpath, options, depth + 1));
|
||||
} else if (depth === 1 && file === "package.json") {
|
||||
fileDeferred.resolve(parsePackageJson(fpath));
|
||||
} else {
|
||||
fileDeferred.resolve(fpath);
|
||||
}
|
||||
@ -61,6 +89,15 @@ var when = require('when'),
|
||||
},
|
||||
readAll = function (dir, options, depth) {
|
||||
return when(readDir(dir, options, depth)).then(function (paths) {
|
||||
// for all contents of the dir, I'm interested in the ones that are directories and within /theme/
|
||||
if (typeof paths === "object" && dir.indexOf('theme') !== -1) {
|
||||
_.each(paths, function (path, index) {
|
||||
if (typeof path === 'object' && !path.hasOwnProperty('package.json') && index.indexOf('.') !== 0) {
|
||||
messages.warns.push({message: 'Theme does not have a package.json file', context: index});
|
||||
}
|
||||
});
|
||||
}
|
||||
paths._messages = messages;
|
||||
return paths;
|
||||
});
|
||||
};
|
||||
|
@ -195,10 +195,10 @@ describe('Frontend Controller', function () {
|
||||
'availableThemes': {
|
||||
'casper': {
|
||||
'assets': null,
|
||||
'default': '/content/themes/casper/default.hbs',
|
||||
'index': '/content/themes/casper/index.hbs',
|
||||
'page': '/content/themes/casper/page.hbs',
|
||||
'post': '/content/themes/casper/post.hbs'
|
||||
'default.hbs': '/content/themes/casper/default.hbs',
|
||||
'index.hbs': '/content/themes/casper/index.hbs',
|
||||
'page.hbs': '/content/themes/casper/page.hbs',
|
||||
'post.hbs': '/content/themes/casper/post.hbs'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user