Compare commits

...

113 Commits

Author SHA1 Message Date
Samy Pessé b24760c819 Bump version to 2.4.0 2015-09-15 14:32:11 +02:00
Samy Pessé 6732957e42 Merge pull request #930 from GitbookIO/jshint
Add config for jshint and fix lint errors
2015-09-15 14:21:27 +02:00
Samy Pessé 1fd0006859 Lint all tests 2015-09-15 14:20:32 +02:00
Samy Pessé 5a205346e3 Jshint all files 2015-09-15 13:57:21 +02:00
Samy Pessé e193004659 Fix passing context to block functions
Add test for it
2015-09-15 13:36:02 +02:00
Samy Pessé fe3a9c33d0 Improve code style for book.js and index.js 2015-09-15 13:16:26 +02:00
Samy Pessé d83116b88f Add jshint configuration 2015-09-15 13:16:06 +02:00
Samy Pessé 5f56098ae7 Fix stupid error that passed tests because "context" was global 2015-09-15 12:38:13 +02:00
Samy Pessé 0f935f4372 Merge pull request #806 from aschempp/aria-roles
Aria roles for accessibility
2015-09-15 12:29:12 +02:00
Samy Pessé df5c5a8c01 Merge pull request #919 from gaearon/fix-cmd-click
Don't react when user wants to open a link in a new tab
2015-09-15 12:28:32 +02:00
Samy Pessé 57a0c3bad8 Merge pull request #929 from GitbookIO/feature/improve_resolve
Improve paths resolving for conrefs
2015-09-15 12:27:07 +02:00
Samy Pessé 2a52326a45 Improve conrefs to handle all absolute file paths correctly
Add test for it
2015-09-15 12:22:54 +02:00
Samy Pessé 87e4ee1eeb Handle absolute file correctly for conrefs
Add test for absolute file for conrefs
2015-09-15 11:48:18 +02:00
Samy Pessé 45833eea9a Add test for navigation
Update mocha and should
2015-09-15 11:31:50 +02:00
Samy Pessé baf10e9b15 Improve book.resolve to ensure file is in the book
Adapt tests to plugin-highlight
2015-09-15 11:09:08 +02:00
Samy Pessé 463a947df1 Change text for editor 2015-09-15 09:47:34 +02:00
Samy Pessé cceebb4fd9 Merge branch 'improve/template-blocks' 2015-09-15 09:37:43 +02:00
Samy Pessé afd5465a61 Merge pull request #928 from GitbookIO/feature/highlight_block
Code highlighting extended by plugins
2015-09-14 18:26:26 +02:00
Samy Pesse fe604733de Change name of highlight test plugin 2015-09-14 12:05:51 +02:00
Samy Pesse da22f9f39f Update css without highlight.js
Add highlight as default plugin to be loaded
2015-09-14 11:57:54 +02:00
Samy Pesse 284ebbf75d Add highlight as default plugin 2015-09-14 11:47:56 +02:00
Samy Pesse 2c08ccad87 Pass language as kwargs to code block
Improve tests for extending code highlighting
2015-09-14 11:41:01 +02:00
Samy Pesse fa4e234bab Add base test for extending code highlighting 2015-09-14 11:28:14 +02:00
Samy Pesse 35c4179ca1 Use block code for highlight pre/code
Cleanup correctly predefined blocks
2015-09-14 11:21:16 +02:00
Dan Abramov c14ba7ce34 Don't react when user wants to open a link in a new tab
Fixes #846
2015-09-12 21:31:40 +03:00
Samy Pesse 601ce3add3 Add default blocks (html and code) 2015-09-12 19:25:01 +02:00
Samy Pesse 08ff39fd0b Remove highlight.js dependency 2015-09-12 19:23:07 +02:00
Samy Pesse 82a6ee3875 Add test for replacing highlighting 2015-09-12 18:21:35 +02:00
Samy Pessé 3bf592f870 Bump version to 2.3.3 2015-09-10 11:26:15 +02:00
Samy Pessé 241e205717 Merge pull request #912 from GitbookIO/fix/538
Fix 538: duplicate entries without paths are ignored
2015-09-10 09:59:45 +02:00
Samy Pessé fb2720ea8d Update gitbook-parsers@0.8.2 2015-09-10 09:57:04 +02:00
Samy Pessé 14853befda Add test for init with deep summary 2015-09-10 09:56:18 +02:00
Samy Pessé e7f2803d11 Bump version to 2.3.2 2015-09-09 09:30:53 +02:00
Samy Pessé 320015dd8f Fix #910: fix stupid error with semver api 2015-09-09 09:27:08 +02:00
Samy Pessé 471c124a98 Merge pull request #908 from GitbookIO/fix/asciidoc_blocks
Fix blocks in asciidoc
2015-09-09 00:01:43 +02:00
Samy Pesse aa44a109c6 Use position indicator that doesn't conflict with asciidoc 2015-09-08 23:57:40 +02:00
Samy Pesse 41e5ca8422 Add test for blocks without parsing 2015-09-08 23:55:30 +02:00
Samy Pessé 53af8b2bb6 Bump version to 2.3.1 2015-09-08 16:33:22 +02:00
Samy Pessé bd885b135f Merge pull request #904 from kuaipao/fix-mobi-font-color
use black font on mobi
2015-09-08 09:16:43 +02:00
kuaipao 62a6dde81a use black font on mobi 2015-09-08 04:02:48 +08:00
Samy Pesse 14b72b344f Log modified file in watcher 2015-09-06 21:13:18 +02:00
Samy Pesse ac03668063 Update chokidar@1.0.5 2015-09-06 21:11:49 +02:00
Samy Pesse 2512e176c9 Fix #893: korean iso code is "ko" not "kr" 2015-09-06 21:01:39 +02:00
Samy Pesse b613393866 Update highlight.js@8.8.0 2015-09-06 19:04:09 +02:00
Samy Pessé 607a6e95de Update gitbook-parsers@0.8.1 2015-09-05 19:00:42 +02:00
Samy Pessé 871f574ff7 Fix #761: fix syntax highlighting for asciidoc 2015-09-05 17:28:01 +02:00
Samy Pessé 377e470b15 Add warning for file outside spine 2015-09-04 19:12:27 +02:00
Samy Pessé e0a3f0cea5 Add warning for too strict gitbook version 2015-09-04 18:58:16 +02:00
Samy Pessé 66727b2736 Update gitbook-parsers@0.8.0 2015-09-04 18:33:45 +02:00
Samy Pessé 8215ad977f Merge pull request #898 from deminoth/master
Korean translation fixed
2015-09-04 08:36:19 +02:00
SangYeob Bono Yu a611dffbdf Add my name 2015-09-04 10:29:59 +09:00
SangYeob Bono Yu 39f378d8cf Korean translation fixed 2015-09-04 10:22:24 +09:00
Samy Pessé f00da58153 Update appveyor button 2015-09-01 17:52:27 +02:00
Samy Pessé 09b038b16d Bump version to 2.3.0 2015-09-01 17:44:53 +02:00
Samy Pessé cf601d97ad Improve error handling for failed image download 2015-09-01 17:38:33 +02:00
Samy Pessé 80edad53d4 Update nunjucks to fix raw and loader 2015-09-01 17:25:43 +02:00
Samy Pessé a972b32769 Update nunjucks@2.0.0 2015-08-28 08:45:28 +02:00
Samy Pessé efcaae3e60 Add author for hebrew 2015-08-27 19:07:31 +02:00
Samy Pessé e0ee591638 Merge pull request #877 from a-moses/hebrew
hebrew support theme
2015-08-27 19:06:26 +02:00
Samy Pessé 310a6d909f Add method 'get' to config object (helper for plugins) 2015-08-27 15:26:12 +02:00
Samy Pessé cefd8fc50f Don't fail if hook returns nothing for "page" and "page:before" 2015-08-27 15:04:28 +02:00
Samy Pessé a4422593f2 Add back page:before and page as non-deprecated 2015-08-26 11:16:02 +02:00
Samy Pessé e2c5d22756 Merge pull request #844 from xcv58/master
Fix #843 ignore _book in watch.js
2015-08-26 11:05:43 +02:00
Samy Pessé 84385d9dc3 Merge pull request #881 from mortonfox/patch-1
Fix Plugins link.
2015-08-26 11:01:28 +02:00
Morton Fox 6cfa4c8ab7 Fix Plugins link. 2015-08-25 23:35:15 -04:00
a-moses c76ccc53e1 Update he.json 2015-08-23 09:59:14 +03:00
a-moses d48eafb1a2 hebrew support theme
full Hebrew support for GITBOOK (with rtl )

