mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-16 07:35:16 +00:00
Compare commits
64 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 67b2394c16 | |||
| 269d08a35f | |||
| f626e83e48 | |||
| 8ba18cd587 | |||
| 54c12fea89 | |||
| afb5ce71ce | |||
| 6fef6acf10 | |||
| a27411401b | |||
| 3718fc319b | |||
| c6c9463f8c | |||
| b410685318 | |||
| b742b29259 | |||
| df5d27ab61 | |||
| 2870155c0b | |||
| 9ba1075f48 | |||
| 4ae5b2e050 | |||
| 4369bd8f5e | |||
| 321b24a7b9 | |||
| 22e0c1fb54 | |||
| ba65e3c020 | |||
| c19ab952e3 | |||
| ecc29087b5 | |||
| 87e056de64 | |||
| 761200529f | |||
| 770351916e | |||
| 4b7d957b47 | |||
| a1c03c18a5 | |||
| 5d376b054f | |||
| 277d13c2bb | |||
| 4a9389d80a | |||
| 33593c13ae | |||
| eef82c18c2 | |||
| 7363580095 | |||
| 23a46b0597 | |||
| 51c79f294c | |||
| ce1e0e1873 | |||
| c2775b3b63 | |||
| bcb224d1cb | |||
| 8bc5f22866 | |||
| c3f2ef02c4 | |||
| 08e2c90d9d | |||
| d2bb2ba454 | |||
| ba912318cd | |||
| 3d1f057373 | |||
| 0679807517 | |||
| 7f0e4803e2 | |||
| fa76029a17 | |||
| 376c68957f | |||
| 222ec8d4b9 | |||
| 90715c1944 | |||
| 801e1b6059 | |||
| 14bb659b75 | |||
| eab3c50288 | |||
| 74396e7240 | |||
| 6c2539e886 | |||
| aba25d8521 | |||
| f0c97756de | |||
| f14c57d4c2 | |||
| b6f60cc8ad | |||
| 170516d343 | |||
| c931e91bef | |||
| db9151ae36 | |||
| f2d86b6d69 | |||
| 534cdd091b |
@@ -0,0 +1 @@
|
||||
theme/**/*
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"rules": {
|
||||
"indent": [ 2, 4 ],
|
||||
"quotes": [ 2, "single" ],
|
||||
"linebreak-style": [ 2, "unix" ],
|
||||
"semi": [ 2, "always" ],
|
||||
"no-unused-vars": [ 2, {
|
||||
"vars": "all",
|
||||
"args": "none"
|
||||
} ],
|
||||
"spaced-comment": [ 2, "always" ]
|
||||
},
|
||||
"env": {
|
||||
"node": true,
|
||||
"mocha": true,
|
||||
"browser": true
|
||||
},
|
||||
"extends": "eslint:recommended"
|
||||
}
|
||||
@@ -24,8 +24,5 @@ build/Release
|
||||
# see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git
|
||||
node_modules
|
||||
|
||||
theme/javascript/vendors
|
||||
theme/vendors
|
||||
|
||||
# vim swapfile
|
||||
*.swp
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"strict": false,
|
||||
"browser": false,
|
||||
"quotmark": true,
|
||||
"node": true,
|
||||
"mocha": true
|
||||
}
|
||||
+3
-1
@@ -1,7 +1,9 @@
|
||||
sudo: false
|
||||
language: node_js
|
||||
node_js:
|
||||
- "4.1"
|
||||
- "0.12"
|
||||
- "0.11"
|
||||
- "0.10"
|
||||
before_install:
|
||||
- npm install svgexport -g
|
||||
- npm install svgexport -g
|
||||
|
||||
@@ -55,3 +55,5 @@ Translators
|
||||
- Hong Nguyen (@nghong)
|
||||
- Hebrew
|
||||
- @a-moses
|
||||
- Ukrainian
|
||||
- @Karnaukhov
|
||||
|
||||
+18
@@ -2,6 +2,24 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## 2.5.0-beta.2
|
||||
- Fix support for pre-releases
|
||||
|
||||
## 2.5.0-beta.1
|
||||
- Font settings, sharing and search are externalized as default plugins
|
||||
- Plugins can define a configuration schema in the manifest, this schema will be used to validate configuration during build
|
||||
- New Node.js API for plugin: `book.formatString(type, content)`
|
||||
- New client side API for website plugins: `gitbook.toolbar.createButton(opts)`
|
||||
- Better header/footer for PDF, CSS wil be inlined to easily style the header/footer
|
||||
- Cleaner table of contents for ebooks
|
||||
- Support for RTL in ebook's table of contents
|
||||
- Better colors for mobi (links and code blocks)
|
||||
|
||||
## 2.4.3
|
||||
- Add ukrainian translation (`uk`)
|
||||
- Add `book.json` configuration for maximum size of search index
|
||||
- Improve reliability of summary parser
|
||||
|
||||
## 2.4.2
|
||||
- Default plugins should not be installed by `gitbook install`
|
||||
- Limit search index size to avoid crash during generation
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
module.exports = function (grunt) {
|
||||
var path = require("path");
|
||||
|
||||
// Load NPM tasks
|
||||
grunt.loadNpmTasks('grunt-contrib-copy');
|
||||
grunt.loadNpmTasks('grunt-contrib-less');
|
||||
grunt.loadNpmTasks('grunt-contrib-requirejs');
|
||||
grunt.loadNpmTasks("grunt-bower-install-simple");
|
||||
|
||||
// Init GRUNT configuraton
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
'bower-install-simple': {
|
||||
options: {
|
||||
color: true,
|
||||
production: false,
|
||||
directory: "theme/vendors"
|
||||
}
|
||||
},
|
||||
less: {
|
||||
development: {
|
||||
options: {
|
||||
compress: true,
|
||||
yuicompress: true,
|
||||
optimization: 2
|
||||
},
|
||||
files: {
|
||||
"theme/assets/style.css": "theme/stylesheets/website.less",
|
||||
"theme/assets/print.css": "theme/stylesheets/ebook.less"
|
||||
}
|
||||
}
|
||||
},
|
||||
requirejs: {
|
||||
compile: {
|
||||
options: {
|
||||
name: "gitbook",
|
||||
baseUrl: "theme/javascript/",
|
||||
out: "theme/assets/app.js",
|
||||
preserveLicenseComments: false,
|
||||
optimize: "uglify",
|
||||
include: ["requireLib"],
|
||||
paths: {
|
||||
"jQuery": '../vendors/jquery/dist/jquery',
|
||||
"lodash": '../vendors/lodash/dist/lodash',
|
||||
"requireLib": '../vendors/requirejs/require',
|
||||
"Mousetrap": '../vendors/mousetrap/mousetrap',
|
||||
"lunr": '../vendors/lunr.js/lunr',
|
||||
"URIjs": '../vendors/URIjs/src/',
|
||||
"ace": '../vendors/ace-builds/src-noconflict/'
|
||||
},
|
||||
shim: {
|
||||
'jQuery': {
|
||||
exports: '$'
|
||||
},
|
||||
'lodash': {
|
||||
exports: '_'
|
||||
},
|
||||
'Mousetrap': {
|
||||
exports: 'Mousetrap'
|
||||
},
|
||||
'lunr': {
|
||||
exports: 'lunr'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
copy: {
|
||||
vendors: {
|
||||
files: [
|
||||
{
|
||||
expand: true,
|
||||
cwd: 'theme/vendors/fontawesome/fonts/',
|
||||
src: ['**'],
|
||||
dest: 'theme/assets/fonts/fontawesome/',
|
||||
filter: 'isFile'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
grunt.registerTask("bower-install", [ "bower-install-simple" ]);
|
||||
|
||||
// Build
|
||||
grunt.registerTask('build', [
|
||||
'bower-install',
|
||||
'less',
|
||||
'requirejs',
|
||||
'copy:vendors'
|
||||
]);
|
||||
|
||||
grunt.registerTask('default', [
|
||||
'build'
|
||||
]);
|
||||
};
|
||||
@@ -4,12 +4,13 @@ GitBook
|
||||
[](http://badge.fury.io/js/gitbook)
|
||||
[](https://travis-ci.org/GitbookIO/gitbook)
|
||||
[](https://ci.appveyor.com/project/GitBook/gitbook)
|
||||
[](https://slack.gitbook.com)
|
||||
|
||||
GitBook is a command line tool (and Node.js library) for building beautiful books using GitHub/Git and Markdown (or AsciiDoc). Here is an example: [Learn Javascript](https://www.gitbook.com/book/GitBookIO/javascript).
|
||||
|
||||
You can publish and host book easily online using [gitbook.com](https://www.gitbook.com), a desktop editor is [also available](https://www.gitbook.com/editor).
|
||||
|
||||
Stay updated by following [@GitBookIO](https://twitter.com/GitBookIO) on Twitter or [GitBook](https://www.facebook.com/gitbookcom) on Facebook.
|
||||
Check out the [GitBook Community Slack Channel](https://slack.gitbook.com), Stay updated by following [@GitBookIO](https://twitter.com/GitBookIO) on Twitter or [GitBook](https://www.facebook.com/gitbookcom) on Facebook.
|
||||
|
||||
Complete documentation is available at [help.gitbook.com](http://help.gitbook.com/).
|
||||
|
||||
|
||||
+3
-3
@@ -2,6 +2,6 @@
|
||||
|
||||
var color = require('bash-color');
|
||||
|
||||
console.log(color.red("You need to install 'gitbook-cli' to have access to the gitbook command anywhere on your system."));
|
||||
console.log(color.red("If you've installed this package globally, you need to uninstall it."));
|
||||
console.log(color.red(">> Run 'npm uninstall -g gitbook' then 'npm install -g gitbook-cli'"));
|
||||
console.log(color.red('You need to install "gitbook-cli" to have access to the gitbook command anywhere on your system.'));
|
||||
console.log(color.red('If you\'ve installed this package globally, you need to uninstall it.'));
|
||||
console.log(color.red('>> Run "npm uninstall -g gitbook" then "npm install -g gitbook-cli"'));
|
||||
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"name": "GitBook",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"jquery": "2.1.1",
|
||||
"lodash": "2.4.1",
|
||||
"requirejs": "2.1.11",
|
||||
"URIjs": "1.13.1",
|
||||
"mousetrap": "1.4.6",
|
||||
"lunr.js": "0.5.2",
|
||||
"fontawesome": "4.1.0"
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
var _ = require('lodash');
|
||||
var gulp = require('gulp');
|
||||
var gutil = require('gulp-util');
|
||||
var less = require('gulp-less');
|
||||
var rename = require('gulp-rename');
|
||||
var minifyCSS = require('gulp-minify-css');
|
||||
var browserify = require('browserify');
|
||||
var mergeStream = require('merge-stream');
|
||||
var source = require('vinyl-source-stream');
|
||||
|
||||
gulp.task('css', function() {
|
||||
var merged = mergeStream();
|
||||
|
||||
_.each({
|
||||
'ebook.less': 'ebook/ebook.css',
|
||||
'pdf.less': 'ebook/pdf.css',
|
||||
'mobi.less': 'ebook/mobi.css',
|
||||
'epub.less': 'ebook/epub.css',
|
||||
'website.less': 'website/style.css'
|
||||
}, function(out, input) {
|
||||
gutil.log('compiling', input, 'into', out);
|
||||
merged.add(gulp.src('theme/stylesheets/'+input)
|
||||
.pipe(less())
|
||||
.pipe(minifyCSS())
|
||||
.pipe(rename(out))
|
||||
.pipe(gulp.dest('theme/assets/')));
|
||||
});
|
||||
|
||||
return merged;
|
||||
});
|
||||
|
||||
gulp.task('js', function() {
|
||||
return browserify('./theme/javascript/index.js')
|
||||
.bundle()
|
||||
.pipe(source('app.js'))
|
||||
.pipe(gulp.dest('./theme/assets/website'));
|
||||
});
|
||||
|
||||
gulp.task('assets', function() {
|
||||
return gulp.src('./node_modules/font-awesome/fonts/*')
|
||||
.pipe(gulp.dest('theme/assets/website/fonts/fontawesome/'));
|
||||
});
|
||||
|
||||
gulp.task('default', ['css', 'js', 'assets'], function() {
|
||||
|
||||
});
|
||||
|
||||
+131
-213
@@ -1,25 +1,22 @@
|
||||
var Q = require("q");
|
||||
var _ = require("lodash");
|
||||
var path = require("path");
|
||||
var lunr = require("lunr");
|
||||
var parsers = require("gitbook-parsers");
|
||||
var Q = require('q');
|
||||
var _ = require('lodash');
|
||||
var path = require('path');
|
||||
var parsers = require('gitbook-parsers');
|
||||
|
||||
var fs = require("./utils/fs");
|
||||
var parseNavigation = require("./utils/navigation");
|
||||
var parseProgress = require("./utils/progress");
|
||||
var pageUtil = require("./utils/page");
|
||||
var pathUtil = require("./utils/path");
|
||||
var links = require("./utils/links");
|
||||
var i18n = require("./utils/i18n");
|
||||
var logger = require("./utils/logger");
|
||||
var fs = require('./utils/fs');
|
||||
var parseNavigation = require('./utils/navigation');
|
||||
var parseProgress = require('./utils/progress');
|
||||
var pageUtil = require('./utils/page');
|
||||
var pathUtil = require('./utils/path');
|
||||
var links = require('./utils/links');
|
||||
var i18n = require('./utils/i18n');
|
||||
var logger = require('./utils/logger');
|
||||
|
||||
var Configuration = require("./configuration");
|
||||
var TemplateEngine = require("./template");
|
||||
var PluginsList = require("./pluginslist");
|
||||
var Configuration = require('./configuration');
|
||||
var TemplateEngine = require('./template');
|
||||
var PluginsList = require('./pluginslist');
|
||||
|
||||
var generators = require("./generators");
|
||||
|
||||
var SEARCHINDEX_MAXSIZE = 1000000;
|
||||
var generators = require('./generators');
|
||||
|
||||
var Book = function(root, context, parent) {
|
||||
this.context = _.defaults(context || {}, {
|
||||
@@ -32,7 +29,7 @@ var Book = function(root, context, parent) {
|
||||
},
|
||||
|
||||
// Log level
|
||||
logLevel: "info"
|
||||
logLevel: 'info'
|
||||
});
|
||||
|
||||
// Log
|
||||
@@ -46,7 +43,7 @@ var Book = function(root, context, parent) {
|
||||
|
||||
// Configuration
|
||||
this.config = new Configuration(this, this.context.config);
|
||||
Object.defineProperty(this, "options", {
|
||||
Object.defineProperty(this, 'options', {
|
||||
get: function () {
|
||||
return this.config.options;
|
||||
}
|
||||
@@ -80,23 +77,13 @@ var Book = function(root, context, parent) {
|
||||
this.readmeFile = null;
|
||||
this.langsFile = null;
|
||||
|
||||
// Search Index
|
||||
this.searchIndexEnabled = true;
|
||||
this.searchIndexSize = 0;
|
||||
this.searchIndex = lunr(function () {
|
||||
this.ref("url");
|
||||
|
||||
this.field("title", { boost: 10 });
|
||||
this.field("body");
|
||||
});
|
||||
|
||||
// Bind methods
|
||||
_.bindAll(this);
|
||||
};
|
||||
|
||||
// Return string representation
|
||||
Book.prototype.toString = function() {
|
||||
return "[Book "+this.root+"]";
|
||||
return '[Book '+this.root+']';
|
||||
};
|
||||
|
||||
// Initialize and parse the book: config, summary, glossary
|
||||
@@ -114,17 +101,17 @@ Book.prototype.parse = function() {
|
||||
return that.parseLangs()
|
||||
.then(function() {
|
||||
multilingual = that.langs.length > 0;
|
||||
if (multilingual) that.log.info.ln("Parsing multilingual book, with", that.langs.length, "languages");
|
||||
if (multilingual) that.log.info.ln('Parsing multilingual book, with', that.langs.length, 'languages');
|
||||
|
||||
// Sub-books that inherit from the current book configuration
|
||||
that.books = _.map(that.langs, function(lang) {
|
||||
that.log.info.ln("Preparing language book", lang.lang);
|
||||
that.log.info.ln('Preparing language book', lang.lang);
|
||||
return new Book(
|
||||
path.join(that.root, lang.path),
|
||||
_.merge({}, that.context, {
|
||||
config: _.extend({}, that.options, {
|
||||
"output": path.join(that.options.output, lang.lang),
|
||||
"language": lang.lang
|
||||
'output': path.join(that.options.output, lang.lang),
|
||||
'language': lang.lang
|
||||
})
|
||||
}),
|
||||
that
|
||||
@@ -167,15 +154,15 @@ Book.prototype.generate = function(generator) {
|
||||
var that = this;
|
||||
that.options.generator = generator || that.options.generator;
|
||||
|
||||
that.log.info.ln("start generation with", that.options.generator, "generator");
|
||||
that.log.info.ln('start generation with', that.options.generator, 'generator');
|
||||
return Q()
|
||||
|
||||
// Clean output folder
|
||||
.then(function() {
|
||||
that.log.info("clean", that.options.generator, "generator");
|
||||
that.log.info('clean', that.options.generator, 'generator');
|
||||
return fs.clean(that.options.output)
|
||||
.progress(function(p) {
|
||||
that.log.debug.ln("remove", p.file, "("+p.i+"/"+p.count+")");
|
||||
that.log.debug.ln('remove', p.file, '('+p.i+'/'+p.count+')');
|
||||
})
|
||||
.then(function() {
|
||||
that.log.info.ok();
|
||||
@@ -185,12 +172,20 @@ Book.prototype.generate = function(generator) {
|
||||
// Create generator
|
||||
.then(function() {
|
||||
var Generator = generators[generator];
|
||||
if (!Generator) throw "Generator \""+that.options.generator+"\" doesn't exist";
|
||||
if (!Generator) throw 'Generator \''+that.options.generator+'\' doesn\'t exist';
|
||||
generator = new Generator(that);
|
||||
|
||||
return generator.prepare();
|
||||
})
|
||||
|
||||
// Transform configuration
|
||||
.then(function() {
|
||||
return that.callHook('config', that.config.dump())
|
||||
.then(function(newConfig) {
|
||||
that.config.replace(newConfig);
|
||||
});
|
||||
})
|
||||
|
||||
// Generate content
|
||||
.then(function() {
|
||||
if (that.isMultilingual()) {
|
||||
@@ -198,43 +193,43 @@ Book.prototype.generate = function(generator) {
|
||||
} else {
|
||||
// Separate list of files into the different operations needed
|
||||
var ops = _.groupBy(that.files, function(file) {
|
||||
if (file[file.length -1] == "/") {
|
||||
return "directories";
|
||||
if (file[file.length -1] == '/') {
|
||||
return 'directories';
|
||||
} else if (_.contains(parsers.extensions, path.extname(file)) && that.navigation[file]) {
|
||||
return "content";
|
||||
return 'content';
|
||||
} else {
|
||||
return "files";
|
||||
return 'files';
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return Q()
|
||||
|
||||
// First, let"s create folder
|
||||
// First, let's create folder
|
||||
.then(function() {
|
||||
return _.reduce(ops.directories || [], function(prev, folder) {
|
||||
return prev.then(function() {
|
||||
that.log.debug.ln("transferring folder", folder);
|
||||
that.log.debug.ln('transferring folder', folder);
|
||||
return Q(generator.transferFolder(folder));
|
||||
});
|
||||
}, Q());
|
||||
})
|
||||
|
||||
// Then, let"s copy other files
|
||||
// Then, let's copy other files
|
||||
.then(function() {
|
||||
return Q.all(_.map(ops.files || [], function(file) {
|
||||
that.log.debug.ln("transferring file", file);
|
||||
that.log.debug.ln('transferring file', file);
|
||||
return Q(generator.transferFile(file));
|
||||
}));
|
||||
})
|
||||
|
||||
// Finally let"s generate content
|
||||
// Finally let's generate content
|
||||
.then(function() {
|
||||
var nFiles = (ops.content || []).length;
|
||||
return _.reduce(ops.content || [], function(prev, file, i) {
|
||||
return prev.then(function() {
|
||||
var p = ((i*100)/nFiles).toFixed(0)+"%";
|
||||
that.log.debug.ln("processing", file, p);
|
||||
var p = ((i*100)/nFiles).toFixed(0)+'%';
|
||||
that.log.debug.ln('processing', file, p);
|
||||
|
||||
return Q(generator.convertFile(file))
|
||||
.fail(function(err) {
|
||||
@@ -251,16 +246,16 @@ Book.prototype.generate = function(generator) {
|
||||
|
||||
// Finish generation
|
||||
.then(function() {
|
||||
return generator.callHook("finish:before");
|
||||
return that.callHook('finish:before');
|
||||
})
|
||||
.then(function() {
|
||||
return generator.finish();
|
||||
})
|
||||
.then(function() {
|
||||
return generator.callHook("finish");
|
||||
return that.callHook('finish');
|
||||
})
|
||||
.then(function() {
|
||||
that.log.info.ln("generation is finished");
|
||||
that.log.info.ln('generation is finished');
|
||||
});
|
||||
};
|
||||
|
||||
@@ -286,7 +281,7 @@ Book.prototype.generateFile = function(output, options) {
|
||||
options = _.defaults(options || {}, {
|
||||
ebookFormat: path.extname(output).slice(1)
|
||||
});
|
||||
output = output || path.resolve(book.root, "book."+options.ebookFormat);
|
||||
output = output || path.resolve(book.root, 'book.'+options.ebookFormat);
|
||||
|
||||
return fs.tmp.dir()
|
||||
.then(function(tmpDir) {
|
||||
@@ -299,13 +294,13 @@ Book.prototype.generateFile = function(output, options) {
|
||||
var _tmpDir = tmpDir;
|
||||
|
||||
if (lang) {
|
||||
_outputFile = _outputFile.slice(0, -path.extname(_outputFile).length)+"_"+lang+path.extname(_outputFile);
|
||||
_outputFile = _outputFile.slice(0, -path.extname(_outputFile).length)+'_'+lang+path.extname(_outputFile);
|
||||
_tmpDir = path.join(_tmpDir, lang);
|
||||
}
|
||||
|
||||
book.log.debug.ln("copy ebook to", _outputFile);
|
||||
book.log.debug.ln('copy ebook to', _outputFile);
|
||||
return fs.copy(
|
||||
path.join(_tmpDir, "index."+options.ebookFormat),
|
||||
path.join(_tmpDir, 'index.'+options.ebookFormat),
|
||||
_outputFile
|
||||
);
|
||||
};
|
||||
@@ -325,7 +320,7 @@ Book.prototype.generateFile = function(output, options) {
|
||||
}
|
||||
})
|
||||
.then(function(n) {
|
||||
book.log.info.ok(n+" file(s) generated");
|
||||
book.log.info.ok(n+' file(s) generated');
|
||||
|
||||
return fs.remove(tmpDir);
|
||||
});
|
||||
@@ -337,7 +332,7 @@ Book.prototype.generateFile = function(output, options) {
|
||||
Book.prototype.parseConfig = function() {
|
||||
var that = this;
|
||||
|
||||
that.log.info("loading book configuration....");
|
||||
that.log.info('loading book configuration....');
|
||||
return that.config.load()
|
||||
.then(function() {
|
||||
that.log.info.ok();
|
||||
@@ -351,34 +346,34 @@ Book.prototype.parsePlugins = function() {
|
||||
// Load plugins
|
||||
return that.plugins.load(that.options.plugins)
|
||||
.then(function() {
|
||||
if (_.size(that.plugins.failed) > 0) return Q.reject(new Error("Error loading plugins: "+that.plugins.failed.join(",")+". Run \"gitbook install\" to install plugins from NPM."));
|
||||
if (_.size(that.plugins.failed) > 0) return Q.reject(new Error('Error loading plugins: '+that.plugins.failed.join(',')+'. Run \'gitbook install\' to install plugins from NPM.'));
|
||||
|
||||
that.log.info.ok(that.plugins.count()+" plugins loaded");
|
||||
that.log.debug.ln("normalize plugins list");
|
||||
that.log.info.ok(that.plugins.count()+' plugins loaded');
|
||||
that.log.debug.ln('normalize plugins list');
|
||||
});
|
||||
};
|
||||
|
||||
// Parse readme to extract defaults title and description
|
||||
Book.prototype.parseReadme = function() {
|
||||
var that = this;
|
||||
var structure = that.config.getStructure("readme");
|
||||
that.log.debug.ln("start parsing readme:", structure);
|
||||
var structure = that.config.getStructure('readme');
|
||||
that.log.debug.ln('start parsing readme:', structure);
|
||||
|
||||
return that.findFile(structure)
|
||||
.then(function(readme) {
|
||||
if (!readme) throw "No README file";
|
||||
if (!_.contains(that.files, readme.path)) throw "README file is ignored";
|
||||
if (!readme) throw 'No README file';
|
||||
if (!_.contains(that.files, readme.path)) throw 'README file is ignored';
|
||||
|
||||
that.readmeFile = readme.path;
|
||||
that._defaultsStructure(that.readmeFile);
|
||||
|
||||
that.log.debug.ln("readme located at", that.readmeFile);
|
||||
that.log.debug.ln('readme located at', that.readmeFile);
|
||||
return that.template.renderFile(that.readmeFile)
|
||||
.then(function(content) {
|
||||
return readme.parser.readme(content)
|
||||
.fail(function(err) {
|
||||
throw that.normError(err, {
|
||||
name: err.name || "Readme Parse Error",
|
||||
name: err.name || 'Readme Parse Error',
|
||||
fileName: that.readmeFile
|
||||
});
|
||||
});
|
||||
@@ -395,8 +390,8 @@ Book.prototype.parseReadme = function() {
|
||||
Book.prototype.parseLangs = function() {
|
||||
var that = this;
|
||||
|
||||
var structure = that.config.getStructure("langs");
|
||||
that.log.debug.ln("start parsing languages index:", structure);
|
||||
var structure = that.config.getStructure('langs');
|
||||
that.log.debug.ln('start parsing languages index:', structure);
|
||||
|
||||
return that.findFile(structure)
|
||||
.then(function(langs) {
|
||||
@@ -405,13 +400,13 @@ Book.prototype.parseLangs = function() {
|
||||
that.langsFile = langs.path;
|
||||
that._defaultsStructure(that.langsFile);
|
||||
|
||||
that.log.debug.ln("languages index located at", that.langsFile);
|
||||
that.log.debug.ln('languages index located at', that.langsFile);
|
||||
return that.template.renderFile(that.langsFile)
|
||||
.then(function(content) {
|
||||
return langs.parser.langs(content)
|
||||
.fail(function(err) {
|
||||
throw that.normError(err, {
|
||||
name: err.name || "Langs Parse Error",
|
||||
name: err.name || 'Langs Parse Error',
|
||||
fileName: that.langsFile
|
||||
});
|
||||
});
|
||||
@@ -426,29 +421,29 @@ Book.prototype.parseLangs = function() {
|
||||
Book.prototype.parseSummary = function() {
|
||||
var that = this;
|
||||
|
||||
var structure = that.config.getStructure("summary");
|
||||
that.log.debug.ln("start parsing summary:", structure);
|
||||
var structure = that.config.getStructure('summary');
|
||||
that.log.debug.ln('start parsing summary:', structure);
|
||||
|
||||
return that.findFile(structure)
|
||||
.then(function(summary) {
|
||||
if (!summary) throw "No SUMMARY file";
|
||||
if (!summary) throw 'No SUMMARY file';
|
||||
|
||||
// Remove the summary from the list of files to parse
|
||||
that.summaryFile = summary.path;
|
||||
that._defaultsStructure(that.summaryFile);
|
||||
that.files = _.without(that.files, that.summaryFile);
|
||||
|
||||
that.log.debug.ln("summary located at", that.summaryFile);
|
||||
that.log.debug.ln('summary located at', that.summaryFile);
|
||||
return that.template.renderFile(that.summaryFile)
|
||||
.then(function(content) {
|
||||
return summary.parser.summary(content, {
|
||||
entryPoint: that.readmeFile,
|
||||
entryPointTitle: that.i18n("SUMMARY_INTRODUCTION"),
|
||||
entryPointTitle: that.i18n('SUMMARY_INTRODUCTION'),
|
||||
files: that.files
|
||||
})
|
||||
.fail(function(err) {
|
||||
throw that.normError(err, {
|
||||
name: err.name || "Summary Parse Error",
|
||||
name: err.name || 'Summary Parse Error',
|
||||
fileName: that.summaryFile
|
||||
});
|
||||
});
|
||||
@@ -464,8 +459,8 @@ Book.prototype.parseSummary = function() {
|
||||
Book.prototype.parseGlossary = function() {
|
||||
var that = this;
|
||||
|
||||
var structure = that.config.getStructure("glossary");
|
||||
that.log.debug.ln("start parsing glossary: ", structure);
|
||||
var structure = that.config.getStructure('glossary');
|
||||
that.log.debug.ln('start parsing glossary: ', structure);
|
||||
|
||||
return that.findFile(structure)
|
||||
.then(function(glossary) {
|
||||
@@ -476,13 +471,13 @@ Book.prototype.parseGlossary = function() {
|
||||
that._defaultsStructure(that.glossaryFile);
|
||||
that.files = _.without(that.files, that.glossaryFile);
|
||||
|
||||
that.log.debug.ln("glossary located at", that.glossaryFile);
|
||||
that.log.debug.ln('glossary located at', that.glossaryFile);
|
||||
return that.template.renderFile(that.glossaryFile)
|
||||
.then(function(content) {
|
||||
return glossary.parser.glossary(content)
|
||||
.fail(function(err) {
|
||||
throw that.normError(err, {
|
||||
name: err.name || "Glossary Parse Error",
|
||||
name: err.name || 'Glossary Parse Error',
|
||||
fileName: that.glossaryFile
|
||||
});
|
||||
});
|
||||
@@ -514,12 +509,12 @@ Book.prototype.parsePage = function(filename, options) {
|
||||
});
|
||||
};
|
||||
|
||||
that.log.debug.ln("start parsing file", filename);
|
||||
that.log.debug.ln('start parsing file', filename);
|
||||
|
||||
var extension = path.extname(filename);
|
||||
var filetype = parsers.get(extension);
|
||||
|
||||
if (!filetype) return Q.reject(new Error("Can't parse file: "+filename));
|
||||
if (!filetype) return Q.reject(new Error('Can\'t parse file: '+filename));
|
||||
|
||||
// Type of parser used
|
||||
page.type = filetype.name;
|
||||
@@ -533,7 +528,7 @@ Book.prototype.parsePage = function(filename, options) {
|
||||
// Progress in the book
|
||||
page.progress = parseProgress(that.navigation, filename);
|
||||
|
||||
that.log.debug.ln("render template", filename);
|
||||
that.log.debug.ln('render template', filename);
|
||||
|
||||
// Read file content
|
||||
return that.readFile(page.path)
|
||||
@@ -560,7 +555,7 @@ Book.prototype.parsePage = function(filename, options) {
|
||||
.then(function(content) {
|
||||
page.content = content;
|
||||
|
||||
that.log.debug.ln("use file parser", filetype.name, "for", filename);
|
||||
that.log.debug.ln('use file parser', filetype.name, 'for', filename);
|
||||
return filetype.page(page.content);
|
||||
})
|
||||
|
||||
@@ -568,7 +563,7 @@ Book.prototype.parsePage = function(filename, options) {
|
||||
.then(function(_page) {
|
||||
return _.reduce(_page.sections, function(prev, section) {
|
||||
return prev.then(function(_sections) {
|
||||
return that.template.postProcess(section.content || "")
|
||||
return that.template.postProcess(section.content || '')
|
||||
.then(function(content) {
|
||||
section.content = content;
|
||||
return _sections.concat([section]);
|
||||
@@ -584,8 +579,8 @@ Book.prototype.parsePage = function(filename, options) {
|
||||
convertImages: options.convertImages,
|
||||
input: filename,
|
||||
navigation: that.navigation,
|
||||
base: path.dirname(filename) || "./",
|
||||
output: path.dirname(filename) || "./",
|
||||
base: path.dirname(filename) || './',
|
||||
output: path.dirname(filename) || './',
|
||||
glossary: that.glossary
|
||||
});
|
||||
})
|
||||
@@ -597,7 +592,6 @@ Book.prototype.parsePage = function(filename, options) {
|
||||
})
|
||||
|
||||
.then(function() {
|
||||
that.indexPage(page);
|
||||
return page;
|
||||
});
|
||||
};
|
||||
@@ -625,6 +619,24 @@ Book.prototype.findFile = function(filename) {
|
||||
}, Q(null));
|
||||
};
|
||||
|
||||
// Format a string using a specific markup language
|
||||
Book.prototype.formatString = function(extension, content) {
|
||||
return Q()
|
||||
.then(function() {
|
||||
var filetype = parsers.get(extension);
|
||||
if (!filetype) throw new Error('Filetype doesn\'t exist: '+filetype);
|
||||
|
||||
return filetype.page(content);
|
||||
})
|
||||
|
||||
// Merge sections
|
||||
.then(function(page) {
|
||||
return _.reduce(page.sections, function(content, section) {
|
||||
return content + section.content;
|
||||
}, '');
|
||||
});
|
||||
};
|
||||
|
||||
// Check if a file exists in the book
|
||||
Book.prototype.fileExists = function(filename) {
|
||||
return fs.exists(
|
||||
@@ -641,7 +653,7 @@ Book.prototype.fileIsInBook = function(filename) {
|
||||
Book.prototype.readFile = function(filename) {
|
||||
return fs.readFile(
|
||||
this.resolve(filename),
|
||||
{ encoding: "utf8" }
|
||||
{ encoding: 'utf8' }
|
||||
);
|
||||
};
|
||||
|
||||
@@ -655,28 +667,28 @@ Book.prototype.listAllFiles = function() {
|
||||
var that = this;
|
||||
|
||||
return fs.list(this.root, {
|
||||
ignoreFiles: [".ignore", ".gitignore", ".bookignore"],
|
||||
ignoreFiles: ['.ignore', '.gitignore', '.bookignore'],
|
||||
ignoreRules: [
|
||||
// Skip Git stuff
|
||||
".git/",
|
||||
".gitignore",
|
||||
'.git/',
|
||||
'.gitignore',
|
||||
|
||||
// Skip OS X meta data
|
||||
".DS_Store",
|
||||
'.DS_Store',
|
||||
|
||||
// Skip stuff installed by plugins
|
||||
"node_modules",
|
||||
'node_modules',
|
||||
|
||||
// Skip book outputs
|
||||
"_book",
|
||||
"*.pdf",
|
||||
"*.epub",
|
||||
"*.mobi",
|
||||
'_book',
|
||||
'*.pdf',
|
||||
'*.epub',
|
||||
'*.mobi',
|
||||
|
||||
// Skip config files
|
||||
".ignore",
|
||||
".bookignore",
|
||||
"book.json",
|
||||
'.ignore',
|
||||
'.bookignore',
|
||||
'book.json',
|
||||
]
|
||||
})
|
||||
.then(function(_files) {
|
||||
@@ -695,7 +707,7 @@ Book.prototype.parentRoot = function() {
|
||||
return this.root;
|
||||
};
|
||||
|
||||
// Return true if it"s a sub-book
|
||||
// Return true if it's a sub-book
|
||||
Book.prototype.isSubBook = function() {
|
||||
return !!this.parent;
|
||||
};
|
||||
@@ -724,13 +736,13 @@ Book.prototype.relative = function(p) {
|
||||
// Normalize a path to .html and convert README -> index
|
||||
Book.prototype.contentPath = function(link) {
|
||||
if (
|
||||
path.basename(link, path.extname(link)) == "README" ||
|
||||
path.basename(link, path.extname(link)) == 'README' ||
|
||||
link == this.readmeFile
|
||||
) {
|
||||
link = path.join(path.dirname(link), "index"+path.extname(link));
|
||||
link = path.join(path.dirname(link), 'index'+path.extname(link));
|
||||
}
|
||||
|
||||
link = links.changeExtension(link, ".html");
|
||||
link = links.changeExtension(link, '.html');
|
||||
return link;
|
||||
};
|
||||
|
||||
@@ -739,40 +751,15 @@ Book.prototype.contentLink = function(link) {
|
||||
return links.normalize(this.contentPath(link));
|
||||
};
|
||||
|
||||
// Index a page into the search index
|
||||
Book.prototype.indexPage = function(page) {
|
||||
var nav = this.navigation[page.path];
|
||||
if (!nav || !this.searchIndexEnabled) return;
|
||||
|
||||
this.log.debug.ln("index page", page.path);
|
||||
|
||||
// Extract text from the page
|
||||
var text = pageUtil.extractText(page.sections);
|
||||
|
||||
// Limit size of index (to avoid #941)
|
||||
this.searchIndexSize = this.searchIndexSize + text.length;
|
||||
if (this.searchIndexSize > SEARCHINDEX_MAXSIZE) {
|
||||
this.log.warn.ln("search index is too big, indexing is now disabled");
|
||||
this.searchIndexEnabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this.searchIndex.add({
|
||||
url: this.contentLink(page.path),
|
||||
title: nav.title,
|
||||
body: text
|
||||
});
|
||||
};
|
||||
|
||||
// Default structure paths to an extension
|
||||
Book.prototype._defaultsStructure = function(filename) {
|
||||
var that = this;
|
||||
var extension = path.extname(filename);
|
||||
|
||||
that.readmeFile = that.readmeFile || that.config.getStructure("readme")+extension;
|
||||
that.summaryFile = that.summaryFile || that.config.getStructure("summary")+extension;
|
||||
that.glossaryFile = that.glossaryFile || that.config.getStructure("glossary")+extension;
|
||||
that.langsFile = that.langsFile || that.config.getStructure("langs")+extension;
|
||||
that.readmeFile = that.readmeFile || that.config.getStructure('readme')+extension;
|
||||
that.summaryFile = that.summaryFile || that.config.getStructure('summary')+extension;
|
||||
that.glossaryFile = that.glossaryFile || that.config.getStructure('glossary')+extension;
|
||||
that.langsFile = that.langsFile || that.config.getStructure('langs')+extension;
|
||||
};
|
||||
|
||||
// Change output path
|
||||
@@ -805,87 +792,18 @@ Book.prototype.normError = function(err, opts, defs) {
|
||||
err.toString = function() {
|
||||
var attributes = [];
|
||||
|
||||
if (this.fileName) attributes.push("In file \""+this.fileName+"\"");
|
||||
if (this.lineNumber) attributes.push("Line "+this.lineNumber);
|
||||
if (this.columnNumber) attributes.push("Column "+this.columnNumber);
|
||||
return (this.name || "Error")+": "+this.message+((attributes.length > 0)? " ("+attributes.join(", ")+")" : "");
|
||||
if (this.fileName) attributes.push('In file \''+this.fileName+'\'');
|
||||
if (this.lineNumber) attributes.push('Line '+this.lineNumber);
|
||||
if (this.columnNumber) attributes.push('Column '+this.columnNumber);
|
||||
return (this.name || 'Error')+': '+this.message+((attributes.length > 0)? ' ('+attributes.join(', ')+')' : '');
|
||||
};
|
||||
|
||||
return err;
|
||||
};
|
||||
|
||||
// Init and return a book
|
||||
Book.init = function(root, opts) {
|
||||
var book = new Book(root, opts);
|
||||
var extensionToUse = ".md";
|
||||
|
||||
var chaptersPaths = function(chapters) {
|
||||
return _.reduce(chapters || [], function(accu, chapter) {
|
||||
var o = {
|
||||
title: chapter.title
|
||||
};
|
||||
if (chapter.path) o.path = chapter.path;
|
||||
|
||||
return accu.concat(
|
||||
[o].concat(chaptersPaths(chapter.articles))
|
||||
);
|
||||
}, []);
|
||||
};
|
||||
|
||||
book.log.info.ln("init book at", root);
|
||||
return fs.mkdirp(root)
|
||||
.then(function() {
|
||||
book.log.info.ln("detect structure from SUMMARY (if it exists)");
|
||||
return book.parseSummary();
|
||||
})
|
||||
.fail(function() {
|
||||
return Q();
|
||||
})
|
||||
.then(function() {
|
||||
var summary = book.summaryFile || "SUMMARY.md";
|
||||
var chapters = book.summary.chapters || [];
|
||||
extensionToUse = path.extname(summary);
|
||||
|
||||
if (chapters.length === 0) {
|
||||
chapters = [
|
||||
{
|
||||
title: "Summary",
|
||||
path: "SUMMARY"+extensionToUse
|
||||
},
|
||||
{
|
||||
title: "Introduction",
|
||||
path: "README"+extensionToUse
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
return Q(chaptersPaths(chapters));
|
||||
})
|
||||
.then(function(chapters) {
|
||||
// Create files that don"t exist
|
||||
return Q.all(_.map(chapters, function(chapter) {
|
||||
if (!chapter.path) return Q();
|
||||
var absolutePath = path.resolve(book.root, chapter.path);
|
||||
|
||||
return fs.exists(absolutePath)
|
||||
.then(function(exists) {
|
||||
if(exists) {
|
||||
book.log.info.ln("found", chapter.path);
|
||||
return;
|
||||
} else {
|
||||
book.log.info.ln("create", chapter.path);
|
||||
}
|
||||
|
||||
return fs.mkdirp(path.dirname(absolutePath))
|
||||
.then(function() {
|
||||
return fs.writeFile(absolutePath, "# "+chapter.title+"\n");
|
||||
});
|
||||
});
|
||||
}));
|
||||
})
|
||||
.then(function() {
|
||||
book.log.info.ln("initialization is finished");
|
||||
});
|
||||
// Call a hook in plugins
|
||||
Book.prototype.callHook = function(name, data) {
|
||||
return this.plugins.hook(name, data);
|
||||
};
|
||||
|
||||
module.exports= Book;
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
var path = require('path');
|
||||
|
||||
module.exports = {
|
||||
// Options that can't be extend
|
||||
'configFile': 'book',
|
||||
'generator': 'website',
|
||||
'extension': null,
|
||||
|
||||
// Book metadats (somes are extracted from the README by default)
|
||||
'title': null,
|
||||
'description': null,
|
||||
'isbn': null,
|
||||
'language': 'en',
|
||||
'direction': null,
|
||||
'author': null,
|
||||
|
||||
// version of gitbook to use
|
||||
'gitbook': '*',
|
||||
|
||||
// Structure
|
||||
'structure': {
|
||||
'langs': 'LANGS.md',
|
||||
'readme': 'README.md',
|
||||
'glossary': 'GLOSSARY.md',
|
||||
'summary': 'SUMMARY.md'
|
||||
},
|
||||
|
||||
// CSS Styles
|
||||
'styles': {
|
||||
'website': 'styles/website.css',
|
||||
'print': 'styles/print.css',
|
||||
'ebook': 'styles/ebook.css',
|
||||
'pdf': 'styles/pdf.css',
|
||||
'mobi': 'styles/mobi.css',
|
||||
'epub': 'styles/epub.css'
|
||||
},
|
||||
|
||||
// Plugins list, can contain '-name' for removing default plugins
|
||||
'plugins': [],
|
||||
|
||||
// Global configuration for plugins
|
||||
'pluginsConfig': {},
|
||||
|
||||
// Variables for templating
|
||||
'variables': {},
|
||||
|
||||
// Set another theme with your own layout
|
||||
// It's recommended to use plugins or add more options for default theme, though
|
||||
// See https://github.com/GitbookIO/gitbook/issues/209
|
||||
'theme': path.resolve(__dirname, '../theme'),
|
||||
|
||||
// Links in template (null: default, false: remove, string: new value)
|
||||
'links': {
|
||||
// Custom links at top of sidebar
|
||||
'sidebar': {
|
||||
// 'Custom link name': 'https://customlink.com'
|
||||
},
|
||||
|
||||
// Sharing links
|
||||
'sharing': {
|
||||
'google': null,
|
||||
'facebook': null,
|
||||
'twitter': null,
|
||||
'weibo': null,
|
||||
'all': null
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// Options for PDF generation
|
||||
'pdf': {
|
||||
// Add toc at the end of the file
|
||||
'toc': true,
|
||||
|
||||
// Add page numbers to the bottom of every page
|
||||
'pageNumbers': false,
|
||||
|
||||
// Font size for the file content
|
||||
'fontSize': 12,
|
||||
|
||||
// Paper size for the pdf
|
||||
// Choices are [u’a0’, u’a1’, u’a2’, u’a3’, u’a4’, u’a5’, u’a6’, u’b0’, u’b1’, u’b2’, u’b3’, u’b4’, u’b5’, u’b6’, u’legal’, u’letter’]
|
||||
'paperSize': 'a4',
|
||||
|
||||
// How to mark detected chapters.
|
||||
// Choices are “pagebreak”, “rule”, 'both' or “none”.
|
||||
'chapterMark' : 'pagebreak',
|
||||
|
||||
// An XPath expression. Page breaks are inserted before the specified elements.
|
||||
// To disable use the expression: '/'
|
||||
'pageBreaksBefore': '/',
|
||||
|
||||
// Margin (in pts)
|
||||
// Note: 72 pts equals 1 inch
|
||||
'margin': {
|
||||
'right': 62,
|
||||
'left': 62,
|
||||
'top': 56,
|
||||
'bottom': 56
|
||||
},
|
||||
|
||||
// Header HTML template. Available variables: _PAGENUM_, _TITLE_, _AUTHOR_ and _SECTION_.
|
||||
'headerTemplate': null,
|
||||
|
||||
// Footer HTML template. Available variables: _PAGENUM_, _TITLE_, _AUTHOR_ and _SECTION_.
|
||||
'footerTemplate': null
|
||||
}
|
||||
};
|
||||
+50
-144
@@ -1,13 +1,16 @@
|
||||
var _ = require("lodash");
|
||||
var Q = require("q");
|
||||
var path = require("path");
|
||||
var semver = require("semver");
|
||||
var _ = require('lodash');
|
||||
var Q = require('q');
|
||||
var path = require('path');
|
||||
var semver = require('semver');
|
||||
|
||||
var pkg = require("../package.json");
|
||||
var i18n = require("./utils/i18n");
|
||||
var pkg = require('../package.json');
|
||||
var i18n = require('./utils/i18n');
|
||||
var version = require('./version');
|
||||
|
||||
var DEFAULT_CONFIG = require('./config_default');
|
||||
|
||||
// Default plugins added to each books
|
||||
var DEFAULT_PLUGINS = ["highlight"];
|
||||
var DEFAULT_PLUGINS = ['highlight', 'search', 'sharing', 'fontsettings'];
|
||||
|
||||
// Check if a plugin is a default plugin
|
||||
// Plugin should be in the list
|
||||
@@ -26,29 +29,29 @@ function isDefaultPlugin(name, version) {
|
||||
// Normalize a list of plugins to use
|
||||
function normalizePluginsList(plugins, addDefaults) {
|
||||
// Normalize list to an array
|
||||
plugins = _.isString(plugins) ? plugins.split(",") : (plugins || []);
|
||||
plugins = _.isString(plugins) ? plugins.split(',') : (plugins || []);
|
||||
|
||||
// Remove empty parts
|
||||
plugins = _.compact(plugins);
|
||||
|
||||
// Divide as {name, version} to handle format like "myplugin@1.0.0"
|
||||
// Divide as {name, version} to handle format like 'myplugin@1.0.0'
|
||||
plugins = _.map(plugins, function(plugin) {
|
||||
if (plugin.name) return plugin;
|
||||
|
||||
var parts = plugin.split("@");
|
||||
var parts = plugin.split('@');
|
||||
var name = parts[0];
|
||||
var version = parts[1];
|
||||
return {
|
||||
"name": name,
|
||||
"version": version, // optional
|
||||
"isDefault": isDefaultPlugin(name, version)
|
||||
'name': name,
|
||||
'version': version, // optional
|
||||
'isDefault': isDefaultPlugin(name, version)
|
||||
};
|
||||
});
|
||||
|
||||
// List plugins to remove
|
||||
var toremove = _.chain(plugins)
|
||||
.filter(function(plugin) {
|
||||
return plugin.name.length > 0 && plugin.name[0] == "-";
|
||||
return plugin.name.length > 0 && plugin.name[0] == '-';
|
||||
})
|
||||
.map(function(plugin) {
|
||||
return plugin.name.slice(1);
|
||||
@@ -63,15 +66,15 @@ function normalizePluginsList(plugins, addDefaults) {
|
||||
}
|
||||
|
||||
plugins.push({
|
||||
"name": plugin,
|
||||
"isDefault": true
|
||||
'name': plugin,
|
||||
'isDefault': true
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Remove plugin that start with '-'
|
||||
plugins = _.filter(plugins, function(plugin) {
|
||||
return !_.contains(toremove, plugin.name) && !(plugin.name.length > 0 && plugin.name[0] == "-");
|
||||
return !_.contains(toremove, plugin.name) && !(plugin.name.length > 0 && plugin.name[0] == '-');
|
||||
});
|
||||
|
||||
// Remove duplicates
|
||||
@@ -84,26 +87,24 @@ var Configuration = function(book, options) {
|
||||
var that = this;
|
||||
|
||||
this.book = book;
|
||||
|
||||
this.options = _.cloneDeep(Configuration.DEFAULT);
|
||||
this.options = _.merge(this.options, options || {});
|
||||
this.replace(options);
|
||||
|
||||
// options.input == book.root
|
||||
Object.defineProperty(this.options, "input", {
|
||||
Object.defineProperty(this.options, 'input', {
|
||||
get: function () {
|
||||
return that.book.root;
|
||||
}
|
||||
});
|
||||
|
||||
// options.originalInput == book.parent.root
|
||||
Object.defineProperty(this.options, "originalInput", {
|
||||
Object.defineProperty(this.options, 'originalInput', {
|
||||
get: function () {
|
||||
return that.book.parent? that.book.parent.root : undefined;
|
||||
}
|
||||
});
|
||||
|
||||
// options.originalOutput == book.parent.options.output
|
||||
Object.defineProperty(this.options, "originalOutput", {
|
||||
Object.defineProperty(this.options, 'originalOutput', {
|
||||
get: function () {
|
||||
return that.book.parent? that.book.parent.options.output : undefined;
|
||||
}
|
||||
@@ -129,7 +130,7 @@ Configuration.prototype.load = function() {
|
||||
_config = require(configPath);
|
||||
that.options = _.merge(
|
||||
that.options,
|
||||
_.omit(_config, "configFile", "defaultsPlugins", "generator", "extension")
|
||||
_.omit(_config, 'configFile', 'defaultsPlugins', 'generator', 'extension')
|
||||
);
|
||||
}
|
||||
catch(err) {
|
||||
@@ -139,19 +140,19 @@ Configuration.prototype.load = function() {
|
||||
})
|
||||
.then(function() {
|
||||
if (!that.book.isSubBook()) {
|
||||
if (!semver.satisfies(pkg.version, that.options.gitbook)) {
|
||||
throw new Error("GitBook version doesn't satisfy version required by the book: "+that.options.gitbook);
|
||||
if (!version.satisfies(that.options.gitbook)) {
|
||||
throw new Error('GitBook version doesn\'t satisfy version required by the book: '+that.options.gitbook);
|
||||
}
|
||||
if (that.options.gitbook != "*" && !semver.satisfies(semver.inc(pkg.version, "patch"), that.options.gitbook)) {
|
||||
that.book.log.warn.ln("gitbook version specified in your book.json might be too strict for future patches, \""+(_.first(pkg.version.split("."))+".x.x")+"\" is more adequate");
|
||||
if (that.options.gitbook != '*' && !semver.satisfies(semver.inc(pkg.version, 'patch'), that.options.gitbook)) {
|
||||
that.book.log.warn.ln('gitbook version specified in your book.json might be too strict for future patches, \''+(_.first(pkg.version.split('.'))+'.x.x')+'\' is more adequate');
|
||||
}
|
||||
}
|
||||
|
||||
that.options.output = path.resolve(that.options.output || that.book.resolve("_book"));
|
||||
that.options.output = path.resolve(that.options.output || that.book.resolve('_book'));
|
||||
that.options.plugins = normalizePluginsList(that.options.plugins);
|
||||
that.options.defaultsPlugins = normalizePluginsList(that.options.defaultsPlugins || "", false);
|
||||
that.options.defaultsPlugins = normalizePluginsList(that.options.defaultsPlugins || '', false);
|
||||
that.options.plugins = _.union(that.options.plugins, that.options.defaultsPlugins);
|
||||
that.options.plugins = _.uniq(that.options.plugins, "name");
|
||||
that.options.plugins = _.uniq(that.options.plugins, 'name');
|
||||
|
||||
// Default value for text direction (from language)
|
||||
if (!that.options.direction) {
|
||||
@@ -168,9 +169,20 @@ Configuration.prototype.extend = function(options) {
|
||||
_.extend(this.options, options);
|
||||
};
|
||||
|
||||
// Replace the whole configuration
|
||||
Configuration.prototype.replace = function(options) {
|
||||
this.options = _.cloneDeep(DEFAULT_CONFIG);
|
||||
this.options = _.merge(this.options, options || {});
|
||||
};
|
||||
|
||||
// Dump configuration as json object
|
||||
Configuration.prototype.dump = function() {
|
||||
return _.cloneDeep(this.options);
|
||||
};
|
||||
|
||||
// Get structure file
|
||||
Configuration.prototype.getStructure = function(name) {
|
||||
return this.options.structure[name].split(".").slice(0, -1).join(".");
|
||||
return this.options.structure[name].split('.').slice(0, -1).join('.');
|
||||
};
|
||||
|
||||
// Return normalized language
|
||||
@@ -183,118 +195,12 @@ Configuration.prototype.get = function(key, def) {
|
||||
return _.get(this.options, key, def);
|
||||
};
|
||||
|
||||
// Default configuration
|
||||
Configuration.DEFAULT = {
|
||||
// Options that can"t be extend
|
||||
"configFile": "book",
|
||||
"generator": "website",
|
||||
"extension": null,
|
||||
|
||||
// Book metadats (somes are extracted from the README by default)
|
||||
"title": null,
|
||||
"description": null,
|
||||
"isbn": null,
|
||||
"language": "en",
|
||||
"direction": null,
|
||||
"author": null,
|
||||
|
||||
// version of gitbook to use
|
||||
"gitbook": "*",
|
||||
|
||||
// Structure
|
||||
"structure": {
|
||||
"langs": "LANGS.md",
|
||||
"readme": "README.md",
|
||||
"glossary": "GLOSSARY.md",
|
||||
"summary": "SUMMARY.md"
|
||||
},
|
||||
|
||||
// CSS Styles
|
||||
"styles": {
|
||||
"website": "styles/website.css",
|
||||
"print": "styles/print.css",
|
||||
"ebook": "styles/ebook.css",
|
||||
"pdf": "styles/pdf.css",
|
||||
"mobi": "styles/mobi.css",
|
||||
"epub": "styles/epub.css"
|
||||
},
|
||||
|
||||
// Plugins list, can contain "-name" for removing default plugins
|
||||
"plugins": [],
|
||||
|
||||
// Global configuration for plugins
|
||||
"pluginsConfig": {
|
||||
"fontSettings": {
|
||||
"theme": null, //"sepia", "night" or "white",
|
||||
"family": "sans",// "serif" or "sans",
|
||||
"size": 2 // 1 - 4
|
||||
}
|
||||
},
|
||||
|
||||
// Variables for templating
|
||||
"variables": {},
|
||||
|
||||
// Set another theme with your own layout
|
||||
// It"s recommended to use plugins or add more options for default theme, though
|
||||
// See https://github.com/GitbookIO/gitbook/issues/209
|
||||
"theme": path.resolve(__dirname, "../theme"),
|
||||
|
||||
// Links in template (null: default, false: remove, string: new value)
|
||||
"links": {
|
||||
// Custom links at top of sidebar
|
||||
"sidebar": {
|
||||
//"Custom link name": "https://customlink.com"
|
||||
},
|
||||
|
||||
// Sharing links
|
||||
"sharing": {
|
||||
"google": null,
|
||||
"facebook": null,
|
||||
"twitter": null,
|
||||
"weibo": null,
|
||||
"all": null
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// Options for PDF generation
|
||||
"pdf": {
|
||||
// Add toc at the end of the file
|
||||
"toc": true,
|
||||
|
||||
// Add page numbers to the bottom of every page
|
||||
"pageNumbers": false,
|
||||
|
||||
// Font size for the file content
|
||||
"fontSize": 12,
|
||||
|
||||
// Paper size for the pdf
|
||||
// Choices are [u’a0’, u’a1’, u’a2’, u’a3’, u’a4’, u’a5’, u’a6’, u’b0’, u’b1’, u’b2’, u’b3’, u’b4’, u’b5’, u’b6’, u’legal’, u’letter’]
|
||||
"paperSize": "a4",
|
||||
|
||||
// How to mark detected chapters.
|
||||
// Choices are “pagebreak”, “rule”, "both" or “none”.
|
||||
"chapterMark" : "pagebreak",
|
||||
|
||||
// An XPath expression. Page breaks are inserted before the specified elements.
|
||||
// To disable use the expression: "/"
|
||||
"pageBreaksBefore": "/",
|
||||
|
||||
// Margin (in pts)
|
||||
// Note: 72 pts equals 1 inch
|
||||
"margin": {
|
||||
"right": 62,
|
||||
"left": 62,
|
||||
"top": 56,
|
||||
"bottom": 56
|
||||
},
|
||||
|
||||
//Header HTML template. Available variables: _PAGENUM_, _TITLE_, _AUTHOR_ and _SECTION_.
|
||||
"headerTemplate": "",
|
||||
|
||||
//Footer HTML template. Available variables: _PAGENUM_, _TITLE_, _AUTHOR_ and _SECTION_.
|
||||
"footerTemplate": ""
|
||||
}
|
||||
// Update a configuration
|
||||
Configuration.prototype.set = function(key, value) {
|
||||
return _.set(this.options, key, value);
|
||||
};
|
||||
|
||||
// Default configuration
|
||||
Configuration.DEFAULT = DEFAULT_CONFIG;
|
||||
|
||||
module.exports= Configuration;
|
||||
|
||||
+13
-13
@@ -1,12 +1,12 @@
|
||||
var _ = require("lodash");
|
||||
var path = require("path");
|
||||
var Q = require("q");
|
||||
var fs = require("./utils/fs");
|
||||
var _ = require('lodash');
|
||||
var path = require('path');
|
||||
var Q = require('q');
|
||||
var fs = require('./utils/fs');
|
||||
|
||||
var BaseGenerator = function(book) {
|
||||
this.book = book;
|
||||
|
||||
Object.defineProperty(this, "options", {
|
||||
Object.defineProperty(this, 'options', {
|
||||
get: function () {
|
||||
return this.book.options;
|
||||
}
|
||||
@@ -16,19 +16,19 @@ var BaseGenerator = function(book) {
|
||||
};
|
||||
|
||||
BaseGenerator.prototype.callHook = function(name, data) {
|
||||
return this.book.plugins.hook(name, data);
|
||||
return this.book.callHook(name, data);
|
||||
};
|
||||
|
||||
// Prepare the genertor
|
||||
BaseGenerator.prototype.prepare = function() {
|
||||
var that = this;
|
||||
|
||||
return that.callHook("init");
|
||||
return that.callHook('init');
|
||||
};
|
||||
|
||||
// Write a parsed file to the output
|
||||
BaseGenerator.prototype.convertFile = function(input) {
|
||||
return Q.reject(new Error("Could not convert "+input));
|
||||
return Q.reject(new Error('Could not convert '+input));
|
||||
};
|
||||
|
||||
// Copy file to the output (non parsable)
|
||||
@@ -51,16 +51,16 @@ BaseGenerator.prototype.copyCover = function() {
|
||||
var that = this;
|
||||
|
||||
return Q.all([
|
||||
fs.copy(that.book.resolve("cover.jpg"), path.join(that.options.output, "cover.jpg")),
|
||||
fs.copy(that.book.resolve("cover_small.jpg"), path.join(that.options.output, "cover_small.jpg"))
|
||||
fs.copy(that.book.resolve('cover.jpg'), path.join(that.options.output, 'cover.jpg')),
|
||||
fs.copy(that.book.resolve('cover_small.jpg'), path.join(that.options.output, 'cover_small.jpg'))
|
||||
])
|
||||
.fail(function() {
|
||||
// If orignaly from multi-lang, try copy from parent
|
||||
if (!that.book.isSubBook()) return;
|
||||
|
||||
return Q.all([
|
||||
fs.copy(path.join(that.book.parentRoot(), "cover.jpg"), path.join(that.options.output, "cover.jpg")),
|
||||
fs.copy(path.join(that.book.parentRoot(), "cover_small.jpg"), path.join(that.options.output, "cover_small.jpg"))
|
||||
fs.copy(path.join(that.book.parentRoot(), 'cover.jpg'), path.join(that.options.output, 'cover.jpg')),
|
||||
fs.copy(path.join(that.book.parentRoot(), 'cover_small.jpg'), path.join(that.options.output, 'cover_small.jpg'))
|
||||
]);
|
||||
})
|
||||
.fail(function() {
|
||||
@@ -70,7 +70,7 @@ BaseGenerator.prototype.copyCover = function() {
|
||||
|
||||
// At teh end of the generation
|
||||
BaseGenerator.prototype.finish = function() {
|
||||
return Q.reject(new Error("Could not finish generation"));
|
||||
return Q.reject(new Error('Could not finish generation'));
|
||||
};
|
||||
|
||||
module.exports = BaseGenerator;
|
||||
|
||||
+88
-56
@@ -1,12 +1,13 @@
|
||||
var util = require("util");
|
||||
var path = require("path");
|
||||
var Q = require("q");
|
||||
var _ = require("lodash");
|
||||
var exec = require("child_process").exec;
|
||||
var util = require('util');
|
||||
var path = require('path');
|
||||
var Q = require('q');
|
||||
var _ = require('lodash');
|
||||
var juice = require('juice');
|
||||
var exec = require('child_process').exec;
|
||||
|
||||
var fs = require("../utils/fs");
|
||||
var stringUtils = require("../utils/string");
|
||||
var BaseGenerator = require("./website");
|
||||
var fs = require('../utils/fs');
|
||||
var stringUtils = require('../utils/string');
|
||||
var BaseGenerator = require('./website');
|
||||
|
||||
var Generator = function(book, format) {
|
||||
BaseGenerator.apply(this, arguments);
|
||||
@@ -15,10 +16,10 @@ var Generator = function(book, format) {
|
||||
this.ebookFormat = format;
|
||||
|
||||
// Resources namespace
|
||||
this.namespace = "ebook";
|
||||
this.namespace = 'ebook';
|
||||
|
||||
// Styles to use
|
||||
this.styles = _.compact(["print", "ebook", this.ebookFormat]);
|
||||
this.styles = _.compact(['print', 'ebook', this.ebookFormat]);
|
||||
|
||||
// Convert images (svg -> png)
|
||||
this.convertImages = true;
|
||||
@@ -26,9 +27,9 @@ var Generator = function(book, format) {
|
||||
util.inherits(Generator, BaseGenerator);
|
||||
|
||||
Generator.prototype.prepareTemplates = function() {
|
||||
this.templates.page = this.book.plugins.template("ebook:page") || path.resolve(this.options.theme, "templates/ebook/page.html");
|
||||
this.templates.summary = this.book.plugins.template("ebook:summary") || path.resolve(this.options.theme, "templates/ebook/summary.html");
|
||||
this.templates.glossary = this.book.plugins.template("ebook:glossary") || path.resolve(this.options.theme, "templates/ebook/glossary.html");
|
||||
this.templates.page = this.book.plugins.template('ebook:page') || path.resolve(this.options.theme, 'templates/ebook/page.html');
|
||||
this.templates.summary = this.book.plugins.template('ebook:summary') || path.resolve(this.options.theme, 'templates/ebook/summary.html');
|
||||
this.templates.glossary = this.book.plugins.template('ebook:glossary') || path.resolve(this.options.theme, 'templates/ebook/glossary.html');
|
||||
|
||||
return Q();
|
||||
};
|
||||
@@ -37,8 +38,39 @@ Generator.prototype.prepareTemplates = function() {
|
||||
Generator.prototype.writeSummary = function() {
|
||||
var that = this;
|
||||
|
||||
that.book.log.info.ln("write SUMMARY.html");
|
||||
return this._writeTemplate(this.templates.summary, {}, path.join(this.options.output, "SUMMARY.html"));
|
||||
that.book.log.info.ln('write SUMMARY.html');
|
||||
return this._writeTemplate(this.templates.summary, {}, path.join(this.options.output, 'SUMMARY.html'));
|
||||
};
|
||||
|
||||
// Return template for footer/header with inlined css
|
||||
Generator.prototype.getPDFTemplate = function(id) {
|
||||
var tpl = this.options.pdf[id+'Template'];
|
||||
var defaultTpl = path.resolve(this.options.theme, 'templates/ebook/'+id+'.html');
|
||||
var defaultCSS = path.resolve(this.options.theme, 'assets/pdf.css');
|
||||
|
||||
// Default template from theme
|
||||
if (!tpl && fs.existsSync(defaultTpl)) {
|
||||
tpl = fs.readFileSync(defaultTpl, { encoding: 'utf-8' });
|
||||
}
|
||||
|
||||
// Inline CSS using juice
|
||||
var stylesheets = [];
|
||||
|
||||
// From theme
|
||||
if (fs.existsSync(defaultCSS)) {
|
||||
stylesheets.push(fs.readFileSync(defaultCSS, { encoding: 'utf-8' }));
|
||||
}
|
||||
|
||||
// Custom PDF style
|
||||
if (this.styles.pdf) {
|
||||
stylesheets.push(fs.readFileSync(this.book.resolve(this.styles.pdf), { encoding: 'utf-8' }));
|
||||
}
|
||||
|
||||
tpl = juice(tpl, {
|
||||
extraCss: stylesheets.concat('/n')
|
||||
});
|
||||
|
||||
return tpl;
|
||||
};
|
||||
|
||||
Generator.prototype.finish = function() {
|
||||
@@ -52,70 +84,70 @@ Generator.prototype.finish = function() {
|
||||
.then(function() {
|
||||
if (!that.ebookFormat) return Q();
|
||||
|
||||
if (!that.options.cover && fs.existsSync(path.join(that.options.output, "cover.jpg"))) {
|
||||
that.options.cover = path.join(that.options.output, "cover.jpg");
|
||||
if (!that.options.cover && fs.existsSync(path.join(that.options.output, 'cover.jpg'))) {
|
||||
that.options.cover = path.join(that.options.output, 'cover.jpg');
|
||||
}
|
||||
|
||||
var d = Q.defer();
|
||||
|
||||
var _options = {
|
||||
"--cover": that.options.cover,
|
||||
"--title": that.options.title,
|
||||
"--comments": that.options.description,
|
||||
"--isbn": that.options.isbn,
|
||||
"--authors": that.options.author,
|
||||
"--language": that.options.language,
|
||||
"--book-producer": "GitBook",
|
||||
"--publisher": "GitBook",
|
||||
"--chapter": "descendant-or-self::*[contains(concat(' ', normalize-space(@class), ' '), ' book-chapter ')]",
|
||||
"--level1-toc": "descendant-or-self::*[contains(concat(' ', normalize-space(@class), ' '), ' book-chapter-1 ')]",
|
||||
"--level2-toc": "descendant-or-self::*[contains(concat(' ', normalize-space(@class), ' '), ' book-chapter-2 ')]",
|
||||
"--level3-toc": "descendant-or-self::*[contains(concat(' ', normalize-space(@class), ' '), ' book-chapter-3 ')]",
|
||||
"--no-chapters-in-toc": true,
|
||||
"--max-levels": "1",
|
||||
"--breadth-first": true
|
||||
'--cover': that.options.cover,
|
||||
'--title': that.options.title,
|
||||
'--comments': that.options.description,
|
||||
'--isbn': that.options.isbn,
|
||||
'--authors': that.options.author,
|
||||
'--language': that.options.language,
|
||||
'--book-producer': 'GitBook',
|
||||
'--publisher': 'GitBook',
|
||||
'--chapter': 'descendant-or-self::*[contains(concat(\' \', normalize-space(@class), \' \'), \' book-chapter \')]',
|
||||
'--level1-toc': 'descendant-or-self::*[contains(concat(\' \', normalize-space(@class), \' \'), \' book-chapter-1 \')]',
|
||||
'--level2-toc': 'descendant-or-self::*[contains(concat(\' \', normalize-space(@class), \' \'), \' book-chapter-2 \')]',
|
||||
'--level3-toc': 'descendant-or-self::*[contains(concat(\' \', normalize-space(@class), \' \'), \' book-chapter-3 \')]',
|
||||
'--no-chapters-in-toc': true,
|
||||
'--max-levels': '1',
|
||||
'--breadth-first': true
|
||||
};
|
||||
|
||||
if (that.ebookFormat == "pdf") {
|
||||
if (that.ebookFormat == 'pdf') {
|
||||
var pdfOptions = that.options.pdf;
|
||||
|
||||
_.extend(_options, {
|
||||
"--chapter-mark": String(pdfOptions.chapterMark),
|
||||
"--page-breaks-before": String(pdfOptions.pageBreaksBefore),
|
||||
"--margin-left": String(pdfOptions.margin.left),
|
||||
"--margin-right": String(pdfOptions.margin.right),
|
||||
"--margin-top": String(pdfOptions.margin.top),
|
||||
"--margin-bottom": String(pdfOptions.margin.bottom),
|
||||
"--pdf-default-font-size": String(pdfOptions.fontSize),
|
||||
"--pdf-mono-font-size": String(pdfOptions.fontSize),
|
||||
"--paper-size": String(pdfOptions.paperSize),
|
||||
"--pdf-page-numbers": Boolean(pdfOptions.pageNumbers),
|
||||
"--pdf-header-template": String(pdfOptions.headerTemplate) || "<p class='header'><span>"+that.options.title+"</span></p>",
|
||||
"--pdf-footer-template": String(pdfOptions.footerTemplate) || "<p class='footer'><span>_SECTION_</span> <span style='float:right;'>_PAGENUM_</span></p>"
|
||||
'--chapter-mark': String(pdfOptions.chapterMark),
|
||||
'--page-breaks-before': String(pdfOptions.pageBreaksBefore),
|
||||
'--margin-left': String(pdfOptions.margin.left),
|
||||
'--margin-right': String(pdfOptions.margin.right),
|
||||
'--margin-top': String(pdfOptions.margin.top),
|
||||
'--margin-bottom': String(pdfOptions.margin.bottom),
|
||||
'--pdf-default-font-size': String(pdfOptions.fontSize),
|
||||
'--pdf-mono-font-size': String(pdfOptions.fontSize),
|
||||
'--paper-size': String(pdfOptions.paperSize),
|
||||
'--pdf-page-numbers': Boolean(pdfOptions.pageNumbers),
|
||||
'--pdf-header-template': that.getPDFTemplate('header'),
|
||||
'--pdf-footer-template': that.getPDFTemplate('footer')
|
||||
});
|
||||
} else if (that.ebookFormat == "epub") {
|
||||
} else if (that.ebookFormat == 'epub') {
|
||||
_.extend(_options, {
|
||||
"--dont-split-on-page-breaks": true
|
||||
'--dont-split-on-page-breaks': true
|
||||
});
|
||||
}
|
||||
|
||||
var command = [
|
||||
"ebook-convert",
|
||||
path.join(that.options.output, "SUMMARY.html"),
|
||||
path.join(that.options.output, "index."+that.ebookFormat),
|
||||
'ebook-convert',
|
||||
path.join(that.options.output, 'SUMMARY.html'),
|
||||
path.join(that.options.output, 'index.'+that.ebookFormat),
|
||||
stringUtils.optionsToShellArgs(_options)
|
||||
].join(" ");
|
||||
].join(' ');
|
||||
|
||||
that.book.log.info("start conversion to", that.ebookFormat, "....");
|
||||
that.book.log.info('start conversion to', that.ebookFormat, '....');
|
||||
|
||||
var child = exec(command, function (error, stdout) {
|
||||
if (error) {
|
||||
that.book.log.info.fail();
|
||||
|
||||
if (error.code == 127) {
|
||||
error.message = "Need to install ebook-convert from Calibre";
|
||||
error.message = 'Need to install ebook-convert from Calibre';
|
||||
} else {
|
||||
error.message = error.message + " "+stdout;
|
||||
error.message = error.message + ' '+stdout;
|
||||
}
|
||||
return d.reject(error);
|
||||
}
|
||||
@@ -124,11 +156,11 @@ Generator.prototype.finish = function() {
|
||||
d.resolve();
|
||||
});
|
||||
|
||||
child.stdout.on("data", function (data) {
|
||||
child.stdout.on('data', function (data) {
|
||||
that.book.log.debug(data);
|
||||
});
|
||||
|
||||
child.stderr.on("data", function (data) {
|
||||
child.stderr.on('data', function (data) {
|
||||
that.book.log.debug(data);
|
||||
});
|
||||
|
||||
|
||||
+38
-47
@@ -1,18 +1,18 @@
|
||||
var util = require("util");
|
||||
var path = require("path");
|
||||
var Q = require("q");
|
||||
var _ = require("lodash");
|
||||
var util = require('util');
|
||||
var path = require('path');
|
||||
var Q = require('q');
|
||||
var _ = require('lodash');
|
||||
|
||||
var nunjucks = require("nunjucks");
|
||||
var AutoEscapeExtension = require("nunjucks-autoescape")(nunjucks);
|
||||
var FilterExtension = require("nunjucks-filter")(nunjucks);
|
||||
var nunjucks = require('nunjucks');
|
||||
var AutoEscapeExtension = require('nunjucks-autoescape')(nunjucks);
|
||||
var FilterExtension = require('nunjucks-filter')(nunjucks);
|
||||
|
||||
var fs = require("../utils/fs");
|
||||
var BaseGenerator = require("../generator");
|
||||
var links = require("../utils/links");
|
||||
var i18n = require("../utils/i18n");
|
||||
var fs = require('../utils/fs');
|
||||
var BaseGenerator = require('../generator');
|
||||
var links = require('../utils/links');
|
||||
var i18n = require('../utils/i18n');
|
||||
|
||||
var pkg = require("../../package.json");
|
||||
var pkg = require('../../package.json');
|
||||
|
||||
var Generator = function() {
|
||||
BaseGenerator.apply(this, arguments);
|
||||
@@ -21,10 +21,10 @@ var Generator = function() {
|
||||
this.revision = new Date();
|
||||
|
||||
// Resources namespace
|
||||
this.namespace = "website";
|
||||
this.namespace = 'website';
|
||||
|
||||
// Style to integrates in the output
|
||||
this.styles = ["website"];
|
||||
this.styles = ['website'];
|
||||
|
||||
// Convert images (svg -> png)
|
||||
this.convertImages = false;
|
||||
@@ -63,9 +63,9 @@ Generator.prototype.prepareStyles = function() {
|
||||
|
||||
// Prepare templates
|
||||
Generator.prototype.prepareTemplates = function() {
|
||||
this.templates.page = this.book.plugins.template("site:page") || path.resolve(this.options.theme, "templates/website/page.html");
|
||||
this.templates.langs = this.book.plugins.template("site:langs") || path.resolve(this.options.theme, "templates/website/langs.html");
|
||||
this.templates.glossary = this.book.plugins.template("site:glossary") || path.resolve(this.options.theme, "templates/website/glossary.html");
|
||||
this.templates.page = this.book.plugins.template('site:page') || path.resolve(this.options.theme, 'templates/website/page.html');
|
||||
this.templates.langs = this.book.plugins.template('site:langs') || path.resolve(this.options.theme, 'templates/website/langs.html');
|
||||
this.templates.glossary = this.book.plugins.template('site:glossary') || path.resolve(this.options.theme, 'templates/website/glossary.html');
|
||||
|
||||
return Q();
|
||||
};
|
||||
@@ -79,7 +79,7 @@ Generator.prototype.prepareTemplateEngine = function() {
|
||||
var language = that.book.config.normalizeLanguage();
|
||||
|
||||
if (!i18n.hasLocale(language)) {
|
||||
that.book.log.warn.ln("Language '"+language+"' is not available as a layout locales (en, "+i18n.getLocales().join(", ")+")");
|
||||
that.book.log.warn.ln('Language "'+language+'" is not available as a layout locales (en, '+i18n.getLocales().join(', ')+')');
|
||||
}
|
||||
|
||||
var folders = _.chain(that.templates)
|
||||
@@ -96,14 +96,14 @@ Generator.prototype.prepareTemplateEngine = function() {
|
||||
);
|
||||
|
||||
// Add filter
|
||||
that.env.addFilter("contentLink", that.book.contentLink.bind(that.book));
|
||||
that.env.addFilter("lvl", function(lvl) {
|
||||
return lvl.split(".").length;
|
||||
that.env.addFilter('contentLink', that.book.contentLink.bind(that.book));
|
||||
that.env.addFilter('lvl', function(lvl) {
|
||||
return lvl.split('.').length;
|
||||
});
|
||||
|
||||
// Add extension
|
||||
that.env.addExtension("AutoEscapeExtension", new AutoEscapeExtension(that.env));
|
||||
that.env.addExtension("FilterExtension", new FilterExtension(that.env));
|
||||
that.env.addExtension('AutoEscapeExtension', new AutoEscapeExtension(that.env));
|
||||
that.env.addExtension('FilterExtension', new FilterExtension(that.env));
|
||||
});
|
||||
};
|
||||
|
||||
@@ -112,7 +112,6 @@ Generator.prototype.finish = function() {
|
||||
return this.copyAssets()
|
||||
.then(this.copyCover)
|
||||
.then(this.writeGlossary)
|
||||
.then(this.writeSearchIndex)
|
||||
.then(this.writeLangsIndex);
|
||||
};
|
||||
|
||||
@@ -123,20 +122,20 @@ Generator.prototype.convertFile = function(input) {
|
||||
return that.book.parsePage(input, {
|
||||
convertImages: that.convertImages,
|
||||
interpolateTemplate: function(page) {
|
||||
return that.callHook("page:before", page);
|
||||
return that.callHook('page:before', page);
|
||||
},
|
||||
interpolateContent: function(page) {
|
||||
return that.callHook("page", page);
|
||||
return that.callHook('page', page);
|
||||
}
|
||||
})
|
||||
.then(function(page) {
|
||||
var relativeOutput = that.book.contentPath(page.path);
|
||||
var output = path.join(that.options.output, relativeOutput);
|
||||
|
||||
var basePath = path.relative(path.dirname(output), that.options.output) || ".";
|
||||
if (process.platform === "win32") basePath = basePath.replace(/\\/g, "/");
|
||||
var basePath = path.relative(path.dirname(output), that.options.output) || '.';
|
||||
if (process.platform === 'win32') basePath = basePath.replace(/\\/g, '/');
|
||||
|
||||
that.book.log.debug.ln("write parsed file", page.path, "to", relativeOutput);
|
||||
that.book.log.debug.ln('write parsed file', page.path, 'to', relativeOutput);
|
||||
|
||||
return that._writeTemplate(that.templates.page, {
|
||||
progress: page.progress,
|
||||
@@ -145,7 +144,7 @@ Generator.prototype.convertFile = function(input) {
|
||||
content: page.sections,
|
||||
|
||||
basePath: basePath,
|
||||
staticBase: links.join(basePath, "gitbook")
|
||||
staticBase: links.join(basePath, 'gitbook')
|
||||
}, output);
|
||||
});
|
||||
};
|
||||
@@ -156,7 +155,7 @@ Generator.prototype.writeLangsIndex = function() {
|
||||
|
||||
return this._writeTemplate(this.templates.langs, {
|
||||
langs: this.book.langs
|
||||
}, path.join(this.options.output, "index.html"));
|
||||
}, path.join(this.options.output, 'index.html'));
|
||||
};
|
||||
|
||||
// Write glossary
|
||||
@@ -164,15 +163,7 @@ Generator.prototype.writeGlossary = function() {
|
||||
// No glossary
|
||||
if (this.book.glossary.length === 0) return Q();
|
||||
|
||||
return this._writeTemplate(this.templates.glossary, {}, path.join(this.options.output, "GLOSSARY.html"));
|
||||
};
|
||||
|
||||
// Write the search index
|
||||
Generator.prototype.writeSearchIndex = function() {
|
||||
return fs.writeFile(
|
||||
path.join(this.options.output, "search_index.json"),
|
||||
JSON.stringify(this.book.searchIndex)
|
||||
);
|
||||
return this._writeTemplate(this.templates.glossary, {}, path.join(this.options.output, 'GLOSSARY.html'));
|
||||
};
|
||||
|
||||
// Convert a page into a normalized data set
|
||||
@@ -189,7 +180,7 @@ Generator.prototype.normalizePage = function(page) {
|
||||
|
||||
return Q()
|
||||
.then(function() {
|
||||
return _callHook("page");
|
||||
return _callHook('page');
|
||||
})
|
||||
.then(function() {
|
||||
return page;
|
||||
@@ -231,10 +222,10 @@ Generator.prototype._writeTemplate = function(tpl, options, output, interpolate)
|
||||
|
||||
options: that.options,
|
||||
|
||||
basePath: ".",
|
||||
staticBase: path.join(".", "gitbook"),
|
||||
basePath: '.',
|
||||
staticBase: path.join('.', 'gitbook'),
|
||||
|
||||
"__": that.book.i18n.bind(that.book)
|
||||
'__': that.book.i18n.bind(that.book)
|
||||
}, options)
|
||||
);
|
||||
})
|
||||
@@ -253,15 +244,15 @@ Generator.prototype.copyAssets = function() {
|
||||
|
||||
// Copy gitbook assets
|
||||
return fs.copy(
|
||||
path.join(that.options.theme, "assets"),
|
||||
path.join(that.options.output, "gitbook")
|
||||
path.join(that.options.theme, 'assets/'+this.namespace),
|
||||
path.join(that.options.output, 'gitbook')
|
||||
)
|
||||
|
||||
// Copy plugins assets
|
||||
.then(function() {
|
||||
return Q.all(
|
||||
_.map(that.book.plugins.list, function(plugin) {
|
||||
var pluginAssets = path.join(that.options.output, "gitbook/plugins/", plugin.name);
|
||||
var pluginAssets = path.join(that.options.output, 'gitbook/plugins/', plugin.name);
|
||||
return plugin.copyAssets(pluginAssets, that.namespace);
|
||||
})
|
||||
);
|
||||
|
||||
+65
-59
@@ -1,50 +1,56 @@
|
||||
var Q = require("q");
|
||||
var _ = require("lodash");
|
||||
var path = require("path");
|
||||
var tinylr = require("tiny-lr");
|
||||
var color = require("bash-color");
|
||||
/*eslint no-console: 0*/
|
||||
|
||||
var Book = require("./book");
|
||||
var Server = require("./utils/server");
|
||||
var stringUtils = require("./utils/string");
|
||||
var watch = require("./utils/watch");
|
||||
var logger = require("./utils/logger");
|
||||
var Q = require('q');
|
||||
var _ = require('lodash');
|
||||
var path = require('path');
|
||||
var tinylr = require('tiny-lr');
|
||||
var color = require('bash-color');
|
||||
|
||||
var Book = require('./book');
|
||||
var initBook = require('./init');
|
||||
var Server = require('./utils/server');
|
||||
var stringUtils = require('./utils/string');
|
||||
var watch = require('./utils/watch');
|
||||
var logger = require('./utils/logger');
|
||||
|
||||
var LOG_OPTION = {
|
||||
name: "log",
|
||||
description: "Minimum log level to display",
|
||||
name: 'log',
|
||||
description: 'Minimum log level to display',
|
||||
values: _.chain(logger.LEVELS).keys().map(stringUtils.toLowerCase).value(),
|
||||
defaults: "info"
|
||||
defaults: 'info'
|
||||
};
|
||||
|
||||
var FORMAT_OPTION = {
|
||||
name: "format",
|
||||
description: "Format to build to",
|
||||
values: ["website", "json", "ebook"],
|
||||
defaults: "website"
|
||||
name: 'format',
|
||||
description: 'Format to build to',
|
||||
values: ['website', 'json', 'ebook'],
|
||||
defaults: 'website'
|
||||
};
|
||||
|
||||
// Export init to gitbook library
|
||||
Book.init = initBook;
|
||||
|
||||
module.exports = {
|
||||
Book: Book,
|
||||
LOG_LEVELS: logger.LEVELS,
|
||||
|
||||
commands: _.flatten([
|
||||
{
|
||||
name: "build [book] [output]",
|
||||
description: "build a book",
|
||||
name: 'build [book] [output]',
|
||||
description: 'build a book',
|
||||
options: [
|
||||
FORMAT_OPTION,
|
||||
LOG_OPTION
|
||||
],
|
||||
exec: function(args, kwargs) {
|
||||
var input = args[0] || process.cwd();
|
||||
var output = args[1] || path.join(input, "_book");
|
||||
var output = args[1] || path.join(input, '_book');
|
||||
|
||||
var book = new Book(input, _.extend({}, {
|
||||
"config": {
|
||||
"output": output
|
||||
'config': {
|
||||
'output': output
|
||||
},
|
||||
"logLevel": kwargs.log
|
||||
'logLevel': kwargs.log
|
||||
}));
|
||||
|
||||
return book.parse()
|
||||
@@ -52,16 +58,16 @@ module.exports = {
|
||||
return book.generate(kwargs.format);
|
||||
})
|
||||
.then(function(){
|
||||
console.log("");
|
||||
console.log(color.green("Done, without error"));
|
||||
console.log('');
|
||||
console.log(color.green('Done, without error'));
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_.map(["pdf", "epub", "mobi"], function(ebookType) {
|
||||
_.map(['pdf', 'epub', 'mobi'], function(ebookType) {
|
||||
return {
|
||||
name: ebookType+" [book] [output]",
|
||||
description: "build a book to "+ebookType,
|
||||
name: ebookType+' [book] [output]',
|
||||
description: 'build a book to '+ebookType,
|
||||
options: [
|
||||
LOG_OPTION
|
||||
],
|
||||
@@ -70,7 +76,7 @@ module.exports = {
|
||||
var output = args[1];
|
||||
|
||||
var book = new Book(input, _.extend({}, {
|
||||
"logLevel": kwargs.log
|
||||
'logLevel': kwargs.log
|
||||
}));
|
||||
|
||||
return book.parse()
|
||||
@@ -80,30 +86,30 @@ module.exports = {
|
||||
});
|
||||
})
|
||||
.then(function(){
|
||||
console.log("");
|
||||
console.log(color.green("Done, without error"));
|
||||
console.log('');
|
||||
console.log(color.green('Done, without error'));
|
||||
});
|
||||
}
|
||||
};
|
||||
}),
|
||||
|
||||
{
|
||||
name: "serve [book]",
|
||||
description: "Build then serve a gitbook from a directory",
|
||||
name: 'serve [book]',
|
||||
description: 'Build then serve a gitbook from a directory',
|
||||
options: [
|
||||
{
|
||||
name: "port",
|
||||
description: "Port for server to listen on",
|
||||
name: 'port',
|
||||
description: 'Port for server to listen on',
|
||||
defaults: 4000
|
||||
},
|
||||
{
|
||||
name: "lrport",
|
||||
description: "Port for livereload server to listen on",
|
||||
name: 'lrport',
|
||||
description: 'Port for livereload server to listen on',
|
||||
defaults: 35729
|
||||
},
|
||||
{
|
||||
name: "watch",
|
||||
description: "Enable/disable file watcher",
|
||||
name: 'watch',
|
||||
description: 'Enable/disable file watcher',
|
||||
defaults: true
|
||||
},
|
||||
FORMAT_OPTION,
|
||||
@@ -118,15 +124,15 @@ module.exports = {
|
||||
var lrPath;
|
||||
|
||||
var generate = function() {
|
||||
if (server.isRunning()) console.log("Stopping server");
|
||||
if (server.isRunning()) console.log('Stopping server');
|
||||
|
||||
return server.stop()
|
||||
.then(function() {
|
||||
var book = new Book(input, _.extend({}, {
|
||||
"config": {
|
||||
"defaultsPlugins": ["livereload"]
|
||||
'config': {
|
||||
'defaultsPlugins': ['livereload']
|
||||
},
|
||||
"logLevel": kwargs.log
|
||||
'logLevel': kwargs.log
|
||||
}));
|
||||
|
||||
return book.parse()
|
||||
@@ -137,10 +143,10 @@ module.exports = {
|
||||
})
|
||||
.then(function(book) {
|
||||
console.log();
|
||||
console.log("Starting server ...");
|
||||
console.log('Starting server ...');
|
||||
return server.start(book.options.output, kwargs.port)
|
||||
.then(function() {
|
||||
console.log("Serving book on http://localhost:"+kwargs.port);
|
||||
console.log('Serving book on http://localhost:'+kwargs.port);
|
||||
|
||||
if (lrPath) {
|
||||
// trigger livereload
|
||||
@@ -157,8 +163,8 @@ module.exports = {
|
||||
.then(function(filepath) {
|
||||
// set livereload path
|
||||
lrPath = filepath;
|
||||
console.log("Restart after change in file", filepath);
|
||||
console.log("");
|
||||
console.log('Restart after change in file', filepath);
|
||||
console.log('');
|
||||
return generate();
|
||||
});
|
||||
});
|
||||
@@ -167,17 +173,17 @@ module.exports = {
|
||||
|
||||
return Q.nfcall(lrServer.listen.bind(lrServer), kwargs.lrport)
|
||||
.then(function() {
|
||||
console.log("Live reload server started on port:", kwargs.lrport);
|
||||
console.log("Press CTRL+C to quit ...");
|
||||
console.log("");
|
||||
console.log('Live reload server started on port:', kwargs.lrport);
|
||||
console.log('Press CTRL+C to quit ...');
|
||||
console.log('');
|
||||
return generate();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: "install [book]",
|
||||
description: "install plugins dependencies",
|
||||
name: 'install [book]',
|
||||
description: 'install plugins dependencies',
|
||||
exec: function(args) {
|
||||
var input = args[0] || process.cwd();
|
||||
|
||||
@@ -188,20 +194,20 @@ module.exports = {
|
||||
return book.plugins.install();
|
||||
})
|
||||
.then(function(){
|
||||
console.log("");
|
||||
console.log(color.green("Done, without error"));
|
||||
console.log('');
|
||||
console.log(color.green('Done, without error'));
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: "init [directory]",
|
||||
description: "create files and folders based on contents of SUMMARY.md",
|
||||
name: 'init [directory]',
|
||||
description: 'create files and folders based on contents of SUMMARY.md',
|
||||
exec: function(args) {
|
||||
return Book.init(args[0] || process.cwd())
|
||||
return initBook(args[0] || process.cwd())
|
||||
.then(function(){
|
||||
console.log("");
|
||||
console.log(color.green("Done, without error"));
|
||||
console.log('');
|
||||
console.log(color.green('Done, without error'));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
var _ = require('lodash');
|
||||
var Q = require('q');
|
||||
var path = require('path');
|
||||
|
||||
var Book = require('./book');
|
||||
var fs = require('./utils/fs');
|
||||
|
||||
// Initialize folder structure for a book
|
||||
// Read SUMMARY to created the right chapter
|
||||
function initBook(root, opts) {
|
||||
var book = new Book(root, opts);
|
||||
var extensionToUse = '.md';
|
||||
|
||||
var chaptersPaths = function(chapters) {
|
||||
return _.reduce(chapters || [], function(accu, chapter) {
|
||||
var o = {
|
||||
title: chapter.title
|
||||
};
|
||||
if (chapter.path) o.path = chapter.path;
|
||||
|
||||
return accu.concat(
|
||||
[o].concat(chaptersPaths(chapter.articles))
|
||||
);
|
||||
}, []);
|
||||
};
|
||||
|
||||
book.log.info.ln('init book at', root);
|
||||
return fs.mkdirp(root)
|
||||
.then(function() {
|
||||
book.log.info.ln('detect structure from SUMMARY (if it exists)');
|
||||
return book.parseSummary();
|
||||
})
|
||||
.fail(function() {
|
||||
return Q();
|
||||
})
|
||||
.then(function() {
|
||||
var summary = book.summaryFile || 'SUMMARY.md';
|
||||
var chapters = book.summary.chapters || [];
|
||||
extensionToUse = path.extname(summary);
|
||||
|
||||
if (chapters.length === 0) {
|
||||
chapters = [
|
||||
{
|
||||
title: 'Summary',
|
||||
path: 'SUMMARY'+extensionToUse
|
||||
},
|
||||
{
|
||||
title: 'Introduction',
|
||||
path: 'README'+extensionToUse
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
return Q(chaptersPaths(chapters));
|
||||
})
|
||||
.then(function(chapters) {
|
||||
// Create files that don't exist
|
||||
return Q.all(_.map(chapters, function(chapter) {
|
||||
if (!chapter.path) return Q();
|
||||
var absolutePath = path.resolve(book.root, chapter.path);
|
||||
|
||||
return fs.exists(absolutePath)
|
||||
.then(function(exists) {
|
||||
if(exists) {
|
||||
book.log.info.ln('found', chapter.path);
|
||||
return;
|
||||
} else {
|
||||
book.log.info.ln('create', chapter.path);
|
||||
}
|
||||
|
||||
return fs.mkdirp(path.dirname(absolutePath))
|
||||
.then(function() {
|
||||
return fs.writeFile(absolutePath, '# '+chapter.title+'\n');
|
||||
});
|
||||
});
|
||||
}));
|
||||
})
|
||||
.then(function() {
|
||||
book.log.info.ln('initialization is finished');
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = initBook;
|
||||
+83
-25
@@ -1,16 +1,27 @@
|
||||
var _ = require("lodash");
|
||||
var Q = require("q");
|
||||
var semver = require("semver");
|
||||
var path = require("path");
|
||||
var url = require("url");
|
||||
var fs = require("./utils/fs");
|
||||
var resolve = require("resolve");
|
||||
var _ = require('lodash');
|
||||
var Q = require('q');
|
||||
var path = require('path');
|
||||
var url = require('url');
|
||||
var fs = require('./utils/fs');
|
||||
var resolve = require('resolve');
|
||||
var mergeDefaults = require('merge-defaults');
|
||||
var jsonschema = require('jsonschema');
|
||||
var jsonSchemaDefaults = require('json-schema-defaults');
|
||||
|
||||
var version = require('./version');
|
||||
|
||||
var PLUGIN_PREFIX = 'gitbook-plugin-';
|
||||
|
||||
// Return an absolute name for the plugin (the one on NPM)
|
||||
function absoluteName(name) {
|
||||
if (name.indexOf(PLUGIN_PREFIX) === 0) return name;
|
||||
return [PLUGIN_PREFIX, name].join('');
|
||||
}
|
||||
|
||||
var pkg = require("../package.json");
|
||||
|
||||
var Plugin = function(book, name) {
|
||||
this.book = book;
|
||||
this.name = name;
|
||||
this.name = absoluteName(name);
|
||||
this.packageInfos = {};
|
||||
this.infos = {};
|
||||
|
||||
@@ -18,9 +29,8 @@ var Plugin = function(book, name) {
|
||||
_.bindAll(this);
|
||||
|
||||
_.each([
|
||||
"gitbook-plugin-"+name,
|
||||
"gitbook-"+name,
|
||||
name,
|
||||
absoluteName(name),
|
||||
name
|
||||
], function(_name) {
|
||||
// Load from the book
|
||||
if (this.load(_name, book.root)) return false;
|
||||
@@ -31,20 +41,27 @@ var Plugin = function(book, name) {
|
||||
};
|
||||
|
||||
// Type of plugins resources
|
||||
Plugin.RESOURCES = ["js", "css"];
|
||||
Plugin.RESOURCES = ['js', 'css'];
|
||||
Plugin.HOOKS = [
|
||||
"init", "finish", "finish:before", "page", "page:before"
|
||||
'init', 'finish', 'finish:before', 'config', 'page', 'page:before'
|
||||
];
|
||||
|
||||
// Return the reduce name for the plugin
|
||||
// "gitbook-plugin-test" -> "test"
|
||||
// Return a relative name for the plugin (the one on GitBook)
|
||||
Plugin.prototype.reducedName = function() {
|
||||
return this.name.replace(PLUGIN_PREFIX, '');
|
||||
};
|
||||
|
||||
// Load from a name
|
||||
Plugin.prototype.load = function(name, baseDir) {
|
||||
try {
|
||||
var res = resolve.sync(name+"/package.json", { basedir: baseDir });
|
||||
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;
|
||||
this.name = this.packageInfos.name;
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
@@ -62,13 +79,13 @@ Plugin.prototype.normalizeResource = function(resource) {
|
||||
// so we will simply link to using it's URL
|
||||
if (parsed.protocol) {
|
||||
return {
|
||||
"url": resource
|
||||
'url': resource
|
||||
};
|
||||
}
|
||||
|
||||
// This will be copied over from disk
|
||||
// and shipped with the book's build
|
||||
return { "path": this.name+"/"+resource };
|
||||
return { 'path': this.name+'/'+resource };
|
||||
};
|
||||
|
||||
// Return resources
|
||||
@@ -77,7 +94,7 @@ Plugin.prototype._getResources = function(base) {
|
||||
var book = this.infos[base];
|
||||
|
||||
// Compatibility with version 1.x.x
|
||||
if (base == "website") book = book || this.infos.book;
|
||||
if (base == 'website') book = book || this.infos.book;
|
||||
|
||||
// Nothing specified, fallback to default
|
||||
if (!book) {
|
||||
@@ -85,7 +102,7 @@ Plugin.prototype._getResources = function(base) {
|
||||
}
|
||||
|
||||
// Dynamic function
|
||||
if(typeof book === "function") {
|
||||
if(typeof book === 'function') {
|
||||
// Call giving it the context of our book
|
||||
return Q().then(book.bind(this.book));
|
||||
}
|
||||
@@ -127,18 +144,49 @@ Plugin.prototype.isValid = function() {
|
||||
this.packageInfos.name &&
|
||||
this.packageInfos.engines &&
|
||||
this.packageInfos.engines.gitbook &&
|
||||
semver.satisfies(pkg.version, this.packageInfos.engines.gitbook)
|
||||
version.satisfies(this.packageInfos.engines.gitbook)
|
||||
);
|
||||
|
||||
// Valid hooks
|
||||
_.each(this.infos.hooks, function(hook, hookName) {
|
||||
if (_.contains(Plugin.HOOKS, hookName)) return;
|
||||
that.book.log.warn.ln("Hook '"+hookName+" 'used by plugin '"+that.packageInfos.name+"' has been removed or is deprecated");
|
||||
that.book.log.warn.ln('Hook "'+hookName+'"" used by plugin "'+that.packageInfos.name+'" has been removed or is deprecated');
|
||||
});
|
||||
|
||||
return isValid;
|
||||
};
|
||||
|
||||
// Normalize, validate configuration for this plugin using its schema
|
||||
// Throw an error when shcema is not respected
|
||||
Plugin.prototype.validateConfig = function(config) {
|
||||
var that = this;
|
||||
|
||||
return Q()
|
||||
.then(function() {
|
||||
var schema = that.packageInfos.gitbook || {};
|
||||
if (!schema) return config;
|
||||
|
||||
// Normalize schema
|
||||
schema.id = '/pluginsConfig.'+that.reducedName();
|
||||
schema.type = 'object';
|
||||
|
||||
// Validate and throw if invalid
|
||||
var v = new jsonschema.Validator();
|
||||
var result = v.validate(config, schema, {
|
||||
propertyName: 'pluginsConfig.'+that.reducedName()
|
||||
});
|
||||
|
||||
// Throw error
|
||||
if (result.errors.length > 0) {
|
||||
throw new Error('Configuration Error: '+result.errors[0].stack);
|
||||
}
|
||||
|
||||
// Insert default values
|
||||
var defaults = jsonSchemaDefaults(schema);
|
||||
return mergeDefaults(config, defaults);
|
||||
});
|
||||
};
|
||||
|
||||
// Resolve file path
|
||||
Plugin.prototype.resolveFile = function(filename) {
|
||||
return path.resolve(this.baseDir, filename);
|
||||
@@ -154,8 +202,8 @@ Plugin.prototype.callHook = function(name, data) {
|
||||
|
||||
if (!hookFunc) return Q(data);
|
||||
|
||||
this.book.log.debug.ln("call hook", name);
|
||||
if (!_.contains(Plugin.HOOKS, name)) this.book.log.warn.ln("hook '"+name+"' used by plugin '"+this.name+"' is deprecated, and will be removed in the coming versions");
|
||||
this.book.log.debug.ln('call hook', name);
|
||||
if (!_.contains(Plugin.HOOKS, name)) this.book.log.warn.ln('hook "'+name+'" used by plugin "'+this.name+'" is deprecated, and will be removed in the coming versions');
|
||||
|
||||
return Q()
|
||||
.then(function() {
|
||||
@@ -168,7 +216,7 @@ Plugin.prototype.copyAssets = function(out, base) {
|
||||
var that = this;
|
||||
|
||||
return this.getResources(base)
|
||||
.get("assets")
|
||||
.get('assets')
|
||||
.then(function(assets) {
|
||||
// Assets are undefined
|
||||
if(!assets) return false;
|
||||
@@ -180,4 +228,14 @@ Plugin.prototype.copyAssets = function(out, base) {
|
||||
}, _.constant(false));
|
||||
};
|
||||
|
||||
// Get config from book
|
||||
Plugin.prototype.getConfig = function() {
|
||||
return this.book.config.get('pluginsConfig.'+this.reducedName(), {});
|
||||
};
|
||||
|
||||
// Set configuration for this plugin
|
||||
Plugin.prototype.setConfig = function(values) {
|
||||
return this.book.config.set('pluginsConfig.'+this.reducedName(), values);
|
||||
};
|
||||
|
||||
module.exports = Plugin;
|
||||
|
||||
+59
-47
@@ -1,14 +1,14 @@
|
||||
var _ = require("lodash");
|
||||
var Q = require("q");
|
||||
var npmi = require("npmi");
|
||||
var npm = require("npm");
|
||||
var semver = require("semver");
|
||||
var _ = require('lodash');
|
||||
var Q = require('q');
|
||||
var npmi = require('npmi');
|
||||
var npm = require('npm');
|
||||
var semver = require('semver');
|
||||
|
||||
var Plugin = require("./plugin");
|
||||
var pkg = require("../package.json");
|
||||
var Plugin = require('./plugin');
|
||||
var pkg = require('../package.json');
|
||||
|
||||
var initNPM = _.memoize(function() {
|
||||
return Q.nfcall(npm.load, { silent: true, loglevel: "silent" });
|
||||
return Q.nfcall(npm.load, { silent: true, loglevel: 'silent' });
|
||||
});
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ var PluginsList = function(book, plugins) {
|
||||
this.failed = [];
|
||||
|
||||
// Namespaces
|
||||
this.namespaces = _.chain(["website", "ebook"])
|
||||
this.namespaces = _.chain(['website', 'ebook'])
|
||||
.map(function(namespace) {
|
||||
return [
|
||||
namespace,
|
||||
@@ -66,7 +66,7 @@ PluginsList.prototype.load = function(plugin) {
|
||||
if (_.isObject(plugin) && !(plugin instanceof Plugin)) plugin = plugin.name;
|
||||
if (_.isString(plugin)) plugin = new Plugin(this.book, plugin);
|
||||
|
||||
that.log.info("load plugin", plugin.name, "....");
|
||||
that.log.info('load plugin', plugin.name, '....');
|
||||
if (!plugin.isValid()) {
|
||||
that.log.info.fail();
|
||||
that.failed.push(plugin.name);
|
||||
@@ -78,34 +78,46 @@ PluginsList.prototype.load = function(plugin) {
|
||||
that.list.push(plugin);
|
||||
}
|
||||
|
||||
// Extract filters
|
||||
that.book.template.addFilters(plugin.getFilters());
|
||||
return Q()
|
||||
|
||||
// Extract blocks
|
||||
that.book.template.addBlocks(plugin.getBlocks());
|
||||
// Validate and normalize configuration
|
||||
.then(function() {
|
||||
var config = plugin.getConfig();
|
||||
return plugin.validateConfig(config);
|
||||
})
|
||||
.then(function(config) {
|
||||
// Update configuration
|
||||
plugin.setConfig(config);
|
||||
|
||||
return _.reduce(_.keys(that.namespaces), function(prev, namespaceName) {
|
||||
return prev.then(function() {
|
||||
return plugin.getResources(namespaceName)
|
||||
.then(function(plResources) {
|
||||
var namespace = that.namespaces[namespaceName];
|
||||
// Extract filters
|
||||
that.book.template.addFilters(plugin.getFilters());
|
||||
|
||||
// Extract js and css
|
||||
_.each(Plugin.RESOURCES, function(resourceType) {
|
||||
namespace.resources[resourceType] = (namespace.resources[resourceType] || []).concat(plResources[resourceType] || []);
|
||||
});
|
||||
// Extract blocks
|
||||
that.book.template.addBlocks(plugin.getBlocks());
|
||||
|
||||
// Map of html resources by name added by each plugin
|
||||
_.each(plResources.html || {}, function(value, tag) {
|
||||
// Turn into function if not one already
|
||||
if (!_.isFunction(value)) value = _.constant(value);
|
||||
return _.reduce(_.keys(that.namespaces), function(prev, namespaceName) {
|
||||
return prev.then(function() {
|
||||
return plugin.getResources(namespaceName)
|
||||
.then(function(plResources) {
|
||||
var namespace = that.namespaces[namespaceName];
|
||||
|
||||
namespace.html[tag] = namespace.html[tag] || [];
|
||||
namespace.html[tag].push(value);
|
||||
// Extract js and css
|
||||
_.each(Plugin.RESOURCES, function(resourceType) {
|
||||
namespace.resources[resourceType] = (namespace.resources[resourceType] || []).concat(plResources[resourceType] || []);
|
||||
});
|
||||
|
||||
// Map of html resources by name added by each plugin
|
||||
_.each(plResources.html || {}, function(value, tag) {
|
||||
// Turn into function if not one already
|
||||
if (!_.isFunction(value)) value = _.constant(value);
|
||||
|
||||
namespace.html[tag] = namespace.html[tag] || [];
|
||||
namespace.html[tag].push(value);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}, Q());
|
||||
}, Q());
|
||||
});
|
||||
};
|
||||
|
||||
// Call a hook
|
||||
@@ -135,7 +147,7 @@ PluginsList.prototype.html = function(namespace, tag, context, options) {
|
||||
var htmlSnippets = this.namespaces[namespace].html[tag];
|
||||
return _.map(htmlSnippets || [], function(code) {
|
||||
return code.call(context, options);
|
||||
}).join("\n");
|
||||
}).join('\n');
|
||||
};
|
||||
|
||||
// Return a resources map for a namespace
|
||||
@@ -153,10 +165,10 @@ PluginsList.prototype.install = function() {
|
||||
});
|
||||
|
||||
// Install plugins one by one
|
||||
that.book.log.info.ln(plugins.length+" plugins to install");
|
||||
that.book.log.info.ln(plugins.length+' plugins to install');
|
||||
return _.reduce(plugins, function(prev, plugin) {
|
||||
return prev.then(function() {
|
||||
var fullname = "gitbook-plugin-"+plugin.name;
|
||||
var fullname = 'gitbook-plugin-'+plugin.name;
|
||||
|
||||
return Q()
|
||||
|
||||
@@ -164,10 +176,10 @@ PluginsList.prototype.install = function() {
|
||||
.then(function() {
|
||||
if (plugin.version) return plugin.version;
|
||||
|
||||
that.book.log.info.ln("No version specified, resolve plugin", plugin.name);
|
||||
that.book.log.info.ln('No version specified, resolve plugin', plugin.name);
|
||||
return initNPM()
|
||||
.then(function() {
|
||||
return Q.nfcall(npm.commands.view, [fullname+"@*", "engines"], true);
|
||||
return Q.nfcall(npm.commands.view, [fullname+'@*', 'engines'], true);
|
||||
})
|
||||
.then(function(versions) {
|
||||
return _.chain(versions)
|
||||
@@ -184,7 +196,7 @@ PluginsList.prototype.install = function() {
|
||||
.sort(function(v1, v2) {
|
||||
return semver.lt(v1.version, v2.version)? 1 : -1;
|
||||
})
|
||||
.pluck("version")
|
||||
.pluck('version')
|
||||
.first()
|
||||
.value();
|
||||
});
|
||||
@@ -193,23 +205,23 @@ PluginsList.prototype.install = function() {
|
||||
// Install the plugin with the resolved version
|
||||
.then(function(version) {
|
||||
if (!version) {
|
||||
throw "Found no satisfactory version for plugin "+plugin.name;
|
||||
throw 'Found no satisfactory version for plugin '+plugin.name;
|
||||
}
|
||||
|
||||
that.book.log.info.ln("install plugin", plugin.name, "from npm ("+fullname+") with version", version);
|
||||
that.book.log.info.ln('install plugin', plugin.name, 'from npm ('+fullname+') with version', version);
|
||||
return Q.nfcall(npmi, {
|
||||
"name": fullname,
|
||||
"version": version,
|
||||
"path": that.book.root,
|
||||
"npmLoad": {
|
||||
"loglevel": "silent",
|
||||
"loaded": true,
|
||||
"prefix": that.book.root
|
||||
'name': fullname,
|
||||
'version': version,
|
||||
'path': that.book.root,
|
||||
'npmLoad': {
|
||||
'loglevel': 'silent',
|
||||
'loaded': true,
|
||||
'prefix': that.book.root
|
||||
}
|
||||
});
|
||||
})
|
||||
.then(function() {
|
||||
that.book.log.info.ok("plugin", plugin.name, "installed with success");
|
||||
that.book.log.info.ok('plugin', plugin.name, 'installed with success');
|
||||
});
|
||||
});
|
||||
}, Q());
|
||||
|
||||
+23
-24
@@ -1,10 +1,10 @@
|
||||
var _ = require("lodash");
|
||||
var Q = require("q");
|
||||
var tmp = require("tmp");
|
||||
var path = require("path");
|
||||
var fs = require("graceful-fs");
|
||||
var fsExtra = require("fs-extra");
|
||||
var Ignore = require("fstream-ignore");
|
||||
var _ = require('lodash');
|
||||
var Q = require('q');
|
||||
var tmp = require('tmp');
|
||||
var path = require('path');
|
||||
var fs = require('graceful-fs');
|
||||
var fsExtra = require('fs-extra');
|
||||
var Ignore = require('fstream-ignore');
|
||||
|
||||
var fsUtils = {
|
||||
tmp: {
|
||||
@@ -33,7 +33,7 @@ var fsUtils = {
|
||||
existsSync: fs.existsSync.bind(fs),
|
||||
readFileSync: fs.readFileSync.bind(fs),
|
||||
clean: cleanFolder,
|
||||
getUniqueFilename: getUniqueFilename,
|
||||
getUniqueFilename: getUniqueFilename
|
||||
};
|
||||
|
||||
// Write a file
|
||||
@@ -57,14 +57,14 @@ function writeStream(filename, st) {
|
||||
|
||||
var wstream = fs.createWriteStream(filename);
|
||||
|
||||
wstream.on("finish", function () {
|
||||
wstream.on('finish', function () {
|
||||
d.resolve();
|
||||
});
|
||||
wstream.on("error", function (err) {
|
||||
wstream.on('error', function (err) {
|
||||
d.reject(err);
|
||||
});
|
||||
|
||||
st.on("error", function(err) {
|
||||
st.on('error', function(err) {
|
||||
d.reject(err);
|
||||
});
|
||||
|
||||
@@ -77,7 +77,7 @@ function writeStream(filename, st) {
|
||||
function getUniqueFilename(base, filename) {
|
||||
if (!filename) {
|
||||
filename = base;
|
||||
base = "/";
|
||||
base = '/';
|
||||
}
|
||||
|
||||
filename = path.resolve(base, filename);
|
||||
@@ -87,9 +87,8 @@ function getUniqueFilename(base, filename) {
|
||||
var _filename = filename+ext;
|
||||
|
||||
var i = 0;
|
||||
while (1) {
|
||||
if (!fs.existsSync(filename)) break;
|
||||
_filename = filename+"_"+i+ext;
|
||||
while (fs.existsSync(filename)) {
|
||||
_filename = filename+'_'+i+ext;
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
@@ -115,20 +114,20 @@ function listFiles(root, options) {
|
||||
});
|
||||
|
||||
// Add extra rules to ignore common folders
|
||||
ig.addIgnoreRules(options.ignoreRules, "__custom_stuff");
|
||||
ig.addIgnoreRules(options.ignoreRules, '__custom_stuff');
|
||||
|
||||
// Push each file to our list
|
||||
ig.on("child", function (c) {
|
||||
ig.on('child', function (c) {
|
||||
files.push(
|
||||
c.path.substr(c.root.path.length + 1) + (c.props.Directory === true ? "/" : "")
|
||||
c.path.substr(c.root.path.length + 1) + (c.props.Directory === true ? '/' : '')
|
||||
);
|
||||
});
|
||||
|
||||
ig.on("end", function() {
|
||||
ig.on('end', function() {
|
||||
// Normalize paths on Windows
|
||||
if(process.platform === "win32") {
|
||||
if(process.platform === 'win32') {
|
||||
return d.resolve(files.map(function(file) {
|
||||
return file.replace(/\\/g, "/");
|
||||
return file.replace(/\\/g, '/');
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -136,7 +135,7 @@ function listFiles(root, options) {
|
||||
return d.resolve(files);
|
||||
});
|
||||
|
||||
ig.on("error", d.reject);
|
||||
ig.on('error', d.reject);
|
||||
|
||||
return d.promise;
|
||||
}
|
||||
@@ -150,8 +149,8 @@ function cleanFolder(root) {
|
||||
ignoreFiles: [],
|
||||
ignoreRules: [
|
||||
// Skip Git and SVN stuff
|
||||
".git/",
|
||||
".svn/"
|
||||
'.git/',
|
||||
'.svn/'
|
||||
]
|
||||
})
|
||||
.then(function(files) {
|
||||
|
||||
+64
-78
@@ -1,18 +1,18 @@
|
||||
var Q = require("q");
|
||||
var _ = require("lodash");
|
||||
var url = require("url");
|
||||
var path = require("path");
|
||||
var cheerio = require("cheerio");
|
||||
var domSerializer = require("dom-serializer");
|
||||
var request = require("request");
|
||||
var crc = require("crc");
|
||||
var Q = require('q');
|
||||
var _ = require('lodash');
|
||||
var url = require('url');
|
||||
var path = require('path');
|
||||
var cheerio = require('cheerio');
|
||||
var domSerializer = require('dom-serializer');
|
||||
var request = require('request');
|
||||
var crc = require('crc');
|
||||
|
||||
var links = require("./links");
|
||||
var imgUtils = require("./images");
|
||||
var fs = require("./fs");
|
||||
var batch = require("./batch");
|
||||
var links = require('./links');
|
||||
var imgUtils = require('./images');
|
||||
var fs = require('./fs');
|
||||
var batch = require('./batch');
|
||||
|
||||
var parsableExtensions = require("gitbook-parsers").extensions;
|
||||
var parsableExtensions = require('gitbook-parsers').extensions;
|
||||
|
||||
// Render a cheerio dom as html
|
||||
var renderDom = function($, dom, options) {
|
||||
@@ -59,7 +59,7 @@ function replaceText($, el, search, replace, text_only ) {
|
||||
// robust way.
|
||||
$(node).before( new_val );
|
||||
|
||||
// Don"t remove the node yet, or the loop will lose its place.
|
||||
// Don't remove the node yet, or the loop will lose its place.
|
||||
remove.push( node );
|
||||
} else {
|
||||
// The new value contains no HTML, so it can be set in this
|
||||
@@ -79,7 +79,7 @@ function replaceText($, el, search, replace, text_only ) {
|
||||
}
|
||||
|
||||
function pregQuote( str ) {
|
||||
return (str+"").replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, "\\$1");
|
||||
return (str+'').replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, '\\$1');
|
||||
}
|
||||
|
||||
|
||||
@@ -101,23 +101,23 @@ function normalizeHtml(src, options) {
|
||||
|
||||
// Find svg images to extract and process
|
||||
if (options.convertImages) {
|
||||
$("svg").each(function() {
|
||||
$('svg').each(function() {
|
||||
var content = renderDom($, $(this));
|
||||
var svgId = _.uniqueId("svg");
|
||||
var dest = svgId+".svg";
|
||||
var svgId = _.uniqueId('svg');
|
||||
var dest = svgId+'.svg';
|
||||
|
||||
// Generate filename
|
||||
dest = "/"+fs.getUniqueFilename(outputRoot, dest);
|
||||
dest = '/'+fs.getUniqueFilename(outputRoot, dest);
|
||||
|
||||
svgContent[dest] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"+content;
|
||||
$(this).replaceWith($("<img>").attr("src", dest));
|
||||
svgContent[dest] = '<?xml version="1.0" encoding="UTF-8"?>'+content;
|
||||
$(this).replaceWith($('<img>').attr('src', dest));
|
||||
});
|
||||
}
|
||||
|
||||
// Find images to normalize
|
||||
$("img").each(function() {
|
||||
$('img').each(function() {
|
||||
var origin;
|
||||
var src = $(this).attr("src");
|
||||
var src = $(this).attr('src');
|
||||
|
||||
if (!src) return;
|
||||
var isExternal = links.isExternal(src);
|
||||
@@ -132,13 +132,13 @@ function normalizeHtml(src, options) {
|
||||
// If image is external and ebook, then downlaod the images
|
||||
if (isExternal) {
|
||||
origin = src;
|
||||
src = "/"+crc.crc32(origin).toString(16)+path.extname(origin);
|
||||
src = '/'+crc.crc32(origin).toString(16)+path.extname(origin);
|
||||
src = links.toAbsolute(src, options.base, options.output);
|
||||
isExternal = false;
|
||||
}
|
||||
|
||||
var ext = path.extname(src);
|
||||
var srcAbs = links.join("/", options.base, src);
|
||||
var srcAbs = links.join('/', options.base, src);
|
||||
|
||||
// Test image extension
|
||||
if (_.contains(imgUtils.INVALID, ext)) {
|
||||
@@ -147,29 +147,29 @@ function normalizeHtml(src, options) {
|
||||
src = imgConversionCache[outputRoot][srcAbs];
|
||||
} else {
|
||||
// Not converted yet
|
||||
var dest = "";
|
||||
var dest = '';
|
||||
|
||||
// Replace extension
|
||||
dest = links.join(path.dirname(srcAbs), path.basename(srcAbs, ext)+".png");
|
||||
dest = dest[0] == "/"? dest.slice(1) : dest;
|
||||
dest = links.join(path.dirname(srcAbs), path.basename(srcAbs, ext)+'.png');
|
||||
dest = dest[0] == '/'? dest.slice(1) : dest;
|
||||
|
||||
// Get a name that doesn"t exists
|
||||
// Get a name that doesn't exists
|
||||
dest = fs.getUniqueFilename(outputRoot, dest);
|
||||
|
||||
options.book.log.debug.ln("detect invalid image (will be converted to png):", srcAbs);
|
||||
options.book.log.debug.ln('detect invalid image (will be converted to png):', srcAbs);
|
||||
|
||||
// Add to cache
|
||||
imgConversionCache[outputRoot][srcAbs] = "/"+dest;
|
||||
imgConversionCache[outputRoot][srcAbs] = '/'+dest;
|
||||
|
||||
// Push to convert
|
||||
toConvert.push({
|
||||
origin: origin,
|
||||
content: svgContent[srcAbs],
|
||||
source: isExternal? srcAbs : path.join("./", srcAbs),
|
||||
dest: path.join("./", dest)
|
||||
source: isExternal? srcAbs : path.join('./', srcAbs),
|
||||
dest: path.join('./', dest)
|
||||
});
|
||||
|
||||
src = links.join("/", dest);
|
||||
src = links.join('/', dest);
|
||||
}
|
||||
|
||||
// Reset as relative to output
|
||||
@@ -180,17 +180,17 @@ function normalizeHtml(src, options) {
|
||||
// Need to downlaod image
|
||||
toConvert.push({
|
||||
origin: origin,
|
||||
source: path.join("./", srcAbs)
|
||||
source: path.join('./', srcAbs)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$(this).attr("src", src);
|
||||
$(this).attr('src', src);
|
||||
});
|
||||
|
||||
// Normalize links
|
||||
$("a").each(function() {
|
||||
var href = $(this).attr("href");
|
||||
$('a').each(function() {
|
||||
var href = $(this).attr('href');
|
||||
if (!href) return;
|
||||
|
||||
if (links.isAnchor(href)) {
|
||||
@@ -198,7 +198,7 @@ function normalizeHtml(src, options) {
|
||||
} else if (links.isRelative(href)) {
|
||||
var parts = url.parse(href);
|
||||
var absolutePath = links.join(options.base, parts.pathname);
|
||||
var anchor = parts.hash || "";
|
||||
var anchor = parts.hash || '';
|
||||
|
||||
|
||||
// If is in navigation relative: transform as content
|
||||
@@ -209,33 +209,33 @@ function normalizeHtml(src, options) {
|
||||
// If md/adoc/rst files is not in summary
|
||||
// or for ebook, signal all files that are outside the summary
|
||||
else if (_.contains(parsableExtensions, path.extname(absolutePath)) ||
|
||||
_.contains(["epub", "pdf", "mobi"], options.book.options.generator)) {
|
||||
options.book.log.warn.ln("page", options.input, "contains an hyperlink to resource outside spine \""+href+"\"");
|
||||
_.contains(['epub', 'pdf', 'mobi'], options.book.options.generator)) {
|
||||
options.book.log.warn.ln('page', options.input, 'contains an hyperlink to resource outside spine \''+href+'\'');
|
||||
}
|
||||
|
||||
// Transform as absolute
|
||||
href = links.toAbsolute("/"+absolutePath, options.base, options.output)+anchor;
|
||||
href = links.toAbsolute('/'+absolutePath, options.base, options.output)+anchor;
|
||||
} else {
|
||||
// External links
|
||||
$(this).attr("target", "_blank");
|
||||
$(this).attr('target', '_blank');
|
||||
}
|
||||
|
||||
// Transform extension
|
||||
$(this).attr("href", href);
|
||||
$(this).attr('href', href);
|
||||
});
|
||||
|
||||
// Highlight code blocks
|
||||
$("code").each(function() {
|
||||
$('code').each(function() {
|
||||
// Normalize language
|
||||
var lang = _.chain(
|
||||
($(this).attr("class") || "").split(" ")
|
||||
($(this).attr('class') || '').split(' ')
|
||||
)
|
||||
.map(function(cl) {
|
||||
// Markdown
|
||||
if (cl.search("lang-") === 0) return cl.slice("lang-".length);
|
||||
if (cl.search('lang-') === 0) return cl.slice('lang-'.length);
|
||||
|
||||
// Asciidoc
|
||||
if (cl.search("language-") === 0) return cl.slice("language-".length);
|
||||
if (cl.search('language-') === 0) return cl.slice('language-'.length);
|
||||
|
||||
return null;
|
||||
})
|
||||
@@ -244,7 +244,7 @@ function normalizeHtml(src, options) {
|
||||
.value();
|
||||
|
||||
var source = $(this).text();
|
||||
var blk = options.book.template.applyBlock("code", {
|
||||
var blk = options.book.template.applyBlock('code', {
|
||||
body: source,
|
||||
kwargs: {
|
||||
language: lang
|
||||
@@ -261,12 +261,12 @@ function normalizeHtml(src, options) {
|
||||
});
|
||||
|
||||
_.each(glossary, function(term) {
|
||||
var r = new RegExp( "\\b(" + pregQuote(term.name.toLowerCase()) + ")\\b" , "gi" );
|
||||
var r = new RegExp( '\\b(' + pregQuote(term.name.toLowerCase()) + ')\\b' , 'gi' );
|
||||
var includedInFiles = false;
|
||||
|
||||
$("*").each(function() {
|
||||
$('*').each(function() {
|
||||
// Ignore codeblocks
|
||||
if (_.contains(["code", "pre", "a"], this.name.toLowerCase())) return;
|
||||
if (_.contains(['code', 'pre', 'a'], this.name.toLowerCase())) return;
|
||||
|
||||
replaceText($, this, r, function(match) {
|
||||
// Add to files index in glossary
|
||||
@@ -275,7 +275,7 @@ function normalizeHtml(src, options) {
|
||||
term.files = term.files || [];
|
||||
term.files.push(options.navigation[options.input]);
|
||||
}
|
||||
return "<a href=\""+links.toAbsolute("/GLOSSARY.html", options.base, options.output) + "#" + term.id+"\" class=\"glossary-term\" title=\""+_.escape(term.description)+"\">"+match+"</a>";
|
||||
return '<a href=\''+links.toAbsolute('/GLOSSARY.html', options.base, options.output) + '#' + term.id+'\' class=\'glossary-term\' title=\''+_.escape(term.description)+'\'>'+match+'</a>';
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -291,7 +291,7 @@ function convertImages(images, options) {
|
||||
if (!options.convertImages) return Q();
|
||||
|
||||
var downloaded = [];
|
||||
options.book.log.debug.ln("convert ", images.length, "images to png");
|
||||
options.book.log.debug.ln('convert ', images.length, 'images to png');
|
||||
|
||||
return batch.execEach(images, {
|
||||
max: 100,
|
||||
@@ -303,13 +303,13 @@ function convertImages(images, options) {
|
||||
// Write image if need to be download
|
||||
.then(function() {
|
||||
if (!image.origin && !_.contains(downloaded, image.origin)) return;
|
||||
options.book.log.debug("download image", image.origin, "...");
|
||||
options.book.log.debug('download image', image.origin, '...');
|
||||
downloaded.push(image.origin);
|
||||
return options.book.log.debug.promise(fs.writeStream(imgin, request(image.origin)))
|
||||
.fail(function(err) {
|
||||
if (!_.isError(err)) err = new Error(err);
|
||||
|
||||
err.message = "Fail downloading "+image.origin+": "+err.message;
|
||||
err.message = 'Fail downloading '+image.origin+': '+err.message;
|
||||
throw err;
|
||||
});
|
||||
})
|
||||
@@ -324,13 +324,13 @@ function convertImages(images, options) {
|
||||
.then(function() {
|
||||
if (!image.dest) return;
|
||||
var imgout = path.resolve(options.book.options.output, image.dest);
|
||||
options.book.log.debug("convert image", image.source, "to", image.dest, "...");
|
||||
options.book.log.debug('convert image', image.source, 'to', image.dest, '...');
|
||||
return options.book.log.debug.promise(imgUtils.convertSVG(imgin, imgout));
|
||||
});
|
||||
}
|
||||
})
|
||||
.then(function() {
|
||||
options.book.log.debug.ok(images.length+" images converted with success");
|
||||
options.book.log.debug.ok(images.length+' images converted with success');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -344,16 +344,16 @@ function normalizePage(sections, options) {
|
||||
convertImages: false,
|
||||
|
||||
// Current file path
|
||||
input: ".",
|
||||
input: '.',
|
||||
|
||||
// Navigation to use to transform path
|
||||
navigation: {},
|
||||
|
||||
// Directory parent of the file currently in rendering process
|
||||
base: "./",
|
||||
base: './',
|
||||
|
||||
// Directory parent from the html output
|
||||
output: "./",
|
||||
output: './',
|
||||
|
||||
// Glossary terms
|
||||
glossary: []
|
||||
@@ -363,7 +363,7 @@ function normalizePage(sections, options) {
|
||||
var toConvert = [];
|
||||
|
||||
sections = _.map(sections, function(section) {
|
||||
if (section.type != "normal") return section;
|
||||
if (section.type != 'normal') return section;
|
||||
|
||||
var out = normalizeHtml(section.content, options);
|
||||
|
||||
@@ -374,27 +374,13 @@ function normalizePage(sections, options) {
|
||||
|
||||
return Q()
|
||||
.then(function() {
|
||||
toConvert = _.uniq(toConvert, "source");
|
||||
toConvert = _.uniq(toConvert, 'source');
|
||||
return convertImages(toConvert, options);
|
||||
})
|
||||
.thenResolve(sections);
|
||||
}
|
||||
|
||||
// Extract text from sections
|
||||
function extractText(sections) {
|
||||
return _.reduce(sections, function(prev, section) {
|
||||
if (section.type != "normal") return prev;
|
||||
|
||||
var $ = cheerio.load(section.content);
|
||||
$("*").each(function() {
|
||||
prev = prev+" "+$(this).text();
|
||||
});
|
||||
|
||||
return prev;
|
||||
}, "");
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
normalize: normalizePage,
|
||||
extractText: extractText
|
||||
normalize: normalizePage
|
||||
};
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
var semver = require('semver');
|
||||
var pkg = require('../package.json');
|
||||
|
||||
var VERSION = pkg.version;
|
||||
var VERSION_STABLE = VERSION.replace(/\-(\S+)/g, '');
|
||||
|
||||
// Test if current current gitbook version satisfies a condition
|
||||
// We can't directly use samver.satisfies since it will break all plugins when gitbook version is a prerelease (beta, alpha)
|
||||
function satisfies(condition) {
|
||||
// Test with real version
|
||||
if (semver.satisfies(VERSION, condition)) return true;
|
||||
|
||||
// Test with future stable release
|
||||
return semver.satisfies(VERSION_STABLE, condition);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
satisfies: satisfies
|
||||
};
|
||||
+25
-11
@@ -1,20 +1,22 @@
|
||||
{
|
||||
"name": "gitbook",
|
||||
"version": "2.4.2",
|
||||
"version": "2.5.0-beta.2",
|
||||
"homepage": "https://www.gitbook.com",
|
||||
"description": "Library and cmd utility to generate GitBooks",
|
||||
"main": "lib/index.js",
|
||||
"dependencies": {
|
||||
"q": "1.0.1",
|
||||
"lunr": "0.5.12",
|
||||
"lodash": "3.10.1",
|
||||
"graceful-fs": "3.0.5",
|
||||
"resolve": "0.6.3",
|
||||
"fs-extra": "0.16.5",
|
||||
"fstream-ignore": "1.0.2",
|
||||
"gitbook-parsers": "0.8.2",
|
||||
"gitbook-parsers": "0.8.4",
|
||||
"gitbook-plugin-highlight": "1.0.3",
|
||||
"nunjucks": "mozilla/nunjucks#dc89bf91611a2101731c2c06afcf5c32160b4dc9",
|
||||
"gitbook-plugin-sharing": "1.0.1",
|
||||
"gitbook-plugin-search": "1.0.2",
|
||||
"gitbook-plugin-fontsettings": "1.0.2",
|
||||
"nunjucks": "2.1.0",
|
||||
"nunjucks-autoescape": "1.0.0",
|
||||
"nunjucks-filter": "1.0.0",
|
||||
"i18n": "0.5.0",
|
||||
@@ -33,17 +35,29 @@
|
||||
"npm": "2.4.1",
|
||||
"dom-serializer": "0.1.0",
|
||||
"spawn-cmd": "0.0.2",
|
||||
"escape-string-regexp": "1.0.3"
|
||||
"escape-string-regexp": "1.0.3",
|
||||
"juice": "1.5.0",
|
||||
"jsonschema": "1.0.2",
|
||||
"json-schema-defaults": "0.1.1",
|
||||
"merge-defaults": "0.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "1.5.0",
|
||||
"mocha": "2.3.2",
|
||||
"should": "7.1.0",
|
||||
"grunt": "~0.4.2",
|
||||
"grunt-cli": "0.1.11",
|
||||
"grunt-contrib-copy": "0.5.0",
|
||||
"grunt-contrib-less": "~0.5.0",
|
||||
"grunt-contrib-requirejs": "0.4.1",
|
||||
"grunt-bower-install-simple": "0.9.2"
|
||||
"should-promised": "0.3.1",
|
||||
"gulp": "^3.8.11",
|
||||
"gulp-rename": "^1.2.2",
|
||||
"gulp-uglify": "1.1.0",
|
||||
"gulp-less": "3.0.2",
|
||||
"gulp-minify-css": "1.0.0",
|
||||
"gulp-util": "3.0.6",
|
||||
"browserify": "11.0.1",
|
||||
"merge-stream": "0.1.7",
|
||||
"vinyl-source-stream": "1.1.0",
|
||||
"jquery": "2.1.4",
|
||||
"mousetrap": "1.5.3",
|
||||
"font-awesome": "4.1.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "node_modules/.bin/mocha --reporter spec --timeout 15000"
|
||||
|
||||
+18
-16
@@ -1,27 +1,29 @@
|
||||
var _ = require("lodash");
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
var should = require("should");
|
||||
var cheerio = require("cheerio");
|
||||
var _ = require('lodash');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var should = require('should');
|
||||
var cheerio = require('cheerio');
|
||||
|
||||
should.Assertion.add("file", function(file, description) {
|
||||
this.params = { actual: this.obj.toString(), operator: "have file " + file, message: description };
|
||||
require('should-promised');
|
||||
|
||||
this.obj.should.have.property("options").which.is.an.Object();
|
||||
this.obj.options.should.have.property("output").which.is.a.String();
|
||||
should.Assertion.add('file', function(file, description) {
|
||||
this.params = { actual: this.obj.toString(), operator: 'have file ' + file, message: description };
|
||||
|
||||
this.obj.should.have.property('options').which.is.an.Object();
|
||||
this.obj.options.should.have.property('output').which.is.a.String();
|
||||
this.assert(fs.existsSync(path.resolve(this.obj.options.output, file)));
|
||||
});
|
||||
|
||||
should.Assertion.add("jsonfile", function(file, description) {
|
||||
this.params = { actual: this.obj.toString(), operator: "have valid jsonfile " + file, message: description };
|
||||
should.Assertion.add('jsonfile', function(file, description) {
|
||||
this.params = { actual: this.obj.toString(), operator: 'have valid jsonfile ' + file, message: description };
|
||||
|
||||
this.obj.should.have.property("options").which.is.an.Object();
|
||||
this.obj.options.should.have.property("output").which.is.a.String();
|
||||
this.assert(JSON.parse(fs.readFileSync(path.resolve(this.obj.options.output, file), { encoding: "utf-8" })));
|
||||
this.obj.should.have.property('options').which.is.an.Object();
|
||||
this.obj.options.should.have.property('output').which.is.a.String();
|
||||
this.assert(JSON.parse(fs.readFileSync(path.resolve(this.obj.options.output, file), { encoding: 'utf-8' })));
|
||||
});
|
||||
|
||||
should.Assertion.add("html", function(rules, description) {
|
||||
this.params = { actual: "HTML string", operator: "valid html", message: description };
|
||||
should.Assertion.add('html', function(rules, description) {
|
||||
this.params = { actual: 'HTML string', operator: 'valid html', message: description };
|
||||
var $ = cheerio.load(this.obj);
|
||||
|
||||
_.each(rules, function(validations, query) {
|
||||
|
||||
+17
-17
@@ -1,37 +1,37 @@
|
||||
describe("Configuration", function () {
|
||||
it("should extract default title from README", function() {
|
||||
return books.parse("basic")
|
||||
describe('Configuration', function () {
|
||||
it('should extract default title from README', function() {
|
||||
return books.parse('basic')
|
||||
.then(function(book) {
|
||||
book.options.title.should.be.equal("Readme");
|
||||
book.options.title.should.be.equal('Readme');
|
||||
});
|
||||
});
|
||||
|
||||
it("should extract default description from README", function() {
|
||||
return books.parse("basic")
|
||||
it('should extract default description from README', function() {
|
||||
return books.parse('basic')
|
||||
.then(function(book) {
|
||||
book.options.description.should.be.equal("Default description for the book.");
|
||||
book.options.description.should.be.equal('Default description for the book.');
|
||||
});
|
||||
});
|
||||
|
||||
it("should correctly load from json (book.json)", function() {
|
||||
return books.parse("config-json")
|
||||
it('should correctly load from json (book.json)', function() {
|
||||
return books.parse('config-json')
|
||||
.then(function(book) {
|
||||
book.options.title.should.be.equal("json-config");
|
||||
book.options.title.should.be.equal('json-config');
|
||||
});
|
||||
});
|
||||
|
||||
it("should correctly load from JavaScript (book.js)", function() {
|
||||
return books.parse("config-js")
|
||||
it('should correctly load from JavaScript (book.js)', function() {
|
||||
return books.parse('config-js')
|
||||
.then(function(book) {
|
||||
book.options.title.should.be.equal("js-config");
|
||||
book.options.title.should.be.equal('js-config');
|
||||
});
|
||||
});
|
||||
|
||||
it("should provide configuration on book.config.get", function() {
|
||||
return books.parse("basic")
|
||||
it('should provide configuration on book.config.get', function() {
|
||||
return books.parse('basic')
|
||||
.then(function(book) {
|
||||
book.config.get("description").should.be.equal("Default description for the book.");
|
||||
book.getConfig("description").should.be.equal("Default description for the book.");
|
||||
book.config.get('description').should.be.equal('Default description for the book.');
|
||||
book.getConfig('description').should.be.equal('Default description for the book.');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+25
-21
@@ -1,66 +1,70 @@
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
describe("eBook generator", function () {
|
||||
describe("Basic Book", function() {
|
||||
describe('eBook generator', function () {
|
||||
describe('Basic Book', function() {
|
||||
var book;
|
||||
|
||||
before(function() {
|
||||
return books.generate("basic", "ebook")
|
||||
return books.generate('basic', 'ebook')
|
||||
.then(function(_book) {
|
||||
book = _book;
|
||||
});
|
||||
});
|
||||
|
||||
it("should correctly output a SUMMARY.html", function() {
|
||||
book.should.have.file("SUMMARY.html");
|
||||
it('should correctly output a SUMMARY.html', function() {
|
||||
book.should.have.file('SUMMARY.html');
|
||||
});
|
||||
|
||||
it("should correctly copy assets", function() {
|
||||
book.should.have.file("gitbook");
|
||||
book.should.have.file("gitbook/style.css");
|
||||
it('should correctly copy assets', function() {
|
||||
book.should.have.file('gitbook');
|
||||
book.should.have.file('gitbook/ebook.css');
|
||||
});
|
||||
|
||||
it('should not copy website assets', function() {
|
||||
book.should.not.have.file('gitbook/style.css');
|
||||
});
|
||||
});
|
||||
|
||||
describe("Custom styles", function() {
|
||||
describe('Custom styles', function() {
|
||||
var book;
|
||||
|
||||
before(function() {
|
||||
return books.generate("style-print", "ebook")
|
||||
return books.generate('style-print', 'ebook')
|
||||
.then(function(_book) {
|
||||
book = _book;
|
||||
});
|
||||
});
|
||||
|
||||
it("should remove default print.css", function() {
|
||||
it('should remove default print.css', function() {
|
||||
var PAGE = fs.readFileSync(
|
||||
path.join(book.options.output, "index.html"),
|
||||
{ encoding: "utf-8" }
|
||||
path.join(book.options.output, 'index.html'),
|
||||
{ encoding: 'utf-8' }
|
||||
);
|
||||
|
||||
// There are 2 styles (one from plugin-highlight and the new style)
|
||||
PAGE.should.be.html({
|
||||
"link": {
|
||||
'link': {
|
||||
count: 2
|
||||
}
|
||||
});
|
||||
|
||||
PAGE.should.be.html({
|
||||
"link[href=\"./styles/print.css\"]": {
|
||||
'link[href=\'./styles/print.css\']': {
|
||||
count: 1
|
||||
}
|
||||
});
|
||||
|
||||
PAGE.should.be.html({
|
||||
"link[href=\"gitbook/plugins/gitbook-plugin-highlight/ebook.css\"]": {
|
||||
'link[href="gitbook/plugins/gitbook-plugin-highlight/ebook.css"]': {
|
||||
count: 1
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("should correctly print.css", function() {
|
||||
book.should.have.file("styles");
|
||||
book.should.have.file("styles/print.css");
|
||||
it('should correctly copy print.css', function() {
|
||||
book.should.have.file('styles');
|
||||
book.should.have.file('styles/print.css');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
describe('Formatting', function () {
|
||||
it('should provide formatting with book.formatString', function() {
|
||||
return books.parse('basic')
|
||||
.then(function(book) {
|
||||
return book.formatString('markdown', 'this is a **test**');
|
||||
})
|
||||
.then(function(content) {
|
||||
content.should.equal('<p>this is a <strong>test</strong></p>\n');
|
||||
});
|
||||
});
|
||||
});
|
||||
+13
-13
@@ -1,24 +1,24 @@
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
var should = require("should");
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var should = require('should');
|
||||
|
||||
var Book = require("../").Book;
|
||||
var LOG_LEVELS = require("../").LOG_LEVELS;
|
||||
var Book = require('../').Book;
|
||||
var LOG_LEVELS = require('../').LOG_LEVELS;
|
||||
|
||||
describe("Init Books", function () {
|
||||
describe('Init Books', function () {
|
||||
var initRoot;
|
||||
|
||||
before(function() {
|
||||
initRoot = path.resolve(__dirname, "books/init");
|
||||
initRoot = path.resolve(__dirname, 'books/init');
|
||||
return Book.init(initRoot, {
|
||||
logLevel: LOG_LEVELS.DISABLED,
|
||||
logLevel: LOG_LEVELS.DISABLED
|
||||
});
|
||||
});
|
||||
|
||||
it("should create all chapters", function() {
|
||||
should(fs.existsSync(path.resolve(initRoot, "hello.md"))).be.ok();
|
||||
should(fs.existsSync(path.resolve(initRoot, "hello2.md"))).be.ok();
|
||||
should(fs.existsSync(path.resolve(initRoot, "hello3/hello4.md"))).be.ok();
|
||||
should(fs.existsSync(path.resolve(initRoot, "hello3/hello5/hello6.md"))).be.ok();
|
||||
it('should create all chapters', function() {
|
||||
should(fs.existsSync(path.resolve(initRoot, 'hello.md'))).be.ok();
|
||||
should(fs.existsSync(path.resolve(initRoot, 'hello2.md'))).be.ok();
|
||||
should(fs.existsSync(path.resolve(initRoot, 'hello3/hello4.md'))).be.ok();
|
||||
should(fs.existsSync(path.resolve(initRoot, 'hello3/hello5/hello6.md'))).be.ok();
|
||||
});
|
||||
});
|
||||
|
||||
+132
-101
@@ -1,47 +1,47 @@
|
||||
var _ = require("lodash");
|
||||
var should = require("should");
|
||||
var path = require("path");
|
||||
var _ = require('lodash');
|
||||
var should = require('should');
|
||||
var path = require('path');
|
||||
|
||||
var Plugin = require("../lib/plugin");
|
||||
var parsers = require("gitbook-parsers");
|
||||
var PLUGINS_ROOT = path.resolve(__dirname, "plugins");
|
||||
var Plugin = require('../lib/plugin');
|
||||
var parsers = require('gitbook-parsers');
|
||||
var PLUGINS_ROOT = path.resolve(__dirname, 'plugins');
|
||||
|
||||
describe("Plugins", function () {
|
||||
describe('Plugins', function () {
|
||||
var book;
|
||||
|
||||
before(function() {
|
||||
return books.parse("basic")
|
||||
.then(function(_book) {
|
||||
book = _book;
|
||||
});
|
||||
return books.parse('basic')
|
||||
.then(function(_book) {
|
||||
book = _book;
|
||||
});
|
||||
});
|
||||
|
||||
describe("Invalid", function() {
|
||||
describe('Invalid', function() {
|
||||
var plugin;
|
||||
|
||||
before(function() {
|
||||
plugin = new Plugin(book, "invalid");
|
||||
plugin.load("./invalid", PLUGINS_ROOT);
|
||||
plugin = new Plugin(book, 'invalid');
|
||||
plugin.load('./invalid', PLUGINS_ROOT);
|
||||
});
|
||||
|
||||
it("should be detected", function() {
|
||||
it('should be detected', function() {
|
||||
should(plugin.isValid()).be.exactly(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Empty", function() {
|
||||
describe('Empty', function() {
|
||||
var plugin;
|
||||
|
||||
before(function() {
|
||||
plugin = new Plugin(book, "empty");
|
||||
plugin.load("./empty", PLUGINS_ROOT);
|
||||
plugin = new Plugin(book, 'empty');
|
||||
plugin.load('./empty', PLUGINS_ROOT);
|
||||
});
|
||||
|
||||
it("should valid a plugin", function() {
|
||||
it('should valid a plugin', function() {
|
||||
should(plugin.isValid()).be.exactly(true);
|
||||
});
|
||||
|
||||
it("should return an empty list of resources", function() {
|
||||
it('should return an empty list of resources', function() {
|
||||
return plugin.getResources()
|
||||
.then(function(resources) {
|
||||
_.each(Plugin.RESOURCES, function(resName) {
|
||||
@@ -51,97 +51,128 @@ describe("Plugins", function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe("Resources", function() {
|
||||
describe('Configuration', function() {
|
||||
var plugin;
|
||||
|
||||
before(function() {
|
||||
plugin = new Plugin(book, "resources");
|
||||
plugin.load("./resources", PLUGINS_ROOT);
|
||||
plugin = new Plugin(book, 'testconfig');
|
||||
plugin.load('./config', PLUGINS_ROOT);
|
||||
});
|
||||
|
||||
it('should throw error for invalid configuration', function() {
|
||||
return plugin.validateConfig({})
|
||||
.should.be.rejectedWith('Configuration Error: pluginsConfig.testconfig.testRequired is required');
|
||||
});
|
||||
|
||||
it('should throw error for invalid types', function() {
|
||||
return plugin.validateConfig({
|
||||
testRequired: 'hello'
|
||||
})
|
||||
.should.be.rejectedWith('Configuration Error: pluginsConfig.testconfig.testRequired is not of a type(s) number');
|
||||
});
|
||||
|
||||
it('should extend with default values', function() {
|
||||
return plugin.validateConfig({
|
||||
testRequired: 12
|
||||
})
|
||||
.should.be.fulfilledWith({
|
||||
hello: 'world',
|
||||
testRequired: 12
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Resources', function() {
|
||||
var plugin;
|
||||
|
||||
before(function() {
|
||||
plugin = new Plugin(book, 'resources');
|
||||
plugin.load('./resources', PLUGINS_ROOT);
|
||||
|
||||
return book.plugins.load(plugin);
|
||||
});
|
||||
|
||||
it("should valid a plugin", function() {
|
||||
it('should valid a plugin', function() {
|
||||
should(plugin.isValid()).be.exactly(true);
|
||||
});
|
||||
|
||||
describe("Website", function() {
|
||||
it("should return a valid list of resources", function() {
|
||||
return plugin.getResources("website")
|
||||
describe('Website', function() {
|
||||
it('should return a valid list of resources', function() {
|
||||
return plugin.getResources('website')
|
||||
.then(function(resources) {
|
||||
resources.js.should.have.lengthOf(1);
|
||||
});
|
||||
});
|
||||
|
||||
it("should extend books plugins", function() {
|
||||
var resources = book.plugins.resources("website");
|
||||
resources.js.should.have.lengthOf(1);
|
||||
it('should extend books plugins', function() {
|
||||
var resources = book.plugins.resources('website');
|
||||
resources.js.should.have.lengthOf(5);
|
||||
});
|
||||
});
|
||||
|
||||
describe("eBook", function() {
|
||||
it("should return a valid list of resources", function() {
|
||||
return plugin.getResources("ebook")
|
||||
describe('eBook', function() {
|
||||
it('should return a valid list of resources', function() {
|
||||
return plugin.getResources('ebook')
|
||||
.then(function(resources) {
|
||||
resources.css.should.have.lengthOf(1);
|
||||
});
|
||||
});
|
||||
|
||||
it("should extend books plugins", function() {
|
||||
var resources = book.plugins.resources("ebook");
|
||||
it('should extend books plugins', function() {
|
||||
var resources = book.plugins.resources('ebook');
|
||||
|
||||
// There is resources from highlight plugin and this plugin
|
||||
resources.css.should.have.lengthOf(2);
|
||||
should.exist(_.find(resources.css, {
|
||||
path: "./resources/test"
|
||||
path: 'gitbook-plugin-resources/test'
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Filters", function() {
|
||||
describe('Filters', function() {
|
||||
var plugin;
|
||||
|
||||
before(function() {
|
||||
plugin = new Plugin(book, "filters");
|
||||
plugin.load("./filters", PLUGINS_ROOT);
|
||||
plugin = new Plugin(book, 'filters');
|
||||
plugin.load('./filters', PLUGINS_ROOT);
|
||||
|
||||
return book.plugins.load(plugin);
|
||||
});
|
||||
|
||||
it("should valid a plugin", function() {
|
||||
it('should valid a plugin', function() {
|
||||
should(plugin.isValid()).be.exactly(true);
|
||||
});
|
||||
|
||||
it("should return a map of filters", function() {
|
||||
it('should return a map of filters', function() {
|
||||
var filters = plugin.getFilters();
|
||||
|
||||
_.size(filters).should.equal(2);
|
||||
filters.should.have.property("hello");
|
||||
filters.should.have.property("helloCtx");
|
||||
filters.should.have.property('hello');
|
||||
filters.should.have.property('helloCtx');
|
||||
});
|
||||
|
||||
it("should correctly extend template filters", function() {
|
||||
return book.template.renderString("{{ \"World\"|hello }}")
|
||||
it('should correctly extend template filters', function() {
|
||||
return book.template.renderString('{{ \'World\'|hello }}')
|
||||
.then(function(content) {
|
||||
content.should.equal("Hello World");
|
||||
content.should.equal('Hello World');
|
||||
});
|
||||
});
|
||||
|
||||
it("should correctly set book as context", function() {
|
||||
return book.template.renderString("{{ \"root\"|helloCtx }}")
|
||||
it('should correctly set book as context', function() {
|
||||
return book.template.renderString('{{ \'root\'|helloCtx }}')
|
||||
.then(function(content) {
|
||||
content.should.equal("root:"+book.root);
|
||||
content.should.equal('root:'+book.root);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Blocks", function() {
|
||||
describe('Blocks', function() {
|
||||
var plugin;
|
||||
|
||||
before(function() {
|
||||
plugin = new Plugin(book, "blocks");
|
||||
plugin.load("./blocks", PLUGINS_ROOT);
|
||||
plugin = new Plugin(book, 'blocks');
|
||||
plugin.load('./blocks', PLUGINS_ROOT);
|
||||
|
||||
return book.plugins.load(plugin);
|
||||
});
|
||||
@@ -151,89 +182,89 @@ describe("Plugins", function () {
|
||||
.then(book.template.postProcess);
|
||||
};
|
||||
|
||||
it("should valid a plugin", function() {
|
||||
it('should valid a plugin', function() {
|
||||
should(plugin.isValid()).be.exactly(true);
|
||||
});
|
||||
|
||||
it("should correctly extend template blocks", function() {
|
||||
return testTpl("{% test %}hello{% endtest %}")
|
||||
it('should correctly extend template blocks', function() {
|
||||
return testTpl('{% test %}hello{% endtest %}')
|
||||
.then(function(content) {
|
||||
content.should.equal("testhellotest");
|
||||
content.should.equal('testhellotest');
|
||||
});
|
||||
});
|
||||
|
||||
it("should correctly accept shortcuts", function() {
|
||||
return testTpl("$$hello$$", {}, {
|
||||
type: "markdown"
|
||||
})
|
||||
it('should correctly accept shortcuts', function() {
|
||||
return testTpl('$$hello$$', {}, {
|
||||
type: 'markdown'
|
||||
})
|
||||
.then(function(content) {
|
||||
content.should.equal('testhellotest');
|
||||
});
|
||||
});
|
||||
|
||||
it('should correctly extend template blocks with defined end', function() {
|
||||
return testTpl('{% test2 %}hello{% endtest2end %}')
|
||||
.then(function(content) {
|
||||
content.should.equal("testhellotest");
|
||||
content.should.equal('test2hellotest2');
|
||||
});
|
||||
});
|
||||
|
||||
it("should correctly extend template blocks with defined end", function() {
|
||||
return testTpl("{% test2 %}hello{% endtest2end %}")
|
||||
it('should correctly extend template blocks with sub-blocks', function() {
|
||||
return testTpl('{% test3join separator=";" %}hello{% also %}world{% endtest3join %}')
|
||||
.then(function(content) {
|
||||
content.should.equal("test2hellotest2");
|
||||
content.should.equal('hello;world');
|
||||
});
|
||||
});
|
||||
|
||||
it("should correctly extend template blocks with sub-blocks", function() {
|
||||
return testTpl("{% test3join separator=\";\" %}hello{% also %}world{% endtest3join %}")
|
||||
it('should correctly extend template blocks with different sub-blocks', function() {
|
||||
return testTpl('{% test4join separator=";" %}hello{% also %}the{% finally %}world{% endtest4join %}')
|
||||
.then(function(content) {
|
||||
content.should.equal("hello;world");
|
||||
content.should.equal('hello;the;world');
|
||||
});
|
||||
});
|
||||
|
||||
it("should correctly extend template blocks with different sub-blocks", function() {
|
||||
return testTpl("{% test4join separator=\";\" %}hello{% also %}the{% finally %}world{% endtest4join %}")
|
||||
it('should correctly extend template blocks with arguments (1)', function() {
|
||||
return testTpl('{% test5args "a" %}{% endtest5args %}')
|
||||
.then(function(content) {
|
||||
content.should.equal("hello;the;world");
|
||||
content.should.equal('test5atest5');
|
||||
});
|
||||
});
|
||||
|
||||
it("should correctly extend template blocks with arguments (1)", function() {
|
||||
return testTpl("{% test5args \"a\" %}{% endtest5args %}")
|
||||
it('should correctly extend template blocks with arguments (2)', function() {
|
||||
return testTpl('{% test5args "a", "b" %}{% endtest5args %}')
|
||||
.then(function(content) {
|
||||
content.should.equal("test5atest5");
|
||||
content.should.equal('test5a,btest5');
|
||||
});
|
||||
});
|
||||
|
||||
it("should correctly extend template blocks with arguments (2)", function() {
|
||||
return testTpl("{% test5args 'a', 'b' %}{% endtest5args %}")
|
||||
it('should correctly extend template blocks with arguments (3)', function() {
|
||||
return testTpl('{% test5args "a", "b", "c" %}{% endtest5args %}')
|
||||
.then(function(content) {
|
||||
content.should.equal("test5a,btest5");
|
||||
content.should.equal('test5a,b,ctest5');
|
||||
});
|
||||
});
|
||||
|
||||
it("should correctly extend template blocks with arguments (3)", function() {
|
||||
return testTpl("{% test5args 'a', 'b', 'c' %}{% endtest5args %}")
|
||||
it('should correctly extend template blocks with args and kwargs', function() {
|
||||
return testTpl('{% test5kwargs "a", "b", "c", d="test", e="test2" %}{% endtest5kwargs %}')
|
||||
.then(function(content) {
|
||||
content.should.equal("test5a,b,ctest5");
|
||||
content.should.equal('test5a,b,c,d:test,e:test2,__keywords:truetest5');
|
||||
});
|
||||
});
|
||||
|
||||
it("should correctly extend template blocks with args and kwargs", function() {
|
||||
return testTpl("{% test5kwargs 'a', 'b', 'c', d='test', e='test2' %}{% endtest5kwargs %}")
|
||||
.then(function(content) {
|
||||
content.should.equal("test5a,b,c,d:test,e:test2,__keywords:truetest5");
|
||||
});
|
||||
});
|
||||
|
||||
it("should correctly extend template blocks with access to context", function() {
|
||||
return testTpl("{% set name = 'john' %}{% test6context %}{% endtest6context %}", {})
|
||||
.then(function(content) {
|
||||
content.should.equal("test6johntest6");
|
||||
});
|
||||
it('should correctly extend template blocks with access to context', function() {
|
||||
return testTpl('{% set name = "john" %}{% test6context %}{% endtest6context %}', {})
|
||||
.then(function(content) {
|
||||
content.should.equal('test6johntest6');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Blocks without parsing", function() {
|
||||
describe('Blocks without parsing', function() {
|
||||
var plugin;
|
||||
|
||||
before(function() {
|
||||
plugin = new Plugin(book, "blocks");
|
||||
plugin.load("./blocks", PLUGINS_ROOT);
|
||||
plugin = new Plugin(book, 'blocks');
|
||||
plugin.load('./blocks', PLUGINS_ROOT);
|
||||
|
||||
return book.plugins.load(plugin);
|
||||
});
|
||||
@@ -242,21 +273,21 @@ describe("Plugins", function () {
|
||||
var filetype = parsers.get(markup);
|
||||
|
||||
return book.template.renderString(str, args, options)
|
||||
.then(filetype.page).get("sections").get(0).get("content")
|
||||
.then(filetype.page).get('sections').get(0).get('content')
|
||||
.then(book.template.postProcess);
|
||||
};
|
||||
|
||||
it("should correctly process unparsable for markdown", function() {
|
||||
return testTpl(".md", "{% test %}**hello**{% endtest %}")
|
||||
it('should correctly process unparsable for markdown', function() {
|
||||
return testTpl('.md', '{% test %}**hello**{% endtest %}')
|
||||
.then(function(content) {
|
||||
content.should.equal("<p>test**hello**test</p>\n");
|
||||
content.should.equal('<p>test**hello**test</p>\n');
|
||||
});
|
||||
});
|
||||
|
||||
it("should correctly process unparsable for asciidoc", function() {
|
||||
return testTpl(".adoc", "{% test %}**hello**{% endtest %}")
|
||||
it('should correctly process unparsable for asciidoc', function() {
|
||||
return testTpl('.adoc', '{% test %}**hello**{% endtest %}')
|
||||
.then(function(content) {
|
||||
content.should.equal("<div class=\"paragraph\">\n<p>test**hello**test</p>\n</div>");
|
||||
content.should.equal('<div class="paragraph">\n<p>test**hello**test</p>\n</div>');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
module.exports = {};
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "gitbook-plugin-testconfig",
|
||||
"description": "Test plugin configuration",
|
||||
"main": "index.js",
|
||||
"version": "0.0.1",
|
||||
"engines": {
|
||||
"gitbook": "*"
|
||||
},
|
||||
"gitbook": {
|
||||
"properties": {
|
||||
"hello": {
|
||||
"type": "string",
|
||||
"default": "world"
|
||||
},
|
||||
"testRequired": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
-9
@@ -1,22 +1,26 @@
|
||||
describe("Website generator", function () {
|
||||
describe("Basic Book", function() {
|
||||
describe('Website generator', function () {
|
||||
describe('Basic Book', function() {
|
||||
var book;
|
||||
|
||||
before(function() {
|
||||
return books.generate("basic", "website")
|
||||
return books.generate('basic', 'website')
|
||||
.then(function(_book) {
|
||||
book = _book;
|
||||
});
|
||||
});
|
||||
|
||||
it("should correctly output an index.html", function() {
|
||||
book.should.have.file("index.html");
|
||||
it('should correctly output an index.html', function() {
|
||||
book.should.have.file('index.html');
|
||||
});
|
||||
|
||||
it("should correctly copy assets", function() {
|
||||
book.should.have.file("gitbook");
|
||||
book.should.have.file("gitbook/app.js");
|
||||
book.should.have.file("gitbook/style.css");
|
||||
it('should correctly copy assets', function() {
|
||||
book.should.have.file('gitbook');
|
||||
book.should.have.file('gitbook/app.js');
|
||||
book.should.have.file('gitbook/style.css');
|
||||
});
|
||||
|
||||
it('should not copy ebook assets', function() {
|
||||
book.should.not.have.file('gitbook/ebook.css');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
.section.glossary>h1,.section.toc>h1{text-align:center}.page .section b,.page .section dl dt,.page .section strong,.page .section table th{font-weight:700}.link-inherit,.link-inherit:focus,.link-inherit:hover{color:inherit}.hidden{display:none}.section.toc>ol{margin:0;padding:0}.section.toc li{list-style:none}.section.toc li .inner{display:block;border-bottom:1px dotted #eee;margin-bottom:4px}.section.toc li .inner a,.section.toc li .inner span{padding-right:5px;border-bottom:1px solid #fff;margin-bottom:-1px}.section.toc li .inner .page{float:right;padding-left:5px}.section.toc li ol{margin:0;padding:0 0 0 2em}.dir-rtl .section.toc li .inner .page{float:left}.dir-rtl .section.toc li ol{margin:0;padding:0 2em 0 0}.section.glossary .glossary-entry{margin-bottom:40px}.section.glossary .glossary-entry h2 a,.section.glossary .glossary-entry h2 a:hover{color:inherit;text-decoration:none}.section.glossary .glossary-entry .glossary-index{list-style:none;margin:0;padding:0}.section.glossary .glossary-entry .glossary-index li{display:inline;margin:0 8px;white-space:nowrap}body{font-family:sans-serif;color:#000;text-size-adjust:100%;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}.page .section{display:block;word-wrap:break-word;overflow:hidden;color:#000;line-height:1.6}.page .section *{-moz-box-sizing:border-box;box-sizing:border-box}.page .section>:first-child{margin-top:0!important}.page .section>:last-child{margin-bottom:0!important}.page .section blockquote,.page .section code,.page .section figure,.page .section img,.page .section pre,.page .section table,.page .section tr{page-break-inside:avoid}.page .section h2,.page .section h3,.page .section h4,.page .section h5,.page .section p{orphans:3;widows:3}.page .section h1,.page .section h2,.page .section h3,.page .section h4,.page .section h5{page-break-after:avoid}.page .section em{font-style:italic}.page .section blockquote,.page .section dl,.page .section ol,.page .section p,.page .section table,.page .section ul{margin-top:0;margin-bottom:.8em}.page .section a{color:#4183c4;text-decoration:none;background:0 0}.page .section a:active,.page .section a:focus,.page .section a:hover{outline:0;text-decoration:underline}.page .section img{border:0;max-width:100%}.page .section hr{height:4px;padding:0;margin:1.6em 0;overflow:hidden;background-color:#e7e7e7;border:none}.page .section hr:after,.page .section hr:before{display:table;content:" "}.page .section hr:after{clear:both}.page .section h1,.page .section h2,.page .section h3,.page .section h4,.page .section h5,.page .section h6{margin-top:1.2em;margin-bottom:.8em;font-weight:700}.page .section h1{font-size:2em}.page .section h2{font-size:1.75em}.page .section h3{font-size:1.5em}.page .section h4{font-size:1.25em}.page .section h5,.page .section h6{font-size:1em}.page .section code,.page .section pre{font-family:Consolas,"Liberation Mono",Menlo,Courier,monospace;direction:ltr;border:none}.page .section pre{overflow:auto;word-wrap:normal;margin:0 0 1.2em;padding:.85em 1em;background:#f7f7f7}.page .section pre>code{display:inline;max-width:initial;padding:0;margin:0;overflow:initial;line-height:inherit;font-size:.85em;white-space:pre;background:0 0}.page .section pre>code:after,.page .section pre>code:before{content:normal}.page .section code{padding:.2em;margin:0;font-size:.85em;background-color:#f7f7f7}.page .section code:after,.page .section code:before{letter-spacing:-.2em;content:"\00a0"}.page .section table{display:table;width:100%;border-collapse:collapse;border-spacing:0;overflow:auto}.page .section table td,.page .section table th{padding:6px 13px;border:1px solid #ddd}.page .section table tr{background-color:#fff;border-top:1px solid #ccc}.page .section table tr:nth-child(2n){background-color:#f8f8f8}.page .section ol,.page .section ul{padding:0 0 0 2em;margin-top:0;margin-bottom:0}.page .section ol ol,.page .section ol ul,.page .section ul ol,.page .section ul ul{margin-top:0;margin-bottom:0}.page .section ol ol{list-style-type:lower-roman}.page .section blockquote{margin:0;padding:0 15px;color:#858585;border-left:4px solid #e5e5e5}.page .section blockquote:first-child{margin-top:0}.page .section blockquote:last-child{margin-bottom:0}.page .section dl{padding:0}.page .section dl dt{padding:0;margin-top:.8em;font-style:italic}.page .section dl dd{padding:0 .8em;margin-bottom:.8em}.page .section dd{margin-left:0}.page .book-chapter{display:none}
|
||||
@@ -0,0 +1 @@
|
||||
.section.glossary>h1,.section.toc>h1{text-align:center}.page .section b,.page .section dl dt,.page .section strong,.page .section table th{font-weight:700}.link-inherit,.link-inherit:focus,.link-inherit:hover{color:inherit}.hidden{display:none}.section.toc>ol{margin:0;padding:0}.section.toc li{list-style:none}.section.toc li .inner{display:block;border-bottom:1px dotted #eee;margin-bottom:4px}.section.toc li .inner a,.section.toc li .inner span{padding-right:5px;border-bottom:1px solid #fff;margin-bottom:-1px}.section.toc li .inner .page{float:right;padding-left:5px}.section.toc li ol{margin:0;padding:0 0 0 2em}.dir-rtl .section.toc li .inner .page{float:left}.dir-rtl .section.toc li ol{margin:0;padding:0 2em 0 0}.section.glossary .glossary-entry{margin-bottom:40px}.section.glossary .glossary-entry h2 a,.section.glossary .glossary-entry h2 a:hover{color:inherit;text-decoration:none}.section.glossary .glossary-entry .glossary-index{list-style:none;margin:0;padding:0}.section.glossary .glossary-entry .glossary-index li{display:inline;margin:0 8px;white-space:nowrap}body{font-family:serif;color:#000;text-size-adjust:100%;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}.page .section{display:block;word-wrap:break-word;overflow:hidden;color:#000;line-height:1.6}.page .section *{-moz-box-sizing:border-box;box-sizing:border-box}.page .section>:first-child{margin-top:0!important}.page .section>:last-child{margin-bottom:0!important}.page .section blockquote,.page .section code,.page .section figure,.page .section img,.page .section pre,.page .section table,.page .section tr{page-break-inside:avoid}.page .section h2,.page .section h3,.page .section h4,.page .section h5,.page .section p{orphans:3;widows:3}.page .section h1,.page .section h2,.page .section h3,.page .section h4,.page .section h5{page-break-after:avoid}.page .section em{font-style:italic}.page .section blockquote,.page .section dl,.page .section ol,.page .section p,.page .section table,.page .section ul{margin-top:0;margin-bottom:.8em}.page .section a{color:#4183c4;text-decoration:none;background:0 0}.page .section a:active,.page .section a:focus,.page .section a:hover{outline:0;text-decoration:underline}.page .section img{border:0;max-width:100%}.page .section hr{height:4px;padding:0;margin:1.6em 0;overflow:hidden;background-color:#e7e7e7;border:none}.page .section hr:after,.page .section hr:before{display:table;content:" "}.page .section hr:after{clear:both}.page .section h1,.page .section h2,.page .section h3,.page .section h4,.page .section h5,.page .section h6{margin-top:1.2em;margin-bottom:.8em;font-weight:700}.page .section h1{font-size:2em}.page .section h2{font-size:1.75em}.page .section h3{font-size:1.5em}.page .section h4{font-size:1.25em}.page .section h5,.page .section h6{font-size:1em}.page .section code,.page .section pre{font-family:Consolas,"Liberation Mono",Menlo,Courier,monospace;direction:ltr;border:none}.page .section pre{overflow:auto;word-wrap:normal;margin:0 0 1.2em;padding:.85em 1em;background:#f7f7f7}.page .section pre>code{display:inline;max-width:initial;padding:0;margin:0;overflow:initial;line-height:inherit;font-size:.85em;white-space:pre;background:0 0}.page .section pre>code:after,.page .section pre>code:before{content:normal}.page .section code{padding:.2em;margin:0;font-size:.85em;background-color:#f7f7f7}.page .section code:after,.page .section code:before{letter-spacing:-.2em;content:"\00a0"}.page .section table{display:table;width:100%;border-collapse:collapse;border-spacing:0;overflow:auto}.page .section table td,.page .section table th{padding:6px 13px;border:1px solid #ddd}.page .section table tr{background-color:#fff;border-top:1px solid #ccc}.page .section table tr:nth-child(2n){background-color:#f8f8f8}.page .section ol,.page .section ul{padding:0 0 0 2em;margin-top:0;margin-bottom:0}.page .section ol ol,.page .section ol ul,.page .section ul ol,.page .section ul ul{margin-top:0;margin-bottom:0}.page .section ol ol{list-style-type:lower-roman}.page .section blockquote{margin:0;padding:0 15px;color:#858585;border-left:4px solid #e5e5e5}.page .section blockquote:first-child{margin-top:0}.page .section blockquote:last-child{margin-bottom:0}.page .section dl{padding:0}.page .section dl dt{padding:0;margin-top:.8em;font-style:italic}.page .section dl dd{padding:0 .8em;margin-bottom:.8em}.page .section dd{margin-left:0}.page .book-chapter{display:none}
|
||||
@@ -0,0 +1 @@
|
||||
.section.glossary>h1,.section.toc>h1{text-align:center}.page .section b,.page .section dl dt,.page .section strong,.page .section table th{font-weight:700}.link-inherit,.link-inherit:focus,.link-inherit:hover{color:inherit}.hidden{display:none}.section.toc>ol{margin:0;padding:0}.section.toc li{list-style:none}.section.toc li .inner{display:block;border-bottom:1px dotted #eee;margin-bottom:4px}.section.toc li .inner a,.section.toc li .inner span{padding-right:5px;border-bottom:1px solid #fff;margin-bottom:-1px}.section.toc li .inner .page{float:right;padding-left:5px}.section.toc li ol{margin:0;padding:0 0 0 2em}.dir-rtl .section.toc li .inner .page{float:left}.dir-rtl .section.toc li ol{margin:0;padding:0 2em 0 0}.section.glossary .glossary-entry{margin-bottom:40px}.section.glossary .glossary-entry h2 a,.section.glossary .glossary-entry h2 a:hover{color:inherit;text-decoration:none}.section.glossary .glossary-entry .glossary-index{list-style:none;margin:0;padding:0}.section.glossary .glossary-entry .glossary-index li{display:inline;margin:0 8px;white-space:nowrap}body{font-family:serif;color:#000;text-size-adjust:100%;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}.page .section{display:block;word-wrap:break-word;overflow:hidden;color:#000;line-height:1.6}.page .section *{-moz-box-sizing:border-box;box-sizing:border-box}.page .section>:first-child{margin-top:0!important}.page .section>:last-child{margin-bottom:0!important}.page .section blockquote,.page .section code,.page .section figure,.page .section img,.page .section pre,.page .section table,.page .section tr{page-break-inside:avoid}.page .section h2,.page .section h3,.page .section h4,.page .section h5,.page .section p{orphans:3;widows:3}.page .section h1,.page .section h2,.page .section h3,.page .section h4,.page .section h5{page-break-after:avoid}.page .section em{font-style:italic}.page .section blockquote,.page .section dl,.page .section ol,.page .section p,.page .section table,.page .section ul{margin-top:0;margin-bottom:.8em}.page .section a{color:#000;text-decoration:none;background:0 0}.page .section a:active,.page .section a:focus,.page .section a:hover{outline:0;text-decoration:underline}.page .section img{border:0;max-width:100%}.page .section hr{height:4px;padding:0;margin:1.6em 0;overflow:hidden;background-color:#e7e7e7;border:none}.page .section hr:after,.page .section hr:before{display:table;content:" "}.page .section hr:after{clear:both}.page .section h1,.page .section h2,.page .section h3,.page .section h4,.page .section h5,.page .section h6{margin-top:1.2em;margin-bottom:.8em;font-weight:700}.page .section h1{font-size:2em}.page .section h2{font-size:1.75em}.page .section h3{font-size:1.5em}.page .section h4{font-size:1.25em}.page .section h5,.page .section h6{font-size:1em}.page .section code,.page .section pre{font-family:Consolas,"Liberation Mono",Menlo,Courier,monospace;direction:ltr;border:none}.page .section pre{overflow:auto;word-wrap:normal;margin:0 0 1.2em;padding:.85em 1em;background:#f7f7f7}.page .section pre>code{display:inline;max-width:initial;padding:0;margin:0;overflow:initial;line-height:inherit;font-size:.85em;white-space:pre;background:0 0}.page .section pre>code:after,.page .section pre>code:before{content:normal}.page .section code{padding:.2em;margin:0;font-size:.85em;background-color:#f7f7f7}.page .section code:after,.page .section code:before{letter-spacing:-.2em;content:"\00a0"}.page .section table{display:table;width:100%;border-collapse:collapse;border-spacing:0;overflow:auto}.page .book-chapter,.page-toc li .inner span.page{display:none}.page .section table td,.page .section table th{padding:6px 13px;border:1px solid #ddd}.page .section table tr{background-color:#fff;border-top:1px solid #ccc}.page .section table tr:nth-child(2n){background-color:#f8f8f8}.page .section ol,.page .section ul{padding:0 0 0 2em;margin-top:0;margin-bottom:0}.page .section ol ol,.page .section ol ul,.page .section ul ol,.page .section ul ul{margin-top:0;margin-bottom:0}.page .section ol ol{list-style-type:lower-roman}.page .section blockquote{margin:0;padding:0 15px;color:#858585;border-left:4px solid #e5e5e5}.page .section blockquote:first-child{margin-top:0}.page .section blockquote:last-child{margin-bottom:0}.page .section dl{padding:0}.page .section dl dt{padding:0;margin-top:.8em;font-style:italic}.page .section dl dd{padding:0 .8em;margin-bottom:.8em}.page .section dd{margin-left:0}a{color:#000;text-decoration:underline!important}.page-toc li{list-style-type:lower-alpha}.page-toc li .inner{border:none}
|
||||
@@ -0,0 +1 @@
|
||||
.section.glossary>h1,.section.toc>h1{text-align:center}.page .section b,.page .section dl dt,.page .section strong,.page .section table th{font-weight:700}.link-inherit,.link-inherit:focus,.link-inherit:hover{color:inherit}.hidden{display:none}.section.toc>ol{margin:0;padding:0}.section.toc li{list-style:none}.section.toc li .inner{display:block;border-bottom:1px dotted #eee;margin-bottom:4px}.section.toc li .inner a,.section.toc li .inner span{padding-right:5px;border-bottom:1px solid #fff;margin-bottom:-1px}.section.toc li .inner .page{float:right;padding-left:5px}.section.toc li ol{margin:0;padding:0 0 0 2em}.dir-rtl .section.toc li .inner .page{float:left}.dir-rtl .section.toc li ol{margin:0;padding:0 2em 0 0}.section.glossary .glossary-entry{margin-bottom:40px}.section.glossary .glossary-entry h2 a,.section.glossary .glossary-entry h2 a:hover{color:inherit;text-decoration:none}.section.glossary .glossary-entry .glossary-index{list-style:none;margin:0;padding:0}.section.glossary .glossary-entry .glossary-index li{display:inline;margin:0 8px;white-space:nowrap}body{font-family:sans-serif;color:#000;text-size-adjust:100%;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}.page .section{display:block;word-wrap:break-word;overflow:hidden;color:#000;line-height:1.6}.page .section *{-moz-box-sizing:border-box;box-sizing:border-box}.page .section>:first-child{margin-top:0!important}.page .section>:last-child{margin-bottom:0!important}.page .section blockquote,.page .section code,.page .section figure,.page .section img,.page .section pre,.page .section table,.page .section tr{page-break-inside:avoid}.page .section h2,.page .section h3,.page .section h4,.page .section h5,.page .section p{orphans:3;widows:3}.page .section h1,.page .section h2,.page .section h3,.page .section h4,.page .section h5{page-break-after:avoid}.page .section em{font-style:italic}.page .section blockquote,.page .section dl,.page .section ol,.page .section p,.page .section table,.page .section ul{margin-top:0;margin-bottom:.8em}.page .section a{color:#4183c4;text-decoration:none;background:0 0}.page .section a:active,.page .section a:focus,.page .section a:hover{outline:0;text-decoration:underline}.page .section img{border:0;max-width:100%}.page .section hr{height:4px;padding:0;margin:1.6em 0;overflow:hidden;background-color:#e7e7e7;border:none}.page .section hr:after,.page .section hr:before{display:table;content:" "}.page .section hr:after{clear:both}.page .section h1,.page .section h2,.page .section h3,.page .section h4,.page .section h5,.page .section h6{margin-top:1.2em;margin-bottom:.8em;font-weight:700}.page .section h1{font-size:2em}.page .section h2{font-size:1.75em}.page .section h3{font-size:1.5em}.page .section h4{font-size:1.25em}.page .section h5,.page .section h6{font-size:1em}.page .section code,.page .section pre{font-family:Consolas,"Liberation Mono",Menlo,Courier,monospace;direction:ltr;border:none}.page .section pre{overflow:auto;word-wrap:normal;margin:0 0 1.2em;padding:.85em 1em;background:#f7f7f7}.page .section pre>code{display:inline;max-width:initial;padding:0;margin:0;overflow:initial;line-height:inherit;font-size:.85em;white-space:pre;background:0 0}.page .section pre>code:after,.page .section pre>code:before{content:normal}.page .section code{padding:.2em;margin:0;font-size:.85em;background-color:#f7f7f7}.page .section code:after,.page .section code:before{letter-spacing:-.2em;content:"\00a0"}.page .section table{display:table;width:100%;border-collapse:collapse;border-spacing:0;overflow:auto}.page .section table td,.page .section table th{padding:6px 13px;border:1px solid #ddd}.page .section table tr{background-color:#fff;border-top:1px solid #ccc}.page .section table tr:nth-child(2n){background-color:#f8f8f8}.page .section ol,.page .section ul{padding:0 0 0 2em;margin-top:0;margin-bottom:0}.page .section ol ol,.page .section ol ul,.page .section ul ol,.page .section ul ul{margin-top:0;margin-bottom:0}.page .section ol ol{list-style-type:lower-roman}.page .section blockquote{margin:0;padding:0 15px;color:#858585;border-left:4px solid #e5e5e5}.page .section blockquote:first-child{margin-top:0}.page .section blockquote:last-child{margin-bottom:0}.page .section dl{padding:0}.page .section dl dt{padding:0;margin-top:.8em;font-style:italic}.pdf-footer,.pdf-header{margin-top:20px;color:#aaa}.page .section dl dd{padding:0 .8em;margin-bottom:.8em}.page .section dd{margin-left:0}.page .book-chapter{display:none}.pdf-footer{padding-top:10px;border-top:1px solid #eee}.pdf-footer .footer-pages-count{float:right}.pdf-header{padding-bottom:10px;border-bottom:1px solid #eee}
|
||||
@@ -1 +0,0 @@
|
||||
.link-inherit{color:inherit}.link-inherit:hover,.link-inherit:focus{color:inherit}.hidden{display:none}.page.page-toc .glossary{margin-bottom:40px}.page.page-toc .glossary h2 a,.page.page-toc .glossary h2 a:hover{color:inherit;text-decoration:none}.page.page-toc .glossary .glossary-index{list-style:none;margin:0;padding:0}.page.page-toc .glossary .glossary-index li{display:inline;margin:0 8px;white-space:nowrap}.page .book-chapter{display:none}body .page{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;line-height:1.4;color:#000;overflow:hidden;line-height:1.6;word-wrap:break-word;display:block}body .page>*:first-child{margin-top:0!important}body .page>*:last-child{margin-bottom:0!important}body .page a{background:transparent}body .page a:active,body .page a:hover{outline:0}body .page strong{font-weight:bold}body .page h1{font-size:2em;margin:.67em 0}body .page img{border:0}body .page hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}body .page pre{overflow:auto}body .page code,body .page pre{font-family:monospace,monospace;font-size:1em;direction:ltr}body .page table{border-collapse:collapse;border-spacing:0}body .page td,body .page th{padding:0}body .page *{-moz-box-sizing:border-box;box-sizing:border-box}body .page a{color:#4183c4;text-decoration:none}body .page a:hover,body .page a:focus,body .page a:active{text-decoration:underline}body .page hr{height:0;margin:15px 0;overflow:hidden;background:transparent;border:0;border-bottom:1px solid #ddd}body .page hr:before,body .page hr:after{display:table;content:" "}body .page hr:after{clear:both}body .page h1,body .page h2,body .page h3,body .page h4,body .page h5,body .page h6{margin-top:15px;margin-bottom:15px;line-height:1.1}body .page h1{font-size:30px}body .page h2{font-size:21px}body .page h3{font-size:16px}body .page h4{font-size:14px}body .page h5{font-size:12px}body .page h6{font-size:11px}body .page blockquote{margin:0}body .page ul,body .page ol{padding:0;margin-top:0;margin-bottom:0}body .page ol ol{list-style-type:lower-roman}body .page dd{margin-left:0}body .page code,body .page pre{font-family:Consolas,"Liberation Mono",Menlo,Courier,monospace;font-size:12px}body .page pre{margin-top:0;margin-bottom:0}body .page .markdown-body>*:first-child{margin-top:0!important}body .page .markdown-body>*:last-child{margin-bottom:0!important}body .page .anchor{position:absolute;top:0;bottom:0;left:0;display:block;padding-right:6px;padding-left:30px;margin-left:-30px}body .page .anchor:focus{outline:0}body .page h1,body .page h2,body .page h3,body .page h4,body .page h5,body .page h6{position:relative;margin-top:1em;margin-bottom:16px;font-weight:bold;line-height:1.4}body .page h1{padding-bottom:.3em;font-size:2.25em;line-height:1.2;border-bottom:1px solid #eee}body .page h2{padding-bottom:.3em;font-size:1.75em;line-height:1.225;border-bottom:1px solid #eee}body .page h3{font-size:1.5em;line-height:1.43}body .page h4{font-size:1.25em}body .page h5{font-size:1em}body .page h6{font-size:1em;color:#777}body .page p,body .page blockquote,body .page ul,body .page ol,body .page dl,body .page table,body .page pre{margin-top:0;margin-bottom:16px}body .page hr{height:4px;padding:0;margin:16px 0;background-color:#e7e7e7;border:0 none}body .page ul,body .page ol{padding-left:2em}body .page ol ol,body .page ol ul,body .page ul ul{margin-top:0;margin-bottom:0}body .page dl{padding:0}body .page dl dt{padding:0;margin-top:16px;font-size:1em;font-style:italic;font-weight:bold}body .page dl dd{padding:0 16px;margin-bottom:16px}body .page blockquote{padding:0 15px;color:#777;border-left:4px solid #ddd}body .page blockquote>:first-child{margin-top:0}body .page blockquote>:last-child{margin-bottom:0}body .page table{display:block;width:100%;overflow:auto}body .page table th{font-weight:bold}body .page table th,body .page table td{padding:6px 13px;border:1px solid #ddd}body .page table tr{background-color:#fff;border-top:1px solid #ccc}body .page table tr:nth-child(2n){background-color:#f8f8f8}body .page img{max-width:100%;-moz-box-sizing:border-box;box-sizing:border-box;page-break-inside:avoid}body .page code{padding:0;padding-top:.2em;padding-bottom:.2em;margin:0;font-size:85%;background-color:#f7f7f7;border-radius:3px}body .page code:before,body .page code:after{letter-spacing:-0.2em;content:"\00a0"}body .page pre>code{padding:0;margin:0;font-size:100%;white-space:pre;background:transparent;border:0}body .page .highlight pre,body .page pre{padding:16px;overflow:auto;font-size:85%;line-height:1.45;background-color:#f7f7f7;border:0;border-radius:3px}body .page pre{word-wrap:normal}body .page pre code{display:inline;max-width:initial;padding:0;margin:0;overflow:initial;line-height:inherit;word-wrap:normal;background-color:transparent;border:0}body .page pre code:before,body .page pre code:after{content:normal}body .page .highlight{background:#fff}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
Executable → Regular
|
Before Width: | Height: | Size: 248 KiB After Width: | Height: | Size: 248 KiB |
|
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
Executable
+9
File diff suppressed because one or more lines are too long
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"LANGS_CHOOSE": "Виберіть мову",
|
||||
"GLOSSARY": "Глосарій",
|
||||
"GLOSSARY_INDEX": "Глосарій",
|
||||
"GLOSSARY_OPEN": "Глосарій",
|
||||
"GITBOOK_LINK": "Опубліковано за допомогою GitBook",
|
||||
"SUMMARY": "Зміст",
|
||||
"SUMMARY_INTRODUCTION": "Вступ",
|
||||
"SUMMARY_TOGGLE": "Зміст",
|
||||
"SEARCH_TOGGLE": "Пошук",
|
||||
"SEARCH_PLACEHOLDER": "Введіть для пошуку",
|
||||
"FONTSETTINGS_TOGGLE": "Шрифт",
|
||||
"SHARE_TOGGLE": "Поділиться",
|
||||
"SHARE_ON": "Поділитися в {{platform}}",
|
||||
"FONTSETTINGS_WHITE": "Світлий",
|
||||
"FONTSETTINGS_SEPIA": "Сепія",
|
||||
"FONTSETTINGS_NIGHT": "Темний",
|
||||
"FONTSETTINGS_SANS": "Sans",
|
||||
"FONTSETTINGS_SERIF": "Serif"
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
define([
|
||||
"jQuery"
|
||||
], function($) {
|
||||
var events = $({});
|
||||
|
||||
return events;
|
||||
});
|
||||
@@ -1,103 +0,0 @@
|
||||
define([
|
||||
"jQuery",
|
||||
"utils/storage"
|
||||
], function($, storage) {
|
||||
var fontState;
|
||||
|
||||
var THEMES = {
|
||||
"white": 0,
|
||||
"sepia": 1,
|
||||
"night": 2
|
||||
};
|
||||
|
||||
var FAMILY = {
|
||||
"serif": 0,
|
||||
"sans": 1
|
||||
};
|
||||
|
||||
var enlargeFontSize = function(e){
|
||||
if (fontState.size < 4){
|
||||
fontState.size++;
|
||||
fontState.save();
|
||||
}
|
||||
};
|
||||
|
||||
var reduceFontSize = function(e){
|
||||
if (fontState.size > 0){
|
||||
fontState.size--;
|
||||
fontState.save();
|
||||
}
|
||||
};
|
||||
|
||||
var changeFontFamily = function(){
|
||||
var index = $(this).data("font");
|
||||
|
||||
fontState.family = index;
|
||||
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 update = function() {
|
||||
var $book = $(".book");
|
||||
|
||||
$(".font-settings .font-family-list li").removeClass("active");
|
||||
$(".font-settings .font-family-list li:nth-child("+(fontState.family+1)+")").addClass("active");
|
||||
|
||||
$book[0].className = $book[0].className.replace(/\bfont-\S+/g, '');
|
||||
$book.addClass("font-size-"+fontState.size);
|
||||
$book.addClass("font-family-"+fontState.family);
|
||||
|
||||
if(fontState.theme !== 0) {
|
||||
$book[0].className = $book[0].className.replace(/\bcolor-theme-\S+/g, '');
|
||||
$book.addClass("color-theme-"+fontState.theme);
|
||||
}
|
||||
};
|
||||
|
||||
var init = function(config) {
|
||||
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: config.size || 2,
|
||||
family: FAMILY[config.family || "sans"],
|
||||
theme: THEMES[config.theme || "white"]
|
||||
});
|
||||
fontState.save = function(){
|
||||
storage.set("fontState",fontState);
|
||||
update();
|
||||
};
|
||||
|
||||
update();
|
||||
|
||||
//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 .button", changeFontFamily);
|
||||
$(document).on('click', "#font-settings-wrapper .color-theme-list .button", changeColorTheme);
|
||||
};
|
||||
|
||||
return {
|
||||
init: init,
|
||||
update: update
|
||||
}
|
||||
});
|
||||
@@ -1,38 +0,0 @@
|
||||
define([
|
||||
"jQuery",
|
||||
"Mousetrap",
|
||||
"core/navigation",
|
||||
"core/sidebar",
|
||||
"core/search"
|
||||
], function($, Mousetrap, navigation, sidebar, search){
|
||||
// Bind keyboard shortcuts
|
||||
var init = function() {
|
||||
// Next
|
||||
Mousetrap.bind(['right'], function(e) {
|
||||
navigation.goNext();
|
||||
return false;
|
||||
});
|
||||
|
||||
// Prev
|
||||
Mousetrap.bind(['left'], function(e) {
|
||||
navigation.goPrev();
|
||||
return false;
|
||||
});
|
||||
|
||||
// Toggle Summary
|
||||
Mousetrap.bind(['s'], function(e) {
|
||||
sidebar.toggle();
|
||||
return false;
|
||||
});
|
||||
|
||||
// Toggle Search
|
||||
Mousetrap.bind(['f'], function(e) {
|
||||
search.toggle();
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
init: init
|
||||
};
|
||||
});
|
||||
@@ -1,16 +0,0 @@
|
||||
define([
|
||||
"jQuery"
|
||||
], function($) {
|
||||
var showLoading = function(p) {
|
||||
$(".book").addClass("is-loading");
|
||||
p.always(function() {
|
||||
$(".book").removeClass("is-loading");
|
||||
});
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
return {
|
||||
show: showLoading
|
||||
};
|
||||
});
|
||||
@@ -1,174 +0,0 @@
|
||||
define([
|
||||
"jQuery",
|
||||
"utils/url",
|
||||
"core/events",
|
||||
"core/state",
|
||||
"core/progress",
|
||||
"core/loading",
|
||||
"core/search"
|
||||
], function($, URL, events, state, progress, loading, search) {
|
||||
var prev, next;
|
||||
|
||||
var usePushState = (typeof history.pushState !== "undefined");
|
||||
|
||||
var handleNavigation = function(relativeUrl, push) {
|
||||
var url = URL.join(window.location.pathname, relativeUrl);
|
||||
console.log("navigate to ", url, "baseurl="+relativeUrl, "current="+window.location.pathname);
|
||||
|
||||
if (!usePushState) {
|
||||
// Refresh the page to the new URL if pushState not supported
|
||||
location.href = relativeUrl;
|
||||
return
|
||||
}
|
||||
|
||||
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 + '>';
|
||||
});
|
||||
|
||||
var $page = $(html);
|
||||
var $pageHead = $page.find("[data-element=head]");
|
||||
var $pageBody = $page.find('.book');
|
||||
|
||||
////
|
||||
// Merge heads
|
||||
// !! Warning !!: we only update necessary portions to avoid strange behavior (page flickering etc ...)
|
||||
////
|
||||
|
||||
// Update title
|
||||
document.title = $pageHead.find("title").text();
|
||||
|
||||
// Reference to $("head");
|
||||
var $head = $("head");
|
||||
|
||||
// Update next & prev <link> tags
|
||||
// Remove old
|
||||
$head.find("link[rel=prev]").remove();
|
||||
$head.find("link[rel=next]").remove();
|
||||
|
||||
// Add new next * prev <link> tags
|
||||
$head.append($pageHead.find("link[rel=prev]"));
|
||||
$head.append($pageHead.find("link[rel=next]"));
|
||||
|
||||
// Merge body
|
||||
var bodyClass = $(".book").attr("class");
|
||||
var scrollPosition = $('.book-summary .summary').scrollTop();
|
||||
$pageBody.toggleClass("with-summary", $(".book").hasClass("with-summary"))
|
||||
|
||||
$(".book").replaceWith($pageBody);
|
||||
$(".book").attr("class", bodyClass);
|
||||
$('.book-summary .summary').scrollTop(scrollPosition);
|
||||
|
||||
// Update state
|
||||
state.update($("html"));
|
||||
// recover search keyword
|
||||
search.recover();
|
||||
preparePage();
|
||||
})
|
||||
.fail(function (e) {
|
||||
location.href = relativeUrl;
|
||||
}));
|
||||
};
|
||||
|
||||
var updateNavigationPosition = function() {
|
||||
var bodyInnerWidth, pageWrapperWidth;
|
||||
|
||||
bodyInnerWidth = parseInt($('.body-inner').css('width'), 10);
|
||||
pageWrapperWidth = parseInt($('.page-wrapper').css('width'), 10);
|
||||
$('.navigation-next').css('margin-right', (bodyInnerWidth - pageWrapperWidth) + 'px');
|
||||
};
|
||||
|
||||
var preparePage = function() {
|
||||
var $bookBody = $(".book-body");
|
||||
var $bookInner = $bookBody.find(".body-inner");
|
||||
var $pageWrapper = $bookInner.find(".page-wrapper");
|
||||
|
||||
// Show progress
|
||||
progress.show();
|
||||
|
||||
// Update navigation position
|
||||
updateNavigationPosition();
|
||||
|
||||
// Focus on content
|
||||
$pageWrapper.focus();
|
||||
|
||||
// Reset scroll
|
||||
$bookInner.scrollTop(0);
|
||||
$bookBody.scrollTop(0);
|
||||
|
||||
// Notify
|
||||
events.trigger("page.change");
|
||||
};
|
||||
|
||||
var isLeftClickEvent = function (e) {
|
||||
return e.button === 0;
|
||||
};
|
||||
|
||||
var isModifiedEvent = function (e) {
|
||||
return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
|
||||
};
|
||||
|
||||
var handlePagination = function (e) {
|
||||
if (isModifiedEvent(e) || !isLeftClickEvent(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
var url = $(this).attr('href');
|
||||
if (url) handleNavigation(url, true);
|
||||
};
|
||||
|
||||
var goNext = function() {
|
||||
var url = $(".navigation-next").attr("href");
|
||||
if (url) handleNavigation(url, true);
|
||||
};
|
||||
|
||||
var goPrev = function() {
|
||||
var url = $(".navigation-prev").attr("href");
|
||||
if (url) handleNavigation(url, true);
|
||||
};
|
||||
|
||||
|
||||
|
||||
var init = function() {
|
||||
// Prevent cache so that using the back button works
|
||||
// See: http://stackoverflow.com/a/15805399/983070
|
||||
$.ajaxSetup({
|
||||
cache: false
|
||||
});
|
||||
|
||||
// Recreate first page when the page loads.
|
||||
history.replaceState({ path: window.location.href }, '');
|
||||
|
||||
// Back Button Hijacking :(
|
||||
window.onpopstate = function (event) {
|
||||
if (event.state === null) {
|
||||
return;
|
||||
}
|
||||
return handleNavigation(event.state.path, false);
|
||||
};
|
||||
|
||||
$(document).on('click', ".navigation-prev", handlePagination);
|
||||
$(document).on('click', ".navigation-next", handlePagination);
|
||||
$(document).on('click', ".summary [data-path] a", handlePagination);
|
||||
|
||||
$(window).resize(updateNavigationPosition);
|
||||
|
||||
// Prepare current page
|
||||
preparePage();
|
||||
};
|
||||
|
||||
return {
|
||||
init: init,
|
||||
goNext: goNext,
|
||||
goPrev: goPrev
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
define([
|
||||
"lodash",
|
||||
"jQuery",
|
||||
"utils/storage",
|
||||
"core/state"
|
||||
], function(_, $, storage, state) {
|
||||
// Get current level
|
||||
var getCurrentLevel = function() {
|
||||
return state.level;
|
||||
};
|
||||
|
||||
// Return all levels
|
||||
var getLevels = function () {
|
||||
var levels = $(".book-summary li[data-level]");
|
||||
|
||||
return _.map(levels, function(level) {
|
||||
return $(level).data("level").toString();
|
||||
});
|
||||
};
|
||||
|
||||
// Return a map chapter -> number (timestamp)
|
||||
var getProgress = function () {
|
||||
// Current level
|
||||
var progress = storage.get("progress", {});
|
||||
|
||||
// Levels
|
||||
var levels = getLevels();
|
||||
|
||||
_.each(levels, function(level) {
|
||||
progress[level] = progress[level] || 0;
|
||||
});
|
||||
|
||||
return progress;
|
||||
};
|
||||
|
||||
// Change value of progress for a level
|
||||
var markProgress = function (level, state) {
|
||||
var progress = getProgress();
|
||||
|
||||
if (state == null) {
|
||||
state = true;
|
||||
}
|
||||
|
||||
progress[level] = state
|
||||
? Date.now()
|
||||
: 0;
|
||||
|
||||
storage.set("progress", progress);
|
||||
};
|
||||
|
||||
// Show progress
|
||||
var showProgress = function () {
|
||||
var progress = getProgress();
|
||||
var $summary = $(".book-summary");
|
||||
|
||||
_.each(progress, function (value, level) {
|
||||
$summary.find("li[data-level='"+level+"']").toggleClass("done", value > 0);
|
||||
});
|
||||
|
||||
// Mark current progress if we have not already
|
||||
if (!progress[getCurrentLevel()]) {
|
||||
markProgress(getCurrentLevel(), true);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
'current': getCurrentLevel,
|
||||
'levels': getLevels,
|
||||
'get': getProgress,
|
||||
'mark': markProgress,
|
||||
'show': showProgress
|
||||
};
|
||||
});
|
||||
@@ -1,114 +0,0 @@
|
||||
define([
|
||||
"jQuery",
|
||||
"lodash",
|
||||
"lunr",
|
||||
"utils/storage",
|
||||
"core/state",
|
||||
"core/sidebar"
|
||||
], function($, _, lunr, storage, state, sidebar) {
|
||||
var index = null;
|
||||
|
||||
// Use a specific idnex
|
||||
var useIndex = function(data) {
|
||||
index = lunr.Index.load(data);
|
||||
};
|
||||
|
||||
// Load complete index
|
||||
var loadIndex = function() {
|
||||
$.getJSON(state.basePath+"/search_index.json")
|
||||
.then(useIndex);
|
||||
};
|
||||
|
||||
// Search for a term
|
||||
var search = function(q) {
|
||||
if (!index) return;
|
||||
var results = _.chain(index.search(q))
|
||||
.map(function(result) {
|
||||
var parts = result.ref.split("#")
|
||||
return {
|
||||
path: parts[0],
|
||||
hash: parts[1]
|
||||
}
|
||||
})
|
||||
.value();
|
||||
|
||||
return results;
|
||||
};
|
||||
|
||||
// Toggle search bar
|
||||
var toggleSearch = function(_state) {
|
||||
if (state != null && isSearchOpen() == _state) return;
|
||||
|
||||
var $searchInput = $(".book-search input");
|
||||
state.$book.toggleClass("with-search", _state);
|
||||
|
||||
// If search bar is open: focus input
|
||||
if (isSearchOpen()) {
|
||||
sidebar.toggle(true);
|
||||
$searchInput.focus();
|
||||
} else {
|
||||
$searchInput.blur();
|
||||
$searchInput.val("");
|
||||
sidebar.filter(null);
|
||||
}
|
||||
};
|
||||
|
||||
// Return true if search bar is open
|
||||
var isSearchOpen = function() {
|
||||
return state.$book.hasClass("with-search");
|
||||
};
|
||||
|
||||
|
||||
var init = function() {
|
||||
loadIndex();
|
||||
|
||||
// Toggle search
|
||||
$(document).on("click", ".book-header .toggle-search", function(e) {
|
||||
e.preventDefault();
|
||||
toggleSearch();
|
||||
});
|
||||
|
||||
|
||||
// Type in search bar
|
||||
$(document).on("keyup", ".book-search input", function(e) {
|
||||
var key = (e.keyCode ? e.keyCode : e.which);
|
||||
var q = $(this).val();
|
||||
|
||||
if (key == 27) {
|
||||
e.preventDefault();
|
||||
toggleSearch(false);
|
||||
return;
|
||||
}
|
||||
if (q.length == 0) {
|
||||
sidebar.filter(null);
|
||||
storage.remove("keyword");
|
||||
} else {
|
||||
var results = search(q);
|
||||
sidebar.filter(
|
||||
_.pluck(results, "path")
|
||||
);
|
||||
storage.set("keyword", q);
|
||||
}
|
||||
})
|
||||
|
||||
};
|
||||
|
||||
// filter sidebar menu with current search keyword
|
||||
var recoverSearch = function() {
|
||||
var keyword = storage.get("keyword", "");
|
||||
if(keyword.length > 0) {
|
||||
if(!isSearchOpen()){
|
||||
toggleSearch();
|
||||
}
|
||||
sidebar.filter(_.pluck(search(keyword), "path"));
|
||||
}
|
||||
$(".book-search input").val(keyword);
|
||||
};
|
||||
|
||||
return {
|
||||
init: init,
|
||||
search: search,
|
||||
toggle: toggleSearch,
|
||||
recover:recoverSearch
|
||||
};
|
||||
});
|
||||
@@ -1,56 +0,0 @@
|
||||
define([
|
||||
"jQuery",
|
||||
"lodash",
|
||||
"utils/storage",
|
||||
"utils/platform",
|
||||
"core/state"
|
||||
], function($, _, storage, platform, state) {
|
||||
// Toggle sidebar with or withour animation
|
||||
var toggleSidebar = function(_state, animation) {
|
||||
if (state != null && isOpen() == _state) return;
|
||||
if (animation == null) animation = true;
|
||||
|
||||
state.$book.toggleClass("without-animation", !animation);
|
||||
state.$book.toggleClass("with-summary", _state);
|
||||
|
||||
storage.set("sidebar", isOpen());
|
||||
};
|
||||
|
||||
// Return true if sidebar is open
|
||||
var isOpen = function() {
|
||||
return state.$book.hasClass("with-summary");
|
||||
};
|
||||
|
||||
// Prepare sidebar: state and toggle button
|
||||
var init = function() {
|
||||
// Toggle summary
|
||||
$(document).on("click", ".book-header .toggle-summary", function(e) {
|
||||
e.preventDefault();
|
||||
toggleSidebar();
|
||||
});
|
||||
|
||||
// Init last state if not mobile
|
||||
if (!platform.isMobile) {
|
||||
toggleSidebar(storage.get("sidebar", true), false);
|
||||
}
|
||||
};
|
||||
|
||||
// Filter summary with a list of path
|
||||
var filterSummary = function(paths) {
|
||||
var $summary = $(".book-summary");
|
||||
|
||||
$summary.find("li").each(function() {
|
||||
var path = $(this).data("path");
|
||||
var st = paths == null || _.contains(paths, path);
|
||||
|
||||
$(this).toggle(st);
|
||||
if (st) $(this).parents("li").show();
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
init: init,
|
||||
toggle: toggleSidebar,
|
||||
filter: filterSummary
|
||||
}
|
||||
});
|
||||
@@ -1,18 +0,0 @@
|
||||
define([
|
||||
"jQuery"
|
||||
], function() {
|
||||
var state = {};
|
||||
|
||||
state.update = function(dom) {
|
||||
var $book = $(dom.find(".book"));
|
||||
|
||||
state.$book = $book;
|
||||
state.level = $book.data("level");
|
||||
state.basePath = $book.data("basepath");
|
||||
state.revision = $book.data("revision");
|
||||
};
|
||||
|
||||
state.update($);
|
||||
|
||||
return state;
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
var $ = require('jquery');
|
||||
|
||||
function toggleDropdown(e) {
|
||||
var $dropdown = $(e.currentTarget).parent().find('.dropdown-menu');
|
||||
|
||||
$dropdown.toggleClass('open');
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
function closeDropdown(e) {
|
||||
$('.dropdown-menu').removeClass('open');
|
||||
}
|
||||
|
||||
// Bind all dropdown
|
||||
function init() {
|
||||
$(document).on('click', '.toggle-dropdown', toggleDropdown);
|
||||
$(document).on('click', '.dropdown-menu', function(e){ e.stopPropagation(); });
|
||||
$(document).on('click', closeDropdown);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: init
|
||||
};
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
var $ = require('jquery');
|
||||
|
||||
module.exports = $({});
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
define([
|
||||
"jQuery",
|
||||
"utils/storage",
|
||||
"utils/sharing",
|
||||
"utils/dropdown",
|
||||
|
||||
"core/events",
|
||||
"core/font-settings",
|
||||
"core/state",
|
||||
"core/keyboard",
|
||||
"core/navigation",
|
||||
"core/progress",
|
||||
"core/sidebar",
|
||||
"core/search"
|
||||
], function($, storage, sharing, dropdown, events, fontSettings, state, keyboard, navigation, progress, sidebar, search){
|
||||
var start = function(config) {
|
||||
var $book;
|
||||
$book = state.$book;
|
||||
|
||||
// Init sidebar
|
||||
sidebar.init();
|
||||
|
||||
// Load search
|
||||
search.init();
|
||||
|
||||
// Init keyboard
|
||||
keyboard.init();
|
||||
|
||||
// Bind sharing button
|
||||
sharing.init();
|
||||
|
||||
// Bind dropdown
|
||||
dropdown.init();
|
||||
|
||||
// Init navigation
|
||||
navigation.init();
|
||||
|
||||
//Init font settings
|
||||
fontSettings.init(config.fontSettings || {});
|
||||
|
||||
events.trigger("start", config);
|
||||
}
|
||||
|
||||
return {
|
||||
start: start,
|
||||
events: events,
|
||||
state: state
|
||||
};
|
||||
});
|
||||
Executable
+81
@@ -0,0 +1,81 @@
|
||||
var $ = require('jquery');
|
||||
var _ = require('lodash');
|
||||
|
||||
var storage = require('./storage');
|
||||
var dropdown = require('./dropdown');
|
||||
var events = require('./events');
|
||||
var state = require('./state');
|
||||
var keyboard = require('./keyboard');
|
||||
var navigation = require('./navigation');
|
||||
var sidebar = require('./sidebar');
|
||||
var toolbar = require('./toolbar');
|
||||
|
||||
|
||||
function start(config) {
|
||||
// Init sidebar
|
||||
sidebar.init();
|
||||
|
||||
// Init keyboard
|
||||
keyboard.init();
|
||||
|
||||
// Bind dropdown
|
||||
dropdown.init();
|
||||
|
||||
// Init navigation
|
||||
navigation.init();
|
||||
|
||||
|
||||
// Add action to toggle sidebar
|
||||
toolbar.createButton({
|
||||
icon: 'fa fa-align-justify',
|
||||
onClick: function(e) {
|
||||
e.preventDefault();
|
||||
sidebar.toggle();
|
||||
}
|
||||
});
|
||||
|
||||
events.trigger('start', config);
|
||||
}
|
||||
|
||||
// Export APIs for plugins
|
||||
var gitbook = {
|
||||
start: start,
|
||||
events: events,
|
||||
state: state,
|
||||
|
||||
// UI sections
|
||||
toolbar: toolbar,
|
||||
sidebar: sidebar,
|
||||
|
||||
// Read/Write the localstorage
|
||||
storage: storage,
|
||||
|
||||
// Create keyboard shortcuts
|
||||
keyboard: keyboard
|
||||
};
|
||||
|
||||
|
||||
// Modules mapping for plugins
|
||||
var MODULES = {
|
||||
'gitbook': gitbook,
|
||||
'jQuery': $,
|
||||
'lodash': _
|
||||
};
|
||||
|
||||
window.gitbook = gitbook;
|
||||
window.$ = $;
|
||||
window.jQuery = $;
|
||||
window.require = function(mods, fn) {
|
||||
mods = _.map(mods, function(mod) {
|
||||
if (!MODULES[mod]) {
|
||||
throw new Error('GitBook module '+mod+' doesn\'t exist');
|
||||
}
|
||||
|
||||
return MODULES[mod];
|
||||
});
|
||||
|
||||
fn.apply(null, mods);
|
||||
};
|
||||
|
||||
module.exports = {};
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
var Mousetrap = require('mousetrap');
|
||||
|
||||
var navigation = require('./navigation');
|
||||
var sidebar = require('./sidebar');
|
||||
|
||||
// Bind a keyboard shortcuts
|
||||
function bindShortcut(keys, fn) {
|
||||
Mousetrap.bind(keys, function(e) {
|
||||
fn();
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Bind keyboard shortcuts
|
||||
function init() {
|
||||
// Next
|
||||
bindShortcut(['right'], function(e) {
|
||||
navigation.goNext();
|
||||
});
|
||||
|
||||
// Prev
|
||||
bindShortcut(['left'], function(e) {
|
||||
navigation.goPrev();
|
||||
});
|
||||
|
||||
// Toggle Summary
|
||||
bindShortcut(['s'], function(e) {
|
||||
sidebar.toggle();
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: init,
|
||||
bind: bindShortcut
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
var state = require('./state');
|
||||
|
||||
function showLoading(p) {
|
||||
state.$book.addClass('is-loading');
|
||||
p.always(function() {
|
||||
state.$book.removeClass('is-loading');
|
||||
});
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
show: showLoading
|
||||
};
|
||||
@@ -0,0 +1,160 @@
|
||||
var $ = require('jquery');
|
||||
var url = require('url');
|
||||
|
||||
var events = require('./events');
|
||||
var state = require('./state');
|
||||
var loading = require('./loading');
|
||||
|
||||
|
||||
var usePushState = (typeof history.pushState !== 'undefined');
|
||||
|
||||
function handleNavigation(relativeUrl, push) {
|
||||
var uri = url.resolve(window.location.pathname, relativeUrl);
|
||||
|
||||
if (!usePushState) {
|
||||
// Refresh the page to the new URL if pushState not supported
|
||||
location.href = relativeUrl;
|
||||
return;
|
||||
}
|
||||
|
||||
return loading.show($.get(uri)
|
||||
.done(function (html) {
|
||||
// Push url to history
|
||||
if (push) history.pushState({ path: uri }, null, uri);
|
||||
|
||||
// Replace html content
|
||||
html = html.replace( /<(\/?)(html|head|body)([^>]*)>/ig, function(a,b,c,d){
|
||||
return '<' + b + 'div' + ( b ? '' : ' data-element="' + c + '"' ) + d + '>';
|
||||
});
|
||||
|
||||
var $page = $(html);
|
||||
var $pageHead = $page.find('[data-element=head]');
|
||||
var $pageBody = $page.find('.book');
|
||||
|
||||
// Merge heads
|
||||
// !! Warning !!: we only update necessary portions to avoid strange behavior (page flickering etc ...)
|
||||
|
||||
// Update title
|
||||
document.title = $pageHead.find('title').text();
|
||||
|
||||
// Reference to $('head');
|
||||
var $head = $('head');
|
||||
|
||||
// Update next & prev <link> tags
|
||||
// Remove old
|
||||
$head.find('link[rel=prev]').remove();
|
||||
$head.find('link[rel=next]').remove();
|
||||
|
||||
// Add new next * prev <link> tags
|
||||
$head.append($pageHead.find('link[rel=prev]'));
|
||||
$head.append($pageHead.find('link[rel=next]'));
|
||||
|
||||
// Merge body
|
||||
var bodyClass = $('.book').attr('class');
|
||||
var scrollPosition = $('.book-summary .summary').scrollTop();
|
||||
$pageBody.toggleClass('with-summary', $('.book').hasClass('with-summary'));
|
||||
|
||||
$('.book').replaceWith($pageBody);
|
||||
$('.book').attr('class', bodyClass);
|
||||
$('.book-summary .summary').scrollTop(scrollPosition);
|
||||
|
||||
// Update state
|
||||
state.update($('html'));
|
||||
preparePage();
|
||||
})
|
||||
.fail(function (e) {
|
||||
location.href = relativeUrl;
|
||||
}));
|
||||
}
|
||||
|
||||
function updateNavigationPosition() {
|
||||
var bodyInnerWidth, pageWrapperWidth;
|
||||
|
||||
bodyInnerWidth = parseInt($('.body-inner').css('width'), 10);
|
||||
pageWrapperWidth = parseInt($('.page-wrapper').css('width'), 10);
|
||||
$('.navigation-next').css('margin-right', (bodyInnerWidth - pageWrapperWidth) + 'px');
|
||||
}
|
||||
|
||||
function preparePage() {
|
||||
var $bookBody = $('.book-body');
|
||||
var $bookInner = $bookBody.find('.body-inner');
|
||||
var $pageWrapper = $bookInner.find('.page-wrapper');
|
||||
|
||||
// Update navigation position
|
||||
updateNavigationPosition();
|
||||
|
||||
// Focus on content
|
||||
$pageWrapper.focus();
|
||||
|
||||
// Reset scroll
|
||||
$bookInner.scrollTop(0);
|
||||
$bookBody.scrollTop(0);
|
||||
|
||||
// Notify
|
||||
events.trigger('page.change');
|
||||
}
|
||||
|
||||
function isLeftClickEvent(e) {
|
||||
return e.button === 0;
|
||||
}
|
||||
|
||||
function isModifiedEvent(e) {
|
||||
return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
|
||||
}
|
||||
|
||||
function handlePagination(e) {
|
||||
if (isModifiedEvent(e) || !isLeftClickEvent(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
var url = $(this).attr('href');
|
||||
if (url) handleNavigation(url, true);
|
||||
}
|
||||
|
||||
function goNext() {
|
||||
var url = $('.navigation-next').attr('href');
|
||||
if (url) handleNavigation(url, true);
|
||||
}
|
||||
|
||||
function goPrev() {
|
||||
var url = $('.navigation-prev').attr('href');
|
||||
if (url) handleNavigation(url, true);
|
||||
}
|
||||
|
||||
|
||||
function init() {
|
||||
// Prevent cache so that using the back button works
|
||||
// See: http://stackoverflow.com/a/15805399/983070
|
||||
$.ajaxSetup({
|
||||
cache: false
|
||||
});
|
||||
|
||||
// Recreate first page when the page loads.
|
||||
history.replaceState({ path: window.location.href }, '');
|
||||
|
||||
// Back Button Hijacking :(
|
||||
window.onpopstate = function (event) {
|
||||
if (event.state === null) {
|
||||
return;
|
||||
}
|
||||
return handleNavigation(event.state.path, false);
|
||||
};
|
||||
|
||||
$(document).on('click', '.navigation-prev', handlePagination);
|
||||
$(document).on('click', '.navigation-next', handlePagination);
|
||||
$(document).on('click', '.summary [data-path] a', handlePagination);
|
||||
|
||||
$(window).resize(updateNavigationPosition);
|
||||
|
||||
// Prepare current page
|
||||
preparePage();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: init,
|
||||
goNext: goNext,
|
||||
goPrev: goPrev
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
isMobile: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
|
||||
};
|
||||
@@ -0,0 +1,51 @@
|
||||
var $ = require('jquery');
|
||||
var _ = require('lodash');
|
||||
|
||||
var storage = require('./storage');
|
||||
var platform = require('./platform');
|
||||
var state = require('./state');
|
||||
|
||||
|
||||
// Toggle sidebar with or withour animation
|
||||
function toggleSidebar(_state, animation) {
|
||||
if (state != null && isOpen() == _state) return;
|
||||
if (animation == null) animation = true;
|
||||
|
||||
state.$book.toggleClass('without-animation', !animation);
|
||||
state.$book.toggleClass('with-summary', _state);
|
||||
|
||||
storage.set('sidebar', isOpen());
|
||||
}
|
||||
|
||||
// Return true if sidebar is open
|
||||
function isOpen() {
|
||||
return state.$book.hasClass('with-summary');
|
||||
}
|
||||
|
||||
// Prepare sidebar: state and toggle button
|
||||
function init() {
|
||||
// Init last state if not mobile
|
||||
if (!platform.isMobile) {
|
||||
toggleSidebar(storage.get('sidebar', true), false);
|
||||
}
|
||||
}
|
||||
|
||||
// Filter summary with a list of path
|
||||
function filterSummary(paths) {
|
||||
var $summary = $('.book-summary');
|
||||
|
||||
$summary.find('li').each(function() {
|
||||
var path = $(this).data('path');
|
||||
var st = paths == null || _.contains(paths, path);
|
||||
|
||||
$(this).toggle(st);
|
||||
if (st) $(this).parents('li').show();
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: init,
|
||||
isOpen: isOpen,
|
||||
toggle: toggleSidebar,
|
||||
filter: filterSummary
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
var $ = require('jquery');
|
||||
|
||||
var state = {};
|
||||
|
||||
state.update = function(dom) {
|
||||
var $book = $(dom.find(".book"));
|
||||
|
||||
state.$book = $book;
|
||||
state.level = $book.data("level");
|
||||
state.basePath = $book.data("basepath");
|
||||
state.revision = $book.data("revision");
|
||||
};
|
||||
|
||||
state.update($);
|
||||
|
||||
module.exports = state;
|
||||
@@ -0,0 +1,37 @@
|
||||
var baseKey = '';
|
||||
|
||||
/*
|
||||
* Simple module for storing data in the browser's local storage
|
||||
*/
|
||||
module.exports = {
|
||||
setBaseKey: function(key) {
|
||||
baseKey = key;
|
||||
},
|
||||
|
||||
// Write something in localstorage
|
||||
set: function(key, value) {
|
||||
key = baseKey+':'+key;
|
||||
|
||||
try {
|
||||
localStorage[key] = JSON.stringify(value);
|
||||
} catch(e) {}
|
||||
},
|
||||
|
||||
// Read a value from localstorage
|
||||
get: function(key, def) {
|
||||
key = baseKey+':'+key;
|
||||
if (localStorage[key] === undefined) return def;
|
||||
try {
|
||||
var v = JSON.parse(localStorage[key]);
|
||||
return v == null ? def : v;;
|
||||
} catch(err) {
|
||||
return localStorage[key] || def;
|
||||
}
|
||||
},
|
||||
|
||||
// Remove a key from localstorage
|
||||
remove: function(key) {
|
||||
key = baseKey+':'+key;
|
||||
localStorage.removeItem(key);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,157 @@
|
||||
var $ = require('jquery');
|
||||
var _ = require('lodash');
|
||||
|
||||
var events = require('./events');
|
||||
|
||||
// List of created buttons
|
||||
var buttons = [];
|
||||
|
||||
|
||||
// Default click handler
|
||||
function defaultOnClick(e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
// Create a dropdown menu
|
||||
function createDropdownMenu(dropdown) {
|
||||
var $menu = $('<div>', {
|
||||
'class': 'dropdown-menu',
|
||||
'html': '<div class="dropdown-caret"><span class="caret-outer"></span><span class="caret-inner"></span></div>'
|
||||
});
|
||||
|
||||
if (_.isString(dropdown)) {
|
||||
$menu.append(dropdown);
|
||||
} else {
|
||||
var groups = _.map(dropdown, function(group) {
|
||||
if (_.isArray(group)) return group;
|
||||
else return [group];
|
||||
});
|
||||
|
||||
// Create buttons groups
|
||||
_.each(groups, function(group) {
|
||||
var $group = $('<div>', {
|
||||
'class': 'buttons'
|
||||
});
|
||||
var sizeClass = 'size-'+group.length;
|
||||
|
||||
// Append buttons
|
||||
_.each(group, function(btn) {
|
||||
btn = _.defaults(btn || {}, {
|
||||
text: '',
|
||||
className: '',
|
||||
onClick: defaultOnClick
|
||||
});
|
||||
|
||||
var $btn = $('<button>', {
|
||||
'class': 'button '+sizeClass+' '+btn.className,
|
||||
'text': btn.text
|
||||
});
|
||||
$btn.click(btn.onClick);
|
||||
|
||||
$group.append($btn);
|
||||
});
|
||||
|
||||
|
||||
$menu.append($group);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
return $menu;
|
||||
}
|
||||
|
||||
// Create a new button in the toolbar
|
||||
function createButton(opts) {
|
||||
opts = _.defaults(opts || {}, {
|
||||
// Aria label for the button
|
||||
label: '',
|
||||
|
||||
// Icon to show
|
||||
icon: '',
|
||||
|
||||
// Inner text
|
||||
text: '',
|
||||
|
||||
// Right or left position
|
||||
position: 'left',
|
||||
|
||||
// Other class name to add to the button
|
||||
className: '',
|
||||
|
||||
// Triggered when user click on the button
|
||||
onClick: defaultOnClick,
|
||||
|
||||
// Button is a dropdown
|
||||
dropdown: null
|
||||
});
|
||||
|
||||
buttons.push(opts);
|
||||
updateButton(opts);
|
||||
}
|
||||
|
||||
// Update a button
|
||||
function updateButton(opts) {
|
||||
var $toolbar = $('.book-header');
|
||||
var $title = $toolbar.find('h1');
|
||||
|
||||
// Build class name
|
||||
var positionClass = 'pull-'+opts.position;
|
||||
|
||||
// Create button
|
||||
var $btn = $('<a>', {
|
||||
'class': 'btn',
|
||||
'text': opts.text,
|
||||
'aria-label': opts.label,
|
||||
'href': '#'
|
||||
});
|
||||
|
||||
// Bind click
|
||||
$btn.click(opts.onClick);
|
||||
|
||||
// Prepend icon
|
||||
if (opts.icon) {
|
||||
$('<i>', {
|
||||
'class': opts.icon
|
||||
}).prependTo($btn);
|
||||
}
|
||||
|
||||
// Prepare dropdown
|
||||
if (opts.dropdown) {
|
||||
var $container = $('<div>', {
|
||||
'class': 'dropdown '+positionClass+' '+opts.className
|
||||
});
|
||||
|
||||
// Add button to container
|
||||
$btn.addClass('toggle-dropdown');
|
||||
$container.append($btn);
|
||||
|
||||
// Create inner menu
|
||||
var $menu = createDropdownMenu(opts.dropdown);
|
||||
|
||||
// Menu position
|
||||
$menu.addClass('dropdown-'+(opts.position == 'right'? 'left' : 'right'));
|
||||
|
||||
$container.append($menu);
|
||||
|
||||
$container.insertBefore($title);
|
||||
} else {
|
||||
$btn.addClass(positionClass);
|
||||
$btn.addClass(opts.className);
|
||||
$btn.insertBefore($title);
|
||||
}
|
||||
}
|
||||
|
||||
// Update all buttons
|
||||
function updateAllButtons() {
|
||||
_.each(buttons, updateButton);
|
||||
}
|
||||
|
||||
// When page changed, reset buttons
|
||||
events.bind('page.change', function() {
|
||||
updateAllButtons();
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
createButton: createButton
|
||||
};
|
||||
@@ -1,27 +0,0 @@
|
||||
define([
|
||||
"jQuery"
|
||||
], function($) {
|
||||
|
||||
var toggleDropdown = function(e) {
|
||||
var $dropdown = $(e.currentTarget).parent().find(".dropdown-menu");
|
||||
|
||||
$dropdown.toggleClass("open");
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
var closeDropdown = function(e) {
|
||||
$(".dropdown-menu").removeClass("open");
|
||||
};
|
||||
|
||||
// Bind all dropdown
|
||||
var init = function() {
|
||||
$(document).on('click', ".toggle-dropdown", toggleDropdown);
|
||||
$(document).on('click', ".dropdown-menu", function(e){ e.stopPropagation(); });
|
||||
$(document).on("click", closeDropdown);
|
||||
};
|
||||
|
||||
return {
|
||||
init: init
|
||||
};
|
||||
});
|
||||
@@ -1,5 +0,0 @@
|
||||
define([], function() {
|
||||
return {
|
||||
isMobile: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
|
||||
};
|
||||
});
|
||||
@@ -1,39 +0,0 @@
|
||||
define([
|
||||
"jQuery"
|
||||
], function($) {
|
||||
var types = {
|
||||
"twitter": function($el) {
|
||||
window.open("http://twitter.com/home?status="+encodeURIComponent($("title").text()+" "+location.href))
|
||||
},
|
||||
"facebook": function($el) {
|
||||
window.open("http://www.facebook.com/sharer/sharer.php?s=100&p[url]="+encodeURIComponent(location.href))
|
||||
},
|
||||
"google-plus": function($el) {
|
||||
window.open("https://plus.google.com/share?url="+encodeURIComponent(location.href))
|
||||
},
|
||||
"weibo": function($el) {
|
||||
window.open("http://service.weibo.com/share/share.php?content=utf-8&url="+encodeURIComponent(location.href)+"&title="+encodeURIComponent($("title").text()))
|
||||
},
|
||||
"instapaper": function($el) {
|
||||
window.open("http://www.instapaper.com/text?u="+encodeURIComponent(location.href));
|
||||
},
|
||||
"vk": function($el) {
|
||||
window.open("http://vkontakte.ru/share.php?url="+encodeURIComponent(location.href));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Bind all sharing button
|
||||
var init = function() {
|
||||
$(document).on("click", "a[data-sharing],button[data-sharing]", function(e) {
|
||||
if (e) e.preventDefault();
|
||||
var type = $(this).data("sharing");
|
||||
|
||||
types[type]($(this));
|
||||
})
|
||||
};
|
||||
|
||||
return {
|
||||
init: init
|
||||
};
|
||||
});
|
||||
@@ -1,31 +0,0 @@
|
||||
define(function(){
|
||||
var baseKey = "";
|
||||
|
||||
/*
|
||||
* Simple module for storing data in the browser's local storage
|
||||
*/
|
||||
return {
|
||||
setBaseKey: function(key) {
|
||||
baseKey = key;
|
||||
},
|
||||
set: function(key, value) {
|
||||
key = baseKey+":"+key;
|
||||
localStorage[key] = JSON.stringify(value);
|
||||
},
|
||||
get: function(key, def) {
|
||||
key = baseKey+":"+key;
|
||||
if (localStorage[key] === undefined) return def;
|
||||
try {
|
||||
var v = JSON.parse(localStorage[key]);
|
||||
return v == null ? def : v;;
|
||||
} catch(err) {
|
||||
console.error(err);
|
||||
return localStorage[key] || def;
|
||||
}
|
||||
},
|
||||
remove: function(key) {
|
||||
key = baseKey+":"+key;
|
||||
localStorage.removeItem(key);
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -1,33 +0,0 @@
|
||||
define([
|
||||
"URIjs/URI"
|
||||
], function(URI) {
|
||||
// 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(baseUrl, url) {
|
||||
var theUrl = new URI(url);
|
||||
if (theUrl.is("relative")) {
|
||||
theUrl = theUrl.absoluteTo(baseUrl);
|
||||
}
|
||||
return theUrl.toString();
|
||||
}
|
||||
|
||||
// A simple function to get the dirname of a path
|
||||
// Trailing slashes are ignored. Leading slash is preserved.
|
||||
function dirname(path) {
|
||||
return join(path, "..");
|
||||
}
|
||||
|
||||
// test if a path or url is absolute
|
||||
function isAbsolute(path) {
|
||||
if (!path) return false;
|
||||
|
||||
return (path[0] == "/" || path.indexOf("http://") == 0 || path.indexOf("https://") == 0);
|
||||
}
|
||||
|
||||
return {
|
||||
dirname: dirname,
|
||||
join: join,
|
||||
isAbsolute: isAbsolute
|
||||
};
|
||||
})
|
||||
@@ -1,389 +0,0 @@
|
||||
.markdown-content(@md-color, @md-line-height) {
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
line-height: 1.4;
|
||||
color: @md-color;
|
||||
overflow: hidden;
|
||||
line-height: @md-line-height;
|
||||
word-wrap: break-word;
|
||||
display: block;
|
||||
|
||||
& > *:first-child {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
& > *:last-child {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
a {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
a:active,
|
||||
a:hover {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: 0.67em 0;
|
||||
}
|
||||
|
||||
img {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
hr {
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
pre {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
code,
|
||||
pre {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
td,
|
||||
th {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
* {
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #4183c4;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover,
|
||||
a:focus,
|
||||
a:active {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
hr {
|
||||
height: 0;
|
||||
margin: 15px 0;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
hr:before,
|
||||
hr:after {
|
||||
display: table;
|
||||
content: " ";
|
||||
}
|
||||
|
||||
hr:after {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
margin-top: 15px;
|
||||
margin-bottom: 15px;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 21px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
padding: 0;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
ol ol {
|
||||
list-style-type: lower-roman;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
code,
|
||||
pre {
|
||||
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
pre {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.markdown-body>*:first-child {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
.markdown-body>*:last-child {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.anchor {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: block;
|
||||
padding-right: 6px;
|
||||
padding-left: 30px;
|
||||
margin-left: -30px;
|
||||
}
|
||||
|
||||
.anchor:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
position: relative;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 16px;
|
||||
font-weight: bold;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
h1 {
|
||||
padding-bottom: 0.3em;
|
||||
font-size: 2.25em;
|
||||
line-height: 1.2;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
h2 {
|
||||
padding-bottom: 0.3em;
|
||||
font-size: 1.75em;
|
||||
line-height: 1.225;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.5em;
|
||||
line-height: 1.43;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 1em;
|
||||
color: #777;
|
||||
}
|
||||
|
||||
p,
|
||||
blockquote,
|
||||
ul,
|
||||
ol,
|
||||
dl,
|
||||
table,
|
||||
pre {
|
||||
margin-top: 0;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
hr {
|
||||
height: 4px;
|
||||
padding: 0;
|
||||
margin: 16px 0;
|
||||
background-color: #e7e7e7;
|
||||
border: 0 none;
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ol ul,
|
||||
ul ul {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dl {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
dl dt {
|
||||
padding: 0;
|
||||
margin-top: 16px;
|
||||
font-size: 1em;
|
||||
font-style: italic;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
dl dd {
|
||||
padding: 0 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
padding: 0 15px;
|
||||
color: #777;
|
||||
border-left: 4px solid #ddd;
|
||||
}
|
||||
|
||||
blockquote>:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
blockquote>:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
table {
|
||||
display: block;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
table th {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
table th,
|
||||
table td {
|
||||
padding: 6px 13px;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
table tr {
|
||||
background-color: #fff;
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
|
||||
table tr:nth-child(2n) {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
|
||||
code {
|
||||
padding: 0;
|
||||
padding-top: 0.2em;
|
||||
padding-bottom: 0.2em;
|
||||
margin: 0;
|
||||
font-size: 85%;
|
||||
background-color: #f7f7f7;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
code:before,
|
||||
code:after {
|
||||
letter-spacing: -0.2em;
|
||||
content: "\00a0";
|
||||
}
|
||||
|
||||
pre>code {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 100%;
|
||||
white-space: pre;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.highlight pre,
|
||||
pre {
|
||||
padding: 16px;
|
||||
overflow: auto;
|
||||
font-size: 85%;
|
||||
line-height: 1.45;
|
||||
background-color: #f7f7f7;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
pre {
|
||||
word-wrap: normal;
|
||||
}
|
||||
|
||||
pre code {
|
||||
display: inline;
|
||||
max-width: initial;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
overflow: initial;
|
||||
line-height: inherit;
|
||||
word-wrap: normal;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
pre code:before,
|
||||
pre code:after {
|
||||
content: normal;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
background: #ffffff;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
.markup-content(@md-color: #000, @md-line-height: 1.7, @md-link-color: #4183c4, @md-code-background: #f7f7f7, @md-code-fontsize: 0.85, @md-blockquote-color: #858585, @md-blockquote-border: #e5e5e5) {
|
||||
// Rate of growth for headings
|
||||
@scale: 0.25;
|
||||
|
||||
// Spacing between blocks
|
||||
@spacing: @md-line-height * 2 * @scale * 1em;
|
||||
@spacing-lg: @md-line-height * 3 * @scale * 1em;
|
||||
|
||||
|
||||
display: block;
|
||||
word-wrap: break-word;
|
||||
overflow: hidden;
|
||||
|
||||
color: @md-color;
|
||||
line-height: @md-line-height;
|
||||
|
||||
* {
|
||||
.box-sizing(border-box);
|
||||
}
|
||||
|
||||
& > *:first-child {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
& > *:last-child {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
/* Printing */
|
||||
pre, code, blockquote, tr, img, table, figure {
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
|
||||
p, h2, h3, h4, h5 {
|
||||
orphans: 3;
|
||||
widows: 3;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5 {
|
||||
page-break-after: avoid;
|
||||
}
|
||||
|
||||
/* Typography */
|
||||
strong, b {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
em {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* Spacing */
|
||||
p, blockquote, ul, ol, dl, table {
|
||||
margin-top: 0;
|
||||
margin-bottom: @spacing;
|
||||
}
|
||||
|
||||
/* Links */
|
||||
a {
|
||||
color: @md-link-color;
|
||||
text-decoration: none;
|
||||
background: transparent;
|
||||
|
||||
&:hover,
|
||||
&:focus,
|
||||
&:active {
|
||||
outline: 0;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
/* Images */
|
||||
img {
|
||||
border: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* Horizontal lines */
|
||||
hr {
|
||||
height: 4px;
|
||||
padding: 0;
|
||||
margin: @md-line-height * 1em 0;
|
||||
overflow: hidden;
|
||||
background-color: #e7e7e7;
|
||||
border: none;
|
||||
|
||||
&:before, &:after {
|
||||
display: table;
|
||||
content: " ";
|
||||
}
|
||||
|
||||
&:after {
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
|
||||
/* Headings */
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
margin-top: @spacing-lg;
|
||||
margin-bottom: @spacing;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: (4 * @scale) + 1em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: (3 * @scale) + 1em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: (2 * @scale) + 1em;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: @scale + 1em;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
code, pre {
|
||||
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
direction: ltr;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
pre {
|
||||
overflow: auto;
|
||||
word-wrap: normal;
|
||||
margin: 0px;
|
||||
padding: 0.85em 1em;
|
||||
margin-bottom: @spacing-lg;
|
||||
background: @md-code-background;
|
||||
|
||||
> code {
|
||||
display: inline;
|
||||
max-width: initial;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
overflow: initial;
|
||||
line-height: inherit;
|
||||
font-size: @md-code-fontsize * 1em;
|
||||
white-space: pre;
|
||||
background: transparent;
|
||||
|
||||
&:before, &:after {
|
||||
content: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
code {
|
||||
padding: 0.2em;
|
||||
margin: 0;
|
||||
font-size: @md-code-fontsize * 1em;
|
||||
background-color: @md-code-background;
|
||||
|
||||
&:before, &:after {
|
||||
letter-spacing: -0.2em;
|
||||
content: "\00a0";
|
||||
}
|
||||
}
|
||||
|
||||
/* Tables */
|
||||
table {
|
||||
display: table;
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
overflow: auto;
|
||||
|
||||
td, th {
|
||||
padding: 6px 13px;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
tr {
|
||||
background-color: #fff;
|
||||
border-top: 1px solid #ccc;
|
||||
|
||||
&:nth-child(2n) {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
}
|
||||
|
||||
th {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
/* Lists */
|
||||
ul, ol {
|
||||
padding: 0;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
padding-left: 2em;
|
||||
|
||||
ol, ul {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
ol ol {
|
||||
list-style-type: lower-roman;
|
||||
}
|
||||
|
||||
|
||||
/* Blockquote */
|
||||
blockquote {
|
||||
margin: 0;
|
||||
padding: 0 15px;
|
||||
color: @md-blockquote-color;
|
||||
border-left: 4px solid @md-blockquote-border;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Description Lists */
|
||||
dl {
|
||||
padding: 0;
|
||||
|
||||
dt {
|
||||
padding: 0;
|
||||
margin-top: @spacing;
|
||||
font-style: italic;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
dd {
|
||||
padding: 0 @spacing;
|
||||
margin-bottom: @spacing;
|
||||
}
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
Executable → Regular
+13
-1
@@ -1,4 +1,4 @@
|
||||
@import "base/markdown.less";
|
||||
@import "./markup.less";
|
||||
|
||||
.link-inherit {
|
||||
color: inherit;
|
||||
@@ -18,3 +18,15 @@
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.box-sizing(@value) {
|
||||
-moz-box-sizing: @value;
|
||||
box-sizing: @value;
|
||||
}
|
||||
|
||||
.text-adjust(@value) {
|
||||
text-size-adjust: @value;
|
||||
-ms-text-size-adjust: @value;
|
||||
-webkit-text-size-adjust: @value;
|
||||
}
|
||||
|
||||
Executable → Regular
+1
-43
@@ -1,43 +1 @@
|
||||
@import "mixins.less";
|
||||
|
||||
@import "ebook/variables.less";
|
||||
|
||||
.page {
|
||||
&.page-toc {
|
||||
.glossary {
|
||||
margin-bottom: 40px;
|
||||
|
||||
h2 {
|
||||
a, a:hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.glossary-index {
|
||||
list-style: none;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
|
||||
li {
|
||||
display: inline;
|
||||
margin: 0px 8px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.book-chapter {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
body {
|
||||
.page {
|
||||
font-family: sans-serif;
|
||||
.markdown-content(#000, 1.6);
|
||||
}
|
||||
}
|
||||
@import "./ebook/base.less";
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
@import "../base/mixins.less";
|
||||
@import "./variables.less";
|
||||
|
||||
@import "./summary.less";
|
||||
@import "./glossary.less";
|
||||
|
||||
body {
|
||||
font-family: @font-family-base;
|
||||
color: @text-color;
|
||||
.text-adjust(100%);
|
||||
}
|
||||
|
||||
.page {
|
||||
// Section and first titles
|
||||
.section {
|
||||
.markup-content(@text-color, 1.6, @md-link-color: @link-color);
|
||||
}
|
||||
|
||||
// Hide the title (only used to build PDF table of content)
|
||||
.book-chapter {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
.section.glossary {
|
||||
> h1 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.glossary-entry {
|
||||
margin-bottom: 40px;
|
||||
|
||||
h2 {
|
||||
a, a:hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.glossary-index {
|
||||
list-style: none;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
|
||||
li {
|
||||
display: inline;
|
||||
margin: 0px 8px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
.section.toc {
|
||||
> h1 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
> ol {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
li {
|
||||
list-style: none;
|
||||
|
||||
.inner {
|
||||
display: block;
|
||||
border-bottom: 1px dotted #eee;
|
||||
margin-bottom: 4px;
|
||||
|
||||
a, span {
|
||||
padding-right: 5px;
|
||||
border-bottom: 1px solid #fff;
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
|
||||
.page {
|
||||
float: right;
|
||||
padding-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
ol {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
padding-left: 2em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For LTR, fix direction of table of content
|
||||
.dir-rtl {
|
||||
.section.toc {
|
||||
li {
|
||||
.inner {
|
||||
.page {
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
|
||||
ol {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
padding-right: 2em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +1,5 @@
|
||||
@font-size-base: 13px;
|
||||
@font-size-base: 13px;
|
||||
@font-family-base: sans-serif;
|
||||
|
||||
@text-color: #000;
|
||||
@link-color: #4183c4;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
@import "./ebook/base.less";
|
||||
|
||||
@font-family-base: serif;
|
||||
@@ -0,0 +1,23 @@
|
||||
@import "./ebook/base.less";
|
||||
|
||||
@font-family-base: serif;
|
||||
@link-color: #000;
|
||||
|
||||
a {
|
||||
color: #000;
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
|
||||
.page-toc {
|
||||
li {
|
||||
list-style-type: lower-alpha;
|
||||
|
||||
.inner {
|
||||
border: none;
|
||||
|
||||
span.page {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
@import "./ebook/base.less";
|
||||
|
||||
.pdf-footer {
|
||||
margin-top: 20px;
|
||||
padding-top: 10px;
|
||||
border-top: 1px solid #eee;
|
||||
color:#aaa;
|
||||
|
||||
.footer-pages-count {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.pdf-header {
|
||||
margin-top: 20px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
@import "base/normalize.less";
|
||||
@import "base/preboot.less";
|
||||
@import "../vendors/fontawesome/less/font-awesome.less";
|
||||
@import "base/mixins.less";
|
||||
@import "../../node_modules/font-awesome/less/font-awesome.less";
|
||||
|
||||
@import "mixins.less";
|
||||
|
||||
@import "website/variables.less";
|
||||
@import "website/languages.less";
|
||||
@@ -10,10 +10,9 @@
|
||||
@import "website/dropdown.less";
|
||||
@import "website/alerts.less";
|
||||
@import "website/summary.less";
|
||||
@import "website/font-settings.less";
|
||||
@import "website/body.less";
|
||||
@import "website/buttons.less";
|
||||
@import "website/markdown.less";
|
||||
@import "website/markup.less";
|
||||
@import "website/navigation.less";
|
||||
@import "website/glossary.less";
|
||||
|
||||
@@ -44,4 +43,5 @@ body {
|
||||
font-family: @font-family-base;
|
||||
font-size: @font-size-base;
|
||||
letter-spacing: .2px;
|
||||
.text-adjust(100%);
|
||||
}
|
||||
|
||||
@@ -84,63 +84,4 @@
|
||||
.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.font-size-0 {
|
||||
.book-body .page-inner section {
|
||||
font-size:@s-font-size;
|
||||
}
|
||||
}
|
||||
&.font-size-1 {
|
||||
.book-body .page-inner section {
|
||||
font-size:@m-font-size;
|
||||
}
|
||||
}
|
||||
&.font-size-2 {
|
||||
.book-body .page-inner section {
|
||||
font-size:@l-font-size;
|
||||
}
|
||||
}
|
||||
&.font-size-3{
|
||||
.book-body .page-inner section {
|
||||
font-size:@xl-font-size;
|
||||
}
|
||||
}
|
||||
&.font-size-4 {
|
||||
.book-body .page-inner section {
|
||||
font-size:@xxl-font-size;
|
||||
}
|
||||
}
|
||||
|
||||
&.font-family-0{
|
||||
font-family: @font-family-serif;
|
||||
}
|
||||
&.font-family-1{
|
||||
font-family: @font-family-sans;
|
||||
}
|
||||
}
|
||||
@@ -103,57 +103,3 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Theme 1
|
||||
*/
|
||||
|
||||
.color-theme-1 {
|
||||
.dropdown-menu{
|
||||
background-color: @dropdown-background-1;
|
||||
border-color: @dropdown-border-color-1;
|
||||
|
||||
.dropdown-caret .caret-inner{
|
||||
border-bottom: 9px solid @dropdown-background-1;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
border-color: @dropdown-divider-color-1;
|
||||
}
|
||||
|
||||
.button {
|
||||
color: @dropdown-button-color-1;
|
||||
|
||||
&:hover{
|
||||
color: @dropdown-button-hover-color-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Theme 2
|
||||
*/
|
||||
|
||||
.color-theme-2 {
|
||||
.dropdown-menu{
|
||||
background-color: @dropdown-background-2;
|
||||
border-color: @dropdown-border-color-2;
|
||||
|
||||
.dropdown-caret .caret-inner{
|
||||
border-bottom: 9px solid @dropdown-background-2;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
border-color: @dropdown-divider-color-2;
|
||||
}
|
||||
|
||||
.button {
|
||||
color: @dropdown-button-color-2;
|
||||
|
||||
&:hover{
|
||||
color: @dropdown-button-hover-color-2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
.book-header{
|
||||
#font-settings-wrapper{
|
||||
#enlarge-font-size, #reduce-font-size {
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
#enlarge-font-size{
|
||||
font-size: 1.4em;
|
||||
}
|
||||
#reduce-font-size{
|
||||
font-size: 1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,42 +79,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.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;
|
||||
}
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: @page-color-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;
|
||||
}
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: @page-color-2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
.book .book-body .page-wrapper .page-inner section {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.book .book-body .page-wrapper .page-inner section.normal {
|
||||
.markdown-content(@content-color, @content-line-height);
|
||||
|
||||
.glossary-term {
|
||||
cursor: help;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.book.color-theme-1 .book-body .page-wrapper .page-inner section.normal {
|
||||
color: @page-color-1;
|
||||
|
||||
a {
|
||||
color: @page-link-color-1;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
color: @page-heading-color-1;
|
||||
}
|
||||
|
||||
h1, h2 {
|
||||
border-color: @page-heading-border-color-1;
|
||||
}
|
||||
|
||||
h6 {
|
||||
color: @page-h6-color-1;
|
||||
}
|
||||
|
||||
hr {
|
||||
background-color: @page-hr-color-1;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-color: @page-blockquote-border-color-1;
|
||||
}
|
||||
|
||||
pre, code {
|
||||
background: @page-pre-background-1;
|
||||
color: @page-pre-color-1;
|
||||
border-color: @page-pre-border-color-1;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
background-color: @page-highlight-background-1;
|
||||
}
|
||||
|
||||
table {
|
||||
th, td {
|
||||
border-color: @page-table-header-border-color-1;
|
||||
}
|
||||
|
||||
tr {
|
||||
color: @page-table-row-color-1;
|
||||
background-color: @page-table-row-background-1;
|
||||
border-color: @page-table-row-border-color-1;
|
||||
}
|
||||
|
||||
tr:nth-child(2n) {
|
||||
background-color: @page-table-row-odd-background-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.book.color-theme-2 .book-body .page-wrapper .page-inner section.normal {
|
||||
color: @page-color-2;
|
||||
|
||||
a {
|
||||
color: @page-link-color-2;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
color: @page-heading-color-2;
|
||||
}
|
||||
|
||||
h1, h2 {
|
||||
border-color: @page-heading-border-color-2;
|
||||
}
|
||||
|
||||
h6 {
|
||||
color: @page-h6-color-2;
|
||||
}
|
||||
|
||||
hr {
|
||||
background-color: @page-hr-color-2;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-color: @page-blockquote-border-color-2;
|
||||
}
|
||||
|
||||
pre, code {
|
||||
color: @page-pre-color-2;
|
||||
background: @page-pre-background-2;
|
||||
border-color: @page-pre-border-color-2;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
background-color: @page-highlight-background-2;
|
||||
}
|
||||
|
||||
table {
|
||||
th, td {
|
||||
border-color: @page-table-header-border-color-2;
|
||||
}
|
||||
|
||||
tr {
|
||||
color: @page-table-row-color-2;
|
||||
background-color: @page-table-row-background-2;
|
||||
border-color: @page-table-row-border-color-2;
|
||||
}
|
||||
|
||||
tr:nth-child(2n) {
|
||||
background-color: @page-table-row-odd-background-2;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
.book .book-body .page-wrapper .page-inner section {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.book .book-body .page-wrapper .page-inner section.normal {
|
||||
.markup-content(@content-color, @content-line-height);
|
||||
|
||||
.glossary-term {
|
||||
cursor: help;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
@@ -48,21 +48,3 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.book.color-theme-1 .book-body {
|
||||
.navigation {
|
||||
color: @navigation-color-1;
|
||||
|
||||
&:hover {
|
||||
color: @navigation-hover-color-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
.book.color-theme-2 .book-body {
|
||||
.navigation {
|
||||
color: @navigation-color-2;
|
||||
|
||||
&:hover {
|
||||
color: @navigation-hover-color-2;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,30 +15,6 @@
|
||||
|
||||
.transition(left @sidebar-transition-duration ease);
|
||||
|
||||
.book-search {
|
||||
padding: @sidebar-search-padding;
|
||||
|
||||
background: @sidebar-search-background;
|
||||
|
||||
position: absolute;
|
||||
top: -@header-height;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
|
||||
.transition(top 0.5s ease);
|
||||
|
||||
input, input:focus, input:hover {
|
||||
width: 100%;
|
||||
background: @sidebar-search-input-background;
|
||||
border: 1px solid @sidebar-search-input-border-color;
|
||||
.box-shadow(none);
|
||||
outline: none;
|
||||
line-height: 22px;
|
||||
padding: 7px 4px;
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
ul.summary {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
@@ -131,112 +107,4 @@
|
||||
.transition(none) !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.with-search {
|
||||
.book-summary {
|
||||
.book-search {
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
ul.summary {
|
||||
top: @header-height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Theme 1
|
||||
*/
|
||||
.book.color-theme-1 {
|
||||
.book-summary {
|
||||
color: @sidebar-color-1;
|
||||
background: @sidebar-background-1;
|
||||
border-right: @sidebar-border-right-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;
|
||||
font-weight: @sidebar-link-weight-1;
|
||||
}
|
||||
|
||||
&.active > a, a:hover {
|
||||
color: @sidebar-link-hover-color-1;
|
||||
background: @sidebar-link-hover-background-1;
|
||||
font-weight: @sidebar-link-hover-weight-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Theme 2
|
||||
*/
|
||||
.book.color-theme-2{
|
||||
.book-summary {
|
||||
color: @sidebar-color-2;
|
||||
background: @sidebar-background-2;
|
||||
border-right: @sidebar-border-right-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;
|
||||
font-weight: @sidebar-link-weight-2;
|
||||
}
|
||||
|
||||
&.active > a, a:hover {
|
||||
color: @sidebar-link-hover-color-2;
|
||||
background: @sidebar-link-hover-background-2;
|
||||
font-weight: @sidebar-link-hover-weight-2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
@body-background: white;
|
||||
|
||||
// Sidebar
|
||||
@sidebar-transition-duration: 250ms;
|
||||
@sidebar-width: 300px;
|
||||
@sidebar-breakpoint: 600px;
|
||||
@sidebar-color: hsl(207, 15%, 25%);
|
||||
@@ -34,12 +35,6 @@
|
||||
@sidebar-border-right: 1px solid @header-border;
|
||||
|
||||
@sidebar-nested-padding: 20px;
|
||||
|
||||
@sidebar-search-padding: 6px;
|
||||
@sidebar-search-background: transparent;
|
||||
@sidebar-search-input-background: transparent;
|
||||
@sidebar-search-input-border-color: transparent;
|
||||
|
||||
@sidebar-divider-color: @header-border;
|
||||
|
||||
@sidebar-link-color: @sidebar-color;
|
||||
@@ -56,7 +51,7 @@
|
||||
@page-background: @body-background;
|
||||
|
||||
// Content
|
||||
@content-line-height: 1.6;
|
||||
@content-line-height: 1.7;
|
||||
@content-color: #333333;
|
||||
|
||||
// Dropdown
|
||||
@@ -110,133 +105,3 @@
|
||||
@xxl-font-size: 4.0rem;
|
||||
@default-font-size: @l-font-size;
|
||||
|
||||
/*
|
||||
,--------.,--.
|
||||
'--. .--'| ,---. ,---. ,--,--,--. ,---. ,---. .--.
|
||||
| | | .-. || .-. :| || .-. :( .-' '--'
|
||||
| | | | | |\ --.| | | |\ --..-' `).--.
|
||||
`--' `--' `--' `----'`--`--`--' `----'`----' '--'
|
||||
*/
|
||||
// Header
|
||||
@header-color-1: #AFA790;
|
||||
@header-color-2: #7e888b;
|
||||
@header-background-1: transparent;
|
||||
@header-background-2: transparent;
|
||||
@header-button-color-1: #AFA790;
|
||||
@header-button-color-2: hsl(230, 17%, 28%);
|
||||
@header-button-hover-color-1: #73553C;
|
||||
@header-button-hover-color-2: hsl(60, 100%, 98%);
|
||||
@header-button-hover-background-1: none;
|
||||
@header-button-hover-background-2: none;
|
||||
@header-dropdown-background-1: @sidebar-background-1;
|
||||
@header-dropdown-background-2: @sidebar-background-2;
|
||||
|
||||
// Body
|
||||
@body-background-1: #F3EACB;
|
||||
@body-background-2: hsl(228, 21%, 14%);
|
||||
|
||||
// Sidebar
|
||||
@sidebar-transition-duration: 250ms;
|
||||
@sidebar-color-1: #AFA790;
|
||||
@sidebar-color-2: hsl(226, 20%, 78%);
|
||||
@sidebar-background-1: #111;
|
||||
@sidebar-background-2: hsl(229, 20%, 22%);
|
||||
@sidebar-border-right-1: @sidebar-border-right;
|
||||
@sidebar-border-right-2: none;
|
||||
|
||||
@sidebar-search-background-1: transparent;
|
||||
@sidebar-search-background-2: transparent;
|
||||
@sidebar-search-input-border-color-1: transparent;
|
||||
@sidebar-search-input-border-color-2: transparent;
|
||||
|
||||
@sidebar-divider-color-1: @sidebar-divider-color;
|
||||
@sidebar-divider-color-2: hsl(230, 19%, 19%);
|
||||
|
||||
@sidebar-link-color-1: #877F6A;
|
||||
@sidebar-link-color-2: hsl(226, 22%, 80%);
|
||||
@sidebar-link-background-1: transparent;
|
||||
@sidebar-link-background-2: transparent;
|
||||
@sidebar-link-weight-1: normal;
|
||||
@sidebar-link-weight-2: 600;
|
||||
@sidebar-link-hover-color-1: #704214;
|
||||
@sidebar-link-hover-color-2: hsl(240, 5%, 96%);
|
||||
@sidebar-link-hover-background-1: transparent;
|
||||
@sidebar-link-hover-background-2: hsl(233, 19%, 18%);
|
||||
@sidebar-link-hover-weight-1: normal;
|
||||
@sidebar-link-hover-weight-2: 600;
|
||||
|
||||
@sidebar-icon-color-1: hsl(120, 60%, 50%);
|
||||
@sidebar-icon-color-2: @sidebar-icon-color-1;
|
||||
@sidebar-link-completed-1: @sidebar-link-color-1;
|
||||
@sidebar-link-completed-2: hsl(227, 13%, 44%);
|
||||
@sidebar-link-completed-weight-1: normal;
|
||||
@sidebar-link-completed-weight-2: 600;
|
||||
|
||||
// Dropdown
|
||||
@dropdown-divider-color-1: @sidebar-divider-color-1;
|
||||
@dropdown-divider-color-2: @sidebar-divider-color-2;
|
||||
@dropdown-border-color-1: @sidebar-divider-color-1;
|
||||
@dropdown-border-color-2: @sidebar-divider-color-2;
|
||||
@dropdown-background-1: @sidebar-background-1;
|
||||
@dropdown-background-2: @sidebar-background-2;
|
||||
|
||||
@dropdown-button-color-1: @header-button-color-1;
|
||||
@dropdown-button-color-2: hsl(228, 13%, 44%);
|
||||
@dropdown-button-hover-color-1: @header-button-hover-color-1;
|
||||
@dropdown-button-hover-color-2: hsl(240, 5%, 96%);
|
||||
|
||||
// Page
|
||||
@page-color-1: #704214;
|
||||
@page-color-2: hsl(214, 29%, 80%);
|
||||
@page-background-1: @body-background-1;
|
||||
@page-background-2: @body-background-2;
|
||||
|
||||
@page-link-color-1: inherit;
|
||||
@page-link-color-2: hsl(193, 61%, 53%);
|
||||
|
||||
@page-heading-color-1: inherit;
|
||||
@page-heading-color-2: hsl(60, 100%, 99%);
|
||||
@page-heading-border-color-1: inherit;
|
||||
@page-heading-border-color-2: hsl(230, 17%, 26%);
|
||||
@page-h6-color-1: inherit;
|
||||
@page-h6-color-2: hsl(230, 17%, 26%);
|
||||
|
||||
@page-hr-color-1: inherit;
|
||||
@page-hr-color-2: hsl(230, 17%, 26%);
|
||||
|
||||
@page-blockquote-border-color-1: inherit;
|
||||
@page-blockquote-border-color-2: hsl(230, 17%, 26%);
|
||||
|
||||
@page-pre-color-1: #657b83;
|
||||
@page-pre-color-2: hsl(206, 43%, 73%);
|
||||
@page-pre-background-1: #fdf6e3;
|
||||
@page-pre-background-2: hsl(229, 20%, 22%);
|
||||
@page-pre-border-color-1: darken(#fdf6e3, 15%);
|
||||
@page-pre-border-color-2: hsl(229, 20%, 22%);
|
||||
@page-highlight-background-1: inherit;
|
||||
@page-highlight-background-2: hsl(233, 18%, 19%);
|
||||
|
||||
@page-table-header-border-color-1: darken(#fdf6e3, 25%);
|
||||
@page-table-header-border-color-2: hsl(230, 17%, 28%);
|
||||
@page-table-row-border-color-1: #444;
|
||||
@page-table-row-border-color-2: hsl(230, 17%, 28%);
|
||||
@page-table-row-color-1: inherit;
|
||||
@page-table-row-color-2: hsl(216, 24%, 77%);
|
||||
@page-table-row-background-1: #fdf6e3;
|
||||
@page-table-row-background-2: hsl(229, 19%, 22%);
|
||||
@page-table-row-odd-background-1: darken(#fdf6e3, 5%);
|
||||
@page-table-row-odd-background-2: hsl(229, 17%, 25%);
|
||||
|
||||
// Page Bar
|
||||
@bar-background-1: @page-background-1;
|
||||
@bar-background-2: @page-background-2;
|
||||
|
||||
// Navigation
|
||||
@navigation-color-1: @header-button-color-1;
|
||||
@navigation-color-2: hsl(224, 19%, 27%);
|
||||
@navigation-hover-color-1: @header-button-hover-color-1;
|
||||
@navigation-hover-color-2: hsl(60, 100%, 98%);
|
||||
|
||||
// Basics of a navbar
|
||||
@navbar-default-border-1: #d5d5d5;
|
||||
@navbar-default-border-2: #d5d5d5;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<body>
|
||||
<div class="pdf-footer">
|
||||
<span>_SECTION_</span>
|
||||
<span class="footer-pages-count">_PAGENUM_</span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user