From e7d94c3c351691d8a0d82f0ddfcdae5a018a4c84 Mon Sep 17 00:00:00 2001 From: Ian Storm Taylor Date: Fri, 17 Jun 2016 00:52:15 -0700 Subject: [PATCH] more fixes --- lib/models/selection.js | 40 ++++++++++++++ lib/models/state.js | 119 +++++++++++++++------------------------- 2 files changed, 85 insertions(+), 74 deletions(-) diff --git a/lib/models/selection.js b/lib/models/selection.js index 2faa8ffe7..15615c8ae 100644 --- a/lib/models/selection.js +++ b/lib/models/selection.js @@ -20,10 +20,22 @@ const SelectionRecord = new Record({ class Selection extends SelectionRecord { + /** + * Create a new `Selection` from `attrs`. + * + * @return {Selection} selection + */ + static create(attrs) { return new Selection(attrs) } + /** + * Get whether the selection is collapsed. + * + * @return {Boolean} isCollapsed + */ + get isCollapsed() { return ( this.anchorKey === this.focusKey && @@ -31,10 +43,38 @@ class Selection extends SelectionRecord { ) } + /** + * Get whether the selection is expanded. + * + * Aliased as `isExtended` since browser implementations refer to it as both. + * + * @return {Boolean} isExpanded + */ + + get isExpanded() { + return ! this.isCollapsed + } + + get isExtended() { + return this.isExpanded + } + + /** + * Get whether the selection is forward. + * + * @return {Boolean} isForward + */ + get isForward() { return ! this.isBackward } + /** + * Get the start key. + * + * @return {String} startKey + */ + get startKey() { return this.isBackward ? this.focusKey diff --git a/lib/models/state.js b/lib/models/state.js index c476ab020..7b7cdd894 100644 --- a/lib/models/state.js +++ b/lib/models/state.js @@ -55,7 +55,7 @@ const SELECTION_LIKE_METHODS = [ class State extends StateRecord { /** - * Create a new `state` from `attrs`. + * Create a new `State` from `attrs`. * * @return {State} state */ @@ -68,119 +68,73 @@ class State extends StateRecord { } /** - * Get whether the selection is collapsed. - * - * @return {Boolean} isCollapsed - */ - - get isCollapsed() { - return this.selection.isCollapsed - } - - /** - * Get the length of the concatenated text of all nodes. - * - * @return {Number} length + * Node-like getters. */ get length() { return this.text.length } - /** - * Get the concatenated text of all nodes. - * - * @return {String} text - */ - get text() { return this.nodes .map(node => node.text) .join('') } + get type() { + return 'state' + } + /** - * Get the anchor key. - * - * @return {String} anchorKey + * Selection-like getters. */ + get isCollapsed() { + return this.selection.isCollapsed + } + + get isExpanded() { + return this.selection.isExpanded + } + + get isExtended() { + return this.selection.isExtended + } + get anchorKey() { return this.selection.anchorKey } - /** - * Get the anchor offset. - * - * @return {String} anchorOffset - */ - get anchorOffset() { return this.selection.anchorOffset } - /** - * Get the focus key. - * - * @return {String} focusKey - */ - get focusKey() { return this.selection.focusKey } - /** - * Get the focus offset. - * - * @return {String} focusOffset - */ - get focusOffset() { return this.selection.focusOffset } - /** - * Get the start key. - * - * @return {String} startKey - */ - get startKey() { return this.selection.startKey } - /** - * Get the start offset. - * - * @return {String} startOffset - */ - get startOffset() { return this.selection.startOffset } - /** - * Get the end key. - * - * @return {String} endKey - */ - get endKey() { return this.selection.endKey } - /** - * Get the end offset. - * - * @return {String} endOffset - */ - get endOffset() { return this.selection.endOffset } /** - * Get the anchor node. + * Get the current anchor node. * * @return {Node} node */ @@ -190,7 +144,7 @@ class State extends StateRecord { } /** - * Get the focus node. + * Get the current focus node. * * @return {Node} node */ @@ -200,7 +154,7 @@ class State extends StateRecord { } /** - * Get the start node. + * Get the current start node. * * @return {Node} node */ @@ -210,7 +164,7 @@ class State extends StateRecord { } /** - * Get the end node. + * Get the current end node. * * @return {Node} node */ @@ -305,8 +259,26 @@ class State extends StateRecord { // When already at the end of the content, there's nothing to do. if (state.isAtEndOf(state)) return state + // When at end of a node, merge forwards into the next node. + const { startNode } = state + if (state.isAtEndOf(startNode)) { + const { selection, startOffset } = state + const parent = state.getParentNode(startNode) + const next = state.getNextNode(parent).nodes.first() + const range = selection.merge({ + anchorKey: startNode.key, + anchorOffset: startNode.length, + focusKey: next.key, + focusOffset: 0, + isBackward: false + }) + + state = state.removeRange(range) + return state + } + // Otherwise, remove one character ahead of the cursor. - const { startOffset, startNode } = state + const { startOffset } = state const endOffset = startOffset + 1 state = state.removeCharacters(startNode.key, startOffset, endOffset) return state @@ -334,6 +306,7 @@ class State extends StateRecord { removeCharacters(key, startOffset, endOffset) { let state = this let node = state.getNode(key) + const characters = node.characters.filterNot((char, i) => { return startOffset <= i && i < endOffset }) @@ -371,17 +344,15 @@ class State extends StateRecord { splitRange(selection = this.selection) { let state = this - // if there's an existing selection, remove it first + // If there's an existing selection, remove it first. if (!selection.isCollapsed) { state = state.removeRange(selection) selection = selection.moveToStart() } - // then split the node at the selection + // Split the text node's characters. const { startNode, startOffset } = state const parent = state.getParentNode(startNode) - - // split the characters const { characters , length } = startNode const firstCharacters = characters.take(startOffset) const secondCharacters = characters.takeLast(length - startOffset)