diff --git a/TODO.md b/TODO.md
index a1e047a..e9d18f6 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,33 +1 @@
-
- - create production mode build and serve settings: `webpack.js` and `src/server/babel.index.js`
-
-
-## State changes
-
-main page edits input documents
-compare page views compare documents
-
-compare button:
-
-- generate id
-- post input documents to server
-- input documents copied to compare documents
-- input documents cleared
-- go to compare route
-
-edit button:
-
-- compare documents copied to input documents
-- compare documents cleared
-- go to main route
-
-client start:
-
-- load input documents from localStore
-
-server start:
-
-- load compare documents from database
-
-
-* client actually never needs to query server for compare documents... huh!
\ No newline at end of file
+Support for displaying and responding to `#markdown` path suffix.
\ No newline at end of file
diff --git a/src/common/selectors.js b/src/common/selectors.js
index e44d32e..3129712 100644
--- a/src/common/selectors.js
+++ b/src/common/selectors.js
@@ -44,20 +44,14 @@ export const isShowDifference= isShow(Show.DIFFERENCE)
export const diff = createSelector(
[format, safeInput],
(format, safeInput) => {
- return Dubdiff.plaintextDiff(safeInput.original, safeInput.final)
-/*
- let diff = JsDiff.diffWords (input.original.replace(/ /g, ' '), input.final.replace(/ /g, ' '))
- return diff.map(({added, removed, value})=>({added, removed, value:value.replace(/ /g, ' ')})).map(part => (
- part.added ? {part.value} :
- part.removed ? {part.value} :
- {part.value}
- ))
-*/
+ if (format==Format.PLAINTEXT)
+ return Dubdiff.plaintextDiff(safeInput.original, safeInput.final)
+ else if (format==Format.MARKDOWN)
+ return Dubdiff.markdownDiff(safeInput.original, safeInput.final)
}
)
-
/*
html diff
---
diff --git a/src/common/util/EditorsDiff.js b/src/common/util/EditorsDiff.js
index bdd7aec..2d649b2 100644
--- a/src/common/util/EditorsDiff.js
+++ b/src/common/util/EditorsDiff.js
@@ -60,4 +60,5 @@ class EditorsDiff extends Diff {
export default EditorsDiff
-const isSpace = str => /[ ]+/.test(str)
\ No newline at end of file
+const isSpace = str => /[ ]+/.test(str)
+const isNewline = str => /[\n]+/.test(str)
\ No newline at end of file
diff --git a/src/common/util/dubdiff.js b/src/common/util/dubdiff.js
index fe5bba9..933b716 100644
--- a/src/common/util/dubdiff.js
+++ b/src/common/util/dubdiff.js
@@ -44,10 +44,12 @@ export function diffToHtml(diff) {
// In essence, moves the markdown formatting elements in or out of the inserted and deleted blocks, as appropriate
//rules:
+
// 1. if a multiline del block is followed by an ins block,
// the first line of the ins block should be inserted at the end of the first line of the del block
// so the markdown will apply to the ins text as it should
-// 2. after a newline, if an ins or del block begins with a markdown line formatting prefix (eg. for a title or list)
+// 2. multiline ins and del blocks should be broken up into a series of single line blocks
+// 3. after a newline, if an ins or del block begins with a markdown line formatting prefix (eg. for a title or list)
// then that prefix should be moved out of the block
//not yet implemented rules:
@@ -59,8 +61,10 @@ export function diffToHtml(diff) {
function rewriteMarkdownDiff(diff) {
//apply transformation rules
let transformedDiff = diff
- transformedDiff= applyTransformationRule1(transformedDiff)
- transformedDiff= applyTransformationRule2(transformedDiff)
+ transformedDiff= applyTransformationRuleMultilineDelThenIns(transformedDiff)
+ transformedDiff= applyTransformationRuleBreakUpDelIns(transformedDiff)
+ transformedDiff= applyTransformationRuleFormattingPrefix(transformedDiff)
+ transformedDiff= applyTransformationRuleRemoveEmpty(transformedDiff)
return transformedDiff
}
@@ -68,7 +72,7 @@ function rewriteMarkdownDiff(diff) {
// 1. if a multiline del block is followed by an ins block,
// the first line of the ins block should be inserted at the end of the first line of the del block
// so the markdown will apply to the ins text as it should
-function applyTransformationRule1(diff) {
+function applyTransformationRuleMultilineDelThenIns(diff) {
let transformedDiff = []
const B_ADDED='added', B_REMOVED='removed', B_SAME='same'
@@ -117,6 +121,46 @@ function applyTransformationRule1(diff) {
return transformedDiff
}
+//Transformation rule 2
+// 2. multiline del and ins blocks should be broken up
+// into a series of single line blocks
+function applyTransformationRuleBreakUpDelIns(diff) {
+ let transformedDiff = []
+
+ const B_ADDED='added', B_REMOVED='removed', B_SAME='same'
+ let blockType = null
+ let blockIsMultiline = false
+
+ //iterate the input tokens to create the intermediate representation
+ diff.forEach((block) => {
+
+ blockType = (block.added ? B_ADDED : (block.removed ? B_REMOVED : B_SAME))
+ blockIsMultiline = isMultilineDiffBlock(block)
+
+ //transform rule applys when:
+ // the current block is an ins or del and is multiline
+ if ((blockType == B_REMOVED || blockType == B_ADDED) && blockIsMultiline) {
+
+ //split the first line from the current block
+ let blockSplit = splitMultilineDiffBlock(block)
+
+ blockSplit.forEach(blockSplitLine => transformedDiff.push(blockSplitLine))
+ }
+ else {
+ //otherwise, we just add the current block to the transformed list
+ transformedDiff.push(block)
+ }
+ })
+
+ return transformedDiff
+}
+
+
+// Transformation rule number 4: remove empty blocks
+function applyTransformationRuleRemoveEmpty(diff) {
+
+ return diff.filter(({value}) => value.length>0)
+}
// matches markdown prefixes that affect the formatting of the whole subsequent line
// ^ - start of line
@@ -126,18 +170,18 @@ function applyTransformationRule1(diff) {
// |([ \t]+[\*\+-]) - unordered lists
// |([ \t]+[0-9]+\.) - numeric lists
// )?
- // [ \t]* - trailing whitespace
-const MARKDOWN_PREFIX = /^([ \t]*\>)*(([ \t]*#*)|([ \t]*[\*\+-])|([ \t]*[\d]+\.))?[ \t]*/
+ // [ \t]+ - trailing whitespace
+const MARKDOWN_PREFIX = /^([ \t]*\>)*(([ \t]*#*)|([ \t]*[\*\+-])|([ \t]*[\d]+\.))?[ \t]+/
//matches strings that end with a newline followed by some whitespace
const NEWLINE_SUFFIX = /\n\s*$/
-// transformation rule 2:
+// transformation rule 3:
// after a newline, if an ins or del block begins with a markdown line formatting prefix (eg. for a title or list)
// then that prefix should be moved out of the block
// also, if an ins block begins with a formatting prefix and follows immediately after a del block that follows a newline,
// the prefix should be moved out of the block _and_ an extra newline character should be added to the beginning of it
-function applyTransformationRule2(diff) {
+function applyTransformationRuleFormattingPrefix(diff) {
let transformedDiff = []
let isNewline = true
@@ -186,42 +230,21 @@ function isMultilineDiffBlock({value}) {
//but with the string split by newlines
//if the diff block has no newlines, an array containing only that diff will be returned
//if the diff block has newlines, the resulting array will have a series of blocks,
-// each of which subsequent to the first block will begin with a newline
+// consisting of the block text, interleaved with newlines
+// ,
+// each of which begin with a newline
//if the diff block begins with a newline, the returned array will begin with an empty diff
function splitMultilineDiffBlock({added, removed, value}) {
- //find the indices of the diff block that coorespond to newlines
- const splits = indicesOf(value, c => (c=='\n') )
+ let lines = value.split('\n')
+ let blocks = []
+// lines = lines.filter(line=>line.length>0)
+ lines.forEach((line, index) => {
+ blocks.push({added, removed, value:line})
+ if (index {
- ranges = ranges.concat([{start:last, end:i}])
- return {last:i, ranges}
- },
- //start with the zero index and an empty array
- {last: 0, ranges:[]}
- ).ranges
-
-
- //map the ranges into blocks
- const blocks = ranges.map(
- //each block is the same as the given original block, but with the values split at newlines
- ({start, end}) => ({added, removed, value:value.substring(start, end)})
- )
-
- //console.log({value, splits, ranges, blocks})
+ console.log(lines)
+ console.log(blocks)
return blocks
-}
-
-//collect all the indices of the given string that satisfy the test function
-const indicesOf = (string, test) => string.split('').reduce(
- //add indexes that satisfy the test function to the array
- (acc, x, i) => (test(x) ? acc.concat([i]) : acc ),
- //start with the empty array
- []
-)
+}
\ No newline at end of file
diff --git a/test/dubdiffMarkdown.js b/test/dubdiffMarkdown.js
index a66be77..69a4f8d 100644
--- a/test/dubdiffMarkdown.js
+++ b/test/dubdiffMarkdown.js
@@ -5,7 +5,7 @@
import chai from 'chai'
-import {markdownDiff, diffToString} from '../src/common/util/dubdiff'
+import {markdownDiff, diffToString, diffToHtml} from '../src/common/util/dubdiff'
let diff = (a,b) => diffToString(markdownDiff(a,b))
@@ -43,7 +43,7 @@ describe('dubdiff', () => {
`# Title
other`,
`# Subtitle`
- )).to.equal('# [-Title-]{+Subtitle+}[-\nother-]')
+ )).to.equal('# [-Title-]{+Subtitle+}\n[-other-]')
})
it('pulls prefixes out of ins or del blocks after newline', () => {
@@ -70,5 +70,18 @@ other`,
'This [link](https://somewhere.com) is the same.',
'This [link](https://somewhere.org) changed.'
)).to.equal('This [link](https://somewhere.[-com-]{+org+}) [-is the same-]{+changed+}.')
+ })
+ it('deletes a title' , () => {
+ expect(diff(
+ 'Hello\n# Title 1\n# Title 2',
+ 'Hello\n# Title 2'
+ )).to.equal('Hello\n# Title [-1-]\n# [-Title -]2',)
})
-})
\ No newline at end of file
+ it('deletes a more different title' , () => {
+ expect(diff(
+ 'Hello\n# Filbert\n# Title 2',
+ 'Hello\n# Title 2'
+ )).to.equal('Hello\n# [-Filbert-]\n# Title 2',)
+ })
+})
+