mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-26 20:27:00 +00:00
Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7b4accb117 | |||
| d6437d31d4 | |||
| 3dd33f1f3c | |||
| 3a0f00411b | |||
| 5b655bb29a | |||
| faf10605e8 | |||
| 5c98b3350b | |||
| 6f4e1d10c1 | |||
| 870886599a | |||
| 1b9801b8a4 | |||
| 897463b22e | |||
| aa4894e94c | |||
| 8a0180ae6b | |||
| d6776b98d3 | |||
| 6a04ba89a5 | |||
| 05eaeeb0d0 | |||
| 77043464b2 | |||
| b90f74a821 | |||
| f804eb42ac | |||
| 74fd8c159b | |||
| a741ec1350 | |||
| 4b26c31b3b | |||
| dfd487692a | |||
| 195374ecee | |||
| 1659778a77 | |||
| 40c4035afb | |||
| 1502d65286 | |||
| 0feb672d70 | |||
| 2a4ef5bbf4 | |||
| c4540332a7 | |||
| 2104404cb3 | |||
| 002d685ebb | |||
| 9da10e2b25 | |||
| 1e4632080b | |||
| 5191106396 | |||
| 6ab5cafaf3 | |||
| d1c0cb9c71 | |||
| 38c750101c | |||
| ba0f379a89 | |||
| 1d9509b3b6 | |||
| 3c8de4a8ab | |||
| 591d8fc9ee | |||
| d480e9cea4 | |||
| 32a71869da | |||
| fdbfda64a6 | |||
| a6f48be39e | |||
| ce50b893e9 | |||
| 225ff27dd1 | |||
| 52e8361846 |
+27
@@ -1,5 +1,32 @@
|
||||
# Release notes
|
||||
|
||||
## 1.3.4
|
||||
- Add glossary to ebooks
|
||||
- Fix autocover with new hook "finish:before"
|
||||
- Add X-UA-Compatible meta tag for IE
|
||||
|
||||
## 1.3.3
|
||||
- Fix parsing of lexed content using the client library
|
||||
|
||||
## 1.3.2
|
||||
- ePub files are now passing validation from epubcheck
|
||||
- Fix replacement of multiple glossary terms in a single sentence
|
||||
- Fix on windows deep relative links
|
||||
- Fix search indexer
|
||||
|
||||
## 1.3.1
|
||||
- Fix error with links in markdown
|
||||
|
||||
## 1.3.0
|
||||
- Bundle gitbook parsing library as a client side library in `gitbook.js` and `gitbook.min.js`
|
||||
|
||||
## 1.2.0
|
||||
- Improvements on ebook generation
|
||||
- Fix incorrect follow of links in ebook generation
|
||||
- Move Table of Contents at the beginning of the ebook
|
||||
- Update to last highlight.js (includes Swift)
|
||||
- Includes of templates and variables (from book.json)
|
||||
|
||||
## 1.1.1
|
||||
- Rewrite quiz logic to be more robust
|
||||
- Improve integration of glossary
|
||||
|
||||
+34
-1
@@ -6,6 +6,8 @@ module.exports = function (grunt) {
|
||||
grunt.loadNpmTasks('grunt-contrib-less');
|
||||
grunt.loadNpmTasks('grunt-contrib-requirejs');
|
||||
grunt.loadNpmTasks("grunt-bower-install-simple");
|
||||
grunt.loadNpmTasks('grunt-browserify');
|
||||
grunt.loadNpmTasks('grunt-contrib-uglify');
|
||||
|
||||
// Init GRUNT configuraton
|
||||
grunt.initConfig({
|
||||
@@ -77,6 +79,30 @@ module.exports = function (grunt) {
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
browserify: {
|
||||
dist: {
|
||||
files: {
|
||||
'gitbook.js': [
|
||||
'./lib/parse/index.js'
|
||||
],
|
||||
},
|
||||
options: {
|
||||
postBundleCB: function (err, src, next) {
|
||||
return next(null, '(function () { var define = undefined; '+src+'; })();')
|
||||
},
|
||||
browserifyOptions: {
|
||||
'standalone': "gitbook"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
uglify: {
|
||||
dist: {
|
||||
files: {
|
||||
'gitbook.min.js': ['gitbook.js']
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -90,7 +116,14 @@ module.exports = function (grunt) {
|
||||
'copy:vendors'
|
||||
]);
|
||||
|
||||
// Bundle the library
|
||||
grunt.registerTask('bundle', [
|
||||
'browserify',
|
||||
'uglify'
|
||||
]);
|
||||
|
||||
grunt.registerTask('default', [
|
||||
'build'
|
||||
'build',
|
||||
'bundle'
|
||||
]);
|
||||
};
|
||||
@@ -74,6 +74,9 @@ Here are the options that can be stored in this file:
|
||||
}
|
||||
},
|
||||
|
||||
// Variables for templating
|
||||
"variables": {},
|
||||
|
||||
// Links in template (null: default, false: remove, string: new value)
|
||||
"links": {
|
||||
// Custom links at top of sidebar
|
||||
@@ -94,9 +97,6 @@ Here are the options that can be stored in this file:
|
||||
|
||||
// Options for PDF generation
|
||||
"pdf": {
|
||||
// Add toc at the end of the file
|
||||
"toc": true,
|
||||
|
||||
// Add page numbers to the bottom of every page
|
||||
"pageNumbers": false,
|
||||
|
||||
@@ -132,7 +132,10 @@ You can publish your books to our index by visiting [GitBook.io](http://www.gitb
|
||||
GitBook can generate your book in the following formats:
|
||||
|
||||
* **Static Website**: This is the default format. It generates a complete interactive static website that can be, for example, hosted on GitHub Pages.
|
||||
* **eBook**: A complete eBook with exercise solutions at the end of the book. Generate this format using: ```gitbook ebook ./myrepo```. You need to have [ebook-convert](http://manual.calibre-ebook.com/cli/ebook-convert.html) installed. The output format could be **PDF**, **ePub** or **MOBI**.
|
||||
* **eBook**: A complete eBook with exercise solutions at the end of the book. You need to have [ebook-convert](http://manual.calibre-ebook.com/cli/ebook-convert.html) installed. You can specify the eBook filename with the `-o` option, otherwise `book` will be used.
|
||||
* Generate a **PDF** using: `gitbook pdf ./myrepo`
|
||||
* Generate a **ePub** using: `gitbook epub ./myrepo`
|
||||
* Generate a **MOBI** using: `gitbook mobi ./myrepo`
|
||||
* **JSON**: This format is used for debugging or extracting metadata from a book. Generate this format using: ```gitbook build ./myrepo -f json```.
|
||||
|
||||
## Book Format
|
||||
@@ -209,7 +212,7 @@ The platform [GitBook.io](https://www.gitbook.io/) is like an "Heroku for books"
|
||||
|
||||
#### Plugins
|
||||
|
||||
Plugins can used to extend your book's functionality. Read [GitbookIO/plugin](https://github.com/GitbookIO/plugin) for more information about how to build a plugin for GitBook.
|
||||
Plugins can be used to extend your book's functionality. Read [GitbookIO/plugin](https://github.com/GitbookIO/plugin) for more information about how to build a plugin for GitBook.
|
||||
|
||||
##### Official plugins:
|
||||
|
||||
@@ -219,6 +222,7 @@ Plugins can used to extend your book's functionality. Read [GitbookIO/plugin](ht
|
||||
| [quizzes](https://github.com/GitbookIO/plugin-quizzes) | Add interactive quizzes to your book. |
|
||||
| [mathjax](https://github.com/GitbookIO/plugin-mathjax) | Displays mathematical notation in the book. |
|
||||
| [mixpanel](https://github.com/GitbookIO/plugin-mixpanel) | Mixpanel tracking for your book |
|
||||
| [infinitescroll](https://github.com/GitbookIO/gitbook-plugin-infinitescroll) | Infinite Scrolling |
|
||||
|
||||
##### Other plugins:
|
||||
|
||||
@@ -235,6 +239,8 @@ Plugins can used to extend your book's functionality. Read [GitbookIO/plugin](ht
|
||||
| [Piwik Open Analytics](https://github.com/emmanuel-keller/gitbook-plugin-piwik) | Piwik Open Analytics tracking for your book |
|
||||
| [Heading Anchors](https://github.com/rlmv/gitbook-plugin-anchors) | Add linkable Github-style anchors to headings |
|
||||
| [JSBin](https://github.com/jcouyang/gitbook-plugin-jsbin) | Embedded jsbin frame into your book |
|
||||
| [gitbook-grvis](https://github.com/romanlytkin/gitbook-grvis) | Gitbook GrViz plugin is used to select from markdown dot and converting it into a picture format svg |
|
||||
| [gitbook-plantuml](https://github.com/romanlytkin/gitbook-plantuml) | Gitbook PlantUml plugin is used to select from markdown uml and converting it into a picture format svg |
|
||||
|
||||
#### Debugging
|
||||
|
||||
|
||||
+20724
File diff suppressed because one or more lines are too long
Vendored
+10
File diff suppressed because one or more lines are too long
@@ -38,6 +38,9 @@ var CONFIG = {
|
||||
}
|
||||
},
|
||||
|
||||
// Variables for templating
|
||||
"variables": {},
|
||||
|
||||
// Set another theme with your own layout
|
||||
// It's recommended to use plugins or add more options for default theme, though
|
||||
// See https://github.com/GitbookIO/gitbook/issues/209
|
||||
|
||||
@@ -39,7 +39,8 @@ Generator.prototype.finish = function() {
|
||||
"--level2-toc": "descendant-or-self::*[contains(concat(' ', normalize-space(@class), ' '), ' book-chapter-2 ')]",
|
||||
"--level3-toc": "descendant-or-self::*[contains(concat(' ', normalize-space(@class), ' '), ' book-chapter-3 ')]",
|
||||
"--no-chapters-in-toc": true,
|
||||
"--max-levels": "1000"
|
||||
"--max-levels": "1",
|
||||
"--breadth-first": true
|
||||
};
|
||||
|
||||
if (format == "pdf") {
|
||||
@@ -50,7 +51,6 @@ Generator.prototype.finish = function() {
|
||||
"--margin-right": String(pdfOptions.margin.right),
|
||||
"--margin-top": String(pdfOptions.margin.top),
|
||||
"--margin-bottom": String(pdfOptions.margin.bottom),
|
||||
"--pdf-add-toc": Boolean(pdfOptions.toc),
|
||||
"--pdf-default-font-size": String(pdfOptions.fontSize),
|
||||
"--pdf-mono-font-size": String(pdfOptions.fontSize),
|
||||
"--paper-size": String(pdfOptions.paperSize),
|
||||
@@ -62,7 +62,7 @@ Generator.prototype.finish = function() {
|
||||
|
||||
var command = [
|
||||
"ebook-convert",
|
||||
path.join(that.options.output, "index.html"),
|
||||
path.join(that.options.output, "SUMMARY.html"),
|
||||
path.join(that.options.output, "index."+format),
|
||||
stringUtils.optionsToShellArgs(_options)
|
||||
].join(" ");
|
||||
|
||||
@@ -74,4 +74,5 @@ module.exports = {
|
||||
fs.exists(path, d.resolve);
|
||||
return d.promise;
|
||||
},
|
||||
readFileSync: fs.readFileSync.bind(fs)
|
||||
};
|
||||
|
||||
@@ -20,6 +20,11 @@ BaseGenerator.prototype.callHook = function(name, data) {
|
||||
return this.plugins.hook(name, data);
|
||||
};
|
||||
|
||||
// Sets up generator
|
||||
BaseGenerator.prototype.load = function() {
|
||||
return this.loadPlugins();
|
||||
};
|
||||
|
||||
BaseGenerator.prototype.loadPlugins = function() {
|
||||
var that = this;
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ var loadGenerator = function(options) {
|
||||
.then(function() {
|
||||
var generator = new generators[options.generator](options);
|
||||
|
||||
return generator.loadPlugins()
|
||||
return generator.load()
|
||||
.then(_.constant(generator));
|
||||
});
|
||||
};
|
||||
@@ -64,7 +64,7 @@ var generate = function(options) {
|
||||
try {
|
||||
var _config = require(path.resolve(options.input, options.configFile));
|
||||
|
||||
options = _.merge(options, _.omit(_config, 'input', 'configFile', 'defaultsPlugins'));
|
||||
options = _.merge(options, _.omit(_config, 'input', 'configFile', 'defaultsPlugins', 'generator'));
|
||||
}
|
||||
catch(err) {
|
||||
// No config file: not a big deal
|
||||
@@ -297,6 +297,9 @@ var generateBook = function(options) {
|
||||
})
|
||||
|
||||
// Finish generation
|
||||
.then(function() {
|
||||
return generator.callHook("finish:before");
|
||||
})
|
||||
.then(function() {
|
||||
return generator.finish();
|
||||
})
|
||||
|
||||
@@ -29,8 +29,9 @@ Generator.prototype.convertFile = function(content, input) {
|
||||
dir: path.dirname(input) || '/'
|
||||
});
|
||||
})
|
||||
.then(function(sections) {
|
||||
json.sections = sections;
|
||||
.then(function(parsed) {
|
||||
json.lexed = parsed.lexed;
|
||||
json.sections = parsed.sections;
|
||||
})
|
||||
.then(function() {
|
||||
return fs.writeFile(
|
||||
|
||||
@@ -21,8 +21,26 @@ util.inherits(Generator, BaseGenerator);
|
||||
|
||||
Generator.prototype.loadTemplates = function() {
|
||||
this.template = swig.compileFile(
|
||||
this.plugins.template("page") || path.resolve(this.options.theme, 'templates/page.html')
|
||||
this.plugins.template("ebook:page") || path.resolve(this.options.theme, 'templates/ebook/page.html')
|
||||
);
|
||||
this.summaryTemplate = swig.compileFile(
|
||||
this.plugins.template("ebook:sumary") || path.resolve(this.options.theme, 'templates/ebook/summary.html')
|
||||
);
|
||||
this.glossaryTemplate = swig.compileFile(
|
||||
this.plugins.template("ebook:glossary") || path.resolve(this.options.theme, 'templates/ebook/glossary.html')
|
||||
);
|
||||
};
|
||||
|
||||
// Generate table of contents
|
||||
Generator.prototype.writeToc = function() {
|
||||
var that = this;
|
||||
var basePath = ".";
|
||||
|
||||
return this._writeTemplate(this.summaryTemplate, {
|
||||
toc: parse.progress(this.options.navigation, "README.md").chapters,
|
||||
basePath: basePath,
|
||||
staticBase: path.join(basePath, "gitbook"),
|
||||
}, path.join(this.options.output, "SUMMARY.html"));
|
||||
};
|
||||
|
||||
Generator.prototype.finish = function() {
|
||||
@@ -31,9 +49,19 @@ Generator.prototype.finish = function() {
|
||||
var output = path.join(this.options.output, "index.html");
|
||||
|
||||
var progress = parse.progress(this.options.navigation, "README.md");
|
||||
|
||||
|
||||
return Q()
|
||||
|
||||
// Write table of contents
|
||||
.then(function() {
|
||||
return that.writeToc();
|
||||
})
|
||||
|
||||
// Write glossary
|
||||
.then(function() {
|
||||
return that.writeGlossary();
|
||||
})
|
||||
|
||||
// Copy cover
|
||||
.then(function() {
|
||||
return that.copyCover();
|
||||
|
||||
+36
-26
@@ -23,29 +23,29 @@ var Generator = function() {
|
||||
};
|
||||
util.inherits(Generator, BaseGenerator);
|
||||
|
||||
// Load all templates
|
||||
Generator.prototype.loadTemplates = function() {
|
||||
this.template = swig.compileFile(
|
||||
this.plugins.template("site") || path.resolve(this.options.theme, 'templates/site.html')
|
||||
);
|
||||
this.langsTemplate = swig.compileFile(
|
||||
this.plugins.template("langs") || path.resolve(this.options.theme, 'templates/langs.html')
|
||||
);
|
||||
this.glossaryTemplate = swig.compileFile(
|
||||
this.plugins.template("glossary") || path.resolve(this.options.theme, 'templates/glossary.html')
|
||||
);
|
||||
};
|
||||
|
||||
// Load plugins
|
||||
Generator.prototype.loadPlugins = function() {
|
||||
// Add template loading to load
|
||||
Generator.prototype.load = function() {
|
||||
var that = this;
|
||||
|
||||
return BaseGenerator.prototype.loadPlugins.apply(this)
|
||||
return BaseGenerator.prototype.load.apply(this)
|
||||
.then(function() {
|
||||
return that.loadTemplates();
|
||||
});
|
||||
};
|
||||
|
||||
// Load all templates
|
||||
Generator.prototype.loadTemplates = function() {
|
||||
this.template = swig.compileFile(
|
||||
this.plugins.template("site:page") || path.resolve(this.options.theme, 'templates/book/page.html')
|
||||
);
|
||||
this.langsTemplate = swig.compileFile(
|
||||
this.plugins.template("site:langs") || path.resolve(this.options.theme, 'templates/book/langs.html')
|
||||
);
|
||||
this.glossaryTemplate = swig.compileFile(
|
||||
this.plugins.template("site:glossary") || path.resolve(this.options.theme, 'templates/book/glossary.html')
|
||||
);
|
||||
};
|
||||
|
||||
// Generate a template
|
||||
Generator.prototype._writeTemplate = function(tpl, options, output, interpolate) {
|
||||
var that = this;
|
||||
@@ -118,20 +118,25 @@ Generator.prototype.prepareFile = function(content, _input) {
|
||||
return _callHook("page:before");
|
||||
})
|
||||
.then(function() {
|
||||
// Lex page
|
||||
return parse.lex(page.content);
|
||||
})
|
||||
.then(function(lexed) {
|
||||
page.lexed = lexed;
|
||||
|
||||
// Lex, parse includes and get
|
||||
// Get HTML generated sections
|
||||
return parse.page(lexed, {
|
||||
return parse.page(page.content, {
|
||||
// Local files path
|
||||
dir: path.dirname(_input) || '/',
|
||||
|
||||
// Output directory
|
||||
outdir: path.dirname(_input) || '/',
|
||||
|
||||
// Includer for templating
|
||||
includer: parse.includer(that.options.variables, [
|
||||
path.dirname(_input) || '/',
|
||||
path.join(that.options.input, '_includes'),
|
||||
], path.join, fs.readFileSync)
|
||||
});
|
||||
})
|
||||
.then(function(sections) {
|
||||
page.sections = sections;
|
||||
.then(function(parsed) {
|
||||
page.lexed = parsed.lexed;
|
||||
page.sections = parsed.sections;
|
||||
|
||||
// Use plugin hook
|
||||
return _callHook("page");
|
||||
@@ -149,7 +154,12 @@ Generator.prototype.convertFile = function(content, _input) {
|
||||
if (_output == "README.html") _output = "index.html";
|
||||
var output = path.join(this.options.output, _output);
|
||||
var basePath = path.relative(path.dirname(output), this.options.output) || ".";
|
||||
|
||||
|
||||
// Bug fix for issue #493 which would occur when relative-links are 2-level or more deep in win32
|
||||
if (process.platform === 'win32') {
|
||||
basePath = basePath.replace(/\\/g, '/');
|
||||
}
|
||||
|
||||
return this.prepareFile(content, _input)
|
||||
.then(function(page) {
|
||||
// Index page in search
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
var fs = require('graceful-fs');
|
||||
var path = require('path');
|
||||
|
||||
module.exports = function(code, folder) {
|
||||
folder = folder || '';
|
||||
|
||||
return code.replace(/{{([\s\S]+?)}}/g, function(match, filename) {
|
||||
// Normalize filename
|
||||
var fname = path.join(folder, filename.trim());
|
||||
|
||||
// Try including snippet from FS
|
||||
try {
|
||||
// Trim trailing newlines/space of imported snippets
|
||||
return fs.readFileSync(fname, 'utf8').trimRight();
|
||||
} catch(err) {}
|
||||
|
||||
// If fails leave content as is
|
||||
return match;
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
var _ = require('lodash');
|
||||
|
||||
module.exports = function(markdown, includer) {
|
||||
// Memoized include function (to cache lookups)
|
||||
var _include = _.memoize(includer);
|
||||
|
||||
return markdown.replace(/{{([\s\S]+?)}}/g, function(match, key) {
|
||||
// If fails leave content as is
|
||||
key = key.trim();
|
||||
return _include(key) || match;
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
// Return a fs inclduer
|
||||
module.exports = function(ctx, folders, resolveFile, readFile) {
|
||||
return function(name) {
|
||||
return ctx[name] ||
|
||||
folders.map(function(folder) {
|
||||
// Try including snippet from FS
|
||||
try {
|
||||
var fname = resolveFile(folder, name);
|
||||
// Trim trailing newlines/space of imported snippets
|
||||
return readFile(fname, 'utf8').trimRight();
|
||||
} catch(err) {}
|
||||
})
|
||||
.filter(Boolean)[0];
|
||||
}
|
||||
};
|
||||
+2
-1
@@ -6,5 +6,6 @@ module.exports = {
|
||||
lex: require('./lex'),
|
||||
progress: require('./progress'),
|
||||
navigation: require('./navigation'),
|
||||
readme: require('./readme')
|
||||
readme: require('./readme'),
|
||||
includer: require('./includer')
|
||||
};
|
||||
|
||||
+10
-11
@@ -5,7 +5,7 @@ var hljs = require('highlight.js');
|
||||
var lex = require('./lex');
|
||||
var renderer = require('./renderer');
|
||||
|
||||
var codeInclude = require('./code_include');
|
||||
var include = require('./include');
|
||||
var lnormalize = require('../utils/lang').normalize;
|
||||
|
||||
|
||||
@@ -51,8 +51,10 @@ function parsePage(src, options) {
|
||||
options = options || {};
|
||||
|
||||
// Lex if not already lexed
|
||||
return (_.isArray(src) ? src : lex(src))
|
||||
.map(function(section) {
|
||||
var parsed = {
|
||||
lexed: (_.isArray(src) ? src : lex(include(src, options.includer || function() { return undefined; })))
|
||||
};
|
||||
parsed.sections = parsed.lexed.map(function(section) {
|
||||
// Transform given type
|
||||
if(section.type === 'exercise') {
|
||||
var nonCodeNodes = _.reject(section, {
|
||||
@@ -74,20 +76,15 @@ function parsePage(src, options) {
|
||||
// Main language
|
||||
var lang = validLangs ? langs[0] : null;
|
||||
|
||||
// codeInclude shortcut
|
||||
var ci = function(code) {
|
||||
return codeInclude(code, options.dir);
|
||||
};
|
||||
|
||||
return {
|
||||
id: section.id,
|
||||
type: section.type,
|
||||
content: render(nonCodeNodes, options),
|
||||
lang: lang,
|
||||
code: {
|
||||
base: ci(codeNodes[0].text),
|
||||
solution: ci(codeNodes[1].text),
|
||||
validation: ci(codeNodes[2].text),
|
||||
base: codeNodes[0].text,
|
||||
solution: codeNodes[1].text,
|
||||
validation: codeNodes[2].text,
|
||||
// Context is optional
|
||||
context: codeNodes[3] ? codeNodes[3].text : null,
|
||||
}
|
||||
@@ -155,6 +152,8 @@ function parsePage(src, options) {
|
||||
content: render(section, options)
|
||||
};
|
||||
});
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
// Exports
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
var url = require('url');
|
||||
var _ = require('lodash');
|
||||
var inherits = require('util').inherits;
|
||||
var links = require('../utils').links;
|
||||
var codeInclude = require('./code_include');
|
||||
|
||||
|
||||
var path = require('path');
|
||||
|
||||
var kramed = require('kramed');
|
||||
|
||||
var rendererId = 0;
|
||||
@@ -52,11 +48,11 @@ GitBookRenderer.prototype.link = function(href, title, text) {
|
||||
|
||||
// Parsed version of the url
|
||||
var parsed = url.parse(href);
|
||||
|
||||
var o = this._extra_options;
|
||||
var extname = parsed.path? _.last(parsed.path.split(".")) : "";
|
||||
|
||||
// Relative link, rewrite it to point to github repo
|
||||
if(links.isRelative(_href) && path.extname(parsed.path) == ".md") {
|
||||
if(links.isRelative(_href) && extname == "md") {
|
||||
_href = links.toAbsolute(_href, o.dir || "./", o.outdir || "./");
|
||||
_href = _href.replace(".md", ".html");
|
||||
}
|
||||
@@ -130,8 +126,7 @@ GitBookRenderer.prototype.listitem = function(text) {
|
||||
GitBookRenderer.prototype.code = function(code, lang, escaped) {
|
||||
return GitBookRenderer.super_.prototype.code.call(
|
||||
this,
|
||||
// Import code snippets
|
||||
codeInclude(code, this._extra_options.dir),
|
||||
code,
|
||||
lang,
|
||||
escaped
|
||||
);
|
||||
|
||||
+2
-2
@@ -11,8 +11,8 @@ function escapeShellArg(arg) {
|
||||
function optionsToShellArgs(options) {
|
||||
return _.chain(options)
|
||||
.map(function(value, key) {
|
||||
if (value == null || value == false) return null;
|
||||
if (value == true) return key;
|
||||
if (value == null || value === false) return null;
|
||||
if (value === true) return key;
|
||||
return key+"="+escapeShellArg(value);
|
||||
})
|
||||
.compact()
|
||||
|
||||
+5
-3
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gitbook",
|
||||
"version": "1.1.1",
|
||||
"version": "1.3.4",
|
||||
"homepage": "http://www.gitbook.io/",
|
||||
"description": "Library and cmd utility to generate GitBooks",
|
||||
"main": "lib/index.js",
|
||||
@@ -16,7 +16,7 @@
|
||||
"commander": "2.2.0",
|
||||
"graceful-fs": "3.0.2",
|
||||
"fs-extra": "0.10.0",
|
||||
"highlight.js": "8.2.0",
|
||||
"highlight.js": "8.3.0",
|
||||
"tmp": "0.0.23",
|
||||
"semver": "2.2.1",
|
||||
"gaze": "~0.5.1",
|
||||
@@ -35,7 +35,9 @@
|
||||
"grunt-contrib-copy": "0.5.0",
|
||||
"grunt-contrib-less": "~0.5.0",
|
||||
"grunt-contrib-requirejs": "0.4.1",
|
||||
"grunt-bower-install-simple": "0.9.2"
|
||||
"grunt-bower-install-simple": "0.9.2",
|
||||
"grunt-browserify": "3.1.0",
|
||||
"grunt-contrib-uglify": "0.6.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "export TESTING=true; mocha --reporter list"
|
||||
|
||||
+5
-1
@@ -3,12 +3,13 @@ var path = require('path');
|
||||
var assert = require('assert');
|
||||
|
||||
var page = require('../').parse.page;
|
||||
var includer = require('../').parse.includer;
|
||||
|
||||
var FIXTURES_DIR = path.join(__dirname, './fixtures/');
|
||||
|
||||
function loadPage (name, options) {
|
||||
var CONTENT = fs.readFileSync(FIXTURES_DIR + name + '.md', 'utf8');
|
||||
return page(CONTENT, options);
|
||||
return page(CONTENT, options).sections;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +17,9 @@ describe('Code includes', function() {
|
||||
|
||||
var LEXED = loadPage('INCLUDES', {
|
||||
'dir': FIXTURES_DIR,
|
||||
'includer': includer({}, [
|
||||
FIXTURES_DIR
|
||||
], path.join, fs.readFileSync)
|
||||
});
|
||||
|
||||
var INCLUDED_C = fs.readFileSync(path.join(FIXTURES_DIR, 'included.c'), 'utf8');
|
||||
|
||||
+1
-10
@@ -6,7 +6,7 @@ var page = require('../').parse.page;
|
||||
|
||||
function loadPage (name, options) {
|
||||
var CONTENT = fs.readFileSync(path.join(__dirname, './fixtures/' + name + '.md'), 'utf8');
|
||||
return page(CONTENT, options);
|
||||
return page(CONTENT, options).sections;
|
||||
}
|
||||
|
||||
var LEXED = loadPage('PAGE', {
|
||||
@@ -80,9 +80,6 @@ describe('Page parsing', function() {
|
||||
describe('Relative links', function() {
|
||||
it('should replace link to .md by link to .html', function() {
|
||||
var LEXED = loadPage('MARKDOWN_LINKS', {
|
||||
// GitHub repo ID
|
||||
repo: 'GitBookIO/javascript',
|
||||
|
||||
// Imaginary folder of markdown file
|
||||
dir: 'course',
|
||||
outdir: 'course'
|
||||
@@ -96,9 +93,6 @@ describe('Relative links', function() {
|
||||
describe('Relative images', function() {
|
||||
it('should keep image relative with considering output directory in site format', function() {
|
||||
var LEXED = loadPage('IMAGES', {
|
||||
// GitHub repo ID
|
||||
repo: 'GitBookIO/javascript',
|
||||
|
||||
// Imaginary folder of markdown file
|
||||
dir: 'syntax',
|
||||
outdir: 'syntax'
|
||||
@@ -110,9 +104,6 @@ describe('Relative images', function() {
|
||||
|
||||
it('should keep image relative with considering output directory in page format', function() {
|
||||
var LEXED = loadPage('IMAGES', {
|
||||
// GitHub repo ID
|
||||
repo: 'GitBookIO/javascript',
|
||||
|
||||
// Imaginary folder of markdown file
|
||||
dir: 'syntax',
|
||||
outdir: './'
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -31,21 +31,57 @@ define([
|
||||
return d.promise();
|
||||
}
|
||||
|
||||
$.fn.replaceText = function( search, replace, text_only ) {
|
||||
return this.each(function(){
|
||||
var node = this.firstChild,
|
||||
val,
|
||||
new_val,
|
||||
|
||||
// Elements to be removed at the end.
|
||||
remove = [];
|
||||
|
||||
// Only continue if firstChild exists.
|
||||
if ( node ) {
|
||||
|
||||
// Loop over all childNodes.
|
||||
do {
|
||||
|
||||
// Only process text nodes.
|
||||
if ( node.nodeType === 3 ) {
|
||||
|
||||
// The original node value.
|
||||
val = node.nodeValue;
|
||||
|
||||
// The new value.
|
||||
new_val = val.replace( search, replace );
|
||||
|
||||
// Only replace text if the new value is actually different!
|
||||
if ( new_val !== val ) {
|
||||
|
||||
if ( !text_only && /</.test( new_val ) ) {
|
||||
// The new value contains HTML, set it in a slower but far more
|
||||
// robust way.
|
||||
$(node).before( new_val );
|
||||
|
||||
// Don't remove the node yet, or the loop will lose its place.
|
||||
remove.push( node );
|
||||
} else {
|
||||
// The new value contains no HTML, so it can be set in this
|
||||
// very fast, simple way.
|
||||
node.nodeValue = new_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} while ( node = node.nextSibling );
|
||||
}
|
||||
|
||||
// Time to remove those elements!
|
||||
remove.length && $(remove).remove();
|
||||
});
|
||||
};
|
||||
|
||||
var pregQuote = function( str ) {
|
||||
// http://kevin.vanzonneveld.net
|
||||
// + original by: booeyOH
|
||||
// + improved by: Ates Goral (http://magnetiq.com)
|
||||
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
|
||||
// + bugfixed by: Onno Marsman
|
||||
// * example 1: preg_quote("$40");
|
||||
// * returns 1: '\$40'
|
||||
// * example 2: preg_quote("*RRRING* Hello?");
|
||||
// * returns 2: '\*RRRING\* Hello\?'
|
||||
// * example 3: preg_quote("\\.+*?[^]$(){}=!<>|:");
|
||||
// * returns 3: '\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:'
|
||||
|
||||
return (str+'').replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, "\\$1");
|
||||
};
|
||||
|
||||
@@ -58,48 +94,13 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
var matchText = function(node, regex, callback, excludeElements) {
|
||||
excludeElements || (excludeElements = ['script', 'style', 'iframe', 'canvas']);
|
||||
var child = node.firstChild;
|
||||
|
||||
if (!child) return;
|
||||
|
||||
do {
|
||||
switch (child.nodeType) {
|
||||
case 1:
|
||||
if (excludeElements.indexOf(child.tagName.toLowerCase()) > -1) {
|
||||
continue;
|
||||
}
|
||||
matchText(child, regex, callback, excludeElements);
|
||||
break;
|
||||
case 3:
|
||||
child.data.replace(regex, function(all) {
|
||||
var args = [].slice.call(arguments),
|
||||
offset = args[args.length - 2],
|
||||
newTextNode = child.splitText(offset);
|
||||
|
||||
newTextNode.data = newTextNode.data.substr(all.length);
|
||||
callback.apply(window, [child].concat(args));
|
||||
child = newTextNode;
|
||||
});
|
||||
break;
|
||||
}
|
||||
} while (child = child.nextSibling);
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
var replaceTerm = function($el, term) {
|
||||
var r = new RegExp( "\\b(" + pregQuote(term.name.toLowerCase()) + ")\\b" , 'gi' );
|
||||
|
||||
matchText($el.get(0), r, function(node, match, offset) {
|
||||
var span = document.createElement("span");
|
||||
span.className = "glossary-term";
|
||||
span.textContent = match;
|
||||
span.setAttribute("data-glossary-term", term.id);
|
||||
span.setAttribute("title", term.description);
|
||||
node.parentNode.insertBefore(span, node.nextSibling);
|
||||
$el.find("*").replaceText(r, function(match) {
|
||||
return "<span class='glossary-term' data-glossary-term='"+term.id+"' title='"+term.description+"'>"+match+"</span>";
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
var prepare = function() {
|
||||
|
||||
@@ -256,7 +256,8 @@
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ol ul {
|
||||
ol ul,
|
||||
ul ul {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
@import "ebook/highlight.less";
|
||||
|
||||
.page {
|
||||
&.page-toc {
|
||||
ol {
|
||||
margin: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.book-chapter {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends "site.html" %}
|
||||
{% extends "page.html" %}
|
||||
|
||||
{% block title %}Glossary | {{ title }}{% endblock %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends "layout.html" %}
|
||||
{% extends "../layout.html" %}
|
||||
|
||||
{% block title %}{{ title }}{% endblock %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends "layout.html" %}
|
||||
{% extends "../layout.html" %}
|
||||
|
||||
{% block head %}
|
||||
{% parent %}
|
||||
@@ -15,10 +15,10 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="book" data-level="{{ progress.current.level }}" data-basepath="{{ basePath }}" data-revision="{{ revision }}">
|
||||
{% include "includes/book/summary.html" %}
|
||||
{% include "includes/summary.html" %}
|
||||
<div class="book-body">
|
||||
<div class="body-inner">
|
||||
{% include "includes/book/header.html" %}
|
||||
{% include "includes/header.html" %}
|
||||
<div class="page-wrapper" tabindex="-1">
|
||||
<div class="page-inner">
|
||||
{% block page_inner %}
|
||||
@@ -27,9 +27,9 @@
|
||||
{% if section.type == "normal" %}
|
||||
{% autoescape false %}{{ section.content }}{% endautoescape %}
|
||||
{% elif section.type == "exercise" %}
|
||||
{% include "./includes/book/exercise.html" with {section: section} %}
|
||||
{% include "./includes/exercise.html" with {section: section} %}
|
||||
{% elif section.type == "quiz" %}
|
||||
{% include "./includes/book/quiz.html" with {section: section} %}
|
||||
{% include "./includes/quiz.html" with {section: section} %}
|
||||
{% endif %}
|
||||
</section>
|
||||
{% endfor %}
|
||||
@@ -0,0 +1,15 @@
|
||||
{% extends "./layout.html" %}
|
||||
|
||||
{% block title %}Glossary | {{ title }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="page page-toc">
|
||||
<h1>Glossary</h1>
|
||||
{% for item in glossaryIndex %}
|
||||
<section class="normal glossary" id="{{ item.id }}">
|
||||
<h2><a href="#{{ item.id }}">{{ item.name }}</a></h2>
|
||||
<p>{{ item.description }}</p>
|
||||
</section>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en-US" {% block htmlTag %}{% endblock %}>
|
||||
{{ htmlSnippet("html:start")|default("") }}
|
||||
<head>
|
||||
{{ htmlSnippet("head:start")|default("") }}
|
||||
<meta charset="UTF-8">
|
||||
<title>{% block title %}{% endblock %}</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||
<meta name="description" content="{% block description %}{% endblock %}">
|
||||
<meta name="generator" content="GitBook {{ gitbook.version }}">
|
||||
{% block head %}{% endblock %}
|
||||
{{ htmlSnippet("head:end")|default("") }}
|
||||
</head>
|
||||
<body>
|
||||
{{ htmlSnippet("body:start")|default("") }}
|
||||
{% block style %}{% endblock %}
|
||||
{% block content %}{% endblock %}
|
||||
{% block javascript %}{% endblock %}
|
||||
{{ htmlSnippet("body:end")|default("") }}
|
||||
</body>
|
||||
{{ htmlSnippet("html:end")|default("") }}
|
||||
</html>
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends "layout.html" %}
|
||||
{% extends "./layout.html" %}
|
||||
|
||||
{% block title %}{{ progress.current.title }} | {{ title }}{% endblock %}
|
||||
|
||||
@@ -17,20 +17,16 @@
|
||||
<div class="page">
|
||||
<h1 class="book-chapter book-chapter-{{ progress.current.level|lvl }}">{{ progress.current.title }}</h1>
|
||||
{% for section in content %}
|
||||
<section class="{{ section.type }}" id="section-{{ section.id }}">
|
||||
<div class="{{ section.type }}" id="section-{{ section.id }}">
|
||||
{% if section.type == "normal" %}
|
||||
{% autoescape false %}{{ section.content }}{% endautoescape %}
|
||||
{% elif section.type == "exercise" %}
|
||||
{% include "./includes/page/exercise.html" with {section: section} %}
|
||||
{% include "./includes/exercise.html" with {section: section} %}
|
||||
{% elif section.type == "quiz" %}
|
||||
{% include "./includes/page/quiz.html" with {section: section} %}
|
||||
{% include "./includes/quiz.html" with {section: section} %}
|
||||
{% endif %}
|
||||
</section>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% if progress.current.next and progress.current.next.path %}
|
||||
<a href="{{ basePath }}/{{ progress.current.next.path|mdLink }}" />
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
{% extends "./layout.html" %}
|
||||
|
||||
{% block title %}Table of Contents | {{ title }}{% endblock %}
|
||||
|
||||
{% block style %}
|
||||
<link rel="stylesheet" href="{{ staticBase }}/print.css">
|
||||
{% for resource in plugins.resources.css %}
|
||||
{% if resource.url %}
|
||||
<link rel="stylesheet" href="{{ resource.url }}">
|
||||
{% else %}
|
||||
<link rel="stylesheet" href="{{ staticBase }}/plugins/{{ resource.path }}">
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
{% macro articles(_articles) %}
|
||||
{% for item in _articles %}
|
||||
{% set externalLink = item.path|isExternalLink %}
|
||||
<li>
|
||||
{% if item.path %}
|
||||
{% if !externalLink %}
|
||||
<a href="{{ basePath }}/{{ item.path|mdLink }}">{{ item.title }}</a>
|
||||
{% else %}
|
||||
<a target="_blank" href="{{ item.path }}">{{ item.title }}</a>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{{ item.title }}
|
||||
{% endif %}
|
||||
{% if item.articles.length > 0 %}
|
||||
<ol>
|
||||
{{ articles(item.articles) }}
|
||||
</ol>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% endmacro %}
|
||||
|
||||
{% block content %}
|
||||
<div class="page page-toc">
|
||||
<h1>Table of Contents</h1>
|
||||
<ol>
|
||||
{{ articles(summary.chapters) }}
|
||||
|
||||
{% if glossary.length > 0 %}
|
||||
<li><a href="{{ basePath }}/GLOSSARY.html">Glossary</a></li>
|
||||
{% endif %}
|
||||
</ol>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<head>
|
||||
{{ htmlSnippet("head:start")|default("") }}
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=11; IE=10; IE=9; IE=8; IE=7; IE=EDGE" />
|
||||
<title>{% block title %}{% endblock %}</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||
<meta name="description" content="{% block description %}{% endblock %}">
|
||||
|
||||
Reference in New Issue
Block a user