mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-28 04:58:52 +00:00
Compare commits
76 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4481b5f556 | |||
| 0e0d051f7c | |||
| a1b649a279 | |||
| e6bc0a0fb7 | |||
| 93e4016c09 | |||
| 20c741a248 | |||
| 54f530c7c3 | |||
| 9fdc5da22d | |||
| 99ce48b146 | |||
| 6a33ad9ef7 | |||
| ca94055adf | |||
| 36a67e4c91 | |||
| 69431e1bbb | |||
| a3fc4ee2b0 | |||
| e505fd6d54 | |||
| 93a3785e4c | |||
| a02de84812 | |||
| c0521f0ec7 | |||
| 83d8c16853 | |||
| 47e9506397 | |||
| b8a3d0e254 | |||
| 001d7ec44e | |||
| 5cb0ec447a | |||
| 67e7d77302 | |||
| 8cbd8b2b48 | |||
| 7c404dbf96 | |||
| c4a67b6f2f | |||
| 3b70347625 | |||
| bb0a7935e9 | |||
| 8f4b799d3c | |||
| 931e0c66c9 | |||
| 0212084862 | |||
| 9abbabbce3 | |||
| ac610487e8 | |||
| a9a0f89892 | |||
| 305f221077 | |||
| 53514f2602 | |||
| 00327778cb | |||
| 37fadec787 | |||
| ada11d0b59 | |||
| 4c90fdb7b2 | |||
| 98c133df3c | |||
| f86c27b090 | |||
| b5b8ed72a5 | |||
| 5beff86548 | |||
| dd395edae1 | |||
| d1c1d7b75b | |||
| 4a380e9279 | |||
| 878c105def | |||
| 74d628676b | |||
| 6fdd98ec3a | |||
| 2ed1be3533 | |||
| 0ac04e1584 | |||
| 2a38d33d8a | |||
| fb14caf5b3 | |||
| cf51772f54 | |||
| cc8516df83 | |||
| c6a624bc6b | |||
| 8be8b825ee | |||
| 56eb4a2897 | |||
| 7a461eaa61 | |||
| fd64c05809 | |||
| 6bce93d893 | |||
| c9db068227 | |||
| 8a6d36ac4d | |||
| 64622c5945 | |||
| 837813edb0 | |||
| 0d9d62f1a9 | |||
| f7e9abf984 | |||
| dd0579b60d | |||
| b5bb953e47 | |||
| ef4a8ea1b6 | |||
| 49cde96ee7 | |||
| 627be20e48 | |||
| e45bb84b02 | |||
| 4e8876c725 |
@@ -15,3 +15,4 @@ Contributors
|
|||||||
------------
|
------------
|
||||||
|
|
||||||
- Nijiko Yonskai
|
- Nijiko Yonskai
|
||||||
|
- Herman Starikov
|
||||||
|
|||||||
+1
-5
@@ -24,7 +24,7 @@ module.exports = function (grunt) {
|
|||||||
requirejs: {
|
requirejs: {
|
||||||
compile: {
|
compile: {
|
||||||
options: {
|
options: {
|
||||||
name: "app",
|
name: "gitbook",
|
||||||
baseUrl: "theme/javascript/",
|
baseUrl: "theme/javascript/",
|
||||||
out: "theme/assets/app.js",
|
out: "theme/assets/app.js",
|
||||||
preserveLicenseComments: false,
|
preserveLicenseComments: false,
|
||||||
@@ -35,7 +35,6 @@ module.exports = function (grunt) {
|
|||||||
"lodash": 'vendors/lodash',
|
"lodash": 'vendors/lodash',
|
||||||
"requireLib": 'vendors/require',
|
"requireLib": 'vendors/require',
|
||||||
"Mousetrap": 'vendors/mousetrap',
|
"Mousetrap": 'vendors/mousetrap',
|
||||||
"mixpanel": 'vendors/mixpanel',
|
|
||||||
"lunr": path.join(__dirname, "node_modules/lunr/lunr")
|
"lunr": path.join(__dirname, "node_modules/lunr/lunr")
|
||||||
},
|
},
|
||||||
shim: {
|
shim: {
|
||||||
@@ -48,9 +47,6 @@ module.exports = function (grunt) {
|
|||||||
'Mousetrap': {
|
'Mousetrap': {
|
||||||
exports: 'Mousetrap'
|
exports: 'Mousetrap'
|
||||||
},
|
},
|
||||||
'mixpanel': {
|
|
||||||
exports: 'mixpanel'
|
|
||||||
},
|
|
||||||
'lunr': {
|
'lunr': {
|
||||||
exports: 'lunr'
|
exports: 'lunr'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ Apache License
|
|||||||
same "printed page" as the copyright notice for easier
|
same "printed page" as the copyright notice for easier
|
||||||
identification within third-party archives.
|
identification within third-party archives.
|
||||||
|
|
||||||
Copyright {yyyy} {name of copyright owner}
|
Copyright 2014 FriendCode Inc.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -198,4 +198,4 @@ Apache License
|
|||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ GitBook
|
|||||||
|
|
||||||
[](https://travis-ci.org/GitbookIO/gitbook)
|
[](https://travis-ci.org/GitbookIO/gitbook)
|
||||||
|
|
||||||
GitBook is a command line tool (and Node.js library) for building beautiful programming books and exercises using GitHub/Git and Markdown. You can see an example: [Learn Javascript](http://gitbookio.github.io/javascript/).
|
GitBook is a command line tool (and Node.js library) for building beautiful programming books and exercises using GitHub/Git and Markdown. You can see an example: [Learn Javascript](http://gitbookio.github.io/javascript/). An [editor](https://github.com/GitbookIO/editor) is available for Windows, Mac and Linux. You can follow [@GitBookIO](https://twitter.com/GitBookIO) on Twitter.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -36,9 +36,12 @@ Options for commands `build` and `serve` are:
|
|||||||
-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/)
|
--githubHost <url> The url of the github host (defaults to https://github.com/)
|
||||||
--theme <path> Path to theme directory
|
--plugins <plugins> List of plugins to use separated by ","
|
||||||
|
--pluginsConfig <json file> JSON File containing plugins configuration
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can publish your books to our index by visiting [GitBook.io](http://www.gitbook.io)
|
||||||
|
|
||||||
## Output Formats
|
## Output Formats
|
||||||
|
|
||||||
GitBook can generate your book in the following formats:
|
GitBook can generate your book in the following formats:
|
||||||
@@ -131,3 +134,19 @@ You can see a complete example with the [Learn Git](https://github.com/GitbookIO
|
|||||||
#### Ignoring files & folders
|
#### Ignoring files & folders
|
||||||
|
|
||||||
GitBook will read the `.gitignore`, `.bookignore` and `.ignore` files to get a list of files and folders to skip. (The format inside those files, follows the same convention as `.gitignore`)
|
GitBook will read the `.gitignore`, `.bookignore` and `.ignore` files to get a list of files and folders to skip. (The format inside those files, follows the same convention as `.gitignore`)
|
||||||
|
|
||||||
|
#### 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.
|
||||||
|
|
||||||
|
##### Default plugins:
|
||||||
|
|
||||||
|
* [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
|
||||||
|
|
||||||
|
##### Other plugins:
|
||||||
|
|
||||||
|
* [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 comments to notes](https://github.com/erixtekila/gitbook-plugin-comments): Allow markdown comments to be inserted in HTML output
|
||||||
|
* [Send code to console](https://github.com/erixtekila/gitbook-plugin-toconsole): Evaluate javascript blockin the browser inspector's console
|
||||||
|
|||||||
+28
-7
@@ -1,18 +1,37 @@
|
|||||||
var path = require('path');
|
var path = require('path');
|
||||||
var Q = require('q');
|
var Q = require('q');
|
||||||
var _ = require('lodash');
|
var _ = require('lodash');
|
||||||
|
var fs = require('fs');
|
||||||
|
|
||||||
var utils = require('./utils');
|
var utils = require('./utils');
|
||||||
|
|
||||||
var generate = require("../lib/generate");
|
var generate = require("../lib/generate");
|
||||||
var parse = require("../lib/parse");
|
var parse = require("../lib/parse");
|
||||||
var fs = require('../lib/generate/fs');
|
|
||||||
var generators = require("../lib/generate").generators;
|
var generators = require("../lib/generate").generators;
|
||||||
|
|
||||||
|
var buildCommand = function(command) {
|
||||||
|
return command
|
||||||
|
.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('-t, --title <name>', 'Name of the book to generate, default is extracted from readme')
|
||||||
|
.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/');
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
var makeBuildFunc = function(converter) {
|
var makeBuildFunc = function(converter) {
|
||||||
return function(dir, options) {
|
return function(dir, options) {
|
||||||
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
|
// Get repo's URL
|
||||||
@@ -25,7 +44,7 @@ var makeBuildFunc = function(converter) {
|
|||||||
})
|
})
|
||||||
.then(function(repoID) {
|
.then(function(repoID) {
|
||||||
return converter(
|
return converter(
|
||||||
_.extend(options || {}, {
|
_.extend({}, options || {}, {
|
||||||
input: dir,
|
input: dir,
|
||||||
output: outputDir,
|
output: outputDir,
|
||||||
title: options.title,
|
title: options.title,
|
||||||
@@ -33,7 +52,8 @@ var makeBuildFunc = function(converter) {
|
|||||||
github: options.github || repoID,
|
github: options.github || repoID,
|
||||||
githubHost: options.githubHost,
|
githubHost: options.githubHost,
|
||||||
generator: options.format,
|
generator: options.format,
|
||||||
theme: options.theme
|
plugins: options.plugins,
|
||||||
|
pluginsConfig: pluginsConfig
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
@@ -42,9 +62,10 @@ var makeBuildFunc = function(converter) {
|
|||||||
return output;
|
return output;
|
||||||
}, utils.logError);
|
}, utils.logError);
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
folder: makeBuildFunc(generate.folder),
|
folder: makeBuildFunc(generate.folder),
|
||||||
file: makeBuildFunc(generate.file)
|
file: makeBuildFunc(generate.file),
|
||||||
|
command: buildCommand
|
||||||
};
|
};
|
||||||
|
|||||||
+36
-26
@@ -12,45 +12,55 @@ 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
|
||||||
.version(pkg.version);
|
.version(pkg.version);
|
||||||
|
|
||||||
var buildCommand = function(command) {
|
build.command(prog.command('build [source_dir]'))
|
||||||
return command
|
|
||||||
.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('-t, --title <name>', 'Name of the book to generate, default is extracted from readme')
|
|
||||||
.option('-i, --intro <intro>', 'Description of the book to generate, default is extracted from readme')
|
|
||||||
.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/')
|
|
||||||
.option('--theme <path>', 'Path to theme directory');
|
|
||||||
};
|
|
||||||
|
|
||||||
buildCommand(prog.command('build [source_dir]'))
|
|
||||||
.description('Build a gitbook from a directory')
|
.description('Build a gitbook from a directory')
|
||||||
.action(build.folder);
|
.action(build.folder);
|
||||||
|
|
||||||
buildCommand(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 "+path.relative(dir, filepath));
|
||||||
|
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();
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
buildCommand(prog.command('pdf [source_dir]'))
|
build.command(prog.command('pdf [source_dir]'))
|
||||||
.description('Build a gitbook as a PDF')
|
.description('Build a gitbook as a PDF')
|
||||||
.option('-pf, --paperformat <format>', 'PDF paper format (default is A4): "5in*7.5in", "10cm*20cm", "A4", "Letter"')
|
.option('-pf, --paperformat <format>', 'PDF paper format (default is A4): "5in*7.5in", "10cm*20cm", "A4", "Letter"')
|
||||||
.action(function(dir, options) {
|
.action(function(dir, options) {
|
||||||
@@ -60,7 +70,7 @@ buildCommand(prog.command('pdf [source_dir]'))
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
buildCommand(prog.command('ebook [source_dir]'))
|
build.command(prog.command('ebook [source_dir]'))
|
||||||
.description('Build a gitbook as a eBook')
|
.description('Build a gitbook as a eBook')
|
||||||
.option('-c, --cover <path>', 'Cover image, default is cover.png if exists')
|
.option('-c, --cover <path>', 'Cover image, default is cover.png if exists')
|
||||||
.action(function(dir, options) {
|
.action(function(dir, options) {
|
||||||
|
|||||||
@@ -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;
|
||||||
+18
-23
@@ -4,8 +4,11 @@ var _ = require('lodash');
|
|||||||
var http = require('http');
|
var http = require('http');
|
||||||
var send = require('send');
|
var send = require('send');
|
||||||
|
|
||||||
var url = require('url');
|
|
||||||
var cp = require('child_process');
|
var cp = require('child_process');
|
||||||
|
var path = require('path');
|
||||||
|
var url = require('url');
|
||||||
|
|
||||||
|
var Gaze = require('gaze').Gaze;
|
||||||
|
|
||||||
|
|
||||||
// Get the remote of a given repo
|
// Get the remote of a given repo
|
||||||
@@ -55,32 +58,24 @@ function titleCase(str)
|
|||||||
return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
|
return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
|
||||||
}
|
}
|
||||||
|
|
||||||
function serveDir(dir, port) {
|
function watch(dir) {
|
||||||
var d = Q.defer();
|
var d = Q.defer();
|
||||||
|
dir = path.resolve(dir);
|
||||||
|
|
||||||
var server = http.createServer(function(req, res){
|
var gaze = new Gaze("**/*.md", {
|
||||||
// Render error
|
cwd: dir
|
||||||
function error(err) {
|
});
|
||||||
res.statusCode = err.status || 500;
|
|
||||||
res.end(err.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Redirect to directory's index.html
|
gaze.once("all", function(e, filepath) {
|
||||||
function redirect() {
|
gaze.close();
|
||||||
res.statusCode = 301;
|
|
||||||
res.setHeader('Location', req.url + '/');
|
|
||||||
res.end('Redirecting to ' + req.url + '/');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send file
|
d.resolve(filepath);
|
||||||
send(req, url.parse(req.url).pathname)
|
});
|
||||||
.root(dir)
|
gaze.once("error", function(err) {
|
||||||
.on('error', error)
|
gaze.close();
|
||||||
.on('directory', redirect)
|
|
||||||
.pipe(res);
|
|
||||||
}).listen(port);
|
|
||||||
|
|
||||||
d.resolve(server);
|
d.reject(err);
|
||||||
|
});
|
||||||
|
|
||||||
return d.promise;
|
return d.promise;
|
||||||
}
|
}
|
||||||
@@ -96,6 +91,6 @@ module.exports = {
|
|||||||
gitURL: gitURL,
|
gitURL: gitURL,
|
||||||
githubID: githubID,
|
githubID: githubID,
|
||||||
titleCase: titleCase,
|
titleCase: titleCase,
|
||||||
serveDir: serveDir,
|
watch: watch,
|
||||||
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
|
||||||
|
|||||||
@@ -1,9 +1,30 @@
|
|||||||
|
var _ = require("lodash");
|
||||||
var path = require("path");
|
var path = require("path");
|
||||||
var Q = require("q");
|
var Q = require("q");
|
||||||
var fs = require("./fs");
|
var fs = require("./fs");
|
||||||
|
|
||||||
|
var Plugin = require("./plugin");
|
||||||
|
|
||||||
var BaseGenerator = function(options) {
|
var BaseGenerator = function(options) {
|
||||||
this.options = options;
|
this.options = options;
|
||||||
|
|
||||||
|
this.options.plugins = Plugin.normalizeNames(this.options.plugins);
|
||||||
|
this.plugins = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
BaseGenerator.prototype.callHook = function(name) {
|
||||||
|
return this.plugins.hook(name, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
BaseGenerator.prototype.loadPlugins = function() {
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
return Plugin.fromList(this.options.plugins, this.options.input)
|
||||||
|
.then(function(_plugins) {
|
||||||
|
that.plugins = _plugins;
|
||||||
|
|
||||||
|
return that.callHook("init");
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
BaseGenerator.prototype.convertFile = function(content, input) {
|
BaseGenerator.prototype.convertFile = function(content, input) {
|
||||||
|
|||||||
+14
-4
@@ -6,6 +6,7 @@ var tmp = require('tmp');
|
|||||||
|
|
||||||
var fs = require("./fs");
|
var fs = require("./fs");
|
||||||
var parse = require("../parse");
|
var parse = require("../parse");
|
||||||
|
var Plugin = require("./plugin");
|
||||||
|
|
||||||
var generators = {
|
var generators = {
|
||||||
"site": require("./site"),
|
"site": require("./site"),
|
||||||
@@ -42,7 +43,11 @@ var generate = function(options) {
|
|||||||
githubHost: 'https://github.com/',
|
githubHost: 'https://github.com/',
|
||||||
|
|
||||||
// Theming
|
// Theming
|
||||||
theme: path.resolve(__dirname, '../../theme')
|
theme: path.resolve(__dirname, '../../theme'),
|
||||||
|
|
||||||
|
// Plugins
|
||||||
|
plugins: [],
|
||||||
|
pluginsConfig: {}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!options.input) {
|
if (!options.input) {
|
||||||
@@ -70,9 +75,10 @@ var generate = function(options) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// Create the generator
|
// Create the generator and load plugins
|
||||||
.then(function() {
|
.then(function() {
|
||||||
generator = new generators[options.generator](options);
|
generator = new generators[options.generator](options);
|
||||||
|
return generator.loadPlugins();
|
||||||
})
|
})
|
||||||
|
|
||||||
// Detect multi-languages book
|
// Detect multi-languages book
|
||||||
@@ -160,9 +166,12 @@ var generate = function(options) {
|
|||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
|
||||||
// Finish gneration
|
// Finish generation
|
||||||
.then(function() {
|
.then(function() {
|
||||||
return generator.finish();
|
return generator.finish();
|
||||||
|
})
|
||||||
|
.then(function() {
|
||||||
|
return generator.callHook("finish");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -234,5 +243,6 @@ var generateFile = function(options) {
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
generators: generators,
|
generators: generators,
|
||||||
folder: generate,
|
folder: generate,
|
||||||
file: generateFile
|
file: generateFile,
|
||||||
|
Plugin: Plugin
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -25,14 +25,18 @@ swig.setFilter('code', function(code, lang) {
|
|||||||
var Generator = function() {
|
var Generator = function() {
|
||||||
BaseGenerator.apply(this, arguments);
|
BaseGenerator.apply(this, arguments);
|
||||||
|
|
||||||
// Load base template
|
|
||||||
this.template = swig.compileFile(path.resolve(this.options.theme, 'templates/page.html'));
|
|
||||||
|
|
||||||
// List of pages content
|
// List of pages content
|
||||||
this.pages = {};
|
this.pages = {};
|
||||||
};
|
};
|
||||||
util.inherits(Generator, BaseGenerator);
|
util.inherits(Generator, BaseGenerator);
|
||||||
|
|
||||||
|
// Load all templates
|
||||||
|
Generator.prototype.loadTemplates = function() {
|
||||||
|
this.template = swig.compileFile(
|
||||||
|
this.plugins.template("page") || path.resolve(this.options.theme, 'templates/page.html')
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
Generator.prototype.convertFile = function(content, input) {
|
Generator.prototype.convertFile = function(content, input) {
|
||||||
var that = this;
|
var that = this;
|
||||||
var json = {
|
var json = {
|
||||||
@@ -46,6 +50,7 @@ Generator.prototype.convertFile = function(content, input) {
|
|||||||
repo: that.options.githubId,
|
repo: that.options.githubId,
|
||||||
dir: path.dirname(input) || '/',
|
dir: path.dirname(input) || '/',
|
||||||
outdir: './',
|
outdir: './',
|
||||||
|
singleFile: true
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then(function(sections) {
|
.then(function(sections) {
|
||||||
|
|||||||
@@ -0,0 +1,187 @@
|
|||||||
|
var _ = require("lodash");
|
||||||
|
var Q = require("q");
|
||||||
|
var semver = require("semver");
|
||||||
|
var path = require("path");
|
||||||
|
var url = require("url");
|
||||||
|
var fs = require("./fs");
|
||||||
|
var resolve = require('resolve');
|
||||||
|
|
||||||
|
var pkg = require("../../package.json");
|
||||||
|
|
||||||
|
var RESOURCES = ["js", "css"];
|
||||||
|
|
||||||
|
var Plugin = function(name, root) {
|
||||||
|
this.name = name;
|
||||||
|
this.root = root;
|
||||||
|
this.packageInfos = {};
|
||||||
|
this.infos = {};
|
||||||
|
|
||||||
|
_.each([
|
||||||
|
"gitbook-plugin-"+name,
|
||||||
|
"gitbook-theme-"+name,
|
||||||
|
"gitbook-"+name,
|
||||||
|
name,
|
||||||
|
], function(_name) {
|
||||||
|
if (this.load(_name, __dirname)) return false;
|
||||||
|
if (this.load(_name, path.resolve(root))) return false;
|
||||||
|
}, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Load from a name
|
||||||
|
Plugin.prototype.load = function(name, baseDir) {
|
||||||
|
try {
|
||||||
|
var res = resolve.sync(name+"/package.json", { basedir: baseDir });
|
||||||
|
|
||||||
|
this.baseDir = path.dirname(res);
|
||||||
|
this.packageInfos = require(res);
|
||||||
|
this.infos = require(resolve.sync(name, { basedir: baseDir }));
|
||||||
|
this.name = name;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Return resources
|
||||||
|
Plugin.prototype.getResources = function(resource) {
|
||||||
|
if (!this.infos.book || !this.infos.book[resource]) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return _.chain(this.infos.book[resource])
|
||||||
|
.map(function(resource) {
|
||||||
|
var parsed = url.parse(resource);
|
||||||
|
if (parsed.protocol) return {"url": resource}
|
||||||
|
else return { "path": this.name+"/"+resource };
|
||||||
|
}.bind(this))
|
||||||
|
.value();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Test if it's a valid plugin
|
||||||
|
Plugin.prototype.isValid = function() {
|
||||||
|
return (
|
||||||
|
this.packageInfos
|
||||||
|
&& this.packageInfos.name
|
||||||
|
&& this.packageInfos.engines
|
||||||
|
&& this.packageInfos.engines.gitbook
|
||||||
|
&& semver.satisfies(pkg.version, this.packageInfos.engines.gitbook)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Resolve file path
|
||||||
|
Plugin.prototype.resolveFile = function(filename) {
|
||||||
|
return path.resolve(this.baseDir, filename);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Resolve file path
|
||||||
|
Plugin.prototype.callHook = function(name, args) {
|
||||||
|
var hookFunc = this.infos.hooks? this.infos.hooks[name] : null;
|
||||||
|
args = _.isArray(args) ? args : [args];
|
||||||
|
|
||||||
|
if (!hookFunc) return Q();
|
||||||
|
|
||||||
|
return Q()
|
||||||
|
.then(function() {
|
||||||
|
return hookFunc.apply(null, args);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Copy plugin assets fodler
|
||||||
|
Plugin.prototype.copyAssets = function(out) {
|
||||||
|
if (!this.infos.book || !this.infos.book.assets) return Q();
|
||||||
|
return fs.copy(
|
||||||
|
this.resolveFile(this.infos.book.assets),
|
||||||
|
out
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Normalize a list of plugin name to use
|
||||||
|
Plugin.normalizeNames = function(names) {
|
||||||
|
// Normalize list to an array
|
||||||
|
names = _.isString(names) ? names.split(",") : (names || []);
|
||||||
|
|
||||||
|
// List plugins to remove
|
||||||
|
var toremove = _.chain(names)
|
||||||
|
.filter(function(name) {
|
||||||
|
return name.length > 0 && name[0] == "-";
|
||||||
|
})
|
||||||
|
.map(function(name) {
|
||||||
|
return name.slice(1)
|
||||||
|
})
|
||||||
|
.value();
|
||||||
|
|
||||||
|
// Merge with defaults
|
||||||
|
names = _.chain(names)
|
||||||
|
.concat(Plugin.defaults)
|
||||||
|
.uniq()
|
||||||
|
.value();
|
||||||
|
|
||||||
|
// Remove plugins starting with
|
||||||
|
names = _.filter(names, function(name) {
|
||||||
|
return !_.contains(toremove, name) && !(name.length > 0 && name[0] == "-");
|
||||||
|
});
|
||||||
|
|
||||||
|
return names;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Extract data from a list of plugin
|
||||||
|
Plugin.fromList = function(names, root) {
|
||||||
|
var failed = [];
|
||||||
|
|
||||||
|
// Load plugins
|
||||||
|
var plugins = _.map(names, function(name) {
|
||||||
|
var plugin = new Plugin(name, root);
|
||||||
|
if (!plugin.isValid()) failed.push(name);
|
||||||
|
return plugin;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (_.size(failed) > 0) return Q.reject(new Error("Error loading plugins: "+failed.join(",")));
|
||||||
|
|
||||||
|
// Get all resources
|
||||||
|
var resources = _.chain(RESOURCES)
|
||||||
|
.map(function(resource) {
|
||||||
|
return [
|
||||||
|
resource,
|
||||||
|
_.chain(plugins)
|
||||||
|
.map(function(plugin) {
|
||||||
|
return plugin.getResources(resource);
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
.value()
|
||||||
|
];
|
||||||
|
})
|
||||||
|
.object()
|
||||||
|
.value();
|
||||||
|
|
||||||
|
return Q({
|
||||||
|
'list': plugins,
|
||||||
|
'resources': resources,
|
||||||
|
'hook': function(name, args) {
|
||||||
|
return _.reduce(plugins, function(prev, plugin) {
|
||||||
|
return prev.then(function() {
|
||||||
|
return plugin.callHook(name, args);
|
||||||
|
})
|
||||||
|
}, Q());
|
||||||
|
},
|
||||||
|
'template': function(name) {
|
||||||
|
var withTpl = _.find(plugins, function(plugin) {
|
||||||
|
return (plugin.infos.templates
|
||||||
|
&& plugin.infos.templates[name]);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!withTpl) return null;
|
||||||
|
return withTpl.resolveFile(withTpl.infos.templates[name]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Default plugins
|
||||||
|
Plugin.defaults = [
|
||||||
|
"mixpanel",
|
||||||
|
"mathjax"
|
||||||
|
];
|
||||||
|
|
||||||
|
module.exports = 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,13 +31,32 @@ var Generator = function() {
|
|||||||
|
|
||||||
this.revision = Date.now();
|
this.revision = Date.now();
|
||||||
this.indexer = indexer();
|
this.indexer = indexer();
|
||||||
|
this.manifest = new Manifest(Date.now());
|
||||||
// Load base template
|
this.manifest.add("NETWORK", [
|
||||||
this.template = swig.compileFile(path.resolve(this.options.theme, 'templates/site.html'));
|
'*'
|
||||||
this.langsTemplate = swig.compileFile(path.resolve(this.options.theme, 'templates/langs.html'));
|
]);
|
||||||
};
|
};
|
||||||
util.inherits(Generator, BaseGenerator);
|
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')
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Load plugins
|
||||||
|
Generator.prototype.loadPlugins = function() {
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
return BaseGenerator.prototype.loadPlugins.apply(this)
|
||||||
|
.then(function() {
|
||||||
|
return that.loadTemplates();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Generate a template
|
// Generate a template
|
||||||
Generator.prototype._writeTemplate = function(tpl, options, output) {
|
Generator.prototype._writeTemplate = function(tpl, options, output) {
|
||||||
@@ -54,7 +74,10 @@ Generator.prototype._writeTemplate = function(tpl, options, output) {
|
|||||||
githubHost: that.options.githubHost,
|
githubHost: that.options.githubHost,
|
||||||
|
|
||||||
summary: that.options.summary,
|
summary: that.options.summary,
|
||||||
allNavigation: that.options.navigation
|
allNavigation: that.options.navigation,
|
||||||
|
|
||||||
|
plugins: that.plugins,
|
||||||
|
pluginsConfig: JSON.stringify(that.options.pluginsConfig)
|
||||||
}, options));
|
}, options));
|
||||||
})
|
})
|
||||||
.then(function(html) {
|
.then(function(html) {
|
||||||
@@ -101,6 +124,8 @@ Generator.prototype.convertFile = function(content, _input) {
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then(function(sections) {
|
.then(function(sections) {
|
||||||
|
that.manifest.add("CACHE", _output);
|
||||||
|
|
||||||
return that._writeTemplate(that.template, {
|
return that._writeTemplate(that.template, {
|
||||||
progress: progress,
|
progress: progress,
|
||||||
|
|
||||||
@@ -134,10 +159,30 @@ Generator.prototype.langsIndex = function(langs) {
|
|||||||
Generator.prototype.copyAssets = function() {
|
Generator.prototype.copyAssets = function() {
|
||||||
var that = this;
|
var that = this;
|
||||||
|
|
||||||
|
// Copy gitbook assets
|
||||||
return fs.copy(
|
return fs.copy(
|
||||||
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
|
||||||
|
.then(function() {
|
||||||
|
return Q.all(
|
||||||
|
_.map(that.plugins.list, function(plugin) {
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
// Dump search index to disk
|
// Dump search index to disk
|
||||||
@@ -148,9 +193,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;
|
||||||
|
|||||||
+30
-49
@@ -6,6 +6,12 @@ function clean(obj) {
|
|||||||
return obj && _.omit(obj, ['articles']);
|
return obj && _.omit(obj, ['articles']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function flattenChapters(chapters) {
|
||||||
|
return _.reduce(chapters, function(accu, chapter) {
|
||||||
|
return accu.concat([clean(chapter)].concat(chapter.articles));
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
|
||||||
// Returns from a summary a map of
|
// Returns from a summary a map of
|
||||||
/*
|
/*
|
||||||
{
|
{
|
||||||
@@ -20,62 +26,37 @@ function navigation(summary, files) {
|
|||||||
// Support single files as well as list
|
// Support single files as well as list
|
||||||
files = _.isArray(files) ? files : (_.isString(files) ? [files] : null);
|
files = _.isArray(files) ? files : (_.isString(files) ? [files] : null);
|
||||||
|
|
||||||
// Mapping of prev/next for a give path
|
|
||||||
var mapping = {};
|
|
||||||
|
|
||||||
// Special README nav
|
// Special README nav
|
||||||
var README_NAV = {
|
var README_NAV = {
|
||||||
path: 'README.md',
|
path: 'README.md',
|
||||||
title: 'Introduction',
|
title: 'Introduction',
|
||||||
};
|
|
||||||
|
|
||||||
// Walk the chapter/article tree and create navigation entires
|
|
||||||
_.each(summary.chapters, function(chapter, idx, chapters) {
|
|
||||||
// Skip if no path
|
|
||||||
if(!chapter.path) return;
|
|
||||||
|
|
||||||
var currentChapter = clean(chapter);
|
|
||||||
var prevChapter = (idx-1 < 0) ? README_NAV : chapters[idx-1];
|
|
||||||
var nextChapter = (idx+1 >= chapters.length) ? null : chapters[idx+1];
|
|
||||||
|
|
||||||
var prev = (!prevChapter || _.isEmpty(prevChapter.articles)) ?
|
|
||||||
prevChapter : _.last(prevChapter.articles);
|
|
||||||
var next = (!chapter || _.isEmpty(chapter.articles)) ?
|
|
||||||
nextChapter : _.first(chapter.articles);
|
|
||||||
|
|
||||||
// Add chapter mapping
|
|
||||||
mapping[chapter.path] = {
|
|
||||||
title: chapter.title,
|
|
||||||
prev: clean(prev),
|
|
||||||
next: clean(next),
|
|
||||||
level: (idx+1).toString(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Check a chapter's articles
|
|
||||||
_.each(chapter.articles, function(article, _idx, articles) {
|
|
||||||
// Skip if no path
|
|
||||||
if(!article.path) return;
|
|
||||||
|
|
||||||
var prev = (_idx-1 < 0) ? currentChapter : clean(articles[_idx-1]);
|
|
||||||
var next = (_idx+1 >= articles.length) ? nextChapter : clean(articles[_idx+1]);
|
|
||||||
|
|
||||||
mapping[article.path] = {
|
|
||||||
title: article.title,
|
|
||||||
prev: clean(prev),
|
|
||||||
next: clean(next),
|
|
||||||
level: [idx+1, _idx+1].join('.'),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Hack for README.html
|
|
||||||
mapping['README.md'] = {
|
|
||||||
title: README_NAV.title,
|
|
||||||
prev: null,
|
|
||||||
next: clean(summary.chapters[0]),
|
|
||||||
level: '0',
|
level: '0',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// List of all navNodes
|
||||||
|
var navNodes = [README_NAV].concat(flattenChapters(summary.chapters));
|
||||||
|
var prevNodes = [null].concat(navNodes.slice(0, -1));
|
||||||
|
var nextNodes = navNodes.slice(1).concat([null]);
|
||||||
|
|
||||||
|
// Mapping of prev/next for a give path
|
||||||
|
var mapping = _.chain(_.zip(navNodes, prevNodes, nextNodes))
|
||||||
|
.map(function(nodes) {
|
||||||
|
var current = nodes[0], prev = nodes[1], next = nodes[2];
|
||||||
|
|
||||||
|
// Skip if no path
|
||||||
|
if(!current.path) return null;
|
||||||
|
|
||||||
|
return [current.path, {
|
||||||
|
title: current.title,
|
||||||
|
prev: prev,
|
||||||
|
next: next,
|
||||||
|
level: current.level,
|
||||||
|
}];
|
||||||
|
})
|
||||||
|
.filter()
|
||||||
|
.object()
|
||||||
|
.value();
|
||||||
|
|
||||||
// Filter for only files we want
|
// Filter for only files we want
|
||||||
if(files) {
|
if(files) {
|
||||||
return _.pick(mapping, files);
|
return _.pick(mapping, files);
|
||||||
|
|||||||
+34
-10
@@ -1,5 +1,7 @@
|
|||||||
var url = require('url');
|
var url = require('url');
|
||||||
var inherits = require('util').inherits;
|
var inherits = require('util').inherits;
|
||||||
|
var links = require('../utils').links;
|
||||||
|
|
||||||
|
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
|
|
||||||
@@ -16,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);
|
||||||
|
|
||||||
@@ -38,23 +41,38 @@ GitBookRenderer.prototype._unsanitized = function(href) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
GitBookRenderer.prototype.link = function(href, title, text) {
|
GitBookRenderer.prototype.link = function(href, title, text) {
|
||||||
|
// Our "fixed" href
|
||||||
|
var _href = href;
|
||||||
|
|
||||||
// Don't build if it looks malicious
|
// Don't build if it looks malicious
|
||||||
if (this.options.sanitize && this._unsanitized(href)) {
|
if (this.options.sanitize && this._unsanitized(href)) {
|
||||||
return '';
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parsed version of the url
|
// Parsed version of the url
|
||||||
var parsed = url.parse(href);
|
var parsed = url.parse(href);
|
||||||
|
|
||||||
var o = this._extra_options;
|
var o = this._extra_options;
|
||||||
|
|
||||||
// Relative link, rewrite it to point to github repo
|
// Relative link, rewrite it to point to github repo
|
||||||
if(!parsed.protocol && parsed.path && parsed.path[0] != '/' && o && o.repo && o.dir) {
|
if(links.isRelative(_href)) {
|
||||||
href = url.resolve('https://github.com/' + o.repo + '/blob/', [o.dir, href].join("/"));
|
if (path.extname(_href) == ".md") {
|
||||||
parsed = url.parse(href);
|
_href = links.toAbsolute(_href, o.dir || "./", o.outdir || "./");
|
||||||
|
|
||||||
|
if (o.singleFile) {
|
||||||
|
_href = "#"+_href;
|
||||||
|
} else {
|
||||||
|
_href = _href.replace(".md", ".html");
|
||||||
|
}
|
||||||
|
} else if (o && o.repo && o.dir) {
|
||||||
|
href = url.resolve('https://github.com/' + o.repo + '/blob/', [o.dir, _href].join("/"));
|
||||||
|
parsed = url.parse(href);
|
||||||
|
_href = parsed.href;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate HTML for link
|
// Generate HTML for link
|
||||||
var out = '<a href="' + parsed.href + '"';
|
var out = '<a href="' + _href + '"';
|
||||||
// Title if no null
|
// Title if no null
|
||||||
if (title) {
|
if (title) {
|
||||||
out += ' title="' + title + '"';
|
out += ' title="' + title + '"';
|
||||||
@@ -78,9 +96,11 @@ GitBookRenderer.prototype.image = function(href, title, text) {
|
|||||||
var o = this._extra_options;
|
var o = this._extra_options;
|
||||||
|
|
||||||
// Relative image, rewrite it depending output
|
// Relative image, rewrite it depending output
|
||||||
if(!parsed.protocol && parsed.path && parsed.path[0] != '/' && o && o.dir && o.outdir) {
|
if(links.isRelative(href) && o && o.dir && o.outdir) {
|
||||||
var outdir = o.outdir.charAt(o.outdir.length - 1) === '/' ? o.outdir : o.outdir + '/';
|
// o.dir: directory parent of the file currently in rendering process
|
||||||
_href = url.resolve(outdir, [o.dir, href].join('/'));
|
// o.outdir: directory parent from the html output
|
||||||
|
|
||||||
|
_href = links.toAbsolute(_href, o.dir, o.outdir);
|
||||||
}
|
}
|
||||||
|
|
||||||
return GitBookRenderer.super_.prototype.image.call(this, _href, title, text);
|
return GitBookRenderer.super_.prototype.image.call(this, _href, title, text);
|
||||||
@@ -97,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) {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
lang: require('./lang'),
|
lang: require('./lang'),
|
||||||
|
links: require('./links')
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
var url = require('url');
|
||||||
|
var path = require('path');
|
||||||
|
|
||||||
|
// Return true if the link is relative
|
||||||
|
var isRelative = function(href) {
|
||||||
|
var parsed = url.parse(href);
|
||||||
|
|
||||||
|
return !parsed.protocol && parsed.path && parsed.path[0] != '/';
|
||||||
|
};
|
||||||
|
|
||||||
|
// Relative to absolute path
|
||||||
|
// dir: directory parent of the file currently in rendering process
|
||||||
|
// outdir: directory parent from the html output
|
||||||
|
|
||||||
|
var toAbsolute = function(_href, dir, outdir) {
|
||||||
|
// Absolute file in source
|
||||||
|
_href = path.join(dir, _href);
|
||||||
|
|
||||||
|
// make it relative to output
|
||||||
|
_href = path.relative(outdir, _href);
|
||||||
|
|
||||||
|
return _href;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
isRelative: isRelative,
|
||||||
|
toAbsolute: toAbsolute
|
||||||
|
};
|
||||||
+22
-4
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "gitbook",
|
"name": "gitbook",
|
||||||
"version": "0.2.2",
|
"version": "0.3.2",
|
||||||
|
"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",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -15,7 +16,14 @@
|
|||||||
"commander": "2.2.0",
|
"commander": "2.2.0",
|
||||||
"fs-extra": "0.8.1",
|
"fs-extra": "0.8.1",
|
||||||
"highlight.js": "8.0.0",
|
"highlight.js": "8.0.0",
|
||||||
"tmp": "0.0.23"
|
"tmp": "0.0.23",
|
||||||
|
"semver": "2.2.1",
|
||||||
|
"gaze": "0.6.4",
|
||||||
|
"resolve": "0.6.3",
|
||||||
|
|
||||||
|
"gitbook-plugin": "0.0.2",
|
||||||
|
"gitbook-plugin-mixpanel": "0.0.2",
|
||||||
|
"gitbook-plugin-mathjax": "0.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"mocha": "1.18.2",
|
"mocha": "1.18.2",
|
||||||
@@ -39,9 +47,19 @@
|
|||||||
"book",
|
"book",
|
||||||
"gitbook"
|
"gitbook"
|
||||||
],
|
],
|
||||||
"author": "Aaron O'Mullan <aaron.omullan@friendco.de>",
|
"author": "FriendCode <contact@friendco.de>",
|
||||||
"license": "Apache 2",
|
"license": "Apache 2",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/GitbookIO/gitbook/issues"
|
"url": "https://github.com/GitbookIO/gitbook/issues"
|
||||||
}
|
},
|
||||||
|
"contributors": [
|
||||||
|
{
|
||||||
|
"name": "Aaron O'Mullan",
|
||||||
|
"email": "aaron.omullan@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Samy Pessé",
|
||||||
|
"email": "samypesse@gmail.com"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+12
@@ -0,0 +1,12 @@
|
|||||||
|
# Images Test
|
||||||
|
|
||||||
|
This is a test for images path calculation. It supposed this fiel is in a syntax/ folder
|
||||||
|
|
||||||
|
### #
|
||||||
|
|
||||||
|
[](./preview.png)
|
||||||
|
|
||||||
|
### 2
|
||||||
|
|
||||||
|
[](./preview2.png)
|
||||||
|
|
||||||
Vendored
+5
@@ -0,0 +1,5 @@
|
|||||||
|
# Nice course
|
||||||
|
|
||||||
|
Check out this other chapter [Test](test.md)
|
||||||
|
|
||||||
|
Check out this other chapter [Test](../before.md)
|
||||||
+61
-5
@@ -36,10 +36,6 @@ describe('Page parsing', function() {
|
|||||||
assert(LEXED[2].content);
|
assert(LEXED[2].content);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should make image URLs relative', function() {
|
|
||||||
assert(LEXED[2].content.indexOf('_book/assets/my-pretty-picture.png') !== -1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should gen code and content for exercise sections', function() {
|
it('should gen code and content for exercise sections', function() {
|
||||||
assert(LEXED[1].content);
|
assert(LEXED[1].content);
|
||||||
assert(LEXED[1].code);
|
assert(LEXED[1].code);
|
||||||
@@ -88,9 +84,69 @@ describe('Relative links', function() {
|
|||||||
repo: 'GitBookIO/javascript',
|
repo: 'GitBookIO/javascript',
|
||||||
|
|
||||||
// Imaginary folder of markdown file
|
// Imaginary folder of markdown file
|
||||||
dir: 'course'
|
dir: 'course',
|
||||||
|
outdir: './'
|
||||||
});
|
});
|
||||||
|
|
||||||
assert(LEXED[0].content.indexOf('https://github.com/GitBookIO/javascript/blob/src/something.cpp') !== -1);
|
assert(LEXED[0].content.indexOf('https://github.com/GitBookIO/javascript/blob/src/something.cpp') !== -1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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'
|
||||||
|
});
|
||||||
|
|
||||||
|
assert(LEXED[0].content.indexOf('test.html') !== -1);
|
||||||
|
assert(LEXED[0].content.indexOf('../before.html') !== -1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should replace link to .md by link to page in format single page', function() {
|
||||||
|
var LEXED = loadPage('MARKDOWN_LINKS', {
|
||||||
|
// GitHub repo ID
|
||||||
|
repo: 'GitBookIO/javascript',
|
||||||
|
|
||||||
|
// Imaginary folder of markdown file
|
||||||
|
dir: 'course',
|
||||||
|
outdir: './',
|
||||||
|
singleFile: true
|
||||||
|
});
|
||||||
|
|
||||||
|
assert(LEXED[0].content.indexOf('#course/test.md') !== -1);
|
||||||
|
assert(LEXED[0].content.indexOf('#before.md') !== -1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
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'
|
||||||
|
});
|
||||||
|
|
||||||
|
assert(LEXED[0].content.indexOf('"preview.png"') !== -1);
|
||||||
|
assert(LEXED[0].content.indexOf('"../preview2.png"') !== -1);
|
||||||
|
});
|
||||||
|
|
||||||
|
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: './'
|
||||||
|
});
|
||||||
|
|
||||||
|
assert(LEXED[0].content.indexOf('"syntax/preview.png"') !== -1);
|
||||||
|
assert(LEXED[0].content.indexOf('"preview2.png"') !== -1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
var _ = require('lodash');
|
||||||
|
var path = require('path');
|
||||||
|
var assert = require('assert');
|
||||||
|
|
||||||
|
var Plugin = require('../').generate.Plugin;
|
||||||
|
|
||||||
|
describe('Plugin validation', function () {
|
||||||
|
var plugin = new Plugin("plugin", __dirname);
|
||||||
|
|
||||||
|
it('should be valid', function() {
|
||||||
|
assert(plugin.isValid());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Plugin list of names', function () {
|
||||||
|
var firstDefault = _.first(Plugin.defaults);
|
||||||
|
|
||||||
|
it('should convert string to array', function() {
|
||||||
|
var _name = "test";
|
||||||
|
assert(_.contains(Plugin.normalizeNames(_name), _name));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should contains default plugins', function() {
|
||||||
|
assert(_.contains(Plugin.normalizeNames([]), firstDefault));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove name starting with -', function() {
|
||||||
|
assert(!_.contains(Plugin.normalizeNames(["-"+firstDefault]), firstDefault));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Plugin defaults loading', function () {
|
||||||
|
var ret = true;
|
||||||
|
|
||||||
|
beforeEach(function(done){
|
||||||
|
Plugin.fromList(Plugin.defaults, __dirname)
|
||||||
|
.then(function(_r) {
|
||||||
|
ret = _r;
|
||||||
|
}, function(err) {
|
||||||
|
ret = null;
|
||||||
|
})
|
||||||
|
.fin(done);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should load defaults addons', function() {
|
||||||
|
assert(ret != null);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
# GitBook Theme
|
|
||||||
|
|
||||||
For creating a theme for GitBook, just copy this folder. The theme folder should at least contains two folders: `assets` and `templates`.
|
|
||||||
|
|
||||||
The theme can be changed using the option ```--theme=<path>```
|
|
||||||
+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,7 @@
|
|||||||
|
define([
|
||||||
|
"jQuery"
|
||||||
|
], function($) {
|
||||||
|
var events = $({});
|
||||||
|
|
||||||
|
return events;
|
||||||
|
});
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
define([
|
define([
|
||||||
"jQuery",
|
"jQuery",
|
||||||
"utils/execute",
|
"utils/execute",
|
||||||
"utils/analytic",
|
"core/events",
|
||||||
"core/state"
|
"core/state"
|
||||||
], function($, execute, analytic, state){
|
], function($, execute, events, state){
|
||||||
// Bind an exercise
|
// Bind an exercise
|
||||||
var prepareExercise = function($exercise) {
|
var prepareExercise = function($exercise) {
|
||||||
var codeSolution = $exercise.find(".code-solution").text();
|
var codeSolution = $exercise.find(".code-solution").text();
|
||||||
@@ -19,7 +19,7 @@ define([
|
|||||||
$exercise.find(".action-submit").click(function(e) {
|
$exercise.find(".action-submit").click(function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
analytic.track("exercise.submit", {type: "code"});
|
events.trigger("exercise.submit", {type: "code"});
|
||||||
|
|
||||||
execute("javascript", editor.getValue(), codeValidation, codeContext, function(err, result) {
|
execute("javascript", editor.getValue(), codeValidation, codeContext, function(err, result) {
|
||||||
$exercise.toggleClass("return-error", err != null);
|
$exercise.toggleClass("return-error", err != null);
|
||||||
|
|||||||
@@ -0,0 +1,115 @@
|
|||||||
|
define([
|
||||||
|
"jQuery",
|
||||||
|
"utils/storage"
|
||||||
|
], function($, storage) {
|
||||||
|
var fontState;
|
||||||
|
|
||||||
|
var togglePopover = function(e) {
|
||||||
|
var $dropdown = $("#font-settings-wrapper .dropdown-menu");
|
||||||
|
|
||||||
|
$dropdown.toggleClass("open");
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
var closePopover = function(e) {
|
||||||
|
var $dropdown = $("#font-settings-wrapper .dropdown-menu");
|
||||||
|
|
||||||
|
$dropdown.removeClass("open");
|
||||||
|
};
|
||||||
|
|
||||||
|
var enlargeFontSize = function(e){
|
||||||
|
var $bookBody = $(".book-body");
|
||||||
|
|
||||||
|
if (fontState.size < 4){
|
||||||
|
$bookBody.toggleClass("font-size-"+fontState.size, false);
|
||||||
|
fontState.size++;
|
||||||
|
|
||||||
|
$bookBody.toggleClass("font-size-"+fontState.size, true);
|
||||||
|
fontState.save();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var reduceFontSize = function(e){
|
||||||
|
var $bookBody = $(".book-body");
|
||||||
|
|
||||||
|
if (fontState.size > 0){
|
||||||
|
$bookBody.toggleClass("font-size-"+fontState.size);
|
||||||
|
fontState.size--;
|
||||||
|
|
||||||
|
$bookBody.toggleClass("font-size-"+fontState.size);
|
||||||
|
fontState.save();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var changeFontFamily = function(){
|
||||||
|
var $bookBody = $(".book-body");
|
||||||
|
var index = $(this).data("font");
|
||||||
|
|
||||||
|
$bookBody.toggleClass("font-family-"+fontState.family);
|
||||||
|
$(".font-settings .font-family-list li:nth-child("+(fontState.family+1)+")")
|
||||||
|
.removeClass("active");
|
||||||
|
|
||||||
|
fontState.family = index;
|
||||||
|
$bookBody.toggleClass("font-family-"+fontState.family);
|
||||||
|
$(this).addClass("active");
|
||||||
|
fontState.save();
|
||||||
|
};
|
||||||
|
|
||||||
|
var changeColorTheme = function(){
|
||||||
|
var $book = $(".book");
|
||||||
|
var index = $(this).data("theme");
|
||||||
|
|
||||||
|
if (fontState.theme !== 0)
|
||||||
|
$book.removeClass("color-theme-"+fontState.theme);
|
||||||
|
|
||||||
|
fontState.theme = index;
|
||||||
|
if (fontState.theme !== 0)
|
||||||
|
$book.addClass("color-theme-"+fontState.theme);
|
||||||
|
|
||||||
|
fontState.save();
|
||||||
|
};
|
||||||
|
|
||||||
|
var init = function() {
|
||||||
|
var $toggle, $bookBody, $dropdown, $book;
|
||||||
|
|
||||||
|
//Find DOM elements.
|
||||||
|
$book = $(".book");
|
||||||
|
$toggle = $(".book-header .toggle-font-settings");
|
||||||
|
$dropdown = $("#font-settings-wrapper .dropdown-menu");
|
||||||
|
$bookBody = $(".book-body");
|
||||||
|
|
||||||
|
//Instantiate font state object
|
||||||
|
fontState = storage.get("fontState", {
|
||||||
|
size:1,
|
||||||
|
family:0,
|
||||||
|
theme:0
|
||||||
|
});
|
||||||
|
fontState.save = function(){
|
||||||
|
storage.set("fontState",fontState);
|
||||||
|
};
|
||||||
|
|
||||||
|
$bookBody.addClass("font-size-"+fontState.size);
|
||||||
|
$bookBody.addClass("font-family-"+fontState.family);
|
||||||
|
|
||||||
|
$(".font-settings .font-family-list li:nth-child("+(fontState.family+1)+")").addClass("active");
|
||||||
|
|
||||||
|
if(fontState.theme !== 0)
|
||||||
|
$book.addClass("color-theme-"+fontState.theme);
|
||||||
|
|
||||||
|
//Add event listeners
|
||||||
|
$(document).on('click', "#enlarge-font-size", enlargeFontSize);
|
||||||
|
$(document).on('click', "#reduce-font-size", reduceFontSize);
|
||||||
|
|
||||||
|
$(document).on('click', "#font-settings-wrapper .font-family-list li", changeFontFamily);
|
||||||
|
$(document).on('click', "#font-settings-wrapper .color-theme-list button", changeColorTheme);
|
||||||
|
|
||||||
|
$(document).on('click', ".book-header .toggle-font-settings", togglePopover);
|
||||||
|
$(document).on('click', "#font-settings-wrapper .dropdown-menu", function(e){ e.stopPropagation(); });
|
||||||
|
$(document).on("click", closePopover);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
init: init
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -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,28 +1,35 @@
|
|||||||
define([
|
define([
|
||||||
"jQuery",
|
"jQuery",
|
||||||
"utils/analytic",
|
"utils/path",
|
||||||
|
"core/events",
|
||||||
"core/state",
|
"core/state",
|
||||||
"core/search",
|
"core/search",
|
||||||
"core/progress",
|
"core/progress",
|
||||||
"core/exercise",
|
"core/exercise",
|
||||||
"core/quiz"
|
"core/quiz",
|
||||||
], function($, analytic, 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 updateHistory = function(url, title) {
|
var usePushState = (typeof history.pushState !== "undefined");
|
||||||
history.pushState({ path: url }, title, url);
|
|
||||||
};
|
|
||||||
|
|
||||||
var handleNavigation = function(url, push) {
|
var handleNavigation = function(relativeUrl, push) {
|
||||||
if (typeof history.pushState === "undefined") {
|
var url = path.isAbsolute(relativeUrl) ? relativeUrl : path.join(path.dirname(window.location.pathname), relativeUrl);
|
||||||
|
console.log("navigate to ", url, "baseurl="+relativeUrl);
|
||||||
|
|
||||||
|
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) {
|
||||||
|
// 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 + '>';
|
||||||
});
|
});
|
||||||
@@ -49,13 +56,11 @@ define([
|
|||||||
|
|
||||||
// Update state
|
// Update state
|
||||||
state.update($("html"));
|
state.update($("html"));
|
||||||
|
|
||||||
if (push) updateHistory(url, null);
|
|
||||||
preparePage();
|
preparePage();
|
||||||
})
|
})
|
||||||
.fail(function () {
|
.fail(function (e) {
|
||||||
location.href = url;
|
location.href = relativeUrl;
|
||||||
});
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
var updateGitHubCounts = function() {
|
var updateGitHubCounts = function() {
|
||||||
@@ -108,7 +113,7 @@ define([
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send to mixpanel
|
// Send to mixpanel
|
||||||
analytic.track("page.view");
|
events.trigger("page.change");
|
||||||
};
|
};
|
||||||
|
|
||||||
var handlePagination = function (e) {
|
var handlePagination = function (e) {
|
||||||
@@ -146,7 +151,6 @@ define([
|
|||||||
if (event.state === null) {
|
if (event.state === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return handleNavigation(event.state.path, false);
|
return handleNavigation(event.state.path, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
define([
|
define([
|
||||||
"jQuery",
|
"jQuery",
|
||||||
"utils/execute",
|
"utils/execute",
|
||||||
"utils/analytic",
|
"core/events",
|
||||||
"core/state"
|
"core/state"
|
||||||
], function($, execute, analytic, state){
|
], function($, execute, events, state){
|
||||||
// Bind an exercise
|
// Bind an exercise
|
||||||
var prepareQuiz = function($quiz) {
|
var prepareQuiz = function($quiz) {
|
||||||
|
|
||||||
@@ -14,14 +14,17 @@ define([
|
|||||||
// Submit: test code
|
// Submit: test code
|
||||||
$quiz.find(".action-submit").click(function(e) {
|
$quiz.find(".action-submit").click(function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
analytic.track("exercise.submit", {type: "quiz"});
|
events.trigger("exercise.submit", {type: "quiz"});
|
||||||
$quiz.find("tr.alert-danger,li.alert-danger").removeClass("alert-danger");
|
$quiz.find("tr.alert-danger,li.alert-danger").removeClass("alert-danger");
|
||||||
$quiz.find(".alert-success,.alert-danger").addClass("hidden");
|
$quiz.find(".alert-success,.alert-danger").addClass("hidden");
|
||||||
|
|
||||||
$quiz.find(".question").each(function(q) {
|
$quiz.find(".question").each(function(q) {
|
||||||
var result = true;
|
var result = true;
|
||||||
var $answers = $quiz.find(".question-answers").slice(q).find("input[type=radio], input[type=checkbox]");
|
|
||||||
$(this).find("input[type=radio],input[type=checkbox]").each(function(i) {
|
var $questions = $(this).find(".question-content").find("input[type=radio], input[type=checkbox]");
|
||||||
|
var $answers = $(this).find(".question-answers").find("input[type=radio], input[type=checkbox]");
|
||||||
|
|
||||||
|
$questions.each(function(i) {
|
||||||
var correct = $(this).is(":checked") === $answers.slice(i).first().is(":checked");
|
var correct = $(this).is(":checked") === $answers.slice(i).first().is(":checked");
|
||||||
result = result && correct;
|
result = result && correct;
|
||||||
if (!correct) {
|
if (!correct) {
|
||||||
|
|||||||
@@ -1,17 +1,19 @@
|
|||||||
require([
|
define([
|
||||||
"jQuery",
|
"jQuery",
|
||||||
"utils/storage",
|
"utils/storage",
|
||||||
"utils/analytic",
|
|
||||||
"utils/sharing",
|
"utils/sharing",
|
||||||
|
"utils/appcache",
|
||||||
|
|
||||||
|
"core/events",
|
||||||
|
"core/font-settings",
|
||||||
"core/state",
|
"core/state",
|
||||||
"core/keyboard",
|
"core/keyboard",
|
||||||
"core/navigation",
|
"core/navigation",
|
||||||
"core/progress",
|
"core/progress",
|
||||||
"core/sidebar",
|
"core/sidebar",
|
||||||
"core/search"
|
"core/search"
|
||||||
], function($, storage, analytic, sharing, state, keyboard, navigation, progress, sidebar, search){
|
], function($, storage, appCache, sharing, events, fontSettings, state, keyboard, navigation, progress, sidebar, search){
|
||||||
$(document).ready(function() {
|
var start = function(config) {
|
||||||
var $book;
|
var $book;
|
||||||
$book = state.$book;
|
$book = state.$book;
|
||||||
|
|
||||||
@@ -29,10 +31,23 @@ require([
|
|||||||
// Init keyboard
|
// Init keyboard
|
||||||
keyboard.init();
|
keyboard.init();
|
||||||
|
|
||||||
|
// Init appcache
|
||||||
|
appCache.init();
|
||||||
|
|
||||||
// Bind sharing button
|
// Bind sharing button
|
||||||
sharing.init();
|
sharing.init();
|
||||||
|
|
||||||
// Init navigation
|
// Init navigation
|
||||||
navigation.init();
|
navigation.init();
|
||||||
});
|
|
||||||
|
//Init font settings
|
||||||
|
fontSettings.init();
|
||||||
|
|
||||||
|
events.trigger("start", config);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
start: start,
|
||||||
|
events: events
|
||||||
|
};
|
||||||
});
|
});
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
define([
|
|
||||||
"lodash",
|
|
||||||
"mixpanel"
|
|
||||||
], function(_, mixpanel) {
|
|
||||||
mixpanel.init("01eb2b950ae09a5fdb15a98dcc5ff20e", {
|
|
||||||
loaded: function() {
|
|
||||||
track("page.start");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var isAvailable = function() {
|
|
||||||
return (
|
|
||||||
typeof mixpanel !== "undefined" &&
|
|
||||||
typeof mixpanel.track === "function"
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
var track = function(e, data) {
|
|
||||||
if (!isAvailable()) {
|
|
||||||
console.warn("tracking not available!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.log("track", e);
|
|
||||||
mixpanel.track(e, _.extend(data || {}, {
|
|
||||||
'domain': window.location.host
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
isAvailable: isAvailable,
|
|
||||||
track: track
|
|
||||||
};
|
|
||||||
});
|
|
||||||
@@ -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
|
||||||
|
};
|
||||||
|
})
|
||||||
Vendored
-2
@@ -1,2 +0,0 @@
|
|||||||
(function(e,b){if(!b.__SV){var a,f,i,g;window.mixpanel=b;b._i=[];b.init=function(a,e,d){function f(b,h){var a=h.split(".");2==a.length&&(b=b[a[0]],h=a[1]);b[h]=function(){b.push([h].concat(Array.prototype.slice.call(arguments,0)))}}var c=b;"undefined"!==typeof d?c=b[d]=[]:d="mixpanel";c.people=c.people||[];c.toString=function(b){var a="mixpanel";"mixpanel"!==d&&(a+="."+d);b||(a+=" (stub)");return a};c.people.toString=function(){return c.toString(1)+".people (stub)"};i="disable track track_pageview track_links track_forms register register_once alias unregister identify name_tag set_config people.set people.set_once people.increment people.append people.track_charge people.clear_charges people.delete_user".split(" ");
|
|
||||||
for(g=0;g<i.length;g++)f(c,i[g]);b._i.push([a,e,d])};b.__SV=1.2;a=e.createElement("script");a.type="text/javascript";a.async=!0;a.src=("https:"===e.location.protocol?"https:":"http:")+'//cdn.mxpnl.com/libs/mixpanel-2.2.min.js';f=e.getElementsByTagName("script")[0];f.parentNode.insertBefore(a,f)}})(document,window.mixpanel||[]);
|
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
left: 0px;
|
left: 0px;
|
||||||
bottom: 0px;
|
bottom: 0px;
|
||||||
|
|
||||||
|
color: @page-color;
|
||||||
background: @body-background;
|
background: @body-background;
|
||||||
.transition(left 0.5s ease);
|
.transition(left 0.5s ease);
|
||||||
|
|
||||||
@@ -23,7 +24,6 @@
|
|||||||
outline: none;
|
outline: none;
|
||||||
|
|
||||||
.page-inner {
|
.page-inner {
|
||||||
font-family: @font-family-serif;
|
|
||||||
max-width: 800px;
|
max-width: 800px;
|
||||||
margin: 0px auto;
|
margin: 0px auto;
|
||||||
|
|
||||||
@@ -33,8 +33,6 @@
|
|||||||
|
|
||||||
background: @page-background;
|
background: @page-background;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 1.5em;
|
line-height: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,6 +55,28 @@
|
|||||||
min-height: calc(~"100% - 57px")
|
min-height: calc(~"100% - 57px")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&.font-size-0{
|
||||||
|
font-size:@s-font-size;
|
||||||
|
}
|
||||||
|
&.font-size-1{
|
||||||
|
font-size:@m-font-size;
|
||||||
|
}
|
||||||
|
&.font-size-2{
|
||||||
|
font-size:@l-font-size;
|
||||||
|
}
|
||||||
|
&.font-size-3{
|
||||||
|
font-size:@xl-font-size;
|
||||||
|
}
|
||||||
|
&.font-size-4{
|
||||||
|
font-size:@xxl-font-size;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.font-family-0{
|
||||||
|
font-family: @font-family-serif;
|
||||||
|
}
|
||||||
|
&.font-family-1{
|
||||||
|
font-family: @font-family-sans;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.with-summary {
|
&.with-summary {
|
||||||
@@ -72,4 +92,30 @@
|
|||||||
.transition(none) !important;
|
.transition(none) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&.color-theme-1{
|
||||||
|
.book-body {
|
||||||
|
color: @page-color-1;
|
||||||
|
background: @body-background-1;
|
||||||
|
.page-wrapper {
|
||||||
|
.page-inner {
|
||||||
|
section{
|
||||||
|
background: @page-background-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.color-theme-2{
|
||||||
|
.book-body {
|
||||||
|
color: @page-color-2;
|
||||||
|
background: @body-background-2;
|
||||||
|
.page-wrapper {
|
||||||
|
.page-inner {
|
||||||
|
section{
|
||||||
|
background: @page-background-2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
.book-header{
|
||||||
|
#font-settings-wrapper{
|
||||||
|
position:relative;
|
||||||
|
.dropdown-menu{
|
||||||
|
background-color:@header-background;
|
||||||
|
border-color:@sidebar-divider-color;
|
||||||
|
padding: 0px;
|
||||||
|
|
||||||
|
.dropdown-caret{
|
||||||
|
position: absolute;
|
||||||
|
top: 14px;
|
||||||
|
left: -8px;
|
||||||
|
width: 10px;
|
||||||
|
height: 18px;
|
||||||
|
float: left;
|
||||||
|
overflow: hidden;
|
||||||
|
.caret-outer{
|
||||||
|
position: absolute;
|
||||||
|
border-bottom: 9px solid transparent;
|
||||||
|
border-top: 9px solid transparent;
|
||||||
|
border-right: 9px solid rgba(0,0,0,0.1);
|
||||||
|
height: auto;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: auto;
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: -1px;
|
||||||
|
}
|
||||||
|
.caret-inner{
|
||||||
|
position: absolute;
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: -1px;
|
||||||
|
top: 0;
|
||||||
|
left: 1px;
|
||||||
|
border-bottom: 9px solid transparent;
|
||||||
|
border-top: 9px solid transparent;
|
||||||
|
border-right: 9px solid @header-background;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
button{
|
||||||
|
border: 0;
|
||||||
|
background-color:transparent;
|
||||||
|
color:@header-button-color;
|
||||||
|
&:hover{
|
||||||
|
color:@header-button-hover-color;
|
||||||
|
background-color:@header-button-hover-background;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#enlarge-font-size{
|
||||||
|
width: 50%;
|
||||||
|
font-size:1.4em;
|
||||||
|
}
|
||||||
|
#reduce-font-size{
|
||||||
|
width: 50.5%;
|
||||||
|
font-size:1em;
|
||||||
|
}
|
||||||
|
.btn-group-xs{
|
||||||
|
.btn{
|
||||||
|
width: 33.7%;
|
||||||
|
padding: initial;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.list-group{
|
||||||
|
margin: 0px 0;
|
||||||
|
|
||||||
|
.list-group-item{
|
||||||
|
cursor:pointer;
|
||||||
|
background-color:transparent;
|
||||||
|
border-color: @sidebar-divider-color;
|
||||||
|
border-width: 1px 0 !important;
|
||||||
|
|
||||||
|
&:hover{
|
||||||
|
color:@header-button-hover-color;
|
||||||
|
background-color:@header-button-hover-background !important;
|
||||||
|
}
|
||||||
|
&.active{
|
||||||
|
color:@header-button-hover-color;
|
||||||
|
background-color:@header-button-hover-background !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.open{
|
||||||
|
display:block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Theme 1
|
||||||
|
*/
|
||||||
|
|
||||||
|
.color-theme-1{
|
||||||
|
#font-settings-wrapper{
|
||||||
|
.dropdown-menu{
|
||||||
|
background-color:@sidebar-background-1;
|
||||||
|
border-color:@sidebar-divider-color-1;
|
||||||
|
.dropdown-caret .caret-inner{
|
||||||
|
border-right: 9px solid @sidebar-background-1;
|
||||||
|
}
|
||||||
|
button{
|
||||||
|
color:@header-button-color-1;
|
||||||
|
&:hover{
|
||||||
|
color:@header-button-hover-color-1;
|
||||||
|
background-color:@header-button-hover-background-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.list-group{
|
||||||
|
.list-group-item{
|
||||||
|
border-color:@sidebar-divider-color-1;
|
||||||
|
&:hover{
|
||||||
|
color:@header-button-hover-color-1;
|
||||||
|
background-color:@header-button-hover-background-1 !important;
|
||||||
|
}
|
||||||
|
&.active{
|
||||||
|
color:@header-button-hover-color-1;
|
||||||
|
background-color:@header-button-hover-background-1 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Theme 2
|
||||||
|
*/
|
||||||
|
|
||||||
|
.color-theme-2{
|
||||||
|
#font-settings-wrapper{
|
||||||
|
.dropdown-menu{
|
||||||
|
background-color:@sidebar-background-2;
|
||||||
|
border-color:@sidebar-divider-color-2;
|
||||||
|
.dropdown-caret .caret-inner{
|
||||||
|
border-right: 9px solid @sidebar-background-2;
|
||||||
|
}
|
||||||
|
button{
|
||||||
|
color:@header-button-color-2;
|
||||||
|
&:hover{
|
||||||
|
color:@header-button-hover-color-2;
|
||||||
|
background-color:@header-button-hover-background-2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.list-group{
|
||||||
|
.list-group-item{
|
||||||
|
border-color:@sidebar-divider-color-2;
|
||||||
|
&:hover{
|
||||||
|
color:@header-button-hover-color-2;
|
||||||
|
background-color:@header-button-hover-background-2 !important;
|
||||||
|
}
|
||||||
|
&.active{
|
||||||
|
color:@header-button-hover-color-2;
|
||||||
|
background-color:@header-button-hover-background-2 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
font-family: @font-family-sans;
|
font-family: @font-family-sans;
|
||||||
|
|
||||||
position: fixed;
|
position: fixed;
|
||||||
overflow: hidden;
|
overflow: visible;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
left: 0px;
|
left: 0px;
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
line-height: @header-height;
|
line-height: @header-height;
|
||||||
.box-shadow(none) !important;
|
.box-shadow(none) !important;
|
||||||
|
position:relative;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -51,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;
|
||||||
@@ -64,4 +79,30 @@
|
|||||||
.transition(none) !important;
|
.transition(none) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&.color-theme-1{
|
||||||
|
.book-header{
|
||||||
|
color: @header-color-1;
|
||||||
|
background: @header-background-1;
|
||||||
|
.btn {
|
||||||
|
color: @header-button-color-1;
|
||||||
|
&:hover {
|
||||||
|
color: @header-button-hover-color-1;
|
||||||
|
background: @header-button-hover-background-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.color-theme-2{
|
||||||
|
.book-header{
|
||||||
|
color: @header-color-2;
|
||||||
|
background: @header-background-2;
|
||||||
|
.btn {
|
||||||
|
color: @header-button-color-2;
|
||||||
|
&:hover {
|
||||||
|
color: @header-button-hover-color-2;
|
||||||
|
background: @header-button-hover-background-2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
+10
-10
@@ -1,8 +1,9 @@
|
|||||||
/* http://jmblog.github.com/color-themes-for-google-code-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,
|
||||||
@@ -1,8 +1,29 @@
|
|||||||
.book .book-body .page-wrapper .page-inner section.normal {
|
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal {
|
||||||
padding: 25px;
|
color:@page-color-1;
|
||||||
padding-top: 15px;
|
|
||||||
background-color: white;
|
|
||||||
|
|
||||||
|
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 {
|
||||||
|
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 {
|
||||||
|
padding: 25px 0px;
|
||||||
|
padding-top: 15px;
|
||||||
|
color:@page-color;
|
||||||
|
|
||||||
& > *:first-child {
|
& > *:first-child {
|
||||||
margin-top: 0 !important; }
|
margin-top: 0 !important; }
|
||||||
@@ -52,12 +73,12 @@
|
|||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
color: black; }
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
border-bottom: 1px solid #eee;
|
border-bottom: 1px solid #eee;
|
||||||
color: black; }
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
font-size: 18px; }
|
font-size: 18px; }
|
||||||
@@ -69,7 +90,6 @@
|
|||||||
font-size: 14px; }
|
font-size: 14px; }
|
||||||
|
|
||||||
h6 {
|
h6 {
|
||||||
color: #777777;
|
|
||||||
font-size: 14px; }
|
font-size: 14px; }
|
||||||
|
|
||||||
p, blockquote, ul, ol, dl, table, pre {
|
p, blockquote, ul, ol, dl, table, pre {
|
||||||
@@ -272,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,4 +42,14 @@
|
|||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
.book.color-theme-1 .book-body {
|
||||||
|
.navigation:hover{
|
||||||
|
background-color: @body-pagination-background-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.book.color-theme-2 .book-body {
|
||||||
|
.navigation:hover{
|
||||||
|
background-color: @body-pagination-background-2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,6 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
z-index: 10;
|
|
||||||
|
|
||||||
.bar {
|
.bar {
|
||||||
height: @bar-height;
|
height: @bar-height;
|
||||||
@@ -81,4 +80,36 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
.book.color-theme-1 .book-body {
|
||||||
|
.book-progress {
|
||||||
|
.bar {
|
||||||
|
background: @bar-background-1;
|
||||||
|
.inner {
|
||||||
|
background: @bar-progress-background-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.chapters .chapter{
|
||||||
|
background: @bar-background-1;
|
||||||
|
&.done{
|
||||||
|
background: @bar-progress-background-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.book.color-theme-2 .book-body {
|
||||||
|
.book-progress {
|
||||||
|
.bar {
|
||||||
|
background: @bar-background-2;
|
||||||
|
.inner {
|
||||||
|
background: @bar-progress-background-2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.chapters .chapter{
|
||||||
|
background: @bar-background-2;
|
||||||
|
&.done{
|
||||||
|
background: @bar-progress-background-2;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,3 +141,93 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Theme 1
|
||||||
|
*/
|
||||||
|
.book.color-theme-1 {
|
||||||
|
.book-summary {
|
||||||
|
color: @sidebar-color-1;
|
||||||
|
background: @sidebar-background-1;
|
||||||
|
|
||||||
|
.book-search {
|
||||||
|
background: @sidebar-search-background-1;
|
||||||
|
|
||||||
|
input, input:focus {
|
||||||
|
border: 1px solid @sidebar-search-input-border-color-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.summary {
|
||||||
|
li {
|
||||||
|
&.divider {
|
||||||
|
background: @sidebar-divider-color-1;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
i.fa-check {
|
||||||
|
color: @sidebar-icon-color-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.done > a {
|
||||||
|
color: @sidebar-link-completed-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
a, span {
|
||||||
|
color: @sidebar-link-color-1;
|
||||||
|
background: @sidebar-link-background-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active > a, a:hover {
|
||||||
|
color: @sidebar-link-hover-color-1;
|
||||||
|
background: @sidebar-link-hover-background-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Theme 2
|
||||||
|
*/
|
||||||
|
.book.color-theme-2{
|
||||||
|
.book-summary {
|
||||||
|
color: @sidebar-color-2;
|
||||||
|
background: @sidebar-background-2;
|
||||||
|
|
||||||
|
.book-search {
|
||||||
|
background: @sidebar-search-background-2;
|
||||||
|
|
||||||
|
input, input:focus {
|
||||||
|
border: 1px solid @sidebar-search-input-border-color-2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.summary {
|
||||||
|
li {
|
||||||
|
&.divider {
|
||||||
|
background: @sidebar-divider-color-2;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
i.fa-check {
|
||||||
|
color: @sidebar-icon-color-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.done > a {
|
||||||
|
color: @sidebar-link-completed-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
a, span {
|
||||||
|
color: @sidebar-link-color-2;
|
||||||
|
background: @sidebar-link-background-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active > a, a:hover {
|
||||||
|
color: @sidebar-link-hover-color-2;
|
||||||
|
background: @sidebar-link-hover-background-2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,10 +5,10 @@
|
|||||||
@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";
|
||||||
|
@import "book/font-settings.less";
|
||||||
@import "book/body.less";
|
@import "book/body.less";
|
||||||
@import "book/exercise.less";
|
@import "book/exercise.less";
|
||||||
@import "book/quiz.less";
|
@import "book/quiz.less";
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */
|
/* http://jmblog.github.io/color-themes-for-highlightjs */
|
||||||
|
|
||||||
/* Tomorrow Comment */
|
/* Tomorrow Comment */
|
||||||
.hljs-comment,
|
.hljs-comment,
|
||||||
@@ -87,4 +87,4 @@
|
|||||||
.xml .css,
|
.xml .css,
|
||||||
.xml .hljs-cdata {
|
.xml .hljs-cdata {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
@sidebar-link-completed-weight: normal;
|
@sidebar-link-completed-weight: normal;
|
||||||
|
|
||||||
// Page
|
// Page
|
||||||
|
@page-color: black;
|
||||||
@page-background: white;
|
@page-background: white;
|
||||||
|
|
||||||
// Progress Bar
|
// Progress Bar
|
||||||
@@ -79,5 +80,94 @@
|
|||||||
@font-family-sans: "Open Sans", "Clear Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
@font-family-sans: "Open Sans", "Clear Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
@font-family-base: @font-family-serif;
|
@font-family-base: @font-family-serif;
|
||||||
|
|
||||||
|
|
||||||
@FontPath: '@{staticPath}/fonts';
|
@FontPath: '@{staticPath}/fonts';
|
||||||
@fa-font-path: "@{FontPath}/fontawesome";
|
@fa-font-path: "@{FontPath}/fontawesome";
|
||||||
|
|
||||||
|
@s-font-size: 1.2rem;
|
||||||
|
@m-font-size: 1.4rem;
|
||||||
|
@l-font-size: 1.6rem;
|
||||||
|
@xl-font-size: 2.2rem;
|
||||||
|
@xxl-font-size: 4.0rem;
|
||||||
|
|
||||||
|
/*
|
||||||
|
,--------.,--.
|
||||||
|
'--. .--'| ,---. ,---. ,--,--,--. ,---. ,---. .--.
|
||||||
|
| | | .-. || .-. :| || .-. :( .-' '--'
|
||||||
|
| | | | | |\ --.| | | |\ --..-' `).--.
|
||||||
|
`--' `--' `--' `----'`--`--`--' `----'`----' '--'
|
||||||
|
*/
|
||||||
|
// Header
|
||||||
|
@header-color-1: #AFA790;
|
||||||
|
@header-color-2: #7e888b;
|
||||||
|
@header-background-1: #ECE3C4;
|
||||||
|
@header-background-2: #1d1f21;
|
||||||
|
@header-button-color-1: #AFA790;
|
||||||
|
@header-button-color-2: #7e888b;
|
||||||
|
@header-button-hover-color-1: #73553C;
|
||||||
|
@header-button-hover-color-2: #C9C9C9;
|
||||||
|
@header-button-hover-background-1: #E2DABE;
|
||||||
|
@header-button-hover-background-2: #0B0D0E;
|
||||||
|
|
||||||
|
// Body
|
||||||
|
@body-background-1: #F3EACB;
|
||||||
|
@body-background-2: #1d1f21;
|
||||||
|
@body-pagination-background-1: #FFFAEA;
|
||||||
|
@body-pagination-background-2: #33404D;
|
||||||
|
|
||||||
|
// Sidebar
|
||||||
|
@sidebar-color-1: #AFA790;
|
||||||
|
@sidebar-color-2: hsl(207, 15%, 80%);
|
||||||
|
@sidebar-background-1: #F3EACB;
|
||||||
|
@sidebar-background-2: #111111;
|
||||||
|
|
||||||
|
@sidebar-search-background-1: transparent;
|
||||||
|
@sidebar-search-background-2: transparent;
|
||||||
|
@sidebar-search-input-border-color-1: #D6CFBA;
|
||||||
|
@sidebar-search-input-border-color-2: #c4cdd4;
|
||||||
|
|
||||||
|
@sidebar-divider-color-1: hsl(207, 15%, 85%);
|
||||||
|
@sidebar-divider-color-2: #1d1f21;
|
||||||
|
|
||||||
|
@sidebar-link-color-1: #877F6A;
|
||||||
|
@sidebar-link-color-2: hsl(207, 15%, 50%);
|
||||||
|
@sidebar-link-background-1: transparent;
|
||||||
|
@sidebar-link-background-2: transparent;
|
||||||
|
@sidebar-link-hover-color-1: #704214;
|
||||||
|
@sidebar-link-hover-color-2: hsl(207, 100%, 50%);
|
||||||
|
@sidebar-link-hover-background-1: transparent;
|
||||||
|
@sidebar-link-hover-background-2: transparent;
|
||||||
|
|
||||||
|
@sidebar-icon-color-1: @bar-progress-background;
|
||||||
|
@sidebar-icon-color-2: @bar-progress-background;
|
||||||
|
@sidebar-link-completed-1: hsl(207, 15%, 25%);
|
||||||
|
@sidebar-link-completed-2: hsl(207, 15%, 25%);
|
||||||
|
@sidebar-link-completed-weight-1: normal;
|
||||||
|
@sidebar-link-completed-weight-2: normal;
|
||||||
|
|
||||||
|
// Page
|
||||||
|
@page-color-1: #704214;
|
||||||
|
@page-color-2: #a4b1b1;
|
||||||
|
@page-background-1: #F3EACB;
|
||||||
|
@page-background-2: #1d1f21;
|
||||||
|
|
||||||
|
@bar-background-1: #F3EACB;
|
||||||
|
@bar-background-2: #1d1f21;
|
||||||
|
@bar-progress-background-1: #704214;
|
||||||
|
@bar-progress-background-2: hsl(120, 60%, 50%);
|
||||||
|
|
||||||
|
// Basics of a navbar
|
||||||
|
@navbar-default-border-1: #d5d5d5;
|
||||||
|
@navbar-default-border-2: #d5d5d5;
|
||||||
|
|
||||||
|
// Navbar brand label
|
||||||
|
@navbar-default-color-1: #333;
|
||||||
|
@navbar-default-color-2: #333;
|
||||||
|
@navbar-default-link-color-1: #333;
|
||||||
|
@navbar-default-link-color-2: #333;
|
||||||
|
@navbar-default-brand-color-1: @navbar-default-link-color;
|
||||||
|
@navbar-default-brand-color-2: @navbar-default-link-color;
|
||||||
|
@navbar-default-brand-hover-color-1: @navbar-default-link-color;
|
||||||
|
@navbar-default-brand-hover-color-2: @navbar-default-link-color;
|
||||||
|
@navbar-default-brand-hover-bg-1: transparent;
|
||||||
|
@navbar-default-brand-hover-bg-2: transparent;
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<div class="dropdown-menu font-settings">
|
||||||
|
<div class="dropdown-caret">
|
||||||
|
<span class="caret-outer"></span>
|
||||||
|
<span class="caret-inner"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="btn-group btn-block">
|
||||||
|
<button id="reduce-font-size" class="btn btn-default">A</button>
|
||||||
|
<button id="enlarge-font-size" class="btn btn-default">A</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="list-group font-family-list">
|
||||||
|
<li class="list-group-item" data-font="0">Serif</li>
|
||||||
|
<li class="list-group-item" data-font="1">Sans</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="btn-group btn-group-xs btn-block color-theme-list">
|
||||||
|
<button type="button" class="btn btn-default" id="color-theme-preview-0" data-theme="0">White</button>
|
||||||
|
<button type="button" class="btn btn-default" id="color-theme-preview-1" data-theme="1">Sepia</button>
|
||||||
|
<button type="button" class="btn btn-default" id="color-theme-preview-2" data-theme="2">Night</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -5,6 +5,11 @@
|
|||||||
{% 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>
|
||||||
|
<span id="font-settings-wrapper">
|
||||||
|
<a href="#" class="btn pull-left toggle-font-settings"><i class="fa fa-font"></i>
|
||||||
|
</a>
|
||||||
|
{% include "./font-settings.html" %}
|
||||||
|
</span>
|
||||||
|
|
||||||
<!-- Actions Right -->
|
<!-- Actions Right -->
|
||||||
<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>
|
||||||
@@ -17,5 +22,8 @@
|
|||||||
{% 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>
|
||||||
|
|||||||
@@ -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">
|
||||||
@@ -35,10 +35,10 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{% block content %}{% endblock %}
|
|
||||||
{% block style %}
|
{% block style %}
|
||||||
<link rel="stylesheet" href="{{ staticBase }}/style.css">
|
<link rel="stylesheet" href="{{ staticBase }}/style.css">
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
{% block content %}{% endblock %}
|
||||||
{% block javascript %}
|
{% block javascript %}
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.1.3/ace.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.1.3/ace.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.1.3/mode-javascript.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.1.3/mode-javascript.js"></script>
|
||||||
|
|||||||
@@ -77,9 +77,11 @@
|
|||||||
<h1>{{ item.title }}</h1>
|
<h1>{{ item.title }}</h1>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
|
{% if pages[item.path] %}
|
||||||
<article>
|
<article>
|
||||||
{{ articleContent(pages[item.path].content) }}
|
{{ articleContent(pages[item.path].content) }}
|
||||||
</article>
|
</article>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if item.articles.length > 0 %}
|
{% if item.articles.length > 0 %}
|
||||||
{% for article in item.articles %}
|
{% for article in item.articles %}
|
||||||
|
|||||||
@@ -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 }}">
|
||||||
@@ -35,3 +36,31 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block javascript %}
|
||||||
|
{% parent %}
|
||||||
|
{% for resource in plugins.resources.js %}
|
||||||
|
{% if resource.url %}
|
||||||
|
<script src="{{ resource.url }}"></script>
|
||||||
|
{% else %}
|
||||||
|
<script src="{{ staticBase }}/plugins/{{ resource.path }}"></script>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
<script>
|
||||||
|
require(["gitbook"], function(gitbook) {
|
||||||
|
var config = {% autoescape false %}{{ pluginsConfig }}{% endautoescape %};
|
||||||
|
gitbook.start(config);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block style %}
|
||||||
|
{% parent %}
|
||||||
|
{% 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 %}
|
||||||
|
|||||||
Reference in New Issue
Block a user