diff options
author | Samy Pessé <samypesse@gmail.com> | 2016-02-20 17:18:18 +0100 |
---|---|---|
committer | Samy Pessé <samypesse@gmail.com> | 2016-02-20 17:18:18 +0100 |
commit | cafbcd409774c383a26ce22b82b2104774c54c6d (patch) | |
tree | 07920323a4197211df483f8793fce0132ca040a5 | |
parent | a22539a91eea4101d244cdaeb5c61e31376ff4bc (diff) | |
download | gitbook-cafbcd409774c383a26ce22b82b2104774c54c6d.zip gitbook-cafbcd409774c383a26ce22b82b2104774c54c6d.tar.gz gitbook-cafbcd409774c383a26ce22b82b2104774c54c6d.tar.bz2 |
Complete normalization of summary with level and multiples parts
-rw-r--r-- | lib/backbone/summary.js | 103 | ||||
-rw-r--r-- | package.json | 4 | ||||
-rw-r--r-- | test/summary.js | 58 |
3 files changed, 135 insertions, 30 deletions
diff --git a/lib/backbone/summary.js b/lib/backbone/summary.js index 8e1a66d..d9253a7 100644 --- a/lib/backbone/summary.js +++ b/lib/backbone/summary.js @@ -20,7 +20,11 @@ function TOCArticle(def, parent) { // As string indicating the overall position // ex: '1.0.0' - this.level = def.level; + this.level; + + // When README has been automatically added + this.isAutoIntro = def.isAutoIntro; + this.isIntroduction = def.isIntroduction; if (!def.title) { throw error.ParsingError(new Error('SUMMARY entries should have an non-empty title')); @@ -41,10 +45,16 @@ function TOCArticle(def, parent) { } // Iterate over all articles in this articles -TOCArticle.prototype.walk = function(iter) { - _.each(this.articles, function(article) { - iter(article); - article.walk(iter); +TOCArticle.prototype.walk = function(iter, base) { + base = base || this.level; + + _.each(this.articles, function(article, i) { + var level = levelId(base, i); + + if (iter(article, level) === false) { + return false; + } + article.walk(iter, level); }); }; @@ -69,6 +79,11 @@ TOCArticle.prototype.isExternal = function() { return location.isExternal(this.ref); }; +// Return true if this article is the introduction +TOCArticle.prototype.isIntro = function() { + return Boolean(this.isIntroduction); +}; + // Return true if has children TOCArticle.prototype.hasChildren = function() { return this.articles.length > 0; @@ -147,19 +162,37 @@ TOCArticle.prototype.map = function(iter) { A part of a ToC is a composed of a tree of articles. */ function TOCPart(part) { + if (!(this instanceof TOCPart)) return new TOCPart(part); + this.articles = _.map(part.articles || part.chapters, function(article) { return new TOCArticle(article, this); }, this); } // Iterate over all entries of the part -TOCPart.prototype.walk = function(iter) { - _.each(this.articles, function(article) { - if (iter(article) === false) { +TOCPart.prototype.walk = function(iter, base) { + var articles = this.articles; + + if (articles.length == 0) return; + + // Has introduction? + if (articles[0].isIntro()) { + if (iter(articles[0], '0') === false) { + return; + } + + articles = articles.slice(1); + } + + + _.each(articles, function(article, i) { + var level = levelId(base, i); + + if (iter(article, level) === false) { return false; } - article.walk(iter); + article.walk(iter, level); }); }; @@ -187,15 +220,27 @@ Summary.prototype.parse = function(content) { return this.parser.summary(content) - // TODO: update GitBook's parsers to return a list of parts - .then(function(part) { - that.parts = [new TOCPart(part)]; + .then(function(summary) { + that.parts = _.map(summary.parts, TOCPart); + + // Create first part if none + if (that.parts.length == 0) { + that.parts.push(new TOCPart([])); + } - // Update count of articles - that._length = 0; - that.walk(function() { - that._length += 1; - }); + // Add README as first entry + var firstArticle = that.parts[0].articles[0]; + if (!firstArticle || firstArticle.path != that.book.readme.path) { + that.parts[0].articles.unshift(new TOCArticle({ + title: 'Introduction', + path: that.book.readme.path, + isAutoIntro: true + }, that.parts[0])); + } + that.parts[0].articles[0].isIntroduction = true; + + // Update count of articles and create "level" + that.update(); }); }; @@ -224,8 +269,10 @@ Summary.prototype.getContext = function() { // Iterate over all entries of the summary // iter is called with an TOCArticle Summary.prototype.walk = function(iter) { - _.each(this.parts, function(part) { - part.walk(iter); + var hasMultipleParts = this.parts.length > 1; + + _.each(this.parts, function(part, i) { + part.walk(iter, hasMultipleParts? levelId('', i) : null); }); }; @@ -264,4 +311,22 @@ Summary.prototype.count = function() { return this._length; }; +// Update the count and indexing of "level" +Summary.prototype.update = function() { + var that = this; + + that._length = 0; + that.walk(function(article, level) { + article.level = level; + that._length += 1; + }); +}; + + +// Return a level string from a base level and an index +function levelId(base, i) { + i = i + 1; + return (base? [base || '', i] : [i]).join('.'); +} + module.exports = Summary; diff --git a/package.json b/package.json index 7163f15..6b923b9 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,8 @@ "resolve": "0.6.3", "mkdirp": "0.5.1", "error": "7.0.2", - "gitbook-markdown": "1.0.0", - "gitbook-asciidoc": "1.0.0", + "gitbook-markdown": "1.0.2", + "gitbook-asciidoc": "1.0.1", "gitbook-plugin-highlight": "1.0.3", "gitbook-plugin-sharing": "1.0.1", "gitbook-plugin-search": "1.1.0", diff --git a/test/summary.js b/test/summary.js index a9aea5d..8805c2d 100644 --- a/test/summary.js +++ b/test/summary.js @@ -2,18 +2,32 @@ var should = require('should'); var mock = require('./mock'); +function mockSummary(files, summary) { + return mock.setupDefaultBook(files, summary) + .then(function(book) { + return book.readme.load() + .then(function() { + return book.summary.load(); + }) + .thenResolve(book); + }); +} + describe('Summary / Table of contents', function() { describe('Empty summary list', function() { var book; before(function() { - return mock.setupDefaultBook({}) + return mockSummary({}) .then(function(_book) { book = _book; - return book.summary.load(); }); }); + it('should add README as first entry', function() { + should(book.summary.getArticle('README.md')).be.ok(); + }); + it('should correctly count articles', function() { book.summary.count().should.equal(1); }); @@ -23,14 +37,13 @@ describe('Summary / Table of contents', function() { var book; before(function() { - return mock.setupDefaultBook({ + return mockSummary({ 'SUMMARY.md': '# Summary\n\n' + '* [Hello](./hello.md)\n' + '* [World](./world.md)\n\n' }) .then(function(_book) { book = _book; - return book.summary.load(); }); }); @@ -39,11 +52,40 @@ describe('Summary / Table of contents', function() { }); }); + describe('Levels', function() { + var book; + + before(function() { + return mockSummary({ + 'SUMMARY.md': '# Summary\n\n' + + '* [Hello](./hello.md)\n' + + ' * [Hello 2](./hello2.md)\n' + + '* [World](./world.md)\n\n' + + '## Part 2\n\n' + + '* [Hello 3](./hello.md)\n' + + ' * [Hello 4](./hello2.md)\n' + }) + .then(function(_book) { + book = _book; + }); + }); + + it('should correctly index levels', function() { + book.summary.getArticleByLevel('0').title.should.equal('Introduction'); + book.summary.getArticleByLevel('1.1').title.should.equal('Hello'); + book.summary.getArticleByLevel('1.1.1').title.should.equal('Hello 2'); + book.summary.getArticleByLevel('1.2').title.should.equal('World'); + + book.summary.getArticleByLevel('2.1').title.should.equal('Hello 3'); + book.summary.getArticleByLevel('2.1.1').title.should.equal('Hello 4'); + }); + }); + describe('External', function() { var book; before(function() { - return mock.setupDefaultBook({}, [ + return mockSummary({}, [ { title: 'Google', path: 'https://www.google.fr' @@ -51,7 +93,6 @@ describe('Summary / Table of contents', function() { ]) .then(function(_book) { book = _book; - return book.summary.load(); }); }); @@ -66,7 +107,7 @@ describe('Summary / Table of contents', function() { should(article.path).not.be.ok(); article.title.should.equal('Google'); - article.ref.should.equal('https:/www.google.fr'); + article.ref.should.equal('https://www.google.fr'); article.isExternal().should.be.ok; }); }); @@ -75,7 +116,7 @@ describe('Summary / Table of contents', function() { var book; before(function() { - return mock.setupDefaultBook({ + return mockSummary({ 'SUMMARY.md': '# Summary\n\n' + '* [Hello](hello.md)\n' + '* [Hello 2](hello2.md)\n' + @@ -86,7 +127,6 @@ describe('Summary / Table of contents', function() { }) .then(function(_book) { book = _book; - return book.summary.load(); }); }); |