* Sans and Serif may still in original name fonts
2015-08-23 09:53:25 +03:00
Aaron O'Mullan 302d9b4b91 Merge pull request #849 from GitbookIO/improve/remove-webfonts
Use system fonts instead of webfonts
2015-08-13 19:19:35 +02:00
Samy Pessé a091a7f68b Update gitbook-parsers@0.7.7 2015-08-09 15:45:04 +02:00
Aaron O'Mullan 53621f6de3 Use system fonts instead of webfonts 2015-08-08 17:35:05 +02:00
Samy Pessé 288b965db3 Merge pull request #847 from GitbookIO/fix/flicker
Improve header merge on page change
2015-08-07 16:55:42 +02:00
Aaron O'Mullan 578c9dcfc6 Improve header merge on page change
Prevents flickering (style reset)

Fixes #782, #838, #840
2015-08-07 16:46:23 +02:00
xcv58 64de17b248 ignore _book in watch.js 2015-08-04 00:50:31 -04:00
Aaron O'Mullan d699dff872 Use Book.resolve when possible
For added consistency
2015-07-31 15:08:56 +02:00
Samy Pesse 501843d624 Bump version to 2.2.0 2015-07-28 15:28:38 -07:00
Samy Pesse 508ce4283e Fix #819: codes must always be ltr 2015-07-28 15:25:12 -07:00
Samy Pessé 4aa8e66549 Merge pull request #813 from MrMaksimize/pdf-options
Allowing for custom chapter-mark and page-break in PDF.
2015-07-01 18:00:31 -04:00
Maksim Pecherskiy 917a6f70d8 Allowing for custom chapter-mark and page-break in PDF. 2015-06-30 19:48:51 -07:00
Samy Pesse 2f5e53da55 Update highlight.js@8.6.0 2015-06-29 10:02:35 -04:00
Samy Pesse c3cdefc90a Simpler template for summary 2015-06-29 09:58:23 -04:00
Samy Pesse 9c580e4989 Fix #802: make book.json accessible as "config." in templating 2015-06-19 16:28:46 +02:00
Andreas Schempp dbc75f7352 Add role and html5 markup for the main navigation 2015-06-18 20:29:11 +02:00
Andreas Schempp db841a8578 Added basic ARIA roles for screenreaders 2015-06-18 20:23:12 +02:00
Samy Pessé 50c902c4e4 Merge pull request #805 from GitbookIO/fix/804
Fix #804
2015-06-18 11:16:32 +02:00
Samy Pesse 84b6e0bde6 Add test for kwargs 2015-06-18 11:15:44 +02:00
Samy Pesse abc29c3fba Fix #804: correctly extract kwargs from blocks 2015-06-18 11:11:47 +02:00
Samy Pesse 8356c534f5 Add failing tests for block's arguments 2015-06-18 11:09:02 +02:00
Samy Pessé 78ff2687b4 Merge pull request #797 from nghong/vi-locale
Adding Vietnamese locale support
2015-06-13 11:15:00 +02:00
Hong Nguyen 9b6586fb36 Add translator name to AUTHORS.md 2015-06-13 16:13:34 +07:00
Hong Nguyen ea133219d0 Minor fix 2015-06-13 16:08:21 +07:00
Hong Nguyen c9b5d81a3c Add Vietnamese locale support 2015-06-13 15:42:49 +07:00
Samy Pessé d895c63211 Bump version to 2.1.0 2015-06-02 14:52:11 +02:00
Samy Pessé 8c86da67ca Update gitbook-parsers@0.7.6 2015-06-02 14:47:21 +02:00
Samy Pessé a9a230dfc3 Merge pull request #781 from GitbookIO/fix/775
Fix #775: add optional print.css style
2015-06-02 11:00:22 +02:00
Samy Pessé 6d53e52771 Handle empty string for styles configuration 2015-06-02 11:00:15 +02:00
Samy Pessé 52e10b7cfe Remove default print.css when styles/print.css is present 2015-06-02 10:23:31 +02:00
Samy Pessé addac85696 Add test for custom print style 2015-06-02 10:18:44 +02:00
Samy Pessé 13fb949d68 Merge pull request #774 from wilhelmmatilainen/patch-1
Styling should go to <head>, not to <body>
2015-05-30 18:11:15 +02:00
Wilhelm f1b593cfbd Styling should go to <head>, not to <body>
https://developers.google.com/speed/pagespeed/module/filter-css-to-head
2015-05-29 15:42:40 +03:00
Samy Pesse f998e2dec9 Bump version to 2.0.4 2015-05-28 18:07:20 +02:00
Samy Pesse 2c0bd53a91 Fix i18n used in multilingual book 2015-05-28 17:06:09 +02:00
Samy Pesse 6dd7f6162f Add title to languages chooser
Related to #757
2015-05-28 16:14:03 +02:00
Samy Pesse 475b0bb2b3 Adapt to nunjucks 1.3.x 2015-05-28 15:59:14 +02:00
Samy Pesse e6343935e3 Update nunjucks to fix raw tags 2015-05-28 15:50:46 +02:00
Samy Pessé 946883fd4c Merge pull request #772 from GitbookIO/feature/glossary_order
Fix #768: sort glossary, start with longest matchs
2015-05-28 15:21:03 +02:00
Samy Pessé b1b7e3148b Merge pull request #743 from chudaol/master
Added vk sharing button.
2015-05-28 14:54:03 +02:00
Samy Pesse 32203f6438 Sort glossary before applying it on pages 2015-05-28 14:49:53 +02:00
Samy Pesse f2d3c5d2ed Add test for #768 2015-05-28 14:38:21 +02:00
Samy Pessé 7e2f0ed4bc Merge pull request #758 from aschempp/hotfix/x-ua-compatible
Fix the X-UA-Compatible meta tag
2015-05-28 14:18:19 +02:00
Samy Pessé a877acf905 Merge pull request #759 from aschempp/hotfix/stylesheets
Move style sheets to the <head> section
2015-05-28 14:17:39 +02:00
Andreas Schempp 1a60778248 Move style sheets to the <head> section
see https://github.com/GitbookIO/gitbook/issues/756
2015-05-23 09:14:26 +02:00
Andreas Schempp cda4bb5bda Fix the X-UA-Compatible meta tag
see https://github.com/GitbookIO/gitbook/issues/755
2015-05-23 09:06:58 +02:00
Olga Filipova 7543781046 Added vk sharing button. 2015-05-12 22:30:09 +02:00
104 changed files with 1446 additions and 1229 deletions
+7
View File
@@ -0,0 +1,7 @@
{
"strict": false,
"browser": false,
"quotmark": true,
"node": true,
"mocha": true
}
+19 -14
View File
@@ -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
+51
View File
@@ -2,6 +2,57 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## 2.4.0
- Fix page being updated when user wants to open a link in a new tab
- Plugins can now replaced default code highlighter
- Add semantic information for screen readers (web version)
- Content references accept absolute paths, resolved to book folder
- Improve overall reliability
## 2.3.3
- Fix bug in SUMMARY parsing preventing multiple entries without filenames
## 2.3.2
- Fix blocks (like maths) in Asciidoc
- Fix error when checking gitbook version
## 2.3.1
- Fix black font color for ebooks (mobi, pdf and epub)
- Fix ISO code for korean language
- Fix korean translation
- Fix syntax highlighting for asciidoc
- Fix inline html escaping in markdown
- Add warning for file outside SUMMARY
- Force SUMMARY entries to be unique by filename
## 2.3.0
- Fix nunjucks issue with multiple `{% raw %}` blocks
- Fix crash when git conref failed
- Fix crash when failed to download remote image (better error message)
- Fix flicking effect when changing page (big UX improvement)
- Add Hebrew translation (`he`)
- Add utility method `book.config.get` for plugins
- Hooks `page:before` and `page` are no longer deprecated
- Remove webfonts to make website lighter
- Make glossary's order case insensitive
## 2.2.0
- Fix direction in code blocks (always LTR)
- Add options `chapterMark` and `pageBreaksBefore` for PDF
- Update code highlighting library
- `book.json` accessible as `config` in templating syntax
- Add Vietnamese translation (`vi`)
## 2.1.0
- Fix error in calcul of `levels` in table of contents, error introduced a few versions ago
- Add optional `styles/print.css` to replace `print.css` used in ebook
## 2.0.4
- Fix `{% raw %}`, got confused with "fake" variable declarations
- Fix title of language chooser
- Fix the X-UA-Compatible meta tag
- Move style sheets to the <head> section
## 2.0.3
- Fix `gitbook init` for SUMMARY with empty entries
- Fix escaping of code blocks in markdown
+4 -4
View File
@@ -2,12 +2,12 @@ GitBook
=======
[![NPM version](https://badge.fury.io/js/gitbook.svg)](http://badge.fury.io/js/gitbook)
[![Build Status](https://travis-ci.org/GitbookIO/gitbook.png?branch=master)](https://travis-ci.org/GitbookIO/gitbook)
[![Windows Build Status](https://ci.appveyor.com/api/projects/status/github/GitbookIO/gitbook?branch=master&svg=true)](https://ci.appveyor.com/project/SamyPesse/gitbook)
[![Linux Build Status](https://travis-ci.org/GitbookIO/gitbook.png?branch=master)](https://travis-ci.org/GitbookIO/gitbook)
[![Windows Build status](https://ci.appveyor.com/api/projects/status/63nlflxcwmb2pue6?svg=true)](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)
+11
View File
@@ -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
};
+72 -62
View File
@@ -1,30 +1,25 @@
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;
this.context = _.defaults(context || {}, {
// Extend book configuration
config: {},
@@ -85,10 +80,10 @@ var Book = function(root, context, parent) {
// Search Index
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 +119,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 +181,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 +206,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 +216,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 +261,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 +289,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 +333,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 +343,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 +439,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 +506,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 +568,7 @@ Book.prototype.parsePage = function(filename, options) {
.then(function(content) {
section.content = content;
return _sections.concat([section]);
})
});
});
}, Q([]));
})
@@ -586,8 +580,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 +616,7 @@ Book.prototype.findFile = function(filename) {
parser: parsers.get(ext),
path: filepath
};
})
});
});
}, Q(null));
};
@@ -630,21 +624,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 +651,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 +681,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 +691,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,28 +701,39 @@ 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) {
@@ -747,7 +757,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 +770,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 +789,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 +830,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 +846,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 +862,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");
});
});
}));
+29 -22
View File
@@ -1,14 +1,13 @@
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 defaultsPlugins = ["highlight"];
// Normalize a list of plugins to use
function normalizePluginsList(plugins) {
@@ -24,9 +23,9 @@ function normalizePluginsList(plugins) {
var parts = plugin.split("@");
return {
'name': parts[0],
'version': parts[1] // optional
}
"name": parts[0],
"version": parts[1] // optional
};
});
// List plugins to remove
@@ -42,7 +41,7 @@ function normalizePluginsList(plugins) {
// Merge with defaults
plugins = _.chain(plugins)
.concat(_.map(defaultsPlugins, function(plugin) {
return { 'name': plugin }
return { "name": plugin };
}))
.uniq()
.value();
@@ -55,11 +54,6 @@ function normalizePluginsList(plugins) {
return plugins;
}
// Normalize a list of plugin name to use
function normalizePluginsNames(plugins) {
return _.pluck(normalizePluginsList(plugins), "name");
};
var Configuration = function(book, options) {
var that = this;
@@ -96,11 +90,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 +103,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) {
@@ -121,11 +115,11 @@ Configuration.prototype.load = 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.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.plugins = _.union(that.options.plugins, that.options.defaultsPlugins);
@@ -156,10 +150,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 +184,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 +207,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 +244,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": {
+63
View File
@@ -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
View File
@@ -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
View File
@@ -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);
});
+2 -2
View File
@@ -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() {
+21 -24
View File
@@ -4,13 +4,12 @@ var Q = require("q");
var _ = require("lodash");
var nunjucks = require("nunjucks");
var AutoEscapeExtension = require("nunjucks-autoescape");
var FilterExtension = require("nunjucks-filter");
var AutoEscapeExtension = require("nunjucks-autoescape")(nunjucks);
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,14 +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;
});
that.env.addGlobal('__', that.book.i18n.bind(that.book));
// 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));
});
};
@@ -114,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
@@ -135,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,
@@ -153,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)
@@ -207,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,6 +233,8 @@ Generator.prototype._writeTemplate = function(tpl, options, output, interpolate)
basePath: ".",
staticBase: path.join(".", "gitbook"),
"__": that.book.i18n.bind(that.book)
}, options)
);
})
+21 -22
View File
@@ -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
View File
@@ -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;
+18 -24
View File
@@ -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,7 +146,7 @@ PluginsList.prototype.resources = function(namespace) {
// Install plugins from a book
PluginsList.prototype.install = function() {
var that = this;
var defaultsPlugins = _.pluck(that.book.options.defaultsPlugins)
var defaultsPlugins = _.pluck(that.book.options.defaultsPlugins);
// Remove defaults (no need to install)
var plugins = _.filter(that.book.options.plugins, function(plugin) {
@@ -180,8 +176,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 +199,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 +216,4 @@ PluginsList.prototype.install = function() {
}, Q());
};
module.exports = PluginsList;
+127 -87
View File
@@ -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
View File
@@ -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);
-36
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+6 -9
View File
@@ -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,
+69 -42
View File
@@ -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,36 +226,46 @@ 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 html = options.book.template.applyBlock("code", {
body: source,
kwargs: {
language: lang
}
}).body;
$(this).html(html);
}
$(this).html(html);
});
// Replace glossary terms
_.each(options.glossary, function(term) {
var r = new RegExp( "\\b(" + pregQuote(term.name.toLowerCase()) + ")\\b" , 'gi' );
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 includedInFiles = false;
$("*").each(function() {
// Ignore codeblocks
if (_.contains(["code", "pre"], this.name.toLowerCase())) return;
if (_.contains(["code", "pre", "a"], this.name.toLowerCase())) return;
replaceText($, this, r, function(match) {
// Add to files index in glossary
@@ -252,7 +274,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>";
});
});
});
@@ -261,7 +283,7 @@ function normalizeHtml(src, options) {
html: renderDom($),
images: toConvert
};
};
}
// Convert svg images to png
function convertImages(images, options) {
@@ -282,7 +304,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
@@ -303,8 +331,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) {
@@ -337,7 +364,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;
@@ -346,11 +373,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) {
@@ -364,7 +391,7 @@ function extractText(sections) {
return prev;
}, "");
};
}
module.exports = {
normalize: normalizePage,
+40
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
});
+11 -11
View File
@@ -1,27 +1,28 @@
{
"name": "gitbook",
"version": "2.0.3",
"version": "2.4.0",
"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",
"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": "1.3.0",
"nunjucks-autoescape": "0.1.1",
"nunjucks-filter": "0.1.0",
"gitbook-parsers": "0.8.2",
"gitbook-plugin-highlight": "1.0.1",
"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
View File
@@ -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);
});
});
+4 -2
View File
@@ -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>
+4
View File
@@ -7,3 +7,7 @@ Just a simple and easy to understand test.
## hakunamatata
This word is not present in the content.
## test long
This is a test with a longer text that the first entry to test order.
+2
View File
@@ -6,3 +6,5 @@ The word test should be replaced by a glossary link.
But the word test should not be replaced in code blocks
```
The two words test long should be replaced by the correct glossary links.
+15
View File
@@ -0,0 +1,15 @@
# Readme
Block without language
```
test 1
```
Block with a language
```lang
test 2
```
Inline code: `test 3`
+1
View File
@@ -0,0 +1 @@
# Summary
+3
View File
@@ -4,3 +4,6 @@
* [Hello 2](hello2.md)
* Hello 3
* [Hello 4](hello3/hello4.md)
* Hello 5
* [Hello 6](hello3/hello5/hello6.md)
+3
View File
@@ -0,0 +1,3 @@
# Readme
Default description for the book.
+1
View File
@@ -0,0 +1 @@
# Summary
+3
View File
@@ -0,0 +1,3 @@
body {
color: red;
}
+56
View File
@@ -0,0 +1,56 @@
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"
}
});
});
});
+13 -8
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+23 -14
View File
@@ -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(2);
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,21 +58,30 @@ describe('Glossary', function () {
});
});
it('should correctly replaced terms by links (relative)', function() {
it("should correctly replaced terms by links (relative)", function() {
page.should.be.html({
".page-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
}
});
});
it("should correctly select the longest term", function() {
readme.should.be.html({
".page-inner a[href=\"GLOSSARY.html#test_long\"]": {
count: 1,
text: "test long"
}
});
});
});
});
});
+19 -15
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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");
});
});
});
+61
View File
@@ -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");
});
});
+103 -43
View File
@@ -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,80 @@ 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", 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>");
});
});
});
});
+21 -1
View File
@@ -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";
}
},
}
};
+11
View File
@@ -0,0 +1,11 @@
module.exports = {
blocks: {
"code": {
process: function(blk) {
var lang = blk.kwargs.language || "code";
return lang+"_"+blk.body+"_"+lang;
}
}
}
};
@@ -0,0 +1,9 @@
{
"name": "gitbook-plugin-replace_highlight",
"description": "Test replacing default code highlighter",
"main": "index.js",
"version": "0.0.1",
"engines": {
"gitbook": "*"
}
}
+60
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
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
+21
View File
@@ -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"
}
+8 -8
View File
@@ -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": "명조"
}
+20
View File
@@ -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"
}
+29 -5
View File
@@ -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();
+3
View File
@@ -16,6 +16,9 @@ define([
},
"instapaper": function($el) {
window.open("http://www.instapaper.com/text?u="+encodeURIComponent(location.href));
},
"vk": function($el) {
window.open("http://vkontakte.ru/share.php?url="+encodeURIComponent(location.href));
}
};
+1
View File
@@ -51,6 +51,7 @@
pre {
font-family: monospace, monospace;
font-size: 1em;
direction: ltr;
}
table {
+1 -2
View File
@@ -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);
}
}
-90
View File
@@ -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;
}
+1 -1
View File
@@ -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;
}
-96
View File
@@ -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;
}
-8
View File
@@ -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 {
+2 -2
View File
@@ -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;
+7 -7
View File
@@ -1,8 +1,8 @@
<!DOCTYPE HTML>
<html lang="{{ language }}" {% block htmlTag %}{% endblock %} {% if options.direction == "rtl" %}dir="rtl"{% endif %}>
{{ htmlSnippet("html:start")|default("")|safe }}
{{ htmlSnippet("html:start")|default("", true)|safe }}
<head>
{{ htmlSnippet("head:start")|default("")|safe }}
{{ htmlSnippet("head:start")|default("", true)|safe }}
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
@@ -11,14 +11,14 @@
{% 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 %}
{{ htmlSnippet("head:end")|default("")|safe }}
{% block style %}{% endblock %}
{{ htmlSnippet("head:end")|default("", true)|safe }}
</head>
<body>
{{ htmlSnippet("body:start")|default("")|safe }}
{% block style %}{% endblock %}
{{ htmlSnippet("body:start")|default("", true)|safe }}
{% block content %}{% endblock %}
{% block javascript %}{% endblock %}
{{ htmlSnippet("body:end")|default("")|safe }}
{{ htmlSnippet("body:end")|default("", true)|safe }}
</body>
{{ htmlSnippet("html:end")|default("")|safe }}
{{ htmlSnippet("html:end")|default("", true)|safe }}
</html>
+3 -1
View File
@@ -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 %}
+5 -1
View File
@@ -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>
@@ -54,6 +54,10 @@
{% if options.links.sharing.weibo == true %}
<a href="#" target="_blank" class="btn pull-right weibo-sharing-link sharing-link" data-sharing="weibo" aria-label="Weibo"><i class="fa fa-weibo"></i></a>
{% endif %}
{% if options.links.sharing.vk == true %}
<a href="#" target="_blank" class="btn pull-right vk-sharing-link sharing-link" data-sharing="vk" aria-label="VK"><i class="fa fa-vk"></i></a>
{% endif %}
<!-- Title -->
<h1>

Some files were not shown because too many files have changed in this diff Show More