diff options
-rw-r--r-- | docs/config.md | 10 | ||||
-rw-r--r-- | docs/ebook.md | 5 | ||||
-rw-r--r-- | docs/themes/README.md | 17 | ||||
-rw-r--r-- | lib/cli/serve.js | 4 | ||||
-rw-r--r-- | lib/models/plugin.js | 82 | ||||
-rw-r--r-- | lib/plugins/__tests__/sortPlugins.js | 86 | ||||
-rw-r--r-- | lib/plugins/loadForBook.js | 15 | ||||
-rw-r--r-- | lib/plugins/sortPlugins.js | 47 |
8 files changed, 126 insertions, 140 deletions
diff --git a/docs/config.md b/docs/config.md index 01d4d48..2629cbb 100644 --- a/docs/config.md +++ b/docs/config.md @@ -20,18 +20,12 @@ GitBook allows you to customize your book using a flexible configuration. These Plugins and their configurations are specified in the `book.json`. See [the plugins section](plugins/README.md) for more details. -| Variable | Description | -| -------- | ----------- | -| `plugins` | List of plugins to load | -| `pluginsConfig` |Configuration for plugins | - -### Theme - Since version 3.0.0, GitBook can use themes. See [the theming section](themes/README.md) for more details. | Variable | Description | | -------- | ----------- | -| `theme` | The theme to use for the book | +| `plugins` | List of plugins to load | +| `pluginsConfig` |Configuration for plugins | ### Structure diff --git a/docs/ebook.md b/docs/ebook.md index 6230488..7b338a3 100644 --- a/docs/ebook.md +++ b/docs/ebook.md @@ -31,10 +31,11 @@ You can replace `/usr/bin` with any directory that is in your $PATH. Covers are used for all the ebook formats. It's an important part of an ebook brandline. +To provide a cover, place a **`cover.jpg`** file at the root directory of your book. Adding a **`cover_small.jpg`** will specify a smaller version of the cover. The cover should be a **JPEG** file. + A good cover should respect the following guidelines: -* Size of 1800x2360 (pixels) +* Size of 1800x2360 pixels for `cover.jpg`, 200x262 for `cover_small.jpg` * No border * Clearly visible book title * Any important text should be visible in the small version - diff --git a/docs/themes/README.md b/docs/themes/README.md index 5209d89..a0b138e 100644 --- a/docs/themes/README.md +++ b/docs/themes/README.md @@ -17,7 +17,22 @@ A theme is a plugin containing templates and assets. Overriding any individual t ### Extend/Customize theme in a book -Authors can extend the templates of a theme directly from their book's source (without creating an external theme). Templates will be resolved in the `_layouts` folder of the book first, then in +Authors can extend the templates of a theme directly from their book's source (without creating an external theme). Templates will be resolved in the `_layouts` folder of the book first, then in the installed plugins/themes. + +### Extend instead of Forking + +When you want to make your theme changes available to multiple books, instead of forking the default theme, you can extend it using the [templating syntax](../templating/README.md): + +```html +{% extends template.self %} + +{% block body %} + {{ super() }} + ... This will be added to the "body" block +{% endblock %} +``` + +Take a look at the [API](https://github.com/GitbookIO/theme-api) theme for a more complete example. ### Publish a theme diff --git a/lib/cli/serve.js b/lib/cli/serve.js index e2012e4..4ba5148 100644 --- a/lib/cli/serve.js +++ b/lib/cli/serve.js @@ -45,7 +45,9 @@ function generateBook(args, kwargs) { .then(function(resultBook) { if (hasLiveReloading) { // Enable livereload plugin - resultBook = ConfigModifier.addPlugin(resultBook, 'livereload'); + var config = resultBook.getConfig(); + config = ConfigModifier.addPlugin(config, 'livereload'); + resultBook = resultBook.set('config', config); } return Output.generate(Generator, resultBook, { diff --git a/lib/models/plugin.js b/lib/models/plugin.js index e3d6c4d..c8bb2f7 100644 --- a/lib/models/plugin.js +++ b/lib/models/plugin.js @@ -1,9 +1,10 @@ var Immutable = require('immutable'); var TemplateBlock = require('./templateBlock'); -var DEFAULT_VERSION = '*'; - var PluginDependency = require('./pluginDependency'); +var THEME_PREFIX = require('../constants/themePrefix'); + +var DEFAULT_VERSION = '*'; var Plugin = Immutable.Record({ name: String(), @@ -49,37 +50,43 @@ Plugin.prototype.getDepth = function() { }; /** - Return the ID on NPM for this plugin - - @return {String} -*/ + * Return the ID on NPM for this plugin + * @return {String} + */ Plugin.prototype.getNpmID = function() { return PluginDependency.nameToNpmID(this.getName()); }; /** - Check if a plugin is loaded - - @return {Boolean} -*/ + * Check if a plugin is loaded + * @return {Boolean} + */ Plugin.prototype.isLoaded = function() { return Boolean(this.getPackage().size > 0); }; /** - Return map of hooks - @return {Map<String:Function>} -*/ + * Check if a plugin is a theme given its name + * @return {Boolean} + */ +Plugin.prototype.isTheme = function() { + var name = this.getName(); + return (name && name.indexOf(THEME_PREFIX) === 0); +}; + +/** + * Return map of hooks + * @return {Map<String:Function>} + */ Plugin.prototype.getHooks = function() { return this.getContent().get('hooks') || Immutable.Map(); }; /** - Return infos about resources for a specific type - - @param {String} type - @return {Map<String:Mixed>} -*/ + * Return infos about resources for a specific type + * @param {String} type + * @return {Map<String:Mixed>} + */ Plugin.prototype.getResources = function(type) { if (type != 'website' && type != 'ebook') { throw new Error('Invalid assets type ' + type); @@ -92,17 +99,17 @@ Plugin.prototype.getResources = function(type) { }; /** - Return map of filters - @return {Map<String:Function>} -*/ + * Return map of filters + * @return {Map<String:Function>} + */ Plugin.prototype.getFilters = function() { return this.getContent().get('filters'); }; /** - Return map of blocks - @return {Map<String:TemplateBlock>} -*/ + * Return map of blocks + * @return {Map<String:TemplateBlock>} + */ Plugin.prototype.getBlocks = function() { var blocks = this.getContent().get('blocks'); blocks = blocks || Immutable.Map(); @@ -114,21 +121,19 @@ Plugin.prototype.getBlocks = function() { }; /** - Return a specific hook - - @param {String} name - @return {Function|undefined} -*/ + * Return a specific hook + * @param {String} name + * @return {Function|undefined} + */ Plugin.prototype.getHook = function(name) { return this.getHooks().get(name); }; /** - Create a plugin from a string - - @param {String} - @return {Plugin} -*/ + * Create a plugin from a string + * @param {String} + * @return {Plugin} + */ Plugin.createFromString = function(s) { var parts = s.split('@'); var name = parts[0]; @@ -141,11 +146,10 @@ Plugin.createFromString = function(s) { }; /** - Create a plugin from a dependency - - @param {PluginDependency} - @return {Plugin} -*/ + * Create a plugin from a dependency + * @param {PluginDependency} + * @return {Plugin} + */ Plugin.createFromDep = function(dep) { return new Plugin({ name: dep.getName(), diff --git a/lib/plugins/__tests__/sortPlugins.js b/lib/plugins/__tests__/sortPlugins.js index 2e1b594..c50c851 100644 --- a/lib/plugins/__tests__/sortPlugins.js +++ b/lib/plugins/__tests__/sortPlugins.js @@ -1,70 +1,50 @@ var PluginDependency = require('../../models/pluginDependency'); var sortPlugins = require('../sortPlugins'); var listAll = require('../listAll'); -var THEME_PREFIX = require('../../constants/themePrefix'); - - -/** - Check if a plugin is a theme given its name - - @return {Boolean} -*/ -function isTheme(name) { - return (name && name.indexOf(THEME_PREFIX) === 0); -} describe('sortPlugins', function() { it('must load themes after plugins', function() { var deps = PluginDependency.listFromString('theme-faq'), allPlugins = listAll(deps); - return sortPlugins(allPlugins, []) - .then(function(sorted) { - var plugins = sorted.slice(0, -2), - themes = sorted.slice(-2); - - var pluginsOk = plugins.every(function(plugin) { - return !isTheme(plugin.getName()); - }); - - var themesOk = themes.every(function(theme) { - return isTheme(theme.getName()); - }); - - expect(pluginsOk).toBe(true); - expect(plugins.has('search')).toBe(true); - - expect(themesOk).toBe(true); - expect(themes.size).toBe(2); - expect(themes.has('theme-faq')).toBe(true); - expect(themes.has('theme-default')).toBe(true); - }); + var sorted = sortPlugins(allPlugins, []); + var names = sorted + .map(function(plugin) { + return plugin.getName(); + }) + .toArray(); + + expect(names).toEqual([ + 'fontsettings', + 'sharing', + 'lunr', + 'search', + 'highlight', + 'theme-faq', + 'theme-default' + ]); }); it('must load themes after plugins with a complex dependencies list', function() { var deps = PluginDependency.listFromString('comment,theme-faq,-search,ga'), allPlugins = listAll(deps); - return sortPlugins(allPlugins, []) - .then(function(sorted) { - var plugins = sorted.slice(0, -2), - themes = sorted.slice(-2); - - var pluginsOk = plugins.every(function(plugin) { - return !isTheme(plugin.getName()); - }); - - var themesOk = themes.every(function(theme) { - return isTheme(theme.getName()); - }); - - expect(pluginsOk).toBe(true); - expect(plugins.has('search')).toBe(false); - - expect(themesOk).toBe(true); - expect(themes.size).toBe(2); - expect(themes.has('theme-faq')).toBe(true); - expect(themes.has('theme-default')).toBe(true); - }); + var sorted = sortPlugins(allPlugins, []); + var names = sorted + .map(function(plugin) { + return plugin.getName(); + }) + .toArray(); + + expect(names).toEqual([ + 'ga', + 'comment', + 'fontsettings', + 'sharing', + 'lunr', + 'highlight', + 'theme-faq', + 'theme-default' + ]); }); });
\ No newline at end of file diff --git a/lib/plugins/loadForBook.js b/lib/plugins/loadForBook.js index fd45a77..296cb01 100644 --- a/lib/plugins/loadForBook.js +++ b/lib/plugins/loadForBook.js @@ -7,11 +7,10 @@ var sortPlugins = require('./sortPlugins'); /** - Load a list of plugins in a book - - @param {Book} - @return {Promise<Map<String:Plugin>} -*/ + * Load a list of plugins in a book + * @param {Book} + * @return {Promise<Map<String:Plugin>} + */ function loadForBook(book) { var logger = book.getLogger(); var requirements = listForBook(book); @@ -28,9 +27,9 @@ function loadForBook(book) { ); }); - return sortPlugins(installed, requirementsKeys); - }) - .then(function(installed) { + // Sort plugins + installed = sortPlugins(installed, requirementsKeys); + // Log state logger.info.ln(installed.size + ' plugins are installed'); if (requirements.size != installed.size) { diff --git a/lib/plugins/sortPlugins.js b/lib/plugins/sortPlugins.js index 6626936..e96b02c 100644 --- a/lib/plugins/sortPlugins.js +++ b/lib/plugins/sortPlugins.js @@ -1,44 +1,35 @@ -var Promise = require('../utils/promise'); - var THEME_PREFIX = require('../constants/themePrefix'); var LOADING_ORDER = ['plugin', 'theme']; /** - Returns the type of a plugin given its name - - @return {String} -*/ + * Returns the type of a plugin given its name + * @return {String} + */ function pluginType(name) { return (name && name.indexOf(THEME_PREFIX) === 0) ? 'theme' : 'plugin'; } /** - Sort the list of installed plugins to match list in book.json - The themes should always be loaded after the plugins - - @param {<OrderedMap<String:Plugin>>} plugins - @param {<List<String>>} requirementsKeys - @return {Promise<OrderedMap<String:Plugin>>} -*/ - + * Sort the list of installed plugins to match list in book.json + * The themes should always be loaded after the plugins + * + * @param {<OrderedMap<String:Plugin>>} plugins + * @param {<List<String>>} requirementsKeys + * @return {OrderedMap<String:Plugin>} + */ function sortPlugins(plugins, requirementsKeys) { - return Promise() - .then(function() { - // Sort plugins to match list in book.json - plugins = plugins.sort(function(a, b) { - // Get order from book.json - var definitionOrder = requirementsKeys.indexOf(a.getName()) < requirementsKeys.indexOf(b.getName()); - - // Get order from plugins a and b type - var aType = pluginType(a.getName()), - bType = pluginType(b.getName()), - loadingOrder = LOADING_ORDER.indexOf(aType) < LOADING_ORDER.indexOf(bType); + // Sort plugins to match list in book.json + return plugins.sort(function(a, b) { + // Get order from book.json + var definitionOrder = requirementsKeys.indexOf(a.getName()) < requirementsKeys.indexOf(b.getName()); - return loadingOrder || definitionOrder ? -1 : 1; - }); + // Get order from plugins a and b type + var aType = pluginType(a.getName()), + bType = pluginType(b.getName()), + loadingOrder = LOADING_ORDER.indexOf(aType) < LOADING_ORDER.indexOf(bType); - return plugins; + return loadingOrder || definitionOrder ? -1 : 1; }); } |