diff --git a/src/utils/applyChangeToValue.js b/src/utils/applyChangeToValue.js index 670283e3..3c358d62 100644 --- a/src/utils/applyChangeToValue.js +++ b/src/utils/applyChangeToValue.js @@ -60,16 +60,26 @@ const applyChangeToValue = ( // find start of diff spliceStart = 0 - while (plainTextValue[spliceStart] === controlPlainTextValue[spliceStart]) + while (plainTextValue[spliceStart] === oldPlainTextValue[spliceStart]) spliceStart++ + // find end of diff + let spliceEndOfNew = plainTextValue.length + let spliceEndOfOld = oldPlainTextValue.length + while ( + plainTextValue[spliceEndOfNew - 1] === + oldPlainTextValue[spliceEndOfOld - 1] + ) { + spliceEndOfNew-- + spliceEndOfOld-- + } + // extract auto-corrected insertion - insert = plainTextValue.slice(spliceStart, selectionEndAfter) + insert = plainTextValue.slice(spliceStart, spliceEndOfNew) // find index of the unchanged remainder - spliceEnd = oldPlainTextValue.lastIndexOf( - plainTextValue.substring(selectionEndAfter) - ) + spliceEnd = + spliceEndOfOld >= spliceStart ? spliceEndOfOld : selectionEndAfter // re-map the corrected indices mappedSpliceStart = mapPlainTextIndex(value, config, spliceStart, 'START') diff --git a/src/utils/applyChangeToValue.spec.js b/src/utils/applyChangeToValue.spec.js index 06f6850e..896e7366 100644 --- a/src/utils/applyChangeToValue.spec.js +++ b/src/utils/applyChangeToValue.spec.js @@ -23,7 +23,7 @@ describe('#applyChangeToValue', () => { const plainText = "Hi John Doe, \n\nlet's add joe@smoe.com to this conversation..." - const displayTransform = id => `<--${id}-->` + const displayTransform = (id) => `<--${id}-->` const plainTextDisplayTransform = "Hi <--johndoe-->, \n\nlet's add <--joe@smoe.com--> to this conversation..." @@ -70,6 +70,50 @@ describe('#applyChangeToValue', () => { ) }) + it('should correctly add characters with cursor in the middle at the end, beginning, and in the middle of text', () => { + let changed = 'S[start]' + plainText + let result = applyChangeToValue( + value, + changed, + { + selectionStartBefore: 0, + selectionEndBefore: 0, + selectionEndAfter: 1, + }, + config + ) + expect(result).toEqual('S[start]' + value) + + changed = plainText + 'E[end]' + result = applyChangeToValue( + value, + changed, + { + selectionStartBefore: plainText.length, + selectionEndBefore: plainText.length, + selectionEndAfter: plainText.length + 1, + }, + config + ) + expect(result).toEqual(value + 'E[end]') + + changed = + "Hi John Doe, \n\nlet's M[mid]add joe@smoe.com to this conversation..." + result = applyChangeToValue( + value, + changed, + { + selectionStartBefore: 21, + selectionEndBefore: 21, + selectionEndAfter: 22, + }, + config + ) + expect(result).toEqual( + "Hi @[John Doe](user:johndoe), \n\nlet's M[mid]add @[joe@smoe.com](email:joe@smoe.com) to this conversation..." + ) + }) + it('should correctly delete single characters and ranges of selected text', () => { // delete "i" let changed = @@ -133,6 +177,20 @@ describe('#applyChangeToValue', () => { config ) expect(result).toEqual(value.replace('add', 'remove')) + + // replace range with cursor in the middle, eg. remove|[remove] + changed = plainText.replace('add', 'remove[remove]') + result = applyChangeToValue( + value, + changed, + { + selectionStartBefore: plainText.indexOf('add'), + selectionEndBefore: plainText.indexOf('add') + 'add'.length, + selectionEndAfter: plainText.indexOf('add') + 'remove'.length, + }, + config + ) + expect(result).toEqual(value.replace('add', 'remove[remove]')) }) it('should remove mentions markup contained in deleted text ranges', () => { @@ -249,7 +307,7 @@ describe('#applyChangeToValue', () => { selectionEndBefore: 26, selectionEndAfter: 26, }, - config.map(c => ({ ...c, displayTransform })) + config.map((c) => ({ ...c, displayTransform })) ) expect(result).toEqual( "Hi @[John Doe](user:johndoe), \n\nlet's dd @[joe@smoe.com](email:joe@smoe.com) to this conversation..." @@ -257,7 +315,7 @@ describe('#applyChangeToValue', () => { }) it('should correctly handle text auto-correction', () => { - const result = applyChangeToValue( + let result = applyChangeToValue( 'ill', "I'll", { @@ -268,5 +326,20 @@ describe('#applyChangeToValue', () => { config ) expect(result).toEqual("I'll") + + // case like + // input queue: s -> a -> d + // IME queue(| is the cursor position): s|[sa] -> s'a|[sa'a] -> sad|[sad] + result = applyChangeToValue( + "s'a[sa'a]", + 'sad[sad]', + { + selectionStartBefore: 2, + selectionEndBefore: 2, + selectionEndAfter: 3, + }, + config + ) + expect(result).toEqual('sad[sad]') }) })