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
75 changes: 70 additions & 5 deletions lib/web_ui/lib/src/engine/semantics/text_field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,70 @@

part of engine;

/// Text editing used by accesibility mode.
///
/// [SemanticsTextEditingStrategy] assumes the caller will own the creation,
/// insertion and disposal of the DOM element. Due to this
/// [initializeElementPlacement], [initializeTextEditing] and
/// [disable] strategies are handled differently.
///
/// This class is still responsible for hooking up the DOM element with the
/// [HybridTextEditing] instance so that changes are communicated to Flutter.
class SemanticsTextEditingStrategy extends DefaultTextEditingStrategy {
/// Creates a [SemanticsTextEditingStrategy] that eagerly instantiates
/// [domElement] so the caller can insert it before calling
/// [SemanticsTextEditingStrategy.enable].
SemanticsTextEditingStrategy(
HybridTextEditing owner, html.HtmlElement domElement)
: super(owner) {
// Make sure the DOM element is of a type that we support for text editing.
// TODO(yjbanov): move into initializer list when https://github.com/dart-lang/sdk/issues/37881 is fixed.
assert((domElement is html.InputElement) ||
(domElement is html.TextAreaElement));
super.domElement = domElement;
}

@override
void disable() {
// We don't want to remove the DOM element because the caller is responsible
// for that.
//
// Remove focus from the editable element to cause the keyboard to hide.
// Otherwise, the keyboard stays on screen even when the user navigates to
// a different screen (e.g. by hitting the "back" button).
domElement.blur();
}

@override
void initializeElementPlacement() {
// Element placement is done by [TextField].
}

@override
void initializeTextEditing(InputConfiguration inputConfig,
{_OnChangeCallback onChange, _OnActionCallback onAction}) {
// In accesibilty mode, the user of this class is supposed to insert the
// [domElement] on their own. Let's make sure they did.
assert(domElement != null);
assert(html.document.body.contains(domElement));

isEnabled = true;
_inputConfiguration = inputConfig;
_onChange = onChange;
_onAction = onAction;

domElement.focus();
}

@override
void setEditingState(EditingState editingState) {
super.setEditingState(editingState);

// Refocus after setting editing state.
domElement.focus();
}
}

/// Manages semantics objects that represent editable text fields.
///
/// This role is implemented via a content-editable HTML element. This role does
Expand All @@ -19,15 +83,15 @@ class TextField extends RoleManager {
semanticsObject.hasFlag(ui.SemanticsFlag.isMultiline)
? html.TextAreaElement()
: html.InputElement();
persistentTextEditingElement = PersistentTextEditingElement(
textEditingElement = SemanticsTextEditingStrategy(
textEditing,
editableDomElement,
);
_setupDomElement();
}

PersistentTextEditingElement persistentTextEditingElement;
html.Element get _textFieldElement => persistentTextEditingElement.domElement;
SemanticsTextEditingStrategy textEditingElement;
html.Element get _textFieldElement => textEditingElement.domElement;

void _setupDomElement() {
// On iOS, even though the semantic text field is transparent, the cursor
Expand Down Expand Up @@ -61,6 +125,7 @@ class TextField extends RoleManager {
switch (browserEngine) {
case BrowserEngine.blink:
case BrowserEngine.edge:
case BrowserEngine.ie11:
case BrowserEngine.firefox:
case BrowserEngine.ie11:
case BrowserEngine.unknown:
Expand All @@ -82,7 +147,7 @@ class TextField extends RoleManager {
return;
}

textEditing.useCustomEditableElement(persistentTextEditingElement);
textEditing.useCustomEditableElement(textEditingElement);
ui.window
.onSemanticsAction(semanticsObject.id, ui.SemanticsAction.tap, null);
});
Expand All @@ -98,7 +163,7 @@ class TextField extends RoleManager {
num lastTouchStartOffsetY;

_textFieldElement.addEventListener('touchstart', (html.Event event) {
textEditing.useCustomEditableElement(persistentTextEditingElement);
textEditing.useCustomEditableElement(textEditingElement);
final html.TouchEvent touchEvent = event;
lastTouchStartOffsetX = touchEvent.changedTouches.last.client.x;
lastTouchStartOffsetY = touchEvent.changedTouches.last.client.y;
Expand Down
Loading