diff --git a/packages/slate/src/operations/apply.js b/packages/slate/src/operations/apply.js index 067d6d31a..9fe5a608e 100644 --- a/packages/slate/src/operations/apply.js +++ b/packages/slate/src/operations/apply.js @@ -287,12 +287,20 @@ const APPLIERS = { const { anchorKey, focusKey, anchorOffset, focusOffset } = selection let node = document.assertPath(path) - if (anchorKey == node.key && anchorOffset >= rangeOffset) { - selection = selection.moveAnchor(-length) + if (anchorKey == node.key) { + if (anchorOffset >= rangeOffset) { + selection = selection.moveAnchor(-length) + } else if (anchorOffset > offset) { + selection = selection.moveAnchorTo(anchorKey, offset) + } } - if (focusKey == node.key && focusOffset >= rangeOffset) { - selection = selection.moveFocus(-length) + if (focusKey == node.key) { + if (focusOffset >= rangeOffset) { + selection = selection.moveFocus(-length) + } else if (focusOffset > offset) { + selection = selection.moveFocusTo(focusKey, offset) + } } node = node.removeText(offset, length) diff --git a/packages/slate/test/index.js b/packages/slate/test/index.js index 6871abd08..bfc424731 100644 --- a/packages/slate/test/index.js +++ b/packages/slate/test/index.js @@ -20,6 +20,7 @@ describe('slate', () => { require('./schema') require('./changes') require('./history') + require('./operations') }) /** diff --git a/packages/slate/test/operations/apply/remove_text/cursor-inside-removed-text.js b/packages/slate/test/operations/apply/remove_text/cursor-inside-removed-text.js new file mode 100644 index 000000000..cfc446704 --- /dev/null +++ b/packages/slate/test/operations/apply/remove_text/cursor-inside-removed-text.js @@ -0,0 +1,31 @@ +/** @jsx h */ + +import h from '../../../helpers/h' + +export default [{ + type: 'remove_text', + path: [0, 0], + offset: 2, + text: 'is is some text inside ', + marks: [] +}] + +export const input = ( + + + + This is some text inside a paragraph. + + + +) + +export const output = ( + + + + Tha paragraph. + + + +) diff --git a/packages/slate/test/operations/index.js b/packages/slate/test/operations/index.js new file mode 100644 index 000000000..1615d21c6 --- /dev/null +++ b/packages/slate/test/operations/index.js @@ -0,0 +1,42 @@ + +import assert from 'assert' +import fs from 'fs-promise' // eslint-disable-line import/no-extraneous-dependencies +import toCamel from 'to-camel-case' // eslint-disable-line import/no-extraneous-dependencies +import { basename, extname, resolve } from 'path' + +/** + * Tests. + */ + +describe('operations', async () => { + const dir = resolve(__dirname) + const categories = fs.readdirSync(dir).filter(c => c[0] != '.' && c != 'index.js') + + for (const category of categories) { + describe(category, () => { + const categoryDir = resolve(dir, category) + const methods = fs.readdirSync(categoryDir).filter(c => c[0] != '.') + + for (const method of methods) { + describe(toCamel(method), () => { + const testDir = resolve(categoryDir, method) + const tests = fs.readdirSync(testDir).filter(t => t[0] != '.' && !!~t.indexOf('.js')).map(t => basename(t, extname(t))) + + for (const test of tests) { + it(test, async () => { + const module = require(resolve(testDir, test)) + const { input, output } = module + const operations = module.default + const change = input.change() + change.applyOperations(operations) + const opts = { preserveSelection: true, preserveData: true } + const actual = change.value.toJSON(opts) + const expected = output.toJSON(opts) + assert.deepEqual(actual, expected) + }) + } + }) + } + }) + } +})