Compare commits

...

48 Commits

Author SHA1 Message Date
Aaron O'Mullan 4850c0f302 Bump version to 0.1.1 2014-04-05 01:10:51 -07:00
Aaron O'Mullan ac258329ff Copy README.html to index.html instead of symlimk
Fixes #28
2014-04-05 01:05:31 -07:00
Samy Pessé d5bd08dcd2 Show exercise in page format 2014-04-04 20:12:22 -07:00
Samy Pessé 6c414ec400 Fix link for chapters in page format 2014-04-04 20:01:50 -07:00
Samy Pessé 881a0c6f6d Add info about --theme option 2014-04-04 18:21:40 -07:00
Samy Pessé 0071594300 Fix error with mixpanel loading 2014-04-04 18:18:50 -07:00
Samy Pessé 460799828f Merge pull request #27 from qrohlf/fix-sidebar-mobile
don't show the sidebar by default on mobile
2014-04-05 02:56:57 +02:00
Samy Pessé 02b75288d2 No need to include highlight twice (style.css and print.css) 2014-04-04 17:50:35 -07:00
Samy Pessé b108be0c3b Add separation line between pages 2014-04-04 17:46:59 -07:00
Samy Pessé 7ab285832b Improve style for page printing 2014-04-04 17:40:37 -07:00
Quinn Rohlf 0bc288fe96 don't show the sidebar by default on mobile 2014-04-04 16:44:25 -07:00
Samy Pessé 9fbe240843 Add summary to page generator 2014-04-04 16:40:21 -07:00
Samy Pessé 0c7e2b3557 Add base style for printing 2014-04-04 16:02:57 -07:00
Samy Pessé e34e65813c Fix pages order in page generator 2014-04-04 15:53:30 -07:00
Samy Pessé 63f946ced9 In page generator, add break for printing between pages 2014-04-04 15:47:45 -07:00
Samy Pessé af9f3cf89f Don't generate folder when using generator "page" 2014-04-04 15:41:22 -07:00
Samy Pessé 355094bbb3 Change option for changing generator to format 2014-04-04 15:38:01 -07:00
Samy Pessé b3adedb468 Add base for generating single page html 2014-04-04 14:40:27 -07:00
Samy Pessé 026e4362d8 Move mixpanel to app.js 2014-04-04 14:27:32 -07:00
Samy Pessé 9cf5384fbe Change template name for site generation to site 2014-04-04 14:22:48 -07:00
Samy Pessé 9bc0bf19da Add command line options for changing theme 2014-04-04 14:15:06 -07:00
Samy Pessé f49a1a484e Remove lex command 2014-04-04 14:11:43 -07:00
Samy Pessé 446d486a0f Add base for theming 2014-04-04 14:10:56 -07:00
Samy Pessé 07101deaef Move generator to specific folder 2014-04-04 13:57:07 -07:00
Samy Pessé 76b3fcb41c Add base for page generator 2014-04-04 13:55:43 -07:00
Samy Pessé febda9aba1 Add Travis CI badge 2014-04-04 20:07:05 +02:00
Aaron O'Mullan f952fa47b9 Use relative symlink between index & README
Fixes #19, fixes #21
2014-04-04 11:04:58 -07:00
Samy Pessé 1984660930 Rename PAGE.MD to PAGE.md 2014-04-04 20:04:49 +02:00
Aaron O'Mullan d475affd3b Merge pull request #25 from GitbookIO/feature/generators
Feature/generators
2014-04-04 10:59:13 -07:00
Samy Pessé fe3de93e06 Create .travis.yml 2014-04-04 19:57:51 +02:00
Samy Pessé 5cae311edf Log error in command line tool 2014-04-04 10:55:48 -07:00
Samy Pessé 26701a2a73 Remove logs from generation 2014-04-04 10:50:59 -07:00
Samy Pessé 5125e04814 Update tests 2014-04-04 10:47:44 -07:00
Samy Pessé 0a6194340f Remove file template.js 2014-04-04 10:46:11 -07:00
Samy Pessé e0d96b3163 Fix links in templates 2014-04-04 10:45:36 -07:00
Samy Pessé f656390783 Base for new site generator 2014-04-04 10:39:27 -07:00
Samy Pessé 88c480ba4f Complete json generator 2014-04-04 10:27:45 -07:00
Samy Pessé 3da53d56a2 Add option -g to choice generator
Add base json generator
2014-04-04 09:53:05 -07:00
Samy Pessé 91359fab1e _path is not used anymore 2014-04-04 09:47:34 -07:00
Samy Pessé a52a4bed1a Change normalization of parser to give link in .md 2014-04-04 09:47:06 -07:00
Samy Pessé 9dce855113 Add class BaseGenerator 2014-04-04 09:45:04 -07:00
Samy Pessé 57e2595a3e Merge pull request #20 from mintbridge/github-host-url
Adding config option for github host
2014-04-04 16:51:28 +02:00
Paul Dixon b1314273bb Adding config option for github host
- this config option allows the github host url to be set to
something other than github.com, mainly so that github enterprise
users can change the url to their private host but will also
work with bitbucket
2014-04-04 14:55:08 +01:00
Samy Pessé cb9a0b82ba Fix some typos in lib 2014-04-04 00:00:12 -07:00
Samy Pessé 57ecfe4a54 Make templates more modular 2014-04-03 23:54:03 -07:00
Samy Pessé 405792fd8f Fix #17: Remember state of book summary panel 2014-04-03 23:17:45 -07:00
Samy Pessé fc6d911340 Merge pull request #16 from wh0/patch-1
GiBook -> GitBook
2014-04-04 05:00:29 +02:00
wh0 1e6307b69b GiBook -> GitBook 2014-04-03 19:59:56 -07:00
134 changed files with 679 additions and 298 deletions
+5
View File
@@ -0,0 +1,5 @@
language: node_js
node_js:
- "0.11"
- "0.10"
- "0.8"
+9 -4
View File
@@ -16,7 +16,8 @@ module.exports = function (grunt) {
optimization: 2
},
files: {
"assets/static/style.css": "assets/stylesheets/main.less"
"theme/assets/style.css": "theme/stylesheets/main.less",
"theme/assets/print.css": "theme/stylesheets/print.less"
}
}
},
@@ -24,8 +25,8 @@ module.exports = function (grunt) {
compile: {
options: {
name: "app",
baseUrl: "assets/javascript/",
out: "assets/static/app.js",
baseUrl: "theme/javascript/",
out: "theme/assets/app.js",
preserveLicenseComments: false,
optimize: "uglify",
include: ["requireLib"],
@@ -33,7 +34,8 @@ module.exports = function (grunt) {
"jQuery": 'vendors/jquery',
"lodash": 'vendors/lodash',
"requireLib": 'vendors/require',
"Mousetrap": 'vendors/mousetrap'
"Mousetrap": 'vendors/mousetrap',
"mixpanel": 'vendors/mixpanel'
},
shim: {
'jQuery': {
@@ -44,6 +46,9 @@ module.exports = function (grunt) {
},
'Mousetrap': {
exports: 'Mousetrap'
},
'mixpanel': {
exports: 'mixpanel'
}
}
}
+3 -1
View File
@@ -1,7 +1,9 @@
GitBook
=======
GiBook is a command line tool (and Node.js library) for building beautiful programming books and exercises using GitHub/Git and Markdown. You can see an example: [Learn Javascript](http://gitbookio.github.io/javascript/).
[![Build Status](https://travis-ci.org/GitbookIO/gitbook.png?branch=master)](https://travis-ci.org/GitbookIO/gitbook)
GitBook is a command line tool (and Node.js library) for building beautiful programming books and exercises using GitHub/Git and Markdown. You can see an example: [Learn Javascript](http://gitbookio.github.io/javascript/).
![Image](https://raw.github.com/GitbookIO/gitbook/master/preview.png)
-18
View File
@@ -1,18 +0,0 @@
define([], function() {
var isAvailable = function() {
return (typeof mixpanel !== "undefined");
};
var track = function(event, data) {
if (!isAvailable()) {
console.log("tracking not available!");
return;
}
mixpanel.track(event, data);
};
return {
isAvailable: isAvailable,
track: track
};
});
File diff suppressed because one or more lines are too long
+20 -19
View File
@@ -1,6 +1,7 @@
#! /usr/bin/env node
// Requires
var Q = require('q');
var _ = require('lodash');
var path = require('path');
var prog = require('commander');
@@ -10,9 +11,14 @@ var fs = require('fs');
var pkg = require('../package.json');
var generate = require("../lib/generate");
var parse = require("../lib/parse");
var generators = require("../lib/generate").generators;
var utils = require('./utils');
var logError = function(err) {
console.log(err.message || err);
return Q.reject(err);
};
// General options
prog
@@ -25,9 +31,12 @@ prog
.command('build [source_dir]')
.description('Build a gitbook from a directory')
.option('-o, --output <directory>', 'Path to output directory, defaults to ./_book')
.option('-f, --format <name>', 'Change generation format, defaults to site, availables are: '+_.keys(generators).join(", "))
.option('-t, --title <name>', 'Name of the book to generate, defaults to repo name')
.option('-i, --intro <intro>', 'Description of the book to generate')
.option('-g, --github <repo_path>', 'ID of github repo like : username/repo')
.option('-gh, --githubHost <url>', 'The url of the github host (defaults to https://github.com/')
.option('--theme <path>', 'Path to theme directory')
.action(buildFunc = function(dir, options) {
dir = dir || process.cwd();
outputDir = options.output || path.join(dir, '_book');
@@ -54,20 +63,20 @@ prog
var title = options.title || utils.titleCase(repo);
return generate.folder(
dir,
outputDir,
{
input: dir,
output: outputDir,
title: title,
description: options.intro,
github: githubID
github: githubID,
generator: options.format,
theme: options.theme
}
);
})
.then(function(output) {
console.log("Successfuly built !");
}, function(err) {
throw err;
})
}, logError)
.then(_.constant(outputDir));
});
@@ -76,34 +85,26 @@ prog
.description('Build then serve a gitbook from a directory')
.option('-p, --port <port>', 'Port for server to listen on', 4000)
.option('-o, --output <directory>', 'Path to output directory, defaults to ./_book')
.option('-f, --format <name>', 'Change generation format, defaults to site, availables are: '+_.keys(generators).join(", "))
.option('-t, --title <name>', 'Name of the book to generate, defaults to repo name')
.option('-g, --github <repo_path>', 'ID of github repo like : username/repo')
.option('-gh, --githubHost <url>', 'The url of the github host (defaults to https://github.com/')
.option('--theme <path>', 'Path to theme directory')
.action(function(dir, options) {
buildFunc(dir, options)
.then(function(outputDir) {
console.log();
console.log('Starting server ...');
return utils.serveDir(outputDir, options.port);
return utils.serveDir(outputDir, options.port)
.fail(logError);
})
.then(function() {
console.log('Serving book on http://localhost:'+options.port);
console.log();
console.log('Press CTRL+C to quit ...');
})
.fail(function(err) {
console.error(err);
});
});
prog
.command('lex <page_file>')
.description('Parse a page file into sections, display JSON dump')
.action(function(page_file) {
var parsed = parse.page(fs.readFileSync(page_file, 'utf-8'));
console.log(JSON.stringify(parsed, null, 4));
});
// Parse and fallback to help if no args
+32
View File
@@ -0,0 +1,32 @@
var path = require("path");
var Q = require("q");
var fs = require("./fs");
var BaseGenerator = function(options) {
this.options = options;
};
BaseGenerator.prototype.convertFile = function(content, input) {
return Q.reject(new Error("Could not convert "+input));
};
BaseGenerator.prototype.transferFile = function(input) {
return fs.copy(
path.join(this.options.input, input),
path.join(this.options.output, input)
);
};
BaseGenerator.prototype.transferFolder = function(input) {
return fs.mkdirp(
path.join(this.options.output, input)
);
};
BaseGenerator.prototype.finish = function() {
return Q.reject(new Error("Could not finish generation"));
};
module.exports = BaseGenerator;
+46 -57
View File
@@ -5,33 +5,55 @@ var path = require("path");
var fs = require("./fs");
var parse = require("../parse");
var template = require("./template");
var generate = function(root, output, options) {
var files, summary, navigation, tpl;
var generators = {
"site": require("./site"),
"page": require("./page"),
"json": require("./json")
};
var generate = function(options) {
var generator = null;
var files;
options = _.defaults(options || {}, {
// Folders to use
input: null,
output: null,
// Output generator
generator: "site",
// Book title, keyword, description
title: null,
description: "Book generated using GitBook",
// Origin github repository id
github: null
github: null,
githubHost: 'https://github.com/',
// Theming
theme: path.resolve(__dirname, '../../theme')
});
if (!options.github || !options.title) return Q.reject(new Error("Need options.github and optiosn.title"));
if (!options.github || !options.title || !options.input || !options.output) {
return Q.reject(new Error("Need options: github, title, input, output"));
}
if (!generators[options.generator]) {
return Q.reject(new Error("Invalid generator (availables are: "+_.keys(generators).join(", ")));
}
// Clean output folder
return fs.remove(output)
return fs.remove(options.output)
.then(function() {
return fs.mkdirp(output);
return fs.mkdirp(options.output);
})
// List all files in the repository
.then(function() {
return fs.list(root);
return fs.list(options.input);
})
// Check repository is valid
@@ -45,31 +67,18 @@ var generate = function(root, output, options) {
// Get summary
.then(function() {
return fs.readFile(path.join(root, "SUMMARY.md"), "utf-8")
return fs.readFile(path.join(options.input, "SUMMARY.md"), "utf-8")
.then(function(_summary) {
summary = parse.summary(_summary);
options.summary = parse.summary(_summary);
// Parse navigation
navigation = parse.navigation(summary);
options.navigation = parse.navigation(options.summary);
});
})
// Create template
// Create the generator
.then(function() {
tpl = template({
root: root,
output: output,
locals: {
title: options.title,
description: options.description,
githubAuthor: options.github.split("/")[0],
githubId: options.github,
summary: summary,
allNavigation: navigation
}
});
generator = new generators[options.generator](options);
})
// Copy file and replace markdown file
@@ -78,49 +87,29 @@ var generate = function(root, output, options) {
_.chain(files)
.map(function(file) {
if (!file) return;
var _html = file.replace(".md", ".html");
// Folder
if (file[file.length -1] == "/") {
return fs.mkdirp(
path.join(output, file)
);
}
// Markdown file (only from the summary)
else if (path.extname(file) == ".md" && navigation[_html] != null) {
return tpl(file, file.replace(".md", ".html"));
}
// Copy file
else {
return fs.copy(
path.join(root, file),
path.join(output, file)
);
return Q(generator.transferFolder(file));
} else if (path.extname(file) == ".md" && options.navigation[file] != null) {
return fs.readFile(path.join(options.input, file), "utf-8")
.then(function(content) {
return Q(generator.convertFile(content, file));
});
} else {
return Q(generator.transferFile(file));
}
})
.value()
);
})
// Symlink index.html to README.html
// Finish gneration
.then(function() {
return fs.symlink(
path.join(output, 'README.html'),
path.join(output, 'index.html')
);
})
// Copy assets
.then(function() {
return fs.copy(
path.join(__dirname, "../../assets/static"),
path.join(output, "gitbook")
);
return generator.finish();
});
};
module.exports = {
generators: generators,
folder: generate
};
+47
View File
@@ -0,0 +1,47 @@
var util = require("util");
var path = require("path");
var Q = require("q");
var fs = require("../fs");
var parse = require("../../parse");
var BaseGenerator = require("../generator");
var Generator = function() {
BaseGenerator.apply(this, arguments);
};
util.inherits(Generator, BaseGenerator);
Generator.prototype.transferFile = function(input) {
// ignore
};
Generator.prototype.convertFile = function(content, input) {
var that = this;
var json = {
progress: parse.progress(this.options.navigation, input)
};
return Q()
.then(function() {
return parse.page(content, {
repo: that.options.githubId,
dir: path.dirname(input) || '/'
});
})
.then(function(sections) {
json.sections = sections;
})
.then(function() {
return fs.writeFile(
path.join(that.options.output, input.replace(".md", ".json")),
JSON.stringify(json, null, 4)
);
});
};
Generator.prototype.finish = function() {
// ignore
};
module.exports = Generator;
+109
View File
@@ -0,0 +1,109 @@
var _ = require("lodash");
var util = require("util");
var path = require("path");
var Q = require("q");
var swig = require('swig');
var hljs = require('highlight.js');
var fs = require("../fs");
var parse = require("../../parse");
var BaseGenerator = require("../generator");
// Swig filter: highlight coloration
swig.setFilter('code', function(code, lang) {
try {
return hljs.highlight(lang, code).value;
} catch(e) {
return hljs.highlightAuto(code).value;
}
});
/*
* This generator will generate a simple index.html which can be converted as a PDF
*/
var Generator = function() {
BaseGenerator.apply(this, arguments);
// Load base template
this.template = swig.compileFile(path.resolve(this.options.theme, 'templates/page.html'));
// List of pages content
this.pages = {};
};
util.inherits(Generator, BaseGenerator);
Generator.prototype.transferFile = function(input) {
// ignore
};
Generator.prototype.transferFolder = function(input) {
// ignore
};
Generator.prototype.convertFile = function(content, input) {
var that = this;
var json = {
path: input,
progress: parse.progress(this.options.navigation, input)
};
return Q()
.then(function() {
return parse.page(content, {
repo: that.options.githubId,
dir: path.dirname(input) || '/'
});
})
.then(function(sections) {
json.content = sections;
})
.then(function() {
that.pages[input] = json;
});
};
Generator.prototype.finish = function() {
var that = this;
var basePath = ".";
var output = path.join(this.options.output, "index.html");
return Q()
// Generate html
.then(function(pages) {
return that.template({
title: that.options.title,
description: that.options.description,
githubAuthor: that.options.github.split("/")[0],
githubId: that.options.github,
githubHost: that.options.githubHost,
summary: that.options.summary,
allNavigation: that.options.navigation,
pages: that.pages,
basePath: basePath,
staticBase: path.join(basePath, "gitbook"),
});
})
// Write html to index.html
.then(function(html) {
return fs.writeFile(
output,
html
);
})
// Copy assets
.then(function() {
return fs.copy(
path.join(that.options.theme, "assets"),
path.join(that.options.output, "gitbook")
);
});
};
module.exports = Generator;
+92
View File
@@ -0,0 +1,92 @@
var util = require("util");
var path = require("path");
var Q = require("q");
var _ = require("lodash");
var swig = require('swig');
var fs = require("../fs");
var parse = require("../../parse");
var BaseGenerator = require("../generator");
// Swig filter for returning the count of lines in a code section
swig.setFilter('lines', function(content) {
return content.split('\n').length;
});
// Swig filter for returning a link to the associated html file of a markdown file
swig.setFilter('mdLink', function(link) {
return link.replace(".md", ".html");
});
var Generator = function() {
BaseGenerator.apply(this, arguments);
// Load base template
this.template = swig.compileFile(path.resolve(this.options.theme, 'templates/site.html'));
};
util.inherits(Generator, BaseGenerator);
// Convert a markdown file to html
Generator.prototype.convertFile = function(content, _input) {
var that = this;
var progress = parse.progress(this.options.navigation, _input);
_output = _input.replace(".md", ".html");
var input = path.join(this.options.input, _input);
var output = path.join(this.options.output, _output);
var basePath = path.relative(path.dirname(output), this.options.output) || ".";
return Q()
.then(function() {
return parse.page(content, {
repo: that.options.githubId,
dir: path.dirname(input) || '/'
});
})
.then(function(sections) {
return that.template({
title: that.options.title,
description: that.options.description,
githubAuthor: that.options.github.split("/")[0],
githubId: that.options.github,
githubHost: that.options.githubHost,
summary: that.options.summary,
allNavigation: that.options.navigation,
progress: progress,
_input: _input,
content: sections,
basePath: basePath,
staticBase: path.join(basePath, "gitbook"),
});
})
.then(function(html) {
return fs.writeFile(
output,
html
);
});
};
// Symlink index.html and copy assets
Generator.prototype.finish = function() {
var that = this;
return fs.copy(
path.join(that.options.output, 'README.html'),
path.join(that.options.output, 'index.html')
)
.then(function() {
return fs.copy(
path.join(that.options.theme, "assets"),
path.join(that.options.output, "gitbook")
);
});
};
module.exports = Generator;
-67
View File
@@ -1,67 +0,0 @@
var swig = require('swig');
var path = require('path');
var _ = require("lodash");
var parse = require("../parse");
var fs = require('./fs');
swig.setFilter('lines', function(content) {
return content.split('\n').length;
});
// return a templeter for page
var initTemplate = function(options) {
var tpl = swig.compileFile(path.resolve(__dirname, '../../templates/page.html'));
var nExercise = 1;
options = _.defaults(options || {}, {
// Base folder for input
root: "./",
// Base folder for output
output: "./",
// Locals for templates
locals: {}
});
return function(input, output, local) {
var _input = input, _output = output;
input = path.join(options.root, input);
output = path.join(options.output, output);
var basePath = path.relative(path.dirname(output), options.output) || ".";
// Read markdown file
return fs.readFile(input, "utf-8")
// Parse sections
.then(function(markdown) {
return parse.page(markdown, {
repo: options.locals.githubId,
dir: path.dirname(_input) || '/'
});
})
//Calcul template
.then(function(sections) {
return tpl(
_.extend(local || {}, options.locals, {
_input: _input,
content: sections,
basePath: basePath,
staticBase: path.join(basePath, "gitbook"),
progress: parse.progress(options.locals.allNavigation, _output)
})
);
})
// Write html
.then(function(html) {
return fs.writeFile(output, html);
})
}
};
module.exports = initTemplate;
+6 -6
View File
@@ -1,15 +1,15 @@
var _ = require('lodash');
// Cleans up an article/chapter object
// remove 'articles' and '_path' attributes
// remove 'articles' attributes
function clean(obj) {
return obj && _.omit(obj, ['articles', '_path']);
return obj && _.omit(obj, ['articles']);
}
// Returns a map of
// Returns from a summary a map of
/*
{
"file/path.html": {
"file/path.md": {
prev: ...,
next: ...,
},
@@ -25,7 +25,7 @@ function navigation(summary, files) {
// Special README nav
var README_NAV = {
path: 'README.html',
path: 'README.md',
title: 'Introduction',
};
@@ -69,7 +69,7 @@ function navigation(summary, files) {
});
// Hack for README.html
mapping['README.html'] = {
mapping['README.md'] = {
title: README_NAV.title,
prev: null,
next: clean(summary.chapters[0]),
+1
View File
@@ -1,5 +1,6 @@
var _ = require("lodash");
// Returns from a navigation and a current file, a snapshot of current detailed state
var calculProgress = function(navigation, current) {
var n = _.size(navigation);
var percent = 0, prevPercent = 0, currentChapter = null;
+1 -4
View File
@@ -82,10 +82,7 @@ function parseTitle(src, nums) {
level: level,
// Replace .md references with .html
path: matches[2].replace(/\.md$/, '.html'),
// Original, non normalized path
_path: matches[2],
path: matches[2],
};
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "gitbook",
"version": "0.1.0",
"version": "0.1.1",
"description": "Library and cmd utility to generate GitBooks",
"main": "lib/index.js",
"dependencies": {
-51
View File
@@ -1,51 +0,0 @@
{% extends "layout.html" %}
{% block title %}{{ progress.current.title }}{% parent %}{% endblock %}
{% block content %}
<div class="book with-summary" data-github="{{ githubId }}" data-level="{{ progress.current.level }}">
{% include "includes/book/header.html" %}
{% include "includes/book/summary.html" %}
<div class="book-body" tabindex="-1">
<div class="page-wrapper">
<div class="book-progress">
<div class="bar">
<div class="inner" style="width: {{ progress.percent }}%;min-width: {{ progress.prevPercent }}%;"></div>
</div>
<div class="chapters">
{% for p in progress.chapters %}
<a href="{{ basePath }}/{{ p.path }}" title="{{ p.title }}" class="chapter {% if p.done %}done{% endif %} {% if p.level.length == 1 %}new-chapter{% endif %}" data-progress="{{ p.level }}" style="left: {{ p.percent }}%;"></a>
{% endfor %}
</div>
</div>
<div class="page-inner">
{% for section in content %}
<section class="{{ section.type }}" id="section-{{ section.id }}">
{% if section.type == "normal" %}
{% autoescape false %}{{ section.content }}{% endautoescape %}
{% elif section.type == "exercise" %}
{% include "./includes/book/exercise.html" with {section: section} %}
{% endif %}
</section>
{% endfor %}
</div>
<div class="page-footer">
{% if _input == "README.md" %}
<a href="{{ basePath }}/{{ progress.current.next.path }}" class="navigation-link">Start</a>
{% else %}
{% if progress.current.next %}
{% if progress.current.next.path %}
<a href="{{ basePath }}/{{ progress.current.next.path }}" class="navigation-link next">Next</a>
{% else %}
<div class="navigation-link coming-soon">Coming soon</div>
{% endif %}
{% else %}
<div class="navigation-link finished">Finished!</div>
{% endif %}
{% endif %}
</div>
</div>
</div>
</div>
{% endblock %}
View File
+32 -32
View File
@@ -13,57 +13,57 @@ var LEXED = summary(CONTENT);
describe('Summary navigation', function() {
it('should provide next & prev entries for a file', function() {
var nav = navigation(LEXED, [
'README.html',
'chapter-1/README.html',
'chapter-1/ARTICLE1.html',
'chapter-1/ARTICLE2.html',
'chapter-2/README.html',
'README.md',
'chapter-1/README.md',
'chapter-1/ARTICLE1.md',
'chapter-1/ARTICLE2.md',
'chapter-2/README.md',
]);
// Make sure it found the files we gave it
assert(nav['README.html']);
assert(nav['chapter-1/README.html']);
assert(nav['chapter-1/ARTICLE1.html']);
assert(nav['chapter-1/ARTICLE2.html']);
assert(nav['chapter-2/README.html']);
assert(nav['README.md']);
assert(nav['chapter-1/README.md']);
assert(nav['chapter-1/ARTICLE1.md']);
assert(nav['chapter-1/ARTICLE2.md']);
assert(nav['chapter-2/README.md']);
assert.equal(nav['README.html'].prev, null);
assert.equal(nav['README.html'].next.path, 'chapter-1/README.html');
assert.equal(nav['README.md'].prev, null);
assert.equal(nav['README.md'].next.path, 'chapter-1/README.md');
assert.equal(nav['chapter-1/README.html'].prev.path, 'README.html');
assert.equal(nav['chapter-1/README.html'].next.path, 'chapter-1/ARTICLE1.html');
assert.equal(nav['chapter-1/README.md'].prev.path, 'README.md');
assert.equal(nav['chapter-1/README.md'].next.path, 'chapter-1/ARTICLE1.md');
assert.equal(nav['chapter-1/ARTICLE1.html'].prev.path, 'chapter-1/README.html');
assert.equal(nav['chapter-1/ARTICLE1.html'].next.path, 'chapter-1/ARTICLE2.html');
assert.equal(nav['chapter-1/ARTICLE1.md'].prev.path, 'chapter-1/README.md');
assert.equal(nav['chapter-1/ARTICLE1.md'].next.path, 'chapter-1/ARTICLE2.md');
assert.equal(nav['chapter-1/ARTICLE2.html'].prev.path, 'chapter-1/ARTICLE1.html');
assert.equal(nav['chapter-1/ARTICLE2.html'].next.path, 'chapter-2/README.html');
assert.equal(nav['chapter-1/ARTICLE2.md'].prev.path, 'chapter-1/ARTICLE1.md');
assert.equal(nav['chapter-1/ARTICLE2.md'].next.path, 'chapter-2/README.md');
assert.equal(nav['chapter-2/README.html'].prev.path, 'chapter-1/ARTICLE2.html');
assert.equal(nav['chapter-2/README.html'].next.path, 'chapter-3/README.html');
assert.equal(nav['chapter-2/README.md'].prev.path, 'chapter-1/ARTICLE2.md');
assert.equal(nav['chapter-2/README.md'].next.path, 'chapter-3/README.md');
});
it('should give full tree, when not limited', function() {
var nav = navigation(LEXED);
assert(nav['README.html']);
assert(nav['chapter-1/README.html']);
assert(nav['chapter-1/ARTICLE1.html']);
assert(nav['chapter-1/ARTICLE2.html']);
assert(nav['chapter-2/README.html']);
assert(nav['chapter-3/README.html']);
assert(nav['README.md']);
assert(nav['chapter-1/README.md']);
assert(nav['chapter-1/ARTICLE1.md']);
assert(nav['chapter-1/ARTICLE2.md']);
assert(nav['chapter-2/README.md']);
assert(nav['chapter-3/README.md']);
});
it('should detect levels correctly', function() {
var nav = navigation(LEXED);
assert.equal(nav['README.html'].level, '0');
assert.equal(nav['chapter-1/README.html'].level, '1');
assert.equal(nav['chapter-1/ARTICLE1.html'].level, '1.1');
assert.equal(nav['chapter-1/ARTICLE2.html'].level, '1.2');
assert.equal(nav['chapter-2/README.html'].level, '2');
assert.equal(nav['chapter-3/README.html'].level, '3');
assert.equal(nav['README.md'].level, '0');
assert.equal(nav['chapter-1/README.md'].level, '1');
assert.equal(nav['chapter-1/ARTICLE1.md'].level, '1.1');
assert.equal(nav['chapter-1/ARTICLE2.md'].level, '1.2');
assert.equal(nav['chapter-2/README.md'].level, '2');
assert.equal(nav['chapter-3/README.md'].level, '3');
});
it('should not accept null paths', function() {
+3 -6
View File
@@ -37,12 +37,9 @@ describe('Summary parsing', function () {
});
it('should normalize paths from .md to .html', function() {
assert.equal(LEXED.chapters[0].path,'chapter-1/README.html');
assert.equal(LEXED.chapters[0]._path,'chapter-1/README.md');
assert.equal(LEXED.chapters[1].path,'chapter-2/README.html');
assert.equal(LEXED.chapters[1]._path,'chapter-2/README.md');
assert.equal(LEXED.chapters[2].path,'chapter-3/README.html');
assert.equal(LEXED.chapters[2]._path,'chapter-3/README.md');
assert.equal(LEXED.chapters[0].path,'chapter-1/README.md');
assert.equal(LEXED.chapters[1].path,'chapter-2/README.md');
assert.equal(LEXED.chapters[2].path,'chapter-3/README.md');
});
it('should detect levels correctly', function() {
+5
View File
@@ -0,0 +1,5 @@
# GitBook Theme
For creating a theme for GitBook, just copy this folder. The theme folder should at least contains two folders: `assets` and `templates`.
The theme can be changed using the option ```--theme=<path>```
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 198 KiB

After

Width:  |  Height:  |  Size: 198 KiB

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 59 KiB

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

+1
View File
@@ -0,0 +1 @@
h1,h2{page-break-after:avoid;page-break-before:auto}pre,blockquote{border:1px solid #999;page-break-inside:avoid}img{max-width:100%!important;page-break-inside:avoid}section{page-break-after:always}section#cover{padding:3cm 0;text-align:center}section#cover h1{font-size:1.5cm}section#summary{text-align:center}section#summary ul{font-size:.5cm;line-height:1.8em;padding:0;margin:0;list-style:none}section#summary>ul>li{margin-bottom:1cm}section#summary>ul>li>a{font-size:.6cm}section article{margin:1.5cm}section article.new-chapter{page-break-after:always;font-size:.6cm;text-align:center;padding:3cm 0;border-top:1px solid #ccc}@media print{section article.new-chapter{border:0}}section article .exercise{border:3px solid #ddd}
File diff suppressed because one or more lines are too long
@@ -17,9 +17,6 @@ require([
// Initialize storage
storage.setBaseKey(state.githubId);
// Tract page view
analytic.track("View");
// Init sidebar
sidebar.init();
@@ -31,8 +31,10 @@ define([
toggleSidebar();
});
// Init last state if not mobile and not homepage
toggleSidebar(platform.isMobile ? false : storage.get("sidebar", true), false);
// Init last state if not mobile
if (!platform.isMobile) {
toggleSidebar(storage.get("sidebar", true), false);
}
};
return {
+30
View File
@@ -0,0 +1,30 @@
define([
"lodash",
"mixpanel"
], function(_, mixpanel) {
mixpanel.init("01eb2b950ae09a5fdb15a98dcc5ff20e", {
loaded: function() {
track("View");
}
});
var isAvailable = function() {
return (typeof mixpanel !== "undefined");
};
var track = function(e, data) {
if (!isAvailable()) {
console.warn("tracking not available!");
return;
}
console.log("track", e);
mixpanel.track(e, _.extend(data || {}, {
'domain': window.location.host
}));
};
return {
isAvailable: isAvailable,
track: track
};
});
@@ -14,9 +14,12 @@ define(function(){
},
get: function(key, def) {
key = baseKey+":"+key;
if (localStorage[key] === undefined) return def;
try {
return JSON.parse(localStorage[key]) || def;
var v = JSON.parse(localStorage[key]);
return v == null ? def : v;;
} catch(err) {
console.error(err);
return localStorage[key] || def;
}
},
+2
View File
@@ -0,0 +1,2 @@
(function(e,b){if(!b.__SV){var a,f,i,g;window.mixpanel=b;b._i=[];b.init=function(a,e,d){function f(b,h){var a=h.split(".");2==a.length&&(b=b[a[0]],h=a[1]);b[h]=function(){b.push([h].concat(Array.prototype.slice.call(arguments,0)))}}var c=b;"undefined"!==typeof d?c=b[d]=[]:d="mixpanel";c.people=c.people||[];c.toString=function(b){var a="mixpanel";"mixpanel"!==d&&(a+="."+d);b||(a+=" (stub)");return a};c.people.toString=function(){return c.toString(1)+".people (stub)"};i="disable track track_pageview track_links track_forms register register_once alias unregister identify name_tag set_config people.set people.set_once people.increment people.append people.track_charge people.clear_charges people.delete_user".split(" ");
for(g=0;g<i.length;g++)f(c,i[g]);b._i.push([a,e,d])};b.__SV=1.2;a=e.createElement("script");a.type="text/javascript";a.async=!0;a.src=("https:"===e.location.protocol?"https:":"http:")+'//cdn.mxpnl.com/libs/mixpanel-2.2.min.js';f=e.getElementsByTagName("script")[0];f.parentNode.insertBefore(a,f)}})(document,window.mixpanel||[]);
+72
View File
@@ -0,0 +1,72 @@
h1, h2 {
page-break-after: avoid;
page-break-before: auto;
}
pre, blockquote {
border: 1px solid #999;
page-break-inside: avoid;
}
img {
max-width: 100% !important;
page-break-inside: avoid;
}
section {
page-break-after: always;
&#cover {
padding: 3cm 0cm;
text-align: center;
h1 {
font-size: 1.5cm;
}
}
&#summary {
text-align: center;
ul {
font-size: 0.5cm;
line-height: 1.8em;
padding: 0px;
margin: 0px;
list-style: none;
}
> ul {
> li {
margin-bottom: 1cm;
> a {
font-size: 0.6cm;
}
}
}
}
article {
margin: 1.5cm;
/* Big centered title */
&.new-chapter {
page-break-after: always;
font-size: 0.6cm;
text-align: center;
padding: 3cm 0cm;
border-top: 1px solid #ccc;
@media print {
border: none;
}
}
.exercise {
border: 3px solid #ddd;
}
}
}
@@ -14,7 +14,7 @@
// Reset
@import "normalize.less";
@import "print.less";
//@import "print.less";
// Core CSS
@import "scaffolding.less";

Some files were not shown because too many files have changed in this diff Show More