diff --git a/src/component/handlers/edit/__tests__/editOnBeforeInput.test.js b/src/component/handlers/edit/__tests__/editOnBeforeInput.test.js index cc711c9ac8..53bb8b2fdd 100644 --- a/src/component/handlers/edit/__tests__/editOnBeforeInput.test.js +++ b/src/component/handlers/edit/__tests__/editOnBeforeInput.test.js @@ -14,7 +14,6 @@ 'use strict'; jest.disableAutomock(); -jest.mock('gkx', () => name => name === 'draft_improved_decorator_fingerprint'); const CompositeDraftDecorator = require('CompositeDraftDecorator'); const ContentBlock = require('ContentBlock'); diff --git a/src/component/handlers/edit/editOnBeforeInput.js b/src/component/handlers/edit/editOnBeforeInput.js index 1b909563c9..bbb88821c1 100644 --- a/src/component/handlers/edit/editOnBeforeInput.js +++ b/src/component/handlers/edit/editOnBeforeInput.js @@ -15,13 +15,11 @@ import type DraftEditor from 'DraftEditor.react'; import type {DraftInlineStyle} from 'DraftInlineStyle'; -const BlockTree = require('BlockTree'); const DraftModifier = require('DraftModifier'); const EditorState = require('EditorState'); const UserAgent = require('UserAgent'); const getEntityKeyForSelection = require('getEntityKeyForSelection'); -const gkx = require('gkx'); const isEventHandled = require('isEventHandled'); const isSelectionAtLeafStart = require('isSelectionAtLeafStart'); const nullthrows = require('nullthrows'); @@ -190,73 +188,60 @@ function editOnBeforeInput( } } if (!mustPreventNative) { - if (gkx('draft_improved_decorator_fingerprint')) { - // Let's say we have a decorator that highlights hashtags. In many cases - // we need to prevent native behavior and rerender ourselves -- - // particularly, any case *except* where the inserted characters end up - // anywhere except exactly where you put them. - // - // Using [] to denote a decorated leaf, some examples: - // - // 1. 'hi #' and append 'f' - // desired rendering: 'hi [#f]' - // native rendering would be: 'hi #f' (incorrect) - // - // 2. 'x [#foo]' and insert '#' before 'f' - // desired rendering: 'x #[#foo]' - // native rendering would be: 'x [##foo]' (incorrect) - // - // 3. '[#foobar]' and insert ' ' between 'foo' and 'bar' - // desired rendering: '[#foo] bar' - // native rendering would be: '[#foo bar]' (incorrect) - // - // 4. '[#foo]' and delete '#' [won't use this beforeinput codepath though] - // desired rendering: 'foo' - // native rendering would be: '[foo]' (incorrect) - // - // 5. '[#foo]' and append 'b' - // desired rendering: '[#foob]' - // native rendering would be: '[#foob]' (native insertion is OK here) - // - // It is safe to allow native insertion if and only if the full list of - // decorator ranges matches what we expect native insertion to give. We - // don't need to compare the content because the only possible mutation - // to consider here is inserting plain text and decorators can't affect - // text content. - const oldBlockTree = editorState.getBlockTree(anchorKey); - const newBlockTree = newEditorState.getBlockTree(anchorKey); - mustPreventNative = - oldBlockTree.size !== newBlockTree.size || - oldBlockTree.zip(newBlockTree).some(([oldLeafSet, newLeafSet]) => { - // selectionStart is guaranteed to be selectionEnd here - const oldStart = oldLeafSet.get('start'); - const adjustedStart = - oldStart + (oldStart >= selectionStart ? chars.length : 0); - const oldEnd = oldLeafSet.get('end'); - const adjustedEnd = - oldEnd + (oldEnd >= selectionStart ? chars.length : 0); - return ( - // Different decorators - oldLeafSet.get('decoratorKey') !== newLeafSet.get('decoratorKey') || - // Different number of inline styles - oldLeafSet.get('leaves').size !== newLeafSet.get('leaves').size || - // Different effective decorator position - adjustedStart !== newLeafSet.get('start') || - adjustedEnd !== newLeafSet.get('end') - ); - }); - } else { - // Check the old and new "fingerprints" of the current block to determine - // whether this insertion requires any addition or removal of text nodes, - // in which case we would prevent the native character insertion. - const originalFingerprint = BlockTree.getFingerprint( - editorState.getBlockTree(anchorKey), - ); - const newFingerprint = BlockTree.getFingerprint( - newEditorState.getBlockTree(anchorKey), - ); - mustPreventNative = originalFingerprint !== newFingerprint; - } + // Let's say we have a decorator that highlights hashtags. In many cases + // we need to prevent native behavior and rerender ourselves -- + // particularly, any case *except* where the inserted characters end up + // anywhere except exactly where you put them. + // + // Using [] to denote a decorated leaf, some examples: + // + // 1. 'hi #' and append 'f' + // desired rendering: 'hi [#f]' + // native rendering would be: 'hi #f' (incorrect) + // + // 2. 'x [#foo]' and insert '#' before 'f' + // desired rendering: 'x #[#foo]' + // native rendering would be: 'x [##foo]' (incorrect) + // + // 3. '[#foobar]' and insert ' ' between 'foo' and 'bar' + // desired rendering: '[#foo] bar' + // native rendering would be: '[#foo bar]' (incorrect) + // + // 4. '[#foo]' and delete '#' [won't use this beforeinput codepath though] + // desired rendering: 'foo' + // native rendering would be: '[foo]' (incorrect) + // + // 5. '[#foo]' and append 'b' + // desired rendering: '[#foob]' + // native rendering would be: '[#foob]' (native insertion is OK here) + // + // It is safe to allow native insertion if and only if the full list of + // decorator ranges matches what we expect native insertion to give. We + // don't need to compare the content because the only possible mutation + // to consider here is inserting plain text and decorators can't affect + // text content. + const oldBlockTree = editorState.getBlockTree(anchorKey); + const newBlockTree = newEditorState.getBlockTree(anchorKey); + mustPreventNative = + oldBlockTree.size !== newBlockTree.size || + oldBlockTree.zip(newBlockTree).some(([oldLeafSet, newLeafSet]) => { + // selectionStart is guaranteed to be selectionEnd here + const oldStart = oldLeafSet.get('start'); + const adjustedStart = + oldStart + (oldStart >= selectionStart ? chars.length : 0); + const oldEnd = oldLeafSet.get('end'); + const adjustedEnd = + oldEnd + (oldEnd >= selectionStart ? chars.length : 0); + return ( + // Different decorators + oldLeafSet.get('decoratorKey') !== newLeafSet.get('decoratorKey') || + // Different number of inline styles + oldLeafSet.get('leaves').size !== newLeafSet.get('leaves').size || + // Different effective decorator position + adjustedStart !== newLeafSet.get('start') || + adjustedEnd !== newLeafSet.get('end') + ); + }); } if (!mustPreventNative) { mustPreventNative = mustPreventDefaultForCharacter(chars); diff --git a/src/model/immutable/BlockTree.js b/src/model/immutable/BlockTree.js index 5caaf8d6e4..12c8ec0ee1 100644 --- a/src/model/immutable/BlockTree.js +++ b/src/model/immutable/BlockTree.js @@ -93,24 +93,6 @@ const BlockTree = { return List(leafSets); }, - - /** - * Create a string representation of the given tree map. This allows us - * to rapidly determine whether a tree has undergone a significant - * structural change. - */ - getFingerprint: function(tree: List): string { - return tree - .map(leafSet => { - const decoratorKey = leafSet.get('decoratorKey'); - const fingerprintString = - decoratorKey !== null - ? decoratorKey + '.' + (leafSet.get('end') - leafSet.get('start')) - : ''; - return '' + fingerprintString + '.' + leafSet.get('leaves').size; - }) - .join(FINGERPRINT_DELIMITER); - }, }; /** diff --git a/src/model/immutable/__tests__/BlockTree-test.js b/src/model/immutable/__tests__/BlockTree-test.js index 118b91d309..570a56e0e3 100644 --- a/src/model/immutable/__tests__/BlockTree-test.js +++ b/src/model/immutable/__tests__/BlockTree-test.js @@ -97,7 +97,6 @@ const assertBlockTreeGenerate = ( const tree = BlockTree.generate(content, block, decorator); expect(tree.toJS()).toMatchSnapshot(); - expect(BlockTree.getFingerprint(tree)).toMatchSnapshot(); // to remove return tree; diff --git a/src/model/immutable/__tests__/__snapshots__/BlockTree-test.js.snap b/src/model/immutable/__tests__/__snapshots__/BlockTree-test.js.snap index dcaf0a467d..b072df38b7 100644 --- a/src/model/immutable/__tests__/__snapshots__/BlockTree-test.js.snap +++ b/src/model/immutable/__tests__/__snapshots__/BlockTree-test.js.snap @@ -24,8 +24,6 @@ Array [ ] `; -exports[`must generate for styled block with empty decorator 2`] = `".3"`; - exports[`must generate for styled block with multiple decorators 1`] = ` Array [ Object { @@ -72,8 +70,6 @@ Array [ ] `; -exports[`must generate for styled block with multiple decorators 2`] = `"y.3.1-.2-z.4.2"`; - exports[`must generate for styled block with single decorator 1`] = ` Array [ Object { @@ -120,8 +116,6 @@ Array [ ] `; -exports[`must generate for styled block with single decorator 2`] = `".1-x.3.2-.2"`; - exports[`must generate for unstyled block with empty decorator 1`] = ` Array [ Object { @@ -138,8 +132,6 @@ Array [ ] `; -exports[`must generate for unstyled block with empty decorator 2`] = `".1"`; - exports[`must generate for unstyled block with multiple decorators 1`] = ` Array [ Object { @@ -178,8 +170,6 @@ Array [ ] `; -exports[`must generate for unstyled block with multiple decorators 2`] = `"y.3.1-.1-z.1.1"`; - exports[`must generate for unstyled block with single decorator 1`] = ` Array [ Object { @@ -217,5 +207,3 @@ Array [ }, ] `; - -exports[`must generate for unstyled block with single decorator 2`] = `".1-x.3.1-.1"`;