[web] Migrate Flutter Web DOM usage to JS static interop - 23. (flutter/engine#33351)

This commit is contained in:
joshualitt 2022-06-02 10:06:49 -07:00 committed by GitHub
parent 1a229d9b48
commit 15280cb88e
4 changed files with 67 additions and 40 deletions

View File

@ -20,7 +20,7 @@ import 'package:js/js_util.dart' as js_util;
@JS()
@staticInterop
class DomWindow {}
class DomWindow extends DomEventTarget {}
extension DomWindowExtension on DomWindow {
external DomConsole get console;
@ -122,6 +122,8 @@ class DomEvent {}
extension DomEventExtension on DomEvent {
external DomEventTarget? get target;
external num? get timeStamp;
external String get type;
external void preventDefault();
external void stopPropagation();
}
@ -315,7 +317,7 @@ extension DomCSSStyleDeclarationExtension on DomCSSStyleDeclaration {
String get flexDirection => getPropertyValue('flex-direction');
String get alignItems => getPropertyValue('align-items');
String get margin => getPropertyValue('margin');
String get background=> getPropertyValue('background');
String get background => getPropertyValue('background');
external String getPropertyValue(String property);
void setProperty(String propertyName, String value, [String? priority]) {
@ -670,6 +672,27 @@ extension DomResponseExtension on DomResponse {
js_util.promiseToFuture(js_util.callMethod(this, 'text', <Object>[]));
}
@JS()
@staticInterop
class DomUIEvent extends DomEvent {}
@JS()
@staticInterop
class DomKeyboardEvent extends DomUIEvent {}
extension DomKeyboardEventExtension on DomKeyboardEvent {
external bool get altKey;
external String? get code;
external bool get ctrlKey;
external String? get key;
external int get keyCode;
external int get location;
external bool get metaKey;
external bool? get repeat;
external bool get shiftKey;
external bool getModifierState(String keyArg);
}
Object? domGetConstructor(String constructorName) =>
js_util.getProperty(domWindow, constructorName);

View File

@ -337,7 +337,7 @@ class FlutterViewEmbedder {
}
PointerBinding.initInstance(glassPaneElement as html.Element);
KeyboardBinding.initInstance(glassPaneElement as html.Element);
KeyboardBinding.initInstance(glassPaneElement);
if (html.window.visualViewport == null && isWebKit) {
// Older Safari versions sometimes give us bogus innerWidth/innerHeight

View File

@ -3,11 +3,12 @@
// found in the LICENSE file.
import 'dart:async';
import 'dart:html' as html;
import 'dart:typed_data';
import '../engine.dart' show registerHotRestartListener;
import 'dom.dart';
import 'platform_dispatcher.dart';
import 'safe_browser_api.dart';
import 'services.dart';
/// Provides keyboard bindings, such as the `flutter/keyevent` channel.
@ -29,19 +30,19 @@ class Keyboard {
/// if no repeat events were received.
final Map<String, Timer> _keydownTimers = <String, Timer>{};
html.EventListener? _keydownListener;
html.EventListener? _keyupListener;
DomEventListener? _keydownListener;
DomEventListener? _keyupListener;
Keyboard._(this._onMacOs) {
_keydownListener = (html.Event event) {
_keydownListener = allowInterop((DomEvent event) {
_handleHtmlEvent(event);
};
html.window.addEventListener('keydown', _keydownListener);
});
domWindow.addEventListener('keydown', _keydownListener);
_keyupListener = (html.Event event) {
_keyupListener = allowInterop((DomEvent event) {
_handleHtmlEvent(event);
};
html.window.addEventListener('keyup', _keyupListener);
});
domWindow.addEventListener('keyup', _keyupListener);
registerHotRestartListener(() {
dispose();
});
@ -52,8 +53,8 @@ class Keyboard {
/// After calling this method this object becomes unusable and [instance]
/// becomes `null`. Call [initialize] again to initialize a new singleton.
void dispose() {
html.window.removeEventListener('keydown', _keydownListener);
html.window.removeEventListener('keyup', _keyupListener);
domWindow.removeEventListener('keydown', _keydownListener);
domWindow.removeEventListener('keyup', _keyupListener);
for (final String key in _keydownTimers.keys) {
_keydownTimers[key]!.cancel();
@ -86,12 +87,12 @@ class Keyboard {
return _onMacOs;
}
void _handleHtmlEvent(html.Event event) {
if (event is! html.KeyboardEvent) {
void _handleHtmlEvent(DomEvent event) {
if (!domInstanceOfString(event, 'KeyboardEvent')) {
return;
}
final html.KeyboardEvent keyboardEvent = event;
final DomKeyboardEvent keyboardEvent = event as DomKeyboardEvent;
final String timerKey = keyboardEvent.code!;
// Don't handle synthesizing a keyup event for modifier keys
@ -146,7 +147,7 @@ class Keyboard {
);
}
void _synthesizeKeyup(html.KeyboardEvent event) {
void _synthesizeKeyup(DomKeyboardEvent event) {
final Map<String, dynamic> eventData = <String, dynamic>{
'type': 'keyup',
'keymap': 'web',
@ -179,7 +180,7 @@ const int modifierCapsLock = 0x20;
const int modifierScrollLock = 0x40;
/// Creates a bitmask representing the meta state of the [event].
int _getMetaState(html.KeyboardEvent event) {
int _getMetaState(DomKeyboardEvent event) {
int metaState = _modifierNone;
if (event.getModifierState('Shift')) {
metaState |= _modifierShift;
@ -211,7 +212,7 @@ int _getMetaState(html.KeyboardEvent event) {
///
/// Modifier keys are shift, alt, ctrl and meta/cmd/win. These are the keys used
/// to perform keyboard shortcuts (e.g. `cmd+c`, `cmd+l`).
bool _isModifierKey(html.KeyboardEvent event) {
bool _isModifierKey(DomKeyboardEvent event) {
final String key = event.key!;
return key == 'Meta' || key == 'Shift' || key == 'Alt' || key == 'Control';
}
@ -219,7 +220,7 @@ bool _isModifierKey(html.KeyboardEvent event) {
/// Returns true if the [event] is been affects by any of the modifiers key
///
/// This is a strong indication that this key is been used for a shortcut
bool _isAffectedByModifiers(html.KeyboardEvent event) {
bool _isAffectedByModifiers(DomKeyboardEvent event) {
return event.ctrlKey || event.shiftKey || event.altKey || event.metaKey;
}

View File

@ -8,8 +8,10 @@ import 'package:ui/ui.dart' as ui;
import '../engine.dart' show registerHotRestartListener;
import 'browser_detection.dart';
import 'dom.dart';
import 'key_map.dart';
import 'platform_dispatcher.dart';
import 'safe_browser_api.dart';
import 'semantics.dart';
typedef _VoidCallback = void Function();
@ -92,7 +94,7 @@ class KeyboardBinding {
static KeyboardBinding? get instance => _instance;
static KeyboardBinding? _instance;
static void initInstance(html.Element glassPaneElement) {
static void initInstance(DomElement glassPaneElement) {
if (_instance == null) {
_instance = KeyboardBinding._(glassPaneElement);
assert(() {
@ -106,30 +108,31 @@ class KeyboardBinding {
_setup();
}
final html.Element glassPaneElement;
final DomElement glassPaneElement;
late KeyboardConverter _converter;
final Map<String, html.EventListener> _listeners = <String, html.EventListener>{};
final Map<String, DomEventListener> _listeners = <String, DomEventListener>{};
void _addEventListener(String eventName, html.EventListener handler) {
dynamic loggedHandler(html.Event event) {
void _addEventListener(String eventName, DomEventListener handler) {
dynamic loggedHandler(DomEvent event) {
if (_debugLogKeyEvents) {
print(event.type);
}
if (EngineSemanticsOwner.instance.receiveGlobalEvent(event)) {
if (EngineSemanticsOwner.instance.receiveGlobalEvent(event as html.Event)) {
return handler(event);
}
return null;
}
final DomEventListener wrappedHandler = allowInterop(loggedHandler);
assert(!_listeners.containsKey(eventName));
_listeners[eventName] = loggedHandler;
html.window.addEventListener(eventName, loggedHandler, true);
_listeners[eventName] = wrappedHandler;
domWindow.addEventListener(eventName, wrappedHandler, true);
}
/// Remove all active event listeners.
void _clearListeners() {
_listeners.forEach((String eventName, html.EventListener listener) {
html.window.removeEventListener(eventName, listener, true);
_listeners.forEach((String eventName, DomEventListener listener) {
domWindow.removeEventListener(eventName, listener, true);
});
_listeners.clear();
}
@ -143,12 +146,12 @@ class KeyboardBinding {
}
void _setup() {
_addEventListener('keydown', (html.Event event) {
return _converter.handleEvent(FlutterHtmlKeyboardEvent(event as html.KeyboardEvent));
});
_addEventListener('keyup', (html.Event event) {
return _converter.handleEvent(FlutterHtmlKeyboardEvent(event as html.KeyboardEvent));
});
_addEventListener('keydown', allowInterop((DomEvent event) {
return _converter.handleEvent(FlutterHtmlKeyboardEvent(event as DomKeyboardEvent));
}));
_addEventListener('keyup', allowInterop((DomEvent event) {
return _converter.handleEvent(FlutterHtmlKeyboardEvent(event as DomKeyboardEvent));
}));
_converter = KeyboardConverter(_onKeyData, onMacOs: operatingSystem == OperatingSystem.macOs);
}
@ -168,12 +171,12 @@ class AsyncKeyboardDispatching {
final _VoidCallback? callback;
}
// A wrapper of [html.KeyboardEvent] with reduced methods delegated to the event
// A wrapper of [DomKeyboardEvent] with reduced methods delegated to the event
// for the convenience of testing.
class FlutterHtmlKeyboardEvent {
FlutterHtmlKeyboardEvent(this._event);
final html.KeyboardEvent _event;
final DomKeyboardEvent _event;
String get type => _event.type;
String? get code => _event.code;
@ -190,7 +193,7 @@ class FlutterHtmlKeyboardEvent {
void preventDefault() => _event.preventDefault();
}
// Reads [html.KeyboardEvent], then [dispatches ui.KeyData] accordingly.
// Reads [DomKeyboardEvent], then [dispatches ui.KeyData] accordingly.
//
// The events are read through [handleEvent], and dispatched through the
// [dispatchKeyData] as given in the constructor. Some key data might be