mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-26 12:18:01 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 44a3bfe296 | |||
| a9ce6f808d | |||
| e5c667e0fa | |||
| e36f274dbe | |||
| 2a88427e74 | |||
| ed48f5f3ee | |||
| 7b4accb117 | |||
| d6437d31d4 | |||
| 3dd33f1f3c | |||
| 3a0f00411b | |||
| 5b655bb29a | |||
| faf10605e8 | |||
| 5c98b3350b | |||
| 6f4e1d10c1 | |||
| 870886599a | |||
| 1b9801b8a4 |
@@ -1,5 +1,14 @@
|
||||
# Release notes
|
||||
|
||||
## 1.4.0
|
||||
- Add command `gitbook install` to install plugins from book.json
|
||||
- `package.json` is no longer necessary
|
||||
|
||||
## 1.3.4
|
||||
- Add glossary to ebooks
|
||||
- Fix autocover with new hook "finish:before"
|
||||
- Add X-UA-Compatible meta tag for IE
|
||||
|
||||
## 1.3.3
|
||||
- Fix parsing of lexed content using the client library
|
||||
|
||||
|
||||
@@ -132,7 +132,10 @@ You can publish your books to our index by visiting [GitBook.io](http://www.gitb
|
||||
GitBook can generate your book in the following formats:
|
||||
|
||||
* **Static Website**: This is the default format. It generates a complete interactive static website that can be, for example, hosted on GitHub Pages.
|
||||
* **eBook**: A complete eBook with exercise solutions at the end of the book. Generate this format using: ```gitbook ebook ./myrepo```. You need to have [ebook-convert](http://manual.calibre-ebook.com/cli/ebook-convert.html) installed. The output format could be **PDF**, **ePub** or **MOBI**.
|
||||
* **eBook**: A complete eBook with exercise solutions at the end of the book. You need to have [ebook-convert](http://manual.calibre-ebook.com/cli/ebook-convert.html) installed. You can specify the eBook filename with the `-o` option, otherwise `book` will be used.
|
||||
* Generate a **PDF** using: `gitbook pdf ./myrepo`
|
||||
* Generate a **ePub** using: `gitbook epub ./myrepo`
|
||||
* Generate a **MOBI** using: `gitbook mobi ./myrepo`
|
||||
* **JSON**: This format is used for debugging or extracting metadata from a book. Generate this format using: ```gitbook build ./myrepo -f json```.
|
||||
|
||||
## Book Format
|
||||
@@ -211,6 +214,8 @@ The platform [GitBook.io](https://www.gitbook.io/) is like an "Heroku for books"
|
||||
|
||||
Plugins can be used to extend your book's functionality. Read [GitbookIO/plugin](https://github.com/GitbookIO/plugin) for more information about how to build a plugin for GitBook.
|
||||
|
||||
Plugins needed to build a book can be installed using: `gitbook install ./`.
|
||||
|
||||
##### Official plugins:
|
||||
|
||||
| Name | Description |
|
||||
|
||||
+23
-1
@@ -7,7 +7,7 @@ var prog = require('commander');
|
||||
var tinylr = require('tiny-lr-fork');
|
||||
|
||||
var pkg = require('../package.json');
|
||||
var generators = require("../lib/generate").generators;
|
||||
var genbook = require("../lib/generate");
|
||||
var initDir = require("../lib/generate/init");
|
||||
var fs = require('../lib/generate/fs');
|
||||
|
||||
@@ -80,6 +80,28 @@ build.command(prog.command('serve [source_dir]'))
|
||||
generate();
|
||||
});
|
||||
|
||||
build.commandEbook(prog.command('install [source_dir]'))
|
||||
.description('Install plugins for a book')
|
||||
.action(function(dir, options) {
|
||||
console.log("Install plugins in", dir);
|
||||
genbook.config.read({
|
||||
input: dir
|
||||
})
|
||||
.then(function(options) {
|
||||
return genbook.Plugin.install(options);
|
||||
})
|
||||
.then(function() {
|
||||
console.log("Successfully installed plugins!");
|
||||
})
|
||||
.fail(function(err) {
|
||||
// Log error
|
||||
utils.logError(err);
|
||||
|
||||
// Exit process with failure code
|
||||
process.exit(-1);
|
||||
});
|
||||
});
|
||||
|
||||
build.commandEbook(prog.command('pdf [source_dir]'))
|
||||
.description('Build a gitbook as a PDF')
|
||||
.action(function(dir, options) {
|
||||
|
||||
+26
-3
@@ -1,3 +1,4 @@
|
||||
var Q = require('q');
|
||||
var _ = require('lodash');
|
||||
var path = require('path');
|
||||
|
||||
@@ -96,10 +97,32 @@ var CONFIG = {
|
||||
}
|
||||
};
|
||||
|
||||
// Return complete configuration
|
||||
var defaultsConfig = function(options) {
|
||||
return _.merge(options || {}, CONFIG, _.defaults);
|
||||
};
|
||||
|
||||
// Read configuration from book.json
|
||||
var readConfig = function(options) {
|
||||
options = defaultsConfig(options);
|
||||
|
||||
return Q()
|
||||
.then(function() {
|
||||
try {
|
||||
var _config = require(path.resolve(options.input, options.configFile));
|
||||
options = _.merge(options, _.omit(_config, 'input', 'configFile', 'defaultsPlugins', 'generator'));
|
||||
}
|
||||
catch(err) {
|
||||
// No config file: not a big deal
|
||||
return Q();
|
||||
}
|
||||
})
|
||||
.thenResolve(options);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
CONFIG: CONFIG,
|
||||
defaults: function(options) {
|
||||
return _.merge(options || {}, CONFIG, _.defaults);
|
||||
}
|
||||
defaults: defaultsConfig,
|
||||
read: readConfig
|
||||
}
|
||||
|
||||
|
||||
+16
-20
@@ -48,28 +48,18 @@ var loadGenerator = function(options) {
|
||||
|
||||
|
||||
var generate = function(options) {
|
||||
// Set defaults to options
|
||||
options = defaultConfig.defaults(options);
|
||||
|
||||
// Validate options
|
||||
if (!options.input) {
|
||||
return Q.reject(new Error("Need option input (book input directory)"));
|
||||
}
|
||||
|
||||
// Check files to get folder type (book, multilanguage book or neither)
|
||||
return checkGenerator(options)
|
||||
|
||||
// Read config file
|
||||
.then(function() {
|
||||
try {
|
||||
var _config = require(path.resolve(options.input, options.configFile));
|
||||
return defaultConfig.read(options)
|
||||
.then(function(_options) {
|
||||
options = _options;
|
||||
|
||||
options = _.merge(options, _.omit(_config, 'input', 'configFile', 'defaultsPlugins'));
|
||||
}
|
||||
catch(err) {
|
||||
// No config file: not a big deal
|
||||
return Q();
|
||||
// Validate options
|
||||
if (!options.input) {
|
||||
return Q.reject(new Error("Need option input (book input directory)"));
|
||||
}
|
||||
|
||||
// Check files to get folder type (book, multilanguage book or neither)
|
||||
return checkGenerator(options);
|
||||
})
|
||||
|
||||
// Read readme
|
||||
@@ -99,7 +89,9 @@ var generate = function(options) {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Generate a multilanguage book by generating a book for each folder.
|
||||
*/
|
||||
var generateMultiLang = function(options) {
|
||||
var langsSummary;
|
||||
options.output = options.output || path.join(options.input, "_book");
|
||||
@@ -297,6 +289,9 @@ var generateBook = function(options) {
|
||||
})
|
||||
|
||||
// Finish generation
|
||||
.then(function() {
|
||||
return generator.callHook("finish:before");
|
||||
})
|
||||
.then(function() {
|
||||
return generator.finish();
|
||||
})
|
||||
@@ -375,4 +370,5 @@ module.exports = {
|
||||
file: generateFile,
|
||||
book: generateBook,
|
||||
Plugin: Plugin,
|
||||
config: defaultConfig
|
||||
};
|
||||
|
||||
@@ -26,6 +26,9 @@ Generator.prototype.loadTemplates = function() {
|
||||
this.summaryTemplate = swig.compileFile(
|
||||
this.plugins.template("ebook:sumary") || path.resolve(this.options.theme, 'templates/ebook/summary.html')
|
||||
);
|
||||
this.glossaryTemplate = swig.compileFile(
|
||||
this.plugins.template("ebook:glossary") || path.resolve(this.options.theme, 'templates/ebook/glossary.html')
|
||||
);
|
||||
};
|
||||
|
||||
// Generate table of contents
|
||||
@@ -46,7 +49,7 @@ Generator.prototype.finish = function() {
|
||||
var output = path.join(this.options.output, "index.html");
|
||||
|
||||
var progress = parse.progress(this.options.navigation, "README.md");
|
||||
|
||||
|
||||
return Q()
|
||||
|
||||
// Write table of contents
|
||||
@@ -54,6 +57,11 @@ Generator.prototype.finish = function() {
|
||||
return that.writeToc();
|
||||
})
|
||||
|
||||
// Write glossary
|
||||
.then(function() {
|
||||
return that.writeGlossary();
|
||||
})
|
||||
|
||||
// Copy cover
|
||||
.then(function() {
|
||||
return that.copyCover();
|
||||
|
||||
+57
-16
@@ -4,6 +4,7 @@ var semver = require("semver");
|
||||
var path = require("path");
|
||||
var url = require("url");
|
||||
var fs = require("./fs");
|
||||
var npmi = require('npmi');
|
||||
var resolve = require('resolve');
|
||||
|
||||
var pkg = require("../../package.json");
|
||||
@@ -152,33 +153,73 @@ Plugin.prototype.copyAssets = function(out, options) {
|
||||
};
|
||||
|
||||
|
||||
// Normalize a list of plugin name to use
|
||||
Plugin.normalizeNames = function(names) {
|
||||
// Install a list of plugin
|
||||
Plugin.install = function(options) {
|
||||
// Normalize list of plugins
|
||||
var plugins = Plugin.normalizeList(options.plugins);
|
||||
|
||||
// Install plugins one by one
|
||||
return _.reduce(plugins, function(prev, plugin) {
|
||||
return prev.then(function() {
|
||||
var fullname = "gitbook-plugin-"+plugin.name;
|
||||
console.log("Install plugin", plugin.name, "from npm ("+fullname+") with version", (plugin.version || "*"));
|
||||
return Q.nfcall(npmi, {
|
||||
'name': fullname,
|
||||
'version': plugin.version,
|
||||
'path': options.input,
|
||||
'npmLoad': {
|
||||
'loglevel': 'silent',
|
||||
'loaded': false,
|
||||
'prefix': options.input
|
||||
}
|
||||
});
|
||||
});
|
||||
}, Q());
|
||||
};
|
||||
|
||||
// Normalize a list of plugins to use
|
||||
Plugin.normalizeList = function(plugins) {
|
||||
// Normalize list to an array
|
||||
names = _.isString(names) ? names.split(",") : (names || []);
|
||||
plugins = _.isString(plugins) ? plugins.split(",") : (plugins || []);
|
||||
|
||||
// Divide as {name, version} to handle format like "myplugin@1.0.0"
|
||||
plugins = _.map(plugins, function(plugin) {
|
||||
var parts = plugin.split("@");
|
||||
return {
|
||||
'name': parts[0],
|
||||
'version': parts[1] // optional
|
||||
}
|
||||
});
|
||||
|
||||
// List plugins to remove
|
||||
var toremove = _.chain(names)
|
||||
.filter(function(name) {
|
||||
return name.length > 0 && name[0] == "-";
|
||||
var toremove = _.chain(plugins)
|
||||
.filter(function(plugin) {
|
||||
return plugin.name.length > 0 && plugin.name[0] == "-";
|
||||
})
|
||||
.map(function(name) {
|
||||
return name.slice(1);
|
||||
.map(function(plugin) {
|
||||
return plugin.name.slice(1);
|
||||
})
|
||||
.value();
|
||||
|
||||
// Merge with defaults
|
||||
names = _.chain(names)
|
||||
.concat(Plugin.defaults)
|
||||
plugins = _.chain(plugins)
|
||||
.concat(_.map(Plugin.defaults, function(plugin) {
|
||||
return { 'name': plugin }
|
||||
}))
|
||||
.uniq()
|
||||
.value();
|
||||
|
||||
// Remove plugins starting with
|
||||
names = _.filter(names, function(name) {
|
||||
return !_.contains(toremove, name) && !(name.length > 0 && name[0] == "-");
|
||||
// Build final list
|
||||
plugins = _.filter(plugins, function(plugin) {
|
||||
return !_.contains(toremove, plugin.name) && !(plugin.name.length > 0 && plugin.name[0] == "-");
|
||||
});
|
||||
|
||||
return names;
|
||||
return plugins;
|
||||
};
|
||||
|
||||
// Normalize a list of plugin name to use
|
||||
Plugin.normalizeNames = function(plugins) {
|
||||
return _.pluck(Plugin.normalizeList(plugins), "name");
|
||||
};
|
||||
|
||||
// Extract data from a list of plugin
|
||||
@@ -196,7 +237,7 @@ Plugin.fromList = function(names, root, generator, options) {
|
||||
return plugin;
|
||||
});
|
||||
|
||||
if (_.size(failed) > 0) return Q.reject(new Error("Error loading plugins: "+failed.join(",")));
|
||||
if (_.size(failed) > 0) return Q.reject(new Error("Error loading plugins: "+failed.join(",")+". Run 'gitbook install' to install plugins from NPM."));
|
||||
|
||||
// The raw resources extracted from each plugin
|
||||
var pluginResources;
|
||||
@@ -276,7 +317,7 @@ Plugin.fromList = function(names, root, generator, options) {
|
||||
});
|
||||
};
|
||||
|
||||
// Default plugins
|
||||
// Default plugins added to each books
|
||||
Plugin.defaults = [
|
||||
"mathjax"
|
||||
];
|
||||
|
||||
+2
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gitbook",
|
||||
"version": "1.3.3",
|
||||
"version": "1.4.0",
|
||||
"homepage": "http://www.gitbook.io/",
|
||||
"description": "Library and cmd utility to generate GitBooks",
|
||||
"main": "lib/index.js",
|
||||
@@ -19,6 +19,7 @@
|
||||
"highlight.js": "8.3.0",
|
||||
"tmp": "0.0.23",
|
||||
"semver": "2.2.1",
|
||||
"npmi": "0.1.1",
|
||||
"gaze": "~0.5.1",
|
||||
"resolve": "0.6.3",
|
||||
"tiny-lr-fork": "0.0.5",
|
||||
|
||||
+10
-1
@@ -12,7 +12,7 @@ describe('Plugin validation', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Plugin list of names', function () {
|
||||
describe('Plugins list', function () {
|
||||
var firstDefault = _.first(Plugin.defaults);
|
||||
|
||||
it('should convert string to array', function() {
|
||||
@@ -27,6 +27,15 @@ describe('Plugin list of names', function () {
|
||||
it('should remove name starting with -', function() {
|
||||
assert(!_.contains(Plugin.normalizeNames(["-"+firstDefault]), firstDefault));
|
||||
});
|
||||
|
||||
it('should accept version', function() {
|
||||
var _name = "test@0.3.0,exercises@1.2.0,test2";
|
||||
var plugins = Plugin.normalizeList(_name);
|
||||
|
||||
assert(_.find(plugins, {'name': "test"}).version = "0.3.0");
|
||||
assert(_.find(plugins, {'name': "exercises"}).version = "1.2.0");
|
||||
assert(!_.find(plugins, {'name': "test2"}).version);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Plugin defaults loading', function () {
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
{% extends "./layout.html" %}
|
||||
|
||||
{% block title %}Glossary | {{ title }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="page page-toc">
|
||||
<h1>Glossary</h1>
|
||||
{% for item in glossaryIndex %}
|
||||
<section class="normal glossary" id="{{ item.id }}">
|
||||
<h2><a href="#{{ item.id }}">{{ item.name }}</a></h2>
|
||||
<p>{{ item.description }}</p>
|
||||
</section>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -40,6 +40,10 @@
|
||||
<h1>Table of Contents</h1>
|
||||
<ol>
|
||||
{{ articles(summary.chapters) }}
|
||||
|
||||
{% if glossary.length > 0 %}
|
||||
<li><a href="{{ basePath }}/GLOSSARY.html">Glossary</a></li>
|
||||
{% endif %}
|
||||
</ol>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<head>
|
||||
{{ htmlSnippet("head:start")|default("") }}
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=11; IE=10; IE=9; IE=8; IE=7; IE=EDGE" />
|
||||
<title>{% block title %}{% endblock %}</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||
<meta name="description" content="{% block description %}{% endblock %}">
|
||||
|
||||
Reference in New Issue
Block a user