From f5ebbe936af34bd2a8106e96bf15879be5214a87 Mon Sep 17 00:00:00 2001 From: Satsrag Date: Thu, 6 Jun 2024 20:42:22 +0800 Subject: [PATCH 1/3] fix: TapTextFieldTapRegion not working on ios safari/chrome/webview --- lib/web_ui/lib/src/engine/text_editing/text_editing.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/web_ui/lib/src/engine/text_editing/text_editing.dart b/lib/web_ui/lib/src/engine/text_editing/text_editing.dart index da49e877b2d7c..013154e4ba675 100644 --- a/lib/web_ui/lib/src/engine/text_editing/text_editing.dart +++ b/lib/web_ui/lib/src/engine/text_editing/text_editing.dart @@ -1707,7 +1707,7 @@ class IOSTextEditingStrategy extends GloballyPositionedTextEditingStrategy { subscriptions.add(DomSubscription(activeDomElement, 'blur', (_) { final bool isFastCallback = blurWatch.elapsed < _blurFastCallbackInterval; - if (windowHasFocus && isFastCallback) { + if (windowHasFocus || isFastCallback) { activeDomElement.focus(); } else { owner.sendTextConnectionClosedToFrameworkIfAny(); From a96e7dfd2680c3e741e8121dad696680b575fdab Mon Sep 17 00:00:00 2001 From: Satsrag Date: Mon, 17 Jun 2024 20:14:57 +0800 Subject: [PATCH 2/3] fix TapTextFieldTapRegion is not working by whether or not the window has touched just before the blur event --- lib/web_ui/lib/src/engine/dom.dart | 5 +++-- .../src/engine/text_editing/text_editing.dart | 20 ++++++++++++++----- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/lib/web_ui/lib/src/engine/dom.dart b/lib/web_ui/lib/src/engine/dom.dart index d008d5ae1c271..66759af2808c6 100644 --- a/lib/web_ui/lib/src/engine/dom.dart +++ b/lib/web_ui/lib/src/engine/dom.dart @@ -3080,10 +3080,11 @@ extension DomScreenOrientationExtension on DomScreenOrientation { // remove the listener. class DomSubscription { DomSubscription( - this.target, String typeString, DartDomEventListener dartListener) + this.target, String typeString, DartDomEventListener dartListener, + {bool userCapture = false}) : type = typeString.toJS, listener = createDomEventListener(dartListener) { - target._addEventListener1(type, listener); + target.addEventListener(typeString, listener, userCapture); } final JSString type; diff --git a/lib/web_ui/lib/src/engine/text_editing/text_editing.dart b/lib/web_ui/lib/src/engine/text_editing/text_editing.dart index 013154e4ba675..e644276f3c0a3 100644 --- a/lib/web_ui/lib/src/engine/text_editing/text_editing.dart +++ b/lib/web_ui/lib/src/engine/text_editing/text_editing.dart @@ -1687,6 +1687,11 @@ class IOSTextEditingStrategy extends GloballyPositionedTextEditingStrategy { // Record start time of blur subscription. final Stopwatch blurWatch = Stopwatch()..start(); + final Stopwatch touchWatch = Stopwatch()..start(); + + subscriptions.add(DomSubscription(domDocument, 'touchstart', userCapture: true, (_) { + touchWatch.reset(); + })); // On iOS, blur is trigerred in the following cases: // @@ -1695,10 +1700,14 @@ class IOSTextEditingStrategy extends GloballyPositionedTextEditingStrategy { // so we close the input connection with the framework. // 2. The user taps on another focusable element. In this case, we refocus // the input field and wait for the framework to manage the focus change. - // 3. The virtual keyboard is closed by tapping "done". We can't detect this - // programmatically, so we end up refocusing the input field. This is - // okay because the virtual keyboard will hide, and as soon as the user - // taps the text field again, the virtual keyboard will come up. + // 3. The virtual keyboard is closed by tapping "done". We detect this by + // whether or not the window has touched just before the blur event. If + // the window has been touched just now, we know that the user has not + // tapped the "done" button on the virtual keyboard. In this case, we + // refocus the input field and wait for the framework to manage the focus + // change. If the window has not been touched, we know that the user has + // tapped the "done" button, so we close the input connection with the + // framework. // 4. Safari sometimes sends a blur event immediately after activating the // input field. In this case, we want to keep the focus on the input field. // In order to detect this, we measure how much time has passed since the @@ -1707,7 +1716,8 @@ class IOSTextEditingStrategy extends GloballyPositionedTextEditingStrategy { subscriptions.add(DomSubscription(activeDomElement, 'blur', (_) { final bool isFastCallback = blurWatch.elapsed < _blurFastCallbackInterval; - if (windowHasFocus || isFastCallback) { + final bool isTouchWindowJustNow = touchWatch.elapsed < _blurFastCallbackInterval; + if (windowHasFocus && (isFastCallback || isTouchWindowJustNow)) { activeDomElement.focus(); } else { owner.sendTextConnectionClosedToFrameworkIfAny(); From 3dd2f43e7ee06005aa7caba65cf6fcba4da7675a Mon Sep 17 00:00:00 2001 From: Satsrag Date: Fri, 21 Jun 2024 19:03:24 +0800 Subject: [PATCH 3/3] added test --- lib/web_ui/test/engine/text_editing_test.dart | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/web_ui/test/engine/text_editing_test.dart b/lib/web_ui/test/engine/text_editing_test.dart index ac93b4c0c0657..57226f2c539fe 100644 --- a/lib/web_ui/test/engine/text_editing_test.dart +++ b/lib/web_ui/test/engine/text_editing_test.dart @@ -929,6 +929,15 @@ Future testMain() async { textEditing!.strategy.domElement, 'abcd', 2, 3); expect(textEditing!.isEditing, isTrue); + // touchstart event is dispatched to the DOM element. + domDocument.dispatchEvent(createDomEvent('Event', 'touchstart')); + // No connection close message sent. + expect(spy.messages, hasLength(0)); + await Future.delayed(Duration.zero); + // DOM element still keeps the focus. + expect(defaultTextEditingRoot.ownerDocument?.activeElement, + textEditing!.strategy.domElement); + // Delay for not to be a fast callback with blur. await Future.delayed(const Duration(milliseconds: 200)); // DOM element is blurred.