summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/backbone/summary.js73
-rw-r--r--test/git.js6
-rw-r--r--test/parse.js4
-rw-r--r--test/summary.js143
4 files changed, 200 insertions, 26 deletions
diff --git a/lib/backbone/summary.js b/lib/backbone/summary.js
index 0d1d0d7..8e1a66d 100644
--- a/lib/backbone/summary.js
+++ b/lib/backbone/summary.js
@@ -79,38 +79,62 @@ TOCArticle.prototype.hasParent = function() {
return (this.parent instanceof TOCArticle);
};
-// Return next article in the TOC
-TOCArticle.prototype.next = function() {
+// Return a sibling (next or prev) in the parent
+// Withotu taking in consideration children/parent
+TOCArticle.prototype.sibling = function(direction) {
var parentsArticles = this.parent.articles;
var pos = _.findIndex(parentsArticles, this);
- if ((pos + 1) >= parentsArticles.length) {
- if (this.hasParent()) {
- return this.parent.next();
- } else {
- return null;
- }
- } else {
- // next has the same parent
- return parentsArticles[pos + 1];
+ if (parentsArticles[pos + direction]) {
+ return parentsArticles[pos + direction];
}
+
+ return null;
};
-// Return previous article in the TOC
-TOCArticle.prototype.prev = function() {
+// Return a sibling (next or prev)
+// It takes parents.children in consideration
+TOCArticle.prototype._sibling = function(direction) {
+ // Next should go to the first children
+ if (direction > 0 && this.hasChildren()) {
+ return _.first(this.articles);
+ }
+
var parentsArticles = this.parent.articles;
var pos = _.findIndex(parentsArticles, this);
- if ((pos - 1) < 0) {
- if (this.hasParent()) {
- return this.parent.prev();
- } else {
- return null;
+ // First child and has parent
+ if (pos == 0 && direction < 0 && this.hasParent()) {
+ return this.parent;
+ }
+
+ // Last child and has parent
+ if(pos == (parentsArticles.length - 1) && direction > 0 && this.hasParent()) {
+ return this.parent.sibling(1);
+ }
+
+ if (parentsArticles[pos + direction]) {
+ var article = parentsArticles[pos + direction];
+
+ // If goign back, take last children from "brother"
+ if (direction < 0 && article.hasChildren()) {
+ article = _.last(article.articles);
}
- } else {
- // prev has the same parent
- return parentsArticles[pos - 1];
+
+ return article;
}
+
+ return null;
+};
+
+// Return next article in the TOC
+TOCArticle.prototype.next = function() {
+ return this._sibling(1);
+};
+
+// Return previous article in the TOC
+TOCArticle.prototype.prev = function() {
+ return this._sibling(-1);
};
// Map over all articles
@@ -228,6 +252,13 @@ Summary.prototype.getArticle = function(page) {
});
};
+// Return the first TOCArticle for a specific level
+Summary.prototype.getArticleByLevel = function(lvl) {
+ return this.find(function(article) {
+ return article.level == lvl;
+ });
+};
+
// Return the count of articles in the summary
Summary.prototype.count = function() {
return this._length;
diff --git a/test/git.js b/test/git.js
index 8667b07..9fd7490 100644
--- a/test/git.js
+++ b/test/git.js
@@ -10,14 +10,14 @@ describe('Git', function() {
it('should correctly validate git urls', function() {
// HTTPS
- Git.isUrl('git+https://github.com/Hello/world.git').should.be.ok;
+ Git.isUrl('git+https://github.com/Hello/world.git').should.be.ok();
// SSH
Git.isUrl('git+git@github.com:GitbookIO/gitbook.git/directory/README.md#e1594cde2c32e4ff48f6c4eff3d3d461743d74e1').should.be.ok;
// Non valid
- Git.isUrl('https://github.com/Hello/world.git').should.not.be.ok;
- Git.isUrl('README.md').should.not.be.ok;
+ Git.isUrl('https://github.com/Hello/world.git').should.not.be.ok();
+ Git.isUrl('README.md').should.not.be.ok();
});
it('should parse HTTPS urls', function() {
diff --git a/test/parse.js b/test/parse.js
index e190107..63565ee 100644
--- a/test/parse.js
+++ b/test/parse.js
@@ -1,12 +1,12 @@
var mock = require('./mock');
describe('Parsing', function() {
- it('should fail without SUMMARY', function() {
+ it('should not fail without SUMMARY', function() {
return mock.setupBook({
'README.md': ''
})
.then(function(book) {
- return book.parse().should.be.rejected;
+ return book.parse().should.be.fulfilled();
});
});
diff --git a/test/summary.js b/test/summary.js
index 2744c43..a9aea5d 100644
--- a/test/summary.js
+++ b/test/summary.js
@@ -1,3 +1,5 @@
+var should = require('should');
+
var mock = require('./mock');
describe('Summary / Table of contents', function() {
@@ -36,5 +38,146 @@ describe('Summary / Table of contents', function() {
book.summary.count().should.equal(3);
});
});
+
+ describe('External', function() {
+ var book;
+
+ before(function() {
+ return mock.setupDefaultBook({}, [
+ {
+ title: 'Google',
+ path: 'https://www.google.fr'
+ }
+ ])
+ .then(function(_book) {
+ book = _book;
+ return book.summary.load();
+ });
+ });
+
+ it('should correctly count articles', function() {
+ book.summary.count().should.equal(2);
+ });
+
+ it('should correctly signal it as external', function() {
+ var article = book.summary.getArticleByLevel('1');
+
+ should(article).be.ok();
+ should(article.path).not.be.ok();
+
+ article.title.should.equal('Google');
+ article.ref.should.equal('https:/www.google.fr');
+ article.isExternal().should.be.ok;
+ });
+ });
+
+ describe('Next / Previous', function() {
+ var book;
+
+ before(function() {
+ return mock.setupDefaultBook({
+ 'SUMMARY.md': '# Summary\n\n' +
+ '* [Hello](hello.md)\n' +
+ '* [Hello 2](hello2.md)\n' +
+ ' * [Hello 3](hello3.md)\n' +
+ ' * [Hello 4](hello4.md)\n' +
+ ' * [Hello 5](hello5.md)\n' +
+ '* [Hello 6](hello6.md)\n'
+ })
+ .then(function(_book) {
+ book = _book;
+ return book.summary.load();
+ });
+ });
+
+ it('should only return a next for the readme', function() {
+ var article = book.summary.getArticle('README.md');
+
+ var prev = article.prev();
+ var next = article.next();
+
+ should(prev).equal(null);
+ should(next).be.ok();
+
+ next.path.should.equal('hello.md');
+ });
+
+ it('should return next/prev for a first level page', function() {
+ var article = book.summary.getArticle('hello.md');
+
+ var prev = article.prev();
+ var next = article.next();
+
+ should(prev).be.ok();
+ should(next).be.ok();
+
+ prev.path.should.equal('README.md');
+ next.path.should.equal('hello2.md');
+ });
+
+ it('should return next/prev for a joint -> child', function() {
+ var article = book.summary.getArticle('hello2.md');
+
+ var prev = article.prev();
+ var next = article.next();
+
+ should(prev).be.ok();
+ should(next).be.ok();
+
+ prev.path.should.equal('hello.md');
+ next.path.should.equal('hello3.md');
+ });
+
+ it('should return next/prev for a joint <- child', function() {
+ var article = book.summary.getArticle('hello3.md');
+
+ var prev = article.prev();
+ var next = article.next();
+
+ should(prev).be.ok();
+ should(next).be.ok();
+
+ prev.path.should.equal('hello2.md');
+ next.path.should.equal('hello4.md');
+ });
+
+ it('should return next/prev for a children', function() {
+ var article = book.summary.getArticle('hello4.md');
+
+ var prev = article.prev();
+ var next = article.next();
+
+ should(prev).be.ok();
+ should(next).be.ok();
+
+ prev.path.should.equal('hello3.md');
+ next.path.should.equal('hello5.md');
+ });
+
+ it('should return next/prev for a joint -> parent', function() {
+ var article = book.summary.getArticle('hello5.md');
+
+ var prev = article.prev();
+ var next = article.next();
+
+ should(prev).be.ok();
+ should(next).be.ok();
+
+ prev.path.should.equal('hello4.md');
+ next.path.should.equal('hello6.md');
+ });
+
+ it('should return prev for last', 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();
+
+ prev.path.should.equal('hello5.md');
+ });
+ });
});