blob: cf3cb998161065e2c531757be08c7c28219a8586 [file] [log] [blame]
// Copyright (c) 2016, 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:async';
import 'package:web/web.dart';
import 'package:observatory/src/elements/helpers/element_utils.dart';
import 'package:observatory/utils.dart';
HTMLElement element(CustomElement e) => e.element;
class CustomElement {
static Expando reverseElements = new Expando();
static CustomElement reverse(HTMLElement element) =>
reverseElements[element] as CustomElement;
static List<CustomElement> toBeAttached = <CustomElement>[];
static void drainAttached() {
// Send 'attached' to elements that have been attached to the document.
bool fired = false;
var connectedElements = toBeAttached
.where((CustomElement element) => element.element.isConnected)
.toList();
for (CustomElement element in connectedElements) {
toBeAttached.remove(element);
element.attached();
fired = true;
}
if (toBeAttached.isEmpty) {
return; // Done.
}
if (fired) {
// The 'attached' events above may have scheduled microtasks that will
// will add more CustomElements to be document, e.g. 'render'.
scheduleMicrotask(() => drainAttached());
}
while (!toBeAttached.isEmpty) {
// Either this element will never be attached or it will be attached
// after a turn of the outer event loop. Fire 'attached' in case it is
// the latter, since firing it out of order is preferable to not firing
// it at all.
CustomElement element = toBeAttached.removeLast();
print("Warning: created but not in document: $element");
element.attached();
}
}
final HTMLElement element;
CustomElement.created(String elementClass)
: element = document.createElement("shadow") as HTMLElement {
reverseElements[element] = this;
element.className = elementClass;
if (toBeAttached.isEmpty) {
scheduleMicrotask(() => drainAttached());
}
toBeAttached.add(this);
}
void attached() {}
void detached() {}
HTMLElement? get parent => element.parentElement as HTMLElement?;
List<Node> get children {
final list = <Node>[];
for (var i = 0; i < element.children.length; i++) {
final child = element.children.item(i);
if (child != null) {
list.add(child);
}
}
return list;
}
set children(List<Node> nodes) {
element.removeChildren();
for (var node in nodes) {
element.appendChild(node);
}
}
CustomElement appendChild(Node node) {
element.appendChild(node);
return this;
}
CustomElement removeChildren() {
element.removeChildren();
return this;
}
CustomElement appendChildren(Iterable<Node> nodes) {
element.appendChildren(nodes);
return this;
}
CustomElement setChildren(Iterable<Node> nodes) {
element.setChildren(nodes);
return this;
}
String get className => element.className;
set className(String c) => element.className = c;
String get title => element.title;
set title(String t) => element.title = t;
String get innerText => element.innerText;
set innerText(String t) => element.innerText = t;
CSSStyleDeclaration get style => element.style;
ElementStream<MouseEvent> get onClick => element.onClick;
DOMRect getBoundingClientRect() => element.getBoundingClientRect();
HTMLCollection getElementsByClassName(String c) =>
element.getElementsByClassName(c);
void scrollIntoView() => element.scrollIntoView();
}