Unverified Commit bec24367 authored by Mouad Debbar's avatar Mouad Debbar Committed by GitHub

[web] Migrate framework to fully use package:web (#128901)

Remove `dom.dart`'s JS interop definitions in favor of `package:web`.

Part of https://github.com/flutter/flutter/issues/113402
Part of https://github.com/flutter/flutter/issues/127030
parent 5140b0f0
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
import 'dart:ui' as ui; import 'dart:ui' as ui;
import '../services/dom.dart'; import 'package:web/web.dart' as web;
import 'platform.dart' as platform; import 'platform.dart' as platform;
...@@ -40,7 +40,7 @@ final platform.TargetPlatform? _testPlatform = () { ...@@ -40,7 +40,7 @@ final platform.TargetPlatform? _testPlatform = () {
// 0.20ms. As `defaultTargetPlatform` is routinely called dozens of times per // 0.20ms. As `defaultTargetPlatform` is routinely called dozens of times per
// frame this value should be cached. // frame this value should be cached.
final platform.TargetPlatform _browserPlatform = () { final platform.TargetPlatform _browserPlatform = () {
final String navigatorPlatform = domWindow.navigator.platform?.toLowerCase() ?? ''; final String navigatorPlatform = web.window.navigator.platform.toLowerCase();
if (navigatorPlatform.startsWith('mac')) { if (navigatorPlatform.startsWith('mac')) {
return platform.TargetPlatform.macOS; return platform.TargetPlatform.macOS;
} }
...@@ -60,7 +60,7 @@ final platform.TargetPlatform _browserPlatform = () { ...@@ -60,7 +60,7 @@ final platform.TargetPlatform _browserPlatform = () {
// indicates that a device has a "fine pointer" (mouse) as the primary // indicates that a device has a "fine pointer" (mouse) as the primary
// pointing device, then we'll assume desktop linux, and otherwise we'll // pointing device, then we'll assume desktop linux, and otherwise we'll
// assume Android. // assume Android.
if (domWindow.matchMedia('only screen and (pointer: fine)').matches) { if (web.window.matchMedia('only screen and (pointer: fine)').matches) {
return platform.TargetPlatform.linux; return platform.TargetPlatform.linux;
} }
return platform.TargetPlatform.android; return platform.TargetPlatform.android;
......
...@@ -7,17 +7,17 @@ import 'dart:js_interop'; ...@@ -7,17 +7,17 @@ import 'dart:js_interop';
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:web/web.dart' as web;
import '../services/dom.dart';
import 'image_provider.dart' as image_provider; import 'image_provider.dart' as image_provider;
import 'image_stream.dart'; import 'image_stream.dart';
/// Creates a type for an overridable factory function for testing purposes. /// Creates a type for an overridable factory function for testing purposes.
typedef HttpRequestFactory = DomXMLHttpRequest Function(); typedef HttpRequestFactory = web.XMLHttpRequest Function();
/// Default HTTP client. /// Default HTTP client.
DomXMLHttpRequest _httpClient() { web.XMLHttpRequest _httpClient() {
return DomXMLHttpRequest(); return web.XMLHttpRequest();
} }
/// Creates an overridable factory function. /// Creates an overridable factory function.
...@@ -135,9 +135,9 @@ class NetworkImage ...@@ -135,9 +135,9 @@ class NetworkImage
// We use a different method when headers are set because the // We use a different method when headers are set because the
// `ui.webOnlyInstantiateImageCodecFromUrl` method is not capable of handling headers. // `ui.webOnlyInstantiateImageCodecFromUrl` method is not capable of handling headers.
if (isCanvasKit || containsNetworkImageHeaders) { if (isCanvasKit || containsNetworkImageHeaders) {
final Completer<DomXMLHttpRequest> completer = final Completer<web.XMLHttpRequest> completer =
Completer<DomXMLHttpRequest>(); Completer<web.XMLHttpRequest>();
final DomXMLHttpRequest request = httpRequestFactory(); final web.XMLHttpRequest request = httpRequestFactory();
request.open('GET', key.url, true); request.open('GET', key.url, true);
request.responseType = 'arraybuffer'; request.responseType = 'arraybuffer';
...@@ -147,9 +147,9 @@ class NetworkImage ...@@ -147,9 +147,9 @@ class NetworkImage
}); });
} }
request.addEventListener('load', createDomEventListener((DomEvent e) { request.addEventListener('load', (web.Event e) {
final int? status = request.status; final int status = request.status;
final bool accepted = status! >= 200 && status < 300; final bool accepted = status >= 200 && status < 300;
final bool fileUri = status == 0; // file:// URIs have status of 0. final bool fileUri = status == 0; // file:// URIs have status of 0.
final bool notModified = status == 304; final bool notModified = status == 304;
final bool unknownRedirect = status > 307 && status < 400; final bool unknownRedirect = status > 307 && status < 400;
...@@ -161,12 +161,11 @@ class NetworkImage ...@@ -161,12 +161,11 @@ class NetworkImage
} else { } else {
completer.completeError(e); completer.completeError(e);
throw image_provider.NetworkImageLoadException( throw image_provider.NetworkImageLoadException(
statusCode: request.status ?? 400, uri: resolved); statusCode: status, uri: resolved);
} }
})); }.toJS);
request.addEventListener('error', request.addEventListener('error', completer.completeError.toJS);
createDomEventListener(completer.completeError));
request.send(); request.send();
...@@ -176,7 +175,7 @@ class NetworkImage ...@@ -176,7 +175,7 @@ class NetworkImage
if (bytes.lengthInBytes == 0) { if (bytes.lengthInBytes == 0) {
throw image_provider.NetworkImageLoadException( throw image_provider.NetworkImageLoadException(
statusCode: request.status!, uri: resolved); statusCode: request.status, uri: resolved);
} }
if (decode != null) { if (decode != null) {
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:js_interop';
/// This file includes static interop helpers for Flutter Web.
// TODO(joshualitt): This file will eventually be removed,
// https://github.com/flutter/flutter/issues/113402.
/// [DomWindow] interop object.
@JS()
@staticInterop
class DomWindow {}
/// [DomWindow] required extension.
extension DomWindowExtension on DomWindow {
@JS('matchMedia')
external DomMediaQueryList _matchMedia(JSString? query);
/// Returns a [DomMediaQueryList] of the media that matches [query].
DomMediaQueryList matchMedia(String? query) => _matchMedia(query?.toJS);
/// Returns the [DomNavigator] associated with this window.
external DomNavigator get navigator;
/// Gets the current selection.
external DomSelection? getSelection();
}
/// The underyling window.
@JS('window')
external DomWindow get domWindow;
/// [DomMediaQueryList] interop object.
@JS()
@staticInterop
class DomMediaQueryList {}
/// [DomMediaQueryList] required extension.
extension DomMediaQueryListExtension on DomMediaQueryList {
@JS('matches')
external JSBoolean get _matches;
/// Whether or not the query matched.
bool get matches => _matches.toDart;
}
/// [DomNavigator] interop object.
@JS()
@staticInterop
class DomNavigator {}
/// [DomNavigator] required extension.
extension DomNavigatorExtension on DomNavigator {
@JS('platform')
external JSString? get _platform;
/// The underyling platform string.
String? get platform => _platform?.toDart;
}
/// A DOM event target.
@JS()
@staticInterop
class DomEventTarget {}
/// [DomEventTarget]'s required extension.
extension DomEventTargetExtension on DomEventTarget {
@JS('addEventListener')
external JSVoid _addEventListener1(JSString type, DomEventListener? listener);
@JS('addEventListener')
external JSVoid _addEventListener2(
JSString type, DomEventListener? listener, JSBoolean useCapture);
/// Adds an event listener to this event target.
@JS('addEventListener')
void addEventListener(String type, DomEventListener? listener,
[bool? useCapture]) {
if (listener != null) {
if (useCapture == null) {
_addEventListener1(type.toJS, listener);
} else {
_addEventListener2(type.toJS, listener, useCapture.toJS);
}
}
}
}
/// [DomXMLHttpRequest] interop class.
@JS('XMLHttpRequest')
@staticInterop
class DomXMLHttpRequest extends DomEventTarget {
/// Constructor for [DomXMLHttpRequest].
external factory DomXMLHttpRequest();
}
/// [DomXMLHttpRequest] extension.
extension DomXMLHttpRequestExtension on DomXMLHttpRequest {
/// Gets the response.
external JSAny? get response;
@JS('responseText')
external JSString? get _responseText;
/// Gets the response text.
String? get responseText => _responseText?.toDart;
@JS('responseType')
external JSString get _responseType;
/// Gets the response type.
String get responseType => _responseType.toDart;
@JS('status')
external JSNumber? get _status;
/// Gets the status.
int? get status => _status?.toDart.toInt();
@JS('responseType')
external set _responseType(JSString value);
/// Set the response type.
set responseType(String value) => _responseType = value.toJS;
@JS('setRequestHeader')
external void _setRequestHeader(JSString header, JSString value);
/// Set the request header.
void setRequestHeader(String header, String value) =>
_setRequestHeader(header.toJS, value.toJS);
@JS('open')
external JSVoid _open(JSString method, JSString url, JSBoolean isAsync);
/// Open the request.
void open(String method, String url, bool isAsync) =>
_open(method.toJS, url.toJS, isAsync.toJS);
/// Send the request.
external JSVoid send();
}
/// Type for event listener.
typedef DartDomEventListener = JSVoid Function(DomEvent event);
/// The type of [JSFunction] expected as an `EventListener`.
@JS()
@staticInterop
class DomEventListener {}
/// Creates a [DomEventListener] from a [DartDomEventListener].
DomEventListener createDomEventListener(DartDomEventListener listener) =>
listener.toJS as DomEventListener;
/// [DomEvent] interop object.
@JS()
@staticInterop
class DomEvent {}
/// [DomEvent] required extension.
extension DomEventExtension on DomEvent {
@JS('type')
external JSString get _type;
/// Get the event type.
String get type => _type.toDart;
/// Initialize an event.
external JSVoid initEvent(
JSString type, JSBoolean bubbles, JSBoolean cancelable);
}
/// [DomProgressEvent] interop object.
@JS()
@staticInterop
class DomProgressEvent extends DomEvent {}
/// [DomProgressEvent] required extension.
extension DomProgressEventExtension on DomProgressEvent {
@JS('loaded')
external JSNumber? get _loaded;
/// Amount of work done.
int? get loaded => _loaded?.toDart.toInt();
@JS('total')
external JSNumber? get _total;
/// Total amount of work.
int? get total => _total?.toDart.toInt();
}
/// The underlying DOM document.
@JS()
@staticInterop
class DomDocument {}
/// [DomDocument]'s required extension.
extension DomDocumentExtension on DomDocument {
@JS('createEvent')
external DomEvent _createEvent(JSString eventType);
/// Creates an event.
DomEvent createEvent(String eventType) => _createEvent(eventType.toJS);
/// Creates a range.
external DomRange createRange();
/// Gets the head element.
external DomHTMLHeadElement? get head;
/// Creates a [DomElement].
@JS('createElement')
external DomElement createElement(JSString name);
}
/// Returns the top level document.
@JS('window.document')
external DomDocument get domDocument;
/// Creates a new DOM event.
DomEvent createDomEvent(String type, String name) {
final DomEvent event = domDocument.createEvent(type);
event.initEvent(name.toJS, true.toJS, true.toJS);
return event;
}
/// A Range object.
@JS()
@staticInterop
class DomRange {}
/// [DomRange]'s required extension.
extension DomRangeExtension on DomRange {
/// Selects the provided node.
external JSVoid selectNode(DomNode node);
}
/// A node in the DOM.
@JS()
@staticInterop
class DomNode extends DomEventTarget {}
/// [DomNode]'s required extension.
extension DomNodeExtension on DomNode {
@JS('innerText')
external set _innerText(JSString text);
/// Sets the innerText of this node.
set innerText(String text) => _innerText = text.toJS;
/// Appends a node this node.
external JSVoid append(DomNode node);
}
/// An element in the DOM.
@JS()
@staticInterop
class DomElement extends DomNode {}
/// [DomElement]'s required extension.
extension DomElementExtension on DomElement {
/// Returns the style of this element.
external DomCSSStyleDeclaration get style;
/// Returns the class list of this element.
external DomTokenList get classList;
}
/// An HTML element in the DOM.
@JS()
@staticInterop
class DomHTMLElement extends DomElement {}
/// A UI event.
@JS()
@staticInterop
class DomUIEvent extends DomEvent {}
/// A mouse event.
@JS()
@staticInterop
class DomMouseEvent extends DomUIEvent {}
/// [DomMouseEvent]'s required extension.
extension DomMouseEventExtension on DomMouseEvent {
@JS('offsetX')
external JSNumber get _offsetX;
/// Returns the current x offset.
num get offsetX => _offsetX.toDart;
@JS('offsetY')
external JSNumber get _offsetY;
/// Returns the current y offset.
num get offsetY => _offsetY.toDart;
@JS('button')
external JSNumber get _button;
/// Returns the current button.
int get button => _button.toDart.toInt();
}
/// A DOM selection.
@JS()
@staticInterop
class DomSelection {}
/// [DomSelection]'s required extension.
extension DomSelectionExtension on DomSelection {
/// Removes all ranges from this selection.
external JSVoid removeAllRanges();
/// Adds a range to this selection.
external JSVoid addRange(DomRange range);
}
/// A DOM html div element.
@JS()
@staticInterop
class DomHTMLDivElement extends DomHTMLElement {}
/// Factory constructor for [DomHTMLDivElement].
DomHTMLDivElement createDomHTMLDivElement() =>
domDocument.createElement('div'.toJS) as DomHTMLDivElement;
/// An html style element.
@JS()
@staticInterop
class DomHTMLStyleElement extends DomHTMLElement {}
/// [DomHTMLStyleElement]'s required extension.
extension DomHTMLStyleElementExtension on DomHTMLStyleElement {
/// Get's the style sheet of this element.
external DomStyleSheet? get sheet;
}
/// Factory constructor for [DomHTMLStyleElement].
DomHTMLStyleElement createDomHTMLStyleElement() =>
domDocument.createElement('style'.toJS) as DomHTMLStyleElement;
/// CSS styles.
@JS()
@staticInterop
class DomCSSStyleDeclaration {}
/// [DomCSSStyleDeclaration]'s required extension.
extension DomCSSStyleDeclarationExtension on DomCSSStyleDeclaration {
/// Sets the width.
set width(String value) => setProperty('width', value);
/// Sets the height.
set height(String value) => setProperty('height', value);
@JS('setProperty')
external JSVoid _setProperty(
JSString propertyName, JSString value, JSString priority);
/// Sets a CSS property by name.
void setProperty(String propertyName, String value, [String? priority]) {
priority ??= '';
_setProperty(propertyName.toJS, value.toJS, priority.toJS);
}
}
/// The HTML head element.
@JS()
@staticInterop
class DomHTMLHeadElement extends DomHTMLElement {}
/// A DOM style sheet.
@JS()
@staticInterop
class DomStyleSheet {}
/// A DOM CSS style sheet.
@JS()
@staticInterop
class DomCSSStyleSheet extends DomStyleSheet {}
/// [DomCSSStyleSheet]'s required extension.
extension DomCSSStyleSheetExtension on DomCSSStyleSheet {
@JS('insertRule')
external JSNumber _insertRule1(JSString rule);
@JS('insertRule')
external JSNumber _insertRule2(JSString rule, JSNumber index);
/// Inserts a rule into this style sheet.
int insertRule(String rule, [int? index]) {
if (index == null) {
return _insertRule1(rule.toJS).toDart.toInt();
} else {
return _insertRule2(rule.toJS, index.toDouble().toJS).toDart.toInt();
}
}
}
/// A list of token.
@JS()
@staticInterop
class DomTokenList {}
/// [DomTokenList]'s required extension.
extension DomTokenListExtension on DomTokenList {
@JS('add')
external JSVoid _add(JSString value);
/// Adds a token to this token list.
void add(String value) => _add(value.toJS);
}
...@@ -2,11 +2,12 @@ ...@@ -2,11 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:js_interop';
import 'dart:ui_web' as ui_web; import 'dart:ui_web' as ui_web;
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:web/web.dart' as web;
import '../services/dom.dart';
import 'basic.dart'; import 'basic.dart';
import 'framework.dart'; import 'framework.dart';
import 'platform_view.dart'; import 'platform_view.dart';
...@@ -27,7 +28,7 @@ const String _kClassRule = ''' ...@@ -27,7 +28,7 @@ const String _kClassRule = '''
'''; ''';
const int _kRightClickButton = 2; const int _kRightClickButton = 2;
typedef _WebSelectionCallBack = void Function(DomHTMLElement, DomMouseEvent); typedef _WebSelectionCallBack = void Function(web.HTMLElement, web.MouseEvent);
/// Function signature for `ui_web.platformViewRegistry.registerViewFactory`. /// Function signature for `ui_web.platformViewRegistry.registerViewFactory`.
@visibleForTesting @visibleForTesting
...@@ -80,11 +81,11 @@ class PlatformSelectableRegionContextMenu extends StatelessWidget { ...@@ -80,11 +81,11 @@ class PlatformSelectableRegionContextMenu extends StatelessWidget {
// Registers the view factories for the interceptor widgets. // Registers the view factories for the interceptor widgets.
static void _register() { static void _register() {
assert(_registeredViewType == null); assert(_registeredViewType == null);
_registeredViewType = _registerWebSelectionCallback((DomHTMLElement element, DomMouseEvent event) { _registeredViewType = _registerWebSelectionCallback((web.HTMLElement element, web.MouseEvent event) {
final SelectionContainerDelegate? client = _activeClient; final SelectionContainerDelegate? client = _activeClient;
if (client != null) { if (client != null) {
// Converts the html right click event to flutter coordinate. // Converts the html right click event to flutter coordinate.
final Offset localOffset = Offset(event.offsetX.toDouble(), event.offsetY.toDouble()); final Offset localOffset = Offset(event.offsetX, event.offsetY);
final Matrix4 transform = client.getTransformTo(null); final Matrix4 transform = client.getTransformTo(null);
final Offset globalOffset = MatrixUtils.transformPoint(transform, localOffset); final Offset globalOffset = MatrixUtils.transformPoint(transform, localOffset);
client.dispatchSelectionEvent(SelectWordSelectionEvent(globalPosition: globalOffset)); client.dispatchSelectionEvent(SelectWordSelectionEvent(globalPosition: globalOffset));
...@@ -93,9 +94,9 @@ class PlatformSelectableRegionContextMenu extends StatelessWidget { ...@@ -93,9 +94,9 @@ class PlatformSelectableRegionContextMenu extends StatelessWidget {
element.innerText = client.getSelectedContent()?.plainText ?? ''; element.innerText = client.getSelectedContent()?.plainText ?? '';
// Programmatically select the dom element in browser. // Programmatically select the dom element in browser.
final DomRange range = domDocument.createRange(); final web.Range range = web.document.createRange();
range.selectNode(element); range.selectNode(element);
final DomSelection? selection = domWindow.getSelection(); final web.Selection? selection = web.window.getSelection();
if (selection != null) { if (selection != null) {
selection.removeAllRanges(); selection.removeAllRanges();
selection.addRange(range); selection.addRange(range);
...@@ -106,26 +107,26 @@ class PlatformSelectableRegionContextMenu extends StatelessWidget { ...@@ -106,26 +107,26 @@ class PlatformSelectableRegionContextMenu extends StatelessWidget {
static String _registerWebSelectionCallback(_WebSelectionCallBack callback) { static String _registerWebSelectionCallback(_WebSelectionCallBack callback) {
_registerViewFactory(_viewType, (int viewId) { _registerViewFactory(_viewType, (int viewId) {
final DomHTMLElement htmlElement = createDomHTMLDivElement(); final web.HTMLElement htmlElement = web.document.createElement('div') as web.HTMLElement;
htmlElement htmlElement
..style.width = '100%' ..style.width = '100%'
..style.height = '100%' ..style.height = '100%'
..classList.add(_kClassName); ..classList.add(_kClassName);
// Create css style for _kClassName. // Create css style for _kClassName.
final DomHTMLStyleElement styleElement = createDomHTMLStyleElement(); final web.HTMLStyleElement styleElement = web.document.createElement('style') as web.HTMLStyleElement;
domDocument.head!.append(styleElement); web.document.head!.append(styleElement);
final DomCSSStyleSheet sheet = styleElement.sheet! as DomCSSStyleSheet; final web.CSSStyleSheet sheet = styleElement.sheet!;
sheet.insertRule(_kClassRule, 0); sheet.insertRule(_kClassRule, 0);
sheet.insertRule(_kClassSelectionRule, 1); sheet.insertRule(_kClassSelectionRule, 1);
htmlElement.addEventListener('mousedown', createDomEventListener((DomEvent event) { htmlElement.addEventListener('mousedown', (web.Event event) {
final DomMouseEvent mouseEvent = event as DomMouseEvent; final web.MouseEvent mouseEvent = event as web.MouseEvent;
if (mouseEvent.button != _kRightClickButton) { if (mouseEvent.button != _kRightClickButton) {
return; return;
} }
callback(htmlElement, mouseEvent); callback(htmlElement, mouseEvent);
})); }.toJS);
return htmlElement; return htmlElement;
}, isVisible: false); }, isVisible: false);
return _viewType; return _viewType;
......
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/src/painting/_network_image_web.dart'; import 'package:flutter/src/painting/_network_image_web.dart';
import 'package:flutter/src/services/dom.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:web/web.dart' as web;
import '../image_data.dart'; import '../image_data.dart';
import '_test_http_request.dart'; import '_test_http_request.dart';
...@@ -20,7 +20,7 @@ void runTests() { ...@@ -20,7 +20,7 @@ void runTests() {
(WidgetTester tester) async { (WidgetTester tester) async {
final TestHttpRequest testHttpRequest = TestHttpRequest() final TestHttpRequest testHttpRequest = TestHttpRequest()
..status = 200 ..status = 200
..mockEvent = MockEvent('load', createDomEvent('Event', 'test error')) ..mockEvent = MockEvent('load', web.Event('test error'))
..response = (Uint8List.fromList(kTransparentImage)).buffer; ..response = (Uint8List.fromList(kTransparentImage)).buffer;
httpRequestFactory = () { httpRequestFactory = () {
...@@ -46,7 +46,7 @@ void runTests() { ...@@ -46,7 +46,7 @@ void runTests() {
(WidgetTester tester) async { (WidgetTester tester) async {
final TestHttpRequest testHttpRequest = TestHttpRequest() final TestHttpRequest testHttpRequest = TestHttpRequest()
..status = 404 ..status = 404
..mockEvent = MockEvent('error', createDomEvent('Event', 'test error')); ..mockEvent = MockEvent('error', web.Event('test error'));
httpRequestFactory = () { httpRequestFactory = () {
...@@ -64,14 +64,14 @@ void runTests() { ...@@ -64,14 +64,14 @@ void runTests() {
); );
await tester.pumpWidget(image); await tester.pumpWidget(image);
expect((tester.takeException() as DomProgressEvent).type, 'test error'); expect((tester.takeException() as web.ProgressEvent).type, 'test error');
}); });
testWidgets('loads an image from the network with empty response', testWidgets('loads an image from the network with empty response',
(WidgetTester tester) async { (WidgetTester tester) async {
final TestHttpRequest testHttpRequest = TestHttpRequest() final TestHttpRequest testHttpRequest = TestHttpRequest()
..status = 200 ..status = 200
..mockEvent = MockEvent('load', createDomEvent('Event', 'test error')) ..mockEvent = MockEvent('load', web.Event('test error'))
..response = (Uint8List.fromList(<int>[])).buffer; ..response = (Uint8List.fromList(<int>[])).buffer;
httpRequestFactory = () { httpRequestFactory = () {
......
...@@ -4,16 +4,16 @@ ...@@ -4,16 +4,16 @@
import 'dart:js_interop'; import 'dart:js_interop';
import 'package:flutter/src/services/dom.dart'; import 'package:web/web.dart' as web;
/// Defines a new property on an Object. /// Defines a new property on an Object.
@JS('Object.defineProperty') @JS('Object.defineProperty')
external JSVoid objectDefineProperty(JSAny o, JSString symbol, JSAny desc); external void objectDefineProperty(JSAny o, String symbol, JSAny desc);
void createGetter(JSAny mock, String key, JSAny? Function() get) { void createGetter(JSAny mock, String key, JSAny? Function() get) {
objectDefineProperty( objectDefineProperty(
mock, mock,
key.toJS, key,
<String, JSFunction>{ <String, JSFunction>{
'get': (() => get()).toJS, 'get': (() => get()).toJS,
}.jsify()!, }.jsify()!,
...@@ -35,6 +35,8 @@ class DomXMLHttpRequestMock { ...@@ -35,6 +35,8 @@ class DomXMLHttpRequestMock {
}); });
} }
typedef _DartDomEventListener = JSVoid Function(web.Event event);
class TestHttpRequest { class TestHttpRequest {
TestHttpRequest() { TestHttpRequest() {
_mock = DomXMLHttpRequestMock( _mock = DomXMLHttpRequestMock(
...@@ -60,26 +62,26 @@ class TestHttpRequest { ...@@ -60,26 +62,26 @@ class TestHttpRequest {
Object? response; Object? response;
Map<String, String> get responseHeaders => headers; Map<String, String> get responseHeaders => headers;
JSVoid open(JSString method, JSString url, JSBoolean async) {} JSVoid open(String method, String url, bool async) {}
JSVoid send() {} JSVoid send() {}
JSVoid setRequestHeader(JSString name, JSString value) { JSVoid setRequestHeader(String name, String value) {
headers[name.toDart] = value.toDart; headers[name] = value;
} }
JSVoid addEventListener(JSString type, DomEventListener listener) { JSVoid addEventListener(String type, web.EventListener listener) {
if (type.toDart == mockEvent?.type) { if (type == mockEvent?.type) {
final DartDomEventListener dartListener = final _DartDomEventListener dartListener =
(listener as JSExportedDartFunction).toDart as DartDomEventListener; (listener as JSExportedDartFunction).toDart as _DartDomEventListener;
dartListener(mockEvent!.event); dartListener(mockEvent!.event);
} }
} }
DomXMLHttpRequest getMock() => _mock as DomXMLHttpRequest; web.XMLHttpRequest getMock() => _mock as web.XMLHttpRequest;
} }
class MockEvent { class MockEvent {
MockEvent(this.type, this.event); MockEvent(this.type, this.event);
final String type; final String type;
final DomEvent event; final web.Event event;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment