Compare commits

...

76 Commits

Author SHA1 Message Date
Aaron O'Mullan 4481b5f556 Bump version to 0.3.2 2014-04-27 13:46:20 -07:00
Samy Pessé 0e0d051f7c Merge pull request #173 from erixtekila/master
Update README.md
2014-04-27 22:26:56 +02:00
Eric Priou a1b649a279 Update README.md 2014-04-27 22:24:37 +02:00
Eric Priou e6bc0a0fb7 Update README.md
3rd party plugins done in the weekend
2014-04-27 22:18:09 +02:00
Samy Pessé 93e4016c09 Add link to disqus plugin 2014-04-27 21:55:50 +02:00
Samy Pessé 20c741a248 Fix stupid typo thanks to @erixtekila 2014-04-27 21:21:48 +02:00
Samy Pessé 54f530c7c3 Merge pull request #171 from GitbookIO/feature/offlineCache
Improve pages loading
2014-04-27 18:05:13 +02:00
Samy Pessé 9fdc5da22d Update page when new version of application cache 2014-04-27 17:57:34 +02:00
Samy Pessé 99ce48b146 Add base loading indicator for navigation
#161
2014-04-27 17:36:12 +02:00
Samy Pessé 6a33ad9ef7 Add base cache manifest 2014-04-27 17:14:57 +02:00
Samy Pessé ca94055adf Adapt tests for plugins 2014-04-27 15:45:16 +02:00
Samy Pessé 36a67e4c91 Fix #169: fix resolve of external plugins 2014-04-27 15:41:02 +02:00
Samy Pessé 69431e1bbb Fix #165: replace separator from ":" to "," 2014-04-27 09:14:39 +02:00
Samy Pessé a3fc4ee2b0 Fix display of code element in sepia/night 2014-04-25 18:14:41 +02:00
Samy Pessé e505fd6d54 Improve summary divider for theme sepia and night 2014-04-25 18:12:39 +02:00
Samy Pessé 93a3785e4c Improve highlight theme for sepia and night themes 2014-04-25 18:05:09 +02:00
Samy Pessé a02de84812 Change highlight theme to tomorrow 2014-04-25 17:56:48 +02:00
Samy Pessé c0521f0ec7 Improve display of pre in markdown content 2014-04-25 17:48:31 +02:00
Samy Pessé 83d8c16853 Add file watcher in "gitbook serve" command (Fix #47, #89, #140) 2014-04-25 16:23:13 +02:00
Samy Pessé 47e9506397 Fix #153 and Improve pushState navigation 2014-04-25 15:12:19 +02:00
Samy Pessé b8a3d0e254 Merge pull request #144 from attomos/master
Make quiz easier to click by surround it with label.
2014-04-25 14:29:04 +02:00
Samy Pessé 001d7ec44e Merge pull request #155 from pborreli/patch-1
Fixed typo
2014-04-24 22:44:36 +02:00
Pascal Borreli 5cb0ec447a Fixed typo 2014-04-24 21:43:32 +01:00
Aaron O'Mullan 67e7d77302 Bump version to 0.3.1 2014-04-24 10:45:55 -07:00
Aaron O'Mullan 8cbd8b2b48 Reorder plugin names
Improves #149 and improves GitBookIO/editor#12
2014-04-24 01:38:42 -07:00
Aaron O'Mullan 7c404dbf96 Fix plugin tests 2014-04-24 01:34:35 -07:00
Aaron O'Mullan c4a67b6f2f Require plugin names to contain gitbook-*
Fixes #149, fixes GitBookIO/editor#12
2014-04-24 01:28:04 -07:00
Samy Pessé 3b70347625 Fix #146: complete license 2014-04-24 09:00:15 +02:00
Aaron O'Mullan bb0a7935e9 Merge pull request #141 from frodsan/niceties
Niceties
2014-04-23 11:34:08 -07:00
Nattaphoom Ch 8f4b799d3c Make quiz easier to click by surround it with label. 2014-04-24 01:19:13 +07:00
Francesco Rodriguez 931e0c66c9 Update color themes for highlight.js link. 2014-04-23 12:30:05 -03:00
Francesco Rodriguez 0212084862 Fix typo. 2014-04-23 12:28:44 -03:00
Samy Pessé 9abbabbce3 Merge pull request #138 from Hermanya/patch-1
Add @Hermanya as a contributor
2014-04-22 23:47:13 +02:00
Hermanya ac610487e8 Add @Hermanya as a contributor 2014-04-22 17:45:41 -04:00
Aaron O'Mullan a9a0f89892 Bump version to 0.3.0 2014-04-22 14:05:52 -07:00
Samy Pessé 305f221077 Fix #136: replace links to .md by links to .html
Add more tests for links in page
2014-04-22 17:45:12 +02:00
Samy Pessé 53514f2602 Improve sepia theme sidebar 2014-04-22 14:27:48 +02:00
Samy Pessé 00327778cb Improve font-settings dropdown design 2014-04-22 14:12:53 +02:00
Samy Pessé 37fadec787 Merge branch 'master' of https://github.com/Hermanya/gitbook into Hermanya-master 2014-04-22 14:02:19 +02:00
Samy Pessé ada11d0b59 Add section in readme about plugins 2014-04-22 12:51:10 +02:00
Aaron O'Mullan 4c90fdb7b2 Merge pull request #123 from GitbookIO/feature/plugins
Fix #65: Plugins Architecture
2014-04-21 14:26:09 -07:00
Samy Pessé 98c133df3c Change plugins separator to "," 2014-04-21 23:23:53 +02:00
Samy Pessé f86c27b090 Add option --pluginsConfig 2014-04-21 22:58:51 +02:00
Samy Pessé b5b8ed72a5 Update default addons 2014-04-21 22:39:23 +02:00
Samy Pessé 5beff86548 Change js interface for plugins and add configuration 2014-04-21 22:20:41 +02:00
Samy Pessé dd395edae1 Use mathjax plugin version 0.0.2 2014-04-21 16:30:02 +02:00
Aaron O'Mullan d1c1d7b75b Bump version to 0.2.4 2014-04-20 16:41:09 -07:00
Samy Pessé 4a380e9279 Fix #36: add mathjax plugin as default 2014-04-20 15:20:21 +02:00
Samy Pessé 878c105def Use complete assets folder for plugins 2014-04-20 02:04:15 +02:00
Samy Pessé 74d628676b Add option to change templates from plugin 2014-04-20 00:10:46 +02:00
Samy Pessé 6fdd98ec3a Trigger event on document when ready 2014-04-19 20:39:58 +02:00
Samy Pessé 2ed1be3533 Add global js interface for plugins and remove mixpanel 2014-04-19 20:10:03 +02:00
Samy Pessé 0ac04e1584 Add call for hooks "init" and "finish" 2014-04-19 19:50:32 +02:00
Herman Starikov 2a38d33d8a Font settings, closes #102 2014-04-19 13:46:14 -04:00
Samy Pessé fb14caf5b3 Add resources to site build 2014-04-19 19:31:02 +02:00
Samy Pessé cf51772f54 Add command line option "plugins" 2014-04-19 18:00:24 +02:00
Samy Pessé cc8516df83 Load plugins during generation 2014-04-19 17:57:40 +02:00
Samy Pessé c6a624bc6b Add method to load a list of plugins from generator options 2014-04-19 17:54:15 +02:00
Samy Pessé 8be8b825ee Add base loading of default addons
Add mixpanel as default addon
2014-04-19 17:28:44 +02:00
Samy Pessé 56eb4a2897 Add base plugin object and test validation of plugin 2014-04-19 15:41:29 +02:00
Samy Pessé 7a461eaa61 Remove theme readme
Add semver dependency
2014-04-19 14:40:46 +02:00
Samy Pessé fd64c05809 Fix #118: fix single page generation when file from summary doesn't exists 2014-04-18 23:42:02 +02:00
Aaron O'Mullan 6bce93d893 Bump version to 0.2.3 2014-04-18 11:53:18 -07:00
Aaron O'Mullan c9db068227 Refactor navigation generation to be functional
This makes it a lot less error prone and far more robust. As well as a
lot easier to understand
2014-04-18 11:49:55 -07:00
Samy Pessé 8a6d36ac4d Improve stability of mixpanel tracking 2014-04-18 20:42:18 +02:00
Samy Pessé 64622c5945 Load css before content 2014-04-18 20:19:45 +02:00
Samy Pessé 837813edb0 Add warning about theme 2014-04-18 20:16:21 +02:00
Aaron O'Mullan 0d9d62f1a9 Merge pull request #117 from GitbookIO/fix/99
Fix #99
2014-04-18 10:17:20 -07:00
Samy Pessé f7e9abf984 Fix quiz interractivity 2014-04-18 19:10:13 +02:00
Samy Pessé dd0579b60d Update tests for relative images 2014-04-18 17:23:33 +02:00
Samy Pessé b5bb953e47 Fix image path calcul 2014-04-18 17:15:03 +02:00
Samy Pessé ef4a8ea1b6 Fix #116: update url before updating html content 2014-04-18 15:49:53 +02:00
Samy Pessé 49cde96ee7 Add contributors to package.json and change homepage 2014-04-18 15:00:40 +02:00
Samy Pessé 627be20e48 Add editor and twitter links in the readme 2014-04-18 14:48:03 +02:00
Samy Pessé e45bb84b02 Fix navigation on chrome for iOS: disable pushState 2014-04-18 13:09:16 +02:00
Aaron O'Mullan 4e8876c725 Update README.md 2014-04-17 16:39:06 -07:00
57 changed files with 1850 additions and 265 deletions
+1
View File
@@ -15,3 +15,4 @@ Contributors
------------
- Nijiko Yonskai
- Herman Starikov
+1 -5
View File
@@ -24,7 +24,7 @@ module.exports = function (grunt) {
requirejs: {
compile: {
options: {
name: "app",
name: "gitbook",
baseUrl: "theme/javascript/",
out: "theme/assets/app.js",
preserveLicenseComments: false,
@@ -35,7 +35,6 @@ module.exports = function (grunt) {
"lodash": 'vendors/lodash',
"requireLib": 'vendors/require',
"Mousetrap": 'vendors/mousetrap',
"mixpanel": 'vendors/mixpanel',
"lunr": path.join(__dirname, "node_modules/lunr/lunr")
},
shim: {
@@ -48,9 +47,6 @@ module.exports = function (grunt) {
'Mousetrap': {
exports: 'Mousetrap'
},
'mixpanel': {
exports: 'mixpanel'
},
'lunr': {
exports: 'lunr'
}
+2 -2
View File
@@ -186,7 +186,7 @@ Apache License
same "printed page" as the copyright notice for easier
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");
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,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
limitations under the License.
+21 -2
View File
@@ -3,7 +3,7 @@ GitBook
[![Build Status](https://travis-ci.org/GitbookIO/gitbook.png?branch=master)](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.
![Image](https://raw.github.com/GitbookIO/gitbook/master/preview.png)
@@ -36,9 +36,12 @@ Options for commands `build` and `serve` are:
-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
--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
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
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
View File
@@ -1,18 +1,37 @@
var path = require('path');
var Q = require('q');
var _ = require('lodash');
var fs = require('fs');
var utils = require('./utils');
var generate = require("../lib/generate");
var parse = require("../lib/parse");
var fs = require('../lib/generate/fs');
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) {
return function(dir, options) {
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 ...');
// Get repo's URL
@@ -25,7 +44,7 @@ var makeBuildFunc = function(converter) {
})
.then(function(repoID) {
return converter(
_.extend(options || {}, {
_.extend({}, options || {}, {
input: dir,
output: outputDir,
title: options.title,
@@ -33,7 +52,8 @@ var makeBuildFunc = function(converter) {
github: options.github || repoID,
githubHost: options.githubHost,
generator: options.format,
theme: options.theme
plugins: options.plugins,
pluginsConfig: pluginsConfig
})
);
})
@@ -42,9 +62,10 @@ var makeBuildFunc = function(converter) {
return output;
}, utils.logError);
};
}
};
module.exports = {
folder: makeBuildFunc(generate.folder),
file: makeBuildFunc(generate.file)
file: makeBuildFunc(generate.file),
command: buildCommand
};
+36 -26
View File
@@ -12,45 +12,55 @@ var fs = require('../lib/generate/fs');
var utils = require('./utils');
var build = require('./build');
var Server = require('./server');
// General options
prog
.version(pkg.version);
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('-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]'))
build.command(prog.command('build [source_dir]'))
.description('Build a gitbook from a directory')
.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')
.option('-p, --port <port>', 'Port for server to listen on', 4000)
.option('--no-watch', 'Disable restart with file watching')
.action(function(dir, options) {
build.folder(dir, options || {})
.then(function(_options) {
console.log();
console.log('Starting server ...');
return utils.serveDir(_options.output, options.port)
var server = new Server();
var generate = function() {
if (server.isRunning()) console.log("Stopping server");
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);
})
.then(function() {
console.log('Serving book on http://localhost:'+options.port);
console.log();
console.log('Press CTRL+C to quit ...');
});
};
console.log('Press CTRL+C to quit ...');
console.log('')
generate();
});
buildCommand(prog.command('pdf [source_dir]'))
build.command(prog.command('pdf [source_dir]'))
.description('Build a gitbook as a PDF')
.option('-pf, --paperformat <format>', 'PDF paper format (default is A4): "5in*7.5in", "10cm*20cm", "A4", "Letter"')
.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')
.option('-c, --cover <path>', 'Cover image, default is cover.png if exists')
.action(function(dir, options) {
+96
View File
@@ -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
View File
@@ -4,8 +4,11 @@ var _ = require('lodash');
var http = require('http');
var send = require('send');
var url = require('url');
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
@@ -55,32 +58,24 @@ function titleCase(str)
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();
dir = path.resolve(dir);
var server = http.createServer(function(req, res){
// Render error
function error(err) {
res.statusCode = err.status || 500;
res.end(err.message);
}
var gaze = new Gaze("**/*.md", {
cwd: dir
});
// Redirect to directory's index.html
function redirect() {
res.statusCode = 301;
res.setHeader('Location', req.url + '/');
res.end('Redirecting to ' + req.url + '/');
}
gaze.once("all", function(e, filepath) {
gaze.close();
// Send file
send(req, url.parse(req.url).pathname)
.root(dir)
.on('error', error)
.on('directory', redirect)
.pipe(res);
}).listen(port);
d.resolve(filepath);
});
gaze.once("error", function(err) {
gaze.close();
d.resolve(server);
d.reject(err);
});
return d.promise;
}
@@ -96,6 +91,6 @@ module.exports = {
gitURL: gitURL,
githubID: githubID,
titleCase: titleCase,
serveDir: serveDir,
watch: watch,
logError: logError
};
+1
View File
@@ -18,6 +18,7 @@ var getFiles = function(path) {
ig.addIgnoreRules([
'.git/',
'.gitignore',
'.DS_Store'
], '__custom_stuff');
// Push each file to our list
+21
View File
@@ -1,9 +1,30 @@
var _ = require("lodash");
var path = require("path");
var Q = require("q");
var fs = require("./fs");
var Plugin = require("./plugin");
var BaseGenerator = function(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) {
+14 -4
View File
@@ -6,6 +6,7 @@ var tmp = require('tmp');
var fs = require("./fs");
var parse = require("../parse");
var Plugin = require("./plugin");
var generators = {
"site": require("./site"),
@@ -42,7 +43,11 @@ var generate = function(options) {
githubHost: 'https://github.com/',
// Theming
theme: path.resolve(__dirname, '../../theme')
theme: path.resolve(__dirname, '../../theme'),
// Plugins
plugins: [],
pluginsConfig: {}
});
if (!options.input) {
@@ -70,9 +75,10 @@ var generate = function(options) {
})
})
// Create the generator
// Create the generator and load plugins
.then(function() {
generator = new generators[options.generator](options);
return generator.loadPlugins();
})
// Detect multi-languages book
@@ -160,9 +166,12 @@ var generate = function(options) {
);
})
// Finish gneration
// Finish generation
.then(function() {
return generator.finish();
})
.then(function() {
return generator.callHook("finish");
});
}
})
@@ -234,5 +243,6 @@ var generateFile = function(options) {
module.exports = {
generators: generators,
folder: generate,
file: generateFile
file: generateFile,
Plugin: Plugin
};
+72
View File
@@ -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;
+8 -3
View File
@@ -25,14 +25,18 @@ swig.setFilter('code', function(code, lang) {
var Generator = function() {
BaseGenerator.apply(this, arguments);
// Load base template
this.template = swig.compileFile(path.resolve(this.options.theme, 'templates/page.html'));
// List of pages content
this.pages = {};
};
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) {
var that = this;
var json = {
@@ -46,6 +50,7 @@ Generator.prototype.convertFile = function(content, input) {
repo: that.options.githubId,
dir: path.dirname(input) || '/',
outdir: './',
singleFile: true
});
})
.then(function(sections) {
+187
View File
@@ -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;
+62 -7
View File
@@ -9,6 +9,7 @@ var parse = require("../../parse");
var BaseGenerator = require("../generator");
var indexer = require('./search_indexer');
var Manifest = require('../manifest');
// Swig filter for returning the count of lines in a code section
swig.setFilter('lines', function(content) {
@@ -30,13 +31,32 @@ var Generator = function() {
this.revision = Date.now();
this.indexer = indexer();
// Load base template
this.template = swig.compileFile(path.resolve(this.options.theme, 'templates/site.html'));
this.langsTemplate = swig.compileFile(path.resolve(this.options.theme, 'templates/langs.html'));
this.manifest = new Manifest(Date.now());
this.manifest.add("NETWORK", [
'*'
]);
};
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
Generator.prototype._writeTemplate = function(tpl, options, output) {
@@ -54,7 +74,10 @@ Generator.prototype._writeTemplate = function(tpl, options, output) {
githubHost: that.options.githubHost,
summary: that.options.summary,
allNavigation: that.options.navigation
allNavigation: that.options.navigation,
plugins: that.plugins,
pluginsConfig: JSON.stringify(that.options.pluginsConfig)
}, options));
})
.then(function(html) {
@@ -101,6 +124,8 @@ Generator.prototype.convertFile = function(content, _input) {
});
})
.then(function(sections) {
that.manifest.add("CACHE", _output);
return that._writeTemplate(that.template, {
progress: progress,
@@ -134,10 +159,30 @@ Generator.prototype.langsIndex = function(langs) {
Generator.prototype.copyAssets = function() {
var that = this;
// Copy gitbook assets
return fs.copy(
path.join(that.options.theme, "assets"),
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
@@ -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() {
return this.copyAssets()
.then(this.writeSearchIndex);
.then(this.writeSearchIndex)
.then(this.writeCacheManifest);
};
module.exports = Generator;
+30 -49
View File
@@ -6,6 +6,12 @@ function clean(obj) {
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
/*
{
@@ -20,62 +26,37 @@ function navigation(summary, files) {
// Support single files as well as list
files = _.isArray(files) ? files : (_.isString(files) ? [files] : null);
// Mapping of prev/next for a give path
var mapping = {};
// Special README nav
var README_NAV = {
path: 'README.md',
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',
};
// 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
if(files) {
return _.pick(mapping, files);
+34 -10
View File
@@ -1,5 +1,7 @@
var url = require('url');
var inherits = require('util').inherits;
var links = require('../utils').links;
var path = require('path');
@@ -16,6 +18,7 @@ function GitBookRenderer(options, extra_options) {
this._extra_options = extra_options;
this.quizRowId = 0;
this.id = rendererId++;
this.quizIndex = 0;
}
inherits(GitBookRenderer, marked.Renderer);
@@ -38,23 +41,38 @@ GitBookRenderer.prototype._unsanitized = function(href) {
};
GitBookRenderer.prototype.link = function(href, title, text) {
// Our "fixed" href
var _href = href;
// Don't build if it looks malicious
if (this.options.sanitize && this._unsanitized(href)) {
return '';
return text;
}
// Parsed version of the url
var parsed = url.parse(href);
var o = this._extra_options;
// Relative link, rewrite it to point to github repo
if(!parsed.protocol && parsed.path && parsed.path[0] != '/' && o && o.repo && o.dir) {
href = url.resolve('https://github.com/' + o.repo + '/blob/', [o.dir, href].join("/"));
parsed = url.parse(href);
if(links.isRelative(_href)) {
if (path.extname(_href) == ".md") {
_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
var out = '<a href="' + parsed.href + '"';
var out = '<a href="' + _href + '"';
// Title if no null
if (title) {
out += ' title="' + title + '"';
@@ -78,9 +96,11 @@ GitBookRenderer.prototype.image = function(href, title, text) {
var o = this._extra_options;
// Relative image, rewrite it depending output
if(!parsed.protocol && parsed.path && parsed.path[0] != '/' && o && o.dir && o.outdir) {
var outdir = o.outdir.charAt(o.outdir.length - 1) === '/' ? o.outdir : o.outdir + '/';
_href = url.resolve(outdir, [o.dir, href].join('/'));
if(links.isRelative(href) && o && o.dir && o.outdir) {
// o.dir: directory parent of the file currently in rendering process
// 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);
@@ -97,10 +117,14 @@ GitBookRenderer.prototype._createCheckboxAndRadios = function(text) {
if (!match) {
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[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) {
+1
View File
@@ -1,3 +1,4 @@
module.exports = {
lang: require('./lang'),
links: require('./links')
};
+29
View File
@@ -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
View File
@@ -1,6 +1,7 @@
{
"name": "gitbook",
"version": "0.2.2",
"version": "0.3.2",
"homepage": "http://www.gitbook.io/",
"description": "Library and cmd utility to generate GitBooks",
"main": "lib/index.js",
"dependencies": {
@@ -15,7 +16,14 @@
"commander": "2.2.0",
"fs-extra": "0.8.1",
"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": {
"mocha": "1.18.2",
@@ -39,9 +47,19 @@
"book",
"gitbook"
],
"author": "Aaron O'Mullan <aaron.omullan@friendco.de>",
"author": "FriendCode <contact@friendco.de>",
"license": "Apache 2",
"bugs": {
"url": "https://github.com/GitbookIO/gitbook/issues"
}
},
"contributors": [
{
"name": "Aaron O'Mullan",
"email": "aaron.omullan@gmail.com"
},
{
"name": "Samy Pessé",
"email": "samypesse@gmail.com"
}
]
}
+12
View File
@@ -0,0 +1,12 @@
# Images Test
This is a test for images path calculation. It supposed this fiel is in a syntax/ folder
### #
[![Screen](./preview.png)](./preview.png)
### 2
[![Screen](../preview2.png)](./preview2.png)
+5
View File
@@ -0,0 +1,5 @@
# Nice course
Check out this other chapter [Test](test.md)
Check out this other chapter [Test](../before.md)
+61 -5
View File
@@ -36,10 +36,6 @@ describe('Page parsing', function() {
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() {
assert(LEXED[1].content);
assert(LEXED[1].code);
@@ -88,9 +84,69 @@ describe('Relative links', function() {
repo: 'GitBookIO/javascript',
// 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);
});
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);
});
});
+49
View File
@@ -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);
});
});
-5
View File
@@ -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
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+7
View File
@@ -0,0 +1,7 @@
define([
"jQuery"
], function($) {
var events = $({});
return events;
});
+3 -3
View File
@@ -1,9 +1,9 @@
define([
"jQuery",
"utils/execute",
"utils/analytic",
"core/events",
"core/state"
], function($, execute, analytic, state){
], function($, execute, events, state){
// Bind an exercise
var prepareExercise = function($exercise) {
var codeSolution = $exercise.find(".code-solution").text();
@@ -19,7 +19,7 @@ define([
$exercise.find(".action-submit").click(function(e) {
e.preventDefault();
analytic.track("exercise.submit", {type: "code"});
events.trigger("exercise.submit", {type: "code"});
execute("javascript", editor.getValue(), codeValidation, codeContext, function(err, result) {
$exercise.toggleClass("return-error", err != null);
+115
View File
@@ -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
}
});
+18
View File
@@ -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
};
});
+21 -17
View File
@@ -1,28 +1,35 @@
define([
"jQuery",
"utils/analytic",
"utils/path",
"core/events",
"core/state",
"core/search",
"core/progress",
"core/exercise",
"core/quiz"
], function($, analytic, state, search, progress, exercises, quiz) {
"core/quiz",
"core/loading"
], function($, path, events, state, search, progress, exercises, quiz, loading) {
var prev, next;
var githubCountStars, githubCountWatch;
var updateHistory = function(url, title) {
history.pushState({ path: url }, title, url);
};
var usePushState = (typeof history.pushState !== "undefined");
var handleNavigation = function(url, push) {
if (typeof history.pushState === "undefined") {
var handleNavigation = function(relativeUrl, push) {
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
location.href = url;
location.href = relativeUrl;
return
}
return $.get(url)
return loading.show($.get(url)
.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){
return '<' + b + 'div' + ( b ? '' : ' data-element="' + c + '"' ) + d + '>';
});
@@ -49,13 +56,11 @@ define([
// Update state
state.update($("html"));
if (push) updateHistory(url, null);
preparePage();
})
.fail(function () {
location.href = url;
});
.fail(function (e) {
location.href = relativeUrl;
}));
};
var updateGitHubCounts = function() {
@@ -108,7 +113,7 @@ define([
}
// Send to mixpanel
analytic.track("page.view");
events.trigger("page.change");
};
var handlePagination = function (e) {
@@ -146,7 +151,6 @@ define([
if (event.state === null) {
return;
}
return handleNavigation(event.state.path, false);
};
+8 -5
View File
@@ -1,9 +1,9 @@
define([
"jQuery",
"utils/execute",
"utils/analytic",
"core/events",
"core/state"
], function($, execute, analytic, state){
], function($, execute, events, state){
// Bind an exercise
var prepareQuiz = function($quiz) {
@@ -14,14 +14,17 @@ define([
// Submit: test code
$quiz.find(".action-submit").click(function(e) {
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(".alert-success,.alert-danger").addClass("hidden");
$quiz.find(".question").each(function(q) {
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");
result = result && correct;
if (!correct) {
@@ -1,17 +1,19 @@
require([
define([
"jQuery",
"utils/storage",
"utils/analytic",
"utils/sharing",
"utils/appcache",
"core/events",
"core/font-settings",
"core/state",
"core/keyboard",
"core/navigation",
"core/progress",
"core/sidebar",
"core/search"
], function($, storage, analytic, sharing, state, keyboard, navigation, progress, sidebar, search){
$(document).ready(function() {
], function($, storage, appCache, sharing, events, fontSettings, state, keyboard, navigation, progress, sidebar, search){
var start = function(config) {
var $book;
$book = state.$book;
@@ -29,10 +31,23 @@ require([
// Init keyboard
keyboard.init();
// Init appcache
appCache.init();
// Bind sharing button
sharing.init();
// Init navigation
navigation.init();
});
//Init font settings
fontSettings.init();
events.trigger("start", config);
}
return {
start: start,
events: events
};
});
-33
View File
@@ -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
};
});
+15
View File
@@ -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
};
});
+47
View File
@@ -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
};
})
-2
View File
@@ -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||[]);
+49 -3
View File
@@ -6,6 +6,7 @@
left: 0px;
bottom: 0px;
color: @page-color;
background: @body-background;
.transition(left 0.5s ease);
@@ -23,7 +24,6 @@
outline: none;
.page-inner {
font-family: @font-family-serif;
max-width: 800px;
margin: 0px auto;
@@ -33,8 +33,6 @@
background: @page-background;
border-radius: 2px;
font-size: 16px;
line-height: 1.5em;
}
@@ -57,6 +55,28 @@
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 {
@@ -72,4 +92,30 @@
.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;
}
}
}
}
}
}
+159
View File
@@ -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;
}
}
}
}
}
}
+42 -1
View File
@@ -3,7 +3,7 @@
font-family: @font-family-sans;
position: fixed;
overflow: hidden;
overflow: visible;
top: 0px;
right: 0px;
left: 0px;
@@ -24,6 +24,7 @@
text-transform: uppercase;
line-height: @header-height;
.box-shadow(none) !important;
position:relative;
&:hover {
position: relative;
@@ -51,9 +52,23 @@
@media (max-width: 800px) {
display: none;
}
i {
display: none;
}
}
}
&.is-loading {
.book-header h1 {
i {
display: inline-block;
}
a {
display: none;
}
}
}
&.with-summary {
.book-header h1 {
margin-left: 250px;
@@ -64,4 +79,30 @@
.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;
}
+107
View File
@@ -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;
}
@@ -1,8 +1,9 @@
/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */
/* Tomorrow Comment */
.hljs-comment {
color: hsl(207, 35%, 35%);
.hljs-comment,
.hljs-title {
color: #8e908c;
}
/* Tomorrow Red */
@@ -27,9 +28,9 @@
.hljs-pragma,
.hljs-built_in,
.hljs-literal,
.hljs-constant,
.hljs-function .hljs-title {
color: hsl(50, 100%, 60%);
.hljs-params,
.hljs-constant {
color: #f5871f;
}
/* Tomorrow Yellow */
@@ -45,7 +46,7 @@
.hljs-header,
.ruby .hljs-symbol,
.xml .hljs-cdata {
color: hsl(0, 100%, 70%);
color: #718c00;
}
/* Tomorrow Aqua */
@@ -54,7 +55,7 @@
}
/* Tomorrow Blue */
.hljs-function .keyword,
.hljs-function,
.python .hljs-decorator,
.python .hljs-title,
.ruby .hljs-function .hljs-title,
@@ -62,13 +63,13 @@
.perl .hljs-sub,
.javascript .hljs-title,
.coffeescript .hljs-title {
color: hsl(207, 70%, 60%);
color: #4271ae;
}
/* Tomorrow Purple */
.hljs-keyword,
.javascript .hljs-function {
color: hsl(207, 95%, 70%);
color: #8959a8;
}
.hljs {
@@ -76,7 +77,6 @@
background: white;
color: #4d4d4c;
padding: 0.5em;
font-family: "Anonymous Pro", "Inconsolata", "Monaco", monospace;
}
.coffeescript .javascript,
+29 -23
View File
@@ -1,8 +1,29 @@
.book .book-body .page-wrapper .page-inner section.normal {
padding: 25px;
padding-top: 15px;
background-color: white;
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal {
color:@page-color-1;
pre, code {
background: #fdf6e3;
color: #657b83;
border-color: darken(#fdf6e3, 15%);
@import "./highlight/sepia.less";
}
}
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal {
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 {
margin-top: 0 !important; }
@@ -52,12 +73,12 @@
h1 {
font-size: 28px;
color: black; }
}
h2 {
font-size: 24px;
border-bottom: 1px solid #eee;
color: black; }
}
h3 {
font-size: 18px; }
@@ -69,7 +90,6 @@
font-size: 14px; }
h6 {
color: #777777;
font-size: 14px; }
p, blockquote, ul, ol, dl, table, pre {
@@ -272,29 +292,15 @@
white-space: pre;
border: none;
background: transparent;
}
.highlight pre {
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;
@import "./highlight/white.less";
}
pre {
color: hsl(204, 40%, 80%);
background-color: hsl(204, 30%, 10%);
border: 1px solid hsl(204, 30%, 10%);
font-size: 16px;
font-size: inherit;
line-height: 1.5em;
overflow: auto;
padding: 20px;
margin: 0 -20px;
border-radius: 3px;
}
+10
View File
@@ -42,4 +42,14 @@
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;
}
}
+32 -1
View File
@@ -17,7 +17,6 @@
position: relative;
background: #fff;
margin-bottom: 20px;
z-index: 10;
.bar {
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;
}
}
}
+6 -2
View File
@@ -29,8 +29,12 @@
.question-inner {
padding: 15px;
.quiz-label {
font-weight: normal;
cursor: pointer;
}
}
table {
margin-bottom: 10px;
width: 100%;
@@ -46,4 +50,4 @@
}
}
}
}
}
+90
View File
@@ -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;
}
}
}
}
}
+1 -1
View File
@@ -5,10 +5,10 @@
@import "variables.less";
@import "fonts.less";
@import "book/highlight.less";
@import "book/languages.less";
@import "book/header.less";
@import "book/summary.less";
@import "book/font-settings.less";
@import "book/body.less";
@import "book/exercise.less";
@import "book/quiz.less";
+2 -2
View File
@@ -1,4 +1,4 @@
/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */
/* http://jmblog.github.io/color-themes-for-highlightjs */
/* Tomorrow Comment */
.hljs-comment,
@@ -87,4 +87,4 @@
.xml .css,
.xml .hljs-cdata {
opacity: 0.5;
}
}
+90
View File
@@ -38,6 +38,7 @@
@sidebar-link-completed-weight: normal;
// Page
@page-color: black;
@page-background: white;
// Progress Bar
@@ -79,5 +80,94 @@
@font-family-sans: "Open Sans", "Clear Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
@font-family-base: @font-family-serif;
@FontPath: '@{staticPath}/fonts';
@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>
+9 -1
View File
@@ -5,6 +5,11 @@
{% endif %}
<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>
<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 -->
<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 %}
<!-- Title -->
<h1><a href="{{ basePath }}/" >{{ title }}</a></h1>
<h1>
<i class="fa fa-spinner fa-spin"></i>
<a href="{{ basePath }}/" >{{ title }}</a>
</h1>
</div>
+2 -2
View File
@@ -1,5 +1,5 @@
<!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#">
{% block head %}
<meta charset="UTF-8">
@@ -35,10 +35,10 @@
{% endblock %}
</head>
<body>
{% block content %}{% endblock %}
{% block style %}
<link rel="stylesheet" href="{{ staticBase }}/style.css">
{% endblock %}
{% block content %}{% endblock %}
{% 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/mode-javascript.js"></script>
+2
View File
@@ -77,9 +77,11 @@
<h1>{{ item.title }}</h1>
</article>
{% if pages[item.path] %}
<article>
{{ articleContent(pages[item.path].content) }}
</article>
{% endif %}
{% if item.articles.length > 0 %}
{% for article in item.articles %}
+29
View File
@@ -1,5 +1,6 @@
{% extends "layout.html" %}
{% block htmlTag %}manifest="{{ basePath }}/manifest.appcache"{% endblock %}
{% block title %}{{ progress.current.title }}{% parent %}{% endblock %}
{% block content %}
<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>
{% 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 %}