blob: 8bd3e1df50949581f4a06621f91b091096d37b94 [file] [log] [blame]
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
// for details. 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';
import 'dart:js_interop_unsafe';
extension type Window(EventTarget _) implements EventTarget {
@pragma('dart2js:as:trust')
Window get parent => getProperty('parent'.toJS) as Window;
external Location get location;
Console get console => getProperty('console'.toJS) as Console;
CSSStyleDeclaration? getComputedStyle(Element elt, [String? pseudoElt]) =>
callMethodVarArgs('getComputedStyle'.toJS, <JSAny?>[
elt,
if (pseudoElt != null) pseudoElt.toJS,
])
as CSSStyleDeclaration?;
external Navigator get navigator;
void postMessage(
Object message,
String targetOrigin, [
List<MessagePort>? messagePorts,
]) => callMethodVarArgs('postMessage'.toJS, <JSAny?>[
message.jsify(),
targetOrigin.toJS,
if (messagePorts != null) messagePorts.toJS,
]);
}
@JS('window')
external Window get window;
extension type Console(JSObject _) implements JSObject {
external void log(JSAny? object);
external void warn(JSAny? object);
}
extension type Document(Node _) implements Node {
external Element? querySelector(String selectors);
Element createElement(String name, [Object? options]) =>
callMethodVarArgs('createElement'.toJS, <JSAny?>[
name.toJS,
if (options != null) options.jsify(),
])
as Element;
}
extension type HTMLDocument(Document _) implements Document {
external HTMLBodyElement? get body;
external String? get title;
}
@JS('document')
external HTMLDocument get document;
extension type Navigator(JSObject _) implements JSObject {
external String get userAgent;
}
extension type Element(Node _) implements Node {
external DomTokenList get classList;
}
extension type HTMLElement(Element _) implements Element {}
extension type HTMLBodyElement(HTMLElement _) implements HTMLElement {}
extension type Node(EventTarget _) implements EventTarget {
external Node appendChild(Node node);
void remove() {
if (parentNode != null) {
final parent = parentNode!;
parent.removeChild(this);
}
}
external Node removeChild(Node child);
external Node? get parentNode;
}
extension type EventTarget(JSObject _) implements JSObject {
void addEventListener(
String type,
EventListener? listener, [
bool? useCapture,
]) {
if (listener != null) {
callMethodVarArgs('addEventListener'.toJS, <JSAny?>[
type.toJS,
listener.toJS,
if (useCapture != null) useCapture.toJS,
]);
}
}
void removeEventListener(
String type,
EventListener? listener, [
bool? useCapture,
]) {
if (listener != null) {
callMethodVarArgs('removeEventListener'.toJS, <JSAny?>[
type.toJS,
listener.toJS,
if (useCapture != null) useCapture.toJS,
]);
}
}
}
typedef EventListener = void Function(Event event);
extension type Event(JSObject _) implements JSObject {
external void stopPropagation();
}
extension type MessageEvent(Event _) implements Event {
dynamic get data => getProperty('data'.toJS).dartify();
external String get origin;
List<MessagePort> get ports =>
getProperty<JSArray>('ports'.toJS).toDart.cast<MessagePort>();
/// The source may be a `WindowProxy`, a `MessagePort`, or a `ServiceWorker`.
///
/// When a message is sent from an iframe through `window.parent.postMessage`
/// the source will be a `WindowProxy` which has the same methods as [Window].
@pragma('dart2js:as:trust')
MessageEventSource get source =>
getProperty('source'.toJS) as MessageEventSource;
}
extension type MessageEventSource(JSObject _) implements JSObject {
@pragma('dart2js:as:trust')
MessageEventSourceLocation? get location =>
getProperty('location'.toJS) as MessageEventSourceLocation;
}
extension type MessageEventSourceLocation(JSObject _) implements JSObject {
external String? get href;
}
extension type Location(JSObject _) implements JSObject {
external String get href;
external String get origin;
}
extension type MessagePort(EventTarget _) implements EventTarget {
void postMessage(Object? message) => callMethodVarArgs(
'postMessage'.toJS,
<JSAny?>[if (message != null) message.jsify()],
);
external void start();
}
extension type CSSStyleDeclaration(JSObject _) implements JSObject {}
extension type HTMLScriptElement(HTMLElement _) implements HTMLElement {
external set src(String value);
}
HTMLScriptElement createHTMLScriptElement() =>
document.createElement('script') as HTMLScriptElement;
extension type DomTokenList(JSObject _) implements JSObject {
external void add(String value);
external void remove(String value);
external bool contains(String token);
}
extension type HTMLIFrameElement(HTMLElement _) implements HTMLElement {
external String? get src;
external set src(String? value);
external Window get contentWindow;
}
HTMLIFrameElement createHTMLIFrameElement() =>
document.createElement('iframe') as HTMLIFrameElement;
extension type WebSocket(EventTarget _) implements EventTarget {
external void send(JSAny? data);
}
WebSocket createWebSocket(String url) =>
_callConstructor('WebSocket', <JSAny?>[url.toJS])! as WebSocket;
extension type MessageChannel(JSObject _) implements JSObject {
external MessagePort get port1;
external MessagePort get port2;
}
MessageChannel createMessageChannel() =>
_callConstructor('MessageChannel', <JSAny?>[])! as MessageChannel;
Object? _callConstructor(String constructorName, List<JSAny?> args) {
final constructor = window.getProperty(constructorName.toJS) as JSFunction?;
if (constructor == null) {
return null;
}
return constructor.callAsConstructorVarArgs(args);
}
class Subscription {
final String type;
final EventTarget target;
final EventListener listener;
Subscription(this.target, this.type, this.listener) {
target.addEventListener(type, listener);
}
void cancel() => target.removeEventListener(type, listener);
}