summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGES.md1
-rw-r--r--lib/models/parser.js4
-rw-r--r--lib/models/summary.js34
-rw-r--r--lib/modifiers/summary/__tests__/mergeAtLevel.js45
-rw-r--r--lib/modifiers/summary/__tests__/moveArticle.js68
-rw-r--r--lib/modifiers/summary/editArticleTitle.js4
-rw-r--r--lib/modifiers/summary/editPartTitle.js1
-rw-r--r--lib/modifiers/summary/index.js3
-rw-r--r--lib/modifiers/summary/insertArticle.js56
-rw-r--r--lib/modifiers/summary/mergeAtLevel.js (renamed from lib/modifiers/summary/editArticle.js)37
-rw-r--r--lib/modifiers/summary/moveArticle.js82
-rw-r--r--lib/modifiers/summary/removeArticle.js37
-rw-r--r--lib/modifiers/summary/unshiftArticle.js2
-rw-r--r--lib/output/__tests__/website.js9
-rw-r--r--lib/parse/parseIgnore.js3
-rw-r--r--package.json2
16 files changed, 327 insertions, 61 deletions
diff --git a/CHANGES.md b/CHANGES.md
index ba7f8fa..3c9deba 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -17,6 +17,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Fix `uk` translation
- Fix heading ID including dashes
- Fix error in code highlighting for unknown languages
+- Fix data-uri images being handled as external images
- Accept SSH url as plugin version
- Add templating blocks `markdown`, `asciidoc` and `markup`
- Better search experience
diff --git a/lib/models/parser.js b/lib/models/parser.js
index e776582..d28a4e2 100644
--- a/lib/models/parser.js
+++ b/lib/models/parser.js
@@ -43,6 +43,10 @@ Parser.prototype.parseGlossary = function(content) {
Parser.prototype.preparePage = function(content) {
var page = this.get('page');
+ if (!page.prepare) {
+ return Promise(content);
+ }
+
return Promise(page.prepare(content));
};
diff --git a/lib/models/summary.js b/lib/models/summary.js
index ec7e05f..8a4afc7 100644
--- a/lib/models/summary.js
+++ b/lib/models/summary.js
@@ -56,7 +56,7 @@ Summary.prototype.getArticle = function(iter, partIter) {
Return a part/article by its level
@param {String} level
- @return {Article}
+ @return {Article|Part}
*/
Summary.prototype.getByLevel = function(level) {
function iterByLevel(article) {
@@ -130,6 +130,27 @@ Summary.prototype.getPrevArticle = function(current) {
};
/**
+ Return the parent article, or parent part of an article
+
+ @param {String|Article} current
+ @return {Article|Part|Null}
+*/
+Summary.prototype.getParent = function (level) {
+ // Coerce to level
+ level = is.string(level)? level : level.getLevel();
+
+ // Get parent level
+ var parentLevel = getParentLevel(level);
+ if (!parentLevel) {
+ return null;
+ }
+
+ // Get parent of the position
+ var parentArticle = this.getByLevel(parentLevel);
+ return parentArticle || null;
+};
+
+/**
Render summary as text
@param {String} parseExt Extension of the parser to use
@@ -188,4 +209,15 @@ Summary.createFromParts = function createFromParts(file, parts) {
});
};
+/**
+ Returns parent level of a level
+
+ @param {String} level
+ @return {String}
+*/
+function getParentLevel(level) {
+ var parts = level.split('.');
+ return parts.slice(0, -1).join('.');
+}
+
module.exports = Summary;
diff --git a/lib/modifiers/summary/__tests__/mergeAtLevel.js b/lib/modifiers/summary/__tests__/mergeAtLevel.js
new file mode 100644
index 0000000..e2635ec
--- /dev/null
+++ b/lib/modifiers/summary/__tests__/mergeAtLevel.js
@@ -0,0 +1,45 @@
+var Immutable = require('immutable');
+var Summary = require('../../../models/summary');
+var File = require('../../../models/file');
+
+describe('mergeAtLevel', function() {
+ var mergeAtLevel = require('../mergeAtLevel');
+ var summary = Summary.createFromParts(File(), [
+ {
+ articles: [
+ {
+ title: '1.1',
+ path: '1.1'
+ },
+ {
+ title: '1.2',
+ path: '1.2'
+ }
+ ]
+ },
+ {
+ title: 'Part I',
+ articles: []
+ }
+ ]);
+
+ it('should edit a part', function() {
+ var beforeChildren = summary.getByLevel('1').getArticles();
+ var newSummary = mergeAtLevel(summary, '1', {title: 'Part O'});
+ var edited = newSummary.getByLevel('1');
+
+ expect(edited.getTitle()).toBe('Part O');
+ // Same children
+ expect(Immutable.is(beforeChildren, edited.getArticles())).toBe(true);
+ });
+
+ it('should edit a part', function() {
+ var beforePath = summary.getByLevel('1.2').getPath();
+ var newSummary = mergeAtLevel(summary, '1.2', {title: 'Renamed article'});
+ var edited = newSummary.getByLevel('1.2');
+
+ expect(edited.getTitle()).toBe('Renamed article');
+ // Same children
+ expect(Immutable.is(beforePath, edited.getPath())).toBe(true);
+ });
+});
diff --git a/lib/modifiers/summary/__tests__/moveArticle.js b/lib/modifiers/summary/__tests__/moveArticle.js
new file mode 100644
index 0000000..9a101f6
--- /dev/null
+++ b/lib/modifiers/summary/__tests__/moveArticle.js
@@ -0,0 +1,68 @@
+var Immutable = require('immutable');
+var Summary = require('../../../models/summary');
+var File = require('../../../models/file');
+
+describe('moveArticle', function() {
+ var moveArticle = require('../moveArticle');
+ var summary = Summary.createFromParts(File(), [
+ {
+ articles: [
+ {
+ title: '1.1',
+ path: '1.1'
+ },
+ {
+ title: '1.2',
+ path: '1.2'
+ }
+ ]
+ },
+ {
+ title: 'Part I',
+ articles: [
+ {
+ title: '2.1',
+ path: '2.1',
+ articles: [
+ {
+ title: '2.1.1',
+ path: '2.1.1'
+ },
+ {
+ title: '2.1.2',
+ path: '2.1.2'
+ }
+ ]
+ },
+ {
+ title: '2.2',
+ path: '2.2'
+ }
+ ]
+ }
+ ]);
+
+ it('should move an article at in place', function() {
+ var newSummary = moveArticle(summary, '2.1', '2.1');
+
+ expect(Immutable.is(summary, newSummary)).toBe(true);
+ });
+
+ it('should move an article to an previous level', function() {
+ var newSummary = moveArticle(summary, '2.2', '2.1');
+ var moved = newSummary.getByLevel('2.1');
+ var other = newSummary.getByLevel('2.2');
+
+ expect(moved.getTitle()).toBe('2.2');
+ expect(other.getTitle()).toBe('2.1');
+ });
+
+ it('should move an article to a next level', function() {
+ var newSummary = moveArticle(summary, '2.1', '2.2');
+ var moved = newSummary.getByLevel('2.1');
+ var other = newSummary.getByLevel('2.2');
+
+ expect(moved.getTitle()).toBe('2.2');
+ expect(other.getTitle()).toBe('2.1');
+ });
+});
diff --git a/lib/modifiers/summary/editArticleTitle.js b/lib/modifiers/summary/editArticleTitle.js
index bd9b6f2..4edee83 100644
--- a/lib/modifiers/summary/editArticleTitle.js
+++ b/lib/modifiers/summary/editArticleTitle.js
@@ -1,4 +1,4 @@
-var editArticle = require('./editArticle');
+var mergeAtLevel = require('./mergeAtLevel');
/**
Edit title of an article
@@ -9,7 +9,7 @@ var editArticle = require('./editArticle');
@return {Summary}
*/
function editArticleTitle(summary, level, newTitle) {
- return editArticle(summary, level, {
+ return mergeAtLevel(summary, level, {
title: newTitle
});
}
diff --git a/lib/modifiers/summary/editPartTitle.js b/lib/modifiers/summary/editPartTitle.js
index 472399b..b79ac1e 100644
--- a/lib/modifiers/summary/editPartTitle.js
+++ b/lib/modifiers/summary/editPartTitle.js
@@ -1,4 +1,3 @@
-
/**
Edit title of a part in the summary
diff --git a/lib/modifiers/summary/index.js b/lib/modifiers/summary/index.js
index 855d7cc..4498287 100644
--- a/lib/modifiers/summary/index.js
+++ b/lib/modifiers/summary/index.js
@@ -1,6 +1,7 @@
-
module.exports = {
insertArticle: require('./insertArticle'),
+ moveArticle: require('./moveArticle'),
+ removeArticle: require('./removeArticle'),
unshiftArticle: require('./unshiftArticle'),
editPartTitle: require('./editPartTitle'),
diff --git a/lib/modifiers/summary/insertArticle.js b/lib/modifiers/summary/insertArticle.js
index ae920c2..849f39e 100644
--- a/lib/modifiers/summary/insertArticle.js
+++ b/lib/modifiers/summary/insertArticle.js
@@ -1,25 +1,14 @@
var is = require('is');
var SummaryArticle = require('../../models/summaryArticle');
-var editArticle = require('./editArticle');
+var mergeAtLevel = require('./mergeAtLevel');
var indexArticleLevels = require('./indexArticleLevels');
-
-/**
- Get level of parent of an article
-
- @param {String} level
- @return {String}
-*/
-function getParentLevel(level) {
- var parts = level.split('.');
- return parts.slice(0, -1).join('.');
-}
-
/**
- Insert an article in a summary at a specific position
+ Returns a new Summary with the article at the given level, with
+ subsequent article shifted.
@param {Summary} summary
- @param {String|Article} level: level to insert after
+ @param {String|Article} level: level to insert at
@param {Article} article
@return {Summary}
*/
@@ -27,37 +16,34 @@ function insertArticle(summary, level, article) {
article = SummaryArticle(article);
level = is.string(level)? level : level.getLevel();
- var parentLevel = getParentLevel(level);
-
- if (!parentLevel) {
- // todo: insert new part
- return summary;
- }
-
- // Get parent of the position
- var parentArticle = summary.getByLevel(parentLevel);
- if (!parentLevel) {
+ var parent = summary.getParent(level);
+ if (!parent) {
return summary;
}
// Find the index to insert at
- var articles = parentArticle.getArticles();
- var index = articles.findIndex(function(art) {
- return art.getLevel() === level;
- });
- if (!index) {
- return summary;
- }
+ var articles = parent.getArticles();
+ var index = getLeafIndex(level);
// Insert the article at the right index
articles = articles.insert(index, article);
// Reindex the level from here
- parentArticle = parentArticle.set('articles', articles);
- parentArticle = indexArticleLevels(parentArticle);
+ parent = parent.set('articles', articles);
+ parent = indexArticleLevels(parent);
- return editArticle(summary, parentLevel, parentArticle);
+ return mergeAtLevel(summary, parent.getLevel(), parent);
+}
+/**
+ @param {String}
+ @return {Number} The index of this level within its parent's children
+ */
+function getLeafIndex(level) {
+ var arr = level.split('.').map(function (char) {
+ return parseInt(char, 10);
+ });
+ return arr[arr.length - 1] - 1;
}
module.exports = insertArticle;
diff --git a/lib/modifiers/summary/editArticle.js b/lib/modifiers/summary/mergeAtLevel.js
index 1625398..9a95ffc 100644
--- a/lib/modifiers/summary/editArticle.js
+++ b/lib/modifiers/summary/mergeAtLevel.js
@@ -11,16 +11,17 @@ function editArticleInList(articles, level, newArticle) {
return articles.map(function(article) {
var articleLevel = article.getLevel();
- if (articleLevel == level) {
+ if (articleLevel === level) {
+ // it is the article to edit
return article.merge(newArticle);
- }
-
- if (level.indexOf(articleLevel) === 0) {
+ } else if (level.indexOf(articleLevel) === 0) {
+ // it is a parent
var articles = editArticleInList(article.getArticles(), level, newArticle);
return article.set('articles', articles);
+ } else {
+ // This is not the article you are looking for
+ return article;
}
-
- return article;
});
}
@@ -35,36 +36,40 @@ function editArticleInList(articles, level, newArticle) {
*/
function editArticleInPart(part, level, newArticle) {
var articles = part.getArticles();
- articles = editArticleInList(articles);
+ articles = editArticleInList(articles, level, newArticle);
return part.set('articles', articles);
}
/**
- Edit an article in a summary
+ Edit an article, or a part, in a summary. Does a shallow merge.
@param {Summary} summary
@param {String} level
- @param {Article} newArticle
+ @param {Article|Part} newValue
@return {Summary}
*/
-function editArticle(summary, level, newArticle) {
- var parts = summary.getParts();
-
+function mergeAtLevel(summary, level, newValue) {
var levelParts = level.split('.');
- var partIndex = Number(levelParts[0]);
+ var partIndex = Number(levelParts[0]) -1;
+ var parts = summary.getParts();
var part = parts.get(partIndex);
if (!part) {
return summary;
}
- part = editArticleInPart(part, level, newArticle);
- parts = parts.set(partIndex, part);
+ var isEditingPart = levelParts.length < 2;
+ if (isEditingPart) {
+ part = part.merge(newValue);
+ } else {
+ part = editArticleInPart(part, level, newValue);
+ }
+ parts = parts.set(partIndex, part);
return summary.set('parts', parts);
}
-module.exports = editArticle;
+module.exports = mergeAtLevel;
diff --git a/lib/modifiers/summary/moveArticle.js b/lib/modifiers/summary/moveArticle.js
new file mode 100644
index 0000000..06d82ca
--- /dev/null
+++ b/lib/modifiers/summary/moveArticle.js
@@ -0,0 +1,82 @@
+var is = require('is');
+var removeArticle = require('./removeArticle');
+var insertArticle = require('./insertArticle');
+
+/**
+ Returns a new summary, with the given article removed from its
+ origin level, and placed at the given target level.
+
+ @param {Summary} summary
+ @param {String|SummaryArticle} origin: level to remove
+ @param {String|SummaryArticle} target: the level where the article will be found
+ @return {Summary}
+*/
+function moveArticle(summary, origin, target) {
+ // Coerce to level
+ var originLevel = is.string(origin)? origin : origin.getLevel();
+ var targetLevel = is.string(target)? target : target.getLevel();
+
+ var article = summary.getByLevel(originLevel);
+
+ // Remove
+ var removed = removeArticle(summary, origin);
+
+ // Adjust targetLevel if removing impacted it
+ targetLevel = arrayToLevel(
+ shiftLevel(levelToArray(originLevel),
+ levelToArray(targetLevel)));
+ // Re-insert
+ return insertArticle(removed, target, article);
+}
+
+/**
+ @param {Array<Number>} removedLevel
+ @param {Array<Number>} level The level to udpate
+ @return {Array<Number>}
+ */
+function shiftLevel(removedLevel, level) {
+ if (level.length === 0) {
+ // `removedLevel` is under level, so no effect
+ return level;
+ } else if (removedLevel.length === 0) {
+ // Either `level` is a child of `removedLevel`... or they are equal
+ // This is undefined behavior.
+ return level;
+ }
+
+ var removedRoot = removedLevel[0];
+ var root = level[0];
+ var removedRest = removedLevel.slice(1);
+ var rest = level.slice(1);
+
+ if (removedRoot < root) {
+ // It will shift levels at this point. The rest is unchanged.
+ return Array.prototype.concat(root - 1, rest);
+ } else if (removedRoot === root) {
+ // Look deeper
+ return Array.prototype.concat(root, shiftLevel(removedRest, rest));
+ } else {
+ // No impact
+ return level;
+ }
+}
+
+/**
+ @param {String}
+ @return {Array<Number>}
+ */
+function levelToArray(l) {
+ return l.split('.').map(function (char) {
+ return parseInt(char, 10);
+ });
+}
+
+/**
+ @param {Array<Number>}
+ @return {String}
+ */
+function arrayToLevel(a) {
+ return a.join('.');
+}
+
+module.exports = moveArticle;
diff --git a/lib/modifiers/summary/removeArticle.js b/lib/modifiers/summary/removeArticle.js
new file mode 100644
index 0000000..8a30d0a
--- /dev/null
+++ b/lib/modifiers/summary/removeArticle.js
@@ -0,0 +1,37 @@
+var is = require('is');
+var mergeAtLevel = require('./mergeAtLevel');
+var indexArticleLevels = require('./indexArticleLevels');
+
+/**
+ Remove an article from a level.
+
+ @param {Summary} summary
+ @param {String|SummaryArticle} level: level to remove
+ @return {Summary}
+*/
+function removeArticle(summary, level) {
+ // Coerce to level
+ level = is.string(level)? level : level.getLevel();
+
+ var parent = summary.getParent(level);
+
+ var articles = parent.getArticles();
+ // Find the index to remove
+ var index = articles.findIndex(function(art) {
+ return art.getLevel() === level;
+ });
+ if (index === -1) {
+ return summary;
+ }
+
+ // Remove from children
+ articles = articles.remove(index);
+ parent = parent.set('articles', articles);
+
+ // Reindex the level from here
+ parent = indexArticleLevels(parent);
+
+ return mergeAtLevel(summary, parent.getLevel(), parent);
+}
+
+module.exports = removeArticle;
diff --git a/lib/modifiers/summary/unshiftArticle.js b/lib/modifiers/summary/unshiftArticle.js
index 3f2ae4d..d1ebc05 100644
--- a/lib/modifiers/summary/unshiftArticle.js
+++ b/lib/modifiers/summary/unshiftArticle.js
@@ -4,7 +4,7 @@ var SummaryPart = require('../../models/summaryPart');
var indexLevels = require('./indexLevels');
/**
- Insert an article at the
+ Insert an article at the beginning of summary
@param {Summary} summary
@param {Article} article
diff --git a/lib/output/__tests__/website.js b/lib/output/__tests__/website.js
index 6b949a4..f9fcdae 100644
--- a/lib/output/__tests__/website.js
+++ b/lib/output/__tests__/website.js
@@ -12,6 +12,15 @@ describe('WebsiteGenerator', function() {
});
});
+ pit('should generate an index.html for AsciiDoc', function() {
+ return generateMock(WebsiteGenerator, {
+ 'README.adoc': 'Hello World'
+ })
+ .then(function(folder) {
+ expect(folder).toHaveFile('index.html');
+ });
+ });
+
pit('should generate an HTML file for each articles', function() {
return generateMock(WebsiteGenerator, {
'README.md': 'Hello World',
diff --git a/lib/parse/parseIgnore.js b/lib/parse/parseIgnore.js
index b23bfd8..fafcc6f 100644
--- a/lib/parse/parseIgnore.js
+++ b/lib/parse/parseIgnore.js
@@ -27,9 +27,6 @@ function parseIgnore(book) {
// Skip book outputs
'_book',
- '*.pdf',
- '*.epub',
- '*.mobi',
// Ignore files in the templates folder
'_layouts'
diff --git a/package.json b/package.json
index f72b523..4dd61dd 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "gitbook",
- "version": "3.0.0-pre.10",
+ "version": "3.0.0-pre.11",
"homepage": "https://www.gitbook.com",
"description": "Library and cmd utility to generate GitBooks",
"main": "lib/index.js",