Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion lib/web_ui/lib/src/engine/text_editing/text_editing.dart
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ class EngineAutofillForm {
this.elements,
this.items,
this.formIdentifier = '',
this.insertionReferenceNode,
});

final DomHTMLFormElement formElement;
Expand All @@ -153,6 +154,7 @@ class EngineAutofillForm {

final Map<String, AutofillInfo>? items;

final DomHTMLElement? insertionReferenceNode;
/// Identifier for the form.
///
/// It is constructed by concatenating unique ids of input elements on the
Expand Down Expand Up @@ -189,6 +191,7 @@ class EngineAutofillForm {
final Map<String, DomHTMLElement> elements = <String, DomHTMLElement>{};
final Map<String, AutofillInfo> items = <String, AutofillInfo>{};
final DomHTMLFormElement formElement = createDomHTMLFormElement();
DomHTMLElement? insertionReferenceNode;

// Validation is in the framework side.
formElement.noValidate = true;
Expand All @@ -209,6 +212,7 @@ class EngineAutofillForm {
AutofillInfo.fromFrameworkMessage(focusedElementAutofill);

if (fields != null) {
bool fieldIsFocusedElement = false;
for (final Map<String, dynamic> field in
fields.cast<Map<String, dynamic>>()) {
final Map<String, dynamic> autofillInfo = field.readJson('autofill');
Expand All @@ -234,6 +238,17 @@ class EngineAutofillForm {
items[autofill.uniqueIdentifier] = autofill;
elements[autofill.uniqueIdentifier] = htmlElement;
formElement.append(htmlElement);

// We want to track the node in the position directly after our focused
// element, so we can later insert that element in the correct position
// right before this node.
if(fieldIsFocusedElement){
insertionReferenceNode = htmlElement;
fieldIsFocusedElement = false;
}
} else {
// current field is the focused element that we create elsewhere
fieldIsFocusedElement = true;
}
}
} else {
Expand Down Expand Up @@ -268,16 +283,21 @@ class EngineAutofillForm {

formElement.append(submitButton);

// If the focused node is at the end of the form, we'll default to inserting
// it before the submit field.
insertionReferenceNode ??= submitButton;

return EngineAutofillForm(
formElement: formElement,
elements: elements,
items: items,
formIdentifier: formIdentifier,
insertionReferenceNode: insertionReferenceNode
);
}

void placeForm(DomHTMLElement mainTextEditingElement) {
formElement.append(mainTextEditingElement);
formElement.insertBefore(mainTextEditingElement, insertionReferenceNode);
defaultTextEditingRoot.append(formElement);
}

Expand Down
41 changes: 41 additions & 0 deletions lib/web_ui/test/engine/text_editing_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2176,6 +2176,47 @@ Future<void> testMain() async {
expect(autofillForm, isNull);
});

test('placeForm() should place element in correct position', () {
final List<dynamic> fields = createFieldValues(<String>[
'email',
'username',
'password',
], <String>[
'field1',
'field2',
'field3'
]);
final EngineAutofillForm autofillForm =
EngineAutofillForm.fromFrameworkMessage(
createAutofillInfo('email', 'field1'), fields)!;

expect(autofillForm.elements, hasLength(2));

List<DomHTMLInputElement> formChildNodes =
autofillForm.formElement.childNodes.toList() as List<DomHTMLInputElement>;

// Only username, password, submit nodes are created
expect(formChildNodes, hasLength(3));
expect(formChildNodes[0].name, 'username');
expect(formChildNodes[1].name, 'current-password');
expect(formChildNodes[2].type, 'submit');
// insertion point for email should be before username
expect(autofillForm.insertionReferenceNode, formChildNodes[0]);

final DomHTMLInputElement testInputElement = createDomHTMLInputElement();
testInputElement.name = 'email';
autofillForm.placeForm(testInputElement);

formChildNodes = autofillForm.formElement.childNodes.toList()
as List<DomHTMLInputElement>;
// email node should be placed before username
expect(formChildNodes, hasLength(4));
expect(formChildNodes[0].name, 'email');
expect(formChildNodes[1].name, 'username');
expect(formChildNodes[2].name, 'current-password');
expect(formChildNodes[3].type, 'submit');
});

tearDown(() {
clearForms();
});
Expand Down