Skip to content

Commit

Permalink
Revert "[web] Don't overwrite editing state with semantic updates (fl…
Browse files Browse the repository at this point in the history
…utter#38271)" (flutter#38562)

This reverts commit 45713ea.
  • Loading branch information
XilaiZhang authored Dec 29, 2022
1 parent e012dc8 commit 5713a21
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 99 deletions.
11 changes: 10 additions & 1 deletion lib/web_ui/lib/src/engine/semantics/text_field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,11 @@ class TextField extends RoleManager {
// element, so that both the framework and the browser agree on what's
// currently focused.
bool needsDomFocusRequest = false;

final EditingState editingState = EditingState(
text: semanticsObject.value,
baseOffset: semanticsObject.textSelectionBase,
extentOffset: semanticsObject.textSelectionExtent,
);
if (semanticsObject.hasFocus) {
if (!_hasFocused) {
_hasFocused = true;
Expand All @@ -374,9 +378,14 @@ class TextField extends RoleManager {
if (domDocument.activeElement != editableElement) {
needsDomFocusRequest = true;
}
// Focused elements should have full text editing state applied.
SemanticsTextEditingStrategy.instance.setEditingState(editingState);
} else if (_hasFocused) {
SemanticsTextEditingStrategy.instance.deactivate(this);

// Only apply text, because this node is not focused.
editingState.applyTextToDomElement(editableElement);

if (_hasFocused && domDocument.activeElement == editableElement) {
// Unlike `editableElement.focus()` we don't need to schedule `blur`
// post-update because `document.activeElement` implies that the
Expand Down
101 changes: 3 additions & 98 deletions lib/web_ui/test/engine/semantics/text_field_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

@TestOn('chrome || safari || firefox')

import 'dart:typed_data';

import 'package:test/bootstrap/browser.dart';
import 'package:test/test.dart';

Expand Down Expand Up @@ -50,11 +48,6 @@ void testMain() {
testTextEditing.configuration = singlelineConfig;
});

/// Emulates sending of a message by the framework to the engine.
void sendFrameworkMessage(ByteData? message) {
testTextEditing.channel.handleTextInput(message, (ByteData? data) {});
}

test('renders a text field', () async {
semantics()
..debugOverrideTimestampFunction(() => _testTime)
Expand Down Expand Up @@ -134,7 +127,7 @@ void testMain() {
// TODO(yjbanov): https://github.com/flutter/flutter/issues/50754
skip: browserEngine != BrowserEngine.blink);

test('Syncs semantic state from framework', () async {
test('Syncs editing state from framework', () async {
semantics()
..debugOverrideTimestampFunction(() => _testTime)
..semanticsEnabled = true;
Expand Down Expand Up @@ -166,6 +159,7 @@ void testMain() {
expect(domDocument.activeElement, flutterViewEmbedder.glassPaneElement);
expect(appHostNode.activeElement, strategy.domElement);
expect(textField.editableElement, strategy.domElement);
expect((textField.editableElement as dynamic).value, 'hello');
expect(textField.editableElement.getAttribute('aria-label'), 'greeting');
expect(textField.editableElement.style.width, '10px');
expect(textField.editableElement.style.height, '15px');
Expand All @@ -180,6 +174,7 @@ void testMain() {
expect(domDocument.activeElement, domDocument.body);
expect(appHostNode.activeElement, null);
expect(strategy.domElement, null);
expect((textField.editableElement as dynamic).value, 'bye');
expect(textField.editableElement.getAttribute('aria-label'), 'farewell');
expect(textField.editableElement.style.width, '12px');
expect(textField.editableElement.style.height, '17px');
Expand All @@ -193,92 +188,6 @@ void testMain() {
expect(actionCount, 0);
});

test(
'Does not overwrite text value and selection editing state on semantic updates',
() async {
semantics()
..debugOverrideTimestampFunction(() => _testTime)
..semanticsEnabled = true;

strategy.enable(
singlelineConfig,
onChange: (_, __) {},
onAction: (_) {},
);

final SemanticsObject textFieldSemantics = createTextFieldSemantics(
value: 'hello',
textSelectionBase: 1,
textSelectionExtent: 3,
isFocused: true,
rect: const ui.Rect.fromLTWH(0, 0, 10, 15));

final TextField textField =
textFieldSemantics.debugRoleManagerFor(Role.textField)! as TextField;
final DomHTMLInputElement editableElement =
textField.editableElement as DomHTMLInputElement;

expect(editableElement, strategy.domElement);
expect(editableElement.value, '');
expect(editableElement.selectionStart, 0);
expect(editableElement.selectionEnd, 0);

strategy.disable();
semantics().semanticsEnabled = false;
});

test(
'Updates editing state when receiving framework messages from the text input channel',
() async {
semantics()
..debugOverrideTimestampFunction(() => _testTime)
..semanticsEnabled = true;

expect(domDocument.activeElement, domDocument.body);
expect(appHostNode.activeElement, null);

strategy.enable(
singlelineConfig,
onChange: (_, __) {},
onAction: (_) {},
);

final SemanticsObject textFieldSemantics = createTextFieldSemantics(
value: 'hello',
textSelectionBase: 1,
textSelectionExtent: 3,
isFocused: true,
rect: const ui.Rect.fromLTWH(0, 0, 10, 15));

final TextField textField =
textFieldSemantics.debugRoleManagerFor(Role.textField)! as TextField;
final DomHTMLInputElement editableElement =
textField.editableElement as DomHTMLInputElement;

// No updates expected on semantic updates
expect(editableElement, strategy.domElement);
expect(editableElement.value, '');
expect(editableElement.selectionStart, 0);
expect(editableElement.selectionEnd, 0);

// Update from framework
const MethodCall setEditingState =
MethodCall('TextInput.setEditingState', <String, dynamic>{
'text': 'updated',
'selectionBase': 2,
'selectionExtent': 3,
});
sendFrameworkMessage(codec.encodeMethodCall(setEditingState));

// Editing state should now be updated
expect(editableElement.value, 'updated');
expect(editableElement.selectionStart, 2);
expect(editableElement.selectionEnd, 3);

strategy.disable();
semantics().semanticsEnabled = false;
});

test('Gives up focus after DOM blur', () async {
semantics()
..debugOverrideTimestampFunction(() => _testTime)
Expand Down Expand Up @@ -537,8 +446,6 @@ SemanticsObject createTextFieldSemantics({
bool isFocused = false,
bool isMultiline = false,
ui.Rect rect = const ui.Rect.fromLTRB(0, 0, 100, 50),
int textSelectionBase = 0,
int textSelectionExtent = 0,
}) {
final SemanticsTester tester = SemanticsTester(semantics());
tester.updateNode(
Expand All @@ -551,8 +458,6 @@ SemanticsObject createTextFieldSemantics({
hasTap: true,
rect: rect,
textDirection: ui.TextDirection.ltr,
textSelectionBase: textSelectionBase,
textSelectionExtent: textSelectionExtent
);
tester.apply();
return tester.getSemanticsObject(0);
Expand Down

0 comments on commit 5713a21

Please sign in to comment.