mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-29 05:29:02 +00:00
Compare commits
56 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 799815d85a | |||
| 2946246834 | |||
| 6d276d1e79 | |||
| 6a3a369b3e | |||
| 5d8afa2135 | |||
| ab3e6aa8ce | |||
| 822092736e | |||
| 7497acd2e3 | |||
| ae137885b8 | |||
| b964cc7009 | |||
| c2ea126c5f | |||
| b668dba479 | |||
| 2cae5a0310 | |||
| b6a0f3ff67 | |||
| fa00b52fb5 | |||
| 2999d90907 | |||
| b6696bcad2 | |||
| 728c87c525 | |||
| ace394ee2d | |||
| 076ee98f64 | |||
| 2e472654ca | |||
| d46bd14678 | |||
| b3e5b3d106 | |||
| b830ef5dca | |||
| 45326c4ad2 | |||
| 603b61e8c8 | |||
| efb066c8e3 | |||
| c30db427b1 | |||
| 23056fc85d | |||
| 5f1bfc0280 | |||
| b715901f92 | |||
| 38fea06cf9 | |||
| 4481b5f556 | |||
| 0e0d051f7c | |||
| a1b649a279 | |||
| e6bc0a0fb7 | |||
| 93e4016c09 | |||
| 20c741a248 | |||
| 54f530c7c3 | |||
| 9fdc5da22d | |||
| 99ce48b146 | |||
| 6a33ad9ef7 | |||
| ca94055adf | |||
| 36a67e4c91 | |||
| 69431e1bbb | |||
| a3fc4ee2b0 | |||
| e505fd6d54 | |||
| 93a3785e4c | |||
| a02de84812 | |||
| c0521f0ec7 | |||
| 83d8c16853 | |||
| 47e9506397 | |||
| b8a3d0e254 | |||
| 001d7ec44e | |||
| 5cb0ec447a | |||
| 8f4b799d3c |
@@ -30,14 +30,55 @@ $ gitbook build ./repository --output=./outputFolder
|
|||||||
Options for commands `build` and `serve` are:
|
Options for commands `build` and `serve` are:
|
||||||
|
|
||||||
```
|
```
|
||||||
-t, --title <name> Name of the book to generate, defaults to repo name
|
|
||||||
-i, --intro <intro> Description of the book to generate
|
|
||||||
-g, --github <repo_path> ID of github repo like : username/repo
|
|
||||||
-o, --output <directory> Path to output directory, defaults to ./_book
|
-o, --output <directory> Path to output directory, defaults to ./_book
|
||||||
-f, --format <name> Change generation format, defaults to site, availables are: site, page, pdf, json
|
-f, --format <name> Change generation format, defaults to site, availables are: site, page, pdf, json
|
||||||
--githubHost <url> The url of the github host (defaults to https://github.com/)
|
--config <config file> Configuration file to use, defaults to book.json
|
||||||
--plugins <plugins> List of plugins to use separated by ","
|
```
|
||||||
--pluginsConfig <json file> JSON File containing plugins configuration
|
|
||||||
|
GitBook load the default configuration from a `book.json` file in the repository if it exists.
|
||||||
|
|
||||||
|
Here are the options that can be stored in this file:
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
// Folders to use for output (caution: it override the value from the command line)
|
||||||
|
"output": null,
|
||||||
|
|
||||||
|
// Generator to use for building (caution: it override the value from the command line)
|
||||||
|
"generator": "site",
|
||||||
|
|
||||||
|
// Book title and description (defaults are extracted from the README)
|
||||||
|
"title": null,
|
||||||
|
"description": null,
|
||||||
|
|
||||||
|
// GitHub informations (defaults are extracted using git)
|
||||||
|
"github": null,
|
||||||
|
"githubHost": "https://github.com/",
|
||||||
|
|
||||||
|
// Plugins list, can contain "-name" for removing default plugins
|
||||||
|
"plugins": [],
|
||||||
|
|
||||||
|
// Global configuration for plugins
|
||||||
|
"pluginsConfig": {},
|
||||||
|
|
||||||
|
// Links in template (null: default, false: remove, string: new value)
|
||||||
|
"links": {
|
||||||
|
// Link to home in the top-left corner
|
||||||
|
"home": null,
|
||||||
|
|
||||||
|
// Links in top of sidebar
|
||||||
|
"about": null,
|
||||||
|
"issues": null,
|
||||||
|
"edit": null,
|
||||||
|
|
||||||
|
// Sharing links
|
||||||
|
"sharing": {
|
||||||
|
"google": null,
|
||||||
|
"facebook": null,
|
||||||
|
"twitter": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
You can publish your books to our index by visiting [GitBook.io](http://www.gitbook.io)
|
You can publish your books to our index by visiting [GitBook.io](http://www.gitbook.io)
|
||||||
@@ -137,7 +178,7 @@ GitBook will read the `.gitignore`, `.bookignore` and `.ignore` files to get a l
|
|||||||
|
|
||||||
#### Plugins
|
#### Plugins
|
||||||
|
|
||||||
Plugins can used to extend your book functionnalities. Read [GitbookIO/plugin](https://github.com/GitbookIO/plugin) for more informations about how to build a plugin for gitbook.
|
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.
|
||||||
|
|
||||||
##### Default plugins:
|
##### Default plugins:
|
||||||
|
|
||||||
@@ -147,3 +188,9 @@ Plugins can used to extend your book functionnalities. Read [GitbookIO/plugin](h
|
|||||||
##### Other plugins:
|
##### Other plugins:
|
||||||
|
|
||||||
* [Google Analytics](https://github.com/GitbookIO/plugin-ga): Google Analytics tracking for your book
|
* [Google Analytics](https://github.com/GitbookIO/plugin-ga): Google Analytics tracking for your book
|
||||||
|
* [Disqus](https://github.com/GitbookIO/plugin-disqus): Disqus comments integration in your book
|
||||||
|
* [Transform annoted quotes to notes](https://github.com/erixtekila/gitbook-plugin-richquotes): Allow extra markdown markup to render blockquotes as nice notes
|
||||||
|
* [Send code to console](https://github.com/erixtekila/gitbook-plugin-toconsole): Evaluate javascript blockin the browser inspector's console
|
||||||
|
* [Revealable sections](https://github.com/mrpotes/gitbook-plugin-reveal): Reveal sections of the page using buttons made from the first title in each section
|
||||||
|
* [Markdown within HTML](https://github.com/mrpotes/gitbook-plugin-nestedmd): Process markdown within HTML blocks - allows custom layout options for individual pages
|
||||||
|
* [Bootstrap JavaScript plugins](https://github.com/mrpotes/gitbook-plugin-bootstrapjs): Use the [Bootstrap JavaScript plugins](http://getbootstrap.com/javascript) in your online GitBook
|
||||||
|
|||||||
+9
-36
@@ -12,12 +12,7 @@ var buildCommand = function(command) {
|
|||||||
return command
|
return command
|
||||||
.option('-o, --output <directory>', 'Path to output directory, defaults to ./_book')
|
.option('-o, --output <directory>', 'Path to output directory, defaults to ./_book')
|
||||||
.option('-f, --format <name>', 'Change generation format, defaults to site, availables are: '+_.keys(generators).join(", "))
|
.option('-f, --format <name>', 'Change generation format, defaults to site, availables are: '+_.keys(generators).join(", "))
|
||||||
.option('-t, --title <name>', 'Name of the book to generate, default is extracted from readme')
|
.option('--config <config file>', 'Configuration file to use, defualt to book.json')
|
||||||
.option('-i, --intro <intro>', 'Description of the book to generate, default is extracted from readme')
|
|
||||||
.option('--plugins <plugins>', 'List of plugins to use separated by ","')
|
|
||||||
.option('--pluginsConfig <json file>', 'JSON File containing plugins configuration')
|
|
||||||
.option('-g, --github <repo_path>', 'ID of github repo like : username/repo')
|
|
||||||
.option('--githubHost <url>', 'The url of the github host (defaults to https://github.com/');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -26,37 +21,15 @@ var makeBuildFunc = function(converter) {
|
|||||||
dir = dir || process.cwd();
|
dir = dir || process.cwd();
|
||||||
outputDir = options.output;
|
outputDir = options.output;
|
||||||
|
|
||||||
// Read plugins config
|
|
||||||
var pluginsConfig = {};
|
|
||||||
if (options.pluginsConfig) {
|
|
||||||
pluginsConfig = JSON.parse(fs.readFileSync(options.pluginsConfig))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
console.log('Starting build ...');
|
console.log('Starting build ...');
|
||||||
// Get repo's URL
|
return converter(
|
||||||
return utils.gitURL(dir)
|
_.extend({}, options || {}, {
|
||||||
.then(function(url) {
|
input: dir,
|
||||||
// Get ID of repo
|
output: outputDir,
|
||||||
return utils.githubID(url);
|
generator: options.format,
|
||||||
}, function(err) {
|
configFile: options.config
|
||||||
return null;
|
})
|
||||||
})
|
)
|
||||||
.then(function(repoID) {
|
|
||||||
return converter(
|
|
||||||
_.extend(options || {}, {
|
|
||||||
input: dir,
|
|
||||||
output: outputDir,
|
|
||||||
title: options.title,
|
|
||||||
description: options.intro,
|
|
||||||
github: options.github || repoID,
|
|
||||||
githubHost: options.githubHost,
|
|
||||||
generator: options.format,
|
|
||||||
plugins: options.plugins,
|
|
||||||
pluginsConfig: pluginsConfig
|
|
||||||
})
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.then(function(output) {
|
.then(function(output) {
|
||||||
console.log("Successfuly built !");
|
console.log("Successfuly built !");
|
||||||
return output;
|
return output;
|
||||||
|
|||||||
+32
-11
@@ -12,6 +12,7 @@ var fs = require('../lib/generate/fs');
|
|||||||
|
|
||||||
var utils = require('./utils');
|
var utils = require('./utils');
|
||||||
var build = require('./build');
|
var build = require('./build');
|
||||||
|
var Server = require('./server');
|
||||||
|
|
||||||
// General options
|
// General options
|
||||||
prog
|
prog
|
||||||
@@ -24,19 +25,39 @@ build.command(prog.command('build [source_dir]'))
|
|||||||
build.command(prog.command('serve [source_dir]'))
|
build.command(prog.command('serve [source_dir]'))
|
||||||
.description('Build then serve a gitbook from a directory')
|
.description('Build then serve a gitbook from a directory')
|
||||||
.option('-p, --port <port>', 'Port for server to listen on', 4000)
|
.option('-p, --port <port>', 'Port for server to listen on', 4000)
|
||||||
|
.option('--no-watch', 'Disable restart with file watching')
|
||||||
.action(function(dir, options) {
|
.action(function(dir, options) {
|
||||||
build.folder(dir, options || {})
|
var server = new Server();
|
||||||
.then(function(_options) {
|
|
||||||
console.log();
|
var generate = function() {
|
||||||
console.log('Starting server ...');
|
if (server.isRunning()) console.log("Stopping server");
|
||||||
return utils.serveDir(_options.output, options.port)
|
|
||||||
|
server.stop()
|
||||||
|
.then(function() {
|
||||||
|
return build.folder(dir, options);
|
||||||
|
})
|
||||||
|
.then(function(_options) {
|
||||||
|
console.log();
|
||||||
|
console.log('Starting server ...');
|
||||||
|
return server.start(_options.output, options.port)
|
||||||
|
.then(function() {
|
||||||
|
console.log('Serving book on http://localhost:'+options.port);
|
||||||
|
|
||||||
|
if (!options.watch) return;
|
||||||
|
return utils.watch(_options.input)
|
||||||
|
.then(function(filepath) {
|
||||||
|
console.log("Restart after change in files");
|
||||||
|
console.log('');
|
||||||
|
return generate();
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
.fail(utils.logError);
|
.fail(utils.logError);
|
||||||
})
|
};
|
||||||
.then(function() {
|
|
||||||
console.log('Serving book on http://localhost:'+options.port);
|
console.log('Press CTRL+C to quit ...');
|
||||||
console.log();
|
console.log('')
|
||||||
console.log('Press CTRL+C to quit ...');
|
generate();
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
build.command(prog.command('pdf [source_dir]'))
|
build.command(prog.command('pdf [source_dir]'))
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
var Q = require('q');
|
||||||
|
var _ = require('lodash');
|
||||||
|
|
||||||
|
var events = require('events');
|
||||||
|
var http = require('http');
|
||||||
|
var send = require('send');
|
||||||
|
var util = require('util');
|
||||||
|
var url = require('url');
|
||||||
|
|
||||||
|
var Server = function() {
|
||||||
|
this.running = null;
|
||||||
|
this.dir = null;
|
||||||
|
this.port = 0;
|
||||||
|
this.sockets = [];
|
||||||
|
};
|
||||||
|
util.inherits(Server, events.EventEmitter);
|
||||||
|
|
||||||
|
// Return true if the server is running
|
||||||
|
Server.prototype.isRunning = function() {
|
||||||
|
return this.running != null;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Stop the server
|
||||||
|
Server.prototype.stop = function() {
|
||||||
|
var that = this;
|
||||||
|
if (!this.isRunning()) return Q();
|
||||||
|
|
||||||
|
var d = Q.defer();
|
||||||
|
this.running.close(function(err) {
|
||||||
|
that.running = null;
|
||||||
|
that.emit("state", false);
|
||||||
|
|
||||||
|
if (err) d.reject(err);
|
||||||
|
else d.resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
for (var i = 0; i < this.sockets.length; i++) {
|
||||||
|
this.sockets[i].destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
return d.promise;
|
||||||
|
};
|
||||||
|
|
||||||
|
Server.prototype.start = function(dir, port) {
|
||||||
|
var that = this, pre = Q();
|
||||||
|
port = port || 8004;
|
||||||
|
|
||||||
|
if (that.isRunning()) pre = this.stop();
|
||||||
|
return pre
|
||||||
|
.then(function() {
|
||||||
|
var d = Q.defer();
|
||||||
|
|
||||||
|
that.running = http.createServer(function(req, res){
|
||||||
|
// Render error
|
||||||
|
function error(err) {
|
||||||
|
res.statusCode = err.status || 500;
|
||||||
|
res.end(err.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Redirect to directory's index.html
|
||||||
|
function redirect() {
|
||||||
|
res.statusCode = 301;
|
||||||
|
res.setHeader('Location', req.url + '/');
|
||||||
|
res.end('Redirecting to ' + req.url + '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send file
|
||||||
|
send(req, url.parse(req.url).pathname)
|
||||||
|
.root(dir)
|
||||||
|
.on('error', error)
|
||||||
|
.on('directory', redirect)
|
||||||
|
.pipe(res);
|
||||||
|
});
|
||||||
|
|
||||||
|
that.running.on('connection', function (socket) {
|
||||||
|
that.sockets.push(socket);
|
||||||
|
socket.setTimeout(4000);
|
||||||
|
socket.on('close', function () {
|
||||||
|
that.sockets.splice(that.sockets.indexOf(socket), 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
that.running.listen(port, function(err) {
|
||||||
|
if (err) return d.reject(err);
|
||||||
|
|
||||||
|
that.port = port;
|
||||||
|
that.dir = dir;
|
||||||
|
that.emit("state", true);
|
||||||
|
d.resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
return d.promise;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Server;
|
||||||
+15
-74
@@ -4,83 +4,27 @@ var _ = require('lodash');
|
|||||||
var http = require('http');
|
var http = require('http');
|
||||||
var send = require('send');
|
var send = require('send');
|
||||||
|
|
||||||
var url = require('url');
|
var path = require('path');
|
||||||
var cp = require('child_process');
|
var Gaze = require('gaze').Gaze;
|
||||||
|
|
||||||
|
function watch(dir) {
|
||||||
// Get the remote of a given repo
|
|
||||||
function gitURL(path) {
|
|
||||||
var d = Q.defer();
|
var d = Q.defer();
|
||||||
|
dir = path.resolve(dir);
|
||||||
|
|
||||||
cp.exec("git config --get remote.origin.url", {
|
var gaze = new Gaze("**/*.md", {
|
||||||
cwd: path,
|
cwd: dir
|
||||||
env: process.env,
|
|
||||||
}, function(err, stdout, stderr) {
|
|
||||||
if(err) {
|
|
||||||
return d.reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
return d.resolve(stdout);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return d.promise
|
gaze.once("all", function(e, filepath) {
|
||||||
.then(function(output) {
|
gaze.close();
|
||||||
return output.replace(/(\r\n|\n|\r)/gm, "");
|
|
||||||
|
d.resolve(filepath);
|
||||||
});
|
});
|
||||||
}
|
gaze.once("error", function(err) {
|
||||||
|
gaze.close();
|
||||||
|
|
||||||
// Poorman's parsing
|
d.reject(err);
|
||||||
// Parse a git URL to a github ID : username/reponame
|
});
|
||||||
function githubID(_url) {
|
|
||||||
// Remove .git if it's in _url
|
|
||||||
var sliceEnd = _url.slice(-4) === '.git' ? -4 : _url.length;
|
|
||||||
|
|
||||||
// Detect HTTPS repos
|
|
||||||
var parsed = url.parse(_url);
|
|
||||||
if(parsed.protocol === 'https:' && parsed.host === 'github.com') {
|
|
||||||
return parsed.path.slice(1, sliceEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Detect SSH repos
|
|
||||||
if(_url.indexOf('git@') === 0) {
|
|
||||||
return _url.split(':', 2)[1].slice(0, sliceEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
// None found
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function titleCase(str)
|
|
||||||
{
|
|
||||||
return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
|
|
||||||
}
|
|
||||||
|
|
||||||
function serveDir(dir, port) {
|
|
||||||
var d = Q.defer();
|
|
||||||
|
|
||||||
var server = http.createServer(function(req, res){
|
|
||||||
// Render error
|
|
||||||
function error(err) {
|
|
||||||
res.statusCode = err.status || 500;
|
|
||||||
res.end(err.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Redirect to directory's index.html
|
|
||||||
function redirect() {
|
|
||||||
res.statusCode = 301;
|
|
||||||
res.setHeader('Location', req.url + '/');
|
|
||||||
res.end('Redirecting to ' + req.url + '/');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send file
|
|
||||||
send(req, url.parse(req.url).pathname)
|
|
||||||
.root(dir)
|
|
||||||
.on('error', error)
|
|
||||||
.on('directory', redirect)
|
|
||||||
.pipe(res);
|
|
||||||
}).listen(port);
|
|
||||||
|
|
||||||
d.resolve(server);
|
|
||||||
|
|
||||||
return d.promise;
|
return d.promise;
|
||||||
}
|
}
|
||||||
@@ -93,9 +37,6 @@ function logError(err) {
|
|||||||
|
|
||||||
// Exports
|
// Exports
|
||||||
module.exports = {
|
module.exports = {
|
||||||
gitURL: gitURL,
|
watch: watch,
|
||||||
githubID: githubID,
|
|
||||||
titleCase: titleCase,
|
|
||||||
serveDir: serveDir,
|
|
||||||
logError: logError
|
logError: logError
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ var getFiles = function(path) {
|
|||||||
ig.addIgnoreRules([
|
ig.addIgnoreRules([
|
||||||
'.git/',
|
'.git/',
|
||||||
'.gitignore',
|
'.gitignore',
|
||||||
|
'.DS_Store'
|
||||||
], '__custom_stuff');
|
], '__custom_stuff');
|
||||||
|
|
||||||
// Push each file to our list
|
// Push each file to our list
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ var BaseGenerator = function(options) {
|
|||||||
this.plugins = [];
|
this.plugins = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
BaseGenerator.prototype.callHook = function(name) {
|
BaseGenerator.prototype.callHook = function(name, data) {
|
||||||
return this.plugins.hook(name, this);
|
return this.plugins.hook(name, this, data);
|
||||||
};
|
};
|
||||||
|
|
||||||
BaseGenerator.prototype.loadPlugins = function() {
|
BaseGenerator.prototype.loadPlugins = function() {
|
||||||
var that = this;
|
var that = this;
|
||||||
|
|
||||||
return Plugin.fromList(this.options.plugins)
|
return Plugin.fromList(this.options.plugins, this.options.input)
|
||||||
.then(function(_plugins) {
|
.then(function(_plugins) {
|
||||||
that.plugins = _plugins;
|
that.plugins = _plugins;
|
||||||
|
|
||||||
|
|||||||
+48
-11
@@ -28,26 +28,34 @@ var generate = function(options) {
|
|||||||
|
|
||||||
options = _.defaults(options || {}, {
|
options = _.defaults(options || {}, {
|
||||||
// Folders to use
|
// Folders to use
|
||||||
input: null,
|
"input": null,
|
||||||
output: null,
|
"output": null,
|
||||||
|
|
||||||
|
// Config file (relative to input)
|
||||||
|
"configFile": "book.json",
|
||||||
|
|
||||||
// Output generator
|
// Output generator
|
||||||
generator: "site",
|
"generator": "site",
|
||||||
|
|
||||||
// Book title, keyword, description
|
// Book title, keyword, description
|
||||||
title: null,
|
"title": null,
|
||||||
description: null,
|
"description": null,
|
||||||
|
|
||||||
// Origin github repository id
|
// Origin github repository id
|
||||||
github: null,
|
"github": null,
|
||||||
githubHost: 'https://github.com/',
|
"githubHost": 'https://github.com/',
|
||||||
|
|
||||||
// Theming
|
// Theming
|
||||||
theme: path.resolve(__dirname, '../../theme'),
|
"theme": path.resolve(__dirname, '../../theme'),
|
||||||
|
|
||||||
// Plugins
|
// Plugins
|
||||||
plugins: [],
|
"plugins": [],
|
||||||
pluginsConfig: {}
|
"pluginsConfig": {},
|
||||||
|
|
||||||
|
// Links
|
||||||
|
"links": {
|
||||||
|
"about": null
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!options.input) {
|
if (!options.input) {
|
||||||
@@ -63,6 +71,35 @@ var generate = function(options) {
|
|||||||
// Clean output folder
|
// Clean output folder
|
||||||
return fs.remove(options.output)
|
return fs.remove(options.output)
|
||||||
|
|
||||||
|
// Read config file
|
||||||
|
.then(function() {
|
||||||
|
return fs.readFile(path.resolve(options.input, options.configFile))
|
||||||
|
.then(function(_config) {
|
||||||
|
// Extend current config
|
||||||
|
_config = JSON.parse(_config);
|
||||||
|
_config = _.omit(_config, 'input', 'configFile');
|
||||||
|
|
||||||
|
_.extend(options, _config);
|
||||||
|
}, function() {
|
||||||
|
// No config file: not a big deal
|
||||||
|
return Q();
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Get repo's URL
|
||||||
|
.then(function() {
|
||||||
|
return parse.git.url(options.input)
|
||||||
|
.then(function(_url) {
|
||||||
|
// Get ID of repo
|
||||||
|
return parse.git.githubID(_url);
|
||||||
|
}, function(err) {
|
||||||
|
return null;
|
||||||
|
})
|
||||||
|
.then(function(repoId) {
|
||||||
|
options.github = options.github || repoId;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
.then(function() {
|
.then(function() {
|
||||||
return fs.mkdirp(options.output);
|
return fs.mkdirp(options.output);
|
||||||
})
|
})
|
||||||
@@ -166,7 +203,7 @@ var generate = function(options) {
|
|||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
|
||||||
// Finish gneration
|
// Finish generation
|
||||||
.then(function() {
|
.then(function() {
|
||||||
return generator.finish();
|
return generator.finish();
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
var _ = require('lodash');
|
||||||
|
var path = require('path');
|
||||||
|
var Q = require('q');
|
||||||
|
|
||||||
|
var fs = require("./fs");
|
||||||
|
|
||||||
|
var extsToIgnore = [".gz"]
|
||||||
|
|
||||||
|
var Manifest = function() {
|
||||||
|
this.revision = 0;
|
||||||
|
this.clear(Date.now());
|
||||||
|
};
|
||||||
|
|
||||||
|
// Regenerate manifest
|
||||||
|
Manifest.prototype.clear = function(revision) {
|
||||||
|
if (revision) this.revision = revision;
|
||||||
|
this.sections = {
|
||||||
|
'CACHE': {},
|
||||||
|
'NETWORK': {},
|
||||||
|
'FALLBACK': {}
|
||||||
|
};
|
||||||
|
return Q(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add a resource
|
||||||
|
Manifest.prototype.add = function(category, resource, value) {
|
||||||
|
if (_.isArray(resource)) {
|
||||||
|
_.each(resource, function(subres) {
|
||||||
|
this.add(category, subres, value);
|
||||||
|
}, this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.sections[category][resource] = value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add a directory in cache
|
||||||
|
Manifest.prototype.addFolder = function(folder, root, except) {
|
||||||
|
var that = this;
|
||||||
|
root = root || "/";
|
||||||
|
|
||||||
|
return fs.list(folder)
|
||||||
|
.then(function(files) {
|
||||||
|
_.each(
|
||||||
|
// Ignore diretcories
|
||||||
|
_.filter(files, function(file) {
|
||||||
|
return file.substr(-1) != "/" && !_.contains(except, path.join(root, file)) && !_.contains(extsToIgnore, path.extname(file));
|
||||||
|
}),
|
||||||
|
function(file) {
|
||||||
|
that.add("CACHE", path.join(root, file));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get manifest content
|
||||||
|
Manifest.prototype.dump = function() {
|
||||||
|
var lines = [
|
||||||
|
"CACHE MANIFEST",
|
||||||
|
"# Revision "+this.revision
|
||||||
|
];
|
||||||
|
|
||||||
|
_.each(this.sections, function(content, section) {
|
||||||
|
if (_.size(content) == 0) return;
|
||||||
|
lines.push("");
|
||||||
|
lines.push(section+":");
|
||||||
|
lines = lines.concat(_.keys(content));
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
return Q(lines.join("\n"));
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Manifest;
|
||||||
+31
-19
@@ -4,13 +4,15 @@ var semver = require("semver");
|
|||||||
var path = require("path");
|
var path = require("path");
|
||||||
var url = require("url");
|
var url = require("url");
|
||||||
var fs = require("./fs");
|
var fs = require("./fs");
|
||||||
|
var resolve = require('resolve');
|
||||||
|
|
||||||
var pkg = require("../../package.json");
|
var pkg = require("../../package.json");
|
||||||
|
|
||||||
var RESOURCES = ["js", "css"];
|
var RESOURCES = ["js", "css"];
|
||||||
|
|
||||||
var Plugin = function(name) {
|
var Plugin = function(name, root) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
this.root = root;
|
||||||
this.packageInfos = {};
|
this.packageInfos = {};
|
||||||
this.infos = {};
|
this.infos = {};
|
||||||
|
|
||||||
@@ -20,16 +22,21 @@ var Plugin = function(name) {
|
|||||||
"gitbook-"+name,
|
"gitbook-"+name,
|
||||||
name,
|
name,
|
||||||
], function(_name) {
|
], function(_name) {
|
||||||
if (this.load(_name)) return false;
|
if (this.load(_name, __dirname)) return false;
|
||||||
}.bind(this));
|
if (this.load(_name, path.resolve(root))) return false;
|
||||||
|
}, this);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Load from a name
|
// Load from a name
|
||||||
Plugin.prototype.load = function(name) {
|
Plugin.prototype.load = function(name, baseDir) {
|
||||||
try {
|
try {
|
||||||
this.packageInfos = require(name+"/package.json");
|
var res = resolve.sync(name+"/package.json", { basedir: baseDir });
|
||||||
this.infos = require(name);
|
|
||||||
|
this.baseDir = path.dirname(res);
|
||||||
|
this.packageInfos = require(res);
|
||||||
|
this.infos = require(resolve.sync(name, { basedir: baseDir }));
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
@@ -63,25 +70,30 @@ Plugin.prototype.isValid = function() {
|
|||||||
|
|
||||||
// Resolve file path
|
// Resolve file path
|
||||||
Plugin.prototype.resolveFile = function(filename) {
|
Plugin.prototype.resolveFile = function(filename) {
|
||||||
return path.resolve(path.dirname(require.resolve(this.name)), filename);
|
return path.resolve(this.baseDir, filename);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Resolve file path
|
// Resolve file path
|
||||||
Plugin.prototype.callHook = function(name, args) {
|
Plugin.prototype.callHook = function(name, context, data) {
|
||||||
var hookFunc = this.infos.hooks? this.infos.hooks[name] : null;
|
var hookFunc = this.infos.hooks? this.infos.hooks[name] : null;
|
||||||
args = _.isArray(args) ? args : [args];
|
data = data || {};
|
||||||
|
|
||||||
if (!hookFunc) return Q();
|
if (!hookFunc) return Q(data);
|
||||||
|
|
||||||
return Q()
|
return Q()
|
||||||
.then(function() {
|
.then(function() {
|
||||||
return hookFunc.apply(null, args);
|
return hookFunc.apply(context, [data]);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Has assets
|
||||||
|
Plugin.prototype.hasAssets = function(out) {
|
||||||
|
return (this.infos.book && this.infos.book.assets);
|
||||||
|
};
|
||||||
|
|
||||||
// Copy plugin assets fodler
|
// Copy plugin assets fodler
|
||||||
Plugin.prototype.copyAssets = function(out) {
|
Plugin.prototype.copyAssets = function(out) {
|
||||||
if (!this.infos.book || !this.infos.book.assets) return Q();
|
if (!this.hasAssets()) return Q();
|
||||||
return fs.copy(
|
return fs.copy(
|
||||||
this.resolveFile(this.infos.book.assets),
|
this.resolveFile(this.infos.book.assets),
|
||||||
out
|
out
|
||||||
@@ -94,7 +106,7 @@ Plugin.prototype.copyAssets = function(out) {
|
|||||||
// Normalize a list of plugin name to use
|
// Normalize a list of plugin name to use
|
||||||
Plugin.normalizeNames = function(names) {
|
Plugin.normalizeNames = function(names) {
|
||||||
// Normalize list to an array
|
// Normalize list to an array
|
||||||
names = _.isString(names) ? names.split(":") : (names || []);
|
names = _.isString(names) ? names.split(",") : (names || []);
|
||||||
|
|
||||||
// List plugins to remove
|
// List plugins to remove
|
||||||
var toremove = _.chain(names)
|
var toremove = _.chain(names)
|
||||||
@@ -121,12 +133,12 @@ Plugin.normalizeNames = function(names) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Extract data from a list of plugin
|
// Extract data from a list of plugin
|
||||||
Plugin.fromList = function(names) {
|
Plugin.fromList = function(names, root) {
|
||||||
var failed = [];
|
var failed = [];
|
||||||
|
|
||||||
// Load plugins
|
// Load plugins
|
||||||
var plugins = _.map(names, function(name) {
|
var plugins = _.map(names, function(name) {
|
||||||
var plugin = new Plugin(name);
|
var plugin = new Plugin(name, root);
|
||||||
if (!plugin.isValid()) failed.push(name);
|
if (!plugin.isValid()) failed.push(name);
|
||||||
return plugin;
|
return plugin;
|
||||||
});
|
});
|
||||||
@@ -152,12 +164,12 @@ Plugin.fromList = function(names) {
|
|||||||
return Q({
|
return Q({
|
||||||
'list': plugins,
|
'list': plugins,
|
||||||
'resources': resources,
|
'resources': resources,
|
||||||
'hook': function(name, args) {
|
'hook': function(name, context, data) {
|
||||||
return _.reduce(plugins, function(prev, plugin) {
|
return _.reduce(plugins, function(prev, plugin) {
|
||||||
return prev.then(function() {
|
return prev.then(function(ret) {
|
||||||
return plugin.callHook(name, args);
|
return plugin.callHook(name, context, ret);
|
||||||
})
|
})
|
||||||
}, Q());
|
}, Q(data));
|
||||||
},
|
},
|
||||||
'template': function(name) {
|
'template': function(name) {
|
||||||
var withTpl = _.find(plugins, function(plugin) {
|
var withTpl = _.find(plugins, function(plugin) {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ var parse = require("../../parse");
|
|||||||
var BaseGenerator = require("../generator");
|
var BaseGenerator = require("../generator");
|
||||||
|
|
||||||
var indexer = require('./search_indexer');
|
var indexer = require('./search_indexer');
|
||||||
|
var Manifest = require('../manifest');
|
||||||
|
|
||||||
// Swig filter for returning the count of lines in a code section
|
// Swig filter for returning the count of lines in a code section
|
||||||
swig.setFilter('lines', function(content) {
|
swig.setFilter('lines', function(content) {
|
||||||
@@ -30,6 +31,10 @@ var Generator = function() {
|
|||||||
|
|
||||||
this.revision = Date.now();
|
this.revision = Date.now();
|
||||||
this.indexer = indexer();
|
this.indexer = indexer();
|
||||||
|
this.manifest = new Manifest(Date.now());
|
||||||
|
this.manifest.add("NETWORK", [
|
||||||
|
'*'
|
||||||
|
]);
|
||||||
};
|
};
|
||||||
util.inherits(Generator, BaseGenerator);
|
util.inherits(Generator, BaseGenerator);
|
||||||
|
|
||||||
@@ -54,8 +59,11 @@ Generator.prototype.loadPlugins = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Generate a template
|
// Generate a template
|
||||||
Generator.prototype._writeTemplate = function(tpl, options, output) {
|
Generator.prototype._writeTemplate = function(tpl, options, output, interpolate) {
|
||||||
var that = this;
|
var that = this;
|
||||||
|
|
||||||
|
interpolate = interpolate || _.identity;
|
||||||
|
|
||||||
return Q()
|
return Q()
|
||||||
.then(function(sections) {
|
.then(function(sections) {
|
||||||
return tpl(_.extend({
|
return tpl(_.extend({
|
||||||
@@ -72,9 +80,12 @@ Generator.prototype._writeTemplate = function(tpl, options, output) {
|
|||||||
allNavigation: that.options.navigation,
|
allNavigation: that.options.navigation,
|
||||||
|
|
||||||
plugins: that.plugins,
|
plugins: that.plugins,
|
||||||
pluginsConfig: JSON.stringify(that.options.pluginsConfig)
|
pluginsConfig: JSON.stringify(that.options.pluginsConfig),
|
||||||
|
|
||||||
|
options: that.options
|
||||||
}, options));
|
}, options));
|
||||||
})
|
})
|
||||||
|
.then(interpolate)
|
||||||
.then(function(html) {
|
.then(function(html) {
|
||||||
return fs.writeFile(
|
return fs.writeFile(
|
||||||
output,
|
output,
|
||||||
@@ -91,7 +102,6 @@ Generator.prototype.indexPage = function(lexed, pagePath) {
|
|||||||
// Convert a markdown file to html
|
// Convert a markdown file to html
|
||||||
Generator.prototype.convertFile = function(content, _input) {
|
Generator.prototype.convertFile = function(content, _input) {
|
||||||
var that = this;
|
var that = this;
|
||||||
var progress = parse.progress(this.options.navigation, _input);
|
|
||||||
|
|
||||||
_output = _input.replace(".md", ".html");
|
_output = _input.replace(".md", ".html");
|
||||||
if (_output == "README.html") _output = "index.html";
|
if (_output == "README.html") _output = "index.html";
|
||||||
@@ -100,10 +110,28 @@ Generator.prototype.convertFile = function(content, _input) {
|
|||||||
var output = path.join(this.options.output, _output);
|
var output = path.join(this.options.output, _output);
|
||||||
var basePath = path.relative(path.dirname(output), this.options.output) || ".";
|
var basePath = path.relative(path.dirname(output), this.options.output) || ".";
|
||||||
|
|
||||||
|
var page = {
|
||||||
|
path: _input,
|
||||||
|
content: content,
|
||||||
|
progress: parse.progress(this.options.navigation, _input)
|
||||||
|
};
|
||||||
|
|
||||||
|
var _callHook = function(name) {
|
||||||
|
return that.callHook(name, page)
|
||||||
|
.then(function(_page) {
|
||||||
|
page = _page;
|
||||||
|
return page;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return Q()
|
return Q()
|
||||||
|
.then(function() {
|
||||||
|
// Send content to plugins
|
||||||
|
return _callHook("page:before");
|
||||||
|
})
|
||||||
.then(function() {
|
.then(function() {
|
||||||
// Lex page
|
// Lex page
|
||||||
return parse.lex(content);
|
return parse.lex(page.content);
|
||||||
})
|
})
|
||||||
.then(function(lexed) {
|
.then(function(lexed) {
|
||||||
// Index page in search
|
// Index page in search
|
||||||
@@ -119,15 +147,27 @@ Generator.prototype.convertFile = function(content, _input) {
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then(function(sections) {
|
.then(function(sections) {
|
||||||
|
page.sections = sections;
|
||||||
|
|
||||||
|
// Use plugin hook
|
||||||
|
return _callHook("page");
|
||||||
|
})
|
||||||
|
.then(function() {
|
||||||
|
that.manifest.add("CACHE", _output);
|
||||||
|
|
||||||
return that._writeTemplate(that.template, {
|
return that._writeTemplate(that.template, {
|
||||||
progress: progress,
|
progress: page.progress,
|
||||||
|
|
||||||
_input: _input,
|
_input: _input,
|
||||||
content: sections,
|
content: page.sections,
|
||||||
|
|
||||||
basePath: basePath,
|
basePath: basePath,
|
||||||
staticBase: path.join(basePath, "gitbook"),
|
staticBase: path.join(basePath, "gitbook"),
|
||||||
}, output);
|
}, output, function(html) {
|
||||||
|
page.content = html;
|
||||||
|
|
||||||
|
return _callHook("page:after").get("content")
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -157,11 +197,23 @@ Generator.prototype.copyAssets = function() {
|
|||||||
path.join(that.options.theme, "assets"),
|
path.join(that.options.theme, "assets"),
|
||||||
path.join(that.options.output, "gitbook")
|
path.join(that.options.output, "gitbook")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Add to cach manifest
|
||||||
|
.then(function() {
|
||||||
|
return that.manifest.addFolder(path.join(that.options.output, "gitbook"), "gitbook");
|
||||||
|
})
|
||||||
|
|
||||||
// Copy plugins assets
|
// Copy plugins assets
|
||||||
.then(function() {
|
.then(function() {
|
||||||
return Q.all(
|
return Q.all(
|
||||||
_.map(that.plugins.list, function(plugin) {
|
_.map(that.plugins.list, function(plugin) {
|
||||||
return plugin.copyAssets(path.join(that.options.output, "gitbook/plugins/", plugin.name))
|
if (!plugin.hasAssets()) return Q();
|
||||||
|
|
||||||
|
var pluginAssets = path.join(that.options.output, "gitbook/plugins/", plugin.name);
|
||||||
|
return plugin.copyAssets(pluginAssets)
|
||||||
|
.then(function() {
|
||||||
|
return that.manifest.addFolder(pluginAssets, "gitbook/plugins/"+plugin.name);
|
||||||
|
});
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
@@ -175,9 +227,19 @@ Generator.prototype.writeSearchIndex = function() {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Add cache manifest
|
||||||
|
Generator.prototype.writeCacheManifest = function() {
|
||||||
|
return fs.writeFile(
|
||||||
|
path.join(this.options.output, 'manifest.appcache'),
|
||||||
|
this.manifest.dump()
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
Generator.prototype.finish = function() {
|
Generator.prototype.finish = function() {
|
||||||
return this.copyAssets()
|
return this.copyAssets()
|
||||||
.then(this.writeSearchIndex);
|
.then(this.writeSearchIndex)
|
||||||
|
.then(this.writeCacheManifest);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = Generator;
|
module.exports = Generator;
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
var Q = require('q');
|
||||||
|
var _ = require('lodash');
|
||||||
|
var cp = require('child_process');
|
||||||
|
var url = require('url');
|
||||||
|
|
||||||
|
// Get the remote of a given repo
|
||||||
|
function gitURL(path) {
|
||||||
|
var d = Q.defer();
|
||||||
|
|
||||||
|
cp.exec("git config --get remote.origin.url", {
|
||||||
|
cwd: path,
|
||||||
|
env: process.env,
|
||||||
|
}, function(err, stdout, stderr) {
|
||||||
|
if(err) {
|
||||||
|
return d.reject(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return d.resolve(stdout);
|
||||||
|
});
|
||||||
|
|
||||||
|
return d.promise
|
||||||
|
.then(function(output) {
|
||||||
|
return output.replace(/(\r\n|\n|\r)/gm, "");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Poorman's parsing
|
||||||
|
// Parse a git URL to a github ID : username/reponame
|
||||||
|
function githubID(_url) {
|
||||||
|
// Remove .git if it's in _url
|
||||||
|
var sliceEnd = _url.slice(-4) === '.git' ? -4 : _url.length;
|
||||||
|
|
||||||
|
// Detect HTTPS repos
|
||||||
|
var parsed = url.parse(_url);
|
||||||
|
if(parsed.protocol === 'https:' && parsed.host === 'github.com') {
|
||||||
|
return parsed.path.slice(1, sliceEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect SSH repos
|
||||||
|
if(_url.indexOf('git@') === 0) {
|
||||||
|
return _url.split(':', 2)[1].slice(0, sliceEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
// None found
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function titleCase(str) {
|
||||||
|
return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
url: gitURL,
|
||||||
|
githubID: githubID,
|
||||||
|
titleCase: titleCase
|
||||||
|
};
|
||||||
+2
-1
@@ -5,5 +5,6 @@ module.exports = {
|
|||||||
lex: require('./lex'),
|
lex: require('./lex'),
|
||||||
progress: require('./progress'),
|
progress: require('./progress'),
|
||||||
navigation: require('./navigation'),
|
navigation: require('./navigation'),
|
||||||
readme: require('./readme')
|
readme: require('./readme'),
|
||||||
|
git: require('./git')
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ function GitBookRenderer(options, extra_options) {
|
|||||||
this._extra_options = extra_options;
|
this._extra_options = extra_options;
|
||||||
this.quizRowId = 0;
|
this.quizRowId = 0;
|
||||||
this.id = rendererId++;
|
this.id = rendererId++;
|
||||||
|
this.quizIndex = 0;
|
||||||
}
|
}
|
||||||
inherits(GitBookRenderer, marked.Renderer);
|
inherits(GitBookRenderer, marked.Renderer);
|
||||||
|
|
||||||
@@ -66,7 +67,7 @@ GitBookRenderer.prototype.link = function(href, title, text) {
|
|||||||
} else if (o && o.repo && o.dir) {
|
} else if (o && o.repo && o.dir) {
|
||||||
href = url.resolve('https://github.com/' + o.repo + '/blob/', [o.dir, _href].join("/"));
|
href = url.resolve('https://github.com/' + o.repo + '/blob/', [o.dir, _href].join("/"));
|
||||||
parsed = url.parse(href);
|
parsed = url.parse(href);
|
||||||
_href = parsed.href;
|
_href = parsed.href;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,10 +117,14 @@ GitBookRenderer.prototype._createCheckboxAndRadios = function(text) {
|
|||||||
if (!match) {
|
if (!match) {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
var field = "<input name='quiz-row-" + this.id + "-" + this.quizRowId + "' type='";
|
var quizIdentifier = 'quiz-row-' + this.id + '-' + this.quizRowId + '-' + this.quizIndex++;
|
||||||
|
var field = "<input name='" + quizIdentifier + "' id='" + quizIdentifier + "' type='";
|
||||||
field += match[1] === '(' ? "radio" : "checkbox";
|
field += match[1] === '(' ? "radio" : "checkbox";
|
||||||
field += match[2] === 'x' ? "' checked/>" : "'/>";
|
field += match[2] === 'x' ? "' checked/>" : "'/>";
|
||||||
return text.replace(fieldRegex, field);
|
var splittedText = text.split(fieldRegex);
|
||||||
|
var length = splittedText.length;
|
||||||
|
var label = '<label class="quiz-label" for="' + quizIdentifier + '">' + splittedText[length - 1] + '</label>';
|
||||||
|
return text.replace(fieldRegex, field).replace(splittedText[length - 1], label);
|
||||||
}
|
}
|
||||||
|
|
||||||
GitBookRenderer.prototype.tablecell = function(content, flags) {
|
GitBookRenderer.prototype.tablecell = function(content, flags) {
|
||||||
|
|||||||
+3
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "gitbook",
|
"name": "gitbook",
|
||||||
"version": "0.3.1",
|
"version": "0.4.2",
|
||||||
"homepage": "http://www.gitbook.io/",
|
"homepage": "http://www.gitbook.io/",
|
||||||
"description": "Library and cmd utility to generate GitBooks",
|
"description": "Library and cmd utility to generate GitBooks",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
@@ -18,6 +18,8 @@
|
|||||||
"highlight.js": "8.0.0",
|
"highlight.js": "8.0.0",
|
||||||
"tmp": "0.0.23",
|
"tmp": "0.0.23",
|
||||||
"semver": "2.2.1",
|
"semver": "2.2.1",
|
||||||
|
"gaze": "~0.5.1",
|
||||||
|
"resolve": "0.6.3",
|
||||||
|
|
||||||
"gitbook-plugin": "0.0.2",
|
"gitbook-plugin": "0.0.2",
|
||||||
"gitbook-plugin-mixpanel": "0.0.2",
|
"gitbook-plugin-mixpanel": "0.0.2",
|
||||||
|
|||||||
+2
-2
@@ -5,7 +5,7 @@ var assert = require('assert');
|
|||||||
var Plugin = require('../').generate.Plugin;
|
var Plugin = require('../').generate.Plugin;
|
||||||
|
|
||||||
describe('Plugin validation', function () {
|
describe('Plugin validation', function () {
|
||||||
var plugin = new Plugin("plugin");
|
var plugin = new Plugin("plugin", __dirname);
|
||||||
|
|
||||||
it('should be valid', function() {
|
it('should be valid', function() {
|
||||||
assert(plugin.isValid());
|
assert(plugin.isValid());
|
||||||
@@ -33,7 +33,7 @@ describe('Plugin defaults loading', function () {
|
|||||||
var ret = true;
|
var ret = true;
|
||||||
|
|
||||||
beforeEach(function(done){
|
beforeEach(function(done){
|
||||||
Plugin.fromList(Plugin.defaults)
|
Plugin.fromList(Plugin.defaults, __dirname)
|
||||||
.then(function(_r) {
|
.then(function(_r) {
|
||||||
ret = _r;
|
ret = _r;
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,18 @@
|
|||||||
|
define([
|
||||||
|
"jQuery"
|
||||||
|
], function($) {
|
||||||
|
var showLoading = function(p) {
|
||||||
|
var $book = $(".book");
|
||||||
|
|
||||||
|
$book.addClass("is-loading");
|
||||||
|
p.always(function() {
|
||||||
|
$book.removeClass("is-loading");
|
||||||
|
});
|
||||||
|
|
||||||
|
return p;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
show: showLoading
|
||||||
|
};
|
||||||
|
});
|
||||||
@@ -1,38 +1,42 @@
|
|||||||
define([
|
define([
|
||||||
"jQuery",
|
"jQuery",
|
||||||
|
"utils/path",
|
||||||
"core/events",
|
"core/events",
|
||||||
"core/state",
|
"core/state",
|
||||||
"core/search",
|
"core/search",
|
||||||
"core/progress",
|
"core/progress",
|
||||||
"core/exercise",
|
"core/exercise",
|
||||||
"core/quiz"
|
"core/quiz",
|
||||||
], function($, events, state, search, progress, exercises, quiz) {
|
"core/loading"
|
||||||
|
], function($, path, events, state, search, progress, exercises, quiz, loading) {
|
||||||
var prev, next;
|
var prev, next;
|
||||||
var githubCountStars, githubCountWatch;
|
var githubCountStars, githubCountWatch;
|
||||||
|
|
||||||
var usePushState = !navigator.userAgent.match('CriOS') && (typeof history.pushState !== "undefined");
|
var usePushState = (typeof history.pushState !== "undefined");
|
||||||
|
|
||||||
var updateHistory = function(url, title) {
|
var handleNavigation = function(relativeUrl, push) {
|
||||||
history.pushState({ path: url }, title, url);
|
var url = path.isAbsolute(relativeUrl) ? relativeUrl : path.join(path.dirname(window.location.pathname), relativeUrl);
|
||||||
};
|
console.log("navigate to ", url, "baseurl="+relativeUrl);
|
||||||
|
|
||||||
var handleNavigation = function(url, push) {
|
|
||||||
if (!usePushState) {
|
if (!usePushState) {
|
||||||
// Refresh the page to the new URL if pushState not supported
|
// Refresh the page to the new URL if pushState not supported
|
||||||
location.href = url;
|
location.href = relativeUrl;
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return $.get(url)
|
return loading.show($.get(url)
|
||||||
.done(function (html) {
|
.done(function (html) {
|
||||||
if (push) updateHistory(url, null);
|
// Push url to history
|
||||||
|
if (push) history.pushState({ path: url }, null, url);
|
||||||
|
|
||||||
|
// Replace html content
|
||||||
html = html.replace( /<(\/?)(html|head|body)([^>]*)>/ig, function(a,b,c,d){
|
html = html.replace( /<(\/?)(html|head|body)([^>]*)>/ig, function(a,b,c,d){
|
||||||
return '<' + b + 'div' + ( b ? '' : ' data-element="' + c + '"' ) + d + '>';
|
return '<' + b + 'div' + ( b ? '' : ' data-element="' + c + '"' ) + d + '>';
|
||||||
});
|
});
|
||||||
|
|
||||||
var $page = $(html);
|
var $page = $(html);
|
||||||
var $pageHead = $page.find("[data-element=head]");
|
var $pageHead = $page.find("[data-element=head]");
|
||||||
|
var $pageBody = $page.find('.book');
|
||||||
|
|
||||||
// Merge heads
|
// Merge heads
|
||||||
var headContent = $pageHead.html()
|
var headContent = $pageHead.html()
|
||||||
@@ -42,22 +46,20 @@ define([
|
|||||||
});
|
});
|
||||||
$("head").html(headContent);
|
$("head").html(headContent);
|
||||||
|
|
||||||
// Update header, body
|
// Merge body
|
||||||
$('.book-header').html($page.find('.book-header').html());
|
|
||||||
$('.book-body').html($page.find('.book-body').html());
|
|
||||||
|
|
||||||
// Update summary
|
|
||||||
var scrollPosition = $('.book-summary .summary').scrollTop();
|
var scrollPosition = $('.book-summary .summary').scrollTop();
|
||||||
$('.book-summary').html($page.find('.book-summary').html());
|
$pageBody.toggleClass("with-summary", $(".book").hasClass("with-summary"))
|
||||||
|
|
||||||
|
$(".book").replaceWith($pageBody);
|
||||||
$('.book-summary .summary').scrollTop(scrollPosition);
|
$('.book-summary .summary').scrollTop(scrollPosition);
|
||||||
|
|
||||||
// Update state
|
// Update state
|
||||||
state.update($("html"));
|
state.update($("html"));
|
||||||
preparePage();
|
preparePage();
|
||||||
})
|
})
|
||||||
.fail(function () {
|
.fail(function (e) {
|
||||||
location.href = url;
|
location.href = relativeUrl;
|
||||||
});
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
var updateGitHubCounts = function() {
|
var updateGitHubCounts = function() {
|
||||||
@@ -131,7 +133,7 @@ define([
|
|||||||
if (url) handleNavigation(url, true);
|
if (url) handleNavigation(url, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var init = function() {
|
var init = function() {
|
||||||
// Prevent cache so that using the back button works
|
// Prevent cache so that using the back button works
|
||||||
@@ -148,14 +150,13 @@ define([
|
|||||||
if (event.state === null) {
|
if (event.state === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return handleNavigation(event.state.path, false);
|
return handleNavigation(event.state.path, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
$(document).on('click', ".navigation-prev", handlePagination);
|
$(document).on('click', ".navigation-prev", handlePagination);
|
||||||
$(document).on('click', ".navigation-next", handlePagination);
|
$(document).on('click', ".navigation-next", handlePagination);
|
||||||
$(document).on('click', ".summary [data-path] a", handlePagination);
|
$(document).on('click', ".summary [data-path] a", handlePagination);
|
||||||
|
|
||||||
$(window).resize(updateNavigationPosition);
|
$(window).resize(updateNavigationPosition);
|
||||||
|
|
||||||
// Prepare current page
|
// Prepare current page
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ define([
|
|||||||
"jQuery",
|
"jQuery",
|
||||||
"utils/storage",
|
"utils/storage",
|
||||||
"utils/sharing",
|
"utils/sharing",
|
||||||
|
"utils/appcache",
|
||||||
|
|
||||||
"core/events",
|
"core/events",
|
||||||
"core/font-settings",
|
"core/font-settings",
|
||||||
@@ -11,7 +12,7 @@ define([
|
|||||||
"core/progress",
|
"core/progress",
|
||||||
"core/sidebar",
|
"core/sidebar",
|
||||||
"core/search"
|
"core/search"
|
||||||
], function($, storage, sharing, events, fontSettings, state, keyboard, navigation, progress, sidebar, search){
|
], function($, storage, appCache, sharing, events, fontSettings, state, keyboard, navigation, progress, sidebar, search){
|
||||||
var start = function(config) {
|
var start = function(config) {
|
||||||
var $book;
|
var $book;
|
||||||
$book = state.$book;
|
$book = state.$book;
|
||||||
@@ -30,6 +31,9 @@ define([
|
|||||||
// Init keyboard
|
// Init keyboard
|
||||||
keyboard.init();
|
keyboard.init();
|
||||||
|
|
||||||
|
// Init appcache
|
||||||
|
appCache.init();
|
||||||
|
|
||||||
// Bind sharing button
|
// Bind sharing button
|
||||||
sharing.init();
|
sharing.init();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
define([], function() {
|
||||||
|
var isAvailable = (typeof applicationCache !== "undefined");
|
||||||
|
|
||||||
|
var init = function() {
|
||||||
|
if (!isAvailable) return;
|
||||||
|
|
||||||
|
window.applicationCache.addEventListener('updateready', function() {
|
||||||
|
window.location.reload();
|
||||||
|
}, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
init: init
|
||||||
|
};
|
||||||
|
});
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
define([], function() {
|
||||||
|
// Joins path segments. Preserves initial "/" and resolves ".." and "."
|
||||||
|
// Does not support using ".." to go above/outside the root.
|
||||||
|
// This means that join("foo", "../../bar") will not resolve to "../bar"
|
||||||
|
function join(/* path segments */) {
|
||||||
|
// Split the inputs into a list of path commands.
|
||||||
|
var parts = [];
|
||||||
|
for (var i = 0, l = arguments.length; i < l; i++) {
|
||||||
|
parts = parts.concat(arguments[i].split("/"));
|
||||||
|
}
|
||||||
|
// Interpret the path commands to get the new resolved path.
|
||||||
|
var newParts = [];
|
||||||
|
for (i = 0, l = parts.length; i < l; i++) {
|
||||||
|
var part = parts[i];
|
||||||
|
// Remove leading and trailing slashes
|
||||||
|
// Also remove "." segments
|
||||||
|
if (!part || part === ".") continue;
|
||||||
|
// Interpret ".." to pop the last segment
|
||||||
|
if (part === "..") newParts.pop();
|
||||||
|
// Push new path segments.
|
||||||
|
else newParts.push(part);
|
||||||
|
}
|
||||||
|
// Preserve the initial slash if there was one.
|
||||||
|
if (parts[0] === "") newParts.unshift("");
|
||||||
|
// Turn back into a single string path.
|
||||||
|
return newParts.join("/") || (newParts.length ? "/" : ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
// A simple function to get the dirname of a path
|
||||||
|
// Trailing slashes are ignored. Leading slash is preserved.
|
||||||
|
function dirname(path) {
|
||||||
|
return join(path, "..");
|
||||||
|
}
|
||||||
|
|
||||||
|
// test if a path or url is absolute
|
||||||
|
function isAbsolute(path) {
|
||||||
|
if (!path) return false;
|
||||||
|
|
||||||
|
return (path[0] == "/" || path.indexOf("http://") == 0 || path.indexOf("https://") == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
dirname: dirname,
|
||||||
|
join: join,
|
||||||
|
isAbsolute: isAbsolute
|
||||||
|
};
|
||||||
|
})
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
.book {
|
.book {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
.book-body {
|
.book-body {
|
||||||
position: fixed;
|
position: absolute;
|
||||||
top: @header-height;
|
top: @header-height;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
left: 0px;
|
left: 0px;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
.book-header {
|
.book-header {
|
||||||
font-family: @font-family-sans;
|
font-family: @font-family-sans;
|
||||||
|
|
||||||
position: fixed;
|
position: absolute;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
@@ -52,9 +52,23 @@
|
|||||||
@media (max-width: 800px) {
|
@media (max-width: 800px) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.is-loading {
|
||||||
|
.book-header h1 {
|
||||||
|
i {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
&.with-summary {
|
&.with-summary {
|
||||||
.book-header h1 {
|
.book-header h1 {
|
||||||
margin-left: 250px;
|
margin-left: 250px;
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
/* Tomorrow Night Bright Theme */
|
||||||
|
/* Original theme - https://github.com/chriskempson/tomorrow-theme */
|
||||||
|
/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */
|
||||||
|
|
||||||
|
/* Tomorrow Comment */
|
||||||
|
.hljs-comment,
|
||||||
|
.hljs-title {
|
||||||
|
color: #969896;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tomorrow Red */
|
||||||
|
.hljs-variable,
|
||||||
|
.hljs-attribute,
|
||||||
|
.hljs-tag,
|
||||||
|
.hljs-regexp,
|
||||||
|
.ruby .hljs-constant,
|
||||||
|
.xml .hljs-tag .hljs-title,
|
||||||
|
.xml .hljs-pi,
|
||||||
|
.xml .hljs-doctype,
|
||||||
|
.html .hljs-doctype,
|
||||||
|
.css .hljs-id,
|
||||||
|
.css .hljs-class,
|
||||||
|
.css .hljs-pseudo {
|
||||||
|
color: #d54e53;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tomorrow Orange */
|
||||||
|
.hljs-number,
|
||||||
|
.hljs-preprocessor,
|
||||||
|
.hljs-pragma,
|
||||||
|
.hljs-built_in,
|
||||||
|
.hljs-literal,
|
||||||
|
.hljs-params,
|
||||||
|
.hljs-constant {
|
||||||
|
color: #e78c45;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tomorrow Yellow */
|
||||||
|
.ruby .hljs-class .hljs-title,
|
||||||
|
.css .hljs-rules .hljs-attribute {
|
||||||
|
color: #e7c547;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tomorrow Green */
|
||||||
|
.hljs-string,
|
||||||
|
.hljs-value,
|
||||||
|
.hljs-inheritance,
|
||||||
|
.hljs-header,
|
||||||
|
.ruby .hljs-symbol,
|
||||||
|
.xml .hljs-cdata {
|
||||||
|
color: #b9ca4a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tomorrow Aqua */
|
||||||
|
.css .hljs-hexcolor {
|
||||||
|
color: #70c0b1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tomorrow Blue */
|
||||||
|
.hljs-function,
|
||||||
|
.python .hljs-decorator,
|
||||||
|
.python .hljs-title,
|
||||||
|
.ruby .hljs-function .hljs-title,
|
||||||
|
.ruby .hljs-title .hljs-keyword,
|
||||||
|
.perl .hljs-sub,
|
||||||
|
.javascript .hljs-title,
|
||||||
|
.coffeescript .hljs-title {
|
||||||
|
color: #7aa6da;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tomorrow Purple */
|
||||||
|
.hljs-keyword,
|
||||||
|
.javascript .hljs-function {
|
||||||
|
color: #c397d8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs {
|
||||||
|
display: block;
|
||||||
|
background: black;
|
||||||
|
color: #eaeaea;
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.coffeescript .javascript,
|
||||||
|
.javascript .xml,
|
||||||
|
.tex .hljs-formula,
|
||||||
|
.xml .javascript,
|
||||||
|
.xml .vbscript,
|
||||||
|
.xml .css,
|
||||||
|
.xml .hljs-cdata {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Orginal Style from ethanschoonover.com/solarized (c) Jeremy Hull <sourdrums@gmail.com>
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
.hljs {
|
||||||
|
display: block;
|
||||||
|
padding: 0.5em;
|
||||||
|
background: #fdf6e3;
|
||||||
|
color: #657b83;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-comment,
|
||||||
|
.hljs-template_comment,
|
||||||
|
.diff .hljs-header,
|
||||||
|
.hljs-doctype,
|
||||||
|
.hljs-pi,
|
||||||
|
.lisp .hljs-string,
|
||||||
|
.hljs-javadoc {
|
||||||
|
color: #93a1a1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Solarized Green */
|
||||||
|
.hljs-keyword,
|
||||||
|
.hljs-winutils,
|
||||||
|
.method,
|
||||||
|
.hljs-addition,
|
||||||
|
.css .hljs-tag,
|
||||||
|
.hljs-request,
|
||||||
|
.hljs-status,
|
||||||
|
.nginx .hljs-title {
|
||||||
|
color: #859900;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Solarized Cyan */
|
||||||
|
.hljs-number,
|
||||||
|
.hljs-command,
|
||||||
|
.hljs-string,
|
||||||
|
.hljs-tag .hljs-value,
|
||||||
|
.hljs-rules .hljs-value,
|
||||||
|
.hljs-phpdoc,
|
||||||
|
.tex .hljs-formula,
|
||||||
|
.hljs-regexp,
|
||||||
|
.hljs-hexcolor,
|
||||||
|
.hljs-link_url {
|
||||||
|
color: #2aa198;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Solarized Blue */
|
||||||
|
.hljs-title,
|
||||||
|
.hljs-localvars,
|
||||||
|
.hljs-chunk,
|
||||||
|
.hljs-decorator,
|
||||||
|
.hljs-built_in,
|
||||||
|
.hljs-identifier,
|
||||||
|
.vhdl .hljs-literal,
|
||||||
|
.hljs-id,
|
||||||
|
.css .hljs-function {
|
||||||
|
color: #268bd2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Solarized Yellow */
|
||||||
|
.hljs-attribute,
|
||||||
|
.hljs-variable,
|
||||||
|
.lisp .hljs-body,
|
||||||
|
.smalltalk .hljs-number,
|
||||||
|
.hljs-constant,
|
||||||
|
.hljs-class .hljs-title,
|
||||||
|
.hljs-parent,
|
||||||
|
.haskell .hljs-type,
|
||||||
|
.hljs-link_reference {
|
||||||
|
color: #b58900;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Solarized Orange */
|
||||||
|
.hljs-preprocessor,
|
||||||
|
.hljs-preprocessor .hljs-keyword,
|
||||||
|
.hljs-pragma,
|
||||||
|
.hljs-shebang,
|
||||||
|
.hljs-symbol,
|
||||||
|
.hljs-symbol .hljs-string,
|
||||||
|
.diff .hljs-change,
|
||||||
|
.hljs-special,
|
||||||
|
.hljs-attr_selector,
|
||||||
|
.hljs-subst,
|
||||||
|
.hljs-cdata,
|
||||||
|
.clojure .hljs-title,
|
||||||
|
.css .hljs-pseudo,
|
||||||
|
.hljs-header {
|
||||||
|
color: #cb4b16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Solarized Red */
|
||||||
|
.hljs-deletion,
|
||||||
|
.hljs-important {
|
||||||
|
color: #dc322f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Solarized Violet */
|
||||||
|
.hljs-link_label {
|
||||||
|
color: #6c71c4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tex .hljs-formula {
|
||||||
|
background: #eee8d5;
|
||||||
|
}
|
||||||
+12
-12
@@ -1,8 +1,9 @@
|
|||||||
/* http://jmblog.github.io/color-themes-for-highlightjs */
|
/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */
|
||||||
|
|
||||||
/* Tomorrow Comment */
|
/* Tomorrow Comment */
|
||||||
.hljs-comment {
|
.hljs-comment,
|
||||||
color: hsl(207, 35%, 35%);
|
.hljs-title {
|
||||||
|
color: #8e908c;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tomorrow Red */
|
/* Tomorrow Red */
|
||||||
@@ -27,9 +28,9 @@
|
|||||||
.hljs-pragma,
|
.hljs-pragma,
|
||||||
.hljs-built_in,
|
.hljs-built_in,
|
||||||
.hljs-literal,
|
.hljs-literal,
|
||||||
.hljs-constant,
|
.hljs-params,
|
||||||
.hljs-function .hljs-title {
|
.hljs-constant {
|
||||||
color: hsl(50, 100%, 60%);
|
color: #f5871f;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tomorrow Yellow */
|
/* Tomorrow Yellow */
|
||||||
@@ -45,7 +46,7 @@
|
|||||||
.hljs-header,
|
.hljs-header,
|
||||||
.ruby .hljs-symbol,
|
.ruby .hljs-symbol,
|
||||||
.xml .hljs-cdata {
|
.xml .hljs-cdata {
|
||||||
color: hsl(0, 100%, 70%);
|
color: #718c00;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tomorrow Aqua */
|
/* Tomorrow Aqua */
|
||||||
@@ -54,7 +55,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Tomorrow Blue */
|
/* Tomorrow Blue */
|
||||||
.hljs-function .keyword,
|
.hljs-function,
|
||||||
.python .hljs-decorator,
|
.python .hljs-decorator,
|
||||||
.python .hljs-title,
|
.python .hljs-title,
|
||||||
.ruby .hljs-function .hljs-title,
|
.ruby .hljs-function .hljs-title,
|
||||||
@@ -62,13 +63,13 @@
|
|||||||
.perl .hljs-sub,
|
.perl .hljs-sub,
|
||||||
.javascript .hljs-title,
|
.javascript .hljs-title,
|
||||||
.coffeescript .hljs-title {
|
.coffeescript .hljs-title {
|
||||||
color: hsl(207, 70%, 60%);
|
color: #4271ae;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tomorrow Purple */
|
/* Tomorrow Purple */
|
||||||
.hljs-keyword,
|
.hljs-keyword,
|
||||||
.javascript .hljs-function {
|
.javascript .hljs-function {
|
||||||
color: hsl(207, 95%, 70%);
|
color: #8959a8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hljs {
|
.hljs {
|
||||||
@@ -76,7 +77,6 @@
|
|||||||
background: white;
|
background: white;
|
||||||
color: #4d4d4c;
|
color: #4d4d4c;
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
font-family: "Anonymous Pro", "Inconsolata", "Monaco", monospace;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.coffeescript .javascript,
|
.coffeescript .javascript,
|
||||||
@@ -87,4 +87,4 @@
|
|||||||
.xml .css,
|
.xml .css,
|
||||||
.xml .hljs-cdata {
|
.xml .hljs-cdata {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,27 @@
|
|||||||
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal {
|
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal {
|
||||||
color:@page-color-1;
|
color:@page-color-1;
|
||||||
|
|
||||||
|
pre, code {
|
||||||
|
background: #fdf6e3;
|
||||||
|
color: #657b83;
|
||||||
|
border-color: darken(#fdf6e3, 15%);
|
||||||
|
|
||||||
|
@import "./highlight/sepia.less";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal {
|
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal {
|
||||||
color:@page-color-2;
|
color:@page-color-2;
|
||||||
|
|
||||||
|
pre, code {
|
||||||
|
background: black;
|
||||||
|
color: #eaeaea;
|
||||||
|
border-color: #000;
|
||||||
|
|
||||||
|
@import "./highlight/night.less";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.book .book-body .page-wrapper .page-inner section.normal {
|
.book .book-body .page-wrapper .page-inner section.normal {
|
||||||
padding: 25px;
|
padding-bottom: 25px;
|
||||||
padding-top: 15px;
|
padding-top: 15px;
|
||||||
color:@page-color;
|
color:@page-color;
|
||||||
|
|
||||||
@@ -56,25 +72,25 @@
|
|||||||
font-size: inherit; }
|
font-size: inherit; }
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 28px;
|
font-size: 2.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font-size: 24px;
|
font-size: 2em;
|
||||||
border-bottom: 1px solid #eee;
|
border-bottom: 1px solid #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
font-size: 18px; }
|
font-size: 1.5em; }
|
||||||
|
|
||||||
h4 {
|
h4 {
|
||||||
font-size: 16px; }
|
font-size: 1.2em; }
|
||||||
|
|
||||||
h5 {
|
h5 {
|
||||||
font-size: 14px; }
|
font-size: 1em; }
|
||||||
|
|
||||||
h6 {
|
h6 {
|
||||||
font-size: 14px; }
|
font-size: 1em; }
|
||||||
|
|
||||||
p, blockquote, ul, ol, dl, table, pre {
|
p, blockquote, ul, ol, dl, table, pre {
|
||||||
margin: 15px 0; }
|
margin: 15px 0; }
|
||||||
@@ -276,29 +292,15 @@
|
|||||||
white-space: pre;
|
white-space: pre;
|
||||||
border: none;
|
border: none;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
|
||||||
|
|
||||||
.highlight pre {
|
@import "./highlight/white.less";
|
||||||
color: hsl(204, 40%, 80%);
|
|
||||||
background-color: hsl(204, 30%, 10%);
|
|
||||||
border: 1px solid hsl(204, 30%, 10%);
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 1.5em;
|
|
||||||
overflow: auto;
|
|
||||||
padding: 20px;
|
|
||||||
margin: 0 -20px;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
color: hsl(204, 40%, 80%);
|
font-size: inherit;
|
||||||
background-color: hsl(204, 30%, 10%);
|
|
||||||
border: 1px solid hsl(204, 30%, 10%);
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 1.5em;
|
line-height: 1.5em;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
margin: 0 -20px;
|
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,11 @@
|
|||||||
width: 50%;
|
width: 50%;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
float: left;
|
float: left;
|
||||||
|
|
||||||
|
&.navigation-unique {
|
||||||
|
max-width: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 10px;
|
||||||
|
|
||||||
.bar {
|
.bar {
|
||||||
height: @bar-height;
|
height: @bar-height;
|
||||||
|
|||||||
@@ -29,8 +29,12 @@
|
|||||||
|
|
||||||
.question-inner {
|
.question-inner {
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
|
.quiz-label {
|
||||||
|
font-weight: normal;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -46,4 +50,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
.book-summary {
|
.book-summary {
|
||||||
font-family: @font-family-sans;
|
font-family: @font-family-sans;
|
||||||
|
|
||||||
position: fixed;
|
position: absolute;
|
||||||
top: @header-height;
|
top: @header-height;
|
||||||
left: -@sidebar-width;
|
left: -@sidebar-width;
|
||||||
bottom: 0px;
|
bottom: 0px;
|
||||||
@@ -162,6 +162,7 @@
|
|||||||
li {
|
li {
|
||||||
&.divider {
|
&.divider {
|
||||||
background: @sidebar-divider-color-1;
|
background: @sidebar-divider-color-1;
|
||||||
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
i.fa-check {
|
i.fa-check {
|
||||||
@@ -206,6 +207,7 @@
|
|||||||
li {
|
li {
|
||||||
&.divider {
|
&.divider {
|
||||||
background: @sidebar-divider-color-2;
|
background: @sidebar-divider-color-2;
|
||||||
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
i.fa-check {
|
i.fa-check {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
@import "variables.less";
|
@import "variables.less";
|
||||||
@import "fonts.less";
|
@import "fonts.less";
|
||||||
|
|
||||||
@import "book/highlight.less";
|
|
||||||
@import "book/languages.less";
|
@import "book/languages.less";
|
||||||
@import "book/header.less";
|
@import "book/header.less";
|
||||||
@import "book/summary.less";
|
@import "book/summary.less";
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<div class="book-header">
|
<div class="book-header">
|
||||||
<!-- Actions Left -->
|
<!-- Actions Left -->
|
||||||
{% if githubId %}
|
{% if options.links.home !== false and (options.links.home != null or githubId) %}
|
||||||
<a href="{{ githubHost }}{{ githubId }}" target="_blank" class="btn pull-left"><i class="fa fa-github-alt"></i></a>
|
<a href="{{ options.links.home|default(githubHost+githubId) }}" target="_blank" class="btn pull-left"><i class="fa fa-bookmark-o"></i></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="#" class="btn pull-left toggle-summary"><i class="fa fa-align-justify"></i></a>
|
<a href="#" class="btn pull-left toggle-summary"><i class="fa fa-align-justify"></i></a>
|
||||||
<a href="#" class="btn pull-left toggle-search"><i class="fa fa-search"></i></a>
|
<a href="#" class="btn pull-left toggle-search"><i class="fa fa-search"></i></a>
|
||||||
@@ -12,15 +12,24 @@
|
|||||||
</span>
|
</span>
|
||||||
|
|
||||||
<!-- Actions Right -->
|
<!-- Actions Right -->
|
||||||
|
{% if options.links.sharing.google !== false %}
|
||||||
<a href="#" target="_blank" class="btn pull-right" data-sharing="google-plus"><i class="fa fa-google-plus"></i></a>
|
<a href="#" target="_blank" class="btn pull-right" data-sharing="google-plus"><i class="fa fa-google-plus"></i></a>
|
||||||
|
{% endif %}
|
||||||
|
{% if options.links.sharing.facebook !== false %}
|
||||||
<a href="#" target="_blank" class="btn pull-right" data-sharing="facebook"><i class="fa fa-facebook"></i></a>
|
<a href="#" target="_blank" class="btn pull-right" data-sharing="facebook"><i class="fa fa-facebook"></i></a>
|
||||||
|
{% endif %}
|
||||||
|
{% if options.links.sharing.twitter !== false %}
|
||||||
<a href="#" target="_blank" class="btn pull-right" data-sharing="twitter"><i class="fa fa-twitter"></i></a>
|
<a href="#" target="_blank" class="btn pull-right" data-sharing="twitter"><i class="fa fa-twitter"></i></a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if githubId %}
|
{% if githubId %}
|
||||||
<a href="{{ githubHost }}{{ githubId }}/stargazers" target="_blank" class="btn pull-right count-star"><i class="fa fa-star-o"></i> Star (<span>-</span>)</a>
|
<a href="{{ githubHost }}{{ githubId }}/stargazers" target="_blank" class="btn pull-right count-star hidden-xs"><i class="fa fa-star-o"></i> Star (<span>-</span>)</a>
|
||||||
<a href="{{ githubHost }}{{ githubId }}/watchers" target="_blank" class="btn pull-right count-watch"><i class="fa fa-eye"></i> Watch (<span>-</span>)</a>
|
<a href="{{ githubHost }}{{ githubId }}/watchers" target="_blank" class="btn pull-right count-watch hidden-xs"><i class="fa fa-eye"></i> Watch (<span>-</span>)</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<!-- Title -->
|
<!-- Title -->
|
||||||
<h1><a href="{{ basePath }}/" >{{ title }}</a></h1>
|
<h1>
|
||||||
|
<i class="fa fa-spinner fa-spin"></i>
|
||||||
|
<a href="{{ basePath }}/" >{{ title }}</a>
|
||||||
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,18 +3,28 @@
|
|||||||
<input type="text" placeholder="Search" class="form-control" />
|
<input type="text" placeholder="Search" class="form-control" />
|
||||||
</div>
|
</div>
|
||||||
<ul class="summary">
|
<ul class="summary">
|
||||||
{% if githubId %}
|
{% if options.links.about !== false && (options.links.about != null || githubId) %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ githubHost }}{{ githubAuthor }}" target="blank">About the author</a>
|
<a href="{{ options.links.about|default(githubHost+githubAuthor) }}" target="blank">About the author</a>
|
||||||
</li>
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if options.links.issues !== false && (options.links.issues != null || githubId) %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ githubHost }}{{ githubId }}/issues" target="blank">Questions and Issues</a>
|
<a href="{{ options.links.issues|default(githubHost+githubId+"/issues") }}" target="blank">Questions and Issues</a>
|
||||||
</li>
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if options.links.contribute !== false && (options.links.contribute != null || githubId) %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ githubHost }}{{ githubId }}/edit/master/{{ _input }}" target="blank">Edit and Contribute</a>
|
<a href="{{ options.links.contribute|default(githubHost+githubId+"/edit/master/"+_input) }}" target="blank">Edit and Contribute</a>
|
||||||
</li>
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if options.links.contribute || options.links.issues || options.links.about || githubId %}
|
||||||
<li class="divider"></li>
|
<li class="divider"></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<li data-level="0" data-path="index.html">
|
<li data-level="0" data-path="index.html">
|
||||||
<a href="{{ basePath }}/"><i class="fa fa-check"></i> Introduction</a>
|
<a href="{{ basePath }}/"><i class="fa fa-check"></i> Introduction</a>
|
||||||
</li>
|
</li>
|
||||||
@@ -44,5 +54,12 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if options.links.gitbook !== false %}
|
||||||
|
<li class="divider"></li>
|
||||||
|
<li>
|
||||||
|
<a href="http://www.gitbook.io/" target="blank">Generated using GitBook</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!DOCTYPE HTML>
|
<!DOCTYPE HTML>
|
||||||
<html lang="en-US">
|
<html lang="en-US" {% block htmlTag %}{% endblock %}>
|
||||||
<head prefix="og: http://ogp.me/ns# book: http://ogp.me/ns/book#">
|
<head prefix="og: http://ogp.me/ns# book: http://ogp.me/ns/book#">
|
||||||
{% block head %}
|
{% block head %}
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{% extends "layout.html" %}
|
{% extends "layout.html" %}
|
||||||
|
|
||||||
|
{% block htmlTag %}manifest="{{ basePath }}/manifest.appcache"{% endblock %}
|
||||||
{% block title %}{{ progress.current.title }}{% parent %}{% endblock %}
|
{% block title %}{{ progress.current.title }}{% parent %}{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="book" {% if githubId %}data-github="{{ githubId }}"{% endif %} data-level="{{ progress.current.level }}" data-basepath="{{ basePath }}" data-revision="{{ revision }}">
|
<div class="book" {% if githubId %}data-github="{{ githubId }}"{% endif %} data-level="{{ progress.current.level }}" data-basepath="{{ basePath }}" data-revision="{{ revision }}">
|
||||||
@@ -27,10 +28,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if progress.current.prev and progress.current.prev.path %}
|
{% if progress.current.prev and progress.current.prev.path %}
|
||||||
<a href="{{ basePath }}/{{ progress.current.prev.path|mdLink }}" class="navigation navigation-prev"><i class="fa fa-angle-left"></i></a>
|
<a href="{{ basePath }}/{{ progress.current.prev.path|mdLink }}" class="navigation navigation-prev {% if !progress.current.next or !progress.current.next.path %}navigation-unique{% endif %}"><i class="fa fa-angle-left"></i></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if progress.current.next and progress.current.next.path %}
|
{% if progress.current.next and progress.current.next.path %}
|
||||||
<a href="{{ basePath }}/{{ progress.current.next.path|mdLink }}" class="navigation navigation-next"><i class="fa fa-angle-right"></i></a>
|
<a href="{{ basePath }}/{{ progress.current.next.path|mdLink }}" class="navigation navigation-next {% if !progress.current.prev or !progress.current.prev.path %}navigation-unique{% endif %}"><i class="fa fa-angle-right"></i></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user