diff options
author | Samy Pessé <samypesse@gmail.com> | 2016-02-21 11:56:14 +0100 |
---|---|---|
committer | Samy Pessé <samypesse@gmail.com> | 2016-02-21 11:56:14 +0100 |
commit | 884540e56530b8e1c68c94604c0b45f0489d5020 (patch) | |
tree | 13f58c99828c1745497e889b516795a99562803a | |
parent | ca1313e891f7cfbdffaf6a47bb75a8bc1d77c1a4 (diff) | |
download | gitbook-884540e56530b8e1c68c94604c0b45f0489d5020.zip gitbook-884540e56530b8e1c68c94604c0b45f0489d5020.tar.gz gitbook-884540e56530b8e1c68c94604c0b45f0489d5020.tar.bz2 |
Fix .next and .prev for summary's articles to use parts
-rw-r--r-- | lib/backbone/summary.js | 119 | ||||
-rw-r--r-- | test/summary.js | 37 |
2 files changed, 122 insertions, 34 deletions
diff --git a/lib/backbone/summary.js b/lib/backbone/summary.js index f3994ca..5cc1418 100644 --- a/lib/backbone/summary.js +++ b/lib/backbone/summary.js @@ -8,8 +8,9 @@ var BackboneFile = require('./file'); /* -An article represent an entry in the Summary. -It's defined by a title, a reference, and children articles, the reference (ref) can be a filename + anchor or an external file (optional) + An article represent an entry in the Summary. + It's defined by a title, a reference, and children articles, + the reference (ref) can be a filename + anchor or an external file (optional) */ function TOCArticle(def, parent) { // Title @@ -26,16 +27,17 @@ function TOCArticle(def, parent) { this.isAutoIntro = def.isAutoIntro; this.isIntroduction = def.isIntroduction; - if (!def.title) { - throw error.ParsingError(new Error('SUMMARY entries should have an non-empty title')); - } + this.validate(); - var parts = url.parse(def.path); + // Path can be a relative path or an url, or nothing this.ref = def.path; + if (this.ref) { + var parts = url.parse(this.ref); - if (!this.isExternal()) { - this.path = parts.pathname; - this.anchor = parts.hash; + if (!this.isExternal()) { + this.path = parts.pathname; + this.anchor = parts.hash; + } } this.articles = _.map(def.articles || [], function(article) { @@ -44,6 +46,13 @@ function TOCArticle(def, parent) { }, this); } +// Validate the article +TOCArticle.prototype.validate = function() { + if (!this.title) { + throw error.ParsingError(new Error('SUMMARY entries should have an non-empty title')); + } +}; + // Iterate over all articles in this articles TOCArticle.prototype.walk = function(iter, base) { base = base || this.level; @@ -91,11 +100,29 @@ TOCArticle.prototype.hasChildren = function() { // Return true if has an article as parent TOCArticle.prototype.hasParent = function() { - return (this.parent instanceof TOCArticle); + return !(this.parent instanceof TOCPart); +}; + +// Return true if has a part as parent +TOCArticle.prototype.hasParentPart = function() { + return (this.parent instanceof TOCPart); +}; + +// Return first article +TOCArticle.prototype.first = function() { + return _.first(this.articles); +}; + +// Return last article +TOCArticle.prototype.last = function() { + var last = _.last(this.articles); + if (!last) return null; + + return last.last() || last; }; // Return a sibling (next or prev) in the parent -// Withotu taking in consideration children/parent +// Without taking in consideration children/parent TOCArticle.prototype.sibling = function(direction) { var parentsArticles = this.parent.articles; var pos = _.findIndex(parentsArticles, this); @@ -115,17 +142,28 @@ TOCArticle.prototype._sibling = function(direction) { return _.first(this.articles); } + var part; var parentsArticles = this.parent.articles; var pos = _.findIndex(parentsArticles, this); // First child and has parent - if (pos == 0 && direction < 0 && this.hasParent()) { - return this.parent; + if (pos == 0 && direction < 0) { + if (this.hasParent()) { + return this.parent; + } else if (this.hasParentPart()) { + part = this.parent.sibling(-1); + return part? part.last() : null; + } } // Last child and has parent - if(pos == (parentsArticles.length - 1) && direction > 0 && this.hasParent()) { - return this.parent.sibling(1); + if(pos == (parentsArticles.length - 1) && direction > 0) { + if (this.hasParent()) { + return this.parent.sibling(1); + } else if (this.hasParentPart()) { + part = this.parent.sibling(1); + return part? part.first() : null; + } } if (parentsArticles[pos + direction]) { @@ -159,16 +197,31 @@ TOCArticle.prototype.map = function(iter) { /* -A part of a ToC is a composed of a tree of articles. + A part of a ToC is a composed of a tree of articles and an optiona title */ -function TOCPart(part) { +function TOCPart(part, summary) { if (!(this instanceof TOCPart)) return new TOCPart(part); - this.title = part.title; - this.articles = _.map(part.articles || part.chapters, function(article) { - return new TOCArticle(article, this); - }, this); + TOCArticle.apply(this, arguments); + + this.summary = summary; } +util.inherits(TOCPart, TOCArticle); + +// Validate the part +TOCPart.prototype.validate = function() { }; + +// Return a sibling (next or prev) of this part +TOCPart.prototype.sibling = function(direction) { + var parts = this.summary.parts; + var pos = _.findIndex(parts, this); + + if (parts[pos + direction]) { + return parts[pos + direction]; + } + + return null; +}; // Iterate over all entries of the part TOCPart.prototype.walk = function(iter, base) { @@ -197,9 +250,16 @@ TOCPart.prototype.walk = function(iter, base) { }); }; -// Map over all articles -TOCPart.prototype.map = function(iter) { - return _.map(this.articles, iter); +// Return templating context for a part +TOCPart.prototype.getContext = function(onArticle) { + onArticle = onArticle || function(article) { + return article.getContext(); + }; + + return { + title: this.title, + articles: this.map(onArticle) + }; }; /* @@ -222,11 +282,13 @@ Summary.prototype.parse = function(content) { return this.parser.summary(content) .then(function(summary) { - that.parts = _.map(summary.parts, TOCPart); + that.parts = _.map(summary.parts, function(part) { + return new TOCPart(part, that); + }); // Create first part if none if (that.parts.length == 0) { - that.parts.push(new TOCPart({})); + that.parts.push(new TOCPart({}, that)); } // Add README as first entry @@ -259,10 +321,7 @@ Summary.prototype.getContext = function() { return { summary: { parts: _.map(this.parts, function(part) { - return { - title: part.title, - articles: part.map(onArticle) - }; + return part.getContext(onArticle); }) } }; diff --git a/test/summary.js b/test/summary.js index 8805c2d..f7a975f 100644 --- a/test/summary.js +++ b/test/summary.js @@ -123,7 +123,10 @@ describe('Summary / Table of contents', function() { ' * [Hello 3](hello3.md)\n' + ' * [Hello 4](hello4.md)\n' + ' * [Hello 5](hello5.md)\n' + - '* [Hello 6](hello6.md)\n' + '* [Hello 6](hello6.md)\n\n\n' + + '### Part 2\n\n' + + '* [Hello 7](hello7.md)\n' + + '* [Hello 8](hello8.md)\n\n' }) .then(function(_book) { book = _book; @@ -136,7 +139,7 @@ describe('Summary / Table of contents', function() { var prev = article.prev(); var next = article.next(); - should(prev).equal(null); + should(prev).not.be.ok(); should(next).be.ok(); next.path.should.equal('hello.md'); @@ -207,16 +210,42 @@ describe('Summary / Table of contents', function() { next.path.should.equal('hello6.md'); }); - it('should return prev for last', function() { + it('should return next/prev for a joint <- parts', function() { + var article = book.summary.getArticle('hello7.md'); + + var prev = article.prev(); + var next = article.next(); + + should(prev).be.ok(); + should(next).be.ok(); + + prev.path.should.equal('hello6.md'); + next.path.should.equal('hello8.md'); + }); + + it('should return next/prev for a joint -> parts', function() { var article = book.summary.getArticle('hello6.md'); var prev = article.prev(); var next = article.next(); should(prev).be.ok(); - should(next).be.not.ok(); + should(next).be.ok(); prev.path.should.equal('hello5.md'); + next.path.should.equal('hello7.md'); + }); + + it('should return only prev for last', function() { + var article = book.summary.getArticle('hello8.md'); + + var prev = article.prev(); + var next = article.next(); + + should(prev).be.ok(); + should(next).be.not.ok(); + + prev.path.should.equal('hello7.md'); }); }); }); |