Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit a33158b

Browse files
committed
Add documentation, extract _transferFocusToViewRoot to an external method, instead of creating a closure every time.
1 parent de1a724 commit a33158b

File tree

1 file changed

+60
-25
lines changed

1 file changed

+60
-25
lines changed

lib/web_ui/lib/src/engine/view_embedder/flutter_view_manager.dart

Lines changed: 60 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -108,37 +108,72 @@ class FlutterViewManager {
108108
const String viewRootSelector =
109109
'${DomManager.flutterViewTagName}[${GlobalHtmlAttributes.flutterViewIdAttributeName}]';
110110
final DomElement? viewRoot = element?.closest(viewRootSelector);
111-
final String? viewIdAttribute = viewRoot?.getAttribute(GlobalHtmlAttributes.flutterViewIdAttributeName);
112-
final int? viewId = viewIdAttribute == null ? null : int.parse(viewIdAttribute);
113-
return viewId == null ? null : _viewData[viewId];
111+
if (viewRoot == null) {
112+
// `element` is not inside any flutter view.
113+
return null;
114+
}
115+
116+
final String? viewIdAttribute = viewRoot.getAttribute(GlobalHtmlAttributes.flutterViewIdAttributeName);
117+
assert(viewIdAttribute != null, 'Located Flutter view is missing its id attribute.');
118+
119+
final int? viewId = int.tryParse(viewIdAttribute!);
120+
assert(viewId != null, 'Flutter view id must be a valid int.');
121+
122+
return _viewData[viewId];
114123
}
115124

116-
/// Safely manages focus when blurring and optionally removing a DOM element.
125+
/// Attempts to transfer focus (blur) from [element] to its
126+
/// [EngineFlutterView] DOM's `rootElement`.
127+
///
128+
/// This focus "transfer" achieves two things:
129+
///
130+
/// * Ensures the focus is preserved within the Flutter View when blurring
131+
/// elements that are part of the internal DOM structure of the Flutter
132+
/// app. This...
133+
/// * Prevents the Flutter engine from reporting bogus "blur" events from the
134+
/// Flutter View because, by default, calling "blur" on an element moves the
135+
/// document.currentElement to the `body` of the page.
117136
///
118-
/// This function ensures the blur operation doesn't disrupt the framework's view focus management.
137+
/// See: https://jsfiddle.net/ditman/1e2swpno for a JS-only demonstration.
119138
///
120-
/// * [removeElement] controls whether the element is removed from the DOM after being blurred.
121-
/// * [delayed] controls whether the engine will be given the opportunity to focus on another element first.
122-
void safelyBlurElement(DomElement element, {bool removeElement = false, bool delayed = true}) {
123-
final EngineFlutterView? view = findViewForElement(element);
124-
125-
void blur() {
126-
// If by the time the timer fired the focused element is no longer the
127-
// editing element whose editing session was disabled, there's no need to
128-
// move the focus, as it is likely that another widget already took the
129-
// focus.
130-
if (element == domDocument.activeElement) {
131-
view?.dom.rootElement.focusWithoutScroll();
132-
}
133-
if (removeElement) {
134-
element.remove();
135-
}
139+
/// When [removeElement] is true, `element` will be removed from the DOM after
140+
/// its focus is transferred to the root of the view. This can be used to
141+
/// safely remove (potentially focused) element, by preserving focus within
142+
/// the Flutter view.
143+
///
144+
/// When [delayed] is true, the blur operation is executed asynchronously as
145+
/// soon as possible (see [Timer.run]). Else it runs immediately.
146+
void safelyBlurElement(
147+
DomElement element, {
148+
bool removeElement = false,
149+
bool delayed = true
150+
}) {
151+
if (delayed) {
152+
Timer.run(() {
153+
_transferFocusToViewRoot(element, removeElement: removeElement);
154+
});
155+
return;
136156
}
157+
_transferFocusToViewRoot(element, removeElement: removeElement);
158+
}
137159

138-
if (delayed) {
139-
Timer(Duration.zero, blur);
140-
} else {
141-
blur();
160+
// The actual implementation of [safelyBlurElement].
161+
void _transferFocusToViewRoot(
162+
DomElement element, {
163+
required bool removeElement
164+
}) {
165+
// If by the time this method is called the focused element is no longer
166+
// `element`, there's no need to move the focus.
167+
//
168+
// This can happen when another element grabs focus when this method runs
169+
// "delayed".
170+
if (element == domDocument.activeElement) {
171+
final EngineFlutterView? view = findViewForElement(element);
172+
// Transfer the browser focus to the root element of `view`
173+
view?.dom.rootElement.focusWithoutScroll();
174+
}
175+
if (removeElement) {
176+
element.remove();
142177
}
143178
}
144179

0 commit comments

Comments
 (0)