summaryrefslogtreecommitdiffstats
path: root/lib/output/website.js
diff options
context:
space:
mode:
authorSamy Pessé <samypesse@gmail.com>2016-02-26 09:41:26 +0100
committerSamy Pessé <samypesse@gmail.com>2016-02-26 09:41:26 +0100
commitd3d64f636c859f7f01a64f7774cf70bd8ccdc562 (patch)
tree4f7731f37c3a793d187b0ab1cd77680e69534c6c /lib/output/website.js
parent4cb9cbb5ae3aa8f9211ffa3ac5e3d34232c0ca4f (diff)
parenteef072693b17526347c37b66078a5059c71caa31 (diff)
downloadgitbook-d3d64f636c859f7f01a64f7774cf70bd8ccdc562.zip
gitbook-d3d64f636c859f7f01a64f7774cf70bd8ccdc562.tar.gz
gitbook-d3d64f636c859f7f01a64f7774cf70bd8ccdc562.tar.bz2
Merge pull request #1109 from GitbookIO/3.0.0
Version 3.0.0
Diffstat (limited to 'lib/output/website.js')
-rw-r--r--lib/output/website.js270
1 files changed, 270 insertions, 0 deletions
diff --git a/lib/output/website.js b/lib/output/website.js
new file mode 100644
index 0000000..230af71
--- /dev/null
+++ b/lib/output/website.js
@@ -0,0 +1,270 @@
+var _ = require('lodash');
+var path = require('path');
+var util = require('util');
+var nunjucks = require('nunjucks');
+var I18n = require('i18n-t');
+
+var Promise = require('../utils/promise');
+var location = require('../utils/location');
+var fs = require('../utils/fs');
+var defaultFilters = require('../template/filters');
+var conrefsLoader = require('./conrefs');
+var Output = require('./base');
+
+// Tranform a theme ID into a plugin
+function themeID(plugin) {
+ return 'theme-' + plugin;
+}
+
+// Directory for a theme with the templates
+function templatesPath(dir) {
+ return path.join(dir, '_layouts');
+}
+
+function _WebsiteOutput() {
+ Output.apply(this, arguments);
+
+ // Nunjucks environment
+ this.env;
+
+ // Plugin instance for the main theme
+ this.theme;
+
+ // Plugin instance for the default theme
+ this.defaultTheme;
+
+ // Resources loaded from plugins
+ this.resources;
+
+ // i18n for themes
+ this.i18n = new I18n();
+}
+util.inherits(_WebsiteOutput, Output);
+
+var WebsiteOutput = conrefsLoader(_WebsiteOutput);
+
+// Name of the generator
+// It's being used as a prefix for templates
+WebsiteOutput.prototype.name = 'website';
+
+// Load and setup the theme
+WebsiteOutput.prototype.prepare = function() {
+ var that = this;
+
+ return Promise()
+ .then(function() {
+ return WebsiteOutput.super_.prototype.prepare.apply(that);
+ })
+
+ .then(function() {
+ var themeName = that.book.config.get('theme');
+ that.theme = that.plugins.get(themeID(themeName));
+ that.themeDefault = that.plugins.get(themeID('default'));
+
+ if (!that.theme) {
+ throw new Error('Theme "' + themeName + '" is not installed, add "' + themeID(themeName) + '" to your "book.json"');
+ }
+
+ if (that.themeDefault.root != that.theme.root) {
+ that.log.info.ln('build using theme "' + themeName + '"');
+ }
+
+ // This list is ordered to give priority to templates in the book
+ var searchPaths = _.chain([
+ // The book itself can contains a "_layouts" folder
+ that.book.root,
+
+ // Installed plugin (it can be identical to themeDefault.root)
+ that.theme.root,
+
+ // Is default theme still installed
+ that.themeDefault? that.themeDefault.root : null
+ ])
+ .compact()
+ .uniq()
+ .value();
+
+ // Load i18n
+ _.each(searchPaths.concat().reverse(), function(searchPath) {
+ var i18nRoot = path.resolve(searchPath, '_i18n');
+
+ if (!fs.existsSync(i18nRoot)) return;
+ that.i18n.load(i18nRoot);
+ });
+
+ that.env = new nunjucks.Environment(new nunjucks.FileSystemLoader(_.map(searchPaths, templatesPath)));
+
+ // Add GitBook default filters
+ _.each(defaultFilters, function(fn, filter) {
+ that.env.addFilter(filter, fn);
+ });
+
+ // Translate using _i18n locales
+ that.env.addFilter('t', function(s) {
+ return that.i18n.t(that.book.config.get('language'), s);
+ });
+
+ // Transform an absolute path into a relative path
+ // using this.ctx.page.path
+ that.env.addFilter('resolveFile', function(href) {
+ return location.normalize(that.resolveForPage(this.ctx.file.path, href));
+ });
+
+ // Test if a file exists
+ that.env.addFilter('fileExists', function(href) {
+ return fs.existsSync(that.resolve(href));
+ });
+
+ // Transform a '.md' into a '.html' (README -> index)
+ that.env.addFilter('contentURL', function(s) {
+ return location.normalize(that.outputUrl(s));
+ });
+
+ // Relase path to an asset
+ that.env.addFilter('resolveAsset', function(href) {
+ href = path.join('gitbook', href);
+
+ // Resolve for current file
+ if (this.ctx.file) {
+ href = that.resolveForPage(this.ctx.file.path, '/' + href);
+ }
+
+ // Use assets from parent
+ if (that.book.isLanguageBook()) {
+ href = path.join('../', href);
+ }
+
+ return location.normalize(href);
+ });
+ })
+
+ // Copy assets from themes before copying files from book
+ .then(function() {
+ if (that.book.isLanguageBook()) return;
+
+ return Promise.serie([
+ // Assets from the book are already copied
+ // The order is reversed from the template's one
+
+ // Is default theme still installed
+ that.themeDefault && that.themeDefault.root != that.theme.root?
+ that.themeDefault.root : null,
+
+ // Installed plugin (it can be identical to themeDefault.root)
+ that.theme.root
+ ], function(folder) {
+ if (!folder) return;
+
+ // Copy assets only if exists (don't fail otherwise)
+ var assetFolder = path.join(folder, '_assets', that.name);
+ if (!fs.existsSync(assetFolder)) return;
+
+ that.log.debug.ln('copy assets from theme', assetFolder);
+ return fs.copyDir(
+ assetFolder,
+ that.resolve('gitbook'),
+ {
+ deleteFirst: false, // Delete "to" before
+ overwrite: true,
+ confirm: true
+ }
+ );
+ });
+ })
+
+ // Load resources for plugins
+ .then(function() {
+ return that.plugins.getResources(that.name)
+ .then(function(resources) {
+ that.resources = resources;
+ });
+ });
+};
+
+// Write a page (parsable file)
+WebsiteOutput.prototype.onPage = function(page) {
+ var that = this;
+
+ // Parse the page
+ return page.toHTML(this)
+
+ // Render the page template with the same context as the json output
+ .then(function() {
+ return that.render('page', page.getContext());
+ })
+
+ // Write the HTML file
+ .then(function(html) {
+ return that.writeFile(
+ that.outputPath(page.path),
+ html
+ );
+ });
+};
+
+// Finish generation, create ebook using ebook-convert
+WebsiteOutput.prototype.finish = function() {
+ var that = this;
+
+ return Promise()
+ .then(function() {
+ return WebsiteOutput.super_.prototype.finish.apply(that);
+ })
+
+ // Copy assets from plugins
+ .then(function() {
+ if (that.book.isLanguageBook()) return;
+ return that.plugins.copyResources(that.name, that.resolve('gitbook'));
+ })
+
+ // Generate homepage to select languages
+ .then(function() {
+ if (!that.book.isMultilingual()) return;
+ return that.outputMultilingualIndex();
+ });
+};
+
+// ----- Utilities ----
+
+// Write multi-languages index
+WebsiteOutput.prototype.outputMultilingualIndex = function() {
+ var that = this;
+
+ return that.render('languages', that.getContext())
+ .then(function(html) {
+ return that.writeFile(
+ 'index.html',
+ html
+ );
+ });
+};
+
+// Render a template using nunjucks
+// Templates are stored in `_layouts` folders
+WebsiteOutput.prototype.render = function(tpl, context) {
+ var filename = this.templateName(tpl);
+ context = _.extend(context, {
+ template: {
+ // Same template but in the default theme
+ default: this.themeDefault? path.resolve(templatesPath(this.themeDefault.root), filename) : null,
+
+ // Same template but in the theme
+ theme: path.resolve(templatesPath(this.theme.root), filename)
+ },
+
+ plugins: {
+ resources: this.resources
+ },
+
+ options: this.opts
+ });
+
+ return Promise.nfcall(this.env.render.bind(this.env), filename, context);
+};
+
+// Return a complete name for a template
+WebsiteOutput.prototype.templateName = function(name) {
+ return path.join(this.name, name+'.html');
+};
+
+module.exports = WebsiteOutput;