updating editing state after location change. focusing on the element (flutter/engine#20620)

This commit is contained in:
nturgut 2020-08-19 14:03:30 -07:00 committed by GitHub
parent 7d3b44dd47
commit 2919c3bbef
2 changed files with 69 additions and 1 deletions

View File

@ -614,10 +614,15 @@ class GloballyPositionedTextEditingStrategy extends DefaultTextEditingStrategy {
@override
void placeElement() {
super.placeElement();
if (hasAutofillGroup) {
_geometry?.applyToDomElement(focusedFormElement!);
placeForm();
// Set the last editing state if it exists, this is critical for a
// users ongoing work to continue uninterrupted when there is an update to
// the transform.
if (_lastEditingState != null) {
_lastEditingState!.applyToDomElement(domElement);
}
// On Chrome, when a form is focused, it opens an autofill menu
// immediately.
// Flutter framework sends `setEditableSizeAndTransform` for informing
@ -627,7 +632,9 @@ class GloballyPositionedTextEditingStrategy extends DefaultTextEditingStrategy {
// `setEditableSizeAndTransform` method is called and focus on the form
// only after placing it to the correct position. Hence autofill menu
// does not appear on top-left of the page.
// Refocus on the elements after applying the geometry.
focusedFormElement!.focus();
domElement.focus();
} else {
_geometry?.applyToDomElement(domElement);
}
@ -663,6 +670,12 @@ class SafariDesktopTextEditingStrategy extends DefaultTextEditingStrategy {
_geometry?.applyToDomElement(domElement);
if (hasAutofillGroup) {
placeForm();
// Set the last editing state if it exists, this is critical for a
// users ongoing work to continue uninterrupted when there is an update to
// the transform.
if (_lastEditingState != null) {
_lastEditingState!.applyToDomElement(domElement);
}
// On Safari Desktop, when a form is focused, it opens an autofill menu
// immediately.
// Flutter framework sends `setEditableSizeAndTransform` for informing
@ -1236,6 +1249,12 @@ class FirefoxTextEditingStrategy extends GloballyPositionedTextEditingStrategy {
void placeElement() {
domElement.focus();
_geometry?.applyToDomElement(domElement);
// Set the last editing state if it exists, this is critical for a
// users ongoing work to continue uninterrupted when there is an update to
// the transform.
if (_lastEditingState != null) {
_lastEditingState!.applyToDomElement(domElement);
}
}
}

View File

@ -1013,6 +1013,55 @@ void testMain() {
expect(formsOnTheDom, hasLength(1));
});
test(
'singleTextField Autofill setEditableSizeAndTransform preserves'
'editing state', () {
// Create a configuration with focused element has autofil hint.
final Map<String, dynamic> flutterSingleAutofillElementConfig =
createFlutterConfig('text', autofillHint: 'username');
final MethodCall setClient = MethodCall('TextInput.setClient',
<dynamic>[123, flutterSingleAutofillElementConfig]);
sendFrameworkMessage(codec.encodeMethodCall(setClient));
const MethodCall setEditingState1 =
MethodCall('TextInput.setEditingState', <String, dynamic>{
'text': 'abcd',
'selectionBase': 2,
'selectionExtent': 3,
});
sendFrameworkMessage(codec.encodeMethodCall(setEditingState1));
const MethodCall show = MethodCall('TextInput.show');
sendFrameworkMessage(codec.encodeMethodCall(show));
// The second [setEditingState] should override the first one.
checkInputEditingState(
textEditing.editingElement.domElement, 'abcd', 2, 3);
// The transform is changed. For example after a validation error, red
// line appeared under the input field.
final MethodCall setSizeAndTransform =
configureSetSizeAndTransformMethodCall(150, 50,
Matrix4.translationValues(10.0, 20.0, 30.0).storage.toList());
sendFrameworkMessage(codec.encodeMethodCall(setSizeAndTransform));
// Check the element still has focus. User can keep editing.
expect(document.activeElement, textEditing.editingElement.domElement);
// Check the cursor location is the same.
checkInputEditingState(
textEditing.editingElement.domElement, 'abcd', 2, 3);
const MethodCall clearClient = MethodCall('TextInput.clearClient');
sendFrameworkMessage(codec.encodeMethodCall(clearClient));
// Confirm that [HybridTextEditing] didn't send any messages.
expect(spy.messages, isEmpty);
// Form stays on the DOM until autofill context is finalized.
expect(document.getElementsByTagName('form'), isNotEmpty);
expect(formsOnTheDom, hasLength(1));
});
test(
'multiTextField Autofill: setClient, setEditingState, show, '
'setEditingState, clearClient', () {