From bfcafbec2b4dd69dbd06a4fe5fa5e88fe62ddf76 Mon Sep 17 00:00:00 2001 From: Nurhan Turgut <50856934+nturgut@users.noreply.github.com> Date: Mon, 30 Sep 2019 12:31:17 -0700 Subject: [PATCH] [web_ui] Fixing invalid state bug for text editing (#12698) * Fixing invalid state bug for text editing. Flutter Framework was sending editing state selection base and extent as -1. Since -1 is an invalid value for a dom element selection it was not applied to the last editing state. Now if the base or offset is sent as negative value, web engine will set 0 to the selection range. * Addressing PR comments. --- lib/web_ui/lib/src/engine/text_editing.dart | 18 +++++++-- lib/web_ui/test/text_editing_test.dart | 41 +++++++++++++++++++++ 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/lib/web_ui/lib/src/engine/text_editing.dart b/lib/web_ui/lib/src/engine/text_editing.dart index 0a85acb861b..957087ecccc 100644 --- a/lib/web_ui/lib/src/engine/text_editing.dart +++ b/lib/web_ui/lib/src/engine/text_editing.dart @@ -61,10 +61,20 @@ class EditingState { /// "composingExtent": -1 /// } /// ``` - EditingState.fromFlutter(Map flutterEditingState) - : text = flutterEditingState['text'], - baseOffset = flutterEditingState['selectionBase'], - extentOffset = flutterEditingState['selectionExtent']; + /// + /// Flutter Framework can send the [selectionBase] and [selectionExtent] as + /// -1, if so 0 assigned to the [baseOffset] and [extentOffset]. -1 is not a + /// valid selection range for input DOM elements. + factory EditingState.fromFlutter(Map flutterEditingState) { + final int selectionBase = flutterEditingState['selectionBase']; + final int selectionExtent = flutterEditingState['selectionExtent']; + final String text = flutterEditingState['text']; + + return EditingState( + text: text, + baseOffset: math.max(0, selectionBase), + extentOffset: math.max(0, selectionExtent)); + } /// Creates an [EditingState] instance using values from the editing element /// in the DOM. diff --git a/lib/web_ui/test/text_editing_test.dart b/lib/web_ui/test/text_editing_test.dart index b8bf2f7bedc..9f41dd32091 100644 --- a/lib/web_ui/test/text_editing_test.dart +++ b/lib/web_ui/test/text_editing_test.dart @@ -549,6 +549,47 @@ void main() { expect(spy.messages, isEmpty); }); + test( + 'negative base offset and selection extent values in editing state is handled', + () { + final MethodCall setClient = MethodCall( + 'TextInput.setClient', [123, flutterSinglelineConfig]); + textEditing.handleTextInput(codec.encodeMethodCall(setClient)); + + const MethodCall setEditingState1 = + MethodCall('TextInput.setEditingState', { + 'text': 'xyz', + 'selectionBase': 1, + 'selectionExtent': 2, + }); + textEditing.handleTextInput(codec.encodeMethodCall(setEditingState1)); + + const MethodCall show = MethodCall('TextInput.show'); + textEditing.handleTextInput(codec.encodeMethodCall(show)); + + // Check if the selection range is correct. + checkInputEditingState( + textEditing.editingElement.domElement, 'xyz', 1, 2); + + const MethodCall setEditingState2 = + MethodCall('TextInput.setEditingState', { + 'text': 'xyz', + 'selectionBase': -1, + 'selectionExtent': -1, + }); + textEditing.handleTextInput(codec.encodeMethodCall(setEditingState2)); + + // The negative offset values are applied to the dom element as 0. + checkInputEditingState( + textEditing.editingElement.domElement, 'xyz', 0, 0); + + const MethodCall clearClient = MethodCall('TextInput.clearClient'); + textEditing.handleTextInput(codec.encodeMethodCall(clearClient)); + + // Confirm that [HybridTextEditing] didn't send any messages. + expect(spy.messages, isEmpty); + }); + test('Syncs the editing state back to Flutter', () { final MethodCall setClient = MethodCall( 'TextInput.setClient', [123, flutterSinglelineConfig]);