Skip to content

Commit

Permalink
Fix updating editor when editing selected text
Browse files Browse the repository at this point in the history
Summary:
Fixes #1509.

Ref: facebookarchive/draft-js#719
Closes facebookarchive/draft-js#1512

Differential Revision: D6673593

fbshipit-source-id: fb5ab4c41de7958139deb125e5e8e79c76b53ec3
  • Loading branch information
existentialism authored and facebook-github-bot committed Jan 10, 2018
1 parent b77ca37 commit 09aa0d5
Show file tree
Hide file tree
Showing 3 changed files with 282 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`editor is updated with new text if it does not match current selection 1`] = `
Immutable.Record {
"entityMap": Object {
"__add": [Function],
"__create": [Function],
"__get": [Function],
"__getLastCreatedEntityKey": [Function],
"__mergeData": [Function],
"__replaceData": [Function],
"add": [Function],
"create": [Function],
"get": [Function],
"getLastCreatedEntityKey": [Function],
"mergeData": [Function],
"replaceData": [Function],
},
"blockMap": Immutable.OrderedMap {
"a": Immutable.Record {
"key": "a",
"type": "unstyled",
"text": "Orsenal",
"characterList": Immutable.List [
Immutable.Record {
"style": Immutable.OrderedSet [],
"entity": null,
},
Immutable.Record {
"style": Immutable.OrderedSet [],
"entity": null,
},
Immutable.Record {
"style": Immutable.OrderedSet [],
"entity": null,
},
Immutable.Record {
"style": Immutable.OrderedSet [],
"entity": null,
},
Immutable.Record {
"style": Immutable.OrderedSet [],
"entity": null,
},
Immutable.Record {
"style": Immutable.OrderedSet [],
"entity": null,
},
Immutable.Record {
"style": Immutable.OrderedSet [],
"entity": null,
},
],
"depth": 0,
"data": Immutable.Map {},
},
},
"selectionBefore": Immutable.Record {
"anchorKey": "a",
"anchorOffset": 0,
"focusKey": "a",
"focusOffset": 1,
"isBackward": false,
"hasFocus": false,
},
"selectionAfter": Immutable.Record {
"anchorKey": "a",
"anchorOffset": 1,
"focusKey": "a",
"focusOffset": 1,
"isBackward": false,
"hasFocus": false,
},
}
`;

exports[`editor selectionstate is updated if new text matches current selection 1`] = `
Immutable.Record {
"entityMap": Object {
"__add": [Function],
"__create": [Function],
"__get": [Function],
"__getLastCreatedEntityKey": [Function],
"__mergeData": [Function],
"__replaceData": [Function],
"add": [Function],
"create": [Function],
"get": [Function],
"getLastCreatedEntityKey": [Function],
"mergeData": [Function],
"replaceData": [Function],
},
"blockMap": Immutable.OrderedMap {
"a": Immutable.Record {
"key": "a",
"type": "unstyled",
"text": "Arsenal",
"characterList": Immutable.List [
Immutable.Record {
"style": Immutable.OrderedSet [],
"entity": null,
},
Immutable.Record {
"style": Immutable.OrderedSet [],
"entity": null,
},
Immutable.Record {
"style": Immutable.OrderedSet [],
"entity": null,
},
Immutable.Record {
"style": Immutable.OrderedSet [],
"entity": null,
},
Immutable.Record {
"style": Immutable.OrderedSet [],
"entity": null,
},
Immutable.Record {
"style": Immutable.OrderedSet [],
"entity": null,
},
Immutable.Record {
"style": Immutable.OrderedSet [],
"entity": null,
},
],
"depth": 0,
"data": Immutable.Map {},
},
},
"selectionBefore": Immutable.Record {
"anchorKey": "a",
"anchorOffset": 0,
"focusKey": "a",
"focusOffset": 0,
"isBackward": false,
"hasFocus": false,
},
"selectionAfter": Immutable.Record {
"anchorKey": "a",
"anchorOffset": 0,
"focusKey": "a",
"focusOffset": 0,
"isBackward": false,
"hasFocus": false,
},
}
`;
129 changes: 129 additions & 0 deletions src/component/handlers/edit/__tests__/editOnBeforeInput.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @emails oncall+ui_infra
* @format
*/

'use strict';

jest.disableAutomock();

const ContentBlock = require('ContentBlock');
const ContentState = require('ContentState');
const EditorState = require('EditorState');
const SelectionState = require('SelectionState');
const onBeforeInput = require('editOnBeforeInput');

const DEFAULT_SELECTION = {
anchorKey: 'a',
anchorOffset: 0,
focusKey: 'a',
focusOffset: 0,
isBackward: false,
};

//const collapsedSelection = new SelectionState(DEFAULT_SELECTION);

const rangedSelection = new SelectionState({
...DEFAULT_SELECTION,
focusOffset: 1,
});

const getEditorState = () => {
return EditorState.createWithContent(
ContentState.createFromBlockArray([
new ContentBlock({
key: 'a',
text: 'Arsenal',
}),
]),
);
};

const getInputEvent = data => ({
data,
preventDefault: () => {},
});

test('editor is not updated if no character data is provided', () => {
const editorState = EditorState.acceptSelection(
getEditorState(),
rangedSelection,
);

const editor = {
_latestEditorState: editorState,
props: {},
update: jest.fn(),
};

onBeforeInput(editor, getInputEvent());

expect(editor.update).toHaveBeenCalledTimes(0);
});

test('editor is not updated if handled by handleBeforeInput', () => {
const editorState = EditorState.acceptSelection(
getEditorState(),
rangedSelection,
);

const editor = {
_latestEditorState: editorState,
props: {
handleBeforeInput: () => true,
},
update: jest.fn(),
};

onBeforeInput(editor, getInputEvent('O'));

expect(editor.update).toHaveBeenCalledTimes(0);
});

test('editor is updated with new text if it does not match current selection', () => {
const editorState = EditorState.acceptSelection(
getEditorState(),
rangedSelection,
);

const editor = {
_latestEditorState: editorState,
props: {},
update: jest.fn(),
};

onBeforeInput(editor, getInputEvent('O'));

expect(editor.update).toHaveBeenCalledTimes(1);

const newEditorState = editor.update.mock.calls[0][0];
expect(newEditorState.getCurrentContent()).toMatchSnapshot();
});

test('editor selectionstate is updated if new text matches current selection', () => {
const editorState = EditorState.acceptSelection(
getEditorState(),
rangedSelection,
);

const editor = {
_latestEditorState: editorState,
props: {},
update: jest.fn(),
};

onBeforeInput(editor, getInputEvent('A'));

expect(editor.update).toHaveBeenCalledTimes(1);

const newEditorState = editor.update.mock.calls[0][0];
expect(newEditorState.getCurrentContent()).toMatchSnapshot();
});
8 changes: 4 additions & 4 deletions src/component/handlers/edit/editOnBeforeInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,15 +117,15 @@ function editOnBeforeInput(
if (!selection.isCollapsed()) {
e.preventDefault();

// If the character that the user is trying to replace with
// is the same as the current selection text the just update the
// `SelectionState`. Else, update the ContentState with the new text
// If the currently selected text matches what the user is trying to
// replace it with, let's just update the `SelectionState`. If not, update
// the `ContentState` with the new text.
var currentlySelectedChars = editorState
.getCurrentContent()
.getPlainText()
.slice(selectionStart, selectionEnd);
if (chars === currentlySelectedChars) {
this.update(
editor.update(
EditorState.forceSelection(
editorState,
selection.merge({
Expand Down

0 comments on commit 09aa0d5

Please sign in to comment.