summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamy Pesse <samypesse@gmail.com>2016-02-11 22:12:07 +0100
committerSamy Pesse <samypesse@gmail.com>2016-02-11 22:12:07 +0100
commit756694c029218510592418deb8aaf6f3b36f95c3 (patch)
tree86d938cbf6360d46845758a7cc9575ca04aa3594
parent669f3b39849890c48171d807225cd6eaa3c9086b (diff)
downloadgitbook-756694c029218510592418deb8aaf6f3b36f95c3.zip
gitbook-756694c029218510592418deb8aaf6f3b36f95c3.tar.gz
gitbook-756694c029218510592418deb8aaf6f3b36f95c3.tar.bz2
Page output a simple html string
-rw-r--r--lib/book.js1
-rw-r--r--lib/generators/json.js2
-rw-r--r--lib/generators/website/index.js3
-rw-r--r--lib/page/html.js36
-rw-r--r--lib/page/index.js25
-rw-r--r--lib/utils/location.js14
-rw-r--r--test/all.js1
-rw-r--r--test/assertions.js62
-rw-r--r--test/mock.js18
-rw-r--r--test/page.js26
10 files changed, 150 insertions, 38 deletions
diff --git a/lib/book.js b/lib/book.js
index 0f73135..148706c 100644
--- a/lib/book.js
+++ b/lib/book.js
@@ -214,6 +214,7 @@ Book.prototype.addPage = function(filename) {
if (this.pages[filename]) return;
this.pages[filename] = new Page(this, filename);
+ return this.pages[filename];
};
// Return a page by its filename (or undefined)
diff --git a/lib/generators/json.js b/lib/generators/json.js
index 560f099..5ba2d16 100644
--- a/lib/generators/json.js
+++ b/lib/generators/json.js
@@ -21,7 +21,7 @@ JSONGenerator.prototype.writePage = function(page) {
version: gitbook.version
},
path: page.path,
- sections: page.content.sections
+ sections: page.content
};
return that.output.writeFile(
diff --git a/lib/generators/website/index.js b/lib/generators/website/index.js
index f474cbb..67c80b6 100644
--- a/lib/generators/website/index.js
+++ b/lib/generators/website/index.js
@@ -19,7 +19,4 @@ WebsiteGenerator.prototype.writePage = function(page) {
};
-
-
-
module.exports = WebsiteGenerator;
diff --git a/lib/page/html.js b/lib/page/html.js
index f828d11..b19d5ed 100644
--- a/lib/page/html.js
+++ b/lib/page/html.js
@@ -4,6 +4,7 @@ var domSerializer = require('dom-serializer');
var slug = require('github-slugid');
var Promise = require('../utils/promise');
+var location = require('../utils/location');
// Render a cheerio DOM as html
function renderDOM($, dom, options) {
@@ -18,7 +19,10 @@ function HTMLPipeline(htmlString, opts) {
_.bindAll(this);
this.opts = _.defaults(opts || {}, {
- convertImages: true
+ convertImages: true,
+
+ // Calcul new href for a relative link
+ onRelativeLink: _.identity
});
this.$ = cheerio.load(htmlString, {
@@ -31,15 +35,38 @@ function HTMLPipeline(htmlString, opts) {
});
}
+// Normalize links
+HTMLPipeline.prototype.normalizeLinks = function() {
+ var that = this;
+
+ this.$('a').each(function() {
+ var $a = that.$(this);
+
+ var href = $a.attr('href');
+ if (!href) return;
+
+ if (location.isAnchor(href)) {
+ // Don't "change" anchor links
+ } else if (location.isRelative(href)) {
+ $a.attr('href', that.opts.onRelativeLink(href));
+ } else {
+ // External links
+ $a.attr('target', '_blank');
+ }
+
+ });
+};
+
// Add ID to headings
HTMLPipeline.prototype.addHeadingIDs = function() {
var that = this;
this.$('h1,h2,h3,h4,h5,h6').each(function() {
- // Already has an ID?
- if (that.$(this).attr('id')) return;
+ var $h = that.$(this);
- that.$(this).attr('id', slug(that.$(this).text()));
+ // Already has an ID?
+ if ($h.attr('id')) return;
+ $h.attr('id', slug($h.text()));
});
};
@@ -48,6 +75,7 @@ HTMLPipeline.prototype.output = function() {
var that = this;
return Promise()
+ .then(this.normalizeLinks)
.then(this.addHeadingIDs)
.then(function() {
return renderDOM(that.$);
diff --git a/lib/page/index.js b/lib/page/index.js
index 8f8819c..e7a4fec 100644
--- a/lib/page/index.js
+++ b/lib/page/index.js
@@ -3,7 +3,6 @@ var path = require('path');
var parsers = require('gitbook-parsers');
var error = require('../utils/error');
-var Promise = require('../utils/promise');
var HTMLPipeline = require('./html');
/*
@@ -99,21 +98,23 @@ Page.prototype.parse = function(opts) {
// Render markup using the parser
.then(function() {
return that.parser.page(that.content)
- .then(that.update);
+ .then(function(out) {
+ var content = _.pluck(out.sections, 'content').join('\n');
+ that.update(content);
+ });
})
// Normalize HTML output
.then(function() {
- return Promise.map(that.content.sections, function(section) {
- var pipeline = new HTMLPipeline(section.content, opts);
-
- return pipeline.output()
- .then(function(content) {
- return {
- content: content
- };
- });
- });
+ var pipelineOpts = _.extend({
+ onRelativeLink: function(href) {
+ console.log('href', href);
+ }
+ }, opts);
+ var pipeline = new HTMLPipeline(that.content, pipelineOpts);
+
+ return pipeline.output()
+ .then(that.update);
});
};
diff --git a/lib/utils/location.js b/lib/utils/location.js
index d57e84f..efe1425 100644
--- a/lib/utils/location.js
+++ b/lib/utils/location.js
@@ -9,13 +9,23 @@ function isExternal(href) {
}
}
-
// Inverse of isExternal
function isRelative(href) {
return !isExternal(href);
}
+// Return true if the link is an achor
+function isAnchor(href) {
+ try {
+ var parsed = url.parse(href);
+ return !!(!parsed.protocol && !parsed.path && parsed.hash);
+ } catch(err) {
+ return false;
+ }
+}
+
module.exports = {
isExternal: isExternal,
- isRelative: isRelative
+ isRelative: isRelative,
+ isAnchor: isAnchor
};
diff --git a/test/all.js b/test/all.js
index 827a182..08be793 100644
--- a/test/all.js
+++ b/test/all.js
@@ -5,6 +5,7 @@ require('./readme');
require('./summary');
require('./glossary');
require('./langs');
+require('./page');
require('./parse');
require('./git');
diff --git a/test/assertions.js b/test/assertions.js
new file mode 100644
index 0000000..b936995
--- /dev/null
+++ b/test/assertions.js
@@ -0,0 +1,62 @@
+var fs = require('fs');
+var _ = require('lodash');
+var cheerio = require('cheerio');
+var should = require('should');
+
+// Assertions to test if an Output has generated a file
+should.Assertion.add('file', function(file, description) {
+ this.params = {
+ actual: this.obj.toString(),
+ operator: 'have file ' + file,
+ message: description
+ };
+
+ this.obj.should.have.property('resolve').which.is.a.Function;
+ this.assert(fs.existsSync(this.obj.resolve(file)));
+});
+
+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) {
+ validations = _.defaults(validations || {}, {
+ // Select a specific element in the list of matched elements
+ index: null,
+
+ // Check that there is the correct count of elements
+ count: 1,
+
+ // Check attribute values
+ attributes: {},
+
+ // Trim inner text
+ trim: false,
+
+ // Check inner text
+ text: undefined
+ });
+
+ var $el = $(query);
+
+ // Select correct element
+ if (_.isNumber(validations.index)) $el = $($el.get(validations.index));
+
+ // Test number of elements
+ $el.length.should.be.equal(validations.count);
+
+ // Test text
+ if (validations.text !== undefined) {
+ var text = $el.text();
+ if (validations.trim) text = text.trim();
+ text.should.be.equal(validations.text);
+ }
+
+ // Test attributes
+ _.each(validations.attributes, function(value, name) {
+ var attr = $el.attr(name);
+ should(attr).be.ok();
+ attr.should.be.equal(value);
+ });
+ });
+});
diff --git a/test/mock.js b/test/mock.js
index 1f7e7d5..ce7b027 100644
--- a/test/mock.js
+++ b/test/mock.js
@@ -1,15 +1,14 @@
var Q = require('q');
var _ = require('lodash');
-var fs = require('fs');
var tmp = require('tmp');
var path = require('path');
-var should = require('should');
-
var Book = require('../').Book;
var Output = require('../lib/output');
var NodeFS = require('../lib/fs/node');
+require('./assertions');
+
// Create filesystem instance for testing
var nodeFS = new NodeFS();
@@ -74,19 +73,6 @@ function outputDefaultBook(generator, files, opts) {
});
}
-// Assertions to test if an Output has generated a file
-should.Assertion.add('file', function(file, description) {
- this.params = {
- actual: this.obj.toString(),
- operator: 'have file ' + file,
- message: description
- };
-
- this.obj.should.have.property('resolve').which.is.a.Function;
- this.assert(fs.existsSync(this.obj.resolve(file)));
-});
-
-
module.exports = {
setupBook: setupBook,
setupDefaultBook: setupDefaultBook,
diff --git a/test/page.js b/test/page.js
new file mode 100644
index 0000000..66c06e1
--- /dev/null
+++ b/test/page.js
@@ -0,0 +1,26 @@
+var mock = require('./mock');
+
+describe('Page', function() {
+ var book;
+
+ before(function() {
+ return mock.setupDefaultBook({
+ 'heading.md': '# Hello\n\n## World'
+ })
+ .then(function(_book) {
+ book = _book;
+ return book.summary.load();
+ });
+ });
+
+ it.only('should add a default ID to headings', function() {
+ var page = book.addPage('heading.md');
+
+ return page.parse()
+ .then(function() {
+ console.log(page.content);
+ });
+
+ });
+
+}); \ No newline at end of file