From e295cca68f72efd7ffaf58e8b230dbfb4201e5db Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Tue, 12 Sep 2023 03:23:21 +0200 Subject: [PATCH] [Web] Properly report inverted selection (flutter/engine#44806) Fixes https://github.com/flutter/flutter/issues/131906 *List which issues are fixed by this PR. You must list at least one issue.* *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style --- .../lib/web_ui/lib/src/engine/dom.dart | 8 +++++ .../src/engine/text_editing/text_editing.dart | 30 ++++++++++++++----- .../web_ui/test/engine/text_editing_test.dart | 18 +++++++---- 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/dom.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/dom.dart index 46f85d0ec0..c5b4411a97 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/dom.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/dom.dart @@ -2068,6 +2068,10 @@ extension DomHTMLTextAreaElementExtension on DomHTMLTextAreaElement { external set _name(JSString value); set name(String value) => _name = value.toJS; + @JS('selectionDirection') + external JSString? get _selectionDirection; + String? get selectionDirection => _selectionDirection?.toDart; + @JS('selectionStart') external JSNumber? get _selectionStart; double? get selectionStart => _selectionStart?.toDartDouble; @@ -2704,6 +2708,10 @@ extension DomHTMLInputElementExtension on DomHTMLInputElement { external set _autocomplete(JSString value); set autocomplete(String value) => _autocomplete = value.toJS; + @JS('selectionDirection') + external JSString? get _selectionDirection; + String? get selectionDirection => _selectionDirection?.toDart; + @JS('selectionStart') external JSNumber? get _selectionStart; double? get selectionStart => _selectionStart?.toDartDouble; diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/text_editing/text_editing.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/text_editing/text_editing.dart index f3edb13e75..bc094ea1cb 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/text_editing/text_editing.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/text_editing/text_editing.dart @@ -770,17 +770,31 @@ class EditingState { factory EditingState.fromDomElement(DomHTMLElement? domElement) { if (domInstanceOfString(domElement, 'HTMLInputElement')) { final DomHTMLInputElement element = domElement! as DomHTMLInputElement; - return EditingState( - text: element.value, - baseOffset: element.selectionStart?.toInt(), - extentOffset: element.selectionEnd?.toInt()); + if (element.selectionDirection == 'backward') { + return EditingState( + text: element.value, + baseOffset: element.selectionEnd?.toInt(), + extentOffset: element.selectionStart?.toInt()); + } else { + return EditingState( + text: element.value, + baseOffset: element.selectionStart?.toInt(), + extentOffset: element.selectionEnd?.toInt()); + } } else if (domInstanceOfString(domElement, 'HTMLTextAreaElement')) { final DomHTMLTextAreaElement element = domElement! as DomHTMLTextAreaElement; - return EditingState( - text: element.value, - baseOffset: element.selectionStart?.toInt(), - extentOffset: element.selectionEnd?.toInt()); + if (element.selectionDirection == 'backward') { + return EditingState( + text: element.value, + baseOffset: element.selectionEnd?.toInt(), + extentOffset: element.selectionStart?.toInt()); + } else { + return EditingState( + text: element.value, + baseOffset: element.selectionStart?.toInt(), + extentOffset: element.selectionEnd?.toInt()); + } } else { throw UnsupportedError('Initialized with unsupported input type'); } diff --git a/engine/src/flutter/lib/web_ui/test/engine/text_editing_test.dart b/engine/src/flutter/lib/web_ui/test/engine/text_editing_test.dart index ce45d12df3..1c3df325cd 100644 --- a/engine/src/flutter/lib/web_ui/test/engine/text_editing_test.dart +++ b/engine/src/flutter/lib/web_ui/test/engine/text_editing_test.dart @@ -2726,14 +2726,17 @@ Future testMain() async { final DomHTMLInputElement input = defaultTextEditingRoot.querySelector('input')! as DomHTMLInputElement; input.value = 'Test'; - input.selectionStart = 1; - input.selectionEnd = 2; + input.setSelectionRange(1, 2); editingState = EditingState.fromDomElement(input); - expect(editingState.text, 'Test'); expect(editingState.baseOffset, 1); expect(editingState.extentOffset, 2); + + input.setSelectionRange(1, 2, 'backward'); + editingState = EditingState.fromDomElement(input); + expect(editingState.baseOffset, 2); + expect(editingState.extentOffset, 1); }); test('Get Editing State from text area element', () { @@ -2747,14 +2750,17 @@ Future testMain() async { final DomHTMLTextAreaElement input = defaultTextEditingRoot.querySelector('textarea')! as DomHTMLTextAreaElement; input.value = 'Test'; - input.selectionStart = 1; - input.selectionEnd = 2; + input.setSelectionRange(1, 2); editingState = EditingState.fromDomElement(input); - expect(editingState.text, 'Test'); expect(editingState.baseOffset, 1); expect(editingState.extentOffset, 2); + + input.setSelectionRange(1, 2, 'backward'); + editingState = EditingState.fromDomElement(input); + expect(editingState.baseOffset, 2); + expect(editingState.extentOffset, 1); }); group('comparing editing states', () {