diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/models/summaryArticle.js | 1 | ||||
-rw-r--r-- | lib/modifiers/summary/__tests__/insertArticle.js | 78 | ||||
-rw-r--r-- | lib/modifiers/summary/__tests__/moveArticle.js | 2 | ||||
-rw-r--r-- | lib/modifiers/summary/__tests__/moveArticleAfter.js | 82 | ||||
-rw-r--r-- | lib/modifiers/summary/__tests__/removeArticle.js | 54 | ||||
-rw-r--r-- | lib/modifiers/summary/editArticleRef.js | 17 | ||||
-rw-r--r-- | lib/modifiers/summary/index.js | 8 | ||||
-rw-r--r-- | lib/modifiers/summary/insertArticle.js | 4 | ||||
-rw-r--r-- | lib/modifiers/summary/insertPart.js | 19 | ||||
-rw-r--r-- | lib/modifiers/summary/moveArticle.js | 63 | ||||
-rw-r--r-- | lib/modifiers/summary/moveArticleAfter.js | 60 | ||||
-rw-r--r-- | lib/modifiers/summary/removePart.js | 15 |
12 files changed, 337 insertions, 66 deletions
diff --git a/lib/models/summaryArticle.js b/lib/models/summaryArticle.js index 08baac3..f072e7b 100644 --- a/lib/models/summaryArticle.js +++ b/lib/models/summaryArticle.js @@ -54,7 +54,6 @@ SummaryArticle.prototype.getPath = function() { return undefined; } - var parts = ref.split('#'); var pathname = (parts.length > 1? parts.slice(0, -1).join('#') : ref); diff --git a/lib/modifiers/summary/__tests__/insertArticle.js b/lib/modifiers/summary/__tests__/insertArticle.js new file mode 100644 index 0000000..1ee1c8a --- /dev/null +++ b/lib/modifiers/summary/__tests__/insertArticle.js @@ -0,0 +1,78 @@ +var Summary = require('../../../models/summary'); +var SummaryArticle = require('../../../models/summaryArticle'); +var File = require('../../../models/file'); + +describe('insertArticle', function() { + var insertArticle = require('../insertArticle'); + 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 insert an article at a given level', function() { + var article = SummaryArticle.create({ + title: 'Inserted' + }, 'fake.level'); + + var newSummary = insertArticle(summary, article, '2.1.1'); + + var inserted = newSummary.getByLevel('2.1.1'); + var nextOne = newSummary.getByLevel('2.1.2'); + + expect(inserted.getTitle()).toBe('Inserted'); + expect(inserted.getLevel()).toBe('2.1.1'); + + expect(nextOne.getTitle()).toBe('2.1.1'); + expect(nextOne.getLevel()).toBe('2.1.2'); + }); + + it('should insert an article in last position', function() { + var article = SummaryArticle.create({ + title: 'Inserted' + }, 'fake.level'); + + var newSummary = insertArticle(summary, article, '2.2'); + + var inserted = newSummary.getByLevel('2.2'); + var previousOne = newSummary.getByLevel('2.1'); + + expect(inserted.getTitle()).toBe('Inserted'); + expect(inserted.getLevel()).toBe('2.2'); + + expect(previousOne.getTitle()).toBe('2.1'); // Unchanged + expect(previousOne.getLevel()).toBe('2.1'); + }); +}); diff --git a/lib/modifiers/summary/__tests__/moveArticle.js b/lib/modifiers/summary/__tests__/moveArticle.js index 9a101f6..aed0b94 100644 --- a/lib/modifiers/summary/__tests__/moveArticle.js +++ b/lib/modifiers/summary/__tests__/moveArticle.js @@ -42,7 +42,7 @@ describe('moveArticle', function() { } ]); - it('should move an article at in place', function() { + it('should move an article to the same place', function() { var newSummary = moveArticle(summary, '2.1', '2.1'); expect(Immutable.is(summary, newSummary)).toBe(true); diff --git a/lib/modifiers/summary/__tests__/moveArticleAfter.js b/lib/modifiers/summary/__tests__/moveArticleAfter.js new file mode 100644 index 0000000..c380575 --- /dev/null +++ b/lib/modifiers/summary/__tests__/moveArticleAfter.js @@ -0,0 +1,82 @@ +var Immutable = require('immutable'); +var Summary = require('../../../models/summary'); +var File = require('../../../models/file'); + +describe('moveArticleAfter', function() { + var moveArticleAfter = require('../moveArticleAfter'); + 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('moving right after itself should be invariant', function() { + var newSummary = moveArticleAfter(summary, '2.1', '2.1'); + + expect(Immutable.is(summary, newSummary)).toBe(true); + }); + + it('moving after previous one should be invariant too', function() { + var newSummary = moveArticleAfter(summary, '2.1', '2.0'); + + expect(Immutable.is(summary, newSummary)).toBe(true); + }); + + it('should move an article after a previous level', function() { + var newSummary = moveArticleAfter(summary, '2.2', '2.0'); + var moved = newSummary.getByLevel('2.1'); + + expect(moved.getTitle()).toBe('2.2'); + expect(newSummary.getByLevel('2.2').getTitle()).toBe('2.1'); + }); + + it('should move an article after a previous and less deep level', function() { + var newSummary = moveArticleAfter(summary, '2.1.1', '2.0'); + var moved = newSummary.getByLevel('2.1'); + + expect(moved.getTitle()).toBe('2.1.1'); + expect(newSummary.getByLevel('2.2.1').getTitle()).toBe('2.1.2'); + expect(newSummary.getByLevel('2.2').getTitle()).toBe('2.1'); + }); + + it('should move an article after a next level', function() { + var newSummary = moveArticleAfter(summary, '2.1', '2.2'); + var moved = newSummary.getByLevel('2.2'); + + expect(moved.getTitle()).toBe('2.1'); + expect(newSummary.getByLevel('2.1').getTitle()).toBe('2.2'); + }); + +}); diff --git a/lib/modifiers/summary/__tests__/removeArticle.js b/lib/modifiers/summary/__tests__/removeArticle.js new file mode 100644 index 0000000..c961f14 --- /dev/null +++ b/lib/modifiers/summary/__tests__/removeArticle.js @@ -0,0 +1,54 @@ +var Summary = require('../../../models/summary'); +var SummaryArticle = require('../../../models/summaryArticle'); +var File = require('../../../models/file'); + +describe('removeArticle', function() { + var removeArticle = require('../removeArticle'); + 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 remove an article at a given level', function() { + var newSummary = removeArticle(summary, '2.1.1'); + + var removed = newSummary.getByLevel('2.1.1'); + var nextOne = newSummary.getByLevel('2.1.2'); + + expect(removed.getTitle()).toBe('2.1.2'); + expect(nextOne).toBe(null); + }); +}); diff --git a/lib/modifiers/summary/editArticleRef.js b/lib/modifiers/summary/editArticleRef.js new file mode 100644 index 0000000..7106960 --- /dev/null +++ b/lib/modifiers/summary/editArticleRef.js @@ -0,0 +1,17 @@ +var mergeAtLevel = require('./mergeAtLevel'); + +/** + Edit the ref of an article + + @param {Summary} summary + @param {String} level + @param {String} newRef + @return {Summary} +*/ +function editArticleRef(summary, level, newRef) { + return mergeAtLevel(summary, level, { + ref: newRef + }); +} + +module.exports = editArticleRef; diff --git a/lib/modifiers/summary/index.js b/lib/modifiers/summary/index.js index 4498287..f91fdb6 100644 --- a/lib/modifiers/summary/index.js +++ b/lib/modifiers/summary/index.js @@ -1,9 +1,13 @@ module.exports = { insertArticle: require('./insertArticle'), moveArticle: require('./moveArticle'), + moveArticleAfter: require('./moveArticleAfter'), removeArticle: require('./removeArticle'), unshiftArticle: require('./unshiftArticle'), + editArticleTitle: require('./editArticleTitle'), + editArticleRef: require('./editArticleRef'), - editPartTitle: require('./editPartTitle'), - editArticleTitle: require('./editArticleTitle') + insertPart: require('./insertPart'), + removePart: require('./removePart'), + editPartTitle: require('./editPartTitle') }; diff --git a/lib/modifiers/summary/insertArticle.js b/lib/modifiers/summary/insertArticle.js index 849f39e..3a084b3 100644 --- a/lib/modifiers/summary/insertArticle.js +++ b/lib/modifiers/summary/insertArticle.js @@ -8,11 +8,11 @@ var indexArticleLevels = require('./indexArticleLevels'); subsequent article shifted. @param {Summary} summary - @param {String|Article} level: level to insert at @param {Article} article + @param {String|Article} level: level to insert at @return {Summary} */ -function insertArticle(summary, level, article) { +function insertArticle(summary, article, level) { article = SummaryArticle(article); level = is.string(level)? level : level.getLevel(); diff --git a/lib/modifiers/summary/insertPart.js b/lib/modifiers/summary/insertPart.js new file mode 100644 index 0000000..199cba7 --- /dev/null +++ b/lib/modifiers/summary/insertPart.js @@ -0,0 +1,19 @@ +var SummaryPart = require('../../models/summaryPart'); +var indexLevels = require('./indexLevels'); + +/** + Returns a new Summary with a part inserted at given index + + @param {Summary} summary + @param {Part} part + @param {Number} index + @return {Summary} +*/ +function insertPart(summary, part, index) { + part = SummaryPart(part); + + var parts = summary.getParts().insert(index, part); + return indexLevels(summary.set('parts', parts)); +} + +module.exports = insertPart; diff --git a/lib/modifiers/summary/moveArticle.js b/lib/modifiers/summary/moveArticle.js index 06d82ca..5cb1868 100644 --- a/lib/modifiers/summary/moveArticle.js +++ b/lib/modifiers/summary/moveArticle.js @@ -15,68 +15,11 @@ 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('.'); + // Remove first + var removed = removeArticle(summary, originLevel); + return insertArticle(removed, article, targetLevel); } module.exports = moveArticle; diff --git a/lib/modifiers/summary/moveArticleAfter.js b/lib/modifiers/summary/moveArticleAfter.js new file mode 100644 index 0000000..e268f73 --- /dev/null +++ b/lib/modifiers/summary/moveArticleAfter.js @@ -0,0 +1,60 @@ +var is = require('is'); +var removeArticle = require('./removeArticle'); +var insertArticle = require('./insertArticle'); + +/** + Returns a new summary, with the an article moved after another + article. Unlike `moveArticle`, does not ensure that the article + will be found at the target's level plus one. + + @param {Summary} summary + @param {String|SummaryArticle} origin + @param {String|SummaryArticle} afterTarget + @return {Summary} +*/ +function moveArticleAfter(summary, origin, afterTarget) { + // Coerce to level + var originLevel = is.string(origin)? origin : origin.getLevel(); + var afterTargetLevel = is.string(afterTarget)? afterTarget : afterTarget.getLevel(); + var article = summary.getByLevel(originLevel); + + var targetLevel = increment(afterTargetLevel); + + if (targetLevel < origin) { + // Remove first + var removed = removeArticle(summary, originLevel); + // Insert then + return insertArticle(removed, article, targetLevel); + } else { + // Insert right after first + var inserted = insertArticle(summary, article, targetLevel); + // Remove old one + return removeArticle(inserted, originLevel); + } +} + +/** + @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('.'); +} + +function increment(level) { + level = levelToArray(level); + level[level.length - 1]++; + return arrayToLevel(level); +} + +module.exports = moveArticleAfter; diff --git a/lib/modifiers/summary/removePart.js b/lib/modifiers/summary/removePart.js new file mode 100644 index 0000000..2f8affc --- /dev/null +++ b/lib/modifiers/summary/removePart.js @@ -0,0 +1,15 @@ +var indexLevels = require('./indexLevels'); + +/** + Remove a part at given index + + @param {Summary} summary + @param {Number|} index + @return {Summary} +*/ +function removePart(summary, index) { + var parts = summary.getParts().remove(index); + return indexLevels(summary.set('parts', parts)); +} + +module.exports = removePart; |