From 1fd27578fae20be2a585a34356fcee03a682c976 Mon Sep 17 00:00:00 2001 From: Ian Storm Taylor Date: Tue, 29 Nov 2016 16:58:12 -0800 Subject: [PATCH 1/4] add char, word, line delete transforms --- src/models/transform.js | 3 +- src/plugins/core.js | 114 +++++++---------------------- src/transforms/at-current-range.js | 72 ++++++++++++++++++ src/transforms/at-range.js | 99 +++++++++++++++++++++++++ src/transforms/index.js | 24 ++++++ 5 files changed, 224 insertions(+), 88 deletions(-) diff --git a/src/models/transform.js b/src/models/transform.js index a5b25c3b0..c82b20ead 100644 --- a/src/models/transform.js +++ b/src/models/transform.js @@ -23,11 +23,10 @@ class Transform { * * @param {Object} properties * @property {State} properties.state - * @property {Boolean} properties.normalized */ constructor(properties) { - const { state, normalized = true } = properties + const { state } = properties this.state = state this.operations = [] } diff --git a/src/plugins/core.js b/src/plugins/core.js index 269765b59..cd5d2554c 100644 --- a/src/plugins/core.js +++ b/src/plugins/core.js @@ -369,8 +369,6 @@ function Plugin(options = {}) { */ function onKeyDownEnter(e, data, state) { - debug('onKeyDownEnter', { data }) - const { document, startKey } = state const hasVoidParent = document.hasVoidParent(startKey) @@ -401,36 +399,13 @@ function Plugin(options = {}) { */ function onKeyDownBackspace(e, data, state) { - debug('onKeyDownBackspace', { data }) - - // If expanded, delete regularly. - if (state.isExpanded) { - return state - .transform() - .delete() - .apply() - } - - const { startOffset, startBlock } = state - const text = startBlock.text - let n - - // Determine how far backwards to delete. - if (data.isWord) { - n = String.getWordOffsetBackward(text, startOffset) - } - - else if (data.isLine) { - n = startOffset - } - - else { - n = String.getCharOffsetBackward(text, startOffset) - } + let boundary = 'Char' + if (data.isWord) boundary = 'Word' + if (data.isLine) boundary = 'Line' return state .transform() - .deleteBackward(n) + [`delete${boundary}Backward`]() .apply() } @@ -444,36 +419,13 @@ function Plugin(options = {}) { */ function onKeyDownDelete(e, data, state) { - debug('onKeyDownDelete', { data }) - - // If expanded, delete regularly. - if (state.isExpanded) { - return state - .transform() - .delete() - .apply() - } - - const { startOffset, startBlock } = state - const text = startBlock.text - let n - - // Determine how far forwards to delete. - if (data.isWord) { - n = String.getWordOffsetForward(text, startOffset) - } - - else if (data.isLine) { - n = text.length - startOffset - } - - else { - n = String.getCharOffsetForward(text, startOffset) - } + let boundary = 'Char' + if (data.isWord) boundary = 'Word' + if (data.isLine) boundary = 'Line' return state .transform() - .deleteForward(n) + [`delete${boundary}Forward`]() .apply() } @@ -505,8 +457,6 @@ function Plugin(options = {}) { const previousText = document.getPreviousText(startKey) if (!previousText) return - debug('onKeyDownLeft', { data }) - e.preventDefault() return state .transform() @@ -543,8 +493,6 @@ function Plugin(options = {}) { const nextText = document.getNextText(startKey) if (!nextText) return state - debug('onKeyDownRight', { data }) - // COMPAT: In Chrome & Safari, selections that are at the zero offset of // an inline node will be automatically replaced to be at the last offset // of a previous inline node, which screws us up, so we always want to set @@ -560,6 +508,26 @@ function Plugin(options = {}) { } } + /** + * On `k` key down, delete untill the end of the line (mac only) + * + * @param {Event} e + * @param {Object} data + * @param {State} state + * @return {State} + */ + + function onKeyDownK(e, data, state) { + if (!IS_MAC || !data.isCtrl) return + + const { startOffset, startBlock } = state + + return state + .transform() + .deleteForward(startBlock.length - startOffset) + .apply() + } + /** * On `y` key down, redo. * @@ -572,8 +540,6 @@ function Plugin(options = {}) { function onKeyDownY(e, data, state) { if (!data.isMod) return - debug('onKeyDownY', { data }) - return state .transform() .redo() @@ -592,36 +558,12 @@ function Plugin(options = {}) { function onKeyDownZ(e, data, state) { if (!data.isMod) return - debug('onKeyDownZ', { data }) - return state .transform() [data.isShift ? 'redo' : 'undo']() .apply({ save: false }) } - /** - * On `k` key down, delete untill the end of the line (mac only) - * - * @param {Event} e - * @param {Object} data - * @param {State} state - * @return {State} - */ - - function onKeyDownK(e, data, state) { - if (!IS_MAC || !data.isCtrl) return - - debug('onKeyDownK', { data }) - - const { startOffset, startBlock } = state - - return state - .transform() - .deleteForward(startBlock.text.length - startOffset) - .apply() - } - /** * On paste. * diff --git a/src/transforms/at-current-range.js b/src/transforms/at-current-range.js index 5c1e6813a..de5623779 100644 --- a/src/transforms/at-current-range.js +++ b/src/transforms/at-current-range.js @@ -63,6 +63,42 @@ export function deleteBackward(transform, n = 1) { transform.deleteBackwardAtRange(selection, n) } +/** + * Delete backward until the character boundary at the current selection. + * + * @param {Transform} transform + */ + +export function deleteCharBackward(transform) { + const { state } = transform + const { selection } = state + transform.deleteCharBackwardAtRange(selection) +} + +/** + * Delete backward until the line boundary at the current selection. + * + * @param {Transform} transform + */ + +export function deleteLineBackward(transform) { + const { state } = transform + const { selection } = state + transform.deleteLineBackwardAtRange(selection) +} + +/** + * Delete backward until the word boundary at the current selection. + * + * @param {Transform} transform + */ + +export function deleteWordBackward(transform) { + const { state } = transform + const { selection } = state + transform.deleteWordBackwardAtRange(selection) +} + /** * Delete forward `n` characters at the current selection. * @@ -76,6 +112,42 @@ export function deleteForward(transform, n = 1) { transform.deleteForwardAtRange(selection, n) } +/** + * Delete forward until the character boundary at the current selection. + * + * @param {Transform} transform + */ + +export function deleteCharForward(transform) { + const { state } = transform + const { selection } = state + transform.deleteCharForwardAtRange(selection) +} + +/** + * Delete forward until the line boundary at the current selection. + * + * @param {Transform} transform + */ + +export function deleteLineForward(transform) { + const { state } = transform + const { selection } = state + transform.deleteLineForwardAtRange(selection) +} + +/** + * Delete forward until the word boundary at the current selection. + * + * @param {Transform} transform + */ + +export function deleteWordForward(transform) { + const { state } = transform + const { selection } = state + transform.deleteWordForwardAtRange(selection) +} + /** * Insert a `block` at the current selection. * diff --git a/src/transforms/at-range.js b/src/transforms/at-range.js index 004994a76..001834a10 100644 --- a/src/transforms/at-range.js +++ b/src/transforms/at-range.js @@ -1,6 +1,7 @@ /* eslint no-console: 0 */ import Normalize from '../utils/normalize' +import String from '../utils/string' import SCHEMA from '../schemas/core' import { List } from 'immutable' @@ -119,6 +120,55 @@ export function deleteAtRange(transform, range, options = {}) { } } +/** + * Delete backward until the character boundary at a `range`. + * + * @param {Transform} transform + * @param {Selection} range + * @param {Object} options + * @property {Boolean} normalize + */ + +export function deleteCharBackwardAtRange(transform, range, options) { + const { state } = transform + const { startOffset, startBlock } = state + const { text } = startBlock + const n = String.getCharOffsetBackward(text, startOffset) + transform.deleteBackwardAtRange(range, n, options) +} + +/** + * Delete backward until the line boundary at a `range`. + * + * @param {Transform} transform + * @param {Selection} range + * @param {Object} options + * @property {Boolean} normalize + */ + +export function deleteLineBackwardAtRange(transform, range, options) { + const { state } = transform + const { startOffset } = state + transform.deleteBackwardAtRange(range, startOffset, options) +} + +/** + * Delete backward until the word boundary at a `range`. + * + * @param {Transform} transform + * @param {Selection} range + * @param {Object} options + * @property {Boolean} normalize + */ + +export function deleteWordBackwardAtRange(transform, range, options) { + const { state } = transform + const { startOffset, startBlock } = state + const { text } = startBlock + const n = String.getWordOffsetBackward(text, startOffset) + transform.deleteBackwardAtRange(range, n, options) +} + /** * Delete backward `n` characters at a `range`. * @@ -189,6 +239,55 @@ export function deleteBackwardAtRange(transform, range, n = 1, options = {}) { transform.deleteAtRange(range, { normalize }) } +/** + * Delete forward until the character boundary at a `range`. + * + * @param {Transform} transform + * @param {Selection} range + * @param {Object} options + * @property {Boolean} normalize + */ + +export function deleteCharForwardAtRange(transform, range, options) { + const { state } = transform + const { startOffset, startBlock } = state + const { text } = startBlock + const n = String.getCharOffsetForward(text, startOffset) + transform.deleteForwardAtRange(range, n, options) +} + +/** + * Delete forward until the line boundary at a `range`. + * + * @param {Transform} transform + * @param {Selection} range + * @param {Object} options + * @property {Boolean} normalize + */ + +export function deleteLineForwardAtRange(transform, range, options) { + const { state } = transform + const { startOffset, startBlock } = state + transform.deleteForwardAtRange(range, startBlock.length - startOffset, options) +} + +/** + * Delete forward until the word boundary at a `range`. + * + * @param {Transform} transform + * @param {Selection} range + * @param {Object} options + * @property {Boolean} normalize + */ + +export function deleteWordForwardAtRange(transform, range, options) { + const { state } = transform + const { startOffset, startBlock } = state + const { text } = startBlock + const n = String.getWordOffsetForward(text, startOffset) + transform.deleteForwardAtRange(range, n, options) +} + /** * Delete forward `n` characters at a `range`. * diff --git a/src/transforms/index.js b/src/transforms/index.js index 8ee1eac6f..0f02063ea 100644 --- a/src/transforms/index.js +++ b/src/transforms/index.js @@ -33,7 +33,13 @@ import { import { deleteAtRange, deleteBackwardAtRange, + deleteCharBackwardAtRange, + deleteCharForwardAtRange, deleteForwardAtRange, + deleteLineBackwardAtRange, + deleteLineForwardAtRange, + deleteWordBackwardAtRange, + deleteWordForwardAtRange, insertBlockAtRange, insertFragmentAtRange, insertInlineAtRange, @@ -59,7 +65,13 @@ import { import { _delete, deleteBackward, + deleteCharBackward, + deleteCharForward, deleteForward, + deleteLineBackward, + deleteLineForward, + deleteWordBackward, + deleteWordForward, insertBlock, insertFragment, insertInline, @@ -194,7 +206,13 @@ export default { deleteAtRange, deleteBackwardAtRange, + deleteCharBackwardAtRange, + deleteCharForwardAtRange, deleteForwardAtRange, + deleteLineBackwardAtRange, + deleteLineForwardAtRange, + deleteWordBackwardAtRange, + deleteWordForwardAtRange, insertBlockAtRange, insertFragmentAtRange, insertInlineAtRange, @@ -218,7 +236,13 @@ export default { delete: _delete, deleteBackward, + deleteCharBackward, + deleteCharForward, deleteForward, + deleteLineBackward, + deleteLineForward, + deleteWordBackward, + deleteWordForward, insertBlock, insertFragment, insertInline, From 2b10e270c6d08d9b4ecb1d5b80b3bc4eebf81d22 Mon Sep 17 00:00:00 2001 From: Ian Storm Taylor Date: Tue, 29 Nov 2016 16:59:28 -0800 Subject: [PATCH 2/4] update k key handler in core plugin --- src/plugins/core.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/plugins/core.js b/src/plugins/core.js index cd5d2554c..8a6bbbfaf 100644 --- a/src/plugins/core.js +++ b/src/plugins/core.js @@ -519,12 +519,9 @@ function Plugin(options = {}) { function onKeyDownK(e, data, state) { if (!IS_MAC || !data.isCtrl) return - - const { startOffset, startBlock } = state - return state .transform() - .deleteForward(startBlock.length - startOffset) + .deleteLineForward() .apply() } From ea2f70469ad66844795e70d4163ea37121104e15 Mon Sep 17 00:00:00 2001 From: Ian Storm Taylor Date: Tue, 29 Nov 2016 17:03:31 -0800 Subject: [PATCH 3/4] add ctrl-d and ctrl-h handling, closes #332 --- src/plugins/core.js | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/src/plugins/core.js b/src/plugins/core.js index 8a6bbbfaf..33a331509 100644 --- a/src/plugins/core.js +++ b/src/plugins/core.js @@ -353,9 +353,11 @@ function Plugin(options = {}) { case 'delete': return onKeyDownDelete(e, data, state) case 'left': return onKeyDownLeft(e, data, state) case 'right': return onKeyDownRight(e, data, state) + case 'd': return onKeyDownD(e, data, state) + case 'h': return onKeyDownH(e, data, state) + case 'k': return onKeyDownK(e, data, state) case 'y': return onKeyDownY(e, data, state) case 'z': return onKeyDownZ(e, data, state) - case 'k': return onKeyDownK(e, data, state) } } @@ -509,7 +511,43 @@ function Plugin(options = {}) { } /** - * On `k` key down, delete untill the end of the line (mac only) + * On `d` key down, for Macs, delete one character forward. + * + * @param {Event} e + * @param {Object} data + * @param {State} state + * @return {State} + */ + + function onKeyDownD(e, data, state) { + if (!IS_MAC || !data.isCtrl) return + e.preventDefault() + return state + .transform() + .deleteCharForward() + .apply() + } + + /** + * On `h` key down, for Macs, delete until the end of the line. + * + * @param {Event} e + * @param {Object} data + * @param {State} state + * @return {State} + */ + + function onKeyDownH(e, data, state) { + if (!IS_MAC || !data.isCtrl) return + e.preventDefault() + return state + .transform() + .deleteCharBackward() + .apply() + } + + /** + * On `k` key down, for Macs, delete until the end of the line. * * @param {Event} e * @param {Object} data @@ -519,6 +557,7 @@ function Plugin(options = {}) { function onKeyDownK(e, data, state) { if (!IS_MAC || !data.isCtrl) return + e.preventDefault() return state .transform() .deleteLineForward() From 60a03370ec61dcffa421ec1bddf71fca5108ebc0 Mon Sep 17 00:00:00 2001 From: Ian Storm Taylor Date: Tue, 29 Nov 2016 17:04:33 -0800 Subject: [PATCH 4/4] cleanup --- src/plugins/core.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/plugins/core.js b/src/plugins/core.js index 33a331509..50cd08abc 100644 --- a/src/plugins/core.js +++ b/src/plugins/core.js @@ -673,15 +673,11 @@ function Plugin(options = {}) { */ function onSelect(e, data, state) { - const { selection } = data - - debug('onSelect', { data, selection: selection.toJS() }) + debug('onSelect', { data }) return state .transform() - .moveTo(selection) - // Since the document has not changed, we only need to normalize the - // selection and this is done automatically in `transform.apply()`. + .moveTo(data.selection) .apply() }