mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-28 13:08:57 +00:00
Compare commits
157 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fdf4a48638 | |||
| 58a3c5634e | |||
| f0ddb6e89f | |||
| 2b408db7cb | |||
| 4e4bd23e2b | |||
| 62d0eb606e | |||
| 0e9beeae14 | |||
| 5e4dbdee24 | |||
| 9435dae6cd | |||
| 813210bf47 | |||
| c372dfc544 | |||
| ac77200683 | |||
| f5afbc90a4 | |||
| b24760c819 | |||
| 6732957e42 | |||
| 1fd0006859 | |||
| 5a205346e3 | |||
| e193004659 | |||
| fe3a9c33d0 | |||
| d83116b88f | |||
| 5f56098ae7 | |||
| 0f935f4372 | |||
| df5c5a8c01 | |||
| 57a0c3bad8 | |||
| 2a52326a45 | |||
| 87e4ee1eeb | |||
| 45833eea9a | |||
| baf10e9b15 | |||
| 463a947df1 | |||
| cceebb4fd9 | |||
| afd5465a61 | |||
| fe604733de | |||
| da22f9f39f | |||
| 284ebbf75d | |||
| 2c08ccad87 | |||
| fa4e234bab | |||
| 35c4179ca1 | |||
| c14ba7ce34 | |||
| 601ce3add3 | |||
| 08ff39fd0b | |||
| 82a6ee3875 | |||
| 3bf592f870 | |||
| 241e205717 | |||
| fb2720ea8d | |||
| 14853befda | |||
| e7f2803d11 | |||
| 320015dd8f | |||
| 471c124a98 | |||
| aa44a109c6 | |||
| 41e5ca8422 | |||
| 53af8b2bb6 | |||
| bd885b135f | |||
| 62a6dde81a | |||
| 14b72b344f | |||
| ac03668063 | |||
| 2512e176c9 | |||
| b613393866 | |||
| 607a6e95de | |||
| 871f574ff7 | |||
| 377e470b15 | |||
| e0a3f0cea5 | |||
| 66727b2736 | |||
| 8215ad977f | |||
| a611dffbdf | |||
| 39f378d8cf | |||
| f00da58153 | |||
| 09b038b16d | |||
| cf601d97ad | |||
| 80edad53d4 | |||
| a972b32769 | |||
| efcaae3e60 | |||
| e0ee591638 | |||
| 310a6d909f | |||
| cefd8fc50f | |||
| a4422593f2 | |||
| e2c5d22756 | |||
| 84385d9dc3 | |||
| 6cfa4c8ab7 | |||
| c76ccc53e1 | |||
| d48eafb1a2 | |||
| 302d9b4b91 | |||
| a091a7f68b | |||
| 53621f6de3 | |||
| 288b965db3 | |||
| 578c9dcfc6 | |||
| 64de17b248 | |||
| d699dff872 | |||
| 501843d624 | |||
| 508ce4283e | |||
| 4aa8e66549 | |||
| 917a6f70d8 | |||
| 2f5e53da55 | |||
| c3cdefc90a | |||
| 9c580e4989 | |||
| dbc75f7352 | |||
| db841a8578 | |||
| 50c902c4e4 | |||
| 84b6e0bde6 | |||
| abc29c3fba | |||
| 8356c534f5 | |||
| 78ff2687b4 | |||
| 9b6586fb36 | |||
| ea133219d0 | |||
| c9b5d81a3c | |||
| d895c63211 | |||
| 8c86da67ca | |||
| a9a230dfc3 | |||
| 6d53e52771 | |||
| 52e10b7cfe | |||
| addac85696 | |||
| 13fb949d68 | |||
| f1b593cfbd | |||
| f998e2dec9 | |||
| 2c0bd53a91 | |||
| 6dd7f6162f | |||
| 475b0bb2b3 | |||
| e6343935e3 | |||
| 946883fd4c | |||
| b1b7e3148b | |||
| 32203f6438 | |||
| f2d3c5d2ed | |||
| 7e2f0ed4bc | |||
| a877acf905 | |||
| ac756ddf7e | |||
| 36e2236e6b | |||
| 72df665520 | |||
| 07785528a5 | |||
| bb579dd581 | |||
| a7d3064340 | |||
| 1a60778248 | |||
| cda4bb5bda | |||
| 7543781046 | |||
| 82f3ffad06 | |||
| dc4d2a1731 | |||
| 2523925915 | |||
| d5bbd8475c | |||
| 54d195268a | |||
| a0deb9509f | |||
| b0b1433594 | |||
| 17a2c0a37c | |||
| fd68ea1cc2 | |||
| 784874c776 | |||
| f45c6d3466 | |||
| 98af70902f | |||
| 41a67b5c4c | |||
| 83ee903af4 | |||
| e591b0e485 | |||
| bcc9a34742 | |||
| 6b56c7de7f | |||
| 7b42719699 | |||
| 64b8343f67 | |||
| fcc5089fa6 | |||
| 334f782aa8 | |||
| 1776f2bf77 | |||
| e259412f79 | |||
| 999a02f110 | |||
| 604d0fba65 |
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"strict": false,
|
||||||
|
"browser": false,
|
||||||
|
"quotmark": true,
|
||||||
|
"node": true,
|
||||||
|
"mocha": true
|
||||||
|
}
|
||||||
+24
-11
@@ -21,24 +21,37 @@ Translators
|
|||||||
------------
|
------------
|
||||||
|
|
||||||
- German
|
- German
|
||||||
- Winnie (@winniehell)
|
- Winnie (@winniehell)
|
||||||
- Italian
|
- Italian
|
||||||
- Giulio Bonanome (@gbonanome)
|
- Giulio Bonanome (@gbonanome)
|
||||||
- Russian
|
- Russian
|
||||||
- Andrey Akinshin (@AndreyAkinshin)
|
- Andrey Akinshin (@AndreyAkinshin)
|
||||||
- Norwegian
|
- Norwegian
|
||||||
- Knut Melvær (@kmelve)
|
- Knut Melvær (@kmelve)
|
||||||
- Persian (Farsi)
|
- Persian (Farsi)
|
||||||
- Mohammad Hossein Mojtahedi (@mhm5000)
|
- Mohammad Hossein Mojtahedi (@mhm5000)
|
||||||
- Polish
|
- Polish
|
||||||
- Łukasz Szeremeta (@lszeremeta)
|
- Łukasz Szeremeta (@lszeremeta)
|
||||||
- Portuguese
|
- Portuguese
|
||||||
- Ryan O'Mullan (@RyanOM)
|
- Ryan O'Mullan (@RyanOM)
|
||||||
- Spanish
|
- Spanish
|
||||||
- Ryan O'Mullan (@RyanOM)
|
- Ryan O'Mullan (@RyanOM)
|
||||||
- Simplifiled Chinese
|
- Simplifiled Chinese
|
||||||
- Hu Hao (@howiehu)
|
- Hu Hao (@howiehu)
|
||||||
- Traditional Chinese
|
- Traditional Chinese
|
||||||
- Hu Hao (@howiehu)
|
- Hu Hao (@howiehu)
|
||||||
- French
|
- French
|
||||||
- Samy Pessé (@SamyPesse)
|
- Samy Pessé (@SamyPesse)
|
||||||
|
- Romanian
|
||||||
|
- Iancu Aurel (@awrelll)
|
||||||
|
- Finnish
|
||||||
|
- Tommi Savikko (@savikko)
|
||||||
|
- Japanese
|
||||||
|
- Iancu Aurel (@awrelll)
|
||||||
|
- Korean
|
||||||
|
- Iancu Aurel (@awrelll)
|
||||||
|
- SangYeob Yu (@deminoth)
|
||||||
|
- Vietnamese
|
||||||
|
- Hong Nguyen (@nghong)
|
||||||
|
- Hebrew
|
||||||
|
- @a-moses
|
||||||
|
|||||||
+72
@@ -2,6 +2,78 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
## 2.4.2
|
||||||
|
- Default plugins should not be installed by `gitbook install`
|
||||||
|
- Limit search index size to avoid crash during generation
|
||||||
|
- Fix code highlighting for html without language specified
|
||||||
|
- Fix warning message for gitbook version when building a multilingual book
|
||||||
|
|
||||||
|
## 2.4.1
|
||||||
|
- Fix disabling of default plugins, ex: `-highlight`
|
||||||
|
|
||||||
|
## 2.4.0
|
||||||
|
- Fix page being updated when user wants to open a link in a new tab
|
||||||
|
- Plugins can now replaced default code highlighter
|
||||||
|
- Add semantic information for screen readers (web version)
|
||||||
|
- Content references accept absolute paths, resolved to book folder
|
||||||
|
- Improve overall reliability
|
||||||
|
|
||||||
|
## 2.3.3
|
||||||
|
- Fix bug in SUMMARY parsing preventing multiple entries without filenames
|
||||||
|
|
||||||
|
## 2.3.2
|
||||||
|
- Fix blocks (like maths) in Asciidoc
|
||||||
|
- Fix error when checking gitbook version
|
||||||
|
|
||||||
|
## 2.3.1
|
||||||
|
- Fix black font color for ebooks (mobi, pdf and epub)
|
||||||
|
- Fix ISO code for korean language
|
||||||
|
- Fix korean translation
|
||||||
|
- Fix syntax highlighting for asciidoc
|
||||||
|
- Fix inline html escaping in markdown
|
||||||
|
- Add warning for file outside SUMMARY
|
||||||
|
- Force SUMMARY entries to be unique by filename
|
||||||
|
|
||||||
|
## 2.3.0
|
||||||
|
- Fix nunjucks issue with multiple `{% raw %}` blocks
|
||||||
|
- Fix crash when git conref failed
|
||||||
|
- Fix crash when failed to download remote image (better error message)
|
||||||
|
- Fix flicking effect when changing page (big UX improvement)
|
||||||
|
- Add Hebrew translation (`he`)
|
||||||
|
- Add utility method `book.config.get` for plugins
|
||||||
|
- Hooks `page:before` and `page` are no longer deprecated
|
||||||
|
- Remove webfonts to make website lighter
|
||||||
|
- Make glossary's order case insensitive
|
||||||
|
|
||||||
|
## 2.2.0
|
||||||
|
- Fix direction in code blocks (always LTR)
|
||||||
|
- Add options `chapterMark` and `pageBreaksBefore` for PDF
|
||||||
|
- Update code highlighting library
|
||||||
|
- `book.json` accessible as `config` in templating syntax
|
||||||
|
- Add Vietnamese translation (`vi`)
|
||||||
|
|
||||||
|
## 2.1.0
|
||||||
|
- Fix error in calcul of `levels` in table of contents, error introduced a few versions ago
|
||||||
|
- Add optional `styles/print.css` to replace `print.css` used in ebook
|
||||||
|
|
||||||
|
## 2.0.4
|
||||||
|
- Fix `{% raw %}`, got confused with "fake" variable declarations
|
||||||
|
- Fix title of language chooser
|
||||||
|
- Fix the X-UA-Compatible meta tag
|
||||||
|
- Move style sheets to the <head> section
|
||||||
|
|
||||||
|
## 2.0.3
|
||||||
|
- Fix `gitbook init` for SUMMARY with empty entries
|
||||||
|
- Fix escaping of code blocks in markdown
|
||||||
|
|
||||||
|
## 2.0.2
|
||||||
|
- Fix relative links in windows
|
||||||
|
- Improve watcher in serve command (switch to chokidar)
|
||||||
|
- Add Romanian translation (`ro`)
|
||||||
|
- Add Finish translation (`fi`)
|
||||||
|
- Add Japanese translation (`jp`)
|
||||||
|
- Add Korean translation (`kr`)
|
||||||
|
|
||||||
## 2.0.1
|
## 2.0.1
|
||||||
- Improve error logging (display file, line and column)
|
- Improve error logging (display file, line and column)
|
||||||
- Add back support for `options.originalInput`
|
- Add back support for `options.originalInput`
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ GitBook
|
|||||||
=======
|
=======
|
||||||
|
|
||||||
[](http://badge.fury.io/js/gitbook)
|
[](http://badge.fury.io/js/gitbook)
|
||||||
[](https://travis-ci.org/GitbookIO/gitbook)
|
[](https://travis-ci.org/GitbookIO/gitbook)
|
||||||
[](https://ci.appveyor.com/project/SamyPesse/gitbook)
|
[](https://ci.appveyor.com/project/GitBook/gitbook)
|
||||||
|
|
||||||
GitBook is a command line tool (and Node.js library) for building beautiful books using GitHub/Git and Markdown (or AsciiDoc). Here is an example: [Learn Javascript](https://www.gitbook.com/book/GitBookIO/javascript).
|
GitBook is a command line tool (and Node.js library) for building beautiful books using GitHub/Git and Markdown (or AsciiDoc). Here is an example: [Learn Javascript](https://www.gitbook.com/book/GitBookIO/javascript).
|
||||||
|
|
||||||
You can publish and host book easily online using [gitbook.com](https://www.gitbook.com), a web-editor is [also available](https://www.gitbook.com/editor).
|
You can publish and host book easily online using [gitbook.com](https://www.gitbook.com), a desktop editor is [also available](https://www.gitbook.com/editor).
|
||||||
|
|
||||||
Stay updated by following [@GitBookIO](https://twitter.com/GitBookIO) on Twitter or [GitBook](https://www.facebook.com/gitbookcom) on Facebook.
|
Stay updated by following [@GitBookIO](https://twitter.com/GitBookIO) on Twitter or [GitBook](https://www.facebook.com/gitbookcom) on Facebook.
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ $ gitbook build
|
|||||||
* [AsciiDoc Support](http://help.gitbook.com/format/asciidoc.html)
|
* [AsciiDoc Support](http://help.gitbook.com/format/asciidoc.html)
|
||||||
* [Variables and Templating](http://help.gitbook.com/format/templating.html)
|
* [Variables and Templating](http://help.gitbook.com/format/templating.html)
|
||||||
* [Content References](http://help.gitbook.com/format/conrefs.html)
|
* [Content References](http://help.gitbook.com/format/conrefs.html)
|
||||||
* [Plugins](http://help.gitbook.com/plugins/index.html)
|
* [Plugins](http://help.gitbook.com/format/plugins.html)
|
||||||
* Interractive reader website:
|
* Interractive reader website:
|
||||||
* Search
|
* Search
|
||||||
* Font Settings (Serif, Sans Serif)
|
* Font Settings (Serif, Sans Serif)
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
var _ = require('lodash');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
// Return non-parsed html
|
||||||
|
// since blocks are by default non-parsable, a simple identity method works fine
|
||||||
|
html: _.identity,
|
||||||
|
|
||||||
|
// Highlight a code block
|
||||||
|
// This block can be extent by plugins
|
||||||
|
code: _.identity
|
||||||
|
};
|
||||||
+106
-76
@@ -1,30 +1,27 @@
|
|||||||
var Q = require("q");
|
var Q = require("q");
|
||||||
var _ = require("lodash");
|
var _ = require("lodash");
|
||||||
var path = require("path");
|
var path = require("path");
|
||||||
var util = require("util");
|
|
||||||
var lunr = require("lunr");
|
var lunr = require("lunr");
|
||||||
var parsers = require("gitbook-parsers");
|
var parsers = require("gitbook-parsers");
|
||||||
var color = require("bash-color");
|
|
||||||
|
|
||||||
var fs = require("./utils/fs");
|
var fs = require("./utils/fs");
|
||||||
var parseNavigation = require("./utils/navigation");
|
var parseNavigation = require("./utils/navigation");
|
||||||
var parseProgress = require("./utils/progress");
|
var parseProgress = require("./utils/progress");
|
||||||
var pageUtil = require("./utils/page");
|
var pageUtil = require("./utils/page");
|
||||||
var batch = require("./utils/batch");
|
var pathUtil = require("./utils/path");
|
||||||
var links = require("./utils/links");
|
var links = require("./utils/links");
|
||||||
var i18n = require("./utils/i18n");
|
var i18n = require("./utils/i18n");
|
||||||
var logger = require("./utils/logger");
|
var logger = require("./utils/logger");
|
||||||
|
|
||||||
var Configuration = require("./configuration");
|
var Configuration = require("./configuration");
|
||||||
var TemplateEngine = require("./template");
|
var TemplateEngine = require("./template");
|
||||||
var Plugin = require("./plugin");
|
|
||||||
var PluginsList = require("./pluginslist");
|
var PluginsList = require("./pluginslist");
|
||||||
|
|
||||||
var generators = require("./generators");
|
var generators = require("./generators");
|
||||||
|
|
||||||
var Book = function(root, context, parent) {
|
var SEARCHINDEX_MAXSIZE = 1000000;
|
||||||
var that = this;
|
|
||||||
|
|
||||||
|
var Book = function(root, context, parent) {
|
||||||
this.context = _.defaults(context || {}, {
|
this.context = _.defaults(context || {}, {
|
||||||
// Extend book configuration
|
// Extend book configuration
|
||||||
config: {},
|
config: {},
|
||||||
@@ -84,11 +81,13 @@ var Book = function(root, context, parent) {
|
|||||||
this.langsFile = null;
|
this.langsFile = null;
|
||||||
|
|
||||||
// Search Index
|
// Search Index
|
||||||
|
this.searchIndexEnabled = true;
|
||||||
|
this.searchIndexSize = 0;
|
||||||
this.searchIndex = lunr(function () {
|
this.searchIndex = lunr(function () {
|
||||||
this.ref('url');
|
this.ref("url");
|
||||||
|
|
||||||
this.field('title', { boost: 10 });
|
this.field("title", { boost: 10 });
|
||||||
this.field('body');
|
this.field("body");
|
||||||
});
|
});
|
||||||
|
|
||||||
// Bind methods
|
// Bind methods
|
||||||
@@ -115,7 +114,7 @@ Book.prototype.parse = function() {
|
|||||||
return that.parseLangs()
|
return that.parseLangs()
|
||||||
.then(function() {
|
.then(function() {
|
||||||
multilingual = that.langs.length > 0;
|
multilingual = that.langs.length > 0;
|
||||||
if (multilingual) that.log.info.ln("Parsing multilingual book, with", that.langs.length, "lanuages");
|
if (multilingual) that.log.info.ln("Parsing multilingual book, with", that.langs.length, "languages");
|
||||||
|
|
||||||
// Sub-books that inherit from the current book configuration
|
// Sub-books that inherit from the current book configuration
|
||||||
that.books = _.map(that.langs, function(lang) {
|
that.books = _.map(that.langs, function(lang) {
|
||||||
@@ -124,12 +123,12 @@ Book.prototype.parse = function() {
|
|||||||
path.join(that.root, lang.path),
|
path.join(that.root, lang.path),
|
||||||
_.merge({}, that.context, {
|
_.merge({}, that.context, {
|
||||||
config: _.extend({}, that.options, {
|
config: _.extend({}, that.options, {
|
||||||
'output': path.join(that.options.output, lang.lang),
|
"output": path.join(that.options.output, lang.lang),
|
||||||
'language': lang.lang
|
"language": lang.lang
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
that
|
that
|
||||||
)
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
@@ -186,7 +185,7 @@ Book.prototype.generate = function(generator) {
|
|||||||
// Create generator
|
// Create generator
|
||||||
.then(function() {
|
.then(function() {
|
||||||
var Generator = generators[generator];
|
var Generator = generators[generator];
|
||||||
if (!Generator) throw "Generator '"+that.options.generator+"' doesn't exist";
|
if (!Generator) throw "Generator \""+that.options.generator+"\" doesn't exist";
|
||||||
generator = new Generator(that);
|
generator = new Generator(that);
|
||||||
|
|
||||||
return generator.prepare();
|
return generator.prepare();
|
||||||
@@ -211,9 +210,9 @@ Book.prototype.generate = function(generator) {
|
|||||||
|
|
||||||
return Q()
|
return Q()
|
||||||
|
|
||||||
// First, let's create folder
|
// First, let"s create folder
|
||||||
.then(function() {
|
.then(function() {
|
||||||
return _.reduce(ops["directories"] || [], function(prev, folder) {
|
return _.reduce(ops.directories || [], function(prev, folder) {
|
||||||
return prev.then(function() {
|
return prev.then(function() {
|
||||||
that.log.debug.ln("transferring folder", folder);
|
that.log.debug.ln("transferring folder", folder);
|
||||||
return Q(generator.transferFolder(folder));
|
return Q(generator.transferFolder(folder));
|
||||||
@@ -221,18 +220,18 @@ Book.prototype.generate = function(generator) {
|
|||||||
}, Q());
|
}, Q());
|
||||||
})
|
})
|
||||||
|
|
||||||
// Then, let's copy other files
|
// Then, let"s copy other files
|
||||||
.then(function() {
|
.then(function() {
|
||||||
return Q.all(_.map(ops["files"] || [], function(file) {
|
return Q.all(_.map(ops.files || [], function(file) {
|
||||||
that.log.debug.ln("transferring file", file);
|
that.log.debug.ln("transferring file", file);
|
||||||
return Q(generator.transferFile(file));
|
return Q(generator.transferFile(file));
|
||||||
}));
|
}));
|
||||||
})
|
})
|
||||||
|
|
||||||
// Finally let's generate content
|
// Finally let"s generate content
|
||||||
.then(function() {
|
.then(function() {
|
||||||
var nFiles = (ops["content"] || []).length;
|
var nFiles = (ops.content || []).length;
|
||||||
return _.reduce(ops["content"] || [], function(prev, file, i) {
|
return _.reduce(ops.content || [], function(prev, file, i) {
|
||||||
return prev.then(function() {
|
return prev.then(function() {
|
||||||
var p = ((i*100)/nFiles).toFixed(0)+"%";
|
var p = ((i*100)/nFiles).toFixed(0)+"%";
|
||||||
that.log.debug.ln("processing", file, p);
|
that.log.debug.ln("processing", file, p);
|
||||||
@@ -266,7 +265,7 @@ Book.prototype.generate = function(generator) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Generate the output for a multilingual book
|
// Generate the output for a multilingual book
|
||||||
Book.prototype.generateMultiLingual = function(generator) {
|
Book.prototype.generateMultiLingual = function() {
|
||||||
var that = this;
|
var that = this;
|
||||||
|
|
||||||
return Q()
|
return Q()
|
||||||
@@ -294,7 +293,7 @@ Book.prototype.generateFile = function(output, options) {
|
|||||||
book.setOutput(tmpDir);
|
book.setOutput(tmpDir);
|
||||||
|
|
||||||
return book.generate(options.ebookFormat)
|
return book.generate(options.ebookFormat)
|
||||||
.then(function(_options) {
|
.then(function() {
|
||||||
var copyFile = function(lang) {
|
var copyFile = function(lang) {
|
||||||
var _outputFile = output;
|
var _outputFile = output;
|
||||||
var _tmpDir = tmpDir;
|
var _tmpDir = tmpDir;
|
||||||
@@ -338,7 +337,7 @@ Book.prototype.generateFile = function(output, options) {
|
|||||||
Book.prototype.parseConfig = function() {
|
Book.prototype.parseConfig = function() {
|
||||||
var that = this;
|
var that = this;
|
||||||
|
|
||||||
that.log.info("loading book configuration....")
|
that.log.info("loading book configuration....");
|
||||||
return that.config.load()
|
return that.config.load()
|
||||||
.then(function() {
|
.then(function() {
|
||||||
that.log.info.ok();
|
that.log.info.ok();
|
||||||
@@ -348,12 +347,11 @@ Book.prototype.parseConfig = function() {
|
|||||||
// Parse list of plugins
|
// Parse list of plugins
|
||||||
Book.prototype.parsePlugins = function() {
|
Book.prototype.parsePlugins = function() {
|
||||||
var that = this;
|
var that = this;
|
||||||
var failed = [];
|
|
||||||
|
|
||||||
// Load plugins
|
// Load plugins
|
||||||
return that.plugins.load(that.options.plugins)
|
return that.plugins.load(that.options.plugins)
|
||||||
.then(function() {
|
.then(function() {
|
||||||
if (_.size(that.plugins.failed) > 0) return Q.reject(new Error("Error loading plugins: "+that.plugins.failed.join(",")+". Run 'gitbook install' to install plugins from NPM."));
|
if (_.size(that.plugins.failed) > 0) return Q.reject(new Error("Error loading plugins: "+that.plugins.failed.join(",")+". Run \"gitbook install\" to install plugins from NPM."));
|
||||||
|
|
||||||
that.log.info.ok(that.plugins.count()+" plugins loaded");
|
that.log.info.ok(that.plugins.count()+" plugins loaded");
|
||||||
that.log.debug.ln("normalize plugins list");
|
that.log.debug.ln("normalize plugins list");
|
||||||
@@ -445,7 +443,7 @@ Book.prototype.parseSummary = function() {
|
|||||||
.then(function(content) {
|
.then(function(content) {
|
||||||
return summary.parser.summary(content, {
|
return summary.parser.summary(content, {
|
||||||
entryPoint: that.readmeFile,
|
entryPoint: that.readmeFile,
|
||||||
entryPointTitle: that.i18n('SUMMARY_INTRODUCTION'),
|
entryPointTitle: that.i18n("SUMMARY_INTRODUCTION"),
|
||||||
files: that.files
|
files: that.files
|
||||||
})
|
})
|
||||||
.fail(function(err) {
|
.fail(function(err) {
|
||||||
@@ -512,7 +510,7 @@ Book.prototype.parsePage = function(filename, options) {
|
|||||||
var interpolate = function(fn) {
|
var interpolate = function(fn) {
|
||||||
return Q(fn(page))
|
return Q(fn(page))
|
||||||
.then(function(_page) {
|
.then(function(_page) {
|
||||||
page = _page;
|
page = _page || page;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -574,7 +572,7 @@ Book.prototype.parsePage = function(filename, options) {
|
|||||||
.then(function(content) {
|
.then(function(content) {
|
||||||
section.content = content;
|
section.content = content;
|
||||||
return _sections.concat([section]);
|
return _sections.concat([section]);
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
}, Q([]));
|
}, Q([]));
|
||||||
})
|
})
|
||||||
@@ -586,8 +584,8 @@ Book.prototype.parsePage = function(filename, options) {
|
|||||||
convertImages: options.convertImages,
|
convertImages: options.convertImages,
|
||||||
input: filename,
|
input: filename,
|
||||||
navigation: that.navigation,
|
navigation: that.navigation,
|
||||||
base: path.dirname(filename) || './',
|
base: path.dirname(filename) || "./",
|
||||||
output: path.dirname(filename) || './',
|
output: path.dirname(filename) || "./",
|
||||||
glossary: that.glossary
|
glossary: that.glossary
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
@@ -622,7 +620,7 @@ Book.prototype.findFile = function(filename) {
|
|||||||
parser: parsers.get(ext),
|
parser: parsers.get(ext),
|
||||||
path: filepath
|
path: filepath
|
||||||
};
|
};
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
}, Q(null));
|
}, Q(null));
|
||||||
};
|
};
|
||||||
@@ -630,21 +628,26 @@ Book.prototype.findFile = function(filename) {
|
|||||||
// Check if a file exists in the book
|
// Check if a file exists in the book
|
||||||
Book.prototype.fileExists = function(filename) {
|
Book.prototype.fileExists = function(filename) {
|
||||||
return fs.exists(
|
return fs.exists(
|
||||||
path.join(this.root, filename)
|
this.resolve(filename)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Check if a file path is inside the book
|
||||||
|
Book.prototype.fileIsInBook = function(filename) {
|
||||||
|
return pathUtil.isInRoot(this.root, filename);
|
||||||
|
};
|
||||||
|
|
||||||
// Read a file
|
// Read a file
|
||||||
Book.prototype.readFile = function(filename) {
|
Book.prototype.readFile = function(filename) {
|
||||||
return fs.readFile(
|
return fs.readFile(
|
||||||
path.join(this.root, filename),
|
this.resolve(filename),
|
||||||
{ encoding: "utf8" }
|
{ encoding: "utf8" }
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return stat for a file
|
// Return stat for a file
|
||||||
Book.prototype.statFile = function(filename) {
|
Book.prototype.statFile = function(filename) {
|
||||||
return fs.stat(path.join(this.root, filename));
|
return fs.stat(this.resolve(filename));
|
||||||
};
|
};
|
||||||
|
|
||||||
// List all files in the book
|
// List all files in the book
|
||||||
@@ -652,28 +655,28 @@ Book.prototype.listAllFiles = function() {
|
|||||||
var that = this;
|
var that = this;
|
||||||
|
|
||||||
return fs.list(this.root, {
|
return fs.list(this.root, {
|
||||||
ignoreFiles: ['.ignore', '.gitignore', '.bookignore'],
|
ignoreFiles: [".ignore", ".gitignore", ".bookignore"],
|
||||||
ignoreRules: [
|
ignoreRules: [
|
||||||
// Skip Git stuff
|
// Skip Git stuff
|
||||||
'.git/',
|
".git/",
|
||||||
'.gitignore',
|
".gitignore",
|
||||||
|
|
||||||
// Skip OS X meta data
|
// Skip OS X meta data
|
||||||
'.DS_Store',
|
".DS_Store",
|
||||||
|
|
||||||
// Skip stuff installed by plugins
|
// Skip stuff installed by plugins
|
||||||
'node_modules',
|
"node_modules",
|
||||||
|
|
||||||
// Skip book outputs
|
// Skip book outputs
|
||||||
'_book',
|
"_book",
|
||||||
'*.pdf',
|
"*.pdf",
|
||||||
'*.epub',
|
"*.epub",
|
||||||
'*.mobi',
|
"*.mobi",
|
||||||
|
|
||||||
// Skip config files
|
// Skip config files
|
||||||
'.ignore',
|
".ignore",
|
||||||
'.bookignore',
|
".bookignore",
|
||||||
'book.json',
|
"book.json",
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
.then(function(_files) {
|
.then(function(_files) {
|
||||||
@@ -682,7 +685,7 @@ Book.prototype.listAllFiles = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Return true if the book is a multilingual book
|
// Return true if the book is a multilingual book
|
||||||
Book.prototype.isMultilingual = function(filename) {
|
Book.prototype.isMultilingual = function() {
|
||||||
return this.books.length > 0;
|
return this.books.length > 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -692,7 +695,7 @@ Book.prototype.parentRoot = function() {
|
|||||||
return this.root;
|
return this.root;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return true if it's a sub-book
|
// Return true if it"s a sub-book
|
||||||
Book.prototype.isSubBook = function() {
|
Book.prototype.isSubBook = function() {
|
||||||
return !!this.parent;
|
return !!this.parent;
|
||||||
};
|
};
|
||||||
@@ -702,39 +705,62 @@ Book.prototype.isEntryPoint = function(fp) {
|
|||||||
return fp == this.readmeFile;
|
return fp == this.readmeFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Resolve a path in book
|
// Alias to book.config.get
|
||||||
Book.prototype.resolve = function(p) {
|
Book.prototype.getConfig = function(key, def) {
|
||||||
return path.resolve(this.root, p);
|
return this.config.get(key, def);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Resolve a path in the book source
|
||||||
|
// Enforce that the output path in the root folder
|
||||||
|
Book.prototype.resolve = function() {
|
||||||
|
return pathUtil.resolveInRoot.apply(null, [this.root].concat(_.toArray(arguments)));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convert an abslute path into a relative path to this
|
||||||
|
Book.prototype.relative = function(p) {
|
||||||
|
return path.relative(this.root, p);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Normalize a path to .html and convert README -> index
|
// Normalize a path to .html and convert README -> index
|
||||||
Book.prototype.contentPath = function(link) {
|
Book.prototype.contentPath = function(link) {
|
||||||
if (
|
if (
|
||||||
path.basename(link, path.extname(link)) == "README"
|
path.basename(link, path.extname(link)) == "README" ||
|
||||||
|| link == this.readmeFile
|
link == this.readmeFile
|
||||||
) {
|
) {
|
||||||
link = path.join(path.dirname(link), "index"+path.extname(link));
|
link = path.join(path.dirname(link), "index"+path.extname(link));
|
||||||
}
|
}
|
||||||
|
|
||||||
link = links.changeExtension(link, ".html");
|
link = links.changeExtension(link, ".html");
|
||||||
return link;
|
return link;
|
||||||
}
|
};
|
||||||
|
|
||||||
// Normalize a link to .html and convert README -> index
|
// Normalize a link to .html and convert README -> index
|
||||||
Book.prototype.contentLink = function(link) {
|
Book.prototype.contentLink = function(link) {
|
||||||
return links.normalize(this.contentPath(link));
|
return links.normalize(this.contentPath(link));
|
||||||
}
|
};
|
||||||
|
|
||||||
// Index a page into the search index
|
// Index a page into the search index
|
||||||
Book.prototype.indexPage = function(page) {
|
Book.prototype.indexPage = function(page) {
|
||||||
var nav = this.navigation[page.path];
|
var nav = this.navigation[page.path];
|
||||||
if (!nav) return;
|
if (!nav || !this.searchIndexEnabled) return;
|
||||||
|
|
||||||
this.log.debug.ln("index page", page.path);
|
this.log.debug.ln("index page", page.path);
|
||||||
|
|
||||||
|
// Extract text from the page
|
||||||
|
var text = pageUtil.extractText(page.sections);
|
||||||
|
|
||||||
|
// Limit size of index (to avoid #941)
|
||||||
|
this.searchIndexSize = this.searchIndexSize + text.length;
|
||||||
|
if (this.searchIndexSize > SEARCHINDEX_MAXSIZE) {
|
||||||
|
this.log.warn.ln("search index is too big, indexing is now disabled");
|
||||||
|
this.searchIndexEnabled = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.searchIndex.add({
|
this.searchIndex.add({
|
||||||
url: this.contentLink(page.path),
|
url: this.contentLink(page.path),
|
||||||
title: nav.title,
|
title: nav.title,
|
||||||
body: pageUtil.extractText(page.sections),
|
body: text
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -747,7 +773,7 @@ Book.prototype._defaultsStructure = function(filename) {
|
|||||||
that.summaryFile = that.summaryFile || that.config.getStructure("summary")+extension;
|
that.summaryFile = that.summaryFile || that.config.getStructure("summary")+extension;
|
||||||
that.glossaryFile = that.glossaryFile || that.config.getStructure("glossary")+extension;
|
that.glossaryFile = that.glossaryFile || that.config.getStructure("glossary")+extension;
|
||||||
that.langsFile = that.langsFile || that.config.getStructure("langs")+extension;
|
that.langsFile = that.langsFile || that.config.getStructure("langs")+extension;
|
||||||
}
|
};
|
||||||
|
|
||||||
// Change output path
|
// Change output path
|
||||||
Book.prototype.setOutput = function(p) {
|
Book.prototype.setOutput = function(p) {
|
||||||
@@ -760,7 +786,7 @@ Book.prototype.setOutput = function(p) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Translate a strign according to the book language
|
// Translate a strign according to the book language
|
||||||
Book.prototype.i18n = function(phrase) {
|
Book.prototype.i18n = function() {
|
||||||
var args = Array.prototype.slice.call(arguments);
|
var args = Array.prototype.slice.call(arguments);
|
||||||
return i18n.__.apply({}, [this.config.normalizeLanguage()].concat(args));
|
return i18n.__.apply({}, [this.config.normalizeLanguage()].concat(args));
|
||||||
};
|
};
|
||||||
@@ -779,30 +805,29 @@ Book.prototype.normError = function(err, opts, defs) {
|
|||||||
err.toString = function() {
|
err.toString = function() {
|
||||||
var attributes = [];
|
var attributes = [];
|
||||||
|
|
||||||
if (this.fileName) attributes.push("In file '"+this.fileName+"'");
|
if (this.fileName) attributes.push("In file \""+this.fileName+"\"");
|
||||||
if (this.lineNumber) attributes.push("Line "+this.lineNumber);
|
if (this.lineNumber) attributes.push("Line "+this.lineNumber);
|
||||||
if (this.columnNumber) attributes.push("Column "+this.columnNumber);
|
if (this.columnNumber) attributes.push("Column "+this.columnNumber);
|
||||||
return (this.name || "Error")+": "+this.message+((attributes.length > 0)? " ("+attributes.join(", ")+")" : "")
|
return (this.name || "Error")+": "+this.message+((attributes.length > 0)? " ("+attributes.join(", ")+")" : "");
|
||||||
};
|
};
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Init and return a book
|
// Init and return a book
|
||||||
Book.init = function(root) {
|
Book.init = function(root, opts) {
|
||||||
var book = new Book(root);
|
var book = new Book(root, opts);
|
||||||
var extensionToUse = ".md";
|
var extensionToUse = ".md";
|
||||||
|
|
||||||
var chaptersPaths = function(chapters) {
|
var chaptersPaths = function(chapters) {
|
||||||
return _.reduce(chapters || [], function(accu, chapter) {
|
return _.reduce(chapters || [], function(accu, chapter) {
|
||||||
if (!chapter.path) return accu;
|
var o = {
|
||||||
|
title: chapter.title
|
||||||
|
};
|
||||||
|
if (chapter.path) o.path = chapter.path;
|
||||||
|
|
||||||
return accu.concat(
|
return accu.concat(
|
||||||
_.filter([
|
[o].concat(chaptersPaths(chapter.articles))
|
||||||
{
|
|
||||||
title: chapter.title,
|
|
||||||
path: chapter.path
|
|
||||||
}
|
|
||||||
].concat(chaptersPaths(chapter.articles)))
|
|
||||||
);
|
);
|
||||||
}, []);
|
}, []);
|
||||||
};
|
};
|
||||||
@@ -821,7 +846,7 @@ Book.init = function(root) {
|
|||||||
var chapters = book.summary.chapters || [];
|
var chapters = book.summary.chapters || [];
|
||||||
extensionToUse = path.extname(summary);
|
extensionToUse = path.extname(summary);
|
||||||
|
|
||||||
if (chapters.length == 0) {
|
if (chapters.length === 0) {
|
||||||
chapters = [
|
chapters = [
|
||||||
{
|
{
|
||||||
title: "Summary",
|
title: "Summary",
|
||||||
@@ -837,18 +862,23 @@ Book.init = function(root) {
|
|||||||
return Q(chaptersPaths(chapters));
|
return Q(chaptersPaths(chapters));
|
||||||
})
|
})
|
||||||
.then(function(chapters) {
|
.then(function(chapters) {
|
||||||
// Create files that don't exist
|
// Create files that don"t exist
|
||||||
return Q.all(_.map(chapters, function(chapter) {
|
return Q.all(_.map(chapters, function(chapter) {
|
||||||
|
if (!chapter.path) return Q();
|
||||||
var absolutePath = path.resolve(book.root, chapter.path);
|
var absolutePath = path.resolve(book.root, chapter.path);
|
||||||
|
|
||||||
return fs.exists(absolutePath)
|
return fs.exists(absolutePath)
|
||||||
.then(function(exists) {
|
.then(function(exists) {
|
||||||
book.log.info.ln("create", chapter.path);
|
if(exists) {
|
||||||
if(exists) return;
|
book.log.info.ln("found", chapter.path);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
book.log.info.ln("create", chapter.path);
|
||||||
|
}
|
||||||
|
|
||||||
return fs.mkdirp(path.dirname(absolutePath))
|
return fs.mkdirp(path.dirname(absolutePath))
|
||||||
.then(function() {
|
.then(function() {
|
||||||
return fs.writeFile(absolutePath, '# '+chapter.title+'\n');
|
return fs.writeFile(absolutePath, "# "+chapter.title+"\n");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|||||||
+68
-33
@@ -1,17 +1,30 @@
|
|||||||
var _ = require("lodash");
|
var _ = require("lodash");
|
||||||
var Q = require("q");
|
var Q = require("q");
|
||||||
var path = require("path");
|
var path = require("path");
|
||||||
var semver = require('semver');
|
var semver = require("semver");
|
||||||
|
|
||||||
var pkg = require('../package.json');
|
var pkg = require("../package.json");
|
||||||
var fs = require("./utils/fs");
|
|
||||||
var i18n = require("./utils/i18n");
|
var i18n = require("./utils/i18n");
|
||||||
|
|
||||||
// Default plugins added to each books
|
// Default plugins added to each books
|
||||||
var defaultsPlugins = [];
|
var DEFAULT_PLUGINS = ["highlight"];
|
||||||
|
|
||||||
|
// Check if a plugin is a default plugin
|
||||||
|
// Plugin should be in the list
|
||||||
|
// And version from book.json specified for this plugin should be satisfied
|
||||||
|
function isDefaultPlugin(name, version) {
|
||||||
|
if (!_.contains(DEFAULT_PLUGINS, name)) return false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
var pluginPkg = require('gitbook-plugin-'+name+'/package.json');
|
||||||
|
return semver.satisfies(pluginPkg.version, version || '*');
|
||||||
|
} catch(e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Normalize a list of plugins to use
|
// Normalize a list of plugins to use
|
||||||
function normalizePluginsList(plugins) {
|
function normalizePluginsList(plugins, addDefaults) {
|
||||||
// Normalize list to an array
|
// Normalize list to an array
|
||||||
plugins = _.isString(plugins) ? plugins.split(",") : (plugins || []);
|
plugins = _.isString(plugins) ? plugins.split(",") : (plugins || []);
|
||||||
|
|
||||||
@@ -23,10 +36,13 @@ function normalizePluginsList(plugins) {
|
|||||||
if (plugin.name) return plugin;
|
if (plugin.name) return plugin;
|
||||||
|
|
||||||
var parts = plugin.split("@");
|
var parts = plugin.split("@");
|
||||||
|
var name = parts[0];
|
||||||
|
var version = parts[1];
|
||||||
return {
|
return {
|
||||||
'name': parts[0],
|
"name": name,
|
||||||
'version': parts[1] // optional
|
"version": version, // optional
|
||||||
}
|
"isDefault": isDefaultPlugin(name, version)
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// List plugins to remove
|
// List plugins to remove
|
||||||
@@ -40,26 +56,30 @@ function normalizePluginsList(plugins) {
|
|||||||
.value();
|
.value();
|
||||||
|
|
||||||
// Merge with defaults
|
// Merge with defaults
|
||||||
plugins = _.chain(plugins)
|
if (addDefaults !== false) {
|
||||||
.concat(_.map(defaultsPlugins, function(plugin) {
|
_.each(DEFAULT_PLUGINS, function(plugin) {
|
||||||
return { 'name': plugin }
|
if (_.find(plugins, { name: plugin })) {
|
||||||
}))
|
return;
|
||||||
.uniq()
|
}
|
||||||
.value();
|
|
||||||
|
|
||||||
// Build final list
|
plugins.push({
|
||||||
|
"name": plugin,
|
||||||
|
"isDefault": true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove plugin that start with '-'
|
||||||
plugins = _.filter(plugins, function(plugin) {
|
plugins = _.filter(plugins, function(plugin) {
|
||||||
return !_.contains(toremove, plugin.name) && !(plugin.name.length > 0 && plugin.name[0] == "-");
|
return !_.contains(toremove, plugin.name) && !(plugin.name.length > 0 && plugin.name[0] == "-");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Remove duplicates
|
||||||
|
plugins = _.uniq(plugins, 'name');
|
||||||
|
|
||||||
return plugins;
|
return plugins;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normalize a list of plugin name to use
|
|
||||||
function normalizePluginsNames(plugins) {
|
|
||||||
return _.pluck(normalizePluginsList(plugins), "name");
|
|
||||||
};
|
|
||||||
|
|
||||||
var Configuration = function(book, options) {
|
var Configuration = function(book, options) {
|
||||||
var that = this;
|
var that = this;
|
||||||
|
|
||||||
@@ -96,11 +116,11 @@ Configuration.prototype.load = function() {
|
|||||||
|
|
||||||
return Q()
|
return Q()
|
||||||
.then(function() {
|
.then(function() {
|
||||||
var configPath, config;
|
var configPath, _config;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
configPath = require.resolve(
|
configPath = require.resolve(
|
||||||
path.resolve(that.book.root, that.options.configFile)
|
that.book.resolve(that.options.configFile)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Invalidate node.js cache for livreloading
|
// Invalidate node.js cache for livreloading
|
||||||
@@ -109,7 +129,7 @@ Configuration.prototype.load = function() {
|
|||||||
_config = require(configPath);
|
_config = require(configPath);
|
||||||
that.options = _.merge(
|
that.options = _.merge(
|
||||||
that.options,
|
that.options,
|
||||||
_.omit(_config, 'configFile', 'defaultsPlugins', 'generator', 'extension')
|
_.omit(_config, "configFile", "defaultsPlugins", "generator", "extension")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
catch(err) {
|
catch(err) {
|
||||||
@@ -118,16 +138,18 @@ Configuration.prototype.load = function() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(function() {
|
.then(function() {
|
||||||
if (!semver.satisfies(pkg.version, that.options.gitbook)) {
|
if (!that.book.isSubBook()) {
|
||||||
throw "GitBook version doesn't satisfy version required by the book: "+that.options.gitbook;
|
if (!semver.satisfies(pkg.version, that.options.gitbook)) {
|
||||||
}
|
throw new Error("GitBook version doesn't satisfy version required by the book: "+that.options.gitbook);
|
||||||
if (that.options.gitbook == "*") {
|
}
|
||||||
that.book.log.warn.ln("you should specify a gitbook version to use in your book.json, for example: "+(_.first(pkg.version.split("."))+".x.x"));
|
if (that.options.gitbook != "*" && !semver.satisfies(semver.inc(pkg.version, "patch"), that.options.gitbook)) {
|
||||||
|
that.book.log.warn.ln("gitbook version specified in your book.json might be too strict for future patches, \""+(_.first(pkg.version.split("."))+".x.x")+"\" is more adequate");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
that.options.output = path.resolve(that.options.output || path.join(that.book.root, "_book"));
|
that.options.output = path.resolve(that.options.output || that.book.resolve("_book"));
|
||||||
that.options.plugins = normalizePluginsList(that.options.plugins);
|
that.options.plugins = normalizePluginsList(that.options.plugins);
|
||||||
that.options.defaultsPlugins = normalizePluginsList(that.options.defaultsPlugins || "");
|
that.options.defaultsPlugins = normalizePluginsList(that.options.defaultsPlugins || "", false);
|
||||||
that.options.plugins = _.union(that.options.plugins, that.options.defaultsPlugins);
|
that.options.plugins = _.union(that.options.plugins, that.options.defaultsPlugins);
|
||||||
that.options.plugins = _.uniq(that.options.plugins, "name");
|
that.options.plugins = _.uniq(that.options.plugins, "name");
|
||||||
|
|
||||||
@@ -156,10 +178,14 @@ Configuration.prototype.normalizeLanguage = function() {
|
|||||||
return i18n.normalizeLanguage(this.options.language);
|
return i18n.normalizeLanguage(this.options.language);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Return a configuration
|
||||||
|
Configuration.prototype.get = function(key, def) {
|
||||||
|
return _.get(this.options, key, def);
|
||||||
|
};
|
||||||
|
|
||||||
// Default configuration
|
// Default configuration
|
||||||
Configuration.DEFAULT = {
|
Configuration.DEFAULT = {
|
||||||
// Options that can't be extend
|
// Options that can"t be extend
|
||||||
"configFile": "book",
|
"configFile": "book",
|
||||||
"generator": "website",
|
"generator": "website",
|
||||||
"extension": null,
|
"extension": null,
|
||||||
@@ -186,6 +212,7 @@ Configuration.DEFAULT = {
|
|||||||
// CSS Styles
|
// CSS Styles
|
||||||
"styles": {
|
"styles": {
|
||||||
"website": "styles/website.css",
|
"website": "styles/website.css",
|
||||||
|
"print": "styles/print.css",
|
||||||
"ebook": "styles/ebook.css",
|
"ebook": "styles/ebook.css",
|
||||||
"pdf": "styles/pdf.css",
|
"pdf": "styles/pdf.css",
|
||||||
"mobi": "styles/mobi.css",
|
"mobi": "styles/mobi.css",
|
||||||
@@ -208,9 +235,9 @@ Configuration.DEFAULT = {
|
|||||||
"variables": {},
|
"variables": {},
|
||||||
|
|
||||||
// Set another theme with your own layout
|
// Set another theme with your own layout
|
||||||
// It's recommended to use plugins or add more options for default theme, though
|
// It"s recommended to use plugins or add more options for default theme, though
|
||||||
// See https://github.com/GitbookIO/gitbook/issues/209
|
// See https://github.com/GitbookIO/gitbook/issues/209
|
||||||
"theme": path.resolve(__dirname, '../theme'),
|
"theme": path.resolve(__dirname, "../theme"),
|
||||||
|
|
||||||
// Links in template (null: default, false: remove, string: new value)
|
// Links in template (null: default, false: remove, string: new value)
|
||||||
"links": {
|
"links": {
|
||||||
@@ -245,6 +272,14 @@ Configuration.DEFAULT = {
|
|||||||
// Choices are [u’a0’, u’a1’, u’a2’, u’a3’, u’a4’, u’a5’, u’a6’, u’b0’, u’b1’, u’b2’, u’b3’, u’b4’, u’b5’, u’b6’, u’legal’, u’letter’]
|
// Choices are [u’a0’, u’a1’, u’a2’, u’a3’, u’a4’, u’a5’, u’a6’, u’b0’, u’b1’, u’b2’, u’b3’, u’b4’, u’b5’, u’b6’, u’legal’, u’letter’]
|
||||||
"paperSize": "a4",
|
"paperSize": "a4",
|
||||||
|
|
||||||
|
// How to mark detected chapters.
|
||||||
|
// Choices are “pagebreak”, “rule”, "both" or “none”.
|
||||||
|
"chapterMark" : "pagebreak",
|
||||||
|
|
||||||
|
// An XPath expression. Page breaks are inserted before the specified elements.
|
||||||
|
// To disable use the expression: "/"
|
||||||
|
"pageBreaksBefore": "/",
|
||||||
|
|
||||||
// Margin (in pts)
|
// Margin (in pts)
|
||||||
// Note: 72 pts equals 1 inch
|
// Note: 72 pts equals 1 inch
|
||||||
"margin": {
|
"margin": {
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
var path = require("path");
|
||||||
|
var nunjucks = require("nunjucks");
|
||||||
|
|
||||||
|
var git = require("./utils/git");
|
||||||
|
var fs = require("./utils/fs");
|
||||||
|
var pathUtil = require("./utils/path");
|
||||||
|
|
||||||
|
// The loader should handle relative and git url
|
||||||
|
var BookLoader = nunjucks.Loader.extend({
|
||||||
|
async: true,
|
||||||
|
|
||||||
|
init: function(book) {
|
||||||
|
this.book = book;
|
||||||
|
},
|
||||||
|
|
||||||
|
getSource: function(fileurl, callback) {
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
git.resolveFile(fileurl)
|
||||||
|
.then(function(filepath) {
|
||||||
|
// Is local file
|
||||||
|
if (!filepath) filepath = path.resolve(fileurl);
|
||||||
|
else that.book.log.debug.ln("resolve from git", fileurl, "to", filepath);
|
||||||
|
|
||||||
|
// Read file from absolute path
|
||||||
|
return fs.readFile(filepath)
|
||||||
|
.then(function(source) {
|
||||||
|
return {
|
||||||
|
src: source.toString(),
|
||||||
|
path: filepath
|
||||||
|
};
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.nodeify(callback);
|
||||||
|
},
|
||||||
|
|
||||||
|
resolve: function(from, to) {
|
||||||
|
// If origin is in the book, we enforce result file to be in the book
|
||||||
|
if (this.book.fileIsInBook(from)) {
|
||||||
|
return this.book.resolve(
|
||||||
|
this.book.relative(path.dirname(from)),
|
||||||
|
to
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If origin is in a git repository, we resolve file in the git repository
|
||||||
|
var gitRoot = git.resolveRoot(from);
|
||||||
|
if (gitRoot) {
|
||||||
|
return pathUtil.resolveInRoot(gitRoot, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If origin is not in the book (include from a git content ref)
|
||||||
|
return path.resolve(path.dirname(from), to);
|
||||||
|
},
|
||||||
|
|
||||||
|
// Handle all files as relative, so that nunjucks pass responsability to "resolve"
|
||||||
|
// Only git urls are considered as absolute
|
||||||
|
isRelative: function(filename) {
|
||||||
|
return !git.checkUrl(filename);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = BookLoader;
|
||||||
+4
-6
@@ -3,8 +3,6 @@ var path = require("path");
|
|||||||
var Q = require("q");
|
var Q = require("q");
|
||||||
var fs = require("./utils/fs");
|
var fs = require("./utils/fs");
|
||||||
|
|
||||||
var Plugin = require("./plugin");
|
|
||||||
|
|
||||||
var BaseGenerator = function(book) {
|
var BaseGenerator = function(book) {
|
||||||
this.book = book;
|
this.book = book;
|
||||||
|
|
||||||
@@ -36,7 +34,7 @@ BaseGenerator.prototype.convertFile = function(input) {
|
|||||||
// Copy file to the output (non parsable)
|
// Copy file to the output (non parsable)
|
||||||
BaseGenerator.prototype.transferFile = function(input) {
|
BaseGenerator.prototype.transferFile = function(input) {
|
||||||
return fs.copy(
|
return fs.copy(
|
||||||
path.join(this.book.root, input),
|
this.book.resolve(input),
|
||||||
path.join(this.options.output, input)
|
path.join(this.options.output, input)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -53,8 +51,8 @@ BaseGenerator.prototype.copyCover = function() {
|
|||||||
var that = this;
|
var that = this;
|
||||||
|
|
||||||
return Q.all([
|
return Q.all([
|
||||||
fs.copy(path.join(that.book.root, "cover.jpg"), path.join(that.options.output, "cover.jpg")),
|
fs.copy(that.book.resolve("cover.jpg"), path.join(that.options.output, "cover.jpg")),
|
||||||
fs.copy(path.join(that.book.root, "cover_small.jpg"), path.join(that.options.output, "cover_small.jpg"))
|
fs.copy(that.book.resolve("cover_small.jpg"), path.join(that.options.output, "cover_small.jpg"))
|
||||||
])
|
])
|
||||||
.fail(function() {
|
.fail(function() {
|
||||||
// If orignaly from multi-lang, try copy from parent
|
// If orignaly from multi-lang, try copy from parent
|
||||||
@@ -65,7 +63,7 @@ BaseGenerator.prototype.copyCover = function() {
|
|||||||
fs.copy(path.join(that.book.parentRoot(), "cover_small.jpg"), path.join(that.options.output, "cover_small.jpg"))
|
fs.copy(path.join(that.book.parentRoot(), "cover_small.jpg"), path.join(that.options.output, "cover_small.jpg"))
|
||||||
]);
|
]);
|
||||||
})
|
})
|
||||||
.fail(function(err) {
|
.fail(function() {
|
||||||
return Q();
|
return Q();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
+13
-13
@@ -2,7 +2,7 @@ var util = require("util");
|
|||||||
var path = require("path");
|
var path = require("path");
|
||||||
var Q = require("q");
|
var Q = require("q");
|
||||||
var _ = require("lodash");
|
var _ = require("lodash");
|
||||||
var exec = require('child_process').exec;
|
var exec = require("child_process").exec;
|
||||||
|
|
||||||
var fs = require("../utils/fs");
|
var fs = require("../utils/fs");
|
||||||
var stringUtils = require("../utils/string");
|
var stringUtils = require("../utils/string");
|
||||||
@@ -18,7 +18,7 @@ var Generator = function(book, format) {
|
|||||||
this.namespace = "ebook";
|
this.namespace = "ebook";
|
||||||
|
|
||||||
// Styles to use
|
// Styles to use
|
||||||
this.styles = _.compact(["ebook", this.ebookFormat]);
|
this.styles = _.compact(["print", "ebook", this.ebookFormat]);
|
||||||
|
|
||||||
// Convert images (svg -> png)
|
// Convert images (svg -> png)
|
||||||
this.convertImages = true;
|
this.convertImages = true;
|
||||||
@@ -26,9 +26,9 @@ var Generator = function(book, format) {
|
|||||||
util.inherits(Generator, BaseGenerator);
|
util.inherits(Generator, BaseGenerator);
|
||||||
|
|
||||||
Generator.prototype.prepareTemplates = function() {
|
Generator.prototype.prepareTemplates = function() {
|
||||||
this.templates["page"] = this.book.plugins.template("ebook:page") || path.resolve(this.options.theme, 'templates/ebook/page.html');
|
this.templates.page = this.book.plugins.template("ebook:page") || path.resolve(this.options.theme, "templates/ebook/page.html");
|
||||||
this.templates["summary"] = this.book.plugins.template("ebook:summary") || path.resolve(this.options.theme, 'templates/ebook/summary.html');
|
this.templates.summary = this.book.plugins.template("ebook:summary") || path.resolve(this.options.theme, "templates/ebook/summary.html");
|
||||||
this.templates["glossary"] = this.book.plugins.template("ebook:glossary") || path.resolve(this.options.theme, 'templates/ebook/glossary.html');
|
this.templates.glossary = this.book.plugins.template("ebook:glossary") || path.resolve(this.options.theme, "templates/ebook/glossary.html");
|
||||||
|
|
||||||
return Q();
|
return Q();
|
||||||
};
|
};
|
||||||
@@ -38,7 +38,7 @@ Generator.prototype.writeSummary = function() {
|
|||||||
var that = this;
|
var that = this;
|
||||||
|
|
||||||
that.book.log.info.ln("write SUMMARY.html");
|
that.book.log.info.ln("write SUMMARY.html");
|
||||||
return this._writeTemplate(this.templates["summary"], {}, path.join(this.options.output, "SUMMARY.html"));
|
return this._writeTemplate(this.templates.summary, {}, path.join(this.options.output, "SUMMARY.html"));
|
||||||
};
|
};
|
||||||
|
|
||||||
Generator.prototype.finish = function() {
|
Generator.prototype.finish = function() {
|
||||||
@@ -52,12 +52,12 @@ Generator.prototype.finish = function() {
|
|||||||
.then(function() {
|
.then(function() {
|
||||||
if (!that.ebookFormat) return Q();
|
if (!that.ebookFormat) return Q();
|
||||||
|
|
||||||
var d = Q.defer();
|
|
||||||
|
|
||||||
if (!that.options.cover && fs.existsSync(path.join(that.options.output, "cover.jpg"))) {
|
if (!that.options.cover && fs.existsSync(path.join(that.options.output, "cover.jpg"))) {
|
||||||
that.options.cover = path.join(that.options.output, "cover.jpg");
|
that.options.cover = path.join(that.options.output, "cover.jpg");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var d = Q.defer();
|
||||||
|
|
||||||
var _options = {
|
var _options = {
|
||||||
"--cover": that.options.cover,
|
"--cover": that.options.cover,
|
||||||
"--title": that.options.title,
|
"--title": that.options.title,
|
||||||
@@ -68,8 +68,6 @@ Generator.prototype.finish = function() {
|
|||||||
"--book-producer": "GitBook",
|
"--book-producer": "GitBook",
|
||||||
"--publisher": "GitBook",
|
"--publisher": "GitBook",
|
||||||
"--chapter": "descendant-or-self::*[contains(concat(' ', normalize-space(@class), ' '), ' book-chapter ')]",
|
"--chapter": "descendant-or-self::*[contains(concat(' ', normalize-space(@class), ' '), ' book-chapter ')]",
|
||||||
"--chapter-mark": "pagebreak",
|
|
||||||
"--page-breaks-before": "/",
|
|
||||||
"--level1-toc": "descendant-or-self::*[contains(concat(' ', normalize-space(@class), ' '), ' book-chapter-1 ')]",
|
"--level1-toc": "descendant-or-self::*[contains(concat(' ', normalize-space(@class), ' '), ' book-chapter-1 ')]",
|
||||||
"--level2-toc": "descendant-or-self::*[contains(concat(' ', normalize-space(@class), ' '), ' book-chapter-2 ')]",
|
"--level2-toc": "descendant-or-self::*[contains(concat(' ', normalize-space(@class), ' '), ' book-chapter-2 ')]",
|
||||||
"--level3-toc": "descendant-or-self::*[contains(concat(' ', normalize-space(@class), ' '), ' book-chapter-3 ')]",
|
"--level3-toc": "descendant-or-self::*[contains(concat(' ', normalize-space(@class), ' '), ' book-chapter-3 ')]",
|
||||||
@@ -82,6 +80,8 @@ Generator.prototype.finish = function() {
|
|||||||
var pdfOptions = that.options.pdf;
|
var pdfOptions = that.options.pdf;
|
||||||
|
|
||||||
_.extend(_options, {
|
_.extend(_options, {
|
||||||
|
"--chapter-mark": String(pdfOptions.chapterMark),
|
||||||
|
"--page-breaks-before": String(pdfOptions.pageBreaksBefore),
|
||||||
"--margin-left": String(pdfOptions.margin.left),
|
"--margin-left": String(pdfOptions.margin.left),
|
||||||
"--margin-right": String(pdfOptions.margin.right),
|
"--margin-right": String(pdfOptions.margin.right),
|
||||||
"--margin-top": String(pdfOptions.margin.top),
|
"--margin-top": String(pdfOptions.margin.top),
|
||||||
@@ -108,7 +108,7 @@ Generator.prototype.finish = function() {
|
|||||||
|
|
||||||
that.book.log.info("start conversion to", that.ebookFormat, "....");
|
that.book.log.info("start conversion to", that.ebookFormat, "....");
|
||||||
|
|
||||||
var child = exec(command, function (error, stdout, stderr) {
|
var child = exec(command, function (error, stdout) {
|
||||||
if (error) {
|
if (error) {
|
||||||
that.book.log.info.fail();
|
that.book.log.info.fail();
|
||||||
|
|
||||||
@@ -124,11 +124,11 @@ Generator.prototype.finish = function() {
|
|||||||
d.resolve();
|
d.resolve();
|
||||||
});
|
});
|
||||||
|
|
||||||
child.stdout.on('data', function (data) {
|
child.stdout.on("data", function (data) {
|
||||||
that.book.log.debug(data);
|
that.book.log.debug(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
child.stderr.on('data', function (data) {
|
child.stderr.on("data", function (data) {
|
||||||
that.book.log.debug(data);
|
that.book.log.debug(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ var Generator = function() {
|
|||||||
util.inherits(Generator, BaseGenerator);
|
util.inherits(Generator, BaseGenerator);
|
||||||
|
|
||||||
// Ignore some methods
|
// Ignore some methods
|
||||||
Generator.prototype.transferFile = function(input) { };
|
Generator.prototype.transferFile = function() { };
|
||||||
|
|
||||||
// Convert an input file
|
// Convert an input file
|
||||||
Generator.prototype.convertFile = function(input) {
|
Generator.prototype.convertFile = function(input) {
|
||||||
@@ -44,7 +44,7 @@ Generator.prototype.finish = function() {
|
|||||||
// Write README.json
|
// Write README.json
|
||||||
Generator.prototype.writeReadme = function() {
|
Generator.prototype.writeReadme = function() {
|
||||||
var that = this;
|
var that = this;
|
||||||
var mainlang, langs;
|
var mainLang, langs, readme;
|
||||||
|
|
||||||
return Q()
|
return Q()
|
||||||
.then(function() {
|
.then(function() {
|
||||||
|
|||||||
+21
-24
@@ -4,13 +4,12 @@ var Q = require("q");
|
|||||||
var _ = require("lodash");
|
var _ = require("lodash");
|
||||||
|
|
||||||
var nunjucks = require("nunjucks");
|
var nunjucks = require("nunjucks");
|
||||||
var AutoEscapeExtension = require("nunjucks-autoescape");
|
var AutoEscapeExtension = require("nunjucks-autoescape")(nunjucks);
|
||||||
var FilterExtension = require("nunjucks-filter");
|
var FilterExtension = require("nunjucks-filter")(nunjucks);
|
||||||
|
|
||||||
var fs = require("../utils/fs");
|
var fs = require("../utils/fs");
|
||||||
var BaseGenerator = require("../generator");
|
var BaseGenerator = require("../generator");
|
||||||
var links = require("../utils/links");
|
var links = require("../utils/links");
|
||||||
var pageUtil = require("../utils/page");
|
|
||||||
var i18n = require("../utils/i18n");
|
var i18n = require("../utils/i18n");
|
||||||
|
|
||||||
var pkg = require("../../package.json");
|
var pkg = require("../../package.json");
|
||||||
@@ -50,12 +49,13 @@ Generator.prototype.prepareStyles = function() {
|
|||||||
this.styles = _.chain(this.styles)
|
this.styles = _.chain(this.styles)
|
||||||
.map(function(style) {
|
.map(function(style) {
|
||||||
var stylePath = that.options.styles[style];
|
var stylePath = that.options.styles[style];
|
||||||
if (fs.existsSync(path.resolve(that.book.root, stylePath))) {
|
if (stylePath && fs.existsSync(that.book.resolve(stylePath))) {
|
||||||
return stylePath;
|
return [style, stylePath];
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
})
|
})
|
||||||
.compact()
|
.compact()
|
||||||
|
.object()
|
||||||
.value();
|
.value();
|
||||||
|
|
||||||
return Q();
|
return Q();
|
||||||
@@ -63,9 +63,9 @@ Generator.prototype.prepareStyles = function() {
|
|||||||
|
|
||||||
// Prepare templates
|
// Prepare templates
|
||||||
Generator.prototype.prepareTemplates = function() {
|
Generator.prototype.prepareTemplates = function() {
|
||||||
this.templates["page"] = this.book.plugins.template("site:page") || path.resolve(this.options.theme, 'templates/website/page.html');
|
this.templates.page = this.book.plugins.template("site:page") || path.resolve(this.options.theme, "templates/website/page.html");
|
||||||
this.templates["langs"] = this.book.plugins.template("site:langs") || path.resolve(this.options.theme, 'templates/website/langs.html');
|
this.templates.langs = this.book.plugins.template("site:langs") || path.resolve(this.options.theme, "templates/website/langs.html");
|
||||||
this.templates["glossary"] = this.book.plugins.template("site:glossary") || path.resolve(this.options.theme, 'templates/website/glossary.html');
|
this.templates.glossary = this.book.plugins.template("site:glossary") || path.resolve(this.options.theme, "templates/website/glossary.html");
|
||||||
|
|
||||||
return Q();
|
return Q();
|
||||||
};
|
};
|
||||||
@@ -97,14 +97,13 @@ Generator.prototype.prepareTemplateEngine = function() {
|
|||||||
|
|
||||||
// Add filter
|
// Add filter
|
||||||
that.env.addFilter("contentLink", that.book.contentLink.bind(that.book));
|
that.env.addFilter("contentLink", that.book.contentLink.bind(that.book));
|
||||||
that.env.addFilter('lvl', function(lvl) {
|
that.env.addFilter("lvl", function(lvl) {
|
||||||
return lvl.split(".").length;
|
return lvl.split(".").length;
|
||||||
});
|
});
|
||||||
that.env.addGlobal('__', that.book.i18n.bind(that.book));
|
|
||||||
|
|
||||||
// Add extension
|
// Add extension
|
||||||
that.env.addExtension('AutoEscapeExtension', new AutoEscapeExtension(that.env));
|
that.env.addExtension("AutoEscapeExtension", new AutoEscapeExtension(that.env));
|
||||||
that.env.addExtension('FilterExtension', new FilterExtension(that.env));
|
that.env.addExtension("FilterExtension", new FilterExtension(that.env));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -114,7 +113,7 @@ Generator.prototype.finish = function() {
|
|||||||
.then(this.copyCover)
|
.then(this.copyCover)
|
||||||
.then(this.writeGlossary)
|
.then(this.writeGlossary)
|
||||||
.then(this.writeSearchIndex)
|
.then(this.writeSearchIndex)
|
||||||
.then(this.writeLangsIndex)
|
.then(this.writeLangsIndex);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Convert an input file
|
// Convert an input file
|
||||||
@@ -135,11 +134,11 @@ Generator.prototype.convertFile = function(input) {
|
|||||||
var output = path.join(that.options.output, relativeOutput);
|
var output = path.join(that.options.output, relativeOutput);
|
||||||
|
|
||||||
var basePath = path.relative(path.dirname(output), that.options.output) || ".";
|
var basePath = path.relative(path.dirname(output), that.options.output) || ".";
|
||||||
if (process.platform === 'win32') basePath = basePath.replace(/\\/g, '/');
|
if (process.platform === "win32") basePath = basePath.replace(/\\/g, "/");
|
||||||
|
|
||||||
that.book.log.debug.ln("write parsed file", page.path, "to", relativeOutput);
|
that.book.log.debug.ln("write parsed file", page.path, "to", relativeOutput);
|
||||||
|
|
||||||
return that._writeTemplate(that.templates["page"], {
|
return that._writeTemplate(that.templates.page, {
|
||||||
progress: page.progress,
|
progress: page.progress,
|
||||||
|
|
||||||
_input: page.path,
|
_input: page.path,
|
||||||
@@ -153,27 +152,23 @@ Generator.prototype.convertFile = function(input) {
|
|||||||
|
|
||||||
// Write the index for langs
|
// Write the index for langs
|
||||||
Generator.prototype.writeLangsIndex = function() {
|
Generator.prototype.writeLangsIndex = function() {
|
||||||
var that = this;
|
|
||||||
if (!this.book.langs.length) return Q();
|
if (!this.book.langs.length) return Q();
|
||||||
return this._writeTemplate(this.templates["langs"], {
|
|
||||||
|
return this._writeTemplate(this.templates.langs, {
|
||||||
langs: this.book.langs
|
langs: this.book.langs
|
||||||
}, path.join(this.options.output, "index.html"));
|
}, path.join(this.options.output, "index.html"));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Write glossary
|
// Write glossary
|
||||||
Generator.prototype.writeGlossary = function() {
|
Generator.prototype.writeGlossary = function() {
|
||||||
var that = this;
|
|
||||||
|
|
||||||
// No glossary
|
// No glossary
|
||||||
if (this.book.glossary.length == 0) return Q();
|
if (this.book.glossary.length === 0) return Q();
|
||||||
|
|
||||||
return this._writeTemplate(this.templates["glossary"], {}, path.join(this.options.output, "GLOSSARY.html"));
|
return this._writeTemplate(this.templates.glossary, {}, path.join(this.options.output, "GLOSSARY.html"));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Write the search index
|
// Write the search index
|
||||||
Generator.prototype.writeSearchIndex = function() {
|
Generator.prototype.writeSearchIndex = function() {
|
||||||
var that = this;
|
|
||||||
|
|
||||||
return fs.writeFile(
|
return fs.writeFile(
|
||||||
path.join(this.options.output, "search_index.json"),
|
path.join(this.options.output, "search_index.json"),
|
||||||
JSON.stringify(this.book.searchIndex)
|
JSON.stringify(this.book.searchIndex)
|
||||||
@@ -207,7 +202,7 @@ Generator.prototype._writeTemplate = function(tpl, options, output, interpolate)
|
|||||||
|
|
||||||
interpolate = interpolate || _.identity;
|
interpolate = interpolate || _.identity;
|
||||||
return Q()
|
return Q()
|
||||||
.then(function(sections) {
|
.then(function() {
|
||||||
return that.env.render(
|
return that.env.render(
|
||||||
tpl,
|
tpl,
|
||||||
_.extend({
|
_.extend({
|
||||||
@@ -238,6 +233,8 @@ Generator.prototype._writeTemplate = function(tpl, options, output, interpolate)
|
|||||||
|
|
||||||
basePath: ".",
|
basePath: ".",
|
||||||
staticBase: path.join(".", "gitbook"),
|
staticBase: path.join(".", "gitbook"),
|
||||||
|
|
||||||
|
"__": that.book.i18n.bind(that.book)
|
||||||
}, options)
|
}, options)
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
|||||||
+21
-22
@@ -1,11 +1,10 @@
|
|||||||
var Q = require("q");
|
var Q = require("q");
|
||||||
var _ = require("lodash");
|
var _ = require("lodash");
|
||||||
var path = require("path");
|
var path = require("path");
|
||||||
var tinylr = require('tiny-lr');
|
var tinylr = require("tiny-lr");
|
||||||
var color = require('bash-color');
|
var color = require("bash-color");
|
||||||
|
|
||||||
var Book = require("./book");
|
var Book = require("./book");
|
||||||
var Plugin = require("./plugin");
|
|
||||||
var Server = require("./utils/server");
|
var Server = require("./utils/server");
|
||||||
var stringUtils = require("./utils/string");
|
var stringUtils = require("./utils/string");
|
||||||
var watch = require("./utils/watch");
|
var watch = require("./utils/watch");
|
||||||
@@ -42,10 +41,10 @@ module.exports = {
|
|||||||
var output = args[1] || path.join(input, "_book");
|
var output = args[1] || path.join(input, "_book");
|
||||||
|
|
||||||
var book = new Book(input, _.extend({}, {
|
var book = new Book(input, _.extend({}, {
|
||||||
'config': {
|
"config": {
|
||||||
'output': output
|
"output": output
|
||||||
},
|
},
|
||||||
'logLevel': kwargs.log
|
"logLevel": kwargs.log
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return book.parse()
|
return book.parse()
|
||||||
@@ -71,7 +70,7 @@ module.exports = {
|
|||||||
var output = args[1];
|
var output = args[1];
|
||||||
|
|
||||||
var book = new Book(input, _.extend({}, {
|
var book = new Book(input, _.extend({}, {
|
||||||
'logLevel': kwargs.log
|
"logLevel": kwargs.log
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return book.parse()
|
return book.parse()
|
||||||
@@ -116,7 +115,7 @@ module.exports = {
|
|||||||
|
|
||||||
// Init livereload server
|
// Init livereload server
|
||||||
var lrServer = tinylr({});
|
var lrServer = tinylr({});
|
||||||
var lrPath = undefined;
|
var lrPath;
|
||||||
|
|
||||||
var generate = function() {
|
var generate = function() {
|
||||||
if (server.isRunning()) console.log("Stopping server");
|
if (server.isRunning()) console.log("Stopping server");
|
||||||
@@ -124,10 +123,10 @@ module.exports = {
|
|||||||
return server.stop()
|
return server.stop()
|
||||||
.then(function() {
|
.then(function() {
|
||||||
var book = new Book(input, _.extend({}, {
|
var book = new Book(input, _.extend({}, {
|
||||||
'config': {
|
"config": {
|
||||||
'defaultsPlugins': ["livereload"]
|
"defaultsPlugins": ["livereload"]
|
||||||
},
|
},
|
||||||
'logLevel': kwargs.log
|
"logLevel": kwargs.log
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return book.parse()
|
return book.parse()
|
||||||
@@ -138,10 +137,10 @@ module.exports = {
|
|||||||
})
|
})
|
||||||
.then(function(book) {
|
.then(function(book) {
|
||||||
console.log();
|
console.log();
|
||||||
console.log('Starting server ...');
|
console.log("Starting server ...");
|
||||||
return server.start(book.options.output, kwargs.port)
|
return server.start(book.options.output, kwargs.port)
|
||||||
.then(function() {
|
.then(function() {
|
||||||
console.log('Serving book on http://localhost:'+kwargs.port);
|
console.log("Serving book on http://localhost:"+kwargs.port);
|
||||||
|
|
||||||
if (lrPath) {
|
if (lrPath) {
|
||||||
// trigger livereload
|
// trigger livereload
|
||||||
@@ -158,19 +157,19 @@ module.exports = {
|
|||||||
.then(function(filepath) {
|
.then(function(filepath) {
|
||||||
// set livereload path
|
// set livereload path
|
||||||
lrPath = filepath;
|
lrPath = filepath;
|
||||||
console.log("Restart after change in files");
|
console.log("Restart after change in file", filepath);
|
||||||
console.log('');
|
console.log("");
|
||||||
return generate();
|
return generate();
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return Q.nfcall(lrServer.listen.bind(lrServer), kwargs.lrport)
|
return Q.nfcall(lrServer.listen.bind(lrServer), kwargs.lrport)
|
||||||
.then(function() {
|
.then(function() {
|
||||||
console.log('Live reload server started on port:', kwargs.lrport);
|
console.log("Live reload server started on port:", kwargs.lrport);
|
||||||
console.log('Press CTRL+C to quit ...');
|
console.log("Press CTRL+C to quit ...");
|
||||||
console.log('')
|
console.log("");
|
||||||
return generate();
|
return generate();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -179,7 +178,7 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
name: "install [book]",
|
name: "install [book]",
|
||||||
description: "install plugins dependencies",
|
description: "install plugins dependencies",
|
||||||
exec: function(args, kwargs) {
|
exec: function(args) {
|
||||||
var input = args[0] || process.cwd();
|
var input = args[0] || process.cwd();
|
||||||
|
|
||||||
var book = new Book(input);
|
var book = new Book(input);
|
||||||
@@ -198,7 +197,7 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
name: "init [directory]",
|
name: "init [directory]",
|
||||||
description: "create files and folders based on contents of SUMMARY.md",
|
description: "create files and folders based on contents of SUMMARY.md",
|
||||||
exec: function(args, kwargs) {
|
exec: function(args) {
|
||||||
return Book.init(args[0] || process.cwd())
|
return Book.init(args[0] || process.cwd())
|
||||||
.then(function(){
|
.then(function(){
|
||||||
console.log("");
|
console.log("");
|
||||||
|
|||||||
+6
-6
@@ -4,7 +4,7 @@ var semver = require("semver");
|
|||||||
var path = require("path");
|
var path = require("path");
|
||||||
var url = require("url");
|
var url = require("url");
|
||||||
var fs = require("./utils/fs");
|
var fs = require("./utils/fs");
|
||||||
var resolve = require('resolve');
|
var resolve = require("resolve");
|
||||||
|
|
||||||
var pkg = require("../package.json");
|
var pkg = require("../package.json");
|
||||||
|
|
||||||
@@ -33,8 +33,8 @@ var Plugin = function(book, name) {
|
|||||||
// Type of plugins resources
|
// Type of plugins resources
|
||||||
Plugin.RESOURCES = ["js", "css"];
|
Plugin.RESOURCES = ["js", "css"];
|
||||||
Plugin.HOOKS = [
|
Plugin.HOOKS = [
|
||||||
"init", "finish", "finish:before"
|
"init", "finish", "finish:before", "page", "page:before"
|
||||||
]
|
];
|
||||||
|
|
||||||
// Load from a name
|
// Load from a name
|
||||||
Plugin.prototype.load = function(name, baseDir) {
|
Plugin.prototype.load = function(name, baseDir) {
|
||||||
@@ -77,7 +77,7 @@ Plugin.prototype._getResources = function(base) {
|
|||||||
var book = this.infos[base];
|
var book = this.infos[base];
|
||||||
|
|
||||||
// Compatibility with version 1.x.x
|
// Compatibility with version 1.x.x
|
||||||
if (base == "website") book = book || this.infos["book"];
|
if (base == "website") book = book || this.infos.book;
|
||||||
|
|
||||||
// Nothing specified, fallback to default
|
// Nothing specified, fallback to default
|
||||||
if (!book) {
|
if (!book) {
|
||||||
@@ -155,7 +155,7 @@ Plugin.prototype.callHook = function(name, data) {
|
|||||||
if (!hookFunc) return Q(data);
|
if (!hookFunc) return Q(data);
|
||||||
|
|
||||||
this.book.log.debug.ln("call hook", name);
|
this.book.log.debug.ln("call hook", name);
|
||||||
if (!_.contains(Plugin.HOOKS, name)) this.book.log.warn.ln("hook '"+name+"' used by plugin '"+this.name+"' is deprecated, and will be remove in the coming versions");
|
if (!_.contains(Plugin.HOOKS, name)) this.book.log.warn.ln("hook '"+name+"' used by plugin '"+this.name+"' is deprecated, and will be removed in the coming versions");
|
||||||
|
|
||||||
return Q()
|
return Q()
|
||||||
.then(function() {
|
.then(function() {
|
||||||
@@ -168,7 +168,7 @@ Plugin.prototype.copyAssets = function(out, base) {
|
|||||||
var that = this;
|
var that = this;
|
||||||
|
|
||||||
return this.getResources(base)
|
return this.getResources(base)
|
||||||
.get('assets')
|
.get("assets")
|
||||||
.then(function(assets) {
|
.then(function(assets) {
|
||||||
// Assets are undefined
|
// Assets are undefined
|
||||||
if(!assets) return false;
|
if(!assets) return false;
|
||||||
|
|||||||
+19
-26
@@ -1,14 +1,14 @@
|
|||||||
var _ = require("lodash");
|
var _ = require("lodash");
|
||||||
var Q = require("q");
|
var Q = require("q");
|
||||||
var npmi = require('npmi');
|
var npmi = require("npmi");
|
||||||
var npm = require('npm');
|
var npm = require("npm");
|
||||||
var semver = require('semver');
|
var semver = require("semver");
|
||||||
|
|
||||||
var Plugin = require("./plugin");
|
var Plugin = require("./plugin");
|
||||||
var pkg = require("../package.json");
|
var pkg = require("../package.json");
|
||||||
|
|
||||||
var initNPM = _.memoize(function() {
|
var initNPM = _.memoize(function() {
|
||||||
return Q.nfcall(npm.load, { silent: true, loglevel: 'silent' });
|
return Q.nfcall(npm.load, { silent: true, loglevel: "silent" });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ PluginsList.prototype.count = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Add and load a plugin
|
// Add and load a plugin
|
||||||
PluginsList.prototype.load = function(plugin, options) {
|
PluginsList.prototype.load = function(plugin) {
|
||||||
var that = this;
|
var that = this;
|
||||||
|
|
||||||
if (_.isArray(plugin)) {
|
if (_.isArray(plugin)) {
|
||||||
@@ -79,14 +79,10 @@ PluginsList.prototype.load = function(plugin, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Extract filters
|
// Extract filters
|
||||||
_.each(plugin.getFilters(), function(filterFunc, filterName) {
|
that.book.template.addFilters(plugin.getFilters());
|
||||||
that.book.template.addFilter(filterName, filterFunc);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Extract blocks
|
// Extract blocks
|
||||||
_.each(plugin.getBlocks(), function(block, blockName) {
|
that.book.template.addBlocks(plugin.getBlocks());
|
||||||
that.book.template.addBlock(blockName, block);
|
|
||||||
});
|
|
||||||
|
|
||||||
return _.reduce(_.keys(that.namespaces), function(prev, namespaceName) {
|
return _.reduce(_.keys(that.namespaces), function(prev, namespaceName) {
|
||||||
return prev.then(function() {
|
return prev.then(function() {
|
||||||
@@ -107,7 +103,7 @@ PluginsList.prototype.load = function(plugin, options) {
|
|||||||
namespace.html[tag] = namespace.html[tag] || [];
|
namespace.html[tag] = namespace.html[tag] || [];
|
||||||
namespace.html[tag].push(value);
|
namespace.html[tag].push(value);
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
}, Q());
|
}, Q());
|
||||||
};
|
};
|
||||||
@@ -150,11 +146,10 @@ PluginsList.prototype.resources = function(namespace) {
|
|||||||
// Install plugins from a book
|
// Install plugins from a book
|
||||||
PluginsList.prototype.install = function() {
|
PluginsList.prototype.install = function() {
|
||||||
var that = this;
|
var that = this;
|
||||||
var defaultsPlugins = _.pluck(that.book.options.defaultsPlugins)
|
|
||||||
|
|
||||||
// Remove defaults (no need to install)
|
// Remove defaults (no need to install)
|
||||||
var plugins = _.filter(that.book.options.plugins, function(plugin) {
|
var plugins = _.reject(that.book.options.plugins, {
|
||||||
return !_.contains(defaultsPlugins, plugin.name);
|
isDefault: true
|
||||||
});
|
});
|
||||||
|
|
||||||
// Install plugins one by one
|
// Install plugins one by one
|
||||||
@@ -180,8 +175,8 @@ PluginsList.prototype.install = function() {
|
|||||||
.map(function(v) {
|
.map(function(v) {
|
||||||
return {
|
return {
|
||||||
version: v[0],
|
version: v[0],
|
||||||
gitbook: (v[1].engines || {})["gitbook"]
|
gitbook: (v[1].engines || {}).gitbook
|
||||||
}
|
};
|
||||||
})
|
})
|
||||||
.filter(function(v) {
|
.filter(function(v) {
|
||||||
return v.gitbook && semver.satisfies(pkg.version, v.gitbook);
|
return v.gitbook && semver.satisfies(pkg.version, v.gitbook);
|
||||||
@@ -203,13 +198,13 @@ PluginsList.prototype.install = function() {
|
|||||||
|
|
||||||
that.book.log.info.ln("install plugin", plugin.name, "from npm ("+fullname+") with version", version);
|
that.book.log.info.ln("install plugin", plugin.name, "from npm ("+fullname+") with version", version);
|
||||||
return Q.nfcall(npmi, {
|
return Q.nfcall(npmi, {
|
||||||
'name': fullname,
|
"name": fullname,
|
||||||
'version': version,
|
"version": version,
|
||||||
'path': that.book.root,
|
"path": that.book.root,
|
||||||
'npmLoad': {
|
"npmLoad": {
|
||||||
'loglevel': 'silent',
|
"loglevel": "silent",
|
||||||
'loaded': true,
|
"loaded": true,
|
||||||
'prefix': that.book.root
|
"prefix": that.book.root
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
@@ -220,6 +215,4 @@ PluginsList.prototype.install = function() {
|
|||||||
}, Q());
|
}, Q());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = PluginsList;
|
module.exports = PluginsList;
|
||||||
|
|||||||
+129
-89
@@ -1,48 +1,18 @@
|
|||||||
var _ = require("lodash");
|
var _ = require("lodash");
|
||||||
var Q = require("q");
|
var Q = require("q");
|
||||||
var path = require("path");
|
|
||||||
var nunjucks = require("nunjucks");
|
var nunjucks = require("nunjucks");
|
||||||
|
var escapeStringRegexp = require("escape-string-regexp");
|
||||||
|
|
||||||
var git = require("./utils/git");
|
|
||||||
var stringUtils = require("./utils/string");
|
|
||||||
var fs = require("./utils/fs");
|
|
||||||
var batch = require("./utils/batch");
|
var batch = require("./utils/batch");
|
||||||
var pkg = require("../package.json");
|
var pkg = require("../package.json");
|
||||||
|
var defaultBlocks = require("./blocks");
|
||||||
|
var BookLoader = require("./conrefs_loader");
|
||||||
|
|
||||||
|
// Normalize result from a block
|
||||||
// The loader should handle relative and git url
|
function normBlockResult(blk) {
|
||||||
var BookLoader = nunjucks.Loader.extend({
|
if (_.isString(blk)) blk = { body: blk };
|
||||||
async: true,
|
return blk;
|
||||||
|
}
|
||||||
init: function(book) {
|
|
||||||
this.book = book;
|
|
||||||
},
|
|
||||||
|
|
||||||
getSource: function(fileurl, callback) {
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
git.resolveFile(fileurl)
|
|
||||||
.then(function(filepath) {
|
|
||||||
// Is local file
|
|
||||||
if (!filepath) filepath = path.resolve(that.book.root, fileurl);
|
|
||||||
else that.book.log.debug.ln("resolve from git", fileurl, "to", filepath)
|
|
||||||
|
|
||||||
// Read file from absolute path
|
|
||||||
return fs.readFile(filepath)
|
|
||||||
.then(function(source) {
|
|
||||||
return {
|
|
||||||
src: source.toString(),
|
|
||||||
path: filepath
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.nodeify(callback);
|
|
||||||
},
|
|
||||||
|
|
||||||
resolve: function(from, to) {
|
|
||||||
return path.resolve(path.dirname(from), to);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
var TemplateEngine = function(book) {
|
var TemplateEngine = function(book) {
|
||||||
@@ -58,12 +28,12 @@ var TemplateEngine = function(book) {
|
|||||||
|
|
||||||
// Tags
|
// Tags
|
||||||
tags: {
|
tags: {
|
||||||
blockStart: '{%',
|
blockStart: "{%",
|
||||||
blockEnd: '%}',
|
blockEnd: "%}",
|
||||||
variableStart: '{{',
|
variableStart: "{{",
|
||||||
variableEnd: '}}',
|
variableEnd: "}}",
|
||||||
commentStart: '{###',
|
commentStart: "{###",
|
||||||
commentEnd: '###}'
|
commentEnd: "###}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -71,49 +41,48 @@ var TemplateEngine = function(book) {
|
|||||||
// List of tags shortcuts
|
// List of tags shortcuts
|
||||||
this.shortcuts = [];
|
this.shortcuts = [];
|
||||||
|
|
||||||
// Map of blocks
|
// Map of blocks bodies (that requires post-processing)
|
||||||
|
this.blockBodies = {};
|
||||||
|
|
||||||
|
// Map of added blocks
|
||||||
this.blocks = {};
|
this.blocks = {};
|
||||||
|
|
||||||
// Bind methods
|
// Bind methods
|
||||||
_.bindAll(this);
|
_.bindAll(this);
|
||||||
|
|
||||||
// Default block "html" that return html not parsed
|
// Add default blocks
|
||||||
this.addBlock("html", {
|
this.addBlocks(defaultBlocks);
|
||||||
process: _.identity
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Process a block in a context
|
// Process the result of block in a context
|
||||||
TemplateEngine.prototype.processBlock = function(blk) {
|
TemplateEngine.prototype.processBlock = function(blk) {
|
||||||
if (_.isString(blk)) blk = { body: blk };
|
|
||||||
|
|
||||||
blk = _.defaults(blk, {
|
blk = _.defaults(blk, {
|
||||||
parse: false,
|
parse: false,
|
||||||
post: undefined
|
post: undefined
|
||||||
});
|
});
|
||||||
blk.id = _.uniqueId("blk");
|
blk.id = _.uniqueId("blk");
|
||||||
|
|
||||||
var toAdd = (!blk.parse) || (blk.post != undefined);
|
var toAdd = (!blk.parse) || (blk.post !== undefined);
|
||||||
|
|
||||||
// Add to global map
|
// Add to global map
|
||||||
if (toAdd) this.blocks[blk.id] = blk;
|
if (toAdd) this.blockBodies[blk.id] = blk;
|
||||||
|
|
||||||
//Parsable block, just return it
|
//Parsable block, just return it
|
||||||
if (blk.parse) {
|
if (blk.parse) {
|
||||||
return blk.body;
|
return blk.body;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return it as a macro
|
// Return it as a position marker
|
||||||
return "%+%"+blk.id+"%+%";
|
return "@%@"+blk.id+"@%@";
|
||||||
};
|
};
|
||||||
|
|
||||||
// Replace blocks by body after processing
|
// Replace position markers of blocks by body after processing
|
||||||
// This is done to avoid that markdown processer parse the block content
|
// This is done to avoid that markdown/asciidoc processer parse the block content
|
||||||
TemplateEngine.prototype.replaceBlocks = function(content) {
|
TemplateEngine.prototype.replaceBlocks = function(content) {
|
||||||
var that = this;
|
var that = this;
|
||||||
|
|
||||||
return content.replace(/\%\+\%([\s\S]+?)\%\+\%/g, function(match, key) {
|
return content.replace(/\@\%\@([\s\S]+?)\@\%\@/g, function(match, key) {
|
||||||
var blk = that.blocks[key];
|
var blk = that.blockBodies[key];
|
||||||
if (!blk) return match;
|
if (!blk) return match;
|
||||||
|
|
||||||
var body = blk.body;
|
var body = blk.body;
|
||||||
@@ -141,11 +110,11 @@ TemplateEngine.prototype.bindContext = function(func) {
|
|||||||
TemplateEngine.prototype.addFilter = function(filterName, func) {
|
TemplateEngine.prototype.addFilter = function(filterName, func) {
|
||||||
try {
|
try {
|
||||||
this.env.getFilter(filterName);
|
this.env.getFilter(filterName);
|
||||||
this.log.warn.ln("conflict in filters, '"+filterName+"' is already set");
|
this.log.warn.ln("conflict in filters, \""+filterName+"\" is already set");
|
||||||
return false;
|
return false;
|
||||||
} catch(e) {}
|
} catch(e) {}
|
||||||
|
|
||||||
this.log.debug.ln("add filter '"+filterName+"'");
|
this.log.debug.ln("add filter \""+filterName+"\"");
|
||||||
this.env.addFilter(filterName, this.bindContext(function() {
|
this.env.addFilter(filterName, this.bindContext(function() {
|
||||||
var ctx = this;
|
var ctx = this;
|
||||||
var args = Array.prototype.slice.apply(arguments);
|
var args = Array.prototype.slice.apply(arguments);
|
||||||
@@ -160,9 +129,41 @@ TemplateEngine.prototype.addFilter = function(filterName, func) {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Add multiple filters
|
||||||
|
TemplateEngine.prototype.addFilters = function(filters) {
|
||||||
|
_.each(filters, function(filter, name) {
|
||||||
|
this.addFilter(name, filter);
|
||||||
|
}, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Return nunjucks extension name of a block
|
||||||
|
TemplateEngine.prototype.blockExtName = function(name) {
|
||||||
|
return "Block"+name+"Extension";
|
||||||
|
};
|
||||||
|
|
||||||
|
// Test if a block is defined
|
||||||
|
TemplateEngine.prototype.hasBlock = function(name) {
|
||||||
|
return this.env.hasExtension(this.blockExtName(name));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Remove a block
|
||||||
|
TemplateEngine.prototype.removeBlock = function(name) {
|
||||||
|
if (!this.hasBlock(name)) return;
|
||||||
|
|
||||||
|
// Remove nunjucks extension
|
||||||
|
this.env.removeExtension(this.blockExtName(name));
|
||||||
|
|
||||||
|
// Cleanup shortcuts
|
||||||
|
this.shortcuts = _.reject(this.shortcuts, {
|
||||||
|
block: name
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Add a block
|
// Add a block
|
||||||
TemplateEngine.prototype.addBlock = function(name, block) {
|
TemplateEngine.prototype.addBlock = function(name, block) {
|
||||||
var that = this;
|
var that = this, Ext, extName;
|
||||||
|
|
||||||
|
if (_.isFunction(block)) block = { process: block };
|
||||||
|
|
||||||
block = _.defaults(block || {}, {
|
block = _.defaults(block || {}, {
|
||||||
shortcuts: [],
|
shortcuts: [],
|
||||||
@@ -171,18 +172,22 @@ TemplateEngine.prototype.addBlock = function(name, block) {
|
|||||||
blocks: []
|
blocks: []
|
||||||
});
|
});
|
||||||
|
|
||||||
var extName = 'Block'+name+'Extension';
|
extName = this.blockExtName(name);
|
||||||
if (this.env.getExtension(extName)) {
|
|
||||||
this.log.warn.ln("conflict in blocks, '"+name+"' is already defined");
|
if (this.hasBlock(name) && !defaultBlocks[name]) {
|
||||||
return false;
|
this.log.warn.ln("conflict in blocks, \""+name+"\" is already defined");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.log.debug.ln("add block '"+name+"'");
|
// Cleanup previous block
|
||||||
|
this.removeBlock(name);
|
||||||
|
|
||||||
var Ext = function () {
|
this.log.debug.ln("add block \""+name+"\"");
|
||||||
|
this.blocks[name] = block;
|
||||||
|
|
||||||
|
Ext = function () {
|
||||||
this.tags = [name];
|
this.tags = [name];
|
||||||
|
|
||||||
this.parse = function(parser, nodes, lexer) {
|
this.parse = function(parser, nodes) {
|
||||||
var body = null;
|
var body = null;
|
||||||
var lastBlockName = null;
|
var lastBlockName = null;
|
||||||
var lastBlockArgs = null;
|
var lastBlockArgs = null;
|
||||||
@@ -223,7 +228,7 @@ TemplateEngine.prototype.addBlock = function(name, block) {
|
|||||||
var bodies = [body];
|
var bodies = [body];
|
||||||
_.each(block.blocks, function(blockName) {
|
_.each(block.blocks, function(blockName) {
|
||||||
subbodies[blockName] = subbodies[blockName] || [];
|
subbodies[blockName] = subbodies[blockName] || [];
|
||||||
if (subbodies[blockName].length == 0) {
|
if (subbodies[blockName].length === 0) {
|
||||||
subbodies[blockName].push({
|
subbodies[blockName].push({
|
||||||
args: new nodes.NodeList(),
|
args: new nodes.NodeList(),
|
||||||
body: new nodes.NodeList()
|
body: new nodes.NodeList()
|
||||||
@@ -233,7 +238,7 @@ TemplateEngine.prototype.addBlock = function(name, block) {
|
|||||||
bodies.push(subbodies[blockName][0].body);
|
bodies.push(subbodies[blockName][0].body);
|
||||||
});
|
});
|
||||||
|
|
||||||
return new nodes.CallExtensionAsync(this, 'run', args, bodies);
|
return new nodes.CallExtensionAsync(this, "run", args, bodies);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.run = function(context) {
|
this.run = function(context) {
|
||||||
@@ -250,7 +255,7 @@ TemplateEngine.prototype.addBlock = function(name, block) {
|
|||||||
|
|
||||||
// Extract main body and kwargs
|
// Extract main body and kwargs
|
||||||
var body = args.pop();
|
var body = args.pop();
|
||||||
var kwargs = args.pop() || {};
|
var kwargs = _.isObject(_.last(args))? args.pop() : {};
|
||||||
|
|
||||||
// Extract blocks body
|
// Extract blocks body
|
||||||
var _blocks = _.map(block.blocks, function(blockName, i){
|
var _blocks = _.map(block.blocks, function(blockName, i){
|
||||||
@@ -260,33 +265,31 @@ TemplateEngine.prototype.addBlock = function(name, block) {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
var func = that.bindContext(block.process);
|
|
||||||
|
|
||||||
Q()
|
Q()
|
||||||
.then(function() {
|
.then(function() {
|
||||||
return func.call(context, {
|
return that.applyBlock(name, {
|
||||||
body: body(),
|
body: body(),
|
||||||
args: args,
|
args: args,
|
||||||
kwargs: kwargs,
|
kwargs: kwargs,
|
||||||
blocks: _blocks
|
blocks: _blocks
|
||||||
});
|
}, context);
|
||||||
})
|
})
|
||||||
|
|
||||||
// process the block returned
|
// process the block returned
|
||||||
.then(that.processBlock)
|
.then(that.processBlock)
|
||||||
.nodeify(callback)
|
.nodeify(callback);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Add the Extension
|
// Add the Extension
|
||||||
this.env.addExtension(extName, new Ext());
|
this.env.addExtension(extName, new Ext());
|
||||||
|
|
||||||
// Add shortcuts
|
// Add shortcuts
|
||||||
if (!_.isArray(block.shortcuts)) block.shortcuts = [block.shortcuts];
|
if (!_.isArray(block.shortcuts)) block.shortcuts = [block.shortcuts];
|
||||||
_.each(block.shortcuts, function(shortcut) {
|
_.each(block.shortcuts, function(shortcut) {
|
||||||
this.log.debug.ln("add template shortcut from '"+shortcut.start+"' to block '"+name+"' for parsers ", shortcut.parsers);
|
this.log.debug.ln("add template shortcut from \""+shortcut.start+"\" to block \""+name+"\" for parsers ", shortcut.parsers);
|
||||||
this.shortcuts.push({
|
this.shortcuts.push({
|
||||||
|
block: name,
|
||||||
parsers: shortcut.parsers,
|
parsers: shortcut.parsers,
|
||||||
start: shortcut.start,
|
start: shortcut.start,
|
||||||
end: shortcut.end,
|
end: shortcut.end,
|
||||||
@@ -298,12 +301,46 @@ TemplateEngine.prototype.addBlock = function(name, block) {
|
|||||||
}, this);
|
}, this);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Add multiple blocks
|
||||||
|
TemplateEngine.prototype.addBlocks = function(blocks) {
|
||||||
|
_.each(blocks, function(block, name) {
|
||||||
|
this.addBlock(name, block);
|
||||||
|
}, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Apply a block to some content
|
||||||
|
// This method result depends on the type of block (async or sync)
|
||||||
|
TemplateEngine.prototype.applyBlock = function(name, blk, ctx) {
|
||||||
|
var func, block, r;
|
||||||
|
|
||||||
|
block = this.blocks[name];
|
||||||
|
if (!block) throw new Error("Block not found \""+name+"\"");
|
||||||
|
if (_.isString(blk)) {
|
||||||
|
blk = {
|
||||||
|
body: blk
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
blk = _.defaults(blk, {
|
||||||
|
args: [],
|
||||||
|
kwargs: {},
|
||||||
|
blocks: []
|
||||||
|
});
|
||||||
|
|
||||||
|
// Bind and call block processor
|
||||||
|
func = this.bindContext(block.process);
|
||||||
|
r = func.call(ctx || {}, blk);
|
||||||
|
|
||||||
|
if (Q.isPromise(r)) return r.then(normBlockResult);
|
||||||
|
else return normBlockResult(r);
|
||||||
|
};
|
||||||
|
|
||||||
// Apply a shortcut to a string
|
// Apply a shortcut to a string
|
||||||
TemplateEngine.prototype._applyShortcut = function(parser, content, shortcut) {
|
TemplateEngine.prototype._applyShortcut = function(parser, content, shortcut) {
|
||||||
if (!_.contains(shortcut.parsers, parser)) return content;
|
if (!_.contains(shortcut.parsers, parser)) return content;
|
||||||
var regex = new RegExp(
|
var regex = new RegExp(
|
||||||
stringUtils.escapeRegex(shortcut.start) + "([\\s\\S]*?[^\\$])" + stringUtils.escapeRegex(shortcut.end),
|
escapeStringRegexp(shortcut.start) + "([\\s\\S]*?[^\\$])" + escapeStringRegexp(shortcut.end),
|
||||||
'g'
|
"g"
|
||||||
);
|
);
|
||||||
return content.replace(regex, function(all, match) {
|
return content.replace(regex, function(all, match) {
|
||||||
return "{% "+shortcut.tag.start+" %}"+ match + "{% "+shortcut.tag.end+" %}";
|
return "{% "+shortcut.tag.start+" %}"+ match + "{% "+shortcut.tag.end+" %}";
|
||||||
@@ -312,10 +349,13 @@ TemplateEngine.prototype._applyShortcut = function(parser, content, shortcut) {
|
|||||||
|
|
||||||
// Render a string from the book
|
// Render a string from the book
|
||||||
TemplateEngine.prototype.renderString = function(content, context, options) {
|
TemplateEngine.prototype.renderString = function(content, context, options) {
|
||||||
var context = _.extend({}, context, {
|
context = _.extend({}, context, {
|
||||||
// Variables from book.json
|
// Variables from book.json
|
||||||
book: this.book.options.variables,
|
book: this.book.options.variables,
|
||||||
|
|
||||||
|
// Complete book.json
|
||||||
|
config: this.book.options,
|
||||||
|
|
||||||
// infos about gitbook
|
// infos about gitbook
|
||||||
gitbook: {
|
gitbook: {
|
||||||
version: pkg.version,
|
version: pkg.version,
|
||||||
@@ -341,8 +381,8 @@ TemplateEngine.prototype.renderString = function(content, context, options) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Render a file from the book
|
// Render a file from the book
|
||||||
TemplateEngine.prototype.renderFile = function(filename, options) {
|
TemplateEngine.prototype.renderFile = function(filename) {
|
||||||
var that = this, context;
|
var that = this;
|
||||||
|
|
||||||
return that.book.readFile(filename)
|
return that.book.readFile(filename)
|
||||||
.then(function(content) {
|
.then(function(content) {
|
||||||
@@ -354,11 +394,11 @@ TemplateEngine.prototype.renderFile = function(filename, options) {
|
|||||||
|
|
||||||
// Render a page from the book
|
// Render a page from the book
|
||||||
TemplateEngine.prototype.renderPage = function(page) {
|
TemplateEngine.prototype.renderPage = function(page) {
|
||||||
var that = this, context;
|
var that = this;
|
||||||
|
|
||||||
return that.book.statFile(page.path)
|
return that.book.statFile(page.path)
|
||||||
.then(function(stat) {
|
.then(function(stat) {
|
||||||
context = {
|
var context = {
|
||||||
// infos about the file
|
// infos about the file
|
||||||
file: {
|
file: {
|
||||||
path: page.path,
|
path: page.path,
|
||||||
@@ -380,7 +420,7 @@ TemplateEngine.prototype.postProcess = function(content) {
|
|||||||
return Q(content)
|
return Q(content)
|
||||||
.then(that.replaceBlocks)
|
.then(that.replaceBlocks)
|
||||||
.then(function(_content) {
|
.then(function(_content) {
|
||||||
return batch.execEach(that.blocks, {
|
return batch.execEach(that.blockBodies, {
|
||||||
max: 20,
|
max: 20,
|
||||||
fn: function(blk, blkId) {
|
fn: function(blk, blkId) {
|
||||||
return Q()
|
return Q()
|
||||||
@@ -389,7 +429,7 @@ TemplateEngine.prototype.postProcess = function(content) {
|
|||||||
return blk.post();
|
return blk.post();
|
||||||
})
|
})
|
||||||
.then(function() {
|
.then(function() {
|
||||||
delete that.blocks[blkId];
|
delete that.blockBodies[blkId];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
+4
-4
@@ -3,12 +3,12 @@ var _ = require("lodash");
|
|||||||
|
|
||||||
// Execute a method for all element
|
// Execute a method for all element
|
||||||
function execEach(items, options) {
|
function execEach(items, options) {
|
||||||
if (_.size(items) == 0) return Q();
|
if (_.size(items) === 0) return Q();
|
||||||
var concurrents = 0, d = Q.defer(), pending = [];
|
var concurrents = 0, d = Q.defer(), pending = [];
|
||||||
|
|
||||||
options = _.defaults(options || {}, {
|
options = _.defaults(options || {}, {
|
||||||
max: 100,
|
max: 100,
|
||||||
fn: function(item) {}
|
fn: function() {}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ function execEach(items, options) {
|
|||||||
// Next pending
|
// Next pending
|
||||||
var next = pending.shift();
|
var next = pending.shift();
|
||||||
|
|
||||||
if (concurrents == 0 && !next) {
|
if (concurrents === 0 && !next) {
|
||||||
d.resolve();
|
d.resolve();
|
||||||
} else if (next) {
|
} else if (next) {
|
||||||
startItem.apply(null, next);
|
startItem.apply(null, next);
|
||||||
@@ -38,7 +38,7 @@ function execEach(items, options) {
|
|||||||
.fail(function(err) {
|
.fail(function(err) {
|
||||||
pending = [];
|
pending = [];
|
||||||
d.reject(err);
|
d.reject(err);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_.each(items, startItem);
|
_.each(items, startItem);
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
var hljs = require('highlight.js');
|
|
||||||
|
|
||||||
var MAP = {
|
|
||||||
'py': 'python',
|
|
||||||
'js': 'javascript',
|
|
||||||
'json': 'javascript',
|
|
||||||
'rb': 'ruby',
|
|
||||||
'csharp': 'cs',
|
|
||||||
};
|
|
||||||
|
|
||||||
function normalize(lang) {
|
|
||||||
if(!lang) { return null; }
|
|
||||||
|
|
||||||
var lower = lang.toLowerCase();
|
|
||||||
return MAP[lower] || lower;
|
|
||||||
}
|
|
||||||
|
|
||||||
function highlight(lang, code) {
|
|
||||||
if(!lang) return code;
|
|
||||||
|
|
||||||
// Normalize lang
|
|
||||||
lang = normalize(lang);
|
|
||||||
|
|
||||||
try {
|
|
||||||
return hljs.highlight(lang, code).value;
|
|
||||||
} catch(e) { }
|
|
||||||
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exports
|
|
||||||
module.exports = {
|
|
||||||
highlight: highlight,
|
|
||||||
normalize: normalize,
|
|
||||||
MAP: MAP
|
|
||||||
};
|
|
||||||
+19
-15
@@ -9,10 +9,10 @@ var Ignore = require("fstream-ignore");
|
|||||||
var fsUtils = {
|
var fsUtils = {
|
||||||
tmp: {
|
tmp: {
|
||||||
file: function(opt) {
|
file: function(opt) {
|
||||||
return Q.nfcall(tmp.file.bind(tmp), opt).get(0)
|
return Q.nfcall(tmp.file.bind(tmp), opt).get(0);
|
||||||
},
|
},
|
||||||
dir: function() {
|
dir: function() {
|
||||||
return Q.nfcall(tmp.dir.bind(tmp)).get(0)
|
return Q.nfcall(tmp.dir.bind(tmp)).get(0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
list: listFiles,
|
list: listFiles,
|
||||||
@@ -34,14 +34,14 @@ var fsUtils = {
|
|||||||
readFileSync: fs.readFileSync.bind(fs),
|
readFileSync: fs.readFileSync.bind(fs),
|
||||||
clean: cleanFolder,
|
clean: cleanFolder,
|
||||||
getUniqueFilename: getUniqueFilename,
|
getUniqueFilename: getUniqueFilename,
|
||||||
}
|
};
|
||||||
|
|
||||||
// Write a file
|
// Write a file
|
||||||
function writeFile(filename, data, options) {
|
function writeFile(filename, data, options) {
|
||||||
var d = Q.defer();
|
var d = Q.defer();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
fs.writeFileSync(filename, data, options)
|
fs.writeFileSync(filename, data, options);
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
d.reject(err);
|
d.reject(err);
|
||||||
}
|
}
|
||||||
@@ -57,10 +57,14 @@ function writeStream(filename, st) {
|
|||||||
|
|
||||||
var wstream = fs.createWriteStream(filename);
|
var wstream = fs.createWriteStream(filename);
|
||||||
|
|
||||||
wstream.on('finish', function () {
|
wstream.on("finish", function () {
|
||||||
d.resolve();
|
d.resolve();
|
||||||
});
|
});
|
||||||
wstream.on('error', function (err) {
|
wstream.on("error", function (err) {
|
||||||
|
d.reject(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
st.on("error", function(err) {
|
||||||
d.reject(err);
|
d.reject(err);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -111,20 +115,20 @@ function listFiles(root, options) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Add extra rules to ignore common folders
|
// Add extra rules to ignore common folders
|
||||||
ig.addIgnoreRules(options.ignoreRules, '__custom_stuff');
|
ig.addIgnoreRules(options.ignoreRules, "__custom_stuff");
|
||||||
|
|
||||||
// Push each file to our list
|
// Push each file to our list
|
||||||
ig.on('child', function (c) {
|
ig.on("child", function (c) {
|
||||||
files.push(
|
files.push(
|
||||||
c.path.substr(c.root.path.length + 1) + (c.props.Directory === true ? '/' : '')
|
c.path.substr(c.root.path.length + 1) + (c.props.Directory === true ? "/" : "")
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
ig.on('end', function() {
|
ig.on("end", function() {
|
||||||
// Normalize paths on Windows
|
// Normalize paths on Windows
|
||||||
if(process.platform === 'win32') {
|
if(process.platform === "win32") {
|
||||||
return d.resolve(files.map(function(file) {
|
return d.resolve(files.map(function(file) {
|
||||||
return file.replace(/\\/g, '/');
|
return file.replace(/\\/g, "/");
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,7 +136,7 @@ function listFiles(root, options) {
|
|||||||
return d.resolve(files);
|
return d.resolve(files);
|
||||||
});
|
});
|
||||||
|
|
||||||
ig.on('error', d.reject);
|
ig.on("error", d.reject);
|
||||||
|
|
||||||
return d.promise;
|
return d.promise;
|
||||||
}
|
}
|
||||||
@@ -146,8 +150,8 @@ function cleanFolder(root) {
|
|||||||
ignoreFiles: [],
|
ignoreFiles: [],
|
||||||
ignoreRules: [
|
ignoreRules: [
|
||||||
// Skip Git and SVN stuff
|
// Skip Git and SVN stuff
|
||||||
'.git/',
|
".git/",
|
||||||
'.svn/'
|
".svn/"
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
.then(function(files) {
|
.then(function(files) {
|
||||||
|
|||||||
+21
-6
@@ -1,11 +1,10 @@
|
|||||||
var Q = require("q");
|
var Q = require("q");
|
||||||
var _ = require("lodash");
|
var _ = require("lodash");
|
||||||
var url = require("url");
|
|
||||||
var tmp = require("tmp");
|
|
||||||
var path = require("path");
|
var path = require("path");
|
||||||
var crc = require("crc");
|
var crc = require("crc");
|
||||||
var exec = Q.denodeify(require("child_process").exec);
|
var exec = Q.denodeify(require("child_process").exec);
|
||||||
var URI = require("URIjs");
|
var URI = require("URIjs");
|
||||||
|
var pathUtil = require("./path");
|
||||||
|
|
||||||
var fs = require("./fs");
|
var fs = require("./fs");
|
||||||
|
|
||||||
@@ -83,13 +82,12 @@ function cloneGitRepo(host, ref) {
|
|||||||
return exec("git clone "+host+" "+repoPath)
|
return exec("git clone "+host+" "+repoPath)
|
||||||
.then(function() {
|
.then(function() {
|
||||||
return exec("git checkout "+ref, { cwd: repoPath });
|
return exec("git checkout "+ref, { cwd: repoPath });
|
||||||
})
|
});
|
||||||
})
|
})
|
||||||
.thenResolve(repoPath);
|
.thenResolve(repoPath);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Get file from a git repo
|
// Get file from a git repo
|
||||||
function resolveFileFromGit(giturl) {
|
function resolveFileFromGit(giturl) {
|
||||||
if (_.isString(giturl)) giturl = parseGitUrl(giturl);
|
if (_.isString(giturl)) giturl = parseGitUrl(giturl);
|
||||||
@@ -102,11 +100,28 @@ function resolveFileFromGit(giturl) {
|
|||||||
// Resolve relative path
|
// Resolve relative path
|
||||||
return path.resolve(repo, giturl.filepath);
|
return path.resolve(repo, giturl.filepath);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
|
// Return root of git repo from a filepath
|
||||||
|
function resolveGitRoot(filepath) {
|
||||||
|
var relativeToGit, repoId;
|
||||||
|
|
||||||
|
// No git repo cloned, or file is not in a git repository
|
||||||
|
if (!GIT_TMP || !pathUtil.isInRoot(GIT_TMP, filepath)) return null;
|
||||||
|
|
||||||
|
// Extract first directory (is the repo id)
|
||||||
|
relativeToGit = path.relative(GIT_TMP, filepath);
|
||||||
|
repoId = _.first(relativeToGit.split(path.sep));
|
||||||
|
if (!repoId) return;
|
||||||
|
|
||||||
|
// Return an absolute file
|
||||||
|
return path.resolve(GIT_TMP, repoId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
checkUrl: checkGitUrl,
|
checkUrl: checkGitUrl,
|
||||||
parseUrl: parseGitUrl,
|
parseUrl: parseGitUrl,
|
||||||
resolveFile: resolveFileFromGit
|
resolveFile: resolveFileFromGit,
|
||||||
|
resolveRoot: resolveGitRoot
|
||||||
};
|
};
|
||||||
|
|||||||
+11
-11
@@ -4,7 +4,7 @@ var fs = require("fs");
|
|||||||
|
|
||||||
var i18n = require("i18n");
|
var i18n = require("i18n");
|
||||||
|
|
||||||
var I18N_PATH = path.resolve(__dirname, "../../theme/i18n/")
|
var I18N_PATH = path.resolve(__dirname, "../../theme/i18n/");
|
||||||
var DEFAULT_LANGUAGE = "en";
|
var DEFAULT_LANGUAGE = "en";
|
||||||
var LOCALES = _.map(fs.readdirSync(I18N_PATH), function(lang) {
|
var LOCALES = _.map(fs.readdirSync(I18N_PATH), function(lang) {
|
||||||
return path.basename(lang, ".json");
|
return path.basename(lang, ".json");
|
||||||
@@ -17,7 +17,7 @@ i18n.configure({
|
|||||||
updateFiles: false
|
updateFiles: false
|
||||||
});
|
});
|
||||||
|
|
||||||
var compareLocales = function(lang, locale) {
|
function compareLocales(lang, locale) {
|
||||||
var langMain = _.first(lang.split("-"));
|
var langMain = _.first(lang.split("-"));
|
||||||
var langSecond = _.last(lang.split("-"));
|
var langSecond = _.last(lang.split("-"));
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ var compareLocales = function(lang, locale) {
|
|||||||
if (localeMain == langMain) return 50;
|
if (localeMain == langMain) return 50;
|
||||||
if (localeSecond == langSecond) return 20;
|
if (localeSecond == langSecond) return 20;
|
||||||
return 0;
|
return 0;
|
||||||
};
|
}
|
||||||
|
|
||||||
var normalizeLanguage = _.memoize(function(lang) {
|
var normalizeLanguage = _.memoize(function(lang) {
|
||||||
var language = _.chain(LOCALES)
|
var language = _.chain(LOCALES)
|
||||||
@@ -37,7 +37,7 @@ var normalizeLanguage = _.memoize(function(lang) {
|
|||||||
return {
|
return {
|
||||||
locale: locale,
|
locale: locale,
|
||||||
score: compareLocales(lang, locale)
|
score: compareLocales(lang, locale)
|
||||||
}
|
};
|
||||||
})
|
})
|
||||||
.filter(function(lang) {
|
.filter(function(lang) {
|
||||||
return lang.score > 0;
|
return lang.score > 0;
|
||||||
@@ -49,25 +49,25 @@ var normalizeLanguage = _.memoize(function(lang) {
|
|||||||
return language || lang;
|
return language || lang;
|
||||||
});
|
});
|
||||||
|
|
||||||
var translate = function(locale, phrase) {
|
function translate(locale, phrase) {
|
||||||
var args = Array.prototype.slice.call(arguments, 2);
|
var args = Array.prototype.slice.call(arguments, 2);
|
||||||
|
|
||||||
return i18n.__.apply({}, [{
|
return i18n.__.apply({}, [{
|
||||||
locale: locale,
|
locale: locale,
|
||||||
phrase: phrase
|
phrase: phrase
|
||||||
}].concat(args));
|
}].concat(args));
|
||||||
};
|
}
|
||||||
|
|
||||||
var getCatalog = function(locale) {
|
function getCatalog(locale) {
|
||||||
locale = normalizeLanguage(locale);
|
locale = normalizeLanguage(locale);
|
||||||
return i18n.getCatalog(locale);
|
return i18n.getCatalog(locale);
|
||||||
};
|
}
|
||||||
|
|
||||||
var getLocales = function() {
|
function getLocales() {
|
||||||
return LOCALES;
|
return LOCALES;
|
||||||
};
|
}
|
||||||
|
|
||||||
var hasLocale = function(locale) {
|
function hasLocale(locale) {
|
||||||
return _.contains(LOCALES, locale);
|
return _.contains(LOCALES, locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-7
@@ -1,9 +1,7 @@
|
|||||||
var _ = require("lodash");
|
var _ = require("lodash");
|
||||||
var Q = require("q");
|
var Q = require("q");
|
||||||
var fs = require("./fs");
|
var fs = require("./fs");
|
||||||
var spawn = require('spawn-cmd').spawn;
|
var spawn = require("spawn-cmd").spawn;
|
||||||
|
|
||||||
var links = require("./links");
|
|
||||||
|
|
||||||
// Convert a svg file
|
// Convert a svg file
|
||||||
var convertSVG = function(source, dest, options) {
|
var convertSVG = function(source, dest, options) {
|
||||||
@@ -14,16 +12,16 @@ var convertSVG = function(source, dest, options) {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
//var command = shellescape(['svgexport', source, dest]);
|
//var command = shellescape(["svgexport", source, dest]);
|
||||||
var child = spawn('svgexport', [source, dest]);
|
var child = spawn("svgexport", [source, dest]);
|
||||||
|
|
||||||
child.on("error", function(error) {
|
child.on("error", function(error) {
|
||||||
if (error.code == "ENOENT") error = new Error("Need to install 'svgexport' using 'npm install svgexport -g'");
|
if (error.code == "ENOENT") error = new Error("Need to install \"svgexport\" using \"npm install svgexport -g\"");
|
||||||
return d.reject(error);
|
return d.reject(error);
|
||||||
});
|
});
|
||||||
|
|
||||||
child.on("close", function(code) {
|
child.on("close", function(code) {
|
||||||
if (code == 0 && fs.existsSync(dest)) {
|
if (code === 0 && fs.existsSync(dest)) {
|
||||||
d.resolve();
|
d.resolve();
|
||||||
} else {
|
} else {
|
||||||
d.reject(new Error("Error converting "+source+" into "+dest));
|
d.reject(new Error("Error converting "+source+" into "+dest));
|
||||||
|
|||||||
+4
-4
@@ -1,5 +1,5 @@
|
|||||||
var url = require('url');
|
var url = require("url");
|
||||||
var path = require('path');
|
var path = require("path");
|
||||||
|
|
||||||
// Is the link an external link
|
// Is the link an external link
|
||||||
var isExternal = function(href) {
|
var isExternal = function(href) {
|
||||||
@@ -33,7 +33,7 @@ var isAnchor = function(href) {
|
|||||||
|
|
||||||
// Normalize a path to be a link
|
// Normalize a path to be a link
|
||||||
var normalizeLink = function(s) {
|
var normalizeLink = function(s) {
|
||||||
return s.replace(/\\/g, '/');
|
return s.replace(/\\/g, "/");
|
||||||
};
|
};
|
||||||
|
|
||||||
// Relative to absolute path
|
// Relative to absolute path
|
||||||
@@ -43,7 +43,7 @@ var normalizeLink = function(s) {
|
|||||||
var toAbsolute = function(_href, dir, outdir) {
|
var toAbsolute = function(_href, dir, outdir) {
|
||||||
if (isExternal(_href)) return _href;
|
if (isExternal(_href)) return _href;
|
||||||
|
|
||||||
// Path '_href' inside the base folder
|
// Path "_href" inside the base folder
|
||||||
var hrefInRoot = path.normalize(path.join(dir, _href));
|
var hrefInRoot = path.normalize(path.join(dir, _href));
|
||||||
if (_href[0] == "/") hrefInRoot = path.normalize(_href.slice(1));
|
if (_href[0] == "/") hrefInRoot = path.normalize(_href.slice(1));
|
||||||
|
|
||||||
|
|||||||
+9
-9
@@ -1,6 +1,6 @@
|
|||||||
var _ = require('lodash');
|
var _ = require("lodash");
|
||||||
var util = require('util');
|
var util = require("util");
|
||||||
var color = require('bash-color');
|
var color = require("bash-color");
|
||||||
|
|
||||||
var LEVELS = {
|
var LEVELS = {
|
||||||
DEBUG: 0,
|
DEBUG: 0,
|
||||||
@@ -19,7 +19,7 @@ var COLORS = {
|
|||||||
|
|
||||||
module.exports = function(_write, logLevel) {
|
module.exports = function(_write, logLevel) {
|
||||||
var logger = {};
|
var logger = {};
|
||||||
var lastChar = '\n';
|
var lastChar = "\n";
|
||||||
if (_.isString(logLevel)) logLevel = LEVELS[logLevel.toUpperCase()];
|
if (_.isString(logLevel)) logLevel = LEVELS[logLevel.toUpperCase()];
|
||||||
|
|
||||||
// Write a simple message
|
// Write a simple message
|
||||||
@@ -47,14 +47,14 @@ module.exports = function(_write, logLevel) {
|
|||||||
var args = Array.prototype.slice.apply(arguments, [1]);
|
var args = Array.prototype.slice.apply(arguments, [1]);
|
||||||
var msg = logger.format.apply(logger, args);
|
var msg = logger.format.apply(logger, args);
|
||||||
|
|
||||||
if (lastChar == '\n') {
|
if (lastChar == "\n") {
|
||||||
msg = COLORS[levelKey](levelKey.toLowerCase()+":")+" "+msg;
|
msg = COLORS[levelKey](levelKey.toLowerCase()+":")+" "+msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
return logger.write(msg);
|
return logger.write(msg);
|
||||||
};
|
};
|
||||||
logger.logLn = function() {
|
logger.logLn = function() {
|
||||||
if (lastChar != '\n') logger.write("\n");
|
if (lastChar != "\n") logger.write("\n");
|
||||||
|
|
||||||
var args = Array.prototype.slice.apply(arguments);
|
var args = Array.prototype.slice.apply(arguments);
|
||||||
args.push("\n");
|
args.push("\n");
|
||||||
@@ -66,7 +66,7 @@ module.exports = function(_write, logLevel) {
|
|||||||
var args = Array.prototype.slice.apply(arguments, [1]);
|
var args = Array.prototype.slice.apply(arguments, [1]);
|
||||||
var msg = logger.format.apply(logger, args);
|
var msg = logger.format.apply(logger, args);
|
||||||
if (arguments.length > 1) {
|
if (arguments.length > 1) {
|
||||||
logger.logLn(level, color.green('>> ') + msg.trim().replace(/\n/g, color.green('\n>> ')));
|
logger.logLn(level, color.green(">> ") + msg.trim().replace(/\n/g, color.green("\n>> ")));
|
||||||
} else {
|
} else {
|
||||||
logger.log(level, color.green("OK"), "\n");
|
logger.log(level, color.green("OK"), "\n");
|
||||||
}
|
}
|
||||||
@@ -77,7 +77,7 @@ module.exports = function(_write, logLevel) {
|
|||||||
return logger.log(level, color.red("ERROR")+"\n");
|
return logger.log(level, color.red("ERROR")+"\n");
|
||||||
};
|
};
|
||||||
|
|
||||||
_.each(_.omit(LEVELS, 'DISABLED'), function(level, levelKey) {
|
_.each(_.omit(LEVELS, "DISABLED"), function(level, levelKey) {
|
||||||
levelKey = levelKey.toLowerCase();
|
levelKey = levelKey.toLowerCase();
|
||||||
|
|
||||||
logger[levelKey] = _.partial(logger.log, level);
|
logger[levelKey] = _.partial(logger.log, level);
|
||||||
@@ -93,7 +93,7 @@ module.exports = function(_write, logLevel) {
|
|||||||
logger[levelKey].fail();
|
logger[levelKey].fail();
|
||||||
throw err;
|
throw err;
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
return logger;
|
return logger;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
var _ = require('lodash');
|
var _ = require("lodash");
|
||||||
|
|
||||||
// Cleans up an article/chapter object
|
// Cleans up an article/chapter object
|
||||||
// remove 'articles' attributes
|
// remove "articles" attributes
|
||||||
function clean(obj) {
|
function clean(obj) {
|
||||||
return obj && _.omit(obj, ['articles']);
|
return obj && _.omit(obj, ["articles"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function flattenChapters(chapters) {
|
function flattenChapters(chapters) {
|
||||||
@@ -27,7 +27,7 @@ function navigation(summary, files) {
|
|||||||
files = _.isArray(files) ? files : (_.isString(files) ? [files] : null);
|
files = _.isArray(files) ? files : (_.isString(files) ? [files] : null);
|
||||||
|
|
||||||
// List of all navNodes
|
// List of all navNodes
|
||||||
// Flatten chapters, then add in default README node if needed etc ...
|
// Flatten chapters
|
||||||
var navNodes = flattenChapters(summary.chapters);
|
var navNodes = flattenChapters(summary.chapters);
|
||||||
|
|
||||||
// Mapping of prev/next for a give path
|
// Mapping of prev/next for a give path
|
||||||
@@ -39,8 +39,7 @@ function navigation(summary, files) {
|
|||||||
if(!current.exists) return null;
|
if(!current.exists) return null;
|
||||||
|
|
||||||
// Find prev
|
// Find prev
|
||||||
prev = _.chain(navNodes)
|
prev = _.chain(navNodes.slice(0, i))
|
||||||
.slice(0, i)
|
|
||||||
.reverse()
|
.reverse()
|
||||||
.find(function(node) {
|
.find(function(node) {
|
||||||
return node.exists && !node.external;
|
return node.exists && !node.external;
|
||||||
@@ -48,14 +47,12 @@ function navigation(summary, files) {
|
|||||||
.value();
|
.value();
|
||||||
|
|
||||||
// Find next
|
// Find next
|
||||||
next = _.chain(navNodes)
|
next = _.chain(navNodes.slice(i+1))
|
||||||
.slice(i+1)
|
|
||||||
.find(function(node) {
|
.find(function(node) {
|
||||||
return node.exists && !node.external;
|
return node.exists && !node.external;
|
||||||
})
|
})
|
||||||
.value();
|
.value();
|
||||||
|
|
||||||
|
|
||||||
return [current.path, {
|
return [current.path, {
|
||||||
index: i,
|
index: i,
|
||||||
title: current.title,
|
title: current.title,
|
||||||
|
|||||||
+71
-43
@@ -1,17 +1,18 @@
|
|||||||
var Q = require('q');
|
var Q = require("q");
|
||||||
var _ = require('lodash');
|
var _ = require("lodash");
|
||||||
var url = require('url');
|
var url = require("url");
|
||||||
var path = require('path');
|
var path = require("path");
|
||||||
var cheerio = require('cheerio');
|
var cheerio = require("cheerio");
|
||||||
var domSerializer = require('dom-serializer');
|
var domSerializer = require("dom-serializer");
|
||||||
var request = require('request');
|
var request = require("request");
|
||||||
var crc = require("crc");
|
var crc = require("crc");
|
||||||
|
|
||||||
var links = require('./links');
|
var links = require("./links");
|
||||||
var imgUtils = require('./images');
|
var imgUtils = require("./images");
|
||||||
var fs = require('./fs');
|
var fs = require("./fs");
|
||||||
var batch = require('./batch');
|
var batch = require("./batch");
|
||||||
var code = require('./code');
|
|
||||||
|
var parsableExtensions = require("gitbook-parsers").extensions;
|
||||||
|
|
||||||
// Render a cheerio dom as html
|
// Render a cheerio dom as html
|
||||||
var renderDom = function($, dom, options) {
|
var renderDom = function($, dom, options) {
|
||||||
@@ -39,7 +40,8 @@ function replaceText($, el, search, replace, text_only ) {
|
|||||||
if ( node ) {
|
if ( node ) {
|
||||||
|
|
||||||
// Loop over all childNodes.
|
// Loop over all childNodes.
|
||||||
do {
|
while (node) {
|
||||||
|
|
||||||
// Only process text nodes.
|
// Only process text nodes.
|
||||||
if ( node.nodeType === 3 ) {
|
if ( node.nodeType === 3 ) {
|
||||||
|
|
||||||
@@ -57,7 +59,7 @@ function replaceText($, el, search, replace, text_only ) {
|
|||||||
// robust way.
|
// robust way.
|
||||||
$(node).before( new_val );
|
$(node).before( new_val );
|
||||||
|
|
||||||
// Don't remove the node yet, or the loop will lose its place.
|
// Don"t remove the node yet, or the loop will lose its place.
|
||||||
remove.push( node );
|
remove.push( node );
|
||||||
} else {
|
} else {
|
||||||
// The new value contains no HTML, so it can be set in this
|
// The new value contains no HTML, so it can be set in this
|
||||||
@@ -67,17 +69,18 @@ function replaceText($, el, search, replace, text_only ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} while ( node = node.nextSibling );
|
node = node.nextSibling;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Time to remove those elements!
|
// Time to remove those elements!
|
||||||
remove.length && $(remove).remove();
|
if (remove.length) $(remove).remove();
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
function pregQuote( str ) {
|
function pregQuote( str ) {
|
||||||
return (str+'').replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, "\\$1");
|
return (str+"").replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, "\\$1");
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
// Adapt an html snippet to be relative to a base folder
|
// Adapt an html snippet to be relative to a base folder
|
||||||
@@ -106,15 +109,16 @@ function normalizeHtml(src, options) {
|
|||||||
// Generate filename
|
// Generate filename
|
||||||
dest = "/"+fs.getUniqueFilename(outputRoot, dest);
|
dest = "/"+fs.getUniqueFilename(outputRoot, dest);
|
||||||
|
|
||||||
svgContent[dest] = '<?xml version="1.0" encoding="UTF-8"?>'+content;
|
svgContent[dest] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"+content;
|
||||||
$(this).replaceWith($("<img>").attr("src", dest));
|
$(this).replaceWith($("<img>").attr("src", dest));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find images to normalize
|
// Find images to normalize
|
||||||
$("img").each(function() {
|
$("img").each(function() {
|
||||||
var origin = undefined;
|
var origin;
|
||||||
var src = $(this).attr("src");
|
var src = $(this).attr("src");
|
||||||
|
|
||||||
if (!src) return;
|
if (!src) return;
|
||||||
var isExternal = links.isExternal(src);
|
var isExternal = links.isExternal(src);
|
||||||
|
|
||||||
@@ -149,7 +153,7 @@ function normalizeHtml(src, options) {
|
|||||||
dest = links.join(path.dirname(srcAbs), path.basename(srcAbs, ext)+".png");
|
dest = links.join(path.dirname(srcAbs), path.basename(srcAbs, ext)+".png");
|
||||||
dest = dest[0] == "/"? dest.slice(1) : dest;
|
dest = dest[0] == "/"? dest.slice(1) : dest;
|
||||||
|
|
||||||
// Get a name that doesn't exists
|
// Get a name that doesn"t exists
|
||||||
dest = fs.getUniqueFilename(outputRoot, dest);
|
dest = fs.getUniqueFilename(outputRoot, dest);
|
||||||
|
|
||||||
options.book.log.debug.ln("detect invalid image (will be converted to png):", srcAbs);
|
options.book.log.debug.ln("detect invalid image (will be converted to png):", srcAbs);
|
||||||
@@ -193,14 +197,22 @@ function normalizeHtml(src, options) {
|
|||||||
// Keep it as it is
|
// Keep it as it is
|
||||||
} else if (links.isRelative(href)) {
|
} else if (links.isRelative(href)) {
|
||||||
var parts = url.parse(href);
|
var parts = url.parse(href);
|
||||||
var absolutePath = path.join(options.base, parts.pathname);
|
var absolutePath = links.join(options.base, parts.pathname);
|
||||||
var anchor = parts.hash || "";
|
var anchor = parts.hash || "";
|
||||||
|
|
||||||
|
|
||||||
// If is in navigation relative: transform as content
|
// If is in navigation relative: transform as content
|
||||||
if (options.navigation[absolutePath]) {
|
if (options.navigation[absolutePath]) {
|
||||||
absolutePath = options.book.contentLink(absolutePath);
|
absolutePath = options.book.contentLink(absolutePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If md/adoc/rst files is not in summary
|
||||||
|
// or for ebook, signal all files that are outside the summary
|
||||||
|
else if (_.contains(parsableExtensions, path.extname(absolutePath)) ||
|
||||||
|
_.contains(["epub", "pdf", "mobi"], options.book.options.generator)) {
|
||||||
|
options.book.log.warn.ln("page", options.input, "contains an hyperlink to resource outside spine \""+href+"\"");
|
||||||
|
}
|
||||||
|
|
||||||
// Transform as absolute
|
// Transform as absolute
|
||||||
href = links.toAbsolute("/"+absolutePath, options.base, options.output)+anchor;
|
href = links.toAbsolute("/"+absolutePath, options.base, options.output)+anchor;
|
||||||
} else {
|
} else {
|
||||||
@@ -214,36 +226,47 @@ function normalizeHtml(src, options) {
|
|||||||
|
|
||||||
// Highlight code blocks
|
// Highlight code blocks
|
||||||
$("code").each(function() {
|
$("code").each(function() {
|
||||||
// Extract language
|
// Normalize language
|
||||||
var lang = _.chain(
|
var lang = _.chain(
|
||||||
($(this).attr("class") || "").split(" ")
|
($(this).attr("class") || "").split(" ")
|
||||||
)
|
)
|
||||||
.map(function(cl) {
|
.map(function(cl) {
|
||||||
|
// Markdown
|
||||||
if (cl.search("lang-") === 0) return cl.slice("lang-".length);
|
if (cl.search("lang-") === 0) return cl.slice("lang-".length);
|
||||||
|
|
||||||
|
// Asciidoc
|
||||||
|
if (cl.search("language-") === 0) return cl.slice("language-".length);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
})
|
})
|
||||||
.compact()
|
.compact()
|
||||||
.first()
|
.first()
|
||||||
.value();
|
.value();
|
||||||
|
|
||||||
if (lang) {
|
var source = $(this).text();
|
||||||
var html = code.highlight(
|
var blk = options.book.template.applyBlock("code", {
|
||||||
lang,
|
body: source,
|
||||||
$(this).text()
|
kwargs: {
|
||||||
);
|
language: lang
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$(this).html(html);
|
if (blk.html === false) $(this).text(blk.body);
|
||||||
}
|
else $(this).html(blk.body);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Replace glossary terms
|
// Replace glossary terms
|
||||||
_.each(options.glossary, function(term) {
|
var glossary = _.sortBy(options.glossary, function(term) {
|
||||||
var r = new RegExp( "\\b(" + pregQuote(term.name.toLowerCase()) + ")\\b" , 'gi' );
|
return -term.name.length;
|
||||||
|
});
|
||||||
|
|
||||||
|
_.each(glossary, function(term) {
|
||||||
|
var r = new RegExp( "\\b(" + pregQuote(term.name.toLowerCase()) + ")\\b" , "gi" );
|
||||||
var includedInFiles = false;
|
var includedInFiles = false;
|
||||||
|
|
||||||
$("*").each(function() {
|
$("*").each(function() {
|
||||||
// Ignore codeblocks
|
// Ignore codeblocks
|
||||||
if (_.contains(["code", "pre"], this.name.toLowerCase())) return;
|
if (_.contains(["code", "pre", "a"], this.name.toLowerCase())) return;
|
||||||
|
|
||||||
replaceText($, this, r, function(match) {
|
replaceText($, this, r, function(match) {
|
||||||
// Add to files index in glossary
|
// Add to files index in glossary
|
||||||
@@ -252,7 +275,7 @@ function normalizeHtml(src, options) {
|
|||||||
term.files = term.files || [];
|
term.files = term.files || [];
|
||||||
term.files.push(options.navigation[options.input]);
|
term.files.push(options.navigation[options.input]);
|
||||||
}
|
}
|
||||||
return "<a href='"+links.toAbsolute("/GLOSSARY.html", options.base, options.output)+"#"+term.id+"' class='glossary-term' title='"+_.escape(term.description)+"'>"+match+"</a>";
|
return "<a href=\""+links.toAbsolute("/GLOSSARY.html", options.base, options.output) + "#" + term.id+"\" class=\"glossary-term\" title=\""+_.escape(term.description)+"\">"+match+"</a>";
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -261,7 +284,7 @@ function normalizeHtml(src, options) {
|
|||||||
html: renderDom($),
|
html: renderDom($),
|
||||||
images: toConvert
|
images: toConvert
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
// Convert svg images to png
|
// Convert svg images to png
|
||||||
function convertImages(images, options) {
|
function convertImages(images, options) {
|
||||||
@@ -282,7 +305,13 @@ function convertImages(images, options) {
|
|||||||
if (!image.origin && !_.contains(downloaded, image.origin)) return;
|
if (!image.origin && !_.contains(downloaded, image.origin)) return;
|
||||||
options.book.log.debug("download image", image.origin, "...");
|
options.book.log.debug("download image", image.origin, "...");
|
||||||
downloaded.push(image.origin);
|
downloaded.push(image.origin);
|
||||||
return options.book.log.debug.promise(fs.writeStream(imgin, request(image.origin)));
|
return options.book.log.debug.promise(fs.writeStream(imgin, request(image.origin)))
|
||||||
|
.fail(function(err) {
|
||||||
|
if (!_.isError(err)) err = new Error(err);
|
||||||
|
|
||||||
|
err.message = "Fail downloading "+image.origin+": "+err.message;
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
// Write svg if content
|
// Write svg if content
|
||||||
@@ -303,8 +332,7 @@ function convertImages(images, options) {
|
|||||||
.then(function() {
|
.then(function() {
|
||||||
options.book.log.debug.ok(images.length+" images converted with success");
|
options.book.log.debug.ok(images.length+" images converted with success");
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
// Adapt page content to be relative to a base folder
|
// Adapt page content to be relative to a base folder
|
||||||
function normalizePage(sections, options) {
|
function normalizePage(sections, options) {
|
||||||
@@ -337,7 +365,7 @@ function normalizePage(sections, options) {
|
|||||||
sections = _.map(sections, function(section) {
|
sections = _.map(sections, function(section) {
|
||||||
if (section.type != "normal") return section;
|
if (section.type != "normal") return section;
|
||||||
|
|
||||||
var out = normalizeHtml(section.content, options);;
|
var out = normalizeHtml(section.content, options);
|
||||||
|
|
||||||
toConvert = toConvert.concat(out.images);
|
toConvert = toConvert.concat(out.images);
|
||||||
section.content = out.html;
|
section.content = out.html;
|
||||||
@@ -346,11 +374,11 @@ function normalizePage(sections, options) {
|
|||||||
|
|
||||||
return Q()
|
return Q()
|
||||||
.then(function() {
|
.then(function() {
|
||||||
toConvert = _.uniq(toConvert, 'source');
|
toConvert = _.uniq(toConvert, "source");
|
||||||
return convertImages(toConvert, options);
|
return convertImages(toConvert, options);
|
||||||
})
|
})
|
||||||
.thenResolve(sections);
|
.thenResolve(sections);
|
||||||
};
|
}
|
||||||
|
|
||||||
// Extract text from sections
|
// Extract text from sections
|
||||||
function extractText(sections) {
|
function extractText(sections) {
|
||||||
@@ -364,7 +392,7 @@ function extractText(sections) {
|
|||||||
|
|
||||||
return prev;
|
return prev;
|
||||||
}, "");
|
}, "");
|
||||||
};
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
normalize: normalizePage,
|
normalize: normalizePage,
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
var _ = require("lodash");
|
||||||
|
var path = require("path");
|
||||||
|
|
||||||
|
// Return true if file path is inside a folder
|
||||||
|
function isInRoot(root, filename) {
|
||||||
|
filename = path.normalize(filename);
|
||||||
|
return (filename.substr(0, root.length) === root);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve paths in a specific folder
|
||||||
|
// Throw error if file is outside this folder
|
||||||
|
function resolveInRoot(root) {
|
||||||
|
var input, result, err;
|
||||||
|
|
||||||
|
input = _.chain(arguments)
|
||||||
|
.toArray()
|
||||||
|
.slice(1)
|
||||||
|
.reduce(function(current, p) {
|
||||||
|
// Handle path relative to book root ("/README.md")
|
||||||
|
if (p[0] == "/" || p[0] == "\\") return p.slice(1);
|
||||||
|
|
||||||
|
return current? path.join(current, p) : path.normalize(p);
|
||||||
|
}, "")
|
||||||
|
.value();
|
||||||
|
|
||||||
|
result = path.resolve(root, input);
|
||||||
|
|
||||||
|
if (!isInRoot(root, result)) {
|
||||||
|
err = new Error("EACCESS: \"" + result + "\" not in \"" + root + "\"");
|
||||||
|
err.code = "EACCESS";
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
isInRoot: isInRoot,
|
||||||
|
resolveInRoot: resolveInRoot
|
||||||
|
};
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
var _ = require("lodash");
|
var _ = require("lodash");
|
||||||
|
|
||||||
// Returns from a navigation and a current file, a snapshot of current detailed state
|
// Returns from a navigation and a current file, a snapshot of current detailed state
|
||||||
var calculProgress = function(navigation, current) {
|
function calculProgress(navigation, current) {
|
||||||
var n = _.size(navigation);
|
var n = _.size(navigation);
|
||||||
var percent = 0, prevPercent = 0, currentChapter = null;
|
var percent = 0, prevPercent = 0, currentChapter = null;
|
||||||
var done = true;
|
var done = true;
|
||||||
|
|||||||
+15
-17
@@ -1,11 +1,9 @@
|
|||||||
var Q = require('q');
|
var Q = require("q");
|
||||||
var _ = require('lodash');
|
var events = require("events");
|
||||||
|
var http = require("http");
|
||||||
var events = require('events');
|
var send = require("send");
|
||||||
var http = require('http');
|
var util = require("util");
|
||||||
var send = require('send');
|
var url = require("url");
|
||||||
var util = require('util');
|
|
||||||
var url = require('url');
|
|
||||||
|
|
||||||
var Server = function() {
|
var Server = function() {
|
||||||
this.running = null;
|
this.running = null;
|
||||||
@@ -17,7 +15,7 @@ util.inherits(Server, events.EventEmitter);
|
|||||||
|
|
||||||
// Return true if the server is running
|
// Return true if the server is running
|
||||||
Server.prototype.isRunning = function() {
|
Server.prototype.isRunning = function() {
|
||||||
return this.running != null;
|
return !!this.running;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Stop the server
|
// Stop the server
|
||||||
@@ -57,25 +55,25 @@ Server.prototype.start = function(dir, port) {
|
|||||||
res.end(err.message);
|
res.end(err.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redirect to directory's index.html
|
// Redirect to directory"s index.html
|
||||||
function redirect() {
|
function redirect() {
|
||||||
res.statusCode = 301;
|
res.statusCode = 301;
|
||||||
res.setHeader('Location', req.url + '/');
|
res.setHeader("Location", req.url + "/");
|
||||||
res.end('Redirecting to ' + req.url + '/');
|
res.end("Redirecting to " + req.url + "/");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send file
|
// Send file
|
||||||
send(req, url.parse(req.url).pathname)
|
send(req, url.parse(req.url).pathname)
|
||||||
.root(dir)
|
.root(dir)
|
||||||
.on('error', error)
|
.on("error", error)
|
||||||
.on('directory', redirect)
|
.on("directory", redirect)
|
||||||
.pipe(res);
|
.pipe(res);
|
||||||
});
|
});
|
||||||
|
|
||||||
that.running.on('connection', function (socket) {
|
that.running.on("connection", function (socket) {
|
||||||
that.sockets.push(socket);
|
that.sockets.push(socket);
|
||||||
socket.setTimeout(4000);
|
socket.setTimeout(4000);
|
||||||
socket.on('close', function () {
|
socket.on("close", function () {
|
||||||
that.sockets.splice(that.sockets.indexOf(socket), 1);
|
that.sockets.splice(that.sockets.indexOf(socket), 1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -91,6 +89,6 @@ Server.prototype.start = function(dir, port) {
|
|||||||
|
|
||||||
return d.promise;
|
return d.promise;
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = Server;
|
module.exports = Server;
|
||||||
|
|||||||
+2
-7
@@ -1,7 +1,7 @@
|
|||||||
var _ = require("lodash");
|
var _ = require("lodash");
|
||||||
|
|
||||||
function escapeShellArg(arg) {
|
function escapeShellArg(arg) {
|
||||||
var ret = '';
|
var ret = "";
|
||||||
|
|
||||||
ret = arg.replace(/"/g, '\\"');
|
ret = arg.replace(/"/g, '\\"');
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ function escapeShellArg(arg) {
|
|||||||
function optionsToShellArgs(options) {
|
function optionsToShellArgs(options) {
|
||||||
return _.chain(options)
|
return _.chain(options)
|
||||||
.map(function(value, key) {
|
.map(function(value, key) {
|
||||||
if (value == null || value === false) return null;
|
if (value === null || value === undefined || value === false) return null;
|
||||||
if (value === true) return key;
|
if (value === true) return key;
|
||||||
return key+"="+escapeShellArg(value);
|
return key+"="+escapeShellArg(value);
|
||||||
})
|
})
|
||||||
@@ -20,12 +20,7 @@ function optionsToShellArgs(options) {
|
|||||||
.join(" ");
|
.join(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
function escapeRegex(str) {
|
|
||||||
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
escapeRegex: escapeRegex,
|
|
||||||
escapeShellArg: escapeShellArg,
|
escapeShellArg: escapeShellArg,
|
||||||
optionsToShellArgs: optionsToShellArgs,
|
optionsToShellArgs: optionsToShellArgs,
|
||||||
toLowerCase: String.prototype.toLowerCase.call.bind(String.prototype.toLowerCase)
|
toLowerCase: String.prototype.toLowerCase.call.bind(String.prototype.toLowerCase)
|
||||||
|
|||||||
+13
-11
@@ -1,9 +1,9 @@
|
|||||||
var Q = require('q');
|
var Q = require("q");
|
||||||
var _ = require('lodash');
|
var _ = require("lodash");
|
||||||
var path = require('path');
|
var path = require("path");
|
||||||
var Gaze = require('gaze').Gaze;
|
var chokidar = require("chokidar");
|
||||||
|
|
||||||
var parsers = require('gitbook-parsers')
|
var parsers = require("gitbook-parsers");
|
||||||
|
|
||||||
function watch(dir) {
|
function watch(dir) {
|
||||||
var d = Q.defer();
|
var d = Q.defer();
|
||||||
@@ -17,17 +17,19 @@ function watch(dir) {
|
|||||||
toWatch.push("**/*"+ext);
|
toWatch.push("**/*"+ext);
|
||||||
});
|
});
|
||||||
|
|
||||||
var gaze = new Gaze(toWatch, {
|
var watcher = chokidar.watch(toWatch, {
|
||||||
cwd: dir
|
cwd: dir,
|
||||||
|
ignored: "_book/**",
|
||||||
|
ignoreInitial: true
|
||||||
});
|
});
|
||||||
|
|
||||||
gaze.once("all", function(e, filepath) {
|
watcher.once("all", function(e, filepath) {
|
||||||
gaze.close();
|
watcher.close();
|
||||||
|
|
||||||
d.resolve(filepath);
|
d.resolve(filepath);
|
||||||
});
|
});
|
||||||
gaze.once("error", function(err) {
|
watcher.once("error", function(err) {
|
||||||
gaze.close();
|
watcher.close();
|
||||||
|
|
||||||
d.reject(err);
|
d.reject(err);
|
||||||
});
|
});
|
||||||
|
|||||||
+14
-13
@@ -1,27 +1,28 @@
|
|||||||
{
|
{
|
||||||
"name": "gitbook",
|
"name": "gitbook",
|
||||||
"version": "2.0.1",
|
"version": "2.4.2",
|
||||||
"homepage": "https://www.gitbook.com",
|
"homepage": "https://www.gitbook.com",
|
||||||
"description": "Library and cmd utility to generate GitBooks",
|
"description": "Library and cmd utility to generate GitBooks",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"q": "1.0.1",
|
"q": "1.0.1",
|
||||||
"lunr": "0.5.7",
|
"lunr": "0.5.12",
|
||||||
"lodash": "3.5.0",
|
"lodash": "3.10.1",
|
||||||
"graceful-fs": "3.0.5",
|
"graceful-fs": "3.0.5",
|
||||||
"resolve": "0.6.3",
|
"resolve": "0.6.3",
|
||||||
"fs-extra": "0.16.5",
|
"fs-extra": "0.16.5",
|
||||||
"fstream-ignore": "1.0.2",
|
"fstream-ignore": "1.0.2",
|
||||||
"gitbook-parsers": "0.7.4",
|
"gitbook-parsers": "0.8.2",
|
||||||
"nunjucks": "git+https://github.com/mozilla/nunjucks.git#0f8b21b8df7e8e852b2e1889388653b7075f0d09",
|
"gitbook-plugin-highlight": "1.0.3",
|
||||||
"nunjucks-autoescape": "0.1.1",
|
"nunjucks": "mozilla/nunjucks#dc89bf91611a2101731c2c06afcf5c32160b4dc9",
|
||||||
"nunjucks-filter": "0.1.0",
|
"nunjucks-autoescape": "1.0.0",
|
||||||
|
"nunjucks-filter": "1.0.0",
|
||||||
"i18n": "0.5.0",
|
"i18n": "0.5.0",
|
||||||
"semver": "2.2.1",
|
"semver": "5.0.1",
|
||||||
"npmi": "0.1.1",
|
"npmi": "0.1.1",
|
||||||
"cheerio": "0.19.0",
|
"cheerio": "0.19.0",
|
||||||
"gitbook-plugin-livereload": "0.0.1",
|
"gitbook-plugin-livereload": "0.0.1",
|
||||||
"gaze": "~0.5.1",
|
"chokidar": "~1.0.5",
|
||||||
"send": "0.2.0",
|
"send": "0.2.0",
|
||||||
"tiny-lr": "0.1.5",
|
"tiny-lr": "0.1.5",
|
||||||
"tmp": "0.0.24",
|
"tmp": "0.0.24",
|
||||||
@@ -32,11 +33,11 @@
|
|||||||
"npm": "2.4.1",
|
"npm": "2.4.1",
|
||||||
"dom-serializer": "0.1.0",
|
"dom-serializer": "0.1.0",
|
||||||
"spawn-cmd": "0.0.2",
|
"spawn-cmd": "0.0.2",
|
||||||
"highlight.js": "8.4.0"
|
"escape-string-regexp": "1.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"mocha": "2.2.1",
|
"mocha": "2.3.2",
|
||||||
"should": "5.2.0",
|
"should": "7.1.0",
|
||||||
"grunt": "~0.4.2",
|
"grunt": "~0.4.2",
|
||||||
"grunt-cli": "0.1.11",
|
"grunt-cli": "0.1.11",
|
||||||
"grunt-contrib-copy": "0.5.0",
|
"grunt-contrib-copy": "0.5.0",
|
||||||
@@ -60,7 +61,7 @@
|
|||||||
"gitbook"
|
"gitbook"
|
||||||
],
|
],
|
||||||
"author": "FriendCode Inc. <contact@gitbook.com>",
|
"author": "FriendCode Inc. <contact@gitbook.com>",
|
||||||
"license": "Apache 2",
|
"license": "Apache-2.0",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/GitbookIO/gitbook/issues"
|
"url": "https://github.com/GitbookIO/gitbook/issues"
|
||||||
},
|
},
|
||||||
|
|||||||
+30
-17
@@ -1,41 +1,54 @@
|
|||||||
var _ = require('lodash');
|
var _ = require("lodash");
|
||||||
var fs = require('fs');
|
var fs = require("fs");
|
||||||
var path = require('path');
|
var path = require("path");
|
||||||
var should = require('should');
|
var should = require("should");
|
||||||
var cheerio = require('cheerio');
|
var cheerio = require("cheerio");
|
||||||
|
|
||||||
should.Assertion.add('file', function(file, description) {
|
should.Assertion.add("file", function(file, description) {
|
||||||
this.params = { actual: this.obj.toString(), operator: 'have file ' + file, message: description };
|
this.params = { actual: this.obj.toString(), operator: "have file " + file, message: description };
|
||||||
|
|
||||||
this.obj.should.have.property('options').which.is.an.Object;
|
this.obj.should.have.property("options").which.is.an.Object();
|
||||||
this.obj.options.should.have.property('output').which.is.a.String;
|
this.obj.options.should.have.property("output").which.is.a.String();
|
||||||
this.assert(fs.existsSync(path.resolve(this.obj.options.output, file)));
|
this.assert(fs.existsSync(path.resolve(this.obj.options.output, file)));
|
||||||
});
|
});
|
||||||
|
|
||||||
should.Assertion.add('jsonfile', function(file, description) {
|
should.Assertion.add("jsonfile", function(file, description) {
|
||||||
this.params = { actual: this.obj.toString(), operator: 'have valid jsonfile ' + file, message: description };
|
this.params = { actual: this.obj.toString(), operator: "have valid jsonfile " + file, message: description };
|
||||||
|
|
||||||
this.obj.should.have.property('options').which.is.an.Object;
|
this.obj.should.have.property("options").which.is.an.Object();
|
||||||
this.obj.options.should.have.property('output').which.is.a.String;
|
this.obj.options.should.have.property("output").which.is.a.String();
|
||||||
this.assert(JSON.parse(fs.readFileSync(path.resolve(this.obj.options.output, file), { encoding: "utf-8" })));
|
this.assert(JSON.parse(fs.readFileSync(path.resolve(this.obj.options.output, file), { encoding: "utf-8" })));
|
||||||
});
|
});
|
||||||
|
|
||||||
should.Assertion.add('html', function(rules, description) {
|
should.Assertion.add("html", function(rules, description) {
|
||||||
this.params = { actual: "HTML string", operator: 'valid html', message: description };
|
this.params = { actual: "HTML string", operator: "valid html", message: description };
|
||||||
var $ = cheerio.load(this.obj);
|
var $ = cheerio.load(this.obj);
|
||||||
|
|
||||||
_.each(rules, function(validations, query) {
|
_.each(rules, function(validations, query) {
|
||||||
validations = _.defaults(validations || {}, {
|
validations = _.defaults(validations || {}, {
|
||||||
|
// Select a specific element in the list of matched elements
|
||||||
|
index: null,
|
||||||
|
|
||||||
|
// Check that there is the correct count of elements
|
||||||
count: 1,
|
count: 1,
|
||||||
|
|
||||||
|
// Check attribute values
|
||||||
attributes: {},
|
attributes: {},
|
||||||
|
|
||||||
|
// Trim inner text
|
||||||
trim: false,
|
trim: false,
|
||||||
|
|
||||||
|
// Check inner text
|
||||||
text: undefined
|
text: undefined
|
||||||
});
|
});
|
||||||
|
|
||||||
var $el = $(query);
|
var $el = $(query);
|
||||||
|
|
||||||
|
// Select correct element
|
||||||
|
if (_.isNumber(validations.index)) $el = $($el.get(validations.index));
|
||||||
|
|
||||||
// Test number of elements
|
// Test number of elements
|
||||||
$el.should.have.lengthOf(validations.count);
|
$el.length.should.be.equal(validations.count);
|
||||||
|
|
||||||
// Test text
|
// Test text
|
||||||
if (validations.text !== undefined) {
|
if (validations.text !== undefined) {
|
||||||
@@ -47,7 +60,7 @@ should.Assertion.add('html', function(rules, description) {
|
|||||||
// Test attributes
|
// Test attributes
|
||||||
_.each(validations.attributes, function(value, name) {
|
_.each(validations.attributes, function(value, name) {
|
||||||
var attr = $el.attr(name);
|
var attr = $el.attr(name);
|
||||||
should(attr).be.ok;
|
should(attr).be.ok();
|
||||||
attr.should.be.equal(value);
|
attr.should.be.equal(value);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,8 +3,10 @@
|
|||||||
### Relative
|
### Relative
|
||||||
|
|
||||||
<p id="t1">{% include "./hello.md" %}</p>
|
<p id="t1">{% include "./hello.md" %}</p>
|
||||||
|
<p id="t2">{% include "/hello.md" %}</p>
|
||||||
|
|
||||||
### Git
|
### Git
|
||||||
|
|
||||||
<p id="t2">{% include "git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test.md" %}</p>
|
<p id="t3">{% include "git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test.md" %}</p>
|
||||||
<p id="t3">{% include "git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test2.md" %}</p>
|
<p id="t4">{% include "git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test2.md" %}</p>
|
||||||
|
<p id="t5">{% include "git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test3.md" %}</p>
|
||||||
|
|||||||
@@ -7,3 +7,7 @@ Just a simple and easy to understand test.
|
|||||||
## hakunamatata
|
## hakunamatata
|
||||||
|
|
||||||
This word is not present in the content.
|
This word is not present in the content.
|
||||||
|
|
||||||
|
## test long
|
||||||
|
|
||||||
|
This is a test with a longer text that the first entry to test order.
|
||||||
|
|||||||
@@ -6,3 +6,5 @@ The word test should be replaced by a glossary link.
|
|||||||
But the word test should not be replaced in code blocks
|
But the word test should not be replaced in code blocks
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The two words test long should be replaced by the correct glossary links.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# Readme
|
||||||
|
|
||||||
|
Block without language
|
||||||
|
|
||||||
|
```
|
||||||
|
test 1
|
||||||
|
```
|
||||||
|
|
||||||
|
Block with a language
|
||||||
|
|
||||||
|
```lang
|
||||||
|
test 2
|
||||||
|
```
|
||||||
|
|
||||||
|
Inline code: `test 3`
|
||||||
|
Inline code with html: `<test>`
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
# Summary
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
*
|
||||||
|
!SUMMARY.md
|
||||||
|
!.gitignore
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Summary
|
||||||
|
|
||||||
|
* [Hello](hello.md)
|
||||||
|
* [Hello 2](hello2.md)
|
||||||
|
* Hello 3
|
||||||
|
* [Hello 4](hello3/hello4.md)
|
||||||
|
* Hello 5
|
||||||
|
* [Hello 6](hello3/hello5/hello6.md)
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
# Readme
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
# Summary
|
||||||
|
|
||||||
|
* [Folder1](folder1/README.md)
|
||||||
|
* [Folder2](folder2/README.md)
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Folder 1
|
||||||
|
|
||||||
|
[Link to folder2](../folder2/README.md)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
# Folder 2
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Readme
|
||||||
|
|
||||||
|
Default description for the book.
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
# Summary
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
body {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
var path = require("path");
|
||||||
|
var fs = require("fs");
|
||||||
|
|
||||||
|
var Plugin = require("../lib/plugin");
|
||||||
|
var PLUGINS_ROOT = path.resolve(__dirname, "plugins");
|
||||||
|
|
||||||
|
describe("Code Highlighting", function () {
|
||||||
|
var book, PAGE;
|
||||||
|
|
||||||
|
before(function() {
|
||||||
|
return books.generate("highlight", "website", {
|
||||||
|
prepare: function(_book) {
|
||||||
|
book = _book;
|
||||||
|
|
||||||
|
var plugin = new Plugin(book, "replace_highlight");
|
||||||
|
plugin.load("./replace_highlight", PLUGINS_ROOT);
|
||||||
|
|
||||||
|
book.plugins.load(plugin);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function() {
|
||||||
|
PAGE = fs.readFileSync(
|
||||||
|
path.join(book.options.output, "index.html"),
|
||||||
|
{ encoding: "utf-8" }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should correctly replace highlighting", function() {
|
||||||
|
PAGE.should.be.html({
|
||||||
|
"code": {
|
||||||
|
index: 0,
|
||||||
|
text: "code_test 1\n_code"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should correctly replace highlighting with language", function() {
|
||||||
|
PAGE.should.be.html({
|
||||||
|
"code": {
|
||||||
|
index: 1,
|
||||||
|
text: "lang_test 2\n_lang"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should correctly replace highlighting for inline code", function() {
|
||||||
|
PAGE.should.be.html({
|
||||||
|
"code": {
|
||||||
|
index: 2,
|
||||||
|
text: "code_test 3_code"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should correctly replace highlighting for inline code with html tags", function() {
|
||||||
|
PAGE.should.be.html({
|
||||||
|
"code": {
|
||||||
|
index: 3,
|
||||||
|
text: "code_<test>_code"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
+13
-8
@@ -1,32 +1,37 @@
|
|||||||
var fs = require('fs');
|
describe("Configuration", function () {
|
||||||
var path = require('path');
|
it("should extract default title from README", function() {
|
||||||
|
|
||||||
describe('Configuration', function () {
|
|
||||||
it('should extract default title from README', function() {
|
|
||||||
return books.parse("basic")
|
return books.parse("basic")
|
||||||
.then(function(book) {
|
.then(function(book) {
|
||||||
book.options.title.should.be.equal("Readme");
|
book.options.title.should.be.equal("Readme");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should extract default description from README', function() {
|
it("should extract default description from README", function() {
|
||||||
return books.parse("basic")
|
return books.parse("basic")
|
||||||
.then(function(book) {
|
.then(function(book) {
|
||||||
book.options.description.should.be.equal("Default description for the book.");
|
book.options.description.should.be.equal("Default description for the book.");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly load from json (book.json)', function() {
|
it("should correctly load from json (book.json)", function() {
|
||||||
return books.parse("config-json")
|
return books.parse("config-json")
|
||||||
.then(function(book) {
|
.then(function(book) {
|
||||||
book.options.title.should.be.equal("json-config");
|
book.options.title.should.be.equal("json-config");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly load from JavaScript (book.js)', function() {
|
it("should correctly load from JavaScript (book.js)", function() {
|
||||||
return books.parse("config-js")
|
return books.parse("config-js")
|
||||||
.then(function(book) {
|
.then(function(book) {
|
||||||
book.options.title.should.be.equal("js-config");
|
book.options.title.should.be.equal("js-config");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should provide configuration on book.config.get", function() {
|
||||||
|
return books.parse("basic")
|
||||||
|
.then(function(book) {
|
||||||
|
book.config.get("description").should.be.equal("Default description for the book.");
|
||||||
|
book.getConfig("description").should.be.equal("Default description for the book.");
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+32
-7
@@ -1,7 +1,7 @@
|
|||||||
var fs = require('fs');
|
var fs = require("fs");
|
||||||
var path = require('path');
|
var path = require("path");
|
||||||
|
|
||||||
describe('ConRefs', function () {
|
describe("ConRefs", function () {
|
||||||
var book, readme;
|
var book, readme;
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
@@ -16,7 +16,7 @@ describe('ConRefs', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle local references', function() {
|
it("should handle local references", function() {
|
||||||
readme.should.be.html({
|
readme.should.be.html({
|
||||||
".page-inner p#t1": {
|
".page-inner p#t1": {
|
||||||
count: 1,
|
count: 1,
|
||||||
@@ -26,14 +26,39 @@ describe('ConRefs', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle git references', function() {
|
it("should handle local references with absolute paths", function() {
|
||||||
readme.should.be.html({
|
readme.should.be.html({
|
||||||
".page-inner p#t2": {
|
".page-inner p#t2": {
|
||||||
|
count: 1,
|
||||||
|
text: "Hello World",
|
||||||
|
trim: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should correctly include file from git reference", function() {
|
||||||
|
readme.should.be.html({
|
||||||
|
".page-inner p#t3": {
|
||||||
count: 1,
|
count: 1,
|
||||||
text: "Hello from git",
|
text: "Hello from git",
|
||||||
trim: true
|
trim: true
|
||||||
},
|
}
|
||||||
".page-inner p#t3": {
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should correctly handle deep include in git reference", function() {
|
||||||
|
readme.should.be.html({
|
||||||
|
".page-inner p#t4": {
|
||||||
|
count: 1,
|
||||||
|
text: "First Hello. Hello from git",
|
||||||
|
trim: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should correctly handle absolute include in git reference", function() {
|
||||||
|
readme.should.be.html({
|
||||||
|
".page-inner p#t5": {
|
||||||
count: 1,
|
count: 1,
|
||||||
text: "First Hello. Hello from git",
|
text: "First Hello. Hello from git",
|
||||||
trim: true
|
trim: true
|
||||||
|
|||||||
+48
-6
@@ -1,8 +1,8 @@
|
|||||||
var fs = require('fs');
|
var fs = require("fs");
|
||||||
var path = require('path');
|
var path = require("path");
|
||||||
|
|
||||||
describe('eBook generator', function () {
|
describe("eBook generator", function () {
|
||||||
describe('Basic Book', function() {
|
describe("Basic Book", function() {
|
||||||
var book;
|
var book;
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
@@ -12,13 +12,55 @@ describe('eBook generator', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly output a SUMMARY.html', function() {
|
it("should correctly output a SUMMARY.html", function() {
|
||||||
book.should.have.file("SUMMARY.html");
|
book.should.have.file("SUMMARY.html");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly copy assets', function() {
|
it("should correctly copy assets", function() {
|
||||||
book.should.have.file("gitbook");
|
book.should.have.file("gitbook");
|
||||||
book.should.have.file("gitbook/style.css");
|
book.should.have.file("gitbook/style.css");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Custom styles", function() {
|
||||||
|
var book;
|
||||||
|
|
||||||
|
before(function() {
|
||||||
|
return books.generate("style-print", "ebook")
|
||||||
|
.then(function(_book) {
|
||||||
|
book = _book;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should remove default print.css", function() {
|
||||||
|
var PAGE = fs.readFileSync(
|
||||||
|
path.join(book.options.output, "index.html"),
|
||||||
|
{ encoding: "utf-8" }
|
||||||
|
);
|
||||||
|
|
||||||
|
// There are 2 styles (one from plugin-highlight and the new style)
|
||||||
|
PAGE.should.be.html({
|
||||||
|
"link": {
|
||||||
|
count: 2
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
PAGE.should.be.html({
|
||||||
|
"link[href=\"./styles/print.css\"]": {
|
||||||
|
count: 1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
PAGE.should.be.html({
|
||||||
|
"link[href=\"gitbook/plugins/gitbook-plugin-highlight/ebook.css\"]": {
|
||||||
|
count: 1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should correctly print.css", function() {
|
||||||
|
book.should.have.file("styles");
|
||||||
|
book.should.have.file("styles/print.css");
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+6
-6
@@ -1,8 +1,8 @@
|
|||||||
var should = require('should');
|
var should = require("should");
|
||||||
var git = require('../lib/utils/git');
|
var git = require("../lib/utils/git");
|
||||||
|
|
||||||
describe('GIT parser and getter', function () {
|
describe("GIT parser and getter", function () {
|
||||||
it('should correctly parse an https url', function() {
|
it("should correctly parse an https url", function() {
|
||||||
var parts = git.parseUrl("git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test.md");
|
var parts = git.parseUrl("git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test.md");
|
||||||
|
|
||||||
should.exist(parts);
|
should.exist(parts);
|
||||||
@@ -11,7 +11,7 @@ describe('GIT parser and getter', function () {
|
|||||||
parts.filepath.should.be.equal("test.md");
|
parts.filepath.should.be.equal("test.md");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly parse an https url with a reference', function() {
|
it("should correctly parse an https url with a reference", function() {
|
||||||
var parts = git.parseUrl("git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test.md#0.1.2");
|
var parts = git.parseUrl("git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test.md#0.1.2");
|
||||||
|
|
||||||
should.exist(parts);
|
should.exist(parts);
|
||||||
@@ -20,7 +20,7 @@ describe('GIT parser and getter', function () {
|
|||||||
parts.filepath.should.be.equal("test.md");
|
parts.filepath.should.be.equal("test.md");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly parse an ssh url', function() {
|
it("should correctly parse an ssh url", function() {
|
||||||
var parts = git.parseUrl("git+git@github.com:GitbookIO/gitbook.git/directory/README.md#e1594cde2c32e4ff48f6c4eff3d3d461743d74e1");
|
var parts = git.parseUrl("git+git@github.com:GitbookIO/gitbook.git/directory/README.md#e1594cde2c32e4ff48f6c4eff3d3d461743d74e1");
|
||||||
|
|
||||||
should.exist(parts);
|
should.exist(parts);
|
||||||
|
|||||||
+23
-14
@@ -1,8 +1,8 @@
|
|||||||
var fs = require('fs');
|
var fs = require("fs");
|
||||||
var path = require('path');
|
var path = require("path");
|
||||||
|
|
||||||
describe('Glossary', function () {
|
describe("Glossary", function () {
|
||||||
describe('Parsing', function() {
|
describe("Parsing", function() {
|
||||||
var book;
|
var book;
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
@@ -12,13 +12,13 @@ describe('Glossary', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly list items', function() {
|
it("should correctly list items", function() {
|
||||||
book.should.have.property("glossary");
|
book.should.have.property("glossary");
|
||||||
book.glossary.should.have.lengthOf(2);
|
book.glossary.should.have.lengthOf(3);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Generation', function() {
|
describe("Generation", function() {
|
||||||
var book;
|
var book;
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
@@ -28,11 +28,11 @@ describe('Glossary', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly generate a GLOSSARY.html', function() {
|
it("should correctly generate a GLOSSARY.html", function() {
|
||||||
book.should.have.file("GLOSSARY.html");
|
book.should.have.file("GLOSSARY.html");
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Page Integration', function() {
|
describe("Page Integration", function() {
|
||||||
var readme, page;
|
var readme, page;
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
@@ -46,9 +46,9 @@ describe('Glossary', function () {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly replaced terms by links', function() {
|
it("should correctly replaced terms by links", function() {
|
||||||
readme.should.be.html({
|
readme.should.be.html({
|
||||||
".page-inner a[href='GLOSSARY.html#test']": {
|
".page-inner a[href=\"GLOSSARY.html#test\"]": {
|
||||||
count: 1,
|
count: 1,
|
||||||
text: "test",
|
text: "test",
|
||||||
attributes: {
|
attributes: {
|
||||||
@@ -58,21 +58,30 @@ describe('Glossary', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly replaced terms by links (relative)', function() {
|
it("should correctly replaced terms by links (relative)", function() {
|
||||||
page.should.be.html({
|
page.should.be.html({
|
||||||
".page-inner a[href='../GLOSSARY.html#test']": {
|
".page-inner a[href=\"../GLOSSARY.html#test\"]": {
|
||||||
count: 1
|
count: 1
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not replace terms in codeblocks', function() {
|
it("should not replace terms in codeblocks", function() {
|
||||||
readme.should.be.html({
|
readme.should.be.html({
|
||||||
".page-inner code a": {
|
".page-inner code a": {
|
||||||
count: 0
|
count: 0
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should correctly select the longest term", function() {
|
||||||
|
readme.should.be.html({
|
||||||
|
".page-inner a[href=\"GLOSSARY.html#test_long\"]": {
|
||||||
|
count: 1,
|
||||||
|
text: "test long"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+19
-15
@@ -1,13 +1,11 @@
|
|||||||
var os = require('os');
|
var os = require("os");
|
||||||
var path = require('path');
|
var path = require("path");
|
||||||
var Q = require('q');
|
var Q = require("q");
|
||||||
var fs = require('fs');
|
var _ = require("lodash");
|
||||||
var _ = require('lodash');
|
|
||||||
var should = require('should');
|
|
||||||
|
|
||||||
var fsUtil = require('../lib/utils/fs');
|
var fsUtil = require("../lib/utils/fs");
|
||||||
var Book = require('../').Book;
|
var Book = require("../").Book;
|
||||||
var LOG_LEVELS = require('../').LOG_LEVELS;
|
var LOG_LEVELS = require("../").LOG_LEVELS;
|
||||||
|
|
||||||
require("./assertions");
|
require("./assertions");
|
||||||
|
|
||||||
@@ -17,10 +15,18 @@ var TMPDIR = os.tmpdir();
|
|||||||
|
|
||||||
|
|
||||||
// Generate and return a book
|
// Generate and return a book
|
||||||
function generateBook(bookId, test) {
|
function generateBook(bookId, test, opts) {
|
||||||
|
opts = _.defaults(opts || {}, {
|
||||||
|
prepare: function() {}
|
||||||
|
});
|
||||||
|
|
||||||
return parseBook(bookId, test)
|
return parseBook(bookId, test)
|
||||||
.then(function(book) {
|
.then(function(book) {
|
||||||
return book.generate(test)
|
|
||||||
|
return Q(opts.prepare(book))
|
||||||
|
.then(function() {
|
||||||
|
return book.generate(test);
|
||||||
|
})
|
||||||
.thenResolve(book);
|
.thenResolve(book);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -53,16 +59,14 @@ global.books = {
|
|||||||
// Cleanup all tests
|
// Cleanup all tests
|
||||||
after(function() {
|
after(function() {
|
||||||
return _.chain(BOOKS)
|
return _.chain(BOOKS)
|
||||||
.map(function(types, bookId) {
|
.map(function(types) {
|
||||||
return _.values(types);
|
return _.values(types);
|
||||||
})
|
})
|
||||||
.flatten()
|
.flatten()
|
||||||
.reduce(function(prev, book) {
|
.reduce(function(prev, book) {
|
||||||
return prev.then(function() {
|
return prev.then(function() {
|
||||||
return fsUtil.remove(book.options.output);
|
return fsUtil.remove(book.options.output);
|
||||||
})
|
});
|
||||||
}, Q())
|
}, Q())
|
||||||
.value();
|
.value();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+14
-12
@@ -1,9 +1,9 @@
|
|||||||
var fs = require('fs');
|
var fs = require("fs");
|
||||||
var _ = require('lodash');
|
var _ = require("lodash");
|
||||||
var path = require('path');
|
var path = require("path");
|
||||||
var cheerio = require('cheerio');
|
var cheerio = require("cheerio");
|
||||||
|
|
||||||
describe('Images', function () {
|
describe("Images", function () {
|
||||||
var book, readme, $, $img, srcs;
|
var book, readme, $, $img, srcs;
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
@@ -17,38 +17,40 @@ describe('Images', function () {
|
|||||||
);
|
);
|
||||||
$ = cheerio.load(readme);
|
$ = cheerio.load(readme);
|
||||||
$img = $("img");
|
$img = $("img");
|
||||||
srcs = $img.map(function() { return $(this).attr("src"); })
|
srcs = $img.map(function() {
|
||||||
|
return $(this).attr("src");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should detect all images', function() {
|
it("should detect all images", function() {
|
||||||
_.uniq(srcs).should.have.lengthOf(4);
|
_.uniq(srcs).should.have.lengthOf(4);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should keep image tags', function() {
|
it("should keep image tags", function() {
|
||||||
srcs.should.have.lengthOf(5);
|
srcs.should.have.lengthOf(5);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not have .svg files', function() {
|
it("should not have .svg files", function() {
|
||||||
_.each(srcs, function(src) {
|
_.each(srcs, function(src) {
|
||||||
path.extname(src).should.not.equal(".svg");
|
path.extname(src).should.not.equal(".svg");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly convert svg images to png', function() {
|
it("should correctly convert svg images to png", function() {
|
||||||
_.each(srcs, function(src) {
|
_.each(srcs, function(src) {
|
||||||
book.should.have.file(src);
|
book.should.have.file(src);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle relative paths', function() {
|
it("should handle relative paths", function() {
|
||||||
var PAGE = fs.readFileSync(
|
var PAGE = fs.readFileSync(
|
||||||
path.join(book.options.output, "folder/PAGE.html"),
|
path.join(book.options.output, "folder/PAGE.html"),
|
||||||
{ encoding: "utf-8" }
|
{ encoding: "utf-8" }
|
||||||
);
|
);
|
||||||
|
|
||||||
PAGE.should.be.html({
|
PAGE.should.be.html({
|
||||||
"img[src='../test.png']": {
|
"img[src=\"../test.png\"]": {
|
||||||
count: 1
|
count: 1
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
var fs = require("fs");
|
||||||
|
var path = require("path");
|
||||||
|
var should = require("should");
|
||||||
|
|
||||||
|
var Book = require("../").Book;
|
||||||
|
var LOG_LEVELS = require("../").LOG_LEVELS;
|
||||||
|
|
||||||
|
describe("Init Books", function () {
|
||||||
|
var initRoot;
|
||||||
|
|
||||||
|
before(function() {
|
||||||
|
initRoot = path.resolve(__dirname, "books/init");
|
||||||
|
return Book.init(initRoot, {
|
||||||
|
logLevel: LOG_LEVELS.DISABLED,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create all chapters", function() {
|
||||||
|
should(fs.existsSync(path.resolve(initRoot, "hello.md"))).be.ok();
|
||||||
|
should(fs.existsSync(path.resolve(initRoot, "hello2.md"))).be.ok();
|
||||||
|
should(fs.existsSync(path.resolve(initRoot, "hello3/hello4.md"))).be.ok();
|
||||||
|
should(fs.existsSync(path.resolve(initRoot, "hello3/hello5/hello6.md"))).be.ok();
|
||||||
|
});
|
||||||
|
});
|
||||||
+17
-17
@@ -1,8 +1,8 @@
|
|||||||
var fs = require('fs');
|
var fs = require("fs");
|
||||||
var path = require('path');
|
var path = require("path");
|
||||||
|
|
||||||
describe('JSON generator', function () {
|
describe("JSON generator", function () {
|
||||||
describe('Basic Book', function() {
|
describe("Basic Book", function() {
|
||||||
var book;
|
var book;
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
@@ -12,15 +12,15 @@ describe('JSON generator', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly output a README.json', function() {
|
it("should correctly output a README.json", function() {
|
||||||
book.should.have.file("README.json");
|
book.should.have.file("README.json");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should output a valid json', function() {
|
it("should output a valid json", function() {
|
||||||
book.should.have.jsonfile("README.json");
|
book.should.have.jsonfile("README.json");
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Page Format', function() {
|
describe("Page Format", function() {
|
||||||
var page;
|
var page;
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
@@ -32,25 +32,25 @@ describe('JSON generator', function () {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should contains valid section', function() {
|
it("should contains valid section", function() {
|
||||||
page.should.have.property("sections").with.lengthOf(1);
|
page.should.have.property("sections").with.lengthOf(1);
|
||||||
page.sections[0].should.have.property("content").which.is.a.String;
|
page.sections[0].should.have.property("content").which.is.a.String();
|
||||||
page.sections[0].should.have.property("type").which.is.a.String.which.equal("normal");
|
page.sections[0].should.have.property("type", "normal");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should contains valid progress', function() {
|
it("should contains valid progress", function() {
|
||||||
page.should.have.property("progress");
|
page.should.have.property("progress");
|
||||||
page.progress.should.have.property("chapters").with.lengthOf(1);
|
page.progress.should.have.property("chapters").with.lengthOf(1);
|
||||||
page.progress.should.have.property("current");
|
page.progress.should.have.property("current");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should contains no languages', function() {
|
it("should contains no languages", function() {
|
||||||
page.should.have.property("langs").with.lengthOf(0);
|
page.should.have.property("langs").with.lengthOf(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Multilingual Book', function() {
|
describe("Multilingual Book", function() {
|
||||||
var book;
|
var book;
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
@@ -60,19 +60,19 @@ describe('JSON generator', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly output READMEs', function() {
|
it("should correctly output READMEs", function() {
|
||||||
book.should.have.file("README.json");
|
book.should.have.file("README.json");
|
||||||
book.should.have.file("en/README.json");
|
book.should.have.file("en/README.json");
|
||||||
book.should.have.file("fr/README.json");
|
book.should.have.file("fr/README.json");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should output valid json', function() {
|
it("should output valid json", function() {
|
||||||
book.should.have.jsonfile("README.json");
|
book.should.have.jsonfile("README.json");
|
||||||
book.should.have.jsonfile("en/README.json");
|
book.should.have.jsonfile("en/README.json");
|
||||||
book.should.have.jsonfile("fr/README.json");
|
book.should.have.jsonfile("fr/README.json");
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Page Format', function() {
|
describe("Page Format", function() {
|
||||||
var page;
|
var page;
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
@@ -84,7 +84,7 @@ describe('JSON generator', function () {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should contains no languages', function() {
|
it("should contains no languages", function() {
|
||||||
page.should.have.property("langs").with.lengthOf(2);
|
page.should.have.property("langs").with.lengthOf(2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+5
-8
@@ -1,8 +1,5 @@
|
|||||||
var fs = require('fs');
|
describe("Languages", function () {
|
||||||
var path = require('path');
|
describe("Parsing", function() {
|
||||||
|
|
||||||
describe('Languages', function () {
|
|
||||||
describe('Parsing', function() {
|
|
||||||
var book;
|
var book;
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
@@ -12,7 +9,7 @@ describe('Languages', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly list languages', function() {
|
it("should correctly list languages", function() {
|
||||||
book.should.have.property("books");
|
book.should.have.property("books");
|
||||||
book.books.should.have.lengthOf(2);
|
book.books.should.have.lengthOf(2);
|
||||||
|
|
||||||
@@ -21,7 +18,7 @@ describe('Languages', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Generation', function() {
|
describe("Generation", function() {
|
||||||
var book;
|
var book;
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
@@ -31,7 +28,7 @@ describe('Languages', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly create books', function() {
|
it("should correctly create books", function() {
|
||||||
book.should.have.file("index.html");
|
book.should.have.file("index.html");
|
||||||
book.should.have.file("en/index.html");
|
book.should.have.file("en/index.html");
|
||||||
book.should.have.file("fr/index.html");
|
book.should.have.file("fr/index.html");
|
||||||
|
|||||||
+34
-8
@@ -1,8 +1,11 @@
|
|||||||
var should = require('should');
|
var fs = require("fs");
|
||||||
|
var path = require("path");
|
||||||
|
var cheerio = require("cheerio");
|
||||||
|
|
||||||
var links = require("../lib/utils/links");
|
var links = require("../lib/utils/links");
|
||||||
|
|
||||||
describe('Links', function () {
|
describe("Links", function () {
|
||||||
it('should correctly test external links', function() {
|
it("should correctly test external links", function() {
|
||||||
links.isExternal("http://google.fr").should.be.exactly(true);
|
links.isExternal("http://google.fr").should.be.exactly(true);
|
||||||
links.isExternal("https://google.fr").should.be.exactly(true);
|
links.isExternal("https://google.fr").should.be.exactly(true);
|
||||||
links.isExternal("test.md").should.be.exactly(false);
|
links.isExternal("test.md").should.be.exactly(false);
|
||||||
@@ -10,28 +13,51 @@ describe('Links', function () {
|
|||||||
links.isExternal("/folder/test.md").should.be.exactly(false);
|
links.isExternal("/folder/test.md").should.be.exactly(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly detect anchor links', function() {
|
it("should correctly detect anchor links", function() {
|
||||||
links.isAnchor("#test").should.be.exactly(true);
|
links.isAnchor("#test").should.be.exactly(true);
|
||||||
links.isAnchor(" #test").should.be.exactly(true);
|
links.isAnchor(" #test").should.be.exactly(true);
|
||||||
links.isAnchor("https://google.fr#test").should.be.exactly(false);
|
links.isAnchor("https://google.fr#test").should.be.exactly(false);
|
||||||
links.isAnchor("test.md#test").should.be.exactly(false);
|
links.isAnchor("test.md#test").should.be.exactly(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('toAbsolute', function() {
|
describe("toAbsolute", function() {
|
||||||
it('should correctly transform as absolute', function() {
|
it("should correctly transform as absolute", function() {
|
||||||
links.toAbsolute("http://google.fr").should.be.equal("http://google.fr");
|
links.toAbsolute("http://google.fr").should.be.equal("http://google.fr");
|
||||||
links.toAbsolute("test.md", "./", "./").should.be.equal("test.md");
|
links.toAbsolute("test.md", "./", "./").should.be.equal("test.md");
|
||||||
links.toAbsolute("folder/test.md", "./", "./").should.be.equal("folder/test.md");
|
links.toAbsolute("folder/test.md", "./", "./").should.be.equal("folder/test.md");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly handle windows path', function() {
|
it("should correctly handle windows path", function() {
|
||||||
links.toAbsolute("folder\\test.md", "./", "./").should.be.equal("folder/test.md");
|
links.toAbsolute("folder\\test.md", "./", "./").should.be.equal("folder/test.md");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly handle absolute path', function() {
|
it("should correctly handle absolute path", function() {
|
||||||
links.toAbsolute("/test.md", "./", "./").should.be.equal("test.md");
|
links.toAbsolute("/test.md", "./", "./").should.be.equal("test.md");
|
||||||
links.toAbsolute("/test.md", "test", "test").should.be.equal("../test.md");
|
links.toAbsolute("/test.md", "test", "test").should.be.equal("../test.md");
|
||||||
links.toAbsolute("/sub/test.md", "test", "test").should.be.equal("../sub/test.md");
|
links.toAbsolute("/sub/test.md", "test", "test").should.be.equal("../sub/test.md");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("page", function() {
|
||||||
|
var book;
|
||||||
|
|
||||||
|
before(function() {
|
||||||
|
return books.generate("links", "website")
|
||||||
|
.then(function(_book) {
|
||||||
|
book = _book;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should correctly replace relative links", function() {
|
||||||
|
var readme = fs.readFileSync(
|
||||||
|
path.join(book.options.output, "folder1/index.html"),
|
||||||
|
{ encoding: "utf-8" }
|
||||||
|
);
|
||||||
|
var $ = cheerio.load(readme);
|
||||||
|
var $a = $(".page-inner a");
|
||||||
|
|
||||||
|
$a.attr("href").should.be.exactly("../folder2/index.html");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
var should = require("should");
|
||||||
|
|
||||||
|
describe("Navigation", function () {
|
||||||
|
var book;
|
||||||
|
|
||||||
|
before(function() {
|
||||||
|
return books.parse("summary")
|
||||||
|
.then(function(_book) {
|
||||||
|
book = _book;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should correctly parse navigation as a map", function() {
|
||||||
|
book.should.have.property("navigation");
|
||||||
|
book.navigation.should.have.property("README.md");
|
||||||
|
book.navigation.should.have.property("README.md");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should correctly include filenames", function() {
|
||||||
|
book.navigation.should.have.property("README.md");
|
||||||
|
book.navigation.should.have.property("PAGE1.md");
|
||||||
|
book.navigation.should.have.property("folder/PAGE2.md");
|
||||||
|
book.navigation.should.not.have.property("NOTFOUND.md");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should correctly detect next/prev for README", function() {
|
||||||
|
var README = book.navigation["README.md"];
|
||||||
|
|
||||||
|
README.index.should.equal(0);
|
||||||
|
README.should.have.property("next");
|
||||||
|
should(README.prev).not.be.ok();
|
||||||
|
|
||||||
|
README.next.should.have.property("path");
|
||||||
|
README.next.path.should.equal("PAGE1.md");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should correctly detect next/prev a page", function() {
|
||||||
|
var PAGE = book.navigation["PAGE1.md"];
|
||||||
|
|
||||||
|
PAGE.index.should.equal(1);
|
||||||
|
PAGE.should.have.property("next");
|
||||||
|
PAGE.should.have.property("prev");
|
||||||
|
|
||||||
|
PAGE.prev.should.have.property("path");
|
||||||
|
PAGE.prev.path.should.equal("README.md");
|
||||||
|
|
||||||
|
PAGE.next.should.have.property("path");
|
||||||
|
PAGE.next.path.should.equal("folder/PAGE2.md");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should correctly detect next/prev for last page", function() {
|
||||||
|
var PAGE = book.navigation["folder/PAGE2.md"];
|
||||||
|
|
||||||
|
PAGE.index.should.equal(2);
|
||||||
|
PAGE.should.have.property("prev");
|
||||||
|
should(PAGE.next).not.be.ok();
|
||||||
|
|
||||||
|
PAGE.prev.should.have.property("path");
|
||||||
|
PAGE.prev.path.should.equal("PAGE1.md");
|
||||||
|
});
|
||||||
|
});
|
||||||
+117
-43
@@ -1,11 +1,12 @@
|
|||||||
var _ = require('lodash');
|
var _ = require("lodash");
|
||||||
var should = require('should');
|
var should = require("should");
|
||||||
var path = require('path');
|
var path = require("path");
|
||||||
|
|
||||||
var Plugin = require('../lib/plugin');
|
var Plugin = require("../lib/plugin");
|
||||||
var PLUGINS_ROOT = path.resolve(__dirname, 'plugins');
|
var parsers = require("gitbook-parsers");
|
||||||
|
var PLUGINS_ROOT = path.resolve(__dirname, "plugins");
|
||||||
|
|
||||||
describe('Plugins', function () {
|
describe("Plugins", function () {
|
||||||
var book;
|
var book;
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
@@ -15,7 +16,7 @@ describe('Plugins', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Invalid', function() {
|
describe("Invalid", function() {
|
||||||
var plugin;
|
var plugin;
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
@@ -23,12 +24,12 @@ describe('Plugins', function () {
|
|||||||
plugin.load("./invalid", PLUGINS_ROOT);
|
plugin.load("./invalid", PLUGINS_ROOT);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be detected', function() {
|
it("should be detected", function() {
|
||||||
should(plugin.isValid()).be.exactly(false);
|
should(plugin.isValid()).be.exactly(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Empty', function() {
|
describe("Empty", function() {
|
||||||
var plugin;
|
var plugin;
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
@@ -36,11 +37,11 @@ describe('Plugins', function () {
|
|||||||
plugin.load("./empty", PLUGINS_ROOT);
|
plugin.load("./empty", PLUGINS_ROOT);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should valid a plugin', function() {
|
it("should valid a plugin", function() {
|
||||||
should(plugin.isValid()).be.exactly(true);
|
should(plugin.isValid()).be.exactly(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return an empty list of resources', function() {
|
it("should return an empty list of resources", function() {
|
||||||
return plugin.getResources()
|
return plugin.getResources()
|
||||||
.then(function(resources) {
|
.then(function(resources) {
|
||||||
_.each(Plugin.RESOURCES, function(resName) {
|
_.each(Plugin.RESOURCES, function(resName) {
|
||||||
@@ -50,7 +51,7 @@ describe('Plugins', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Resources', function() {
|
describe("Resources", function() {
|
||||||
var plugin;
|
var plugin;
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
@@ -60,40 +61,45 @@ describe('Plugins', function () {
|
|||||||
return book.plugins.load(plugin);
|
return book.plugins.load(plugin);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should valid a plugin', function() {
|
it("should valid a plugin", function() {
|
||||||
should(plugin.isValid()).be.exactly(true);
|
should(plugin.isValid()).be.exactly(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Website', function() {
|
describe("Website", function() {
|
||||||
it('should return a valid list of resources', function() {
|
it("should return a valid list of resources", function() {
|
||||||
return plugin.getResources("website")
|
return plugin.getResources("website")
|
||||||
.then(function(resources) {
|
.then(function(resources) {
|
||||||
resources["js"].should.have.lengthOf(1);
|
resources.js.should.have.lengthOf(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should extend books plugins', function() {
|
it("should extend books plugins", function() {
|
||||||
var resources = book.plugins.resources("website");
|
var resources = book.plugins.resources("website");
|
||||||
resources["js"].should.have.lengthOf(1);
|
resources.js.should.have.lengthOf(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('eBook', function() {
|
describe("eBook", function() {
|
||||||
it('should return a valid list of resources', function() {
|
it("should return a valid list of resources", function() {
|
||||||
return plugin.getResources("ebook")
|
return plugin.getResources("ebook")
|
||||||
.then(function(resources) {
|
.then(function(resources) {
|
||||||
resources["css"].should.have.lengthOf(1);
|
resources.css.should.have.lengthOf(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should extend books plugins', function() {
|
it("should extend books plugins", function() {
|
||||||
var resources = book.plugins.resources("ebook");
|
var resources = book.plugins.resources("ebook");
|
||||||
resources["css"].should.have.lengthOf(1);
|
|
||||||
|
// There is resources from highlight plugin and this plugin
|
||||||
|
resources.css.should.have.lengthOf(2);
|
||||||
|
should.exist(_.find(resources.css, {
|
||||||
|
path: "./resources/test"
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Filters', function() {
|
describe("Filters", function() {
|
||||||
var plugin;
|
var plugin;
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
@@ -103,11 +109,11 @@ describe('Plugins', function () {
|
|||||||
return book.plugins.load(plugin);
|
return book.plugins.load(plugin);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should valid a plugin', function() {
|
it("should valid a plugin", function() {
|
||||||
should(plugin.isValid()).be.exactly(true);
|
should(plugin.isValid()).be.exactly(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return a map of filters', function() {
|
it("should return a map of filters", function() {
|
||||||
var filters = plugin.getFilters();
|
var filters = plugin.getFilters();
|
||||||
|
|
||||||
_.size(filters).should.equal(2);
|
_.size(filters).should.equal(2);
|
||||||
@@ -115,22 +121,22 @@ describe('Plugins', function () {
|
|||||||
filters.should.have.property("helloCtx");
|
filters.should.have.property("helloCtx");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly extend template filters', function() {
|
it("should correctly extend template filters", function() {
|
||||||
return book.template.renderString('{{ "World"|hello }}')
|
return book.template.renderString("{{ \"World\"|hello }}")
|
||||||
.then(function(content) {
|
.then(function(content) {
|
||||||
content.should.equal("Hello World");
|
content.should.equal("Hello World");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly set book as context', function() {
|
it("should correctly set book as context", function() {
|
||||||
return book.template.renderString('{{ "root"|helloCtx }}')
|
return book.template.renderString("{{ \"root\"|helloCtx }}")
|
||||||
.then(function(content) {
|
.then(function(content) {
|
||||||
content.should.equal("root:"+book.root);
|
content.should.equal("root:"+book.root);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Blocks', function() {
|
describe("Blocks", function() {
|
||||||
var plugin;
|
var plugin;
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
@@ -142,22 +148,22 @@ describe('Plugins', function () {
|
|||||||
|
|
||||||
var testTpl = function(str, args, options) {
|
var testTpl = function(str, args, options) {
|
||||||
return book.template.renderString(str, args, options)
|
return book.template.renderString(str, args, options)
|
||||||
.then(book.template.postProcess)
|
.then(book.template.postProcess);
|
||||||
};
|
};
|
||||||
|
|
||||||
it('should valid a plugin', function() {
|
it("should valid a plugin", function() {
|
||||||
should(plugin.isValid()).be.exactly(true);
|
should(plugin.isValid()).be.exactly(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly extend template blocks', function() {
|
it("should correctly extend template blocks", function() {
|
||||||
return testTpl('{% test %}hello{% endtest %}')
|
return testTpl("{% test %}hello{% endtest %}")
|
||||||
.then(function(content) {
|
.then(function(content) {
|
||||||
content.should.equal("testhellotest");
|
content.should.equal("testhellotest");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly accept shortcuts', function() {
|
it("should correctly accept shortcuts", function() {
|
||||||
return testTpl('$$hello$$', {}, {
|
return testTpl("$$hello$$", {}, {
|
||||||
type: "markdown"
|
type: "markdown"
|
||||||
})
|
})
|
||||||
.then(function(content) {
|
.then(function(content) {
|
||||||
@@ -165,26 +171,94 @@ describe('Plugins', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly extend template blocks with defined end', function() {
|
it("should correctly extend template blocks with defined end", function() {
|
||||||
return testTpl('{% test2 %}hello{% endtest2end %}')
|
return testTpl("{% test2 %}hello{% endtest2end %}")
|
||||||
.then(function(content) {
|
.then(function(content) {
|
||||||
content.should.equal("test2hellotest2");
|
content.should.equal("test2hellotest2");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly extend template blocks with sub-blocks', function() {
|
it("should correctly extend template blocks with sub-blocks", function() {
|
||||||
return testTpl('{% test3join separator=";" %}hello{% also %}world{% endtest3join %}')
|
return testTpl("{% test3join separator=\";\" %}hello{% also %}world{% endtest3join %}")
|
||||||
.then(function(content) {
|
.then(function(content) {
|
||||||
content.should.equal("hello;world");
|
content.should.equal("hello;world");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly extend template blocks with different sub-blocks', function() {
|
it("should correctly extend template blocks with different sub-blocks", function() {
|
||||||
return testTpl('{% test4join separator=";" %}hello{% also %}the{% finally %}world{% endtest4join %}')
|
return testTpl("{% test4join separator=\";\" %}hello{% also %}the{% finally %}world{% endtest4join %}")
|
||||||
.then(function(content) {
|
.then(function(content) {
|
||||||
content.should.equal("hello;the;world");
|
content.should.equal("hello;the;world");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should correctly extend template blocks with arguments (1)", function() {
|
||||||
|
return testTpl("{% test5args \"a\" %}{% endtest5args %}")
|
||||||
|
.then(function(content) {
|
||||||
|
content.should.equal("test5atest5");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should correctly extend template blocks with arguments (2)", function() {
|
||||||
|
return testTpl("{% test5args 'a', 'b' %}{% endtest5args %}")
|
||||||
|
.then(function(content) {
|
||||||
|
content.should.equal("test5a,btest5");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should correctly extend template blocks with arguments (3)", function() {
|
||||||
|
return testTpl("{% test5args 'a', 'b', 'c' %}{% endtest5args %}")
|
||||||
|
.then(function(content) {
|
||||||
|
content.should.equal("test5a,b,ctest5");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should correctly extend template blocks with args and kwargs", function() {
|
||||||
|
return testTpl("{% test5kwargs 'a', 'b', 'c', d='test', e='test2' %}{% endtest5kwargs %}")
|
||||||
|
.then(function(content) {
|
||||||
|
content.should.equal("test5a,b,c,d:test,e:test2,__keywords:truetest5");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should correctly extend template blocks with access to context", function() {
|
||||||
|
return testTpl("{% set name = 'john' %}{% test6context %}{% endtest6context %}", {})
|
||||||
|
.then(function(content) {
|
||||||
|
content.should.equal("test6johntest6");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Blocks without parsing", function() {
|
||||||
|
var plugin;
|
||||||
|
|
||||||
|
before(function() {
|
||||||
|
plugin = new Plugin(book, "blocks");
|
||||||
|
plugin.load("./blocks", PLUGINS_ROOT);
|
||||||
|
|
||||||
|
return book.plugins.load(plugin);
|
||||||
|
});
|
||||||
|
|
||||||
|
var testTpl = function(markup, str, args, options) {
|
||||||
|
var filetype = parsers.get(markup);
|
||||||
|
|
||||||
|
return book.template.renderString(str, args, options)
|
||||||
|
.then(filetype.page).get("sections").get(0).get("content")
|
||||||
|
.then(book.template.postProcess);
|
||||||
|
};
|
||||||
|
|
||||||
|
it("should correctly process unparsable for markdown", function() {
|
||||||
|
return testTpl(".md", "{% test %}**hello**{% endtest %}")
|
||||||
|
.then(function(content) {
|
||||||
|
content.should.equal("<p>test**hello**test</p>\n");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should correctly process unparsable for asciidoc", function() {
|
||||||
|
return testTpl(".adoc", "{% test %}**hello**{% endtest %}")
|
||||||
|
.then(function(content) {
|
||||||
|
content.should.equal("<div class=\"paragraph\">\n<p>test**hello**test</p>\n</div>");
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,26 @@ module.exports = {
|
|||||||
assert(blk.blocks[1].name, "finally");
|
assert(blk.blocks[1].name, "finally");
|
||||||
return [blk.body, blk.blocks[0].body, blk.blocks[1].body].join(blk.kwargs.separator);
|
return [blk.body, blk.blocks[0].body, blk.blocks[1].body].join(blk.kwargs.separator);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"test5args": {
|
||||||
|
process: function(blk) {
|
||||||
|
return "test5"+blk.args.join(",")+"test5";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test5kwargs": {
|
||||||
|
process: function(blk) {
|
||||||
|
var s = blk.args.join(",");
|
||||||
|
for (var key in blk.kwargs) {
|
||||||
|
s = s + ","+key+":"+blk.kwargs[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return "test5"+s+"test5";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test6context": {
|
||||||
|
process: function() {
|
||||||
|
return "test6"+(this.ctx.name)+"test6";
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
module.exports = {
|
||||||
|
blocks: {
|
||||||
|
"code": {
|
||||||
|
process: function(blk) {
|
||||||
|
var lang = blk.kwargs.language || "code";
|
||||||
|
|
||||||
|
return {
|
||||||
|
body: lang+"_"+blk.body+"_"+lang,
|
||||||
|
html: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"name": "gitbook-plugin-replace_highlight",
|
||||||
|
"description": "Test replacing default code highlighter",
|
||||||
|
"main": "index.js",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"engines": {
|
||||||
|
"gitbook": "*"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
var path = require("path");
|
||||||
|
|
||||||
|
describe("Resolve Files", function () {
|
||||||
|
var book;
|
||||||
|
|
||||||
|
before(function() {
|
||||||
|
return books.parse("basic")
|
||||||
|
.then(function(_book) {
|
||||||
|
book = _book;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("book.fileIsInBook", function() {
|
||||||
|
it("should return true for correct paths", function() {
|
||||||
|
book.fileIsInBook(path.join(book.root, "README.md")).should.equal(true);
|
||||||
|
book.fileIsInBook(path.join(book.root, "styles/website.css")).should.equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return true for root folder", function() {
|
||||||
|
book.fileIsInBook(path.join(book.root, "./")).should.equal(true);
|
||||||
|
book.fileIsInBook(book.root).should.equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return false for files out of scope", function() {
|
||||||
|
book.fileIsInBook(path.join(book.root, "../")).should.equal(false);
|
||||||
|
book.fileIsInBook("README.md").should.equal(false);
|
||||||
|
book.fileIsInBook(path.resolve(book.root, "../README.md")).should.equal(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should correctly handle windows paths", function() {
|
||||||
|
book.fileIsInBook(path.join(book.root, "\\styles\\website.css")).should.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("book.resolve", function() {
|
||||||
|
it("should resolve a file to its absolute path", function() {
|
||||||
|
book.resolve("README.md").should.equal(path.resolve(book.root, "README.md"));
|
||||||
|
book.resolve("website/README.md").should.equal(path.resolve(book.root, "website/README.md"));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should correctly handle windows paths", function() {
|
||||||
|
book.resolve("styles\\website.css").should.equal(path.resolve(book.root, "styles\\website.css"));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should correctly resolve all arguments", function() {
|
||||||
|
book.resolve("test", "hello", "..", "README.md").should.equal(path.resolve(book.root, "test/README.md"));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should correctly resolve to root folder", function() {
|
||||||
|
book.resolve("test", "/README.md").should.equal(path.resolve(book.root, "README.md"));
|
||||||
|
book.resolve("test", "\\README.md").should.equal(path.resolve(book.root, "README.md"));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should throw an error for file out of book", function() {
|
||||||
|
(function() {
|
||||||
|
return book.resolve("../README.md");
|
||||||
|
}).should.throw();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
+12
-12
@@ -1,8 +1,8 @@
|
|||||||
var fs = require('fs');
|
var fs = require("fs");
|
||||||
var path = require('path');
|
var path = require("path");
|
||||||
|
|
||||||
describe('Summary', function () {
|
describe("Summary", function () {
|
||||||
describe('Parsing', function() {
|
describe("Parsing", function() {
|
||||||
var book;
|
var book;
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
@@ -12,13 +12,13 @@ describe('Summary', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly list items', function() {
|
it("should correctly list items", function() {
|
||||||
book.should.have.property("summary");
|
book.should.have.property("summary");
|
||||||
book.summary.should.have.property("chapters");
|
book.summary.should.have.property("chapters");
|
||||||
book.summary.chapters.should.have.lengthOf(4);
|
book.summary.chapters.should.have.lengthOf(4);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly mark non-existant entries', function() {
|
it("should correctly mark non-existant entries", function() {
|
||||||
book.summary.chapters[0].exists.should.have.equal(true);
|
book.summary.chapters[0].exists.should.have.equal(true);
|
||||||
book.summary.chapters[1].exists.should.have.equal(true);
|
book.summary.chapters[1].exists.should.have.equal(true);
|
||||||
book.summary.chapters[2].exists.should.have.equal(true);
|
book.summary.chapters[2].exists.should.have.equal(true);
|
||||||
@@ -26,7 +26,7 @@ describe('Summary', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Generation', function() {
|
describe("Generation", function() {
|
||||||
var book;
|
var book;
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
@@ -36,30 +36,30 @@ describe('Summary', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create files according to summary', function() {
|
it("should create files according to summary", function() {
|
||||||
book.should.have.file("index.html");
|
book.should.have.file("index.html");
|
||||||
book.should.have.file("PAGE1.html");
|
book.should.have.file("PAGE1.html");
|
||||||
book.should.have.file("folder/PAGE2.html");
|
book.should.have.file("folder/PAGE2.html");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly output summary', function() {
|
it("should correctly output summary", function() {
|
||||||
var PAGE = fs.readFileSync(
|
var PAGE = fs.readFileSync(
|
||||||
path.join(book.options.output, "index.html"),
|
path.join(book.options.output, "index.html"),
|
||||||
{ encoding: "utf-8" }
|
{ encoding: "utf-8" }
|
||||||
);
|
);
|
||||||
|
|
||||||
PAGE.should.be.html({
|
PAGE.should.be.html({
|
||||||
".book-summary .chapter[data-level='0'] a": {
|
".book-summary .chapter[data-level=\"0\"] a": {
|
||||||
attributes: {
|
attributes: {
|
||||||
href: "./index.html"
|
href: "./index.html"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
".book-summary .chapter[data-level='1'] a": {
|
".book-summary .chapter[data-level=\"1\"] a": {
|
||||||
attributes: {
|
attributes: {
|
||||||
href: "./PAGE1.html"
|
href: "./PAGE1.html"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
".book-summary .chapter[data-level='2'] a": {
|
".book-summary .chapter[data-level=\"2\"] a": {
|
||||||
attributes: {
|
attributes: {
|
||||||
href: "./folder/PAGE2.html"
|
href: "./folder/PAGE2.html"
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-7
@@ -1,6 +1,6 @@
|
|||||||
var pkg = require("../package.json");
|
var pkg = require("../package.json");
|
||||||
|
|
||||||
describe('Templating', function () {
|
describe("Templating", function () {
|
||||||
var book;
|
var book;
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
@@ -12,19 +12,19 @@ describe('Templating', function () {
|
|||||||
|
|
||||||
var testTpl = function(str, args, options) {
|
var testTpl = function(str, args, options) {
|
||||||
return book.template.renderString(str, args, options)
|
return book.template.renderString(str, args, options)
|
||||||
.then(book.template.postProcess)
|
.then(book.template.postProcess);
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('Context', function() {
|
describe("Context", function() {
|
||||||
it('should correctly have access to generator', function() {
|
it("should correctly have access to generator", function() {
|
||||||
return testTpl('{{ gitbook.generator }}')
|
return testTpl("{{ gitbook.generator }}")
|
||||||
.then(function(content) {
|
.then(function(content) {
|
||||||
content.should.equal("website");
|
content.should.equal("website");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly have access to gitbook version', function() {
|
it("should correctly have access to gitbook version", function() {
|
||||||
return testTpl('{{ gitbook.version }}')
|
return testTpl("{{ gitbook.version }}")
|
||||||
.then(function(content) {
|
.then(function(content) {
|
||||||
content.should.equal(pkg.version.toString());
|
content.should.equal(pkg.version.toString());
|
||||||
});
|
});
|
||||||
|
|||||||
+4
-7
@@ -1,8 +1,5 @@
|
|||||||
var fs = require('fs');
|
describe("Website generator", function () {
|
||||||
var path = require('path');
|
describe("Basic Book", function() {
|
||||||
|
|
||||||
describe('Website generator', function () {
|
|
||||||
describe('Basic Book', function() {
|
|
||||||
var book;
|
var book;
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
@@ -12,11 +9,11 @@ describe('Website generator', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly output an index.html', function() {
|
it("should correctly output an index.html", function() {
|
||||||
book.should.have.file("index.html");
|
book.should.have.file("index.html");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly copy assets', function() {
|
it("should correctly copy assets", function() {
|
||||||
book.should.have.file("gitbook");
|
book.should.have.file("gitbook");
|
||||||
book.should.have.file("gitbook/app.js");
|
book.should.have.file("gitbook/app.js");
|
||||||
book.should.have.file("gitbook/style.css");
|
book.should.have.file("gitbook/style.css");
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"LANGS_CHOOSE": "Valitse kieli",
|
||||||
|
"GLOSSARY": "Sanasto",
|
||||||
|
"GLOSSARY_INDEX": "Hakemisto",
|
||||||
|
"GLOSSARY_OPEN": "Sanasto",
|
||||||
|
"GITBOOK_LINK": "Julkaistu GitBookilla",
|
||||||
|
"SUMMARY": "Sisällysluettelo",
|
||||||
|
"SUMMARY_INTRODUCTION": "Johdanto",
|
||||||
|
"SUMMARY_TOGGLE": "Sisällysluettelu",
|
||||||
|
"SEARCH_TOGGLE": "Etsi",
|
||||||
|
"SEARCH_PLACEHOLDER": "Kirjoita hakusana",
|
||||||
|
"FONTSETTINGS_TOGGLE": "Fonttivalinnat",
|
||||||
|
"SHARE_TOGGLE": "Jaa",
|
||||||
|
"SHARE_ON": "Jaa {{platform}}ssa",
|
||||||
|
"FONTSETTINGS_WHITE": "Valkoinen",
|
||||||
|
"FONTSETTINGS_SEPIA": "Seepia",
|
||||||
|
"FONTSETTINGS_NIGHT": "Yö",
|
||||||
|
"FONTSETTINGS_SANS": "Sans",
|
||||||
|
"FONTSETTINGS_SERIF": "Serif"
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"direction": "rtl",
|
||||||
|
"LANGS_CHOOSE": "בחר שפה",
|
||||||
|
"GLOSSARY": "מונחים",
|
||||||
|
"GLOSSARY_INDEX": "מפתח",
|
||||||
|
"GLOSSARY_OPEN": "מונחים",
|
||||||
|
"GITBOOK_LINK": "הוצאה לאור באמצעות גיט-בוק GITBOOK",
|
||||||
|
"SUMMARY": "תוכן העניינים",
|
||||||
|
"SUMMARY_INTRODUCTION": "הוראות",
|
||||||
|
"SUMMARY_TOGGLE": "תקציר",
|
||||||
|
"SEARCH_TOGGLE": "חיפוש",
|
||||||
|
"SEARCH_PLACEHOLDER": "סוג החיפוש",
|
||||||
|
"FONTSETTINGS_TOGGLE": "הגדרת אותיות",
|
||||||
|
"SHARE_TOGGLE": "שתף",
|
||||||
|
"SHARE_ON": "{{platform}} שתף ב",
|
||||||
|
"FONTSETTINGS_WHITE": "בהיר",
|
||||||
|
"FONTSETTINGS_SEPIA": "חום כהה",
|
||||||
|
"FONTSETTINGS_NIGHT": "מצב לילה",
|
||||||
|
"FONTSETTINGS_SANS": "Sans",
|
||||||
|
"FONTSETTINGS_SERIF": "Serif"
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"LANGS_CHOOSE": "言語を選択",
|
||||||
|
"GLOSSARY": "用語集",
|
||||||
|
"GLOSSARY_INDEX": "インデックス",
|
||||||
|
"GLOSSARY_OPEN": "用語集",
|
||||||
|
"GITBOOK_LINK": "で公開 GitBook",
|
||||||
|
"SUMMARY": "目次",
|
||||||
|
"SUMMARY_INTRODUCTION": "はじめに",
|
||||||
|
"SUMMARY_TOGGLE": "目次",
|
||||||
|
"SEARCH_TOGGLE": "検索",
|
||||||
|
"SEARCH_PLACEHOLDER": "検索すると入力",
|
||||||
|
"FONTSETTINGS_TOGGLE": "フォント設定",
|
||||||
|
"SHARE_TOGGLE": "シェア",
|
||||||
|
"SHARE_ON": "でシェア {{platform}}",
|
||||||
|
"FONTSETTINGS_WHITE": "白",
|
||||||
|
"FONTSETTINGS_SEPIA": "Sepia",
|
||||||
|
"FONTSETTINGS_NIGHT": "夜",
|
||||||
|
"FONTSETTINGS_SANS": "Sans",
|
||||||
|
"FONTSETTINGS_SERIF": "Serif"
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"LANGS_CHOOSE": "언어를 선택하세요",
|
||||||
|
"GLOSSARY": "어휘",
|
||||||
|
"GLOSSARY_INDEX": "색인",
|
||||||
|
"GLOSSARY_OPEN": "어휘",
|
||||||
|
"GITBOOK_LINK": "GitBook에 게시",
|
||||||
|
"SUMMARY": "차례",
|
||||||
|
"SUMMARY_INTRODUCTION": "소개",
|
||||||
|
"SUMMARY_TOGGLE": "차례",
|
||||||
|
"SEARCH_TOGGLE": "검색",
|
||||||
|
"SEARCH_PLACEHOLDER": "검색어 입력",
|
||||||
|
"FONTSETTINGS_TOGGLE": "글꼴 설정",
|
||||||
|
"SHARE_TOGGLE": "공유",
|
||||||
|
"SHARE_ON": "{{platform}}에 공유",
|
||||||
|
"FONTSETTINGS_WHITE": "화이트",
|
||||||
|
"FONTSETTINGS_SEPIA": "세피아",
|
||||||
|
"FONTSETTINGS_NIGHT": "나이트",
|
||||||
|
"FONTSETTINGS_SANS": "고딕",
|
||||||
|
"FONTSETTINGS_SERIF": "명조"
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"LANGS_CHOOSE": "Alege o limba",
|
||||||
|
"GLOSSARY": "Glosar",
|
||||||
|
"GLOSSARY_INDEX": "Index",
|
||||||
|
"GLOSSARY_OPEN": "Glosar",
|
||||||
|
"GITBOOK_LINK": "Publicata cu GitBook",
|
||||||
|
"SUMMARY": "Cuprins",
|
||||||
|
"SUMMARY_INTRODUCTION": "Introducere",
|
||||||
|
"SUMMARY_TOGGLE": "Cuprins",
|
||||||
|
"SEARCH_TOGGLE": "Cauta",
|
||||||
|
"SEARCH_PLACEHOLDER": "Ce cauti",
|
||||||
|
"FONTSETTINGS_TOGGLE": "Setari de font",
|
||||||
|
"SHARE_TOGGLE": "Distribuie",
|
||||||
|
"SHARE_ON": "Distribuie pe {{platform}}",
|
||||||
|
"FONTSETTINGS_WHITE": "Alb",
|
||||||
|
"FONTSETTINGS_SEPIA": "Sepia",
|
||||||
|
"FONTSETTINGS_NIGHT": "Noapte",
|
||||||
|
"FONTSETTINGS_SANS": "Sans",
|
||||||
|
"FONTSETTINGS_SERIF": "Serif"
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"LANGS_CHOOSE": "Lựa chọn ngôn ngữ",
|
||||||
|
"GLOSSARY": "Chú giải",
|
||||||
|
"GLOSSARY_INDEX": "Chỉ mục",
|
||||||
|
"GLOSSARY_OPEN": "Chú giải",
|
||||||
|
"GITBOOK_LINK": "Xuất bản với GitBook",
|
||||||
|
"SUMMARY": "Mục Lục",
|
||||||
|
"SUMMARY_INTRODUCTION": "Giới thiệu",
|
||||||
|
"SUMMARY_TOGGLE": "Mục Lục",
|
||||||
|
"SEARCH_TOGGLE": "Tìm kiếm",
|
||||||
|
"SEARCH_PLACEHOLDER": "Nhập thông tin cần tìm",
|
||||||
|
"FONTSETTINGS_TOGGLE": "Tùy chỉnh phông chữ",
|
||||||
|
"SHARE_TOGGLE": "Chia sẻ",
|
||||||
|
"SHARE_ON": "Chia sẻ trên {{platform}}",
|
||||||
|
"FONTSETTINGS_WHITE": "Sáng",
|
||||||
|
"FONTSETTINGS_SEPIA": "Vàng nâu",
|
||||||
|
"FONTSETTINGS_NIGHT": "Tối",
|
||||||
|
"FONTSETTINGS_SANS": "Sans",
|
||||||
|
"FONTSETTINGS_SERIF": "Serif"
|
||||||
|
}
|
||||||
@@ -35,13 +35,25 @@ define([
|
|||||||
var $pageHead = $page.find("[data-element=head]");
|
var $pageHead = $page.find("[data-element=head]");
|
||||||
var $pageBody = $page.find('.book');
|
var $pageBody = $page.find('.book');
|
||||||
|
|
||||||
|
////
|
||||||
// Merge heads
|
// Merge heads
|
||||||
var headContent = $pageHead.html()
|
// !! Warning !!: we only update necessary portions to avoid strange behavior (page flickering etc ...)
|
||||||
|
////
|
||||||
|
|
||||||
$("head style").each(function() {
|
// Update title
|
||||||
headContent = headContent + this.outerHTML
|
document.title = $pageHead.find("title").text();
|
||||||
});
|
|
||||||
$("head").html(headContent);
|
// Reference to $("head");
|
||||||
|
var $head = $("head");
|
||||||
|
|
||||||
|
// Update next & prev <link> tags
|
||||||
|
// Remove old
|
||||||
|
$head.find("link[rel=prev]").remove();
|
||||||
|
$head.find("link[rel=next]").remove();
|
||||||
|
|
||||||
|
// Add new next * prev <link> tags
|
||||||
|
$head.append($pageHead.find("link[rel=prev]"));
|
||||||
|
$head.append($pageHead.find("link[rel=next]"));
|
||||||
|
|
||||||
// Merge body
|
// Merge body
|
||||||
var bodyClass = $(".book").attr("class");
|
var bodyClass = $(".book").attr("class");
|
||||||
@@ -93,7 +105,19 @@ define([
|
|||||||
events.trigger("page.change");
|
events.trigger("page.change");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var isLeftClickEvent = function (e) {
|
||||||
|
return e.button === 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
var isModifiedEvent = function (e) {
|
||||||
|
return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
|
||||||
|
};
|
||||||
|
|
||||||
var handlePagination = function (e) {
|
var handlePagination = function (e) {
|
||||||
|
if (isModifiedEvent(e) || !isLeftClickEvent(e)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ define([
|
|||||||
},
|
},
|
||||||
"instapaper": function($el) {
|
"instapaper": function($el) {
|
||||||
window.open("http://www.instapaper.com/text?u="+encodeURIComponent(location.href));
|
window.open("http://www.instapaper.com/text?u="+encodeURIComponent(location.href));
|
||||||
|
},
|
||||||
|
"vk": function($el) {
|
||||||
|
window.open("http://vkontakte.ru/share.php?url="+encodeURIComponent(location.href));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,7 @@
|
|||||||
pre {
|
pre {
|
||||||
font-family: monospace, monospace;
|
font-family: monospace, monospace;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
|
direction: ltr;
|
||||||
}
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
@import "mixins.less";
|
@import "mixins.less";
|
||||||
|
|
||||||
@import "ebook/variables.less";
|
@import "ebook/variables.less";
|
||||||
@import "ebook/highlight.less";
|
|
||||||
|
|
||||||
.page {
|
.page {
|
||||||
&.page-toc {
|
&.page-toc {
|
||||||
@@ -39,6 +38,6 @@
|
|||||||
body {
|
body {
|
||||||
.page {
|
.page {
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
.markdown-content(#333, 1.6);
|
.markdown-content(#000, 1.6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,90 +0,0 @@
|
|||||||
/* http://jmblog.github.io/color-themes-for-highlightjs */
|
|
||||||
|
|
||||||
/* Tomorrow Comment */
|
|
||||||
.hljs-comment,
|
|
||||||
.hljs-title {
|
|
||||||
color: #8e908c;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tomorrow Red */
|
|
||||||
.hljs-variable,
|
|
||||||
.hljs-attribute,
|
|
||||||
.hljs-tag,
|
|
||||||
.hljs-regexp,
|
|
||||||
.ruby .hljs-constant,
|
|
||||||
.xml .hljs-tag .hljs-title,
|
|
||||||
.xml .hljs-pi,
|
|
||||||
.xml .hljs-doctype,
|
|
||||||
.html .hljs-doctype,
|
|
||||||
.css .hljs-id,
|
|
||||||
.css .hljs-class,
|
|
||||||
.css .hljs-pseudo {
|
|
||||||
color: #c82829;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tomorrow Orange */
|
|
||||||
.hljs-number,
|
|
||||||
.hljs-preprocessor,
|
|
||||||
.hljs-pragma,
|
|
||||||
.hljs-built_in,
|
|
||||||
.hljs-literal,
|
|
||||||
.hljs-params,
|
|
||||||
.hljs-constant {
|
|
||||||
color: #f5871f;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tomorrow Yellow */
|
|
||||||
.ruby .hljs-class .hljs-title,
|
|
||||||
.css .hljs-rules .hljs-attribute {
|
|
||||||
color: #eab700;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tomorrow Green */
|
|
||||||
.hljs-string,
|
|
||||||
.hljs-value,
|
|
||||||
.hljs-inheritance,
|
|
||||||
.hljs-header,
|
|
||||||
.ruby .hljs-symbol,
|
|
||||||
.xml .hljs-cdata {
|
|
||||||
color: #718c00;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tomorrow Aqua */
|
|
||||||
.css .hljs-hexcolor {
|
|
||||||
color: #3e999f;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tomorrow Blue */
|
|
||||||
.hljs-function,
|
|
||||||
.python .hljs-decorator,
|
|
||||||
.python .hljs-title,
|
|
||||||
.ruby .hljs-function .hljs-title,
|
|
||||||
.ruby .hljs-title .hljs-keyword,
|
|
||||||
.perl .hljs-sub,
|
|
||||||
.javascript .hljs-title,
|
|
||||||
.coffeescript .hljs-title {
|
|
||||||
color: #4271ae;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tomorrow Purple */
|
|
||||||
.hljs-keyword,
|
|
||||||
.javascript .hljs-function {
|
|
||||||
color: #8959a8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs {
|
|
||||||
display: block;
|
|
||||||
background: white;
|
|
||||||
color: #4d4d4c;
|
|
||||||
padding: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.coffeescript .javascript,
|
|
||||||
.javascript .xml,
|
|
||||||
.tex .hljs-formula,
|
|
||||||
.xml .javascript,
|
|
||||||
.xml .vbscript,
|
|
||||||
.xml .css,
|
|
||||||
.xml .hljs-cdata {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
@import "mixins.less";
|
@import "mixins.less";
|
||||||
|
|
||||||
@import "website/fonts.less";
|
|
||||||
@import "website/variables.less";
|
@import "website/variables.less";
|
||||||
@import "website/languages.less";
|
@import "website/languages.less";
|
||||||
@import "website/header.less";
|
@import "website/header.less";
|
||||||
@@ -44,4 +43,5 @@ body {
|
|||||||
font-smoothing: antialiased;
|
font-smoothing: antialiased;
|
||||||
font-family: @font-family-base;
|
font-family: @font-family-base;
|
||||||
font-size: @font-size-base;
|
font-size: @font-size-base;
|
||||||
|
letter-spacing: .2px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,96 +0,0 @@
|
|||||||
@font-face {
|
|
||||||
font-family: 'Merriweather';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 250;
|
|
||||||
src: local('Merriweather Light'),url('@{FontPath}/merriweather/250.woff') format('woff');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Merriweather';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 250;
|
|
||||||
src: local('Merriweather Light Italic'),url('@{FontPath}/merriweather/250i.woff') format('woff');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Merriweather';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('Merriweather'),url('@{FontPath}/merriweather/400.woff') format('woff');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Merriweather';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('Merriweather Italic'),url('@{FontPath}/merriweather/400i.woff') format('woff');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Merriweather';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
src: local('Merriweather Bold'),url('@{FontPath}/merriweather/700.woff') format('woff');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Merriweather';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 700;
|
|
||||||
src: local('Merriweather Bold Italic'),url('@{FontPath}/merriweather/700i.woff') format('woff');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Merriweather';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 900;
|
|
||||||
src: local('Merriweather Heavy'),url('@{FontPath}/merriweather/900.woff') format('woff');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Merriweather';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 900;
|
|
||||||
src: local('Merriweather Heavy Italic'),url('@{FontPath}/merriweather/900i.woff') format('woff');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Open Sans';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 300;
|
|
||||||
src: local('Open Sans Light'),url('@{FontPath}/opensans/300.woff') format('woff');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Open Sans';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 300;
|
|
||||||
src: local('Open Sans Light Italic'),url('@{FontPath}/opensans/300i.woff') format('woff');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Open Sans';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('Open Sans Regular'),url('@{FontPath}/opensans/400.woff') format('woff');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Open Sans';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('Open Sans Italic'),url('@{FontPath}/opensans/400i.woff') format('woff');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Open Sans';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 600;
|
|
||||||
src: local('Open Sans Semibold'),url('@{FontPath}/opensans/600.woff') format('woff');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Open Sans';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 600;
|
|
||||||
src: local('Open Sans Semibold Italic'),url('@{FontPath}/opensans/600i.woff') format('woff');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Open Sans';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
src: local('Open Sans Bold'),url('@{FontPath}/opensans/700.woff') format('woff');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Open Sans';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 700;
|
|
||||||
src: local('Open Sans Bold Italic'),url('@{FontPath}/opensans/700i.woff') format('woff');
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user