mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-26 12:18:01 +00:00
Compare commits
112 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 |
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"strict": false,
|
||||
"browser": false,
|
||||
"quotmark": true,
|
||||
"node": true,
|
||||
"mocha": true
|
||||
}
|
||||
+19
-14
@@ -21,32 +21,37 @@ Translators
|
||||
------------
|
||||
|
||||
- German
|
||||
- Winnie (@winniehell)
|
||||
- Winnie (@winniehell)
|
||||
- Italian
|
||||
- Giulio Bonanome (@gbonanome)
|
||||
- Giulio Bonanome (@gbonanome)
|
||||
- Russian
|
||||
- Andrey Akinshin (@AndreyAkinshin)
|
||||
- Andrey Akinshin (@AndreyAkinshin)
|
||||
- Norwegian
|
||||
- Knut Melvær (@kmelve)
|
||||
- Knut Melvær (@kmelve)
|
||||
- Persian (Farsi)
|
||||
- Mohammad Hossein Mojtahedi (@mhm5000)
|
||||
- Mohammad Hossein Mojtahedi (@mhm5000)
|
||||
- Polish
|
||||
- Łukasz Szeremeta (@lszeremeta)
|
||||
- Łukasz Szeremeta (@lszeremeta)
|
||||
- Portuguese
|
||||
- Ryan O'Mullan (@RyanOM)
|
||||
- Ryan O'Mullan (@RyanOM)
|
||||
- Spanish
|
||||
- Ryan O'Mullan (@RyanOM)
|
||||
- Ryan O'Mullan (@RyanOM)
|
||||
- Simplifiled Chinese
|
||||
- Hu Hao (@howiehu)
|
||||
- Hu Hao (@howiehu)
|
||||
- Traditional Chinese
|
||||
- Hu Hao (@howiehu)
|
||||
- Hu Hao (@howiehu)
|
||||
- French
|
||||
- Samy Pessé (@SamyPesse)
|
||||
- Samy Pessé (@SamyPesse)
|
||||
- Romanian
|
||||
- Iancu Aurel (@awrelll)
|
||||
- Finnish
|
||||
- Tommi Savikko (@savikko)
|
||||
- Tommi Savikko (@savikko)
|
||||
- Japanese
|
||||
- Iancu Aurel (@awrelll)
|
||||
- Iancu Aurel (@awrelll)
|
||||
- Korean
|
||||
- Iancu Aurel (@awrelll)
|
||||
- Iancu Aurel (@awrelll)
|
||||
- SangYeob Yu (@deminoth)
|
||||
- Vietnamese
|
||||
- Hong Nguyen (@nghong)
|
||||
- Hebrew
|
||||
- @a-moses
|
||||
|
||||
+54
@@ -2,6 +2,60 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
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
|
||||
|
||||
@@ -2,12 +2,12 @@ GitBook
|
||||
=======
|
||||
|
||||
[](http://badge.fury.io/js/gitbook)
|
||||
[](https://travis-ci.org/GitbookIO/gitbook)
|
||||
[](https://ci.appveyor.com/project/SamyPesse/gitbook)
|
||||
[](https://travis-ci.org/GitbookIO/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).
|
||||
|
||||
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.
|
||||
|
||||
@@ -50,7 +50,7 @@ $ gitbook build
|
||||
* [AsciiDoc Support](http://help.gitbook.com/format/asciidoc.html)
|
||||
* [Variables and Templating](http://help.gitbook.com/format/templating.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:
|
||||
* Search
|
||||
* 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
|
||||
};
|
||||
+90
-64
@@ -1,30 +1,27 @@
|
||||
var Q = require("q");
|
||||
var _ = require("lodash");
|
||||
var path = require("path");
|
||||
var util = require("util");
|
||||
var lunr = require("lunr");
|
||||
var parsers = require("gitbook-parsers");
|
||||
var color = require("bash-color");
|
||||
|
||||
var fs = require("./utils/fs");
|
||||
var parseNavigation = require("./utils/navigation");
|
||||
var parseProgress = require("./utils/progress");
|
||||
var pageUtil = require("./utils/page");
|
||||
var batch = require("./utils/batch");
|
||||
var pathUtil = require("./utils/path");
|
||||
var links = require("./utils/links");
|
||||
var i18n = require("./utils/i18n");
|
||||
var logger = require("./utils/logger");
|
||||
|
||||
var Configuration = require("./configuration");
|
||||
var TemplateEngine = require("./template");
|
||||
var Plugin = require("./plugin");
|
||||
var PluginsList = require("./pluginslist");
|
||||
|
||||
var generators = require("./generators");
|
||||
|
||||
var Book = function(root, context, parent) {
|
||||
var that = this;
|
||||
var SEARCHINDEX_MAXSIZE = 1000000;
|
||||
|
||||
var Book = function(root, context, parent) {
|
||||
this.context = _.defaults(context || {}, {
|
||||
// Extend book configuration
|
||||
config: {},
|
||||
@@ -84,11 +81,13 @@ var Book = function(root, context, parent) {
|
||||
this.langsFile = null;
|
||||
|
||||
// Search Index
|
||||
this.searchIndexEnabled = true;
|
||||
this.searchIndexSize = 0;
|
||||
this.searchIndex = lunr(function () {
|
||||
this.ref('url');
|
||||
this.ref("url");
|
||||
|
||||
this.field('title', { boost: 10 });
|
||||
this.field('body');
|
||||
this.field("title", { boost: 10 });
|
||||
this.field("body");
|
||||
});
|
||||
|
||||
// Bind methods
|
||||
@@ -124,12 +123,12 @@ Book.prototype.parse = function() {
|
||||
path.join(that.root, lang.path),
|
||||
_.merge({}, that.context, {
|
||||
config: _.extend({}, that.options, {
|
||||
'output': path.join(that.options.output, lang.lang),
|
||||
'language': lang.lang
|
||||
"output": path.join(that.options.output, lang.lang),
|
||||
"language": lang.lang
|
||||
})
|
||||
}),
|
||||
that
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
})
|
||||
@@ -186,7 +185,7 @@ Book.prototype.generate = function(generator) {
|
||||
// Create generator
|
||||
.then(function() {
|
||||
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);
|
||||
|
||||
return generator.prepare();
|
||||
@@ -211,9 +210,9 @@ Book.prototype.generate = function(generator) {
|
||||
|
||||
return Q()
|
||||
|
||||
// First, let's create folder
|
||||
// First, let"s create folder
|
||||
.then(function() {
|
||||
return _.reduce(ops["directories"] || [], function(prev, folder) {
|
||||
return _.reduce(ops.directories || [], function(prev, folder) {
|
||||
return prev.then(function() {
|
||||
that.log.debug.ln("transferring folder", folder);
|
||||
return Q(generator.transferFolder(folder));
|
||||
@@ -221,18 +220,18 @@ Book.prototype.generate = function(generator) {
|
||||
}, Q());
|
||||
})
|
||||
|
||||
// Then, let's copy other files
|
||||
// Then, let"s copy other files
|
||||
.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);
|
||||
return Q(generator.transferFile(file));
|
||||
}));
|
||||
})
|
||||
|
||||
// Finally let's generate content
|
||||
// Finally let"s generate content
|
||||
.then(function() {
|
||||
var nFiles = (ops["content"] || []).length;
|
||||
return _.reduce(ops["content"] || [], function(prev, file, i) {
|
||||
var nFiles = (ops.content || []).length;
|
||||
return _.reduce(ops.content || [], function(prev, file, i) {
|
||||
return prev.then(function() {
|
||||
var p = ((i*100)/nFiles).toFixed(0)+"%";
|
||||
that.log.debug.ln("processing", file, p);
|
||||
@@ -266,7 +265,7 @@ Book.prototype.generate = function(generator) {
|
||||
};
|
||||
|
||||
// Generate the output for a multilingual book
|
||||
Book.prototype.generateMultiLingual = function(generator) {
|
||||
Book.prototype.generateMultiLingual = function() {
|
||||
var that = this;
|
||||
|
||||
return Q()
|
||||
@@ -294,7 +293,7 @@ Book.prototype.generateFile = function(output, options) {
|
||||
book.setOutput(tmpDir);
|
||||
|
||||
return book.generate(options.ebookFormat)
|
||||
.then(function(_options) {
|
||||
.then(function() {
|
||||
var copyFile = function(lang) {
|
||||
var _outputFile = output;
|
||||
var _tmpDir = tmpDir;
|
||||
@@ -338,7 +337,7 @@ Book.prototype.generateFile = function(output, options) {
|
||||
Book.prototype.parseConfig = function() {
|
||||
var that = this;
|
||||
|
||||
that.log.info("loading book configuration....")
|
||||
that.log.info("loading book configuration....");
|
||||
return that.config.load()
|
||||
.then(function() {
|
||||
that.log.info.ok();
|
||||
@@ -348,12 +347,11 @@ Book.prototype.parseConfig = function() {
|
||||
// Parse list of plugins
|
||||
Book.prototype.parsePlugins = function() {
|
||||
var that = this;
|
||||
var failed = [];
|
||||
|
||||
// Load plugins
|
||||
return that.plugins.load(that.options.plugins)
|
||||
.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.debug.ln("normalize plugins list");
|
||||
@@ -445,7 +443,7 @@ Book.prototype.parseSummary = function() {
|
||||
.then(function(content) {
|
||||
return summary.parser.summary(content, {
|
||||
entryPoint: that.readmeFile,
|
||||
entryPointTitle: that.i18n('SUMMARY_INTRODUCTION'),
|
||||
entryPointTitle: that.i18n("SUMMARY_INTRODUCTION"),
|
||||
files: that.files
|
||||
})
|
||||
.fail(function(err) {
|
||||
@@ -512,7 +510,7 @@ Book.prototype.parsePage = function(filename, options) {
|
||||
var interpolate = function(fn) {
|
||||
return Q(fn(page))
|
||||
.then(function(_page) {
|
||||
page = _page;
|
||||
page = _page || page;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -574,7 +572,7 @@ Book.prototype.parsePage = function(filename, options) {
|
||||
.then(function(content) {
|
||||
section.content = content;
|
||||
return _sections.concat([section]);
|
||||
})
|
||||
});
|
||||
});
|
||||
}, Q([]));
|
||||
})
|
||||
@@ -586,8 +584,8 @@ Book.prototype.parsePage = function(filename, options) {
|
||||
convertImages: options.convertImages,
|
||||
input: filename,
|
||||
navigation: that.navigation,
|
||||
base: path.dirname(filename) || './',
|
||||
output: path.dirname(filename) || './',
|
||||
base: path.dirname(filename) || "./",
|
||||
output: path.dirname(filename) || "./",
|
||||
glossary: that.glossary
|
||||
});
|
||||
})
|
||||
@@ -622,7 +620,7 @@ Book.prototype.findFile = function(filename) {
|
||||
parser: parsers.get(ext),
|
||||
path: filepath
|
||||
};
|
||||
})
|
||||
});
|
||||
});
|
||||
}, Q(null));
|
||||
};
|
||||
@@ -630,21 +628,26 @@ Book.prototype.findFile = function(filename) {
|
||||
// Check if a file exists in the book
|
||||
Book.prototype.fileExists = function(filename) {
|
||||
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
|
||||
Book.prototype.readFile = function(filename) {
|
||||
return fs.readFile(
|
||||
path.join(this.root, filename),
|
||||
this.resolve(filename),
|
||||
{ encoding: "utf8" }
|
||||
);
|
||||
};
|
||||
|
||||
// Return stat for a file
|
||||
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
|
||||
@@ -652,28 +655,28 @@ Book.prototype.listAllFiles = function() {
|
||||
var that = this;
|
||||
|
||||
return fs.list(this.root, {
|
||||
ignoreFiles: ['.ignore', '.gitignore', '.bookignore'],
|
||||
ignoreFiles: [".ignore", ".gitignore", ".bookignore"],
|
||||
ignoreRules: [
|
||||
// Skip Git stuff
|
||||
'.git/',
|
||||
'.gitignore',
|
||||
".git/",
|
||||
".gitignore",
|
||||
|
||||
// Skip OS X meta data
|
||||
'.DS_Store',
|
||||
".DS_Store",
|
||||
|
||||
// Skip stuff installed by plugins
|
||||
'node_modules',
|
||||
"node_modules",
|
||||
|
||||
// Skip book outputs
|
||||
'_book',
|
||||
'*.pdf',
|
||||
'*.epub',
|
||||
'*.mobi',
|
||||
"_book",
|
||||
"*.pdf",
|
||||
"*.epub",
|
||||
"*.mobi",
|
||||
|
||||
// Skip config files
|
||||
'.ignore',
|
||||
'.bookignore',
|
||||
'book.json',
|
||||
".ignore",
|
||||
".bookignore",
|
||||
"book.json",
|
||||
]
|
||||
})
|
||||
.then(function(_files) {
|
||||
@@ -682,7 +685,7 @@ Book.prototype.listAllFiles = function() {
|
||||
};
|
||||
|
||||
// Return true if the book is a multilingual book
|
||||
Book.prototype.isMultilingual = function(filename) {
|
||||
Book.prototype.isMultilingual = function() {
|
||||
return this.books.length > 0;
|
||||
};
|
||||
|
||||
@@ -692,7 +695,7 @@ Book.prototype.parentRoot = function() {
|
||||
return this.root;
|
||||
};
|
||||
|
||||
// Return true if it's a sub-book
|
||||
// Return true if it"s a sub-book
|
||||
Book.prototype.isSubBook = function() {
|
||||
return !!this.parent;
|
||||
};
|
||||
@@ -702,39 +705,62 @@ Book.prototype.isEntryPoint = function(fp) {
|
||||
return fp == this.readmeFile;
|
||||
};
|
||||
|
||||
// Resolve a path in book
|
||||
Book.prototype.resolve = function(p) {
|
||||
return path.resolve(this.root, p);
|
||||
// Alias to book.config.get
|
||||
Book.prototype.getConfig = function(key, def) {
|
||||
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
|
||||
Book.prototype.contentPath = function(link) {
|
||||
if (
|
||||
path.basename(link, path.extname(link)) == "README"
|
||||
|| link == this.readmeFile
|
||||
path.basename(link, path.extname(link)) == "README" ||
|
||||
link == this.readmeFile
|
||||
) {
|
||||
link = path.join(path.dirname(link), "index"+path.extname(link));
|
||||
}
|
||||
|
||||
link = links.changeExtension(link, ".html");
|
||||
return link;
|
||||
}
|
||||
};
|
||||
|
||||
// Normalize a link to .html and convert README -> index
|
||||
Book.prototype.contentLink = function(link) {
|
||||
return links.normalize(this.contentPath(link));
|
||||
}
|
||||
};
|
||||
|
||||
// Index a page into the search index
|
||||
Book.prototype.indexPage = function(page) {
|
||||
var nav = this.navigation[page.path];
|
||||
if (!nav) return;
|
||||
if (!nav || !this.searchIndexEnabled) return;
|
||||
|
||||
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({
|
||||
url: this.contentLink(page.path),
|
||||
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.glossaryFile = that.glossaryFile || that.config.getStructure("glossary")+extension;
|
||||
that.langsFile = that.langsFile || that.config.getStructure("langs")+extension;
|
||||
}
|
||||
};
|
||||
|
||||
// Change output path
|
||||
Book.prototype.setOutput = function(p) {
|
||||
@@ -760,7 +786,7 @@ Book.prototype.setOutput = function(p) {
|
||||
};
|
||||
|
||||
// Translate a strign according to the book language
|
||||
Book.prototype.i18n = function(phrase) {
|
||||
Book.prototype.i18n = function() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
return i18n.__.apply({}, [this.config.normalizeLanguage()].concat(args));
|
||||
};
|
||||
@@ -779,10 +805,10 @@ Book.prototype.normError = function(err, opts, defs) {
|
||||
err.toString = function() {
|
||||
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.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;
|
||||
@@ -820,7 +846,7 @@ Book.init = function(root, opts) {
|
||||
var chapters = book.summary.chapters || [];
|
||||
extensionToUse = path.extname(summary);
|
||||
|
||||
if (chapters.length == 0) {
|
||||
if (chapters.length === 0) {
|
||||
chapters = [
|
||||
{
|
||||
title: "Summary",
|
||||
@@ -836,7 +862,7 @@ Book.init = function(root, opts) {
|
||||
return Q(chaptersPaths(chapters));
|
||||
})
|
||||
.then(function(chapters) {
|
||||
// Create files that don't exist
|
||||
// Create files that don"t exist
|
||||
return Q.all(_.map(chapters, function(chapter) {
|
||||
if (!chapter.path) return Q();
|
||||
var absolutePath = path.resolve(book.root, chapter.path);
|
||||
@@ -852,7 +878,7 @@ Book.init = function(root, opts) {
|
||||
|
||||
return fs.mkdirp(path.dirname(absolutePath))
|
||||
.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 Q = require("q");
|
||||
var path = require("path");
|
||||
var semver = require('semver');
|
||||
var semver = require("semver");
|
||||
|
||||
var pkg = require('../package.json');
|
||||
var fs = require("./utils/fs");
|
||||
var pkg = require("../package.json");
|
||||
var i18n = require("./utils/i18n");
|
||||
|
||||
// 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
|
||||
function normalizePluginsList(plugins) {
|
||||
function normalizePluginsList(plugins, addDefaults) {
|
||||
// Normalize list to an array
|
||||
plugins = _.isString(plugins) ? plugins.split(",") : (plugins || []);
|
||||
|
||||
@@ -23,10 +36,13 @@ function normalizePluginsList(plugins) {
|
||||
if (plugin.name) return plugin;
|
||||
|
||||
var parts = plugin.split("@");
|
||||
var name = parts[0];
|
||||
var version = parts[1];
|
||||
return {
|
||||
'name': parts[0],
|
||||
'version': parts[1] // optional
|
||||
}
|
||||
"name": name,
|
||||
"version": version, // optional
|
||||
"isDefault": isDefaultPlugin(name, version)
|
||||
};
|
||||
});
|
||||
|
||||
// List plugins to remove
|
||||
@@ -40,26 +56,30 @@ function normalizePluginsList(plugins) {
|
||||
.value();
|
||||
|
||||
// Merge with defaults
|
||||
plugins = _.chain(plugins)
|
||||
.concat(_.map(defaultsPlugins, function(plugin) {
|
||||
return { 'name': plugin }
|
||||
}))
|
||||
.uniq()
|
||||
.value();
|
||||
if (addDefaults !== false) {
|
||||
_.each(DEFAULT_PLUGINS, function(plugin) {
|
||||
if (_.find(plugins, { name: plugin })) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Build final list
|
||||
plugins.push({
|
||||
"name": plugin,
|
||||
"isDefault": true
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Remove plugin that start with '-'
|
||||
plugins = _.filter(plugins, function(plugin) {
|
||||
return !_.contains(toremove, plugin.name) && !(plugin.name.length > 0 && plugin.name[0] == "-");
|
||||
});
|
||||
|
||||
// Remove duplicates
|
||||
plugins = _.uniq(plugins, 'name');
|
||||
|
||||
return plugins;
|
||||
}
|
||||
|
||||
// Normalize a list of plugin name to use
|
||||
function normalizePluginsNames(plugins) {
|
||||
return _.pluck(normalizePluginsList(plugins), "name");
|
||||
};
|
||||
|
||||
var Configuration = function(book, options) {
|
||||
var that = this;
|
||||
|
||||
@@ -96,11 +116,11 @@ Configuration.prototype.load = function() {
|
||||
|
||||
return Q()
|
||||
.then(function() {
|
||||
var configPath, config;
|
||||
var configPath, _config;
|
||||
|
||||
try {
|
||||
configPath = require.resolve(
|
||||
path.resolve(that.book.root, that.options.configFile)
|
||||
that.book.resolve(that.options.configFile)
|
||||
);
|
||||
|
||||
// Invalidate node.js cache for livreloading
|
||||
@@ -109,7 +129,7 @@ Configuration.prototype.load = function() {
|
||||
_config = require(configPath);
|
||||
that.options = _.merge(
|
||||
that.options,
|
||||
_.omit(_config, 'configFile', 'defaultsPlugins', 'generator', 'extension')
|
||||
_.omit(_config, "configFile", "defaultsPlugins", "generator", "extension")
|
||||
);
|
||||
}
|
||||
catch(err) {
|
||||
@@ -118,16 +138,18 @@ Configuration.prototype.load = function() {
|
||||
}
|
||||
})
|
||||
.then(function() {
|
||||
if (!semver.satisfies(pkg.version, that.options.gitbook)) {
|
||||
throw "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.book.isSubBook()) {
|
||||
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 != "*" && !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.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 = _.uniq(that.options.plugins, "name");
|
||||
|
||||
@@ -156,10 +178,14 @@ Configuration.prototype.normalizeLanguage = function() {
|
||||
return i18n.normalizeLanguage(this.options.language);
|
||||
};
|
||||
|
||||
// Return a configuration
|
||||
Configuration.prototype.get = function(key, def) {
|
||||
return _.get(this.options, key, def);
|
||||
};
|
||||
|
||||
// Default configuration
|
||||
Configuration.DEFAULT = {
|
||||
// Options that can't be extend
|
||||
// Options that can"t be extend
|
||||
"configFile": "book",
|
||||
"generator": "website",
|
||||
"extension": null,
|
||||
@@ -186,6 +212,7 @@ Configuration.DEFAULT = {
|
||||
// CSS Styles
|
||||
"styles": {
|
||||
"website": "styles/website.css",
|
||||
"print": "styles/print.css",
|
||||
"ebook": "styles/ebook.css",
|
||||
"pdf": "styles/pdf.css",
|
||||
"mobi": "styles/mobi.css",
|
||||
@@ -208,9 +235,9 @@ Configuration.DEFAULT = {
|
||||
"variables": {},
|
||||
|
||||
// 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
|
||||
"theme": path.resolve(__dirname, '../theme'),
|
||||
"theme": path.resolve(__dirname, "../theme"),
|
||||
|
||||
// Links in template (null: default, false: remove, string: new value)
|
||||
"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’]
|
||||
"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)
|
||||
// Note: 72 pts equals 1 inch
|
||||
"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 fs = require("./utils/fs");
|
||||
|
||||
var Plugin = require("./plugin");
|
||||
|
||||
var BaseGenerator = function(book) {
|
||||
this.book = book;
|
||||
|
||||
@@ -36,7 +34,7 @@ BaseGenerator.prototype.convertFile = function(input) {
|
||||
// Copy file to the output (non parsable)
|
||||
BaseGenerator.prototype.transferFile = function(input) {
|
||||
return fs.copy(
|
||||
path.join(this.book.root, input),
|
||||
this.book.resolve(input),
|
||||
path.join(this.options.output, input)
|
||||
);
|
||||
};
|
||||
@@ -53,8 +51,8 @@ BaseGenerator.prototype.copyCover = function() {
|
||||
var that = this;
|
||||
|
||||
return Q.all([
|
||||
fs.copy(path.join(that.book.root, "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.jpg"), path.join(that.options.output, "cover.jpg")),
|
||||
fs.copy(that.book.resolve("cover_small.jpg"), path.join(that.options.output, "cover_small.jpg"))
|
||||
])
|
||||
.fail(function() {
|
||||
// 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"))
|
||||
]);
|
||||
})
|
||||
.fail(function(err) {
|
||||
.fail(function() {
|
||||
return Q();
|
||||
});
|
||||
};
|
||||
|
||||
+13
-13
@@ -2,7 +2,7 @@ var util = require("util");
|
||||
var path = require("path");
|
||||
var Q = require("q");
|
||||
var _ = require("lodash");
|
||||
var exec = require('child_process').exec;
|
||||
var exec = require("child_process").exec;
|
||||
|
||||
var fs = require("../utils/fs");
|
||||
var stringUtils = require("../utils/string");
|
||||
@@ -18,7 +18,7 @@ var Generator = function(book, format) {
|
||||
this.namespace = "ebook";
|
||||
|
||||
// Styles to use
|
||||
this.styles = _.compact(["ebook", this.ebookFormat]);
|
||||
this.styles = _.compact(["print", "ebook", this.ebookFormat]);
|
||||
|
||||
// Convert images (svg -> png)
|
||||
this.convertImages = true;
|
||||
@@ -26,9 +26,9 @@ var Generator = function(book, format) {
|
||||
util.inherits(Generator, BaseGenerator);
|
||||
|
||||
Generator.prototype.prepareTemplates = function() {
|
||||
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["glossary"] = this.book.plugins.template("ebook:glossary") || path.resolve(this.options.theme, 'templates/ebook/glossary.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.glossary = this.book.plugins.template("ebook:glossary") || path.resolve(this.options.theme, "templates/ebook/glossary.html");
|
||||
|
||||
return Q();
|
||||
};
|
||||
@@ -38,7 +38,7 @@ Generator.prototype.writeSummary = function() {
|
||||
var that = this;
|
||||
|
||||
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() {
|
||||
@@ -52,12 +52,12 @@ Generator.prototype.finish = function() {
|
||||
.then(function() {
|
||||
if (!that.ebookFormat) return Q();
|
||||
|
||||
var d = Q.defer();
|
||||
|
||||
if (!that.options.cover && fs.existsSync(path.join(that.options.output, "cover.jpg"))) {
|
||||
that.options.cover = path.join(that.options.output, "cover.jpg");
|
||||
}
|
||||
|
||||
var d = Q.defer();
|
||||
|
||||
var _options = {
|
||||
"--cover": that.options.cover,
|
||||
"--title": that.options.title,
|
||||
@@ -68,8 +68,6 @@ Generator.prototype.finish = function() {
|
||||
"--book-producer": "GitBook",
|
||||
"--publisher": "GitBook",
|
||||
"--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 ')]",
|
||||
"--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 ')]",
|
||||
@@ -82,6 +80,8 @@ Generator.prototype.finish = function() {
|
||||
var pdfOptions = that.options.pdf;
|
||||
|
||||
_.extend(_options, {
|
||||
"--chapter-mark": String(pdfOptions.chapterMark),
|
||||
"--page-breaks-before": String(pdfOptions.pageBreaksBefore),
|
||||
"--margin-left": String(pdfOptions.margin.left),
|
||||
"--margin-right": String(pdfOptions.margin.right),
|
||||
"--margin-top": String(pdfOptions.margin.top),
|
||||
@@ -108,7 +108,7 @@ Generator.prototype.finish = function() {
|
||||
|
||||
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) {
|
||||
that.book.log.info.fail();
|
||||
|
||||
@@ -124,11 +124,11 @@ Generator.prototype.finish = function() {
|
||||
d.resolve();
|
||||
});
|
||||
|
||||
child.stdout.on('data', function (data) {
|
||||
child.stdout.on("data", function (data) {
|
||||
that.book.log.debug(data);
|
||||
});
|
||||
|
||||
child.stderr.on('data', function (data) {
|
||||
child.stderr.on("data", function (data) {
|
||||
that.book.log.debug(data);
|
||||
});
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ var Generator = function() {
|
||||
util.inherits(Generator, BaseGenerator);
|
||||
|
||||
// Ignore some methods
|
||||
Generator.prototype.transferFile = function(input) { };
|
||||
Generator.prototype.transferFile = function() { };
|
||||
|
||||
// Convert an input file
|
||||
Generator.prototype.convertFile = function(input) {
|
||||
@@ -44,7 +44,7 @@ Generator.prototype.finish = function() {
|
||||
// Write README.json
|
||||
Generator.prototype.writeReadme = function() {
|
||||
var that = this;
|
||||
var mainlang, langs;
|
||||
var mainLang, langs, readme;
|
||||
|
||||
return Q()
|
||||
.then(function() {
|
||||
|
||||
+18
-22
@@ -10,7 +10,6 @@ var FilterExtension = require("nunjucks-filter")(nunjucks);
|
||||
var fs = require("../utils/fs");
|
||||
var BaseGenerator = require("../generator");
|
||||
var links = require("../utils/links");
|
||||
var pageUtil = require("../utils/page");
|
||||
var i18n = require("../utils/i18n");
|
||||
|
||||
var pkg = require("../../package.json");
|
||||
@@ -50,12 +49,13 @@ Generator.prototype.prepareStyles = function() {
|
||||
this.styles = _.chain(this.styles)
|
||||
.map(function(style) {
|
||||
var stylePath = that.options.styles[style];
|
||||
if (fs.existsSync(path.resolve(that.book.root, stylePath))) {
|
||||
return stylePath;
|
||||
if (stylePath && fs.existsSync(that.book.resolve(stylePath))) {
|
||||
return [style, stylePath];
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.compact()
|
||||
.object()
|
||||
.value();
|
||||
|
||||
return Q();
|
||||
@@ -63,9 +63,9 @@ Generator.prototype.prepareStyles = function() {
|
||||
|
||||
// Prepare templates
|
||||
Generator.prototype.prepareTemplates = function() {
|
||||
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["glossary"] = this.book.plugins.template("site:glossary") || path.resolve(this.options.theme, 'templates/website/glossary.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.glossary = this.book.plugins.template("site:glossary") || path.resolve(this.options.theme, "templates/website/glossary.html");
|
||||
|
||||
return Q();
|
||||
};
|
||||
@@ -97,13 +97,13 @@ Generator.prototype.prepareTemplateEngine = function() {
|
||||
|
||||
// Add filter
|
||||
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;
|
||||
});
|
||||
|
||||
// Add extension
|
||||
that.env.addExtension('AutoEscapeExtension', new AutoEscapeExtension(that.env));
|
||||
that.env.addExtension('FilterExtension', new FilterExtension(that.env));
|
||||
that.env.addExtension("AutoEscapeExtension", new AutoEscapeExtension(that.env));
|
||||
that.env.addExtension("FilterExtension", new FilterExtension(that.env));
|
||||
});
|
||||
};
|
||||
|
||||
@@ -113,7 +113,7 @@ Generator.prototype.finish = function() {
|
||||
.then(this.copyCover)
|
||||
.then(this.writeGlossary)
|
||||
.then(this.writeSearchIndex)
|
||||
.then(this.writeLangsIndex)
|
||||
.then(this.writeLangsIndex);
|
||||
};
|
||||
|
||||
// Convert an input file
|
||||
@@ -134,11 +134,11 @@ Generator.prototype.convertFile = function(input) {
|
||||
var output = path.join(that.options.output, relativeOutput);
|
||||
|
||||
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);
|
||||
|
||||
return that._writeTemplate(that.templates["page"], {
|
||||
return that._writeTemplate(that.templates.page, {
|
||||
progress: page.progress,
|
||||
|
||||
_input: page.path,
|
||||
@@ -152,27 +152,23 @@ Generator.prototype.convertFile = function(input) {
|
||||
|
||||
// Write the index for langs
|
||||
Generator.prototype.writeLangsIndex = function() {
|
||||
var that = this;
|
||||
if (!this.book.langs.length) return Q();
|
||||
return this._writeTemplate(this.templates["langs"], {
|
||||
|
||||
return this._writeTemplate(this.templates.langs, {
|
||||
langs: this.book.langs
|
||||
}, path.join(this.options.output, "index.html"));
|
||||
};
|
||||
|
||||
// Write glossary
|
||||
Generator.prototype.writeGlossary = function() {
|
||||
var that = this;
|
||||
|
||||
// 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
|
||||
Generator.prototype.writeSearchIndex = function() {
|
||||
var that = this;
|
||||
|
||||
return fs.writeFile(
|
||||
path.join(this.options.output, "search_index.json"),
|
||||
JSON.stringify(this.book.searchIndex)
|
||||
@@ -206,7 +202,7 @@ Generator.prototype._writeTemplate = function(tpl, options, output, interpolate)
|
||||
|
||||
interpolate = interpolate || _.identity;
|
||||
return Q()
|
||||
.then(function(sections) {
|
||||
.then(function() {
|
||||
return that.env.render(
|
||||
tpl,
|
||||
_.extend({
|
||||
@@ -238,7 +234,7 @@ Generator.prototype._writeTemplate = function(tpl, options, output, interpolate)
|
||||
basePath: ".",
|
||||
staticBase: path.join(".", "gitbook"),
|
||||
|
||||
'__': that.book.i18n.bind(that.book)
|
||||
"__": that.book.i18n.bind(that.book)
|
||||
}, options)
|
||||
);
|
||||
})
|
||||
|
||||
+21
-22
@@ -1,11 +1,10 @@
|
||||
var Q = require("q");
|
||||
var _ = require("lodash");
|
||||
var path = require("path");
|
||||
var tinylr = require('tiny-lr');
|
||||
var color = require('bash-color');
|
||||
var tinylr = require("tiny-lr");
|
||||
var color = require("bash-color");
|
||||
|
||||
var Book = require("./book");
|
||||
var Plugin = require("./plugin");
|
||||
var Server = require("./utils/server");
|
||||
var stringUtils = require("./utils/string");
|
||||
var watch = require("./utils/watch");
|
||||
@@ -42,10 +41,10 @@ module.exports = {
|
||||
var output = args[1] || path.join(input, "_book");
|
||||
|
||||
var book = new Book(input, _.extend({}, {
|
||||
'config': {
|
||||
'output': output
|
||||
"config": {
|
||||
"output": output
|
||||
},
|
||||
'logLevel': kwargs.log
|
||||
"logLevel": kwargs.log
|
||||
}));
|
||||
|
||||
return book.parse()
|
||||
@@ -71,7 +70,7 @@ module.exports = {
|
||||
var output = args[1];
|
||||
|
||||
var book = new Book(input, _.extend({}, {
|
||||
'logLevel': kwargs.log
|
||||
"logLevel": kwargs.log
|
||||
}));
|
||||
|
||||
return book.parse()
|
||||
@@ -116,7 +115,7 @@ module.exports = {
|
||||
|
||||
// Init livereload server
|
||||
var lrServer = tinylr({});
|
||||
var lrPath = undefined;
|
||||
var lrPath;
|
||||
|
||||
var generate = function() {
|
||||
if (server.isRunning()) console.log("Stopping server");
|
||||
@@ -124,10 +123,10 @@ module.exports = {
|
||||
return server.stop()
|
||||
.then(function() {
|
||||
var book = new Book(input, _.extend({}, {
|
||||
'config': {
|
||||
'defaultsPlugins': ["livereload"]
|
||||
"config": {
|
||||
"defaultsPlugins": ["livereload"]
|
||||
},
|
||||
'logLevel': kwargs.log
|
||||
"logLevel": kwargs.log
|
||||
}));
|
||||
|
||||
return book.parse()
|
||||
@@ -138,10 +137,10 @@ module.exports = {
|
||||
})
|
||||
.then(function(book) {
|
||||
console.log();
|
||||
console.log('Starting server ...');
|
||||
console.log("Starting server ...");
|
||||
return server.start(book.options.output, kwargs.port)
|
||||
.then(function() {
|
||||
console.log('Serving book on http://localhost:'+kwargs.port);
|
||||
console.log("Serving book on http://localhost:"+kwargs.port);
|
||||
|
||||
if (lrPath) {
|
||||
// trigger livereload
|
||||
@@ -158,19 +157,19 @@ module.exports = {
|
||||
.then(function(filepath) {
|
||||
// set livereload path
|
||||
lrPath = filepath;
|
||||
console.log("Restart after change in files");
|
||||
console.log('');
|
||||
console.log("Restart after change in file", filepath);
|
||||
console.log("");
|
||||
return generate();
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return Q.nfcall(lrServer.listen.bind(lrServer), kwargs.lrport)
|
||||
.then(function() {
|
||||
console.log('Live reload server started on port:', kwargs.lrport);
|
||||
console.log('Press CTRL+C to quit ...');
|
||||
console.log('')
|
||||
console.log("Live reload server started on port:", kwargs.lrport);
|
||||
console.log("Press CTRL+C to quit ...");
|
||||
console.log("");
|
||||
return generate();
|
||||
});
|
||||
}
|
||||
@@ -179,7 +178,7 @@ module.exports = {
|
||||
{
|
||||
name: "install [book]",
|
||||
description: "install plugins dependencies",
|
||||
exec: function(args, kwargs) {
|
||||
exec: function(args) {
|
||||
var input = args[0] || process.cwd();
|
||||
|
||||
var book = new Book(input);
|
||||
@@ -198,7 +197,7 @@ module.exports = {
|
||||
{
|
||||
name: "init [directory]",
|
||||
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())
|
||||
.then(function(){
|
||||
console.log("");
|
||||
|
||||
+5
-5
@@ -4,7 +4,7 @@ var semver = require("semver");
|
||||
var path = require("path");
|
||||
var url = require("url");
|
||||
var fs = require("./utils/fs");
|
||||
var resolve = require('resolve');
|
||||
var resolve = require("resolve");
|
||||
|
||||
var pkg = require("../package.json");
|
||||
|
||||
@@ -33,8 +33,8 @@ var Plugin = function(book, name) {
|
||||
// Type of plugins resources
|
||||
Plugin.RESOURCES = ["js", "css"];
|
||||
Plugin.HOOKS = [
|
||||
"init", "finish", "finish:before"
|
||||
]
|
||||
"init", "finish", "finish:before", "page", "page:before"
|
||||
];
|
||||
|
||||
// Load from a name
|
||||
Plugin.prototype.load = function(name, baseDir) {
|
||||
@@ -77,7 +77,7 @@ Plugin.prototype._getResources = function(base) {
|
||||
var book = this.infos[base];
|
||||
|
||||
// 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
|
||||
if (!book) {
|
||||
@@ -168,7 +168,7 @@ Plugin.prototype.copyAssets = function(out, base) {
|
||||
var that = this;
|
||||
|
||||
return this.getResources(base)
|
||||
.get('assets')
|
||||
.get("assets")
|
||||
.then(function(assets) {
|
||||
// Assets are undefined
|
||||
if(!assets) return false;
|
||||
|
||||
+19
-26
@@ -1,14 +1,14 @@
|
||||
var _ = require("lodash");
|
||||
var Q = require("q");
|
||||
var npmi = require('npmi');
|
||||
var npm = require('npm');
|
||||
var semver = require('semver');
|
||||
var npmi = require("npmi");
|
||||
var npm = require("npm");
|
||||
var semver = require("semver");
|
||||
|
||||
var Plugin = require("./plugin");
|
||||
var pkg = require("../package.json");
|
||||
|
||||
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
|
||||
PluginsList.prototype.load = function(plugin, options) {
|
||||
PluginsList.prototype.load = function(plugin) {
|
||||
var that = this;
|
||||
|
||||
if (_.isArray(plugin)) {
|
||||
@@ -79,14 +79,10 @@ PluginsList.prototype.load = function(plugin, options) {
|
||||
}
|
||||
|
||||
// Extract filters
|
||||
_.each(plugin.getFilters(), function(filterFunc, filterName) {
|
||||
that.book.template.addFilter(filterName, filterFunc);
|
||||
});
|
||||
that.book.template.addFilters(plugin.getFilters());
|
||||
|
||||
// Extract blocks
|
||||
_.each(plugin.getBlocks(), function(block, blockName) {
|
||||
that.book.template.addBlock(blockName, block);
|
||||
});
|
||||
that.book.template.addBlocks(plugin.getBlocks());
|
||||
|
||||
return _.reduce(_.keys(that.namespaces), function(prev, namespaceName) {
|
||||
return prev.then(function() {
|
||||
@@ -107,7 +103,7 @@ PluginsList.prototype.load = function(plugin, options) {
|
||||
namespace.html[tag] = namespace.html[tag] || [];
|
||||
namespace.html[tag].push(value);
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
}, Q());
|
||||
};
|
||||
@@ -150,11 +146,10 @@ PluginsList.prototype.resources = function(namespace) {
|
||||
// Install plugins from a book
|
||||
PluginsList.prototype.install = function() {
|
||||
var that = this;
|
||||
var defaultsPlugins = _.pluck(that.book.options.defaultsPlugins)
|
||||
|
||||
// Remove defaults (no need to install)
|
||||
var plugins = _.filter(that.book.options.plugins, function(plugin) {
|
||||
return !_.contains(defaultsPlugins, plugin.name);
|
||||
var plugins = _.reject(that.book.options.plugins, {
|
||||
isDefault: true
|
||||
});
|
||||
|
||||
// Install plugins one by one
|
||||
@@ -180,8 +175,8 @@ PluginsList.prototype.install = function() {
|
||||
.map(function(v) {
|
||||
return {
|
||||
version: v[0],
|
||||
gitbook: (v[1].engines || {})["gitbook"]
|
||||
}
|
||||
gitbook: (v[1].engines || {}).gitbook
|
||||
};
|
||||
})
|
||||
.filter(function(v) {
|
||||
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);
|
||||
return Q.nfcall(npmi, {
|
||||
'name': fullname,
|
||||
'version': version,
|
||||
'path': that.book.root,
|
||||
'npmLoad': {
|
||||
'loglevel': 'silent',
|
||||
'loaded': true,
|
||||
'prefix': that.book.root
|
||||
"name": fullname,
|
||||
"version": version,
|
||||
"path": that.book.root,
|
||||
"npmLoad": {
|
||||
"loglevel": "silent",
|
||||
"loaded": true,
|
||||
"prefix": that.book.root
|
||||
}
|
||||
});
|
||||
})
|
||||
@@ -220,6 +215,4 @@ PluginsList.prototype.install = function() {
|
||||
}, Q());
|
||||
};
|
||||
|
||||
|
||||
|
||||
module.exports = PluginsList;
|
||||
|
||||
+127
-87
@@ -1,48 +1,18 @@
|
||||
var _ = require("lodash");
|
||||
var Q = require("q");
|
||||
var path = require("path");
|
||||
var nunjucks = require("nunjucks");
|
||||
var escapeStringRegexp = require("escape-string-regexp");
|
||||
|
||||
var git = require("./utils/git");
|
||||
var fs = require("./utils/fs");
|
||||
var batch = require("./utils/batch");
|
||||
var pkg = require("../package.json");
|
||||
var defaultBlocks = require("./blocks");
|
||||
var BookLoader = require("./conrefs_loader");
|
||||
|
||||
|
||||
// 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(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);
|
||||
}
|
||||
});
|
||||
// Normalize result from a block
|
||||
function normBlockResult(blk) {
|
||||
if (_.isString(blk)) blk = { body: blk };
|
||||
return blk;
|
||||
}
|
||||
|
||||
|
||||
var TemplateEngine = function(book) {
|
||||
@@ -58,12 +28,12 @@ var TemplateEngine = function(book) {
|
||||
|
||||
// Tags
|
||||
tags: {
|
||||
blockStart: '{%',
|
||||
blockEnd: '%}',
|
||||
variableStart: '{{',
|
||||
variableEnd: '}}',
|
||||
commentStart: '{###',
|
||||
commentEnd: '###}'
|
||||
blockStart: "{%",
|
||||
blockEnd: "%}",
|
||||
variableStart: "{{",
|
||||
variableEnd: "}}",
|
||||
commentStart: "{###",
|
||||
commentEnd: "###}"
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -71,49 +41,48 @@ var TemplateEngine = function(book) {
|
||||
// List of tags shortcuts
|
||||
this.shortcuts = [];
|
||||
|
||||
// Map of blocks
|
||||
// Map of blocks bodies (that requires post-processing)
|
||||
this.blockBodies = {};
|
||||
|
||||
// Map of added blocks
|
||||
this.blocks = {};
|
||||
|
||||
// Bind methods
|
||||
_.bindAll(this);
|
||||
|
||||
// Default block "html" that return html not parsed
|
||||
this.addBlock("html", {
|
||||
process: _.identity
|
||||
});
|
||||
// Add default blocks
|
||||
this.addBlocks(defaultBlocks);
|
||||
};
|
||||
|
||||
// Process a block in a context
|
||||
// Process the result of block in a context
|
||||
TemplateEngine.prototype.processBlock = function(blk) {
|
||||
if (_.isString(blk)) blk = { body: blk };
|
||||
|
||||
blk = _.defaults(blk, {
|
||||
parse: false,
|
||||
post: undefined
|
||||
});
|
||||
blk.id = _.uniqueId("blk");
|
||||
|
||||
var toAdd = (!blk.parse) || (blk.post != undefined);
|
||||
var toAdd = (!blk.parse) || (blk.post !== undefined);
|
||||
|
||||
// Add to global map
|
||||
if (toAdd) this.blocks[blk.id] = blk;
|
||||
if (toAdd) this.blockBodies[blk.id] = blk;
|
||||
|
||||
//Parsable block, just return it
|
||||
if (blk.parse) {
|
||||
return blk.body;
|
||||
}
|
||||
|
||||
// Return it as a macro
|
||||
return "%+%"+blk.id+"%+%";
|
||||
// Return it as a position marker
|
||||
return "@%@"+blk.id+"@%@";
|
||||
};
|
||||
|
||||
// Replace blocks by body after processing
|
||||
// This is done to avoid that markdown processer parse the block content
|
||||
// Replace position markers of blocks by body after processing
|
||||
// This is done to avoid that markdown/asciidoc processer parse the block content
|
||||
TemplateEngine.prototype.replaceBlocks = function(content) {
|
||||
var that = this;
|
||||
|
||||
return content.replace(/\%\+\%([\s\S]+?)\%\+\%/g, function(match, key) {
|
||||
var blk = that.blocks[key];
|
||||
return content.replace(/\@\%\@([\s\S]+?)\@\%\@/g, function(match, key) {
|
||||
var blk = that.blockBodies[key];
|
||||
if (!blk) return match;
|
||||
|
||||
var body = blk.body;
|
||||
@@ -141,11 +110,11 @@ TemplateEngine.prototype.bindContext = function(func) {
|
||||
TemplateEngine.prototype.addFilter = function(filterName, func) {
|
||||
try {
|
||||
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;
|
||||
} catch(e) {}
|
||||
|
||||
this.log.debug.ln("add filter '"+filterName+"'");
|
||||
this.log.debug.ln("add filter \""+filterName+"\"");
|
||||
this.env.addFilter(filterName, this.bindContext(function() {
|
||||
var ctx = this;
|
||||
var args = Array.prototype.slice.apply(arguments);
|
||||
@@ -160,9 +129,41 @@ TemplateEngine.prototype.addFilter = function(filterName, func) {
|
||||
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
|
||||
TemplateEngine.prototype.addBlock = function(name, block) {
|
||||
var that = this;
|
||||
var that = this, Ext, extName;
|
||||
|
||||
if (_.isFunction(block)) block = { process: block };
|
||||
|
||||
block = _.defaults(block || {}, {
|
||||
shortcuts: [],
|
||||
@@ -171,18 +172,22 @@ TemplateEngine.prototype.addBlock = function(name, block) {
|
||||
blocks: []
|
||||
});
|
||||
|
||||
var extName = 'Block'+name+'Extension';
|
||||
if (this.env.getExtension(extName)) {
|
||||
this.log.warn.ln("conflict in blocks, '"+name+"' is already defined");
|
||||
return false;
|
||||
extName = this.blockExtName(name);
|
||||
|
||||
if (this.hasBlock(name) && !defaultBlocks[name]) {
|
||||
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.parse = function(parser, nodes, lexer) {
|
||||
this.parse = function(parser, nodes) {
|
||||
var body = null;
|
||||
var lastBlockName = null;
|
||||
var lastBlockArgs = null;
|
||||
@@ -223,7 +228,7 @@ TemplateEngine.prototype.addBlock = function(name, block) {
|
||||
var bodies = [body];
|
||||
_.each(block.blocks, function(blockName) {
|
||||
subbodies[blockName] = subbodies[blockName] || [];
|
||||
if (subbodies[blockName].length == 0) {
|
||||
if (subbodies[blockName].length === 0) {
|
||||
subbodies[blockName].push({
|
||||
args: new nodes.NodeList(),
|
||||
body: new nodes.NodeList()
|
||||
@@ -233,7 +238,7 @@ TemplateEngine.prototype.addBlock = function(name, block) {
|
||||
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) {
|
||||
@@ -250,7 +255,7 @@ TemplateEngine.prototype.addBlock = function(name, block) {
|
||||
|
||||
// Extract main body and kwargs
|
||||
var body = args.pop();
|
||||
var kwargs = args.pop() || {};
|
||||
var kwargs = _.isObject(_.last(args))? args.pop() : {};
|
||||
|
||||
// Extract blocks body
|
||||
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()
|
||||
.then(function() {
|
||||
return func.call(context, {
|
||||
return that.applyBlock(name, {
|
||||
body: body(),
|
||||
args: args,
|
||||
kwargs: kwargs,
|
||||
blocks: _blocks
|
||||
});
|
||||
}, context);
|
||||
})
|
||||
|
||||
// process the block returned
|
||||
.then(that.processBlock)
|
||||
.nodeify(callback)
|
||||
.nodeify(callback);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// Add the Extension
|
||||
this.env.addExtension(extName, new Ext());
|
||||
|
||||
// Add shortcuts
|
||||
if (!_.isArray(block.shortcuts)) block.shortcuts = [block.shortcuts];
|
||||
_.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({
|
||||
block: name,
|
||||
parsers: shortcut.parsers,
|
||||
start: shortcut.start,
|
||||
end: shortcut.end,
|
||||
@@ -298,12 +301,46 @@ TemplateEngine.prototype.addBlock = function(name, block) {
|
||||
}, 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
|
||||
TemplateEngine.prototype._applyShortcut = function(parser, content, shortcut) {
|
||||
if (!_.contains(shortcut.parsers, parser)) return content;
|
||||
var regex = new RegExp(
|
||||
escapeStringRegexp(shortcut.start) + "([\\s\\S]*?[^\\$])" + escapeStringRegexp(shortcut.end),
|
||||
'g'
|
||||
"g"
|
||||
);
|
||||
return content.replace(regex, function(all, match) {
|
||||
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
|
||||
TemplateEngine.prototype.renderString = function(content, context, options) {
|
||||
var context = _.extend({}, context, {
|
||||
context = _.extend({}, context, {
|
||||
// Variables from book.json
|
||||
book: this.book.options.variables,
|
||||
|
||||
// Complete book.json
|
||||
config: this.book.options,
|
||||
|
||||
// infos about gitbook
|
||||
gitbook: {
|
||||
version: pkg.version,
|
||||
@@ -341,8 +381,8 @@ TemplateEngine.prototype.renderString = function(content, context, options) {
|
||||
};
|
||||
|
||||
// Render a file from the book
|
||||
TemplateEngine.prototype.renderFile = function(filename, options) {
|
||||
var that = this, context;
|
||||
TemplateEngine.prototype.renderFile = function(filename) {
|
||||
var that = this;
|
||||
|
||||
return that.book.readFile(filename)
|
||||
.then(function(content) {
|
||||
@@ -354,11 +394,11 @@ TemplateEngine.prototype.renderFile = function(filename, options) {
|
||||
|
||||
// Render a page from the book
|
||||
TemplateEngine.prototype.renderPage = function(page) {
|
||||
var that = this, context;
|
||||
var that = this;
|
||||
|
||||
return that.book.statFile(page.path)
|
||||
.then(function(stat) {
|
||||
context = {
|
||||
var context = {
|
||||
// infos about the file
|
||||
file: {
|
||||
path: page.path,
|
||||
@@ -380,7 +420,7 @@ TemplateEngine.prototype.postProcess = function(content) {
|
||||
return Q(content)
|
||||
.then(that.replaceBlocks)
|
||||
.then(function(_content) {
|
||||
return batch.execEach(that.blocks, {
|
||||
return batch.execEach(that.blockBodies, {
|
||||
max: 20,
|
||||
fn: function(blk, blkId) {
|
||||
return Q()
|
||||
@@ -389,7 +429,7 @@ TemplateEngine.prototype.postProcess = function(content) {
|
||||
return blk.post();
|
||||
})
|
||||
.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
|
||||
function execEach(items, options) {
|
||||
if (_.size(items) == 0) return Q();
|
||||
if (_.size(items) === 0) return Q();
|
||||
var concurrents = 0, d = Q.defer(), pending = [];
|
||||
|
||||
options = _.defaults(options || {}, {
|
||||
max: 100,
|
||||
fn: function(item) {}
|
||||
fn: function() {}
|
||||
});
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ function execEach(items, options) {
|
||||
// Next pending
|
||||
var next = pending.shift();
|
||||
|
||||
if (concurrents == 0 && !next) {
|
||||
if (concurrents === 0 && !next) {
|
||||
d.resolve();
|
||||
} else if (next) {
|
||||
startItem.apply(null, next);
|
||||
@@ -38,7 +38,7 @@ function execEach(items, options) {
|
||||
.fail(function(err) {
|
||||
pending = [];
|
||||
d.reject(err);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
_.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 = {
|
||||
tmp: {
|
||||
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() {
|
||||
return Q.nfcall(tmp.dir.bind(tmp)).get(0)
|
||||
return Q.nfcall(tmp.dir.bind(tmp)).get(0);
|
||||
}
|
||||
},
|
||||
list: listFiles,
|
||||
@@ -34,14 +34,14 @@ var fsUtils = {
|
||||
readFileSync: fs.readFileSync.bind(fs),
|
||||
clean: cleanFolder,
|
||||
getUniqueFilename: getUniqueFilename,
|
||||
}
|
||||
};
|
||||
|
||||
// Write a file
|
||||
function writeFile(filename, data, options) {
|
||||
var d = Q.defer();
|
||||
|
||||
try {
|
||||
fs.writeFileSync(filename, data, options)
|
||||
fs.writeFileSync(filename, data, options);
|
||||
} catch(err) {
|
||||
d.reject(err);
|
||||
}
|
||||
@@ -57,10 +57,14 @@ function writeStream(filename, st) {
|
||||
|
||||
var wstream = fs.createWriteStream(filename);
|
||||
|
||||
wstream.on('finish', function () {
|
||||
wstream.on("finish", function () {
|
||||
d.resolve();
|
||||
});
|
||||
wstream.on('error', function (err) {
|
||||
wstream.on("error", function (err) {
|
||||
d.reject(err);
|
||||
});
|
||||
|
||||
st.on("error", function(err) {
|
||||
d.reject(err);
|
||||
});
|
||||
|
||||
@@ -111,20 +115,20 @@ function listFiles(root, options) {
|
||||
});
|
||||
|
||||
// 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
|
||||
ig.on('child', function (c) {
|
||||
ig.on("child", function (c) {
|
||||
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
|
||||
if(process.platform === 'win32') {
|
||||
if(process.platform === "win32") {
|
||||
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);
|
||||
});
|
||||
|
||||
ig.on('error', d.reject);
|
||||
ig.on("error", d.reject);
|
||||
|
||||
return d.promise;
|
||||
}
|
||||
@@ -146,8 +150,8 @@ function cleanFolder(root) {
|
||||
ignoreFiles: [],
|
||||
ignoreRules: [
|
||||
// Skip Git and SVN stuff
|
||||
'.git/',
|
||||
'.svn/'
|
||||
".git/",
|
||||
".svn/"
|
||||
]
|
||||
})
|
||||
.then(function(files) {
|
||||
|
||||
+21
-6
@@ -1,11 +1,10 @@
|
||||
var Q = require("q");
|
||||
var _ = require("lodash");
|
||||
var url = require("url");
|
||||
var tmp = require("tmp");
|
||||
var path = require("path");
|
||||
var crc = require("crc");
|
||||
var exec = Q.denodeify(require("child_process").exec);
|
||||
var URI = require("URIjs");
|
||||
var pathUtil = require("./path");
|
||||
|
||||
var fs = require("./fs");
|
||||
|
||||
@@ -83,13 +82,12 @@ function cloneGitRepo(host, ref) {
|
||||
return exec("git clone "+host+" "+repoPath)
|
||||
.then(function() {
|
||||
return exec("git checkout "+ref, { cwd: repoPath });
|
||||
})
|
||||
});
|
||||
})
|
||||
.thenResolve(repoPath);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Get file from a git repo
|
||||
function resolveFileFromGit(giturl) {
|
||||
if (_.isString(giturl)) giturl = parseGitUrl(giturl);
|
||||
@@ -102,11 +100,28 @@ function resolveFileFromGit(giturl) {
|
||||
// Resolve relative path
|
||||
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 = {
|
||||
checkUrl: checkGitUrl,
|
||||
parseUrl: parseGitUrl,
|
||||
resolveFile: resolveFileFromGit
|
||||
resolveFile: resolveFileFromGit,
|
||||
resolveRoot: resolveGitRoot
|
||||
};
|
||||
|
||||
+11
-11
@@ -4,7 +4,7 @@ var fs = require("fs");
|
||||
|
||||
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 LOCALES = _.map(fs.readdirSync(I18N_PATH), function(lang) {
|
||||
return path.basename(lang, ".json");
|
||||
@@ -17,7 +17,7 @@ i18n.configure({
|
||||
updateFiles: false
|
||||
});
|
||||
|
||||
var compareLocales = function(lang, locale) {
|
||||
function compareLocales(lang, locale) {
|
||||
var langMain = _.first(lang.split("-"));
|
||||
var langSecond = _.last(lang.split("-"));
|
||||
|
||||
@@ -28,7 +28,7 @@ var compareLocales = function(lang, locale) {
|
||||
if (localeMain == langMain) return 50;
|
||||
if (localeSecond == langSecond) return 20;
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
|
||||
var normalizeLanguage = _.memoize(function(lang) {
|
||||
var language = _.chain(LOCALES)
|
||||
@@ -37,7 +37,7 @@ var normalizeLanguage = _.memoize(function(lang) {
|
||||
return {
|
||||
locale: locale,
|
||||
score: compareLocales(lang, locale)
|
||||
}
|
||||
};
|
||||
})
|
||||
.filter(function(lang) {
|
||||
return lang.score > 0;
|
||||
@@ -49,25 +49,25 @@ var normalizeLanguage = _.memoize(function(lang) {
|
||||
return language || lang;
|
||||
});
|
||||
|
||||
var translate = function(locale, phrase) {
|
||||
function translate(locale, phrase) {
|
||||
var args = Array.prototype.slice.call(arguments, 2);
|
||||
|
||||
return i18n.__.apply({}, [{
|
||||
locale: locale,
|
||||
phrase: phrase
|
||||
}].concat(args));
|
||||
};
|
||||
}
|
||||
|
||||
var getCatalog = function(locale) {
|
||||
function getCatalog(locale) {
|
||||
locale = normalizeLanguage(locale);
|
||||
return i18n.getCatalog(locale);
|
||||
};
|
||||
}
|
||||
|
||||
var getLocales = function() {
|
||||
function getLocales() {
|
||||
return LOCALES;
|
||||
};
|
||||
}
|
||||
|
||||
var hasLocale = function(locale) {
|
||||
function hasLocale(locale) {
|
||||
return _.contains(LOCALES, locale);
|
||||
}
|
||||
|
||||
|
||||
+5
-7
@@ -1,9 +1,7 @@
|
||||
var _ = require("lodash");
|
||||
var Q = require("q");
|
||||
var fs = require("./fs");
|
||||
var spawn = require('spawn-cmd').spawn;
|
||||
|
||||
var links = require("./links");
|
||||
var spawn = require("spawn-cmd").spawn;
|
||||
|
||||
// Convert a svg file
|
||||
var convertSVG = function(source, dest, options) {
|
||||
@@ -14,16 +12,16 @@ var convertSVG = function(source, dest, options) {
|
||||
|
||||
});
|
||||
|
||||
//var command = shellescape(['svgexport', source, dest]);
|
||||
var child = spawn('svgexport', [source, dest]);
|
||||
//var command = shellescape(["svgexport", source, dest]);
|
||||
var child = spawn("svgexport", [source, dest]);
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
child.on("close", function(code) {
|
||||
if (code == 0 && fs.existsSync(dest)) {
|
||||
if (code === 0 && fs.existsSync(dest)) {
|
||||
d.resolve();
|
||||
} else {
|
||||
d.reject(new Error("Error converting "+source+" into "+dest));
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
var url = require('url');
|
||||
var path = require('path');
|
||||
var url = require("url");
|
||||
var path = require("path");
|
||||
|
||||
// Is the link an external link
|
||||
var isExternal = function(href) {
|
||||
@@ -33,7 +33,7 @@ var isAnchor = function(href) {
|
||||
|
||||
// Normalize a path to be a link
|
||||
var normalizeLink = function(s) {
|
||||
return s.replace(/\\/g, '/');
|
||||
return s.replace(/\\/g, "/");
|
||||
};
|
||||
|
||||
// Relative to absolute path
|
||||
@@ -43,7 +43,7 @@ var normalizeLink = function(s) {
|
||||
var toAbsolute = function(_href, dir, outdir) {
|
||||
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));
|
||||
if (_href[0] == "/") hrefInRoot = path.normalize(_href.slice(1));
|
||||
|
||||
|
||||
+9
-9
@@ -1,6 +1,6 @@
|
||||
var _ = require('lodash');
|
||||
var util = require('util');
|
||||
var color = require('bash-color');
|
||||
var _ = require("lodash");
|
||||
var util = require("util");
|
||||
var color = require("bash-color");
|
||||
|
||||
var LEVELS = {
|
||||
DEBUG: 0,
|
||||
@@ -19,7 +19,7 @@ var COLORS = {
|
||||
|
||||
module.exports = function(_write, logLevel) {
|
||||
var logger = {};
|
||||
var lastChar = '\n';
|
||||
var lastChar = "\n";
|
||||
if (_.isString(logLevel)) logLevel = LEVELS[logLevel.toUpperCase()];
|
||||
|
||||
// Write a simple message
|
||||
@@ -47,14 +47,14 @@ module.exports = function(_write, logLevel) {
|
||||
var args = Array.prototype.slice.apply(arguments, [1]);
|
||||
var msg = logger.format.apply(logger, args);
|
||||
|
||||
if (lastChar == '\n') {
|
||||
if (lastChar == "\n") {
|
||||
msg = COLORS[levelKey](levelKey.toLowerCase()+":")+" "+msg;
|
||||
}
|
||||
|
||||
return logger.write(msg);
|
||||
};
|
||||
logger.logLn = function() {
|
||||
if (lastChar != '\n') logger.write("\n");
|
||||
if (lastChar != "\n") logger.write("\n");
|
||||
|
||||
var args = Array.prototype.slice.apply(arguments);
|
||||
args.push("\n");
|
||||
@@ -66,7 +66,7 @@ module.exports = function(_write, logLevel) {
|
||||
var args = Array.prototype.slice.apply(arguments, [1]);
|
||||
var msg = logger.format.apply(logger, args);
|
||||
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 {
|
||||
logger.log(level, color.green("OK"), "\n");
|
||||
}
|
||||
@@ -77,7 +77,7 @@ module.exports = function(_write, logLevel) {
|
||||
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();
|
||||
|
||||
logger[levelKey] = _.partial(logger.log, level);
|
||||
@@ -93,7 +93,7 @@ module.exports = function(_write, logLevel) {
|
||||
logger[levelKey].fail();
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
return logger;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
var _ = require('lodash');
|
||||
var _ = require("lodash");
|
||||
|
||||
// Cleans up an article/chapter object
|
||||
// remove 'articles' attributes
|
||||
// remove "articles" attributes
|
||||
function clean(obj) {
|
||||
return obj && _.omit(obj, ['articles']);
|
||||
return obj && _.omit(obj, ["articles"]);
|
||||
}
|
||||
|
||||
function flattenChapters(chapters) {
|
||||
@@ -27,7 +27,7 @@ function navigation(summary, files) {
|
||||
files = _.isArray(files) ? files : (_.isString(files) ? [files] : null);
|
||||
|
||||
// List of all navNodes
|
||||
// Flatten chapters, then add in default README node if needed etc ...
|
||||
// Flatten chapters
|
||||
var navNodes = flattenChapters(summary.chapters);
|
||||
|
||||
// Mapping of prev/next for a give path
|
||||
@@ -39,8 +39,7 @@ function navigation(summary, files) {
|
||||
if(!current.exists) return null;
|
||||
|
||||
// Find prev
|
||||
prev = _.chain(navNodes)
|
||||
.slice(0, i)
|
||||
prev = _.chain(navNodes.slice(0, i))
|
||||
.reverse()
|
||||
.find(function(node) {
|
||||
return node.exists && !node.external;
|
||||
@@ -48,14 +47,12 @@ function navigation(summary, files) {
|
||||
.value();
|
||||
|
||||
// Find next
|
||||
next = _.chain(navNodes)
|
||||
.slice(i+1)
|
||||
next = _.chain(navNodes.slice(i+1))
|
||||
.find(function(node) {
|
||||
return node.exists && !node.external;
|
||||
})
|
||||
.value();
|
||||
|
||||
|
||||
return [current.path, {
|
||||
index: i,
|
||||
title: current.title,
|
||||
|
||||
+65
-40
@@ -1,17 +1,18 @@
|
||||
var Q = require('q');
|
||||
var _ = require('lodash');
|
||||
var url = require('url');
|
||||
var path = require('path');
|
||||
var cheerio = require('cheerio');
|
||||
var domSerializer = require('dom-serializer');
|
||||
var request = require('request');
|
||||
var Q = require("q");
|
||||
var _ = require("lodash");
|
||||
var url = require("url");
|
||||
var path = require("path");
|
||||
var cheerio = require("cheerio");
|
||||
var domSerializer = require("dom-serializer");
|
||||
var request = require("request");
|
||||
var crc = require("crc");
|
||||
|
||||
var links = require('./links');
|
||||
var imgUtils = require('./images');
|
||||
var fs = require('./fs');
|
||||
var batch = require('./batch');
|
||||
var code = require('./code');
|
||||
var links = require("./links");
|
||||
var imgUtils = require("./images");
|
||||
var fs = require("./fs");
|
||||
var batch = require("./batch");
|
||||
|
||||
var parsableExtensions = require("gitbook-parsers").extensions;
|
||||
|
||||
// Render a cheerio dom as html
|
||||
var renderDom = function($, dom, options) {
|
||||
@@ -39,7 +40,8 @@ function replaceText($, el, search, replace, text_only ) {
|
||||
if ( node ) {
|
||||
|
||||
// Loop over all childNodes.
|
||||
do {
|
||||
while (node) {
|
||||
|
||||
// Only process text nodes.
|
||||
if ( node.nodeType === 3 ) {
|
||||
|
||||
@@ -57,7 +59,7 @@ function replaceText($, el, search, replace, text_only ) {
|
||||
// robust way.
|
||||
$(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 );
|
||||
} else {
|
||||
// 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!
|
||||
remove.length && $(remove).remove();
|
||||
if (remove.length) $(remove).remove();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function pregQuote( str ) {
|
||||
return (str+'').replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, "\\$1");
|
||||
};
|
||||
return (str+"").replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, "\\$1");
|
||||
}
|
||||
|
||||
|
||||
// Adapt an html snippet to be relative to a base folder
|
||||
@@ -106,15 +109,16 @@ function normalizeHtml(src, options) {
|
||||
// Generate filename
|
||||
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));
|
||||
});
|
||||
}
|
||||
|
||||
// Find images to normalize
|
||||
$("img").each(function() {
|
||||
var origin = undefined;
|
||||
var origin;
|
||||
var src = $(this).attr("src");
|
||||
|
||||
if (!src) return;
|
||||
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 = 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);
|
||||
|
||||
options.book.log.debug.ln("detect invalid image (will be converted to png):", srcAbs);
|
||||
@@ -196,11 +200,19 @@ function normalizeHtml(src, options) {
|
||||
var absolutePath = links.join(options.base, parts.pathname);
|
||||
var anchor = parts.hash || "";
|
||||
|
||||
|
||||
// If is in navigation relative: transform as content
|
||||
if (options.navigation[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
|
||||
href = links.toAbsolute("/"+absolutePath, options.base, options.output)+anchor;
|
||||
} else {
|
||||
@@ -214,34 +226,42 @@ function normalizeHtml(src, options) {
|
||||
|
||||
// Highlight code blocks
|
||||
$("code").each(function() {
|
||||
// Extract language
|
||||
// Normalize language
|
||||
var lang = _.chain(
|
||||
($(this).attr("class") || "").split(" ")
|
||||
)
|
||||
.map(function(cl) {
|
||||
// Markdown
|
||||
if (cl.search("lang-") === 0) return cl.slice("lang-".length);
|
||||
|
||||
// Asciidoc
|
||||
if (cl.search("language-") === 0) return cl.slice("language-".length);
|
||||
|
||||
return null;
|
||||
})
|
||||
.compact()
|
||||
.first()
|
||||
.value();
|
||||
|
||||
if (lang) {
|
||||
var html = code.highlight(
|
||||
lang,
|
||||
$(this).text()
|
||||
);
|
||||
var source = $(this).text();
|
||||
var blk = options.book.template.applyBlock("code", {
|
||||
body: source,
|
||||
kwargs: {
|
||||
language: lang
|
||||
}
|
||||
});
|
||||
|
||||
$(this).html(html);
|
||||
}
|
||||
if (blk.html === false) $(this).text(blk.body);
|
||||
else $(this).html(blk.body);
|
||||
});
|
||||
|
||||
// Replace glossary terms
|
||||
var glossary = _.sortBy(options.glossary, function(term) {
|
||||
return -term.name.length;
|
||||
});
|
||||
|
||||
_.each(glossary, function(term) {
|
||||
var r = new RegExp( "\\b(" + pregQuote(term.name.toLowerCase()) + ")\\b" , 'gi' );
|
||||
var r = new RegExp( "\\b(" + pregQuote(term.name.toLowerCase()) + ")\\b" , "gi" );
|
||||
var includedInFiles = false;
|
||||
|
||||
$("*").each(function() {
|
||||
@@ -255,7 +275,7 @@ function normalizeHtml(src, options) {
|
||||
term.files = term.files || [];
|
||||
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>";
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -264,7 +284,7 @@ function normalizeHtml(src, options) {
|
||||
html: renderDom($),
|
||||
images: toConvert
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// Convert svg images to png
|
||||
function convertImages(images, options) {
|
||||
@@ -285,7 +305,13 @@ function convertImages(images, options) {
|
||||
if (!image.origin && !_.contains(downloaded, image.origin)) return;
|
||||
options.book.log.debug("download image", 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
|
||||
@@ -306,8 +332,7 @@ function convertImages(images, options) {
|
||||
.then(function() {
|
||||
options.book.log.debug.ok(images.length+" images converted with success");
|
||||
});
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// Adapt page content to be relative to a base folder
|
||||
function normalizePage(sections, options) {
|
||||
@@ -340,7 +365,7 @@ function normalizePage(sections, options) {
|
||||
sections = _.map(sections, function(section) {
|
||||
if (section.type != "normal") return section;
|
||||
|
||||
var out = normalizeHtml(section.content, options);;
|
||||
var out = normalizeHtml(section.content, options);
|
||||
|
||||
toConvert = toConvert.concat(out.images);
|
||||
section.content = out.html;
|
||||
@@ -349,11 +374,11 @@ function normalizePage(sections, options) {
|
||||
|
||||
return Q()
|
||||
.then(function() {
|
||||
toConvert = _.uniq(toConvert, 'source');
|
||||
toConvert = _.uniq(toConvert, "source");
|
||||
return convertImages(toConvert, options);
|
||||
})
|
||||
.thenResolve(sections);
|
||||
};
|
||||
}
|
||||
|
||||
// Extract text from sections
|
||||
function extractText(sections) {
|
||||
@@ -367,7 +392,7 @@ function extractText(sections) {
|
||||
|
||||
return prev;
|
||||
}, "");
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
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");
|
||||
|
||||
// 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 percent = 0, prevPercent = 0, currentChapter = null;
|
||||
var done = true;
|
||||
|
||||
+15
-17
@@ -1,11 +1,9 @@
|
||||
var Q = require('q');
|
||||
var _ = require('lodash');
|
||||
|
||||
var events = require('events');
|
||||
var http = require('http');
|
||||
var send = require('send');
|
||||
var util = require('util');
|
||||
var url = require('url');
|
||||
var Q = require("q");
|
||||
var events = require("events");
|
||||
var http = require("http");
|
||||
var send = require("send");
|
||||
var util = require("util");
|
||||
var url = require("url");
|
||||
|
||||
var Server = function() {
|
||||
this.running = null;
|
||||
@@ -17,7 +15,7 @@ util.inherits(Server, events.EventEmitter);
|
||||
|
||||
// Return true if the server is running
|
||||
Server.prototype.isRunning = function() {
|
||||
return this.running != null;
|
||||
return !!this.running;
|
||||
};
|
||||
|
||||
// Stop the server
|
||||
@@ -57,25 +55,25 @@ Server.prototype.start = function(dir, port) {
|
||||
res.end(err.message);
|
||||
}
|
||||
|
||||
// Redirect to directory's index.html
|
||||
// Redirect to directory"s index.html
|
||||
function redirect() {
|
||||
res.statusCode = 301;
|
||||
res.setHeader('Location', req.url + '/');
|
||||
res.end('Redirecting to ' + req.url + '/');
|
||||
res.setHeader("Location", req.url + "/");
|
||||
res.end("Redirecting to " + req.url + "/");
|
||||
}
|
||||
|
||||
// Send file
|
||||
send(req, url.parse(req.url).pathname)
|
||||
.root(dir)
|
||||
.on('error', error)
|
||||
.on('directory', redirect)
|
||||
.on("error", error)
|
||||
.on("directory", redirect)
|
||||
.pipe(res);
|
||||
});
|
||||
|
||||
that.running.on('connection', function (socket) {
|
||||
that.running.on("connection", function (socket) {
|
||||
that.sockets.push(socket);
|
||||
socket.setTimeout(4000);
|
||||
socket.on('close', function () {
|
||||
socket.on("close", function () {
|
||||
that.sockets.splice(that.sockets.indexOf(socket), 1);
|
||||
});
|
||||
});
|
||||
@@ -91,6 +89,6 @@ Server.prototype.start = function(dir, port) {
|
||||
|
||||
return d.promise;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Server;
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
var _ = require("lodash");
|
||||
|
||||
function escapeShellArg(arg) {
|
||||
var ret = '';
|
||||
var ret = "";
|
||||
|
||||
ret = arg.replace(/"/g, '\\"');
|
||||
|
||||
@@ -11,7 +11,7 @@ function escapeShellArg(arg) {
|
||||
function optionsToShellArgs(options) {
|
||||
return _.chain(options)
|
||||
.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;
|
||||
return key+"="+escapeShellArg(value);
|
||||
})
|
||||
|
||||
+6
-5
@@ -1,9 +1,9 @@
|
||||
var Q = require('q');
|
||||
var _ = require('lodash');
|
||||
var path = require('path');
|
||||
var chokidar = require('chokidar');
|
||||
var Q = require("q");
|
||||
var _ = require("lodash");
|
||||
var path = require("path");
|
||||
var chokidar = require("chokidar");
|
||||
|
||||
var parsers = require('gitbook-parsers')
|
||||
var parsers = require("gitbook-parsers");
|
||||
|
||||
function watch(dir) {
|
||||
var d = Q.defer();
|
||||
@@ -19,6 +19,7 @@ function watch(dir) {
|
||||
|
||||
var watcher = chokidar.watch(toWatch, {
|
||||
cwd: dir,
|
||||
ignored: "_book/**",
|
||||
ignoreInitial: true
|
||||
});
|
||||
|
||||
|
||||
+10
-10
@@ -1,27 +1,28 @@
|
||||
{
|
||||
"name": "gitbook",
|
||||
"version": "2.0.4",
|
||||
"version": "2.4.2",
|
||||
"homepage": "https://www.gitbook.com",
|
||||
"description": "Library and cmd utility to generate GitBooks",
|
||||
"main": "lib/index.js",
|
||||
"dependencies": {
|
||||
"q": "1.0.1",
|
||||
"lunr": "0.5.7",
|
||||
"lodash": "3.5.0",
|
||||
"lunr": "0.5.12",
|
||||
"lodash": "3.10.1",
|
||||
"graceful-fs": "3.0.5",
|
||||
"resolve": "0.6.3",
|
||||
"fs-extra": "0.16.5",
|
||||
"fstream-ignore": "1.0.2",
|
||||
"gitbook-parsers": "0.7.5",
|
||||
"nunjucks": "mozilla/nunjucks#103513c294835bcbe64222de6db494e2555e294e",
|
||||
"gitbook-parsers": "0.8.2",
|
||||
"gitbook-plugin-highlight": "1.0.3",
|
||||
"nunjucks": "mozilla/nunjucks#dc89bf91611a2101731c2c06afcf5c32160b4dc9",
|
||||
"nunjucks-autoescape": "1.0.0",
|
||||
"nunjucks-filter": "1.0.0",
|
||||
"i18n": "0.5.0",
|
||||
"semver": "2.2.1",
|
||||
"semver": "5.0.1",
|
||||
"npmi": "0.1.1",
|
||||
"cheerio": "0.19.0",
|
||||
"gitbook-plugin-livereload": "0.0.1",
|
||||
"chokidar": "~1.0.1",
|
||||
"chokidar": "~1.0.5",
|
||||
"send": "0.2.0",
|
||||
"tiny-lr": "0.1.5",
|
||||
"tmp": "0.0.24",
|
||||
@@ -32,12 +33,11 @@
|
||||
"npm": "2.4.1",
|
||||
"dom-serializer": "0.1.0",
|
||||
"spawn-cmd": "0.0.2",
|
||||
"highlight.js": "8.4.0",
|
||||
"escape-string-regexp": "1.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mocha": "2.2.1",
|
||||
"should": "5.2.0",
|
||||
"mocha": "2.3.2",
|
||||
"should": "7.1.0",
|
||||
"grunt": "~0.4.2",
|
||||
"grunt-cli": "0.1.11",
|
||||
"grunt-contrib-copy": "0.5.0",
|
||||
|
||||
+30
-17
@@ -1,41 +1,54 @@
|
||||
var _ = require('lodash');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var should = require('should');
|
||||
var cheerio = require('cheerio');
|
||||
var _ = require("lodash");
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
var should = require("should");
|
||||
var cheerio = require("cheerio");
|
||||
|
||||
should.Assertion.add('file', function(file, description) {
|
||||
this.params = { actual: this.obj.toString(), operator: 'have file ' + file, message: description };
|
||||
should.Assertion.add("file", function(file, 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.options.should.have.property('output').which.is.a.String;
|
||||
this.obj.should.have.property("options").which.is.an.Object();
|
||||
this.obj.options.should.have.property("output").which.is.a.String();
|
||||
this.assert(fs.existsSync(path.resolve(this.obj.options.output, file)));
|
||||
});
|
||||
|
||||
should.Assertion.add('jsonfile', function(file, description) {
|
||||
this.params = { actual: this.obj.toString(), operator: 'have valid jsonfile ' + file, message: description };
|
||||
should.Assertion.add("jsonfile", function(file, 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.options.should.have.property('output').which.is.a.String;
|
||||
this.obj.should.have.property("options").which.is.an.Object();
|
||||
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" })));
|
||||
});
|
||||
|
||||
should.Assertion.add('html', function(rules, description) {
|
||||
this.params = { actual: "HTML string", operator: 'valid html', message: description };
|
||||
should.Assertion.add("html", function(rules, description) {
|
||||
this.params = { actual: "HTML string", operator: "valid html", message: description };
|
||||
var $ = cheerio.load(this.obj);
|
||||
|
||||
_.each(rules, function(validations, query) {
|
||||
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,
|
||||
|
||||
// Check attribute values
|
||||
attributes: {},
|
||||
|
||||
// Trim inner text
|
||||
trim: false,
|
||||
|
||||
// Check inner text
|
||||
text: undefined
|
||||
});
|
||||
|
||||
var $el = $(query);
|
||||
|
||||
// Select correct element
|
||||
if (_.isNumber(validations.index)) $el = $($el.get(validations.index));
|
||||
|
||||
// Test number of elements
|
||||
$el.should.have.lengthOf(validations.count);
|
||||
$el.length.should.be.equal(validations.count);
|
||||
|
||||
// Test text
|
||||
if (validations.text !== undefined) {
|
||||
@@ -47,7 +60,7 @@ should.Assertion.add('html', function(rules, description) {
|
||||
// Test attributes
|
||||
_.each(validations.attributes, function(value, name) {
|
||||
var attr = $el.attr(name);
|
||||
should(attr).be.ok;
|
||||
should(attr).be.ok();
|
||||
attr.should.be.equal(value);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
### Relative
|
||||
|
||||
<p id="t1">{% include "./hello.md" %}</p>
|
||||
<p id="t2">{% include "/hello.md" %}</p>
|
||||
|
||||
### 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/test2.md" %}</p>
|
||||
<p id="t3">{% include "git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test.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>
|
||||
|
||||
@@ -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
|
||||
@@ -4,3 +4,6 @@
|
||||
* [Hello 2](hello2.md)
|
||||
* Hello 3
|
||||
* [Hello 4](hello3/hello4.md)
|
||||
* Hello 5
|
||||
* [Hello 6](hello3/hello5/hello6.md)
|
||||
|
||||
|
||||
@@ -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');
|
||||
var path = require('path');
|
||||
|
||||
describe('Configuration', function () {
|
||||
it('should extract default title from README', function() {
|
||||
describe("Configuration", function () {
|
||||
it("should extract default title from README", function() {
|
||||
return books.parse("basic")
|
||||
.then(function(book) {
|
||||
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")
|
||||
.then(function(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")
|
||||
.then(function(book) {
|
||||
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")
|
||||
.then(function(book) {
|
||||
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 path = require('path');
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
|
||||
describe('ConRefs', function () {
|
||||
describe("ConRefs", function () {
|
||||
var book, readme;
|
||||
|
||||
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({
|
||||
".page-inner p#t1": {
|
||||
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({
|
||||
".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,
|
||||
text: "Hello from git",
|
||||
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,
|
||||
text: "First Hello. Hello from git",
|
||||
trim: true
|
||||
|
||||
+48
-6
@@ -1,8 +1,8 @@
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
|
||||
describe('eBook generator', function () {
|
||||
describe('Basic Book', function() {
|
||||
describe("eBook generator", function () {
|
||||
describe("Basic Book", function() {
|
||||
var book;
|
||||
|
||||
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");
|
||||
});
|
||||
|
||||
it('should correctly copy assets', function() {
|
||||
it("should correctly copy assets", function() {
|
||||
book.should.have.file("gitbook");
|
||||
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 git = require('../lib/utils/git');
|
||||
var should = require("should");
|
||||
var git = require("../lib/utils/git");
|
||||
|
||||
describe('GIT parser and getter', function () {
|
||||
it('should correctly parse an https url', function() {
|
||||
describe("GIT parser and getter", function () {
|
||||
it("should correctly parse an https url", function() {
|
||||
var parts = git.parseUrl("git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test.md");
|
||||
|
||||
should.exist(parts);
|
||||
@@ -11,7 +11,7 @@ describe('GIT parser and getter', function () {
|
||||
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");
|
||||
|
||||
should.exist(parts);
|
||||
@@ -20,7 +20,7 @@ describe('GIT parser and getter', function () {
|
||||
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");
|
||||
|
||||
should.exist(parts);
|
||||
|
||||
+15
-15
@@ -1,8 +1,8 @@
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
|
||||
describe('Glossary', function () {
|
||||
describe('Parsing', function() {
|
||||
describe("Glossary", function () {
|
||||
describe("Parsing", function() {
|
||||
var book;
|
||||
|
||||
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.glossary.should.have.lengthOf(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Generation', function() {
|
||||
describe("Generation", function() {
|
||||
var book;
|
||||
|
||||
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");
|
||||
});
|
||||
|
||||
describe('Page Integration', function() {
|
||||
describe("Page Integration", function() {
|
||||
var readme, page;
|
||||
|
||||
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({
|
||||
".page-inner a[href='GLOSSARY.html#test']": {
|
||||
".page-inner a[href=\"GLOSSARY.html#test\"]": {
|
||||
count: 1,
|
||||
text: "test",
|
||||
attributes: {
|
||||
@@ -58,15 +58,15 @@ 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-inner a[href='../GLOSSARY.html#test']": {
|
||||
".page-inner a[href=\"../GLOSSARY.html#test\"]": {
|
||||
count: 1
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should not replace terms in codeblocks', function() {
|
||||
it("should not replace terms in codeblocks", function() {
|
||||
readme.should.be.html({
|
||||
".page-inner code a": {
|
||||
count: 0
|
||||
@@ -74,9 +74,9 @@ describe('Glossary', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('should correctly select the longest term', function() {
|
||||
it("should correctly select the longest term", function() {
|
||||
readme.should.be.html({
|
||||
".page-inner a[href='GLOSSARY.html#test_long']": {
|
||||
".page-inner a[href=\"GLOSSARY.html#test_long\"]": {
|
||||
count: 1,
|
||||
text: "test long"
|
||||
}
|
||||
|
||||
+19
-15
@@ -1,13 +1,11 @@
|
||||
var os = require('os');
|
||||
var path = require('path');
|
||||
var Q = require('q');
|
||||
var fs = require('fs');
|
||||
var _ = require('lodash');
|
||||
var should = require('should');
|
||||
var os = require("os");
|
||||
var path = require("path");
|
||||
var Q = require("q");
|
||||
var _ = require("lodash");
|
||||
|
||||
var fsUtil = require('../lib/utils/fs');
|
||||
var Book = require('../').Book;
|
||||
var LOG_LEVELS = require('../').LOG_LEVELS;
|
||||
var fsUtil = require("../lib/utils/fs");
|
||||
var Book = require("../").Book;
|
||||
var LOG_LEVELS = require("../").LOG_LEVELS;
|
||||
|
||||
require("./assertions");
|
||||
|
||||
@@ -17,10 +15,18 @@ var TMPDIR = os.tmpdir();
|
||||
|
||||
|
||||
// Generate and return a book
|
||||
function generateBook(bookId, test) {
|
||||
function generateBook(bookId, test, opts) {
|
||||
opts = _.defaults(opts || {}, {
|
||||
prepare: function() {}
|
||||
});
|
||||
|
||||
return parseBook(bookId, test)
|
||||
.then(function(book) {
|
||||
return book.generate(test)
|
||||
|
||||
return Q(opts.prepare(book))
|
||||
.then(function() {
|
||||
return book.generate(test);
|
||||
})
|
||||
.thenResolve(book);
|
||||
});
|
||||
}
|
||||
@@ -53,16 +59,14 @@ global.books = {
|
||||
// Cleanup all tests
|
||||
after(function() {
|
||||
return _.chain(BOOKS)
|
||||
.map(function(types, bookId) {
|
||||
.map(function(types) {
|
||||
return _.values(types);
|
||||
})
|
||||
.flatten()
|
||||
.reduce(function(prev, book) {
|
||||
return prev.then(function() {
|
||||
return fsUtil.remove(book.options.output);
|
||||
})
|
||||
});
|
||||
}, Q())
|
||||
.value();
|
||||
});
|
||||
|
||||
|
||||
|
||||
+14
-12
@@ -1,9 +1,9 @@
|
||||
var fs = require('fs');
|
||||
var _ = require('lodash');
|
||||
var path = require('path');
|
||||
var cheerio = require('cheerio');
|
||||
var fs = require("fs");
|
||||
var _ = require("lodash");
|
||||
var path = require("path");
|
||||
var cheerio = require("cheerio");
|
||||
|
||||
describe('Images', function () {
|
||||
describe("Images", function () {
|
||||
var book, readme, $, $img, srcs;
|
||||
|
||||
before(function() {
|
||||
@@ -17,38 +17,40 @@ describe('Images', function () {
|
||||
);
|
||||
$ = cheerio.load(readme);
|
||||
$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);
|
||||
});
|
||||
|
||||
it('should keep image tags', function() {
|
||||
it("should keep image tags", function() {
|
||||
srcs.should.have.lengthOf(5);
|
||||
});
|
||||
|
||||
it('should not have .svg files', function() {
|
||||
it("should not have .svg files", function() {
|
||||
_.each(srcs, function(src) {
|
||||
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) {
|
||||
book.should.have.file(src);
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle relative paths', function() {
|
||||
it("should handle relative paths", function() {
|
||||
var PAGE = fs.readFileSync(
|
||||
path.join(book.options.output, "folder/PAGE.html"),
|
||||
{ encoding: "utf-8" }
|
||||
);
|
||||
|
||||
PAGE.should.be.html({
|
||||
"img[src='../test.png']": {
|
||||
"img[src=\"../test.png\"]": {
|
||||
count: 1
|
||||
}
|
||||
});
|
||||
|
||||
+11
-10
@@ -1,11 +1,11 @@
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var should = require('should');
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
var should = require("should");
|
||||
|
||||
var Book = require('../').Book;
|
||||
var LOG_LEVELS = require('../').LOG_LEVELS;
|
||||
var Book = require("../").Book;
|
||||
var LOG_LEVELS = require("../").LOG_LEVELS;
|
||||
|
||||
describe('Init Books', function () {
|
||||
describe("Init Books", function () {
|
||||
var initRoot;
|
||||
|
||||
before(function() {
|
||||
@@ -15,9 +15,10 @@ describe('Init Books', function () {
|
||||
});
|
||||
});
|
||||
|
||||
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;
|
||||
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 path = require('path');
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
|
||||
describe('JSON generator', function () {
|
||||
describe('Basic Book', function() {
|
||||
describe("JSON generator", function () {
|
||||
describe("Basic Book", function() {
|
||||
var book;
|
||||
|
||||
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");
|
||||
});
|
||||
|
||||
it('should output a valid json', function() {
|
||||
it("should output a valid json", function() {
|
||||
book.should.have.jsonfile("README.json");
|
||||
});
|
||||
|
||||
describe('Page Format', function() {
|
||||
describe("Page Format", function() {
|
||||
var page;
|
||||
|
||||
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.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("content").which.is.a.String();
|
||||
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.progress.should.have.property("chapters").with.lengthOf(1);
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Multilingual Book', function() {
|
||||
describe("Multilingual Book", function() {
|
||||
var book;
|
||||
|
||||
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("en/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("en/README.json");
|
||||
book.should.have.jsonfile("fr/README.json");
|
||||
});
|
||||
|
||||
describe('Page Format', function() {
|
||||
describe("Page Format", function() {
|
||||
var page;
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
+5
-8
@@ -1,8 +1,5 @@
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
describe('Languages', function () {
|
||||
describe('Parsing', function() {
|
||||
describe("Languages", function () {
|
||||
describe("Parsing", function() {
|
||||
var book;
|
||||
|
||||
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.books.should.have.lengthOf(2);
|
||||
|
||||
@@ -21,7 +18,7 @@ describe('Languages', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Generation', function() {
|
||||
describe("Generation", function() {
|
||||
var book;
|
||||
|
||||
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("en/index.html");
|
||||
book.should.have.file("fr/index.html");
|
||||
|
||||
+14
-16
@@ -1,13 +1,11 @@
|
||||
var should = require('should');
|
||||
var fs = require('fs');
|
||||
var _ = require('lodash');
|
||||
var path = require('path');
|
||||
var cheerio = require('cheerio');
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
var cheerio = require("cheerio");
|
||||
|
||||
var links = require("../lib/utils/links");
|
||||
|
||||
describe('Links', function () {
|
||||
it('should correctly test external links', function() {
|
||||
describe("Links", function () {
|
||||
it("should correctly test external links", function() {
|
||||
links.isExternal("http://google.fr").should.be.exactly(true);
|
||||
links.isExternal("https://google.fr").should.be.exactly(true);
|
||||
links.isExternal("test.md").should.be.exactly(false);
|
||||
@@ -15,32 +13,32 @@ describe('Links', function () {
|
||||
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("https://google.fr#test").should.be.exactly(false);
|
||||
links.isAnchor("test.md#test").should.be.exactly(false);
|
||||
});
|
||||
|
||||
describe('toAbsolute', function() {
|
||||
it('should correctly transform as absolute', function() {
|
||||
describe("toAbsolute", function() {
|
||||
it("should correctly transform as absolute", function() {
|
||||
links.toAbsolute("http://google.fr").should.be.equal("http://google.fr");
|
||||
links.toAbsolute("test.md", "./", "./").should.be.equal("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");
|
||||
});
|
||||
|
||||
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", "test", "test").should.be.equal("../test.md");
|
||||
links.toAbsolute("/sub/test.md", "test", "test").should.be.equal("../sub/test.md");
|
||||
});
|
||||
});
|
||||
|
||||
describe('page', function() {
|
||||
describe("page", function() {
|
||||
var book;
|
||||
|
||||
before(function() {
|
||||
@@ -50,7 +48,7 @@ describe('Links', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('should correctly replace relative links', function() {
|
||||
it("should correctly replace relative links", function() {
|
||||
var readme = fs.readFileSync(
|
||||
path.join(book.options.output, "folder1/index.html"),
|
||||
{ encoding: "utf-8" }
|
||||
@@ -58,8 +56,8 @@ describe('Links', function () {
|
||||
var $ = cheerio.load(readme);
|
||||
var $a = $(".page-inner a");
|
||||
|
||||
$a.attr('href').should.be.exactly("../folder2/index.html");
|
||||
})
|
||||
$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 should = require('should');
|
||||
var path = require('path');
|
||||
var _ = require("lodash");
|
||||
var should = require("should");
|
||||
var path = require("path");
|
||||
|
||||
var Plugin = require('../lib/plugin');
|
||||
var PLUGINS_ROOT = path.resolve(__dirname, 'plugins');
|
||||
var Plugin = require("../lib/plugin");
|
||||
var parsers = require("gitbook-parsers");
|
||||
var PLUGINS_ROOT = path.resolve(__dirname, "plugins");
|
||||
|
||||
describe('Plugins', function () {
|
||||
describe("Plugins", function () {
|
||||
var book;
|
||||
|
||||
before(function() {
|
||||
@@ -15,7 +16,7 @@ describe('Plugins', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Invalid', function() {
|
||||
describe("Invalid", function() {
|
||||
var plugin;
|
||||
|
||||
before(function() {
|
||||
@@ -23,12 +24,12 @@ describe('Plugins', function () {
|
||||
plugin.load("./invalid", PLUGINS_ROOT);
|
||||
});
|
||||
|
||||
it('should be detected', function() {
|
||||
it("should be detected", function() {
|
||||
should(plugin.isValid()).be.exactly(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Empty', function() {
|
||||
describe("Empty", function() {
|
||||
var plugin;
|
||||
|
||||
before(function() {
|
||||
@@ -36,11 +37,11 @@ describe('Plugins', function () {
|
||||
plugin.load("./empty", PLUGINS_ROOT);
|
||||
});
|
||||
|
||||
it('should valid a plugin', function() {
|
||||
it("should valid a plugin", function() {
|
||||
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()
|
||||
.then(function(resources) {
|
||||
_.each(Plugin.RESOURCES, function(resName) {
|
||||
@@ -50,7 +51,7 @@ describe('Plugins', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Resources', function() {
|
||||
describe("Resources", function() {
|
||||
var plugin;
|
||||
|
||||
before(function() {
|
||||
@@ -60,40 +61,45 @@ describe('Plugins', function () {
|
||||
return book.plugins.load(plugin);
|
||||
});
|
||||
|
||||
it('should valid a plugin', function() {
|
||||
it("should valid a plugin", function() {
|
||||
should(plugin.isValid()).be.exactly(true);
|
||||
});
|
||||
|
||||
describe('Website', function() {
|
||||
it('should return a valid list of resources', function() {
|
||||
describe("Website", function() {
|
||||
it("should return a valid list of resources", function() {
|
||||
return plugin.getResources("website")
|
||||
.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");
|
||||
resources["js"].should.have.lengthOf(1);
|
||||
resources.js.should.have.lengthOf(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('eBook', function() {
|
||||
it('should return a valid list of resources', function() {
|
||||
describe("eBook", function() {
|
||||
it("should return a valid list of resources", function() {
|
||||
return plugin.getResources("ebook")
|
||||
.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");
|
||||
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;
|
||||
|
||||
before(function() {
|
||||
@@ -103,11 +109,11 @@ describe('Plugins', function () {
|
||||
return book.plugins.load(plugin);
|
||||
});
|
||||
|
||||
it('should valid a plugin', function() {
|
||||
it("should valid a plugin", function() {
|
||||
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();
|
||||
|
||||
_.size(filters).should.equal(2);
|
||||
@@ -115,22 +121,22 @@ describe('Plugins', function () {
|
||||
filters.should.have.property("helloCtx");
|
||||
});
|
||||
|
||||
it('should correctly extend template filters', function() {
|
||||
return book.template.renderString('{{ "World"|hello }}')
|
||||
it("should correctly extend template filters", function() {
|
||||
return book.template.renderString("{{ \"World\"|hello }}")
|
||||
.then(function(content) {
|
||||
content.should.equal("Hello World");
|
||||
});
|
||||
});
|
||||
|
||||
it('should correctly set book as context', function() {
|
||||
return book.template.renderString('{{ "root"|helloCtx }}')
|
||||
it("should correctly set book as context", function() {
|
||||
return book.template.renderString("{{ \"root\"|helloCtx }}")
|
||||
.then(function(content) {
|
||||
content.should.equal("root:"+book.root);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Blocks', function() {
|
||||
describe("Blocks", function() {
|
||||
var plugin;
|
||||
|
||||
before(function() {
|
||||
@@ -142,22 +148,22 @@ describe('Plugins', function () {
|
||||
|
||||
var testTpl = function(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);
|
||||
});
|
||||
|
||||
it('should correctly extend template blocks', function() {
|
||||
return testTpl('{% test %}hello{% endtest %}')
|
||||
it("should correctly extend template blocks", function() {
|
||||
return testTpl("{% test %}hello{% endtest %}")
|
||||
.then(function(content) {
|
||||
content.should.equal("testhellotest");
|
||||
});
|
||||
});
|
||||
|
||||
it('should correctly accept shortcuts', function() {
|
||||
return testTpl('$$hello$$', {}, {
|
||||
it("should correctly accept shortcuts", function() {
|
||||
return testTpl("$$hello$$", {}, {
|
||||
type: "markdown"
|
||||
})
|
||||
.then(function(content) {
|
||||
@@ -165,26 +171,94 @@ describe('Plugins', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('should correctly extend template blocks with defined end', function() {
|
||||
return testTpl('{% test2 %}hello{% endtest2end %}')
|
||||
it("should correctly extend template blocks with defined end", function() {
|
||||
return testTpl("{% test2 %}hello{% endtest2end %}")
|
||||
.then(function(content) {
|
||||
content.should.equal("test2hellotest2");
|
||||
});
|
||||
});
|
||||
|
||||
it('should correctly extend template blocks with sub-blocks', function() {
|
||||
return testTpl('{% test3join separator=";" %}hello{% also %}world{% endtest3join %}')
|
||||
it("should correctly extend template blocks with sub-blocks", function() {
|
||||
return testTpl("{% test3join separator=\";\" %}hello{% also %}world{% endtest3join %}")
|
||||
.then(function(content) {
|
||||
content.should.equal("hello;world");
|
||||
});
|
||||
});
|
||||
|
||||
it('should correctly extend template blocks with different sub-blocks', function() {
|
||||
return testTpl('{% test4join separator=";" %}hello{% also %}the{% finally %}world{% endtest4join %}')
|
||||
it("should correctly extend template blocks with different sub-blocks", function() {
|
||||
return testTpl("{% test4join separator=\";\" %}hello{% also %}the{% finally %}world{% endtest4join %}")
|
||||
.then(function(content) {
|
||||
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");
|
||||
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 path = require('path');
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
|
||||
describe('Summary', function () {
|
||||
describe('Parsing', function() {
|
||||
describe("Summary", function () {
|
||||
describe("Parsing", function() {
|
||||
var book;
|
||||
|
||||
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.summary.should.have.property("chapters");
|
||||
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[1].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;
|
||||
|
||||
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("PAGE1.html");
|
||||
book.should.have.file("folder/PAGE2.html");
|
||||
});
|
||||
|
||||
it('should correctly output summary', function() {
|
||||
it("should correctly output summary", function() {
|
||||
var PAGE = fs.readFileSync(
|
||||
path.join(book.options.output, "index.html"),
|
||||
{ encoding: "utf-8" }
|
||||
);
|
||||
|
||||
PAGE.should.be.html({
|
||||
".book-summary .chapter[data-level='0'] a": {
|
||||
".book-summary .chapter[data-level=\"0\"] a": {
|
||||
attributes: {
|
||||
href: "./index.html"
|
||||
}
|
||||
},
|
||||
".book-summary .chapter[data-level='1'] a": {
|
||||
".book-summary .chapter[data-level=\"1\"] a": {
|
||||
attributes: {
|
||||
href: "./PAGE1.html"
|
||||
}
|
||||
},
|
||||
".book-summary .chapter[data-level='2'] a": {
|
||||
".book-summary .chapter[data-level=\"2\"] a": {
|
||||
attributes: {
|
||||
href: "./folder/PAGE2.html"
|
||||
}
|
||||
|
||||
+7
-7
@@ -1,6 +1,6 @@
|
||||
var pkg = require("../package.json");
|
||||
|
||||
describe('Templating', function () {
|
||||
describe("Templating", function () {
|
||||
var book;
|
||||
|
||||
before(function() {
|
||||
@@ -12,19 +12,19 @@ describe('Templating', function () {
|
||||
|
||||
var testTpl = function(str, args, options) {
|
||||
return book.template.renderString(str, args, options)
|
||||
.then(book.template.postProcess)
|
||||
.then(book.template.postProcess);
|
||||
};
|
||||
|
||||
describe('Context', function() {
|
||||
it('should correctly have access to generator', function() {
|
||||
return testTpl('{{ gitbook.generator }}')
|
||||
describe("Context", function() {
|
||||
it("should correctly have access to generator", function() {
|
||||
return testTpl("{{ gitbook.generator }}")
|
||||
.then(function(content) {
|
||||
content.should.equal("website");
|
||||
});
|
||||
});
|
||||
|
||||
it('should correctly have access to gitbook version', function() {
|
||||
return testTpl('{{ gitbook.version }}')
|
||||
it("should correctly have access to gitbook version", function() {
|
||||
return testTpl("{{ gitbook.version }}")
|
||||
.then(function(content) {
|
||||
content.should.equal(pkg.version.toString());
|
||||
});
|
||||
|
||||
+4
-7
@@ -1,8 +1,5 @@
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
describe('Website generator', function () {
|
||||
describe('Basic Book', function() {
|
||||
describe("Website generator", function () {
|
||||
describe("Basic Book", function() {
|
||||
var book;
|
||||
|
||||
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");
|
||||
});
|
||||
|
||||
it('should correctly copy assets', function() {
|
||||
it("should correctly copy assets", function() {
|
||||
book.should.have.file("gitbook");
|
||||
book.should.have.file("gitbook/app.js");
|
||||
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,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"
|
||||
}
|
||||
@@ -3,18 +3,18 @@
|
||||
"GLOSSARY": "어휘",
|
||||
"GLOSSARY_INDEX": "색인",
|
||||
"GLOSSARY_OPEN": "어휘",
|
||||
"GITBOOK_LINK": "에 게시 GitBook",
|
||||
"GITBOOK_LINK": "GitBook에 게시",
|
||||
"SUMMARY": "차례",
|
||||
"SUMMARY_INTRODUCTION": "소개",
|
||||
"SUMMARY_TOGGLE": "차례",
|
||||
"SEARCH_TOGGLE": "수색",
|
||||
"SEARCH_TOGGLE": "검색",
|
||||
"SEARCH_PLACEHOLDER": "검색어 입력",
|
||||
"FONTSETTINGS_TOGGLE": "글꼴 설정",
|
||||
"SHARE_TOGGLE": "몫",
|
||||
"SHARE_ON": "공유 {{platform}}",
|
||||
"SHARE_TOGGLE": "공유",
|
||||
"SHARE_ON": "{{platform}}에 공유",
|
||||
"FONTSETTINGS_WHITE": "화이트",
|
||||
"FONTSETTINGS_SEPIA": "Sepia",
|
||||
"FONTSETTINGS_NIGHT": "밤",
|
||||
"FONTSETTINGS_SANS": "Sans",
|
||||
"FONTSETTINGS_SERIF": "Serif"
|
||||
"FONTSETTINGS_SEPIA": "세피아",
|
||||
"FONTSETTINGS_NIGHT": "나이트",
|
||||
"FONTSETTINGS_SANS": "고딕",
|
||||
"FONTSETTINGS_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 $pageBody = $page.find('.book');
|
||||
|
||||
////
|
||||
// Merge heads
|
||||
var headContent = $pageHead.html()
|
||||
// !! Warning !!: we only update necessary portions to avoid strange behavior (page flickering etc ...)
|
||||
////
|
||||
|
||||
$("head style").each(function() {
|
||||
headContent = headContent + this.outerHTML
|
||||
});
|
||||
$("head").html(headContent);
|
||||
// Update title
|
||||
document.title = $pageHead.find("title").text();
|
||||
|
||||
// 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
|
||||
var bodyClass = $(".book").attr("class");
|
||||
@@ -93,7 +105,19 @@ define([
|
||||
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) {
|
||||
if (isModifiedEvent(e) || !isLeftClickEvent(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
pre {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
table {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
@import "mixins.less";
|
||||
|
||||
@import "ebook/variables.less";
|
||||
@import "ebook/highlight.less";
|
||||
|
||||
.page {
|
||||
&.page-toc {
|
||||
@@ -39,6 +38,6 @@
|
||||
body {
|
||||
.page {
|
||||
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 "website/fonts.less";
|
||||
@import "website/variables.less";
|
||||
@import "website/languages.less";
|
||||
@import "website/header.less";
|
||||
@@ -44,4 +43,5 @@ body {
|
||||
font-smoothing: antialiased;
|
||||
font-family: @font-family-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');
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
/* Tomorrow Night Bright Theme */
|
||||
/* Original theme - https://github.com/chriskempson/tomorrow-theme */
|
||||
/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */
|
||||
|
||||
/* Tomorrow Comment */
|
||||
.hljs-comment,
|
||||
.hljs-title {
|
||||
color: #969896;
|
||||
}
|
||||
|
||||
/* 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: #d54e53;
|
||||
}
|
||||
|
||||
/* Tomorrow Orange */
|
||||
.hljs-number,
|
||||
.hljs-preprocessor,
|
||||
.hljs-pragma,
|
||||
.hljs-built_in,
|
||||
.hljs-literal,
|
||||
.hljs-params,
|
||||
.hljs-constant {
|
||||
color: #e78c45;
|
||||
}
|
||||
|
||||
/* Tomorrow Yellow */
|
||||
.ruby .hljs-class .hljs-title,
|
||||
.css .hljs-rules .hljs-attribute {
|
||||
color: #e7c547;
|
||||
}
|
||||
|
||||
/* Tomorrow Green */
|
||||
.hljs-string,
|
||||
.hljs-value,
|
||||
.hljs-inheritance,
|
||||
.hljs-header,
|
||||
.ruby .hljs-symbol,
|
||||
.xml .hljs-cdata {
|
||||
color: #b9ca4a;
|
||||
}
|
||||
|
||||
/* Tomorrow Aqua */
|
||||
.css .hljs-hexcolor {
|
||||
color: #70c0b1;
|
||||
}
|
||||
|
||||
/* 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: #7aa6da;
|
||||
}
|
||||
|
||||
/* Tomorrow Purple */
|
||||
.hljs-keyword,
|
||||
.javascript .hljs-function {
|
||||
color: #c397d8;
|
||||
}
|
||||
|
||||
.hljs {
|
||||
display: block;
|
||||
background: black;
|
||||
color: #eaeaea;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
.coffeescript .javascript,
|
||||
.javascript .xml,
|
||||
.tex .hljs-formula,
|
||||
.xml .javascript,
|
||||
.xml .vbscript,
|
||||
.xml .css,
|
||||
.xml .hljs-cdata {
|
||||
opacity: 0.5;
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
/*
|
||||
|
||||
Orginal Style from ethanschoonover.com/solarized (c) Jeremy Hull <sourdrums@gmail.com>
|
||||
|
||||
*/
|
||||
|
||||
.hljs {
|
||||
display: block;
|
||||
padding: 0.5em;
|
||||
background: #fdf6e3;
|
||||
color: #657b83;
|
||||
}
|
||||
|
||||
.hljs-comment,
|
||||
.hljs-template_comment,
|
||||
.diff .hljs-header,
|
||||
.hljs-doctype,
|
||||
.hljs-pi,
|
||||
.lisp .hljs-string,
|
||||
.hljs-javadoc {
|
||||
color: #93a1a1;
|
||||
}
|
||||
|
||||
/* Solarized Green */
|
||||
.hljs-keyword,
|
||||
.hljs-winutils,
|
||||
.method,
|
||||
.hljs-addition,
|
||||
.css .hljs-tag,
|
||||
.hljs-request,
|
||||
.hljs-status,
|
||||
.nginx .hljs-title {
|
||||
color: #859900;
|
||||
}
|
||||
|
||||
/* Solarized Cyan */
|
||||
.hljs-number,
|
||||
.hljs-command,
|
||||
.hljs-string,
|
||||
.hljs-tag .hljs-value,
|
||||
.hljs-rules .hljs-value,
|
||||
.hljs-phpdoc,
|
||||
.tex .hljs-formula,
|
||||
.hljs-regexp,
|
||||
.hljs-hexcolor,
|
||||
.hljs-link_url {
|
||||
color: #2aa198;
|
||||
}
|
||||
|
||||
/* Solarized Blue */
|
||||
.hljs-title,
|
||||
.hljs-localvars,
|
||||
.hljs-chunk,
|
||||
.hljs-decorator,
|
||||
.hljs-built_in,
|
||||
.hljs-identifier,
|
||||
.vhdl .hljs-literal,
|
||||
.hljs-id,
|
||||
.css .hljs-function {
|
||||
color: #268bd2;
|
||||
}
|
||||
|
||||
/* Solarized Yellow */
|
||||
.hljs-attribute,
|
||||
.hljs-variable,
|
||||
.lisp .hljs-body,
|
||||
.smalltalk .hljs-number,
|
||||
.hljs-constant,
|
||||
.hljs-class .hljs-title,
|
||||
.hljs-parent,
|
||||
.haskell .hljs-type,
|
||||
.hljs-link_reference {
|
||||
color: #b58900;
|
||||
}
|
||||
|
||||
/* Solarized Orange */
|
||||
.hljs-preprocessor,
|
||||
.hljs-preprocessor .hljs-keyword,
|
||||
.hljs-pragma,
|
||||
.hljs-shebang,
|
||||
.hljs-symbol,
|
||||
.hljs-symbol .hljs-string,
|
||||
.diff .hljs-change,
|
||||
.hljs-special,
|
||||
.hljs-attr_selector,
|
||||
.hljs-subst,
|
||||
.hljs-cdata,
|
||||
.clojure .hljs-title,
|
||||
.css .hljs-pseudo,
|
||||
.hljs-header {
|
||||
color: #cb4b16;
|
||||
}
|
||||
|
||||
/* Solarized Red */
|
||||
.hljs-deletion,
|
||||
.hljs-important {
|
||||
color: #dc322f;
|
||||
}
|
||||
|
||||
/* Solarized Violet */
|
||||
.hljs-link_label {
|
||||
color: #6c71c4;
|
||||
}
|
||||
|
||||
.tex .hljs-formula {
|
||||
background: #eee8d5;
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
/* http://jmblog.github.com/color-themes-for-google-code-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;
|
||||
}
|
||||
@@ -5,10 +5,6 @@
|
||||
.book .book-body .page-wrapper .page-inner section.normal {
|
||||
.markdown-content(@content-color, @content-line-height);
|
||||
|
||||
pre, code {
|
||||
@import "./highlight/white.less";
|
||||
}
|
||||
|
||||
.glossary-term {
|
||||
cursor: help;
|
||||
text-decoration: underline;
|
||||
@@ -51,8 +47,6 @@
|
||||
background: @page-pre-background-1;
|
||||
color: @page-pre-color-1;
|
||||
border-color: @page-pre-border-color-1;
|
||||
|
||||
@import "./highlight/sepia.less";
|
||||
}
|
||||
|
||||
.highlight {
|
||||
@@ -112,8 +106,6 @@
|
||||
color: @page-pre-color-2;
|
||||
background: @page-pre-background-2;
|
||||
border-color: @page-pre-border-color-2;
|
||||
|
||||
@import "./highlight/night.less";
|
||||
}
|
||||
|
||||
.highlight {
|
||||
|
||||
@@ -95,8 +95,8 @@
|
||||
@border-radius-small: 1px;
|
||||
|
||||
// Fonts
|
||||
@font-family-serif: "Merriweather", Georgia, serif;
|
||||
@font-family-sans: "Open Sans", "Clear Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
@font-family-serif: Georgia, serif;
|
||||
@font-family-sans: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
@font-family-base: @font-family-sans;
|
||||
@headings-font-family: inherit;
|
||||
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
{% if options.author %}<meta name="author" content="{{ options.author }}">{% endif %}
|
||||
{% if options.isbn %}<meta name="identifier" content="{{ options.isbn }}" scheme="ISBN">{% endif %}
|
||||
{% block head %}{% endblock %}
|
||||
{% block style %}{% endblock %}
|
||||
{{ htmlSnippet("head:end")|default("", true)|safe }}
|
||||
</head>
|
||||
<body>
|
||||
{{ htmlSnippet("body:start")|default("", true)|safe }}
|
||||
{% block style %}{% endblock %}
|
||||
{% block content %}{% endblock %}
|
||||
{% block javascript %}{% endblock %}
|
||||
{{ htmlSnippet("body:end")|default("", true)|safe }}
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
{% block title %}{{ progress.current.title }} | {{ title }}{% endblock %}
|
||||
|
||||
{% block style %}
|
||||
{% if not styles.print %}
|
||||
<link rel="stylesheet" href="{{ staticBase }}/print.css">
|
||||
{% endif %}
|
||||
{% for resource in plugins.resources.css %}
|
||||
{% if resource.url %}
|
||||
<link rel="stylesheet" href="{{ resource.url }}">
|
||||
@@ -11,7 +13,7 @@
|
||||
<link rel="stylesheet" href="{{ staticBase }}/plugins/{{ resource.path }}">
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% for style in styles %}
|
||||
{% for type, style in styles %}
|
||||
<link rel="stylesheet" href="{{ basePath }}/{{ style }}">
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="book-header">
|
||||
<div class="book-header" role="navigation">
|
||||
<!-- Actions Left -->
|
||||
<a href="#" class="btn pull-left toggle-summary" aria-label="{{ __("SUMMARY_TOGGLE") }}"><i class="fa fa-align-justify"></i></a>
|
||||
<a href="#" class="btn pull-left toggle-search" aria-label="{{ __("SEARCH_TOGGLE") }}"><i class="fa fa-search"></i></a>
|
||||
|
||||
@@ -4,21 +4,15 @@
|
||||
{% if item.path and item.exists %}
|
||||
{% if not item.external %}
|
||||
<a href="{{ basePath }}/{{ item.path|contentLink }}">
|
||||
<i class="fa fa-check"></i>
|
||||
{% if item.level != "0" %}
|
||||
<b>{{ item.level }}.</b>
|
||||
{% endif %}
|
||||
{{ item.title }}
|
||||
</a>
|
||||
{% else %}
|
||||
<a target="_blank" href="{{ item.path }}">
|
||||
{% endif %}
|
||||
<i class="fa fa-check"></i>
|
||||
{% if item.level != "0" %}
|
||||
<b>{{ item.level }}.</b>
|
||||
{% endif %}
|
||||
{{ item.title }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span><b>{{ item.level }}.</b> {{ item.title }}</span>
|
||||
{% endif %}
|
||||
@@ -32,33 +26,35 @@
|
||||
{% endmacro %}
|
||||
|
||||
<div class="book-summary">
|
||||
<div class="book-search">
|
||||
<div class="book-search" role="search">
|
||||
<input type="text" placeholder="{{ __("SEARCH_PLACEHOLDER") }}" class="form-control" />
|
||||
</div>
|
||||
<ul class="summary">
|
||||
{% set _divider = false %}
|
||||
{% if options.links.sidebar %}
|
||||
{% for linkTitle, link in options.links.sidebar %}
|
||||
{% set _divider = true %}
|
||||
<nav role="navigation">
|
||||
<ul class="summary">
|
||||
{% set _divider = false %}
|
||||
{% if options.links.sidebar %}
|
||||
{% for linkTitle, link in options.links.sidebar %}
|
||||
{% set _divider = true %}
|
||||
<li>
|
||||
<a href="{{ link }}" target="blank" class="custom-link">{{ linkTitle }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if _divider %}
|
||||
<li class="divider"></li>
|
||||
{% endif %}
|
||||
|
||||
{{ articles(summary.chapters) }}
|
||||
|
||||
{% if options.links.gitbook != false %}
|
||||
<li class="divider"></li>
|
||||
<li>
|
||||
<a href="{{ link }}" target="blank" class="custom-link">{{ linkTitle }}</a>
|
||||
<a href="https://www.gitbook.com" target="blank" class="gitbook-link">
|
||||
{{ __("GITBOOK_LINK") }}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if _divider %}
|
||||
<li class="divider"></li>
|
||||
{% endif %}
|
||||
|
||||
{{ articles(summary.chapters) }}
|
||||
|
||||
{% if options.links.gitbook != false %}
|
||||
<li class="divider"></li>
|
||||
<li>
|
||||
<a href="https://www.gitbook.com" target="blank" class="gitbook-link">
|
||||
{{ __("GITBOOK_LINK") }}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="book-langs-index">
|
||||
<div class="book-langs-index" role="navigation">
|
||||
<div class="inner">
|
||||
<h3>{{ __("LANGS_CHOOSE") }}</h3>
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<div class="book-body">
|
||||
<div class="body-inner">
|
||||
{% include "includes/header.html" %}
|
||||
<div class="page-wrapper" tabindex="-1">
|
||||
<div class="page-wrapper" tabindex="-1" role="main">
|
||||
<div class="page-inner">
|
||||
{% block page_inner %}
|
||||
{% for section in content %}
|
||||
@@ -70,7 +70,7 @@ require(["gitbook"], function(gitbook) {
|
||||
<link rel="stylesheet" href="{{ staticBase }}/plugins/{{ resource.path }}">
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% for style in styles %}
|
||||
{% for type, style in styles %}
|
||||
<link rel="stylesheet" href="{{ basePath }}/{{ style }}">
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user