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

Commit 1b30923

Browse files
committed
[web] Migrate Flutter Web DOM usage to JS static interop - 31.
1 parent f399a20 commit 1b30923

File tree

7 files changed

+96
-68
lines changed

7 files changed

+96
-68
lines changed

lib/web_ui/lib/src/engine/dom.dart

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ extension DomHTMLDocumentExtension on DomHTMLDocument {
9999
external DomHTMLHeadElement? get head;
100100
external DomHTMLBodyElement? get body;
101101
external set title(String? value);
102+
List<DomNode> getElementsByTagName(String tag) =>
103+
js_util.callMethod<List<Object?>>(
104+
this, 'getElementsByTagName', <Object>[tag]).cast<DomNode>();
102105
}
103106

104107
@JS('document')
@@ -124,6 +127,8 @@ extension DomEventTargetExtension on DomEventTarget {
124127
<Object>[type, listener, if (useCapture != null) useCapture]);
125128
}
126129
}
130+
131+
external bool dispatchEvent(DomEvent event);
127132
}
128133

129134
typedef DomEventListener = void Function(DomEvent event);
@@ -223,12 +228,10 @@ extension DomElementExtension on DomElement {
223228
external set tabIndex(int? value);
224229
external int? get tabIndex;
225230
external void focus();
226-
int get scrollTop =>
227-
js_util.getProperty(this, 'scrollTop').round();
231+
int get scrollTop => js_util.getProperty(this, 'scrollTop').round();
228232
set scrollTop(int value) =>
229233
js_util.setProperty<int>(this, 'scrollTop', value.round());
230-
int get scrollLeft =>
231-
js_util.getProperty(this, 'scrollLeft').round();
234+
int get scrollLeft => js_util.getProperty(this, 'scrollLeft').round();
232235
set scrollLeft(int value) =>
233236
js_util.setProperty<int>(this, 'scrollLeft', value.round());
234237
}
@@ -933,11 +936,19 @@ class DomMouseEvent extends DomUIEvent {}
933936
extension DomMouseEventExtension on DomMouseEvent {
934937
external num get clientX;
935938
external num get clientY;
939+
external num get offsetX;
940+
external num get offsetY;
941+
DomPoint get client => DomPoint(clientX, clientY);
942+
DomPoint get offset => DomPoint(offsetX, offsetY);
936943
external int get button;
937944
external int? get buttons;
938945
external bool getModifierState(String keyArg);
939946
}
940947

948+
DomMouseEvent createDomMouseEvent(String type, [Map<dynamic, dynamic>? init]) =>
949+
js_util.callConstructor(domGetConstructor('MouseEvent')!,
950+
<Object>[type, if (init != null) js_util.jsify(init)]);
951+
941952
@JS()
942953
@staticInterop
943954
class DomPointerEvent extends DomMouseEvent {}
@@ -953,6 +964,11 @@ extension DomPointerEventExtension on DomPointerEvent {
953964
this, 'getCoalescedEvents', <Object>[]).cast<DomPointerEvent>();
954965
}
955966

967+
DomPointerEvent createDomPointerEvent(String type,
968+
[Map<dynamic, dynamic>? init]) =>
969+
js_util.callConstructor(domGetConstructor('PointerEvent')!,
970+
<Object>[type, if (init != null) js_util.jsify(init)]);
971+
956972
@JS()
957973
@staticInterop
958974
class DomWheelEvent extends DomMouseEvent {}
@@ -979,10 +995,15 @@ class DomTouch {}
979995

980996
extension DomTouchExtension on DomTouch {
981997
external int? get identifier;
982-
external num? get clientX;
983-
external num? get clientY;
998+
external num get clientX;
999+
external num get clientY;
1000+
DomPoint get client => DomPoint(clientX, clientY);
9841001
}
9851002

1003+
DomTouchEvent createDomTouchEvent(String type, [Map<dynamic, dynamic>? init]) =>
1004+
js_util.callConstructor(domGetConstructor('TouchEvent')!,
1005+
<Object>[type, if (init != null) js_util.jsify(init)]);
1006+
9861007
@JS()
9871008
@staticInterop
9881009
class DomHTMLInputElement extends DomHTMLElement {}
@@ -1000,6 +1021,13 @@ extension DomHTMLInputElementExtension on DomHTMLInputElement {
10001021
DomHTMLInputElement createDomHTMLInputElement() =>
10011022
domDocument.createElement('input') as DomHTMLInputElement;
10021023

1024+
class DomPoint {
1025+
final num x;
1026+
final num y;
1027+
1028+
DomPoint(this.x, this.y);
1029+
}
1030+
10031031
Object? domGetConstructor(String constructorName) =>
10041032
js_util.getProperty(domWindow, constructorName);
10051033

lib/web_ui/lib/src/engine/embedder.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ class FlutterViewEmbedder {
311311

312312
final html.Element _accessibilityPlaceholder = EngineSemanticsOwner
313313
.instance.semanticsHelper
314-
.prepareAccessibilityPlaceholder();
314+
.prepareAccessibilityPlaceholder() as html.Element;
315315

316316
glassPaneElementHostNode.nodes.addAll(<html.Node>[
317317
_accessibilityPlaceholder,

lib/web_ui/lib/src/engine/pointer_binding.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -867,8 +867,8 @@ class _TouchAdapter extends _BaseAdapter {
867867
kind: ui.PointerDeviceKind.touch,
868868
signalKind: ui.PointerSignalKind.none,
869869
device: touch.identifier!,
870-
physicalX: touch.clientX!.toDouble() * ui.window.devicePixelRatio,
871-
physicalY: touch.clientY!.toDouble() * ui.window.devicePixelRatio,
870+
physicalX: touch.clientX.toDouble() * ui.window.devicePixelRatio,
871+
physicalY: touch.clientY.toDouble() * ui.window.devicePixelRatio,
872872
buttons: pressed ? _kPrimaryMouseButton : 0,
873873
pressure: 1.0,
874874
pressureMin: 0.0,

lib/web_ui/lib/src/engine/semantics/semantics.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1675,7 +1675,7 @@ class EngineSemanticsOwner {
16751675
_temporarilyDisableBrowserGestureMode();
16761676
}
16771677

1678-
return semanticsHelper.shouldEnableSemantics(event as html.Event);
1678+
return semanticsHelper.shouldEnableSemantics(event);
16791679
}
16801680

16811681
/// Callbacks called when the [GestureMode] changes.

lib/web_ui/lib/src/engine/semantics/semantics_helper.dart

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
// found in the LICENSE file.
44

55
import 'dart:async';
6-
import 'dart:html' as html;
76

87
import 'package:meta/meta.dart';
98

109
import '../browser_detection.dart';
10+
import '../dom.dart';
11+
import '../safe_browser_api.dart';
1112
import 'semantics.dart';
1213

1314
/// The maximum [semanticsActivationAttempts] before we give up waiting for
@@ -50,11 +51,11 @@ class SemanticsHelper {
5051
_semanticsEnabler = semanticsEnabler;
5152
}
5253

53-
bool shouldEnableSemantics(html.Event event) {
54+
bool shouldEnableSemantics(DomEvent event) {
5455
return _semanticsEnabler.shouldEnableSemantics(event);
5556
}
5657

57-
html.Element prepareAccessibilityPlaceholder() {
58+
DomElement prepareAccessibilityPlaceholder() {
5859
return _semanticsEnabler.prepareAccessibilityPlaceholder();
5960
}
6061

@@ -75,9 +76,9 @@ abstract class SemanticsEnabler {
7576
/// Semantics should be enabled if the web engine is no longer waiting for
7677
/// extra signals from the user events. See [isWaitingToEnableSemantics].
7778
///
78-
/// Or if the received [html.Event] is suitable/enough for enabling the
79+
/// Or if the received [DomEvent] is suitable/enough for enabling the
7980
/// semantics. See [tryEnableSemantics].
80-
bool shouldEnableSemantics(html.Event event) {
81+
bool shouldEnableSemantics(DomEvent event) {
8182
if (!isWaitingToEnableSemantics) {
8283
// Forward to framework as normal.
8384
return true;
@@ -90,15 +91,15 @@ abstract class SemanticsEnabler {
9091
///
9192
/// Returns true if the `event` is not related to semantics activation and
9293
/// should be forwarded to the framework.
93-
bool tryEnableSemantics(html.Event event);
94+
bool tryEnableSemantics(DomEvent event);
9495

9596
/// Creates the placeholder for accessibility.
9697
///
9798
/// Puts it inside the glasspane.
9899
///
99100
/// On focus the element announces that accessibility can be enabled by
100101
/// tapping/clicking. (Announcement depends on the assistive technology)
101-
html.Element prepareAccessibilityPlaceholder();
102+
DomElement prepareAccessibilityPlaceholder();
102103

103104
/// Whether platform is still considering enabling semantics.
104105
///
@@ -123,14 +124,14 @@ abstract class SemanticsEnabler {
123124
@visibleForTesting
124125
class DesktopSemanticsEnabler extends SemanticsEnabler {
125126
/// A temporary placeholder used to capture a request to activate semantics.
126-
html.Element? _semanticsPlaceholder;
127+
DomElement? _semanticsPlaceholder;
127128

128129
/// Whether we are waiting for the user to enable semantics.
129130
@override
130131
bool get isWaitingToEnableSemantics => _semanticsPlaceholder != null;
131132

132133
@override
133-
bool tryEnableSemantics(html.Event event) {
134+
bool tryEnableSemantics(DomEvent event) {
134135
// Semantics may be enabled programmatically. If there's a race between that
135136
// and the DOM event, we may end up here while there's no longer a placeholder
136137
// to work with.
@@ -173,15 +174,15 @@ class DesktopSemanticsEnabler extends SemanticsEnabler {
173174
}
174175

175176
@override
176-
html.Element prepareAccessibilityPlaceholder() {
177-
final html.Element placeholder =
178-
_semanticsPlaceholder = html.Element.tag('flt-semantics-placeholder');
177+
DomElement prepareAccessibilityPlaceholder() {
178+
final DomElement placeholder =
179+
_semanticsPlaceholder = createDomElement('flt-semantics-placeholder');
179180

180181
// Only listen to "click" because other kinds of events are reported via
181182
// PointerBinding.
182-
placeholder.addEventListener('click', (html.Event event) {
183+
placeholder.addEventListener('click', allowInterop((DomEvent event) {
183184
tryEnableSemantics(event);
184-
}, true);
185+
}), true);
185186

186187
// Adding roles to semantics placeholder. 'aria-live' will make sure that
187188
// the content is announced to the assistive technology user as soon as the
@@ -226,7 +227,7 @@ class MobileSemanticsEnabler extends SemanticsEnabler {
226227
Timer? semanticsActivationTimer;
227228

228229
/// A temporary placeholder used to capture a request to activate semantics.
229-
html.Element? _semanticsPlaceholder;
230+
DomElement? _semanticsPlaceholder;
230231

231232
/// The number of events we processed that could potentially activate
232233
/// semantics.
@@ -247,7 +248,7 @@ class MobileSemanticsEnabler extends SemanticsEnabler {
247248
bool get isWaitingToEnableSemantics => _semanticsPlaceholder != null;
248249

249250
@override
250-
bool tryEnableSemantics(html.Event event) {
251+
bool tryEnableSemantics(DomEvent event) {
251252
// Semantics may be enabled programmatically. If there's a race between that
252253
// and the DOM event, we may end up here while there's no longer a placeholder
253254
// to work with.
@@ -320,29 +321,29 @@ class MobileSemanticsEnabler extends SemanticsEnabler {
320321
// semantics tree is designed to not interfere with Flutter's gesture
321322
// detection.
322323
bool enableConditionPassed = false;
323-
html.Point<num> activationPoint;
324+
late final DomPoint activationPoint;
324325

325326
switch (event.type) {
326327
case 'click':
327-
final html.MouseEvent click = event as html.MouseEvent;
328+
final DomMouseEvent click = event as DomMouseEvent;
328329
activationPoint = click.offset;
329330
break;
330331
case 'touchstart':
331332
case 'touchend':
332-
final html.TouchEvent touch = event as html.TouchEvent;
333-
activationPoint = touch.changedTouches!.first.client;
333+
final DomTouchEvent touchEvent = event as DomTouchEvent;
334+
activationPoint = touchEvent.changedTouches!.first.client;
334335
break;
335336
case 'pointerdown':
336337
case 'pointerup':
337-
final html.PointerEvent touch = event as html.PointerEvent;
338-
activationPoint = html.Point<num>(touch.client.x, touch.client.y);
338+
final DomPointerEvent touch = event as DomPointerEvent;
339+
activationPoint = touch.client;
339340
break;
340341
default:
341342
// The event is not relevant, forward to framework as normal.
342343
return true;
343344
}
344345

345-
final html.Rectangle<num> activatingElementRect =
346+
final DomRect activatingElementRect =
346347
_semanticsPlaceholder!.getBoundingClientRect();
347348
final double midX = (activatingElementRect.left +
348349
(activatingElementRect.right - activatingElementRect.left) / 2)
@@ -372,15 +373,15 @@ class MobileSemanticsEnabler extends SemanticsEnabler {
372373
}
373374

374375
@override
375-
html.Element prepareAccessibilityPlaceholder() {
376-
final html.Element placeholder =
377-
_semanticsPlaceholder = html.Element.tag('flt-semantics-placeholder');
376+
DomElement prepareAccessibilityPlaceholder() {
377+
final DomElement placeholder =
378+
_semanticsPlaceholder = createDomElement('flt-semantics-placeholder');
378379

379380
// Only listen to "click" because other kinds of events are reported via
380381
// PointerBinding.
381-
placeholder.addEventListener('click', (html.Event event) {
382+
placeholder.addEventListener('click', allowInterop((DomEvent event) {
382383
tryEnableSemantics(event);
383-
}, true);
384+
}), true);
384385

385386
placeholder
386387
..setAttribute('role', 'button')

0 commit comments

Comments
 (0)