Compare commits

...

82 Commits

Author SHA1 Message Date
Samy Pessé 07d5245a5f Bump version to 3.0.0-pre.7 2016-04-11 09:59:58 +02:00
Samy Pessé 6b844213ec Update theme-default@1.0.0-pre.6 2016-04-11 09:59:18 +02:00
Samy Pessé dabdeb8a80 Fix #1195: fix external images and fix test for it 2016-04-11 09:56:13 +02:00
Samy Pessé ecd56315e6 Merge pull request #1220 from seanlane/patch-1
Fix minor spelling error.
2016-04-11 09:34:15 +02:00
Sean Lane 15b9e839e9 Fix minor spelling error. 2016-04-10 14:31:49 -06:00
Samy Pesse d7f7dcd47b Switch to ignore@3.1.1 2016-04-10 22:28:29 +02:00
Samy Pessé b1981e09b8 Fix generator deprecation warning being shown for each call 2016-04-10 18:20:51 +02:00
Samy Pessé c9edd0a795 Load plugins from book parent in multilingual book 2016-04-09 12:16:17 +02:00
Samy Pesse d83e0716bb Add test for main language in json output 2016-04-08 23:58:42 +02:00
Samy Pessé aed38afff3 Bump version to 3.0.0-pre.6 2016-04-08 16:35:35 +02:00
Samy Pessé 1df522e6ec Update node modules 2016-04-08 16:34:53 +02:00
Samy Pessé bd4ef2354e Merge pull request #1216 from GitbookIO/fix/ignore
Fix #1215: fix ignore rules not working
2016-04-08 15:48:33 +02:00
Samy Pessé 32a49a6969 Inherit ignore rules of output from book 2016-04-08 15:46:46 +02:00
Samy Pessé 21806687e6 Add base tests for fiailng ignore 2016-04-08 15:23:46 +02:00
Samy Pessé 7ade91a091 Disable ssh test when ci 2016-04-08 15:11:54 +02:00
Samy Pessé 4e41f96d89 Add "languages" property to all json files for multilingual book 2016-04-08 14:42:37 +02:00
Johan Preynat 325c32b4c9 Update gitbook-plugin-highlight@2.0.2 2016-04-06 10:50:03 +02:00
Samy Pessé 7d6606a8e5 Merge pull request #1202 from qjcg/patch-1
Proofreading
2016-04-06 09:19:37 +02:00
Samy Pessé c887d520eb Update github-slugid@1.0.1 2016-04-04 11:05:42 +02:00
John Gosset e6050fc558 Proofreading
A few proofreading changes with clarity in mind.
2016-03-31 13:23:15 -04:00
Samy Pessé cae4853334 Merge pull request #1194 from jashaj/master
Fix for incorrect splitting the plugin name/version
2016-03-24 21:50:26 +01:00
Jasha Joachimsthal 9ef2bebfe9 Misinterpreted second argument of String.prototype.split. Remainder of the array must be joined instead. 2016-03-24 21:21:23 +01:00
Samy Pessé 53294af810 Merge pull request #1192 from jashaj/master
Limit splitting plugin name for git with authentication
2016-03-24 16:54:29 +01:00
Jasha Joachimsthal 7d21c815a5 Limit splitting plugin name for git+ssh 2016-03-24 15:23:28 +01:00
Samy Pessé e07719a86c Fix template search paths to use plugins listed first 2016-03-22 10:59:25 +01:00
Soreine fa5bee6ca3 Import paragraph about Escaping nunchuck from old doc. 2016-03-21 15:07:22 +01:00
Samy Pessé 3a43ef2c3f Add doc for inline rendering 2016-03-18 11:55:24 +01:00
Samy Pessé 55deab03cd Add test for blocks markdown/asciidoc/markup 2016-03-18 11:26:31 +01:00
Samy Pessé edda84fefd Add block "markdown", "asciidoc" and "markup" 2016-03-18 11:20:57 +01:00
Samy Pessé 10b191f631 Use stabler block anchor in template output 2016-03-18 11:17:26 +01:00
Samy Pessé d5a575c5e0 Fix context for template block/filters 2016-03-18 11:14:04 +01:00
Samy Pessé 82d8c3e2d9 Add method renderInline and renderBlock to book 2016-03-18 11:10:58 +01:00
Samy Pessé bc0c8dbcf3 Update nunjucks@2.4.1 2016-03-18 11:07:21 +01:00
Samy Pessé de0245ff40 Update nunjucks@2.4.1 2016-03-18 11:03:22 +01:00
Samy Pessé 7f56ff0281 Fix doc for paragraph 2016-03-17 11:53:28 +01:00
Samy Pessé 2cfbf5411c Add question about text direction in the faq 2016-03-17 10:41:34 +01:00
Samy Pessé f70da1c82a Fix links in readme 2016-03-15 12:40:40 +01:00
Samy Pessé 0b4db49f57 Merge pull request #1181 from GitbookIO/feature/allplugins_tpl
All plugins can extend templates/theme
2016-03-15 12:37:52 +01:00
Samy Pessé fbffd54aa2 Load all plugins, even dependencies of plugins 2016-03-15 12:37:25 +01:00
Samy Pessé 4d19a33af2 Add method registry.list to list all plugins for a book 2016-03-15 11:43:37 +01:00
Samy Pessé 9d67a0e656 Add theme for extending theme from book 2016-03-11 11:21:47 +01:00
Samy Pessé 093005bfd9 Fix FSLoader for relative paths 2016-03-11 10:51:36 +01:00
Samy Pessé 514883f0bd Create new loader for nunjucks to avoid infinite loop 2016-03-11 10:43:37 +01:00
Samy Pessé 27681aad98 Update nunjucks@2.4.0 2016-03-11 10:20:26 +01:00
Samy Pessé 0d367da776 Use complete list of plugins for templates resolution / i18n / assets 2016-03-09 16:45:27 +01:00
Samy Pessé c499a8a13a Add back gitbook.generator property as deprecated 2016-03-09 15:50:38 +01:00
Samy Pessé 64a6de751d Change documentation's title 2016-03-09 15:22:04 +01:00
Samy Pessé d39f0d6ff0 Add "output" variables for templating 2016-03-09 15:18:57 +01:00
Samy Pessé bdbfbf7300 Merge doc for ebook and cover 2016-03-09 11:10:52 +01:00
Samy Pessé ccac3d2c3c Publish compleet reference of markdown syntax for gitbook 2016-03-08 17:26:36 +01:00
Samy Pessé f07278490f Add question about rtl to faq 2016-03-08 09:26:46 +01:00
Samy Pessé f1880fc53c Fix incorrect link in themes doc 2016-03-07 15:20:27 +01:00
Samy Pessé e8fe4a2dea Improve docs for plugins 2016-03-07 15:15:41 +01:00
Samy Pessé 1d79507665 Add book to templating context 2016-03-07 14:52:30 +01:00
Samy Pessé f05dc67887 Improve version suggestion 2016-03-07 14:06:58 +01:00
Samy Pessé ca5e57c3b7 Bump version to 3.0.0-pre.5 2016-03-07 12:26:52 +01:00
Samy Pessé 6b1fabdd92 Update theme-default@1.0.0-pre.5 2016-03-07 12:26:22 +01:00
Samy Pessé 35f0581c17 Bump version to 3.0.0-pre.4 2016-03-07 11:16:43 +01:00
Samy Pessé c79f02fe48 Add sitemap plugin for docs 2016-03-07 11:16:27 +01:00
Samy Pessé ec028a1c0d Add deprecated methods isSubBook and contentPath 2016-03-07 11:16:13 +01:00
Samy Pessé e3155dd13a Update plugin-search@1.2.0 2016-03-07 11:00:16 +01:00
Samy Pessé b61254dda6 Add more deprecated api 2016-03-07 11:00:01 +01:00
Samy Pessé b4bdf97cfe Fix linting errors 2016-03-07 10:40:25 +01:00
Samy Pessé bf98984012 Add link to slack 2016-03-07 10:28:44 +01:00
Samy Pessé 77258cbbc9 Improve intro for doc 2016-03-07 10:27:31 +01:00
Samy Pessé 4150455c3e Improve docs 2016-03-07 10:10:38 +01:00
Samy Pessé 008aacb5c2 Fix log when installing plugins 2016-03-07 09:41:59 +01:00
Samy Pessé d12d6a6a46 Fix deprecated method root for send module 2016-03-07 09:41:05 +01:00
Samy Pessé ef7594b8f7 Remove section about autocover 2016-03-07 09:38:56 +01:00
Soreine 6a73217740 Adds section for covers 2016-03-06 09:08:48 +01:00
Samy Pesse 47c44fca89 Add changelog for master 2016-03-05 22:39:11 +01:00
Samy Pesse 6fa63a5c35 Fix #1172: Fix second argument for ebook generation 2016-03-05 22:37:25 +01:00
Samy Pessé 29533908c2 Merge pull request #1168 from GitbookIO/enhancement/doc
v3 doc review
2016-03-05 15:14:17 +01:00
Soreine 74a1e9dee2 Corrects paths. And reformulate associated FAQ 2016-03-03 16:39:18 +01:00
Soreine b3662e07c1 End of review 2016-03-03 16:39:18 +01:00
Soreine 200e0c58c9 More precise git url ? 2016-03-03 16:39:17 +01:00
Soreine e67286c51d Reviewing, first part 2016-03-03 16:39:17 +01:00
Soreine 603622e337 Update plugin-highlight version to 2.0.0 2016-03-03 16:38:09 +01:00
Samy Pessé 5c2a435a25 Update everything (npm, etc) 2016-03-02 11:22:24 +01:00
Samy Pessé 4afcd722ae Fix page description tests 2016-03-02 11:22:12 +01:00
Samy Pessé 21d6964230 Extend "page" with frontmatter attributes 2016-03-02 11:11:39 +01:00
Samy Pessé 4499ccc501 Explicitly use current version as gitbook version to build 2016-03-02 10:01:32 +01:00
59 changed files with 1452 additions and 367 deletions
+5 -1
View File
@@ -13,8 +13,12 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Markdown parser is now using CommonMark
- Root folder for the book can be specified in a `.gitbook` file
- Multi-lingual books share assets folder
- YAML front matter is parsed and page's description can be specified in it
- YAML front matter is parsed and can extend page's properties
- Fix `uk` translation
- Fix heading ID including dashes
- Fix error in code highlighting for unknown languages
- Accept SSH url as plugin version
- Add templating blocks `markdown`, `asciidoc` and `markup`
## 2.6.7
- Fix bug with filenames including spaces
+9 -9
View File
@@ -12,7 +12,7 @@ You can publish and host books easily online using [gitbook.com](https://www.git
Check out the [GitBook Community Slack Channel](https://slack.gitbook.com), Stay updated by following [@GitBookIO](https://twitter.com/GitBookIO) on Twitter or [GitBook](https://www.facebook.com/gitbookcom) on Facebook.
Complete documentation is available at [help.gitbook.com](http://help.gitbook.com/).
Complete documentation is available at [toolchain.gitbook.com](http://toolchain.gitbook.com/).
![Image](https://raw.github.com/GitbookIO/gitbook/master/preview.png)
@@ -32,14 +32,14 @@ We're always happy to help out with your books or any other questions you might
## Features
* [Output as a website or ebook (pdf, epub, mobi)](http://help.gitbook.com/format/output.html)
* [Multi-Languages](http://help.gitbook.com/format/languages.html)
* [Glossary](http://help.gitbook.com/format/glossary.html)
* [Cover](http://help.gitbook.com/format/cover.html)
* [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/format/plugins.html)
* Write using [Markdown](http://toolchain.gitbook.com/syntax/markdown.html) or [AsciiDoc](http://toolchain.gitbook.com/syntax/asciidoc.html)
* Output as a website or [ebook (pdf, epub, mobi)](http://toolchain.gitbook.com/ebook.html)
* [Multi-Languages](http://toolchain.gitbook.com/languages.html)
* [Lexicon / Glossary](http://toolchain.gitbook.com/lexicon.html)
* [Cover](http://toolchain.gitbook.com/ebook.html)
* [Variables and Templating](http://toolchain.gitbook.com/templating/)
* [Content References](http://toolchain.gitbook.com/templating/conrefs.html)
* [Plugins](http://toolchain.gitbook.com/plugins/)
* [Beautiful default theme](https://github.com/GitbookIO/theme-default)
## Publish your book
+14 -2
View File
@@ -1,12 +1,24 @@
var pkg = require('./package.json');
module.exports = {
// Documentation for GitBook is stored under "docs"
root: './docs',
title: 'GitBook Documentation',
title: 'GitBook Toolchain Documentation',
plugins: ['theme-official'],
// Enforce use of GitBook v3
gitbook: pkg.version,
// Use the "official" theme
plugins: ['theme-official', 'sitemap'],
theme: 'official',
variables: {
version: pkg.version
},
pluginsConfig: {
sitemap: {
hostname: 'https://docs.gitbook.com'
}
}
};
+9 -5
View File
@@ -1,10 +1,12 @@
# GitBook Format Documentation
# GitBook Toolchain Documentation
> This documentation is for GitBook version **{{ book.version }}**
This document aims to be a comprehensive guide to GitBook. It contains the full documentation for version **{{ book.version }}**. Help for GitBook.com specific questions can be found at [help.gitbook.com](https://help.gitbook.com).
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). This documentation has been generated using GitBook.
### What is GitBook?
GitBook can output your content as a website ([customizable](themes.md) and [extensibles](plugins.md)) or as an ebook (PDF, ePub or Mobi).
GitBook is a command line tool (and Node.js library) for building beautiful books using GitHub/Git and Markdown (or AsciiDoc). . This documentation has been generated using GitBook.
GitBook can output your content as a website ([customizable](themes/README.md) and [extensibles](plugins/README.md)) or as an ebook (PDF, ePub or Mobi).
[GitBook.com](https://www.gitbook.com) is the online platform to create and host books built using the GitBook format. It offers hosting, collaboration features and an [easy-to-use editor](https://www.gitbook.com/editor).
@@ -12,9 +14,11 @@ GitBook can output your content as a website ([customizable](themes.md) and [ext
We're always happy to help out with your books or any other questions you might have. You can ask a question on the following contact form at [gitbook.com/contact](https://www.gitbook.com/contact) or signal an issue on [GitHub](https://github.com/GitbookIO/gitbook).
Check out the [GitBook Community Slack Channel](https://slack.gitbook.com), Stay updated by following [@GitBookIO](https://twitter.com/GitBookIO) on Twitter or [GitBook](https://www.facebook.com/gitbookcom) on Facebook.
### FAQ
There are questions that are asked quite often, [check this out before creating an issue](faq.md).
Some questions are frequently asked. If you have a problem you should [check this out](faq.md) first.
### Contribute to this documentation
+18 -1
View File
@@ -12,15 +12,32 @@
* [Configuration](config.md)
* [Glossary](lexicon.md)
* [Multi-Lingual](languages.md)
* [AsciiDoc](asciidoc.md)
* [Markdown](syntax/markdown.md)
* [Headings](syntax/markdown.md#headings)
* [Paragraphs](syntax/markdown.md#paragraphs)
* [Lists](syntax/markdown.md#lists)
* [Links](syntax/markdown.md#links)
* [Images](syntax/markdown.md#images)
* [Blockquotes](syntax/markdown.md#blockquotes)
* [Tables](syntax/markdown.md#tables)
* [Code](syntax/markdown.md#code)
* [HTML](syntax/markdown.md#html)
* [Footnotes](syntax/markdown.md#footnotes)
* [AsciiDoc](syntax/asciidoc.md)
* [eBook and PDF](ebook.md)
### Customization
* [Templating](templating/README.md)
* [Content References](templating/conrefs.md)
* [Variables](templating/variables.md)
* [Builtin](templating/builtin.md)
* [Plugins](plugins/README.md)
* [Create a plugin](plugins/create.md)
* [Hooks](plugins/hooks.md)
* [Blocks](plugins/blocks.md)
* [Filters](plugins/filters.md)
* [API & Context](plugins/api.md)
* [Test your plugin](plugins/testing.md)
* [Theming](themes/README.md)
+4 -1
View File
@@ -1,9 +1,12 @@
{% extends template.theme %}
{% extends template.self %}
{% block header_nav %}
<a href="https://github.com/GitbookIO/gitbook/blob/master/docs/{{ file.path }}" target="_blank" class="btn btn-link pull-right hidden-xs">
<i class="octicon octicon-mark-github"></i> Edit on GitHub
</a>
<a href="{{ "faq.md"|resolveFile }}" class="btn btn-link pull-right hidden-xs">
F.A.Q
</a>
<a href="https://github.com/GitbookIO/gitbook/blob/master/CHANGES.md" target="_blank" class="btn btn-link pull-right hidden-xs">
{{ book.version }}
</a>
+23 -13
View File
@@ -1,21 +1,36 @@
# Configuration
GitBook allows you to customize your book using a flexible configuration. These options are specified in a `book.json` file. For authors, not used to write JSON, you can validate the syntax using [jsonlint](http://jsonlint.com).
GitBook allows you to customize your book using a flexible configuration. These options are specified in a `book.json` file. For authors unfamiliar with the JSON syntax, you can validate the syntax using tools such as [JSONlint](http://jsonlint.com).
### Configuration Settings
### General Settings
| Variable | Description |
| -------- | ----------- |
| `root` | Path to the root folder containing the content |
| `root` | Path to the root folder containing all the book's files, except `book.json`|
| `title` | Title of your book, default value is extracted from the README. On GitBook.com this field is pre-filled. |
| `description` | Description of your book, default value is extracted from the README. On GitBook.com this field is pre-filled. |
| `author` | Name of the author. On GitBook.com this field is pre-filled. |
| `isbn` | ISBN of the book |
| `language` | ISO code of the book's language, default value is `en` |
| `direction` | `rtl` or `ltr`, default value depends on the value of `language` |
| `gitbook` | [SemVer](http://semver.org) condition to validate which GitBook version should be used |
| `plugins` | List of plugins to load, See [the plugins section](plugins/README.md) for more details |
| `pluginsConfig` |Configuration for plugins, See [the plugins section](plugins/README.md) for more details |
| `language` | [ISO code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) of the book's language, default value is `en` |
| `direction` | Text's direction. Can be `rtl` or `ltr`, the default value depends on the value of `language` |
| `gitbook` | Version of GitBook that should be used. Uses the [SemVer](http://semver.org) specification and accepts conditions like `">= 3.0.0"` |
### Plugins
Plugins and their configurations are specified in the `book.json`. See [the plugins section](plugins/README.md) for more details.
| Variable | Description |
| -------- | ----------- |
| `plugins` | List of plugins to load |
| `pluginsConfig` |Configuration for plugins |
### Theme
Since version 3.0.0, GitBook can use themes. See [the theming section](themes/README.md) for more details.
| Variable | Description |
| -------- | ----------- |
| `theme` | The theme to use for the book |
### PDF Options
@@ -31,8 +46,3 @@ PDF Output can be customized using a set of options in the `book.json`:
| `pdf.margin.bottom` | Bottom margin (default is `56`) |
| `pdf.margin.right` | Right margin (default is `62`) |
| `pdf.margin.left` | Left margin (default is `62`) |
### Plugins
Plugins and their configurations are specified in the `book.json`. See [the plugins section](plugins/README.md) for more details.
+29
View File
@@ -0,0 +1,29 @@
# Generating eBooks and PDFs
GitBook can generates a website, but can also output content as ebook (ePub, Mobi, PDF).
### Installing ebook-convert
`ebook-convert` is required to generate ebooks (epub, mobi, pdf).
##### OS X
Download the [Calibre application](https://calibre-ebook.com/download). After moving the `calibre.app` to your Applications folder create a symbolic link to the ebook-convert tool:
```
$ sudo ln -s ~/Applications/calibre.app/Contents/MacOS/ebook-convert /usr/bin
```
You can replace `/usr/bin` with any directory that is in your $PATH.
### Cover
Covers are used for all the ebook formats. It's an important part of an ebook brandline.
A good cover should respect the following guidelines:
* Size of 1800x2360 (pixels)
* No border
* Clearly visible book title
* Any important text should be visible in the small version
+3 -3
View File
@@ -4,7 +4,7 @@ description: Real world examples of content published using GitBook.
# Examples
More than 50,000 books have benn published on [GitBook.com](https://www.gitbook.com/explore).
More than 50,000 books have been published on [GitBook.com](https://www.gitbook.com/explore).
### Books
@@ -17,11 +17,11 @@ More than 50,000 books have benn published on [GitBook.com](https://www.gitbook.
### Research Papers
- [TowCenter Collection](https://www.gitbook.com/@towcenter) by [Columbia Journalism School]()
- [TowCenter Collection](https://www.gitbook.com/@towcenter) by [Columbia Journalism School](http://www.journalism.columbia.edu/)
- [Block Relaxation Algorithms in Statistics](https://www.gitbook.com/@jandeleeuw) by Jan de Leeuw
### Documentation
- [DuckDuckHack Documentation](http://docs.duckduckhack.com) by DuckDuckGo
- [DuckDuckHack Documentation](http://docs.duckduckhack.com) by [DuckDuckGo](https://duckduckgo.com/about)
- This documentation
+25 -3
View File
@@ -1,5 +1,9 @@
# GitBook FAQ
This page gathers common questions and answers concerning the GitBook format and toolchain.
Questions about GitBook.com and the Editor are gather into the [help.gitbook.com's FAQ](http://help.gitbook.com/faq.html).
#### How can I host/publish my book?
Books can easily be published and hosted on [GitBook.com](https://www.gitbook.com). But GitBook output can be hosted on any static file hosting solution.
@@ -10,14 +14,32 @@ Any text editor should work! But we advise using the [GitBook Editor](https://ww
---
#### Does GitBook supports RTL/bi-directional text ?
The GitBook format supports right to left, and bi-directional writing. To enable it, you either need to specify a language (ex: `ar`), or force GitBook to use RTL in your `book.json`:
``` json
{
"language": "ar",
"direction": "rtl"
}
```
With version 3.0 of GitBook, it's automatically detected according to the content.
_Note that, while the output book will indeed respect RTL, the Editor doesn't support RTL writing yet_.
#### Should I use an `.html` or `.md` extensions in my links?
You should always use `.md` extensions for your relative links, GitBook will automatically replace these links by the right value when the pointing file is referenced in the Table of Contents.
You should always use paths and the `.md` extensions when linking to your files, GitBook will automatically replace these paths by the appropriate link when the pointing file is referenced in the Table of Contents.
#### Can I create a GitBook in a sub-directory of my repository?
Yes, GitBooks can be created in [sub-directories](structure.md#subdirectory). GitBook.com and the CLI also looks by default in a serie of [folders](structure.md).
#### Does GitBook supports RTL languages?
Yes, GitBook automatically detect the direction in your pages (`rtl` or `ltr`) and adjust the layout accordingly. The direction can also be specified globally in the [book.json](config.md).
---
#### Does GitBook support Math equations?
@@ -26,8 +48,8 @@ GitBook supports math equations and TeX thanks to plugins. There are currently 2
#### Can I customize/theme the output?
Yes, both the website and ebook outputs can be customized using [themes](themes.md).
Yes, both the website and ebook outputs can be customized using [themes](themes/README.md).
#### Can I add interactive content (videos, etc)?
GitBook is very [extensible](plugins.md). You can use [existing plugins](https://plugins.gitbook.com) or create your own!
GitBook is very [extensible](plugins/README.md). You can use [existing plugins](https://plugins.gitbook.com) or create your own!
+1 -1
View File
@@ -14,4 +14,4 @@ GitBook supports building books written in multiple languages. Each language sho
When a language book (ex: `en`) has a `book.json`, its configuration will extend the main configuration.
The only exception is plugins, plugins are specify globally relative to the book, and language specific plugins can not be specified.
The only exception is plugins, plugins are specified globally, and language specific plugins cannot be specified.
+4 -3
View File
@@ -1,6 +1,6 @@
# Glossary
Allows you to specify terms and their respective definitions to be displayed as annotations. Based on those terms, gitbook will automatically build an index and highlight those terms in pages.
Allows you to specify terms and their respective definitions to be displayed as annotations. Based on those terms, GitBook will automatically build an index and highlight those terms in pages.
The `GLOSSARY.md` format is very simple :
@@ -9,5 +9,6 @@ The `GLOSSARY.md` format is very simple :
Definition for this term
# Another term
With it's definition, this can contain bold text and all other kinds of inline markup ...
```
With it's definition, this can contain bold text
and all other kinds of inline markup ...
```
+62 -8
View File
@@ -1,12 +1,12 @@
# Pages and Summary
GitBook uses a `SUMMARY.md` file to define the structure of chapters and subchapters of the book. The `SUMMARY.md` file is used to generate the book's table of contents.
### Summary
The `SUMMARY.md`'s format is simply a list of links, the title of the link is used as the chapter's title, and the target is a path to that chapter's file.
GitBook uses a `SUMMARY.md` file to define the structure of chapters and subchapters of the book. The `SUMMARY.md` file is used to generate the book's table of contents.
Subchapters are defined simply by adding a nested list to a parent chapter.
The format of `SUMMARY.md` is just a list of links. The link's title is used as the chapter's title, and the link's target is a path to that chapter's file.
Adding a nested list to a parent chapter will create subchapters.
##### Simple example
@@ -21,23 +21,74 @@ Subchapters are defined simply by adding a nested list to a parent chapter.
* [Better tools for authors](part2/better_tools.md)
```
##### Example with subchapters split into parts
Each chapter has a dedicated page (`part#/README.md`) and is split into subchapters.
##### Anchors
Chapters in the Table of Contents can be pointing to specific part of a file using anchor.
```markdown
# Summary
### Part 1
### Part I
* [Part I](part1/README.md)
* [Writing is nice](part1/README.md#writing)
* [GitBook is nice](part1/README.md#gitbook)
* [Part II](part2/README.md)
* [We love feedback](part2/README.md#feedback)
* [Better tools for authors](part2/README.md#tools)
```
##### Parts
The Table of Contents can be divided into parts separated by headings or horizontal lines:
```markdown
# Summary
### Part I
* [Writing is nice](part1/writing.md)
* [GitBook is nice](part1/gitbook.md)
### Part 2
### Part II
* [We love feedback](part2/feedback_please.md)
* [Better tools for authors](part2/better_tools.md)
----
* [Last part without title](part3/title.md)
```
### Front Matter
Parts are just groups of chapters and do not have dedicated pages, but according to the theme, it will show in the navigation.
### Pages
#### Markdown syntax
Most of the files for GitBook use the Markdown syntax by default. GitBook infers your pages's structure from it. The syntax used is similar to the [GitHub Flavored Markdown syntax](https://guides.github.com/features/mastering-markdown/). One can also opt for the [AsciiDoc syntax](asciidoc.md).
##### Example of a chapter file
``` markdown
# Title of the chapter
This is a great introduction.
## Section 1
Markdown will dictates _most_ of your **book's structure**
## Section 2
...
```
#### Front Matter
Pages can contain an optional front matter. It can be used to define the page's description. The front matter must be the first thing in the file and must take the form of valid YAML set between triple-dashed lines. Here is a basic example:
@@ -47,4 +98,7 @@ description: This is a short description of my page
---
# The content of my page
...
```
The front matter can define variables of your own, they will be added to the [page variable](templating/variables.md) so you can use them in your templating.
+1 -1
View File
@@ -25,4 +25,4 @@ Plugins are automatically installed on [GitBook.com](https://www.gitbook.com). L
### Configuring plugins
PLugins specific configurations are stored in `pluginsConfig`. You have to refer to the documentation of the plugin itself for details about the available options.
Plugins specific configurations are stored in `pluginsConfig`. You have to refer to the documentation of the plugin itself for details about the available options.
+97
View File
@@ -0,0 +1,97 @@
# Context and APIs
GitBooks provides different APIs and contexts to plugins. These APIs can vary according to the GitBook version being used, your plugin should specify the `engines.gitbook` field in `package.json` accordingly.
#### Book instance
The `Book` class is the central point of GitBook, it centralize all access read methods. This class is defined in [book.js](https://github.com/GitbookIO/gitbook/blob/master/lib/book.js).
```js
// Read configuration from book.json
var value = book.config.get('title', 'Default Value');
// Resolve a filename to an absolute path
var filepath = book.resolve('README.md');
// Render an inline markup string
book.renderInline('markdown', 'This is **Markdown**')
.then(function(str) { ... })
// Render a markup string (block mode)
book.renderBlock('markdown', '* This is **Markdown**')
.then(function(str) { ... })
```
#### Output instance
The `Output` class represent the output/write process.
```js
// Return root folder for the output
var root = output.root();
// Resolve a file in the output folder
var filepath = output.resolve('myimage.png');
// Convert a filename to an URL (returns a path to an html file)
var fileurl = output.toURL('mychapter/README.md');
// Write a file in the output folder
output.write('hello.txt', 'Hello World')
.then(function() { ... });
// Copy a file to the output folder
output.copyFile('./myfile.jpg', 'cover.jpg')
.then(function() { ... });
// Verify that a file exists
output.hasFile('hello.txt')
.then(function(exists) { ... });
```
#### Page instance
A page instance represent the current parsed page.
```js
// Title of the page (from SUMMARY)
page.title
// Content of the page (Markdown/Asciidoc/HTML according to the stage)
page.content
// Relative path in the book
page.path
// Absolute path to the file
page.rawPath
// Type of parser used for this file
page.type ('markdown' or 'asciidoc')
```
#### Context for Blocks and Filters
Blocks and filters have access to the same context, this context is bind to the template engine execution:
```js
{
// Current templating syntax
"ctx": {
// For example, after a {% set message = "hello" %}
"message": "hello"
},
// Book instance
"book" <Book>,
// Output instance
"output": <Output>
}
```
For example a filter or block function can access the current book using: `this.book`.
#### Context for Hooks
Hooks only have access to the `<Book>` instance using `this.book`.
+62
View File
@@ -0,0 +1,62 @@
# Extend Blocks
Extending templating blocks is the best way to provide extra functionalities to authors.
The most common usage is to process the content within some tags at runtime. It's like [filters](./filters.md), but on steroids because you aren't confined to a single expression.
### Defining a new block
Blocks are defined by the plugin, blocks is a map of name associated with a block descriptor. The block descriptor needs to contain at least a `process` method.
```js
module.exports = {
blocks: {
tag1: {
process: function(block) {
return "Hello "+block.body+", How are you?";
}
}
}
};
```
The `process` should return the html content that will replace the tag. Refer to [Context and APIs](./api.md) to learn more about `this` and GitBook API.
### Handling block arguments
Arguments can be passed to blocks:
```
{% tag1 "argument 1", "argument 2", name="Test" %}
This is the body of the block.
{% endtag1 %}
```
And arguments are easily accessible in the `process` method:
```js
module.exports = {
blocks: {
tag1: {
process: function(block) {
// block.args equals ["argument 1", "argument 2"]
// block.kwargs equals { "name": "Test" }
}
}
}
};
```
### Handling sub-blocks
A defined block can be parsed into different sub-blocks, for example let's consider the source:
```
{% myTag %}
Main body
{% subblock1 %}
Body of sub-block 1
{% subblock 2 %}
Body of sub-block 1
{% endmyTag %}
```
+12 -1
View File
@@ -8,13 +8,24 @@ A GitBook plugin is a node package published on NPM that follow a defined conven
The `package.json` is a manifest format for describing **Node.js modules**. GitBook plugins are built on top of Node modules. It declares dependencies, version, ownership, and other information required to run a plugin in GitBook. This document describes the schema in detail.
```
A plugin manifest `package.json` can also contain details about the required configuration. The configuration schema is defined in the `gitbook` field of the `package.json` (This field follow the [JSON-Schema](http://json-schema.org) guidelines):
```js
{
"name": "gitbook-plugin-mytest",
"version": "0.0.1",
"description": "This is my first GitBook plugin",
"engines": {
"gitbook": ">1.x.x"
},
"gitbook": {
"properties": {
"myConfigKey": {
"type": "string",
"default": "it's the default value",
"description": "It defines my awesome config!"
}
}
}
}
```
+57
View File
@@ -0,0 +1,57 @@
# Extend Filters
Filters are essentially functions that can be applied to variables. They are called with a pipe operator (`|`) and can take arguments.
```
{{ foo | title }}
{{ foo | join(",") }}
{{ foo | replace("foo", "bar") | capitalize }}
```
### Defining a new filter
Plugins can extend filters by defining custom functions in their entry point under the `filters` scope.
A filter function takes as first argument the content to filter, and should return the new content.
Refer to [Context and APIs](./api.md) to learn more about `this` and GitBook API.
```js
module.exports = {
filters: {
hello: function(name) {
return 'Hello '+name;
}
}
};
```
The filter `hello` can then be used in the book:
```
{{ "Aaron"|hello }}, how are you?
```
### Handling block arguments
Arguments can be passed to filters:
```
Hello {{ "Samy"|fullName("Pesse", man=true}} }}
```
Arguments are passed to the function, named-arguments are passed as a last argument (object).
```js
module.exports = {
filters: {
fullName: function(firstName, lastName, kwargs) {
var name = firstName + ' ' + lastName;
if (kwargs.man) name = "Mr" + name;
else name = "Mrs" + name;
return name;
}
}
};
```
+90
View File
@@ -0,0 +1,90 @@
# Hooks
Hooks is a method of augmenting or altering the behavior of the process, with custom callbacks.
### List of hooks
### Relative to the global pipeline
| Name | Description | Arguments |
| ---- | ----------- | --------- |
| `init` | Called after parsing the book, before generating output and pages. | None |
| `finish:before` | Called after generating the pages, before copying assets, cover, ... | None |
| `finish` | Called after everything else. | None |
### Relative to the page pipeline
> It is recommended using [templating](./templating.md) to extend page parsing.
| Name | Description | Arguments |
| ---- | ----------- | --------- |
| `page:before` | Called before running the templating engine on the page | Page Object |
| `page` | Called before outputting and indexing the page. | Page Object |
##### Page Object
```js
{
// Parser named
"type": "markdown",
// File Path relative to book root
"path": "page.md",
// Absolute file path
"rawpath": "/usr/...",
// Title of the page in the SUMMARY
"title": "",
// Content of the page
// Markdown/Asciidoc in "page:before"
// HTML in "page"
"content": "# Hello"
}
```
##### Example to add a title
In the `page:before` hook, `page.content` is the markdown/asciidoc content.
```js
{
"page:before": function(page) {
page.content = "# Title\n" +page.content;
return page;
}
}
```
##### Example to replace some html
In the `page` hook, `page.content` is the HTML generated from the markdown/asciidoc conversion.
```js
{
"page": function(page) {
page.content = page.content.replace("<b>", "<strong>")
.replace("</b>", "</strong>");
return page;
}
}
```
### Asynchronous Operations
Hooks callbacks can be asynchronous and return promises.
Example:
```js
{
"init": function() {
return writeSomeFile()
.then(function() {
return writeAnotherFile();
});
}
}
```
+5 -5
View File
@@ -4,7 +4,7 @@ Getting GitBook installed and ready-to-go should only take a few minutes.
### GitBook.com
[GitBook.com](https://www.gitbook.com) is an easy to use solution to write, publish and host books. It's best and easier solution for publishing your content and collaborate on it.
[GitBook.com](https://www.gitbook.com) is an easy to use solution to write, publish and host books. It is the easiest solution for publishing your content and collaborating on it.
It integrates well with the [GitBook Editor](https://www.gitbook.com/editor).
@@ -12,7 +12,7 @@ It integrates well with the [GitBook Editor](https://www.gitbook.com/editor).
##### Requirements
Installing GitBook is easy and straight-forward, but there are a few requirements you’ll need to make sure your system has before you start.
Installing GitBook is easy and straightforward. Your system just needs to meet these two requirements:
* NodeJS (v4.0.0 and above are adviced)
* Windows, Linux, Unix, or Mac OS X
@@ -25,7 +25,7 @@ The best way to install GitBook is via **NPM**. At the terminal prompt, simply r
$ npm install gitbook-cli -g
```
`gitbook-cli` is an utility to install and use multiple versions of GitBook on the same system. It will automatically install the required version to build a book.
`gitbook-cli` is an utility to install and use multiple versions of GitBook on the same system. It will automatically install the required version of GitBook to build a book.
##### Create a book
@@ -43,7 +43,7 @@ Preview and serve your book using:
$ gitbook serve
```
or build the static website using:
Or build the static website using:
```
$ gitbook build
@@ -51,7 +51,7 @@ $ gitbook build
##### Install pre-releases
`gitbook-cli` makes it easy to install and test other versions of GitBook with your book:
`gitbook-cli` makes it easy to download and install other versions of GitBook to test with your book:
```
$ gitbook fetch beta
+10 -8
View File
@@ -1,6 +1,8 @@
# Directory structure
# Directory Structure
GitBook uses a very simple and obvious directory structure:
GitBook uses a simple directory structure. All Markdown/Asciidoc files listed in the [SUMMARY](pages.md) will be transformed as HTML. Multi-Lingual books have a slightly [different structure](languages.md).
A basic GitBook usually looks something like this:
```
.
@@ -21,19 +23,19 @@ An overview of what each of these does:
| -------- | ----------- |
| `book.json` | Stores [configuration](config.md) data (__optional__) |
| `README.md` | Preface / Introduction for your book (**required**) |
| `SUMMARY.md` | Table of Contents |
| `SUMMARY.md` | Table of Contents (See [Pages](pages.md)) (__optional__) |
| `GLOSSARY.md` | Lexicon / List of terms to annotate (See [Glossary](lexicon.md)) (__optional__) |
### Static files and Images
A static file is a file that is not listed in the `SUMMARY.md`. All static files, not [ignored](#ignore), are copied to the output.
A static file is a file that is not listed in the `SUMMARY.md`. All static files, unless [ignored](#ignore), are copied to the output.
### Ignoring files & folders {#ignore}
GitBook will read the `.gitignore`, `.bookignore` and `.ignore` files to get a list of files and folders to skip.
The format inside those files, follows the same convention as `.gitignore`:
```markdown
```
# This is a comment
# Ignore the file test.md
@@ -43,9 +45,9 @@ test.md
bin/*
```
### Project documentation / Sub-directory {#subdirectory}
### Project integration with subdirectory {#subdirectory}
For software project, it sometimes better to use a diretcory (like `docs/`) to store the project's documentation. You can use the [`root` option](config.md) to indicate to GitBook in which folder the book is stored:
For software projects, you can use a subdirectory (like `docs/`) to store the book for the project's documentation. You can configure the [`root` option](config.md) to indicate the folder where GitBook can find the book's files:
```
.
+10 -5
View File
@@ -8,11 +8,11 @@ Just like for markdown, GitBook is using some special files to extract structure
### README.adoc
This is the main entry of your book: the introduction. This file is **non optional**.
This is the main entry of your book: the introduction. This file is **required**.
### SUMMARY.adoc
This file defines the list of chapters and subchapters. Just like [for markdown](./pages.md), the `SUMMARY.adoc`'s format is simply a list of links, the name of the link is used as the chapter's name, and the target is a path to that chapter's file.
This file defines the list of chapters and subchapters. Just like in Markdown, the `SUMMARY.adoc`'s format is simply a list of links, the name of the link is used as the chapter's name, and the target is a path to that chapter's file.
Subchapters are defined simply by adding a nested list to a parent chapter.
@@ -51,10 +51,15 @@ This file is used to define terms. [See the glossary section](./lexicon.md).
= Glossary
== Magic
Sufficiently advanced technology, beyond the understanding of the observer producing a sense of wonder.
Sufficiently advanced technology, beyond the understanding of the
observer producing a sense of wonder.
== PHP
A popular web programming language, used by many large websites such as Facebook. Rasmus Lerdorf originally created PHP in 1994 to power his personal homepage (PHP originally stood for "Personal Home Page" but now stands for "PHP: Hypertext Preprocessor").
```
A popular web programming language, used by many large websites such
as Facebook. Rasmus Lerdorf originally created PHP in 1994 to power
his personal homepage (PHP originally stood for "Personal Home Page"
but now stands for "PHP: Hypertext Preprocessor"). ```
+223
View File
@@ -0,0 +1,223 @@
# Markdown
Most of the examples from this documentation are in Markdown. Markdown is default parser for GitBook, but one can also opt for the [AsciiDoc syntax](asciidoc.md).
Here’s an overview of Markdown syntax that you can use with GitBook (same as GitHub with some additions).
### Headings
To create a heading, add one to six `#` symbols before your heading text. The number of # you use will determine the size of the heading.
```markdown
# This is an <h1> tag
## This is an <h2> tag
###### This is an <h6> tag
```
GitBook supports a nice way for explicitly setting the header ID. If you follow the header text with an opening curly bracket (separated from the text with a least one space), a hash, the ID and a closing curly bracket, the ID is set on the header. If you use the trailing hash feature of atx style headers, the header ID has to go after the trailing hashes. For example:
```markdown
Hello {#id}
-----
# Hello {#id}
# Hello # {#id}
```
### Paragraphs and Line Breaks {#paragraphs}
A paragraph is simply one or more consecutive lines of text, separated by one or more blank lines. (A blank line is any line that looks like a blank line — a line containing nothing but spaces or tabs is considered blank.) Normal paragraphs should not be indented with spaces or tabs.
```
Here's a line for us to start with.
This line is separated from the one above by two newlines, so it will be a *separate paragraph*.
```
### Emphasis {#emphasis}
```markdown
*This text will be italic*
_This will also be italic_
**This text will be bold**
__This will also be bold__
~~This text will be crossed out.~~
_You **can** combine them_
```
### Lists {#lists}
Markdown supports ordered (numbered) and unordered (bulleted) lists.
##### Unordered
Unordered lists use asterisks, pluses, and hyphens — interchangably — as list markers:
```markdown
* Item 1
* Item 2
* Item 2a
* Item 2b
```
##### Ordered
Ordered lists use numbers followed by periods:
```markdown
1. Item 1
2. Item 2
3. Item 3
* Item 3a
* Item 3b
```
### Links {#links}
Markdown supports two style of links: inline and reference.
A simple link can be created by surrounding the text with square brackets and the link URL with parentheses:
```markdown
This is [an example](http://example.com/ "Title") inline link with a title.
[This link](http://example.net/) has no title attribute.
```
Links can point to relative paths, anchors or absolute urls.
### References
There is another way to create links which does not interrupt the text flow. The URL and title are defined using a reference name and this reference name is then used in square brackets instead of the link URL:
```markdown
This is [an example][id] reference-style link.
```
Then, anywhere in the document, you define your link label like this, on a line by itself:
```markdown
[id]: http://example.com/ "Optional Title Here"
```
### Images {#images}
Images can be created in a similar way than links: just use an exclamation mark before the square brackets. The link text will become the alternative text of the image and the link URL specifies the image source:
```markdown
An image: ![gras](img/image.jpg)
```
### Blockquotes {#blockquotes}
A blockquote is started using the `>` marker followed by an optional space; all following lines that are also started with the blockquote marker belong to the blockquote. You can use any block-level elements inside a blockquote:
```markdown
As Kanye West said:
> We're living the future so
> the present is our past.
```
### Tables {#tables}
You can create tables by assembling a list of words and dividing them with hyphens `-` (for the first row), and then separating each column with a pipe `|`:
```markdown
| First Header | Second Header |
| ------------- | ------------- |
| Content Cell | Content Cell |
| Content Cell | Content Cell |
```
The pipes on either end of the table are optional. Cells can vary in width and do not need to be perfectly aligned within columns. There must be at least three hyphens in each column of the header row.
### Code {#code}
Markdown supports two different code block styles. One uses lines indented with either four spaces or one tab whereas the other uses lines with tilde characters as delimiters – therefore the content does not need to be indented:
```markdown
This is a sample code block.
Continued here.
```
##### Fenced code blocks
You can create fenced code blocks by placing triple backticks ` ``` ` before and after the code block. We recommend placing a blank line before and after code blocks to make the raw formatting easier to read.
```
function test() {
console.log("notice the blank line before this function?");
}
```
##### Syntax highlighting
You can add an optional language identifier to enable syntax highlighting in your fenced code block.
For example, to syntax highlight Ruby code:
```ruby
require 'redcarpet'
markdown = Redcarpet.new("Hello World!")
puts markdown.to_html
```
##### Inline code
Text phrases can be marked up as code by surrounding them with backticks:
Use `gitbook` to convert the `text` in markdown
syntax to HTML.
### Footnotes
GitBook supports a simple syntax for such footnotes. Footnotes are relative to each pages.
```markdown
Text prior to footnote reference.[^2]
[^2]: Comment to include in footnote.
```
### HTML
GitBook supports use of raw HTML in your text, Markdown syntax in HTML is not processed:
```
<div>
Markdown here will not be **parsed**
</div>
```
### Horizontal Rule
Horizontal Rules can be inserted using three or more asterisks, dashes or underscores, optionally separated by spaces or tabs, on an otherwise blank line:
```markdown
Three or more...
---
Hyphens
***
Asterisks
```
### Ignoring Markdown formatting
You can tell GitBook to ignore (or escape) Markdown formatting by using `\` before the Markdown character.
```
Let's rename \*our-new-project\* to \*our-old-project\*.
```
+18 -9
View File
@@ -1,18 +1,18 @@
# Templating
GitBook uses the Nunjucks templating language to process pages and theme's templates.
GitBook uses the [Nunjucks templating language](https://mozilla.github.io/nunjucks/) to process pages and theme's templates.
The Nunjucks syntax is very similar to **Jinja2** or **Liquid**.
The Nunjucks syntax is very similar to **Jinja2** or **Liquid**. Its syntax uses surrounding braces `{ }` to mark content that needs to be processed.
### Variables
A variable looks up a value from the template context. If you wanted to simply display a variable, you would do:
A variable looks up a value from the template context. If you wanted to simply display a variable, you would use the `{{ variable }}` syntax. For example :
```twig
{{ username }}
My name is {{ name }}, nice to meet you
```
This looks up username from the context and displays it. Variable names can have dots in them which lookup properties, just like javascript. You can also use the square bracket syntax.
This looks up username from the context and displays it. Variable names can have dots in them which lookup properties, just like JavaScript. You can also use the square bracket syntax.
```twig
{{ foo.bar }}
@@ -21,7 +21,7 @@ This looks up username from the context and displays it. Variable names can have
If a value is undefined, nothing is displayed. The following all output nothing if foo is undefined: `{{ foo }}`, `{{ foo.bar }}`, `{{ foo.bar.baz }}`.
GitBook provides a set of [context variables](variables.md).
GitBook provides a set of [predefined variables](variables.md) from the context.
### Filters
@@ -39,7 +39,7 @@ The third example shows how you can chain filters. It would display "Bar", by fi
##### if
`if` tests a condition and lets you selectively display content. It behaves exactly as javascript's if behaves.
`if` tests a condition and lets you selectively display content. It behaves exactly as JavaScript's `if` behaves.
```twig
{% if variable %}
@@ -49,7 +49,7 @@ The third example shows how you can chain filters. It would display "Bar", by fi
If variable is defined and evaluates to true, "It is true" will be displayed. Otherwise, nothing will be.
You can specify alternate conditions with elif and else:
You can specify alternate conditions with `elif` and `else`:
```twig
{% if hungry %}
@@ -86,5 +86,14 @@ Current version is {{ softwareVersion }}.
##### include and block
Inclusion and inheritance is detailled in the [ConRefs](conrefs.md) section.
Inclusion and inheritance is detailled in the [Content References](conrefs.md) section.
### Escaping
If you want GitBook to ignore any of the special templating tags, you can use raw and anything inside of it will be output as plain text.
``` twig
{% raw %}
this will {{ not be processed }}
{% endraw %}
```
+18
View File
@@ -0,0 +1,18 @@
# Builtin Templating Helpers
GitBook provides a serie of builtin filters and blocks to help you write templates.
### Filters
`value|default(default, [boolean])`If value is strictly undefined, return default, otherwise value. If boolean is true, any JavaScript falsy value will return default (false, "", etc)
`arr|sort(reverse, caseSens, attr)`
Sort arr with JavaScript's arr.sort function. If reverse is true, result will be reversed. Sort is case-insensitive by default, but setting caseSens to true makes it case-sensitive. If attr is passed, will compare attr from each item.
### Blocks
`{% markdown %}Markdown string{% endmarkdown %}`
Render inline markdown
`{% asciidoc %}AsciiDoc string{% endasciidoc %}`
Render inline asciidoc
+4 -4
View File
@@ -1,10 +1,10 @@
# Content References
Content referencing (conref) is a convenient mechanism for reuse of content from other files or books.
Content referencing (conref) is a convenient mechanism to reuse content from other files or books.
### Importing local files
Importing an other file's content is really easy using the `include` tag:
Importing an other file's content is easy using the `include` tag:
```
{% include "./test.md" %}
@@ -21,7 +21,7 @@ GitBook can also resolve the include path by using git:
The format of git url is:
```
git+https://user@hostname/project/blah.git/file#commit-ish
git+https://user@hostname/owner/project.git/file#commit-ish
```
The real git url part should finish with `.git`, the filename to import is extracted after the `.git` till the fragment of the url.
@@ -42,7 +42,7 @@ Template inheritance is a way to make it easy to reuse templates. When writing a
{% endblock %}
```
In the file `mypage.md`, you should specify the blocks that can be extent:
In the file `mypage.md`, you should specify the blocks that can be extended:
```
{% block pageContent %}
+13 -4
View File
@@ -6,12 +6,13 @@ The following is a reference of the available data during book's parsing and the
| Variable | Description |
| -------- | ----------- |
| `book` | Bookwide information + configuration settings from `book.json`. See below for details. |
| `book` | Book-wide information + configuration settings from `book.json`. See below for details. |
| `gitbook` | GitBook specific information |
| `page` | Current page specific information |
| `file` | File associated with the current page specific information |
| `summary` | Information about the table of contents |
| `languages` | List of languages for multi-lingual books |
| `output` | Information about the output generator |
| `config` | Dump of the `book.json` |
### Book Variables
@@ -25,7 +26,7 @@ The following is a reference of the available data during book's parsing and the
| Variable | Description |
| -------- | ----------- |
| `gitbook.time` | The current time (when you run the `gitbook` command). |
| `gitbook.time` | The current time (when you run the `gitbook` command) . |
| `gitbook.version` | Version of GitBook used to generate the book |
### File Variables
@@ -33,7 +34,7 @@ The following is a reference of the available data during book's parsing and the
| Variable | Description |
| -------- | ----------- |
| `file.path` | The path to the raw page |
| `file.mtime` | Modified Time, Time when file data last modified |
| `file.mtime` | Modified Time. Last time the file was modified |
| `file.type` | The name of the parser used to compile this file (ex: `markdown`, `asciidoc`, etc) |
#### Page Variables
@@ -51,7 +52,7 @@ The following is a reference of the available data during book's parsing and the
| -------- | ----------- |
| `summary.parts` | List of sections in the Table of Contents |
Thw whole table of contents (`SUMMARY.md`) can be accessed:
The whole table of contents (`SUMMARY.md`) can be accessed:
`summary.parts[0].articles[0].title` will return the title of the first article.
@@ -62,3 +63,11 @@ Thw whole table of contents (`SUMMARY.md`) can be accessed:
| `languages.list` | List of languages for this book |
Languages are defined by `{ id: 'en', title: 'English' }`.
### Output Variables
| Variable | Description |
| -------- | ----------- |
| `output.name` | Name of the output generator, possible values are `website`, `json`, `ebook` |
| `output.format` | When `output.name == "ebook"`, `format` defines the ebook format that will be generated, possible values are `pdf`, `epub` or `mobi` |
+4 -6
View File
@@ -1,14 +1,12 @@
# Theming
Since version 3.0.0, GitBook can be easily themed. Books are using by default the [theme-default](https://github.com/GitbookIO/theme-default).
The theme to use is specified in the [book's configuration](config.md) using key `theme`.
Since version 3.0.0, GitBook can be easily themed. Books use the [theme-default](https://github.com/GitbookIO/theme-default) theme by default.
> **Caution**: Custom theming can block some plugins from working correctly.
### Structure of a theme
A theme is a folder containing templates and assets. All the templates are optionnal, since theme are always extending the default theme.
A theme is a plugin containing templates and assets. Overriding any individual template is optional, since themes always extend the default theme.
| Folder | Description |
| -------- | ----------- |
@@ -19,8 +17,8 @@ A theme is a folder containing templates and assets. All the templates are optio
### Extend/Customize theme in a book
Authors can extend the templates of a theme directly from the book source (without creating an external theme). Templates will be resolved in the `_layouts` folder of the book first, then in
Authors can extend the templates of a theme directly from their book's source (without creating an external theme). Templates will be resolved in the `_layouts` folder of the book first, then in
### Publish a theme
Themes are published as plugins ([see related docs](plugins.md)) with a `theme-` prefix. For example the theme `awesome` will be loaded from `theme-awesome` plugin, and then from `gitbook-plugin-theme-awesome` NPM package.
Themes are published as plugins ([see related docs](../plugins/README.md)) with a `theme-` prefix. For example the theme `awesome` will be loaded from the `theme-awesome` plugin, and then from the `gitbook-plugin-theme-awesome` NPM package.
+6 -11
View File
@@ -1,6 +1,5 @@
var _ = require('lodash');
var util = require('util');
var url = require('url');
var location = require('../utils/location');
var error = require('../utils/error');
@@ -32,17 +31,13 @@ function TOCArticle(def, parent) {
// Path can be a relative path or an url, or nothing
this.ref = def.path;
if (this.ref) {
var parts = url.parse(this.ref);
if (this.ref && !this.isExternal()) {
var parts = this.ref.split('#');
this.path = (parts.length > 1? parts.slice(0, -1).join('#') : this.ref);
this.anchor = (parts.length > 1? '#' + _.last(parts) : null);
if (!this.isExternal()) {
var parts = this.ref.split('#');
this.path = (parts.length > 1? parts.slice(0, -1).join('#') : this.ref);
this.anchor = (parts.length > 1? '#' + _.last(parts) : null);
// Normalize path to remove ('./', etc)
this.path = location.normalize(this.path);
}
// Normalize path to remove ('./', etc)
this.path = location.normalize(this.path);
}
this.articles = _.map(def.articles || [], function(article) {
+39 -1
View File
@@ -100,6 +100,12 @@ function Book(opts) {
var cfg = this.config.dump();
error.deprecateField(cfg, 'book', (this.output? this.output.name : null), '"options.generator" property is deprecated, use "output.name" instead');
// options.generator
cfg.generator = this.output? this.output.name : null;
// options.output
cfg.output = this.output? this.output.root() : null;
return cfg;
}
});
@@ -314,7 +320,7 @@ Book.prototype.findParsableFile = function(filename) {
if (!realFilepath) return null;
return {
parser: parsers.get(ext),
parser: parsers.getByExt(ext),
path: realFilepath
};
});
@@ -353,6 +359,38 @@ Book.prototype.isInLanguageBook = function(filename) {
});
};
// ----- Parser Methods
// Render a markup string in inline mode
Book.prototype.renderInline = function(type, src) {
var parser = parsers.get(type);
return parser.inline(src)
.get('content');
};
// Render a markup string in block mode
Book.prototype.renderBlock = function(type, src) {
var parser = parsers.get(type);
return parser.page(src)
.get('content');
};
// ----- DEPRECATED METHODS
Book.prototype.contentLink = error.deprecateMethod(function(s) {
return this.output.toURL(s);
}, '.contentLink() is deprecated, use ".output.toURL()" instead');
Book.prototype.contentPath = error.deprecateMethod(function(s) {
return this.output.toURL(s);
}, '.contentPath() is deprecated, use ".output.toURL()" instead');
Book.prototype.isSubBook = error.deprecateMethod(function() {
return this.isLanguageBook();
}, '.isSubBook() is deprecated, use ".isLanguageBook()" instead');
// Initialize a book
Book.init = function(fs, root, opts) {
var book = new Book(_.extend(opts || {}, {
+1 -1
View File
@@ -81,7 +81,7 @@ function ebookCmd(format) {
return fs.tmpDir()
.then(function(dir) {
var ext = '.'+format;
var outputFile = path.resolve(process.cwd(), args[1] || ('book' + ext));
var outputFile = path.resolve(process.cwd(), args[0] || ('book' + ext));
var output = new EBookOutput(book, {
root: dir,
format: format
-1
View File
@@ -7,7 +7,6 @@ var tinylr = require('tiny-lr');
var Promise = require('../utils/promise');
var PluginsManager = require('../plugins');
var Book = require('../book');
var initBook = require('../init');
var helper = require('./helper');
var Server = require('./server');
+3 -2
View File
@@ -64,8 +64,9 @@ Server.prototype.start = function(dir, port) {
}
// Send file
send(req, url.parse(req.url).pathname)
.root(dir)
send(req, url.parse(req.url).pathname, {
root: dir
})
.on('error', error)
.on('directory', redirect)
.pipe(res);
+1 -1
View File
@@ -54,7 +54,7 @@ Config.prototype.load = function() {
throw new Error('GitBook version doesn\'t satisfy version required by the book: '+that.options.gitbook);
}
if (that.options.gitbook != '*' && !semver.satisfies(semver.inc(gitbook.version, 'patch'), that.options.gitbook)) {
that.log.warn.ln('gitbook version specified in your book.json might be too strict for future patches, \''+(_.first(gitbook.version.split('.'))+'.x.x')+'\' is more adequate');
that.log.warn.ln('gitbook version specified in your book.json might be too strict for future patches, \'>='+(_.first(gitbook.version.split('.'))+'.x.x')+'\' is more adequate');
}
that.options.plugins = plugins.toList(that.options.plugins);
+1 -1
View File
@@ -22,7 +22,7 @@ function normalizePluginsList(plugins) {
var parts = plugin.split('@');
var name = parts[0];
var version = parts[1];
var version = parts.slice(1).join('@');
return {
'name': name,
'version': version // optional
-4
View File
@@ -12,10 +12,6 @@ module.exports = {
'type': 'string',
'title': 'Title of the book, default is extracted from README'
},
'title': {
'type': 'string',
'title': 'Description of the book, default is extracted from README'
},
'isbn': {
'type': 'string',
'title': 'ISBN for published book'
-1
View File
@@ -1,4 +1,3 @@
var _ = require('lodash');
var path = require('path');
var fs = require('./utils/fs');
+33 -6
View File
@@ -5,8 +5,10 @@ var path = require('path');
var Promise = require('../utils/promise');
var pathUtil = require('../utils/path');
var location = require('../utils/location');
var error = require('../utils/error');
var PluginsManager = require('../plugins');
var TemplateEngine = require('../template');
var gitbook = require('../gitbook');
/*
Output is like a stream interface for a parsed book
@@ -35,8 +37,14 @@ function Output(book, opts, parent) {
// Files to ignore in output
this.ignore = Ignore();
// Hack to inherits from rules of the book
this.ignore.add(this.book.ignore);
}
// Default name for generator
Output.prototype.name = 'base';
// Default extension for output
Output.prototype.defaultExtension = '.html';
@@ -185,7 +193,7 @@ Output.prototype.onRelativeLink = function(currentPage, href) {
href = currentPage.relative(href);
// Replace .md by .html
href = this.outputUrl(href);
href = this.toURL(href);
}
return href;
@@ -199,6 +207,10 @@ Output.prototype.onOutputSVG = function(page, svg) {
// Output an image as a file
// Normalize the relative link
Output.prototype.onOutputImage = function(page, imgFile) {
if (location.isExternal(imgFile)) {
return imgFile;
}
imgFile = page.resolveLocal(imgFile);
return page.relative(imgFile);
};
@@ -221,16 +233,31 @@ Output.prototype.onLanguageBook = function(book) {
// ---- Utilities ----
// Return conetxt for the output itself
Output.prototype.getSelfContext = function() {
return {
name: this.name
};
};
// Return a default context for templates
Output.prototype.getContext = function() {
return _.extend(
{},
var ctx = _.extend(
{
output: this.getSelfContext()
},
this.book.getContext(),
this.book.langs.getContext(),
(this.book.isLanguageBook()? this.book.parent: this.book).langs.getContext(),
this.book.summary.getContext(),
this.book.glossary.getContext(),
this.book.config.getContext()
this.book.config.getContext(),
gitbook.getContext()
);
// Deprecated fields
error.deprecateField(ctx.gitbook, 'generator', this.name, '"gitbook.generator" property is deprecated, use "output.name" instead');
return ctx;
};
// Resolve a file path in the context of a specific page
@@ -263,7 +290,7 @@ Output.prototype.outputPath = function(filename, ext) {
// Filename for output
// /test/index.html -> /test/
Output.prototype.outputUrl = function(filename, ext) {
Output.prototype.toURL = function(filename, ext) {
var href = this.outputPath(filename, ext);
if (path.basename(href) == 'index.html' && this.opts.directoryIndex) {
+10 -1
View File
@@ -21,6 +21,15 @@ var EbookOutput = assetsInliner(_EbookOutput);
EbookOutput.prototype.name = 'ebook';
// Return context for templating
// Incldue type of ebbook generated
EbookOutput.prototype.getSelfContext = function() {
var ctx = EbookOutput.super_.prototype.getSelfContext.apply(this);
ctx.format = this.opts.format;
return ctx;
};
// Finish generation, create ebook using ebook-convert
EbookOutput.prototype.finish = function() {
var that = this;
@@ -114,7 +123,7 @@ EbookOutput.prototype.locateCover = function() {
// Cover doesn't exist and multilingual?
if (!fs.existsSync(cover)) {
if (this.parent) return this.parent.locateCover()
if (this.parent) return this.parent.locateCover();
else return undefined;
}
+1 -1
View File
@@ -16,7 +16,7 @@ JSONOutput.prototype.onPage = function(page) {
// Write as json
.then(function() {
var json = page.getContext();
var json = page.getOutputContext(that);
// Delete some private properties
delete json.config;
+14 -51
View File
@@ -8,13 +8,10 @@ var Promise = require('../utils/promise');
var location = require('../utils/location');
var fs = require('../utils/fs');
var defaultFilters = require('../template/filters');
var FSLoader = require('../template/fs-loader');
var conrefsLoader = require('./conrefs');
var Output = require('./base');
// Tranform a theme ID into a plugin
function themeID(plugin) {
return 'theme-' + plugin;
}
// Directory for a theme with the templates
function templatesPath(dir) {
@@ -57,32 +54,11 @@ WebsiteOutput.prototype.prepare = function() {
})
.then(function() {
var themeName = that.book.config.get('theme');
that.theme = that.plugins.get(themeID(themeName));
that.themeDefault = that.plugins.get(themeID('default'));
if (!that.theme) {
throw new Error('Theme "' + themeName + '" is not installed, add "' + themeID(themeName) + '" to your "book.json"');
}
if (that.themeDefault.root != that.theme.root) {
that.log.info.ln('build using theme "' + themeName + '"');
}
// This list is ordered to give priority to templates in the book
var searchPaths = _.chain([
// The book itself can contains a "_layouts" folder
that.book.root,
var searchPaths = _.pluck(that.plugins.list(), 'root');
// Installed plugin (it can be identical to themeDefault.root)
that.theme.root,
// Is default theme still installed
that.themeDefault? that.themeDefault.root : null
])
.compact()
.uniq()
.value();
// The book itself can contains a "_layouts" folder
searchPaths.unshift(that.book.root);
// Load i18n
_.each(searchPaths.concat().reverse(), function(searchPath) {
@@ -92,7 +68,7 @@ WebsiteOutput.prototype.prepare = function() {
that.i18n.load(i18nRoot);
});
that.env = new nunjucks.Environment(new nunjucks.FileSystemLoader(_.map(searchPaths, templatesPath)));
that.env = new nunjucks.Environment(new FSLoader(_.map(searchPaths, templatesPath)));
// Add GitBook default filters
_.each(defaultFilters, function(fn, filter) {
@@ -117,7 +93,7 @@ WebsiteOutput.prototype.prepare = function() {
// Transform a '.md' into a '.html' (README -> index)
that.env.addFilter('contentURL', function(s) {
return location.normalize(that.outputUrl(s));
return that.toURL(s);
});
// Relase path to an asset
@@ -142,21 +118,11 @@ WebsiteOutput.prototype.prepare = function() {
.then(function() {
if (that.book.isLanguageBook()) return;
return Promise.serie([
// Assets from the book are already copied
// The order is reversed from the template's one
// Is default theme still installed
that.themeDefault && that.themeDefault.root != that.theme.root?
that.themeDefault.root : null,
// Installed plugin (it can be identical to themeDefault.root)
that.theme.root
], function(folder) {
if (!folder) return;
// Assets from the book are already copied
// Copy assets from plugins (start with default plugins)
return Promise.serie(that.plugins.list().reverse(), function(plugin) {
// Copy assets only if exists (don't fail otherwise)
var assetFolder = path.join(folder, '_assets', that.name);
var assetFolder = path.join(plugin.root, '_assets', that.name);
if (!fs.existsSync(assetFolder)) return;
that.log.debug.ln('copy assets from theme', assetFolder);
@@ -164,7 +130,7 @@ WebsiteOutput.prototype.prepare = function() {
assetFolder,
that.resolve('gitbook'),
{
deleteFirst: false, // Delete "to" before
deleteFirst: false,
overwrite: true,
confirm: true
}
@@ -190,7 +156,7 @@ WebsiteOutput.prototype.onPage = function(page) {
// Render the page template with the same context as the json output
.then(function() {
return that.render('page', page.getContext());
return that.render('page', page.getOutputContext(that));
})
// Write the HTML file
@@ -243,13 +209,10 @@ WebsiteOutput.prototype.outputMultilingualIndex = function() {
// Templates are stored in `_layouts` folders
WebsiteOutput.prototype.render = function(tpl, context) {
var filename = this.templateName(tpl);
context = _.extend(context, {
template: {
// Same template but in the default theme
default: this.themeDefault? path.resolve(templatesPath(this.themeDefault.root), filename) : null,
// Same template but in the theme
theme: path.resolve(templatesPath(this.theme.root), filename)
self: filename
},
plugins: {
+30 -33
View File
@@ -23,12 +23,13 @@ function Page(book, filename) {
this.book = book;
this.log = this.book.log;
// Map of attributes from YAML frontmatter
// Description is also extracted by default from content
this.attributes = {};
// Current content
this.content = '';
// Short description for the page
this.description = '';
// Relative path to the page
this.path = location.normalize(filename);
@@ -40,7 +41,7 @@ function Page(book, filename) {
// Can we parse it?
extension = path.extname(this.path);
this.parser = parsers.get(extension);
this.parser = parsers.getByExt(extension);
if (!this.parser) throw error.ParsingError(new Error('Can\'t parse file "'+this.path+'"'));
this.type = this.parser.name;
@@ -115,31 +116,27 @@ Page.prototype.getContext = function() {
if (dir == 'neutral') dir = null;
}
return _.extend(
{
file: {
path: this.path,
mtime: this.mtime,
type: this.type
},
page: {
title: article? article.title : null,
description: this.description,
next: next? next.getContext() : null,
previous: prev? prev.getContext() : null,
level: article? article.level : null,
depth: article? article.depth : 0,
content: this.content,
dir: dir
}
return {
file: {
path: this.path,
mtime: this.mtime,
type: this.type
},
gitbook.getContext(),
this.book.getContext(),
this.book.langs.getContext(),
this.book.summary.getContext(),
this.book.glossary.getContext(),
this.book.config.getContext()
);
page: _.extend({}, this.attributes, {
title: article? article.title : null,
next: next? next.getContext() : null,
previous: prev? prev.getContext() : null,
level: article? article.level : null,
depth: article? article.depth() : 0,
content: this.content,
dir: dir
})
};
};
// Return complete context for templating (page + book + summary + ...)
Page.prototype.getOutputContext = function(output) {
return _.extend({}, this.getContext(), output.getContext());
};
// Parse the page and return its content
@@ -165,8 +162,8 @@ Page.prototype.toHTML = function(output) {
.then(function() {
var parsed = fm(that.content);
// Extend page with the fontmatter attribute
that.description = parsed.attributes.description || '';
// Extract attributes
that.attributes = parsed.attributes;
// Keep only the body
that.update(parsed.body);
@@ -184,7 +181,7 @@ Page.prototype.toHTML = function(output) {
// Render template
.then(function() {
return output.template.render(that.content, that.getContext(), {
return output.template.render(that.content, that.getOutputContext(output), {
path: that.path
})
.then(that.update);
@@ -223,8 +220,8 @@ Page.prototype.toHTML = function(output) {
// Extract description from page's content if no frontmatter
onDescription: function(description) {
if (that.description) return;
that.description = description;
if (that.attributes.description) return;
that.attributes.description = description;
},
// Convert glossary entries to annotations
+11 -1
View File
@@ -37,11 +37,20 @@ function createParser(parser, base) {
nparser.page = Promise.wrapfn(parser.page);
nparser.page.prepare = Promise.wrapfn(parser.page.prepare || _.identity);
nparser.inline = Promise.wrapfn(parser.inline);
return nparser;
}
// Return a specific parser
function getParser(name) {
return _.find(PARSERS, {
name: name
});
}
// Return a specific parser according to an extension
function getParser(ext) {
function getParserByExt(ext) {
return _.find(PARSERS, function(input) {
return input.name == ext || _.contains(input.extensions, ext);
});
@@ -56,5 +65,6 @@ module.exports = {
all: PARSERS,
extensions: _.flatten(_.pluck(PARSERS, 'extensions')),
get: getParser,
getByExt: getParserByExt,
getForFile: getParserForFile
};
+46 -13
View File
@@ -21,6 +21,11 @@ function PluginsManager(book) {
_.bindAll(this);
}
// Returns the list of plugins
PluginsManager.prototype.list = function() {
return this.plugins;
};
// Return count of plugins loaded
PluginsManager.prototype.count = function() {
return _.size(this.plugins);
@@ -33,24 +38,21 @@ PluginsManager.prototype.get = function(name) {
});
};
// Load a plugin, or a list of plugins
PluginsManager.prototype.load = function(name) {
// Load a plugin (could be a BookPlugin or {name,path})
PluginsManager.prototype.load = function(plugin) {
var that = this;
if (_.isArray(name)) {
return Promise.serie(name, function(_name) {
return that.load(_name);
});
if (_.isArray(plugin)) {
return Promise.serie(plugin, that.load);
}
return Promise()
// Initiate and load the plugin
.then(function() {
var plugin;
if (!_.isString(name)) plugin = name;
else plugin = new BookPlugin(that.book, name);
if (!(plugin instanceof BookPlugin)) {
plugin = new BookPlugin(that.book, plugin.name, plugin.path);
}
if (that.get(plugin.id)) {
throw new Error('Plugin "'+plugin.id+'" is already loaded');
@@ -68,10 +70,41 @@ PluginsManager.prototype.load = function(name) {
// Load all plugins from the book's configuration
PluginsManager.prototype.loadAll = function() {
var plugins = _.pluck(this.book.config.get('plugins'), 'name');
var that = this;
var pluginNames = _.pluck(this.book.config.get('plugins'), 'name');
this.log.info.ln('loading', plugins.length, 'plugins');
return this.load(plugins);
return registry.list(this.book)
.then(function(plugins) {
// Filter out plugins not listed of first level
// (aka pre-installed plugins)
plugins = _.filter(plugins, function(plugin) {
return (
plugin.depth > 1 ||
_.contains(pluginNames, plugin.name)
);
});
// Sort plugins to match list in book.json
plugins.sort(function(a, b){
return pluginNames.indexOf(a.name) < pluginNames.indexOf(b.name) ? -1 : 1;
});
// Log state
that.log.info.ln(_.size(plugins) + ' are installed');
if (_.size(pluginNames) != _.size(plugins)) that.log.info.ln(_.size(pluginNames) + ' explicitly listed');
// Verify that all plugins are present
var notInstalled = _.filter(pluginNames, function(name) {
return !_.find(plugins, { name: name });
});
if (_.size(notInstalled) > 0) {
throw new Error('Couldn\'t locate plugins "' + notInstalled.join(', ') + '", Run \'gitbook install\' to install plugins from registry.');
}
// Load plugins
return that.load(plugins);
});
};
// Setup a plugin
+11 -23
View File
@@ -24,13 +24,14 @@ function isModuleNotFound(err) {
return err.message.indexOf('Cannot find module') >= 0;
}
function BookPlugin(book, pluginId) {
function BookPlugin(book, pluginId, pluginFolder) {
this.book = book;
this.log = this.book.log.prefix(pluginId);
this.id = pluginId;
this.npmId = registry.npmId(pluginId);
this.root;
this.root = pluginFolder;
this.packageInfos = undefined;
this.content = undefined;
@@ -51,8 +52,7 @@ BookPlugin.prototype.bind = function(fn) {
return fn.bind(compatibility.pluginCtx(this));
};
// Load this plugin
// An optional folder to search in can be passed
// Load this plugin from its root folder
BookPlugin.prototype.load = function(folder) {
var that = this;
@@ -60,18 +60,12 @@ BookPlugin.prototype.load = function(folder) {
return Promise.reject(new Error('Plugin "' + this.id + '" is already loaded'));
}
// Fodlers to search plugins in
var searchPaths = _.compact([
folder,
this.book.resolve('node_modules'),
__dirname
]);
// Try loading plugins from different location
var p = Promise.some(searchPaths, function(baseDir) {
var p = Promise()
.then(function() {
// Locate plugin and load pacjage.json
try {
var res = resolve.sync(that.npmId + '/package.json', { basedir: baseDir });
var res = resolve.sync('./package.json', { basedir: that.root });
that.root = path.dirname(res);
that.packageInfos = require(res);
@@ -81,12 +75,12 @@ BookPlugin.prototype.load = function(folder) {
that.packageInfos = undefined;
that.content = undefined;
return false;
return;
}
// Load plugin JS content
try {
that.content = require(resolve.sync(that.npmId, { basedir: baseDir }));
that.content = require(that.root);
} catch(err) {
// It's no big deal if the plugin doesn't have an "index.js"
// (For example: themes)
@@ -98,8 +92,6 @@ BookPlugin.prototype.load = function(folder) {
});
}
}
return true;
})
.then(that.validate)
@@ -122,18 +114,15 @@ BookPlugin.prototype.load = function(folder) {
// This method throws erros if plugin is invalid
BookPlugin.prototype.validate = function() {
var isValid = (
this.isLoaded() &&
this.packageInfos &&
this.packageInfos.name &&
this.packageInfos.engines &&
this.packageInfos.engines.gitbook
);
if (!this.isLoaded()) {
throw new Error('Couldn\'t locate plugin "' + this.id + '", Run \'gitbook install\' to install plugins from registry.');
}
if (!isValid) {
throw new Error('Invalid plugin "' + this.id + '"');
throw new Error('Error loading plugin "' + this.id + '" at "' + this.root + '"');
}
if (!gitbook.satisfies(this.packageInfos.engines.gitbook)) {
@@ -204,7 +193,6 @@ BookPlugin.prototype._getResources = function(base) {
.then(function() {
if (that._resources[base]) return that._resources[base];
base = base;
var book = that.content[base];
// Compatibility with version 1.x.x
+58 -3
View File
@@ -1,7 +1,9 @@
var npm = require('npm');
var npmi = require('npmi');
var path = require('path');
var semver = require('semver');
var _ = require('lodash');
var readInstalled = require('read-installed');
var Promise = require('../utils/promise');
var gitbook = require('../gitbook');
@@ -21,7 +23,7 @@ function pluginId(name) {
// Validate an NPM plugin ID
function validateId(name) {
return name.indexOf(PLUGIN_PREFIX) === 0;
return name && name.indexOf(PLUGIN_PREFIX) === 0;
}
// Initialize NPM for operations
@@ -87,7 +89,7 @@ function installPlugin(book, plugin, version) {
throw new Error('Found no satisfactory version for plugin "' + plugin + '"');
}
book.log.info.ln('install plugin' + plugin +'" from npm ('+npnName+') with version', version);
book.log.info.ln('install plugin "' + plugin +'" from npm ('+npnName+') with version', version);
return Promise.nfcall(npmi, {
'name': npnName,
'version': version,
@@ -104,6 +106,57 @@ function installPlugin(book, plugin, version) {
});
}
// List all packages installed inside a folder
// Returns an ordered list of plugins
function listInstalled(folder) {
var options = {
dev: false,
log: function() {},
depth: 4
};
var results = [];
function onPackage(pkg, isRoot) {
if (!validateId(pkg.name)){
if (!isRoot) return;
} else {
results.push({
name: pluginId(pkg.name),
version: pkg.version,
path: pkg.realPath,
depth: pkg.depth
});
}
_.each(pkg.dependencies, function(dep) {
onPackage(dep);
});
}
return Promise.nfcall(readInstalled, folder, options)
.then(function(data) {
onPackage(data, true);
return _.uniq(results, 'name');
});
}
// List installed plugins for a book (defaults and installed)
function listPlugins(book) {
return Promise.all([
listInstalled(path.resolve(__dirname, '../..')),
listInstalled(book.root),
book.isLanguageBook()? listInstalled(book.parent.root) : Promise([])
])
.spread(function(defaultPlugins, plugins) {
var args = _.toArray(arguments);
var results = _.reduce(args, function(out, a) {
return out.concat(a);
}, []);
return _.uniq(results, 'name');
});
}
module.exports = {
npmId: npmId,
pluginId: pluginId,
@@ -111,5 +164,7 @@ module.exports = {
resolve: resolveVersion,
link: linkPlugin,
install: installPlugin
install: installPlugin,
list: listPlugins,
listInstalled: listInstalled
};
+20
View File
@@ -12,5 +12,25 @@ module.exports = {
html: false,
body: blk.body
};
},
// Render some markdown to HTML
markdown: function(blk) {
return this.book.renderInline('markdown', blk.body)
.then(function(out) {
return { body: out };
});
},
asciidoc: function(blk) {
return this.book.renderInline('asciidoc', blk.body)
.then(function(out) {
return { body: out };
});
},
markup: function(blk) {
return this.book.renderInline(this.ctx.file.type, blk.body)
.then(function(out) {
return { body: out };
});
}
};
+80
View File
@@ -0,0 +1,80 @@
var _ = require('lodash');
var fs = require('fs');
var path = require('path');
var nunjucks = require('nunjucks');
/*
Nunjucks loader similar to FileSystemLoader, but avoid infinite looping
*/
function isRelative(filename) {
return (filename.indexOf('./') === 0 || filename.indexOf('../') === 0);
}
var Loader = nunjucks.Loader.extend({
init: function(searchPaths) {
this.searchPaths = _.map(searchPaths, path.normalize);
},
getSource: function(fullpath) {
if (!fullpath) return null;
fullpath = this.resolve(null, fullpath);
if(!fullpath) {
return null;
}
return {
src: fs.readFileSync(fullpath, 'utf-8'),
path: fullpath,
noCache: true
};
},
// We handle absolute paths ourselves in ".resolve"
isRelative: function() {
return true;
},
resolve: function(from, to) {
var searchPaths = this.searchPaths;
// Relative template like "./test.html"
if (isRelative(to) && from) {
return path.resolve(path.dirname(from), to);
}
// Determine in which search folder we currently are
var originalSearchPath = _.chain(this.searchPaths)
.sortBy(function(s) {
return -s.length;
})
.find(function(basePath) {
return (from && from.indexOf(basePath) === 0);
})
.value();
var originalFilename = originalSearchPath? path.relative(originalSearchPath, from) : null;
// If we are including same file from a different search path
// Slice the search paths to avoid including from previous ones
if (originalFilename == to) {
var currentIndex = searchPaths.indexOf(originalSearchPath);
searchPaths = searchPaths.slice(currentIndex + 1);
}
// Absolute template to resolve in root folder
var resultFolder = _.find(searchPaths, function(basePath) {
var p = path.resolve(basePath, to);
return (
p.indexOf(basePath) === 0
&& fs.existsSync(p)
);
});
if (!resultFolder) return null;
return path.resolve(resultFolder, to);
}
});
module.exports = Loader;
+19 -10
View File
@@ -63,23 +63,32 @@ function TemplateEngine(output) {
// Add default blocks and filters
this.addBlocks(defaultBlocks);
this.addFilters(defaultFilters);
// Build context for this book with depreacted fields
this.ctx = {
book: this.book,
output: this.output
};
error.deprecateField(this.ctx, 'generator', this.output.name, '"generator" property is deprecated, use "output.generator" instead');
}
// Bind a function to a context
// Filters and blocks are binded to this context
TemplateEngine.prototype.bindContext = function(func) {
var ctx = {
ctx: this.ctx,
output: this.output,
generator: this.output.name
};
var that = this;
return _.bind(func, ctx);
return function() {
var ctx = _.extend({
ctx: this.ctx
}, that.ctx);
return func.apply(ctx, arguments);
};
};
// Interpolate a string content to replace shortcuts according to the filetype
TemplateEngine.prototype.interpolate = function(filepath, source) {
var parser = parsers.get(path.extname(filepath));
var parser = parsers.getByExt(path.extname(filepath));
var type = parser? parser.name : null;
return this.applyShortcuts(type, source);
@@ -202,7 +211,7 @@ TemplateEngine.prototype.addBlock = function(name, block) {
lastBlockArgs = parser.parseSignature(null, true);
parser.advanceAfterBlockEnd(lastBlockName);
}
} while (lastBlockName != block.end)
} while (lastBlockName != block.end);
parser.advanceAfterBlockEnd();
@@ -338,7 +347,7 @@ TemplateEngine.prototype.processBlock = function(blk) {
}
// Return it as a position marker
return '@%@'+blk.id+'@%@';
return '{{-%'+blk.id+'%-}}';
};
// Render a string (without post processing)
@@ -386,7 +395,7 @@ TemplateEngine.prototype.applyShortcut = function(content, shortcut) {
TemplateEngine.prototype.replaceBlocks = function(content) {
var that = this;
return content.replace(/\@\%\@([\s\S]+?)\@\%\@/g, function(match, key) {
return content.replace(/\{\{\-\%([\s\S]+?)\%\-\}\}/g, function(match, key) {
var blk = that.blockBodies[key];
if (!blk) return match;
+1 -1
View File
@@ -1,6 +1,6 @@
var _ = require('lodash');
var childProcess = require('child_process');
var spawn = require("spawn-cmd").spawn;
var spawn = require('spawn-cmd').spawn;
var Promise = require('./promise');
// Execute a command
+90 -90
View File
@@ -1,93 +1,93 @@
{
"name": "gitbook",
"version": "3.0.0-pre.3",
"homepage": "https://www.gitbook.com",
"description": "Library and cmd utility to generate GitBooks",
"main": "lib/index.js",
"dependencies": {
"q": "1.0.1",
"lodash": "3.10.1",
"graceful-fs": "4.1.3",
"resolve": "0.6.3",
"mkdirp": "0.5.1",
"error": "7.0.2",
"gitbook-markdown": "1.0.3",
"gitbook-asciidoc": "1.0.2",
"gitbook-plugin-highlight": "1.0.3",
"gitbook-plugin-sharing": "1.0.1",
"gitbook-plugin-search": "1.1.0",
"gitbook-plugin-fontsettings": "1.0.2",
"gitbook-plugin-theme-default": "1.0.0-pre.4",
"nunjucks": "2.3.0",
"nunjucks-autoescape": "1.0.0",
"nunjucks-filter": "1.0.0",
"semver": "5.0.1",
"npmi": "0.1.1",
"cheerio": "0.19.0",
"gitbook-plugin-livereload": "0.0.1",
"chokidar": "~1.0.5",
"send": "0.2.0",
"tiny-lr": "0.2.1",
"tmp": "0.0.28",
"crc": "3.2.1",
"bash-color": "0.0.3",
"urijs": "1.17.0",
"request": "2.69.0",
"npm": "2.4.1",
"dom-serializer": "0.1.0",
"spawn-cmd": "0.0.2",
"escape-string-regexp": "1.0.3",
"juice": "1.9.0",
"jsonschema": "1.1.0",
"json-schema-defaults": "0.1.1",
"merge-defaults": "0.2.1",
"github-slugid": "1.0.0",
"destroy": "1.0.4",
"ignore": "2.2.19",
"deprecated": "0.0.1",
"rmdir": "1.2.0",
"cp": "0.2.0",
"cpr": "1.0.0",
"direction": "0.1.5",
"moment": "2.11.2",
"i18n-t": "1.0.0",
"front-matter": "2.0.6",
"spawn-cmd": "0.0.2"
"name": "gitbook",
"version": "3.0.0-pre.7",
"homepage": "https://www.gitbook.com",
"description": "Library and cmd utility to generate GitBooks",
"main": "lib/index.js",
"dependencies": {
"bash-color": "0.0.3",
"cheerio": "0.20.0",
"chokidar": "1.4.3",
"cp": "0.2.0",
"cpr": "1.1.1",
"crc": "3.4.0",
"deprecated": "0.0.1",
"destroy": "1.0.4",
"direction": "0.1.5",
"dom-serializer": "0.1.0",
"error": "7.0.2",
"escape-string-regexp": "1.0.5",
"eslint": "^2.2.0",
"front-matter": "2.0.7",
"gitbook-asciidoc": "1.1.0",
"gitbook-markdown": "1.2.0",
"gitbook-plugin-fontsettings": "1.0.2",
"gitbook-plugin-highlight": "2.0.2",
"gitbook-plugin-livereload": "0.0.1",
"gitbook-plugin-search": "1.2.0",
"gitbook-plugin-sharing": "1.0.1",
"gitbook-plugin-theme-default": "1.0.0-pre.6",
"github-slugid": "1.0.1",
"graceful-fs": "4.1.3",
"i18n-t": "1.0.0",
"ignore": "3.1.1",
"json-schema-defaults": "0.1.1",
"jsonschema": "1.1.0",
"juice": "1.10.0",
"lodash": "3.10.1",
"merge-defaults": "0.2.1",
"mkdirp": "0.5.1",
"moment": "2.12.0",
"npm": "3.8.6",
"npmi": "1.0.1",
"nunjucks": "2.4.1",
"nunjucks-autoescape": "1.0.1",
"q": "1.4.1",
"read-installed": "^4.0.3",
"request": "2.70.0",
"resolve": "1.1.7",
"rmdir": "1.2.0",
"semver": "5.1.0",
"send": "0.13.2",
"spawn-cmd": "0.0.2",
"tiny-lr": "0.2.1",
"tmp": "0.0.28",
"urijs": "1.17.1"
},
"devDependencies": {
"eslint": "2.7.0",
"mocha": "2.4.5",
"should": "8.3.0"
},
"scripts": {
"test": "node_modules/.bin/mocha --reporter spec --bail --timeout 15000 ./test/all.js",
"lint": "eslint ."
},
"repository": {
"type": "git",
"url": "https://github.com/GitbookIO/gitbook.git"
},
"bin": {
"gitbook": "./bin/gitbook.js"
},
"keywords": [
"git",
"book",
"gitbook"
],
"author": "FriendCode Inc. <contact@gitbook.com>",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/GitbookIO/gitbook/issues"
},
"contributors": [
{
"name": "Aaron O'Mullan",
"email": "aaron@gitbook.com"
},
"devDependencies": {
"eslint": "1.5.0",
"mocha": "2.4.5",
"should": "8.2.2"
},
"scripts": {
"test": "node_modules/.bin/mocha --reporter spec --bail --timeout 15000 ./test/all.js",
"lint": "eslint ."
},
"repository": {
"type": "git",
"url": "https://github.com/GitbookIO/gitbook.git"
},
"bin": {
"gitbook": "./bin/gitbook.js"
},
"keywords": [
"git",
"book",
"gitbook"
],
"author": "FriendCode Inc. <contact@gitbook.com>",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/GitbookIO/gitbook/issues"
},
"contributors": [
{
"name": "Aaron O'Mullan",
"email": "aaron@gitbook.com"
},
{
"name": "Samy Pessé",
"email": "samy@gitbook.com"
}
]
{
"name": "Samy Pessé",
"email": "samy@gitbook.com"
}
]
}
+1
View File
@@ -19,6 +19,7 @@ require('./git');
require('./plugins');
require('./template');
require('./conrefs');
require('./ignore');
// Page and HTML generation
require('./page');
+33
View File
@@ -0,0 +1,33 @@
var mock = require('./mock');
var WebsiteOutput = require('../lib/output/website');
describe('Ignore', function() {
var output;
before(function() {
return mock.outputDefaultBook(WebsiteOutput, {
'.ignore': 'test-1.js',
'.gitignore': 'test-2.js\ntest-3.js',
'.bookignore': '!test-3.js',
'test-1.js': '1',
'test-2.js': '2',
'test-3.js': '3'
})
.then(function(_output) {
output = _output;
});
});
it('should load rules from .ignore', function() {
output.should.not.have.file('test-1.js');
});
it('should load rules from .gitignore', function() {
output.should.not.have.file('test-2.js');
});
it('should load rules from .bookignore', function() {
output.should.have.file('test-3.js');
});
});
+3 -3
View File
@@ -19,7 +19,7 @@ describe('Init', function() {
rootFolder.should.have.file('hello.md');
rootFolder.should.have.file('hello 2.md');
});
})
});
});
it('should create file subfolder', function() {
@@ -38,7 +38,7 @@ describe('Init', function() {
rootFolder.should.have.file('test/hello.md');
rootFolder.should.have.file('test/test2/world.md');
});
})
});
});
it('should create SUMMARY if non-existant', function() {
@@ -51,7 +51,7 @@ describe('Init', function() {
rootFolder.should.have.file('SUMMARY.md');
rootFolder.should.have.file('README.md');
});
})
});
});
});
-1
View File
@@ -1,7 +1,6 @@
var path = require('path');
var should = require('should');
var Book = require('../').Book;
var mock = require('./mock');
describe('Locate', function() {
+16
View File
@@ -41,8 +41,24 @@ describe('JSON Output', function() {
output.should.have.file('fr/README.json');
});
it('should correctly add languages list to all json', function() {
var jsonFR = require(output.resolve('fr/README.json'));
var jsonEN = require(output.resolve('en/README.json'));
jsonFR.should.have.property('languages')
.with.property('list').with.lengthOf(2);
jsonEN.should.have.property('languages')
.with.property('list').with.lengthOf(2);
});
it('should correctly generate a README.json for the whole book', function() {
output.should.have.file('README.json');
var json = require(output.resolve('README.json'));
json.book.language.should.equal('en');
json.should.have.property('languages')
.with.property('list').with.lengthOf(2);
});
});
});
+25
View File
@@ -1,3 +1,5 @@
var fs = require('fs');
var mock = require('./mock');
var WebsiteOutput = require('../lib/output/website');
@@ -95,5 +97,28 @@ describe('Website Output', function() {
});
});
describe('Theming', function() {
var output;
before(function() {
return mock.outputDefaultBook(WebsiteOutput, {
'_layouts/website/page.html': '{% extends "website/page.html" %}{% block body %}{{ super() }}<div id="theming-added"></div>{% endblock %}'
})
.then(function(_output) {
output = _output;
});
});
it('should extend default theme', function() {
var readme = fs.readFileSync(output.resolve('index.html'), 'utf-8');
readme.should.be.html({
'#theming-added': {
count: 1
}
});
});
});
});
+40 -8
View File
@@ -9,7 +9,8 @@ describe('Page', function() {
'README.md': ' # Hello World\n\nThis is a description',
'heading.md': '# Hello\n\n## World',
'description.md': '# This is a title\n\nThis is the short description.\n\nNot this one.',
'frontmatter.md': '---\ndescription: Hello World\n---\n\n# This is a title\n\nThis is not the description',
'frontmatter/description.md': '---\ndescription: Hello World\n---\n\n# This is a title\n\nThis is not the description',
'frontmatter/var.md': '---\ntest: Hello World\n---\n\n{{ page.test }}',
'links.md': '[link](hello.md) [link 2](variables/page/next.md) [readme](README.md)',
'links/relative.md': '[link](../hello.md) [link 2](/variables/page/next.md) [readme](../README.md)',
@@ -35,8 +36,12 @@ describe('Page', function() {
'variables/page/dir/ltr.md': 'This is english: {{ page.dir }}',
'variables/page/dir/rtl.md': 'بسيطة {{ page.dir }}',
'variables/config/title.md': '{{ config.title}}',
'variables/gitbook/generator.md': '{{ gitbook.generator }}',
'GLOSSARY.md': '# Glossary\n\n\n## abracadabra\n\nthis is the description'
'GLOSSARY.md': '# Glossary\n\n\n## abracadabra\n\nthis is the description',
'blocks/markdown.md': 'Hello <span>{% markdown %}**World**{% endmarkdown %}</span>',
'blocks/asciidoc.md': 'Hello <span>{% asciidoc %}^super^script phrase{% endasciidoc %}</span>'
}, [
{
title: 'Test page.next',
@@ -131,23 +136,32 @@ describe('Page', function() {
});
describe('Description', function() {
it('should extratc page description from content', function() {
it('should extract page description from content', function() {
var page = book.addPage('description.md');
return page.toHTML(output)
.then(function() {
page.description.should.equal('This is the short description.');
page.attributes.description.should.equal('This is the short description.');
});
});
});
describe('Font-Matter', function() {
it('should extratc page description from front matter', function() {
var page = book.addPage('frontmatter.md');
it('should extract page description from front matter', function() {
var page = book.addPage('frontmatter/description.md');
return page.toHTML(output)
.then(function() {
page.description.should.equal('Hello World');
page.attributes.description.should.equal('Hello World');
});
});
it('should extend page attributes with custom properties', function() {
var page = book.addPage('frontmatter/var.md');
return page.toHTML(output)
.then(function() {
page.content.should.equal('<p>Hello World</p>\n');
});
});
});
@@ -275,7 +289,7 @@ describe('Page', function() {
it('should keep external images path', function() {
page.content.should.be.html({
'img[src="https:/upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png"]': {
'img[src="https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png"]': {
count: 1
}
});
@@ -348,6 +362,12 @@ describe('Page', function() {
.should.be.fulfilledWith('<p>Hello World</p>\n');
});
it('should set gitbook.generator', function() {
var page = book.addPage('variables/gitbook/generator.md');
return page.toHTML(output)
.should.be.fulfilledWith('<p>base</p>\n');
});
describe('page.dir', function() {
it('should detect ltr', function() {
var page = book.addPage('variables/page/dir/ltr.md');
@@ -396,4 +416,16 @@ describe('Page', function() {
});
});
});
describe('Default Blocks', function() {
it('should render block "markdown"', function() {
return book.addPage('blocks/markdown.md').toHTML(output)
.should.finally.equal('<p>Hello <span><strong>World</strong></span></p>\n');
});
it('should render block "asciidoc"', function() {
return book.addPage('blocks/asciidoc.md').toHTML(output)
.should.finally.equal('<p>Hello <span><sup>super</sup>script phrase</span></p>\n');
});
});
});
+29 -6
View File
@@ -9,6 +9,10 @@ var BookPlugin = require('../lib/plugins/plugin');
var PLUGINS_ROOT = path.resolve(__dirname, 'node_modules');
function TestPlugin(book, name) {
return new BookPlugin(book, name, path.resolve(PLUGINS_ROOT, 'gitbook-plugin-'+name));
}
describe('Plugins', function() {
var book;
@@ -77,6 +81,25 @@ describe('Plugins', function() {
})
.should.be.fulfilledWith(1);
});
// This test requires a SSH key, we only run it locally
if (!process.env.CI) {
it('should correctly install dependencies from GitHub via ssh', function() {
return mock.setupBook({
'book.json': {
plugins: ['ga@git@github.com:GitbookIO/plugin-ga.git#master']
}
})
.then(function(book) {
return book.prepareConfig()
.then(function() {
var plugins = new PluginsManager(book);
return plugins.install();
});
})
.should.be.fulfilledWith(1);
});
}
});
describe('Loading', function() {
@@ -90,7 +113,7 @@ describe('Plugins', function() {
describe('Configuration', function() {
it('should fail loading a plugin with an invalid configuration', function() {
var plugin = new BookPlugin(book, 'test-config');
var plugin = TestPlugin(book, 'test-config');
return plugin.load(PLUGINS_ROOT)
.should.be.rejectedWith('Error with book\'s configuration: pluginsConfig.test-config.myProperty is required');
});
@@ -108,7 +131,7 @@ describe('Plugins', function() {
.then(function(book2) {
return book2.prepareConfig()
.then(function() {
var plugin = new BookPlugin(book2, 'test-config');
var plugin = TestPlugin(book2, 'test-config');
return plugin.load(PLUGINS_ROOT);
})
.then(function() {
@@ -122,7 +145,7 @@ describe('Plugins', function() {
var plugin;
before(function() {
plugin = new BookPlugin(book, 'test-resources');
plugin = TestPlugin(book, 'test-resources');
return plugin.load(PLUGINS_ROOT);
});
@@ -146,7 +169,7 @@ describe('Plugins', function() {
var plugin, filters;
before(function() {
plugin = new BookPlugin(book, 'test-filters');
plugin = TestPlugin(book, 'test-filters');
return plugin.load(PLUGINS_ROOT)
.then(function() {
@@ -171,7 +194,7 @@ describe('Plugins', function() {
var plugin, blocks;
before(function() {
plugin = new BookPlugin(book, 'test-blocks');
plugin = TestPlugin(book, 'test-blocks');
return plugin.load(PLUGINS_ROOT)
.then(function() {
@@ -196,7 +219,7 @@ describe('Plugins', function() {
var plugin;
before(function() {
plugin = new BookPlugin(book, 'test-hooks');
plugin = TestPlugin(book, 'test-hooks');
return plugin.load(PLUGINS_ROOT);
});