Files
sdk/tools/dom/templates/html/impl/impl_Node.darttemplate
T
Sigmund Cherem 6f70ffa4ff [dart:html] Disallow extending html elements.
This change removes the `.created` constructor in the html
class hierarchy. These classes now only offer public factory
constructors. As a result, developers will no longer be able
to extend these classes in their libraries.

This is a breaking change, however we don't expect there to
be as much use of this feature (extending html element
classes). In particular, the ability to extend html elements
was intended for web components.  Dart only ever supported
the 0.5 spec of web components, which is old and long
deprecated.  Previously, in Dart 3.0, we removed APIs used
to register custom elements from `dart:html`, so the ability
to extend html elements has not been useful since then.

For more details see https://github.com/dart-lang/sdk/issues/53264

CoreLibraryReviewExempt: ddc/dart2js-specific library.
Change-Id: I43d8c9ae99dc83545e70e1f3b9dfc9f1b274a5c7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/321741
Reviewed-by: Lasse Nielsen <lrn@google.com>
Reviewed-by: Srujan Gaddam <srujzs@google.com>
Reviewed-by: Stephen Adams <sra@google.com>
Commit-Queue: Srujan Gaddam <srujzs@google.com>
2025-03-11 13:25:58 -07:00

272 lines
7.0 KiB
Plaintext

// Copyright (c) 2012, 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.
part of $LIBRARYNAME;
/**
* Lazy implementation of the child nodes of an element that does not request
* the actual child nodes of an element until strictly necessary greatly
* improving performance for the typical cases where it is not required.
*/
class _ChildNodeListLazy extends ListBase<Node> implements NodeListWrapper {
final Node _this;
_ChildNodeListLazy(this._this);
Node get first {
Node$NULLABLE result = JS('Node|Null', '#.firstChild', _this);
if (result == null) throw new StateError("No elements");
return result;
}
Node get last {
Node$NULLABLE result = JS('Node|Null', '#.lastChild', _this);
if (result == null) throw new StateError("No elements");
return result;
}
Node get single {
int l = this.length;
if (l == 0) throw new StateError("No elements");
if (l > 1) throw new StateError("More than one element");
return JS('Node|Null', '#.firstChild', _this)$NULLASSERT;
}
void add(Node value) {
_this.append(value);
}
void addAll(Iterable<Node> iterable) {
if (iterable is _ChildNodeListLazy) {
_ChildNodeListLazy otherList = iterable;
if (!identical(otherList._this, _this)) {
// Optimized route for copying between nodes.
for (var i = 0, len = otherList.length; i < len; ++i) {
_this.append(otherList._this.firstChild$NULLASSERT);
}
}
return;
}
for (Node node in iterable) {
_this.append(node);
}
}
void insert(int index, Node node) {
if (index < 0 || index > length) {
throw new RangeError.range(index, 0, length);
}
if (index == length) {
_this.append(node);
} else {
_this.insertBefore(node, this[index]);
}
}
void insertAll(int index, Iterable<Node> iterable) {
if (index == length) {
addAll(iterable);
} else {
var item = this[index];
_this.insertAllBefore(iterable, item);
}
}
void setAll(int index, Iterable<Node> iterable) {
throw new UnsupportedError("Cannot setAll on Node list");
}
Node removeLast() {
final result = last;
if (result != null) {
_this._removeChild(result);
}
return result;
}
Node removeAt(int index) {
var result = this[index];
if (result != null) {
_this._removeChild(result);
}
return result;
}
bool remove(Object$NULLABLE object) {
if (object is! Node) return false;
Node node = object;
if (!identical(_this, node.parentNode)) return false;
_this._removeChild(node);
return true;
}
void _filter(bool test(Node node), bool removeMatching) {
// This implementation of removeWhere/retainWhere is more efficient
// than the default in ListBase. Child nodes can be removed in constant
// time.
Node$NULLABLE child = _this.firstChild;
while (child != null) {
Node$NULLABLE nextChild = child.nextNode;
if (test(child) == removeMatching) {
_this._removeChild(child);
}
child = nextChild;
}
}
void removeWhere(bool test(Node node)) {
_filter(test, true);
}
void retainWhere(bool test(Node node)) {
_filter(test, false);
}
void clear() {
_this._clearChildren();
}
void operator []=(int index, Node value) {
_this._replaceChild(value, this[index]);
}
Iterator<Node> get iterator => _this.childNodes.iterator;
// From List<Node>:
// TODO(jacobr): this could be implemented for child node lists.
// The exception we throw here is misleading.
void sort([Comparator<Node>$NULLABLE compare]) {
throw new UnsupportedError("Cannot sort Node list");
}
void shuffle([Random$NULLABLE random]) {
throw new UnsupportedError("Cannot shuffle Node list");
}
// FIXME: implement these.
void setRange(int start, int end, Iterable<Node> iterable,
[int skipCount = 0]) {
throw new UnsupportedError("Cannot setRange on Node list");
}
void fillRange(int start, int end, [Node$NULLABLE fill]) {
throw new UnsupportedError("Cannot fillRange on Node list");
}
void removeRange(int start, int end) {
throw new UnsupportedError("Cannot removeRange on Node list");
}
// -- end List<Node> mixins.
// TODO(jacobr): benchmark whether this is more efficient or whether caching
// a local copy of childNodes is more efficient.
int get length => _this.childNodes.length;
set length(int newLength) {
throw new UnsupportedError(
"Cannot set length on immutable List.");
}
Node operator[](int index) => _this.childNodes[index];
List<Node> get rawList => _this.childNodes;
}
$(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$IMPLEMENTS {
/**
* A modifiable list of this node's children.
*/
List<Node> get nodes {
return new _ChildNodeListLazy(this);
}
set nodes(Iterable<Node> value) {
// Copy list first since we don't want liveness during iteration.
// TODO(jacobr): there is a better way to do this.
var copy = value.toList();
text = '';
for (Node node in copy) {
append(node);
}
}
/**
* Removes this node from the DOM.
*/
void remove() {
// TODO(jacobr): should we throw an exception if parent is already null?
// TODO(vsm): Use the native remove when available.
if (this.parentNode != null) {
final Node parent = this.parentNode$NULLASSERT;
parent._removeChild(this);
}
}
/**
* Replaces this node with another node.
*/
Node replaceWith(Node otherNode) {
try {
final Node parent = this.parentNode$NULLASSERT;
parent._replaceChild(otherNode, this);
} catch (e) {}
return this;
}
/**
* Inserts all of the nodes into this node directly before child.
*
* See also:
*
* * [insertBefore]
*/
void insertAllBefore(Iterable<Node> newNodes, Node child) {
if (newNodes is _ChildNodeListLazy) {
_ChildNodeListLazy otherList = newNodes;
if (identical(otherList._this, this)) {
throw new ArgumentError(newNodes);
}
// Optimized route for copying between nodes.
for (var i = 0, len = otherList.length; i < len; ++i) {
this.insertBefore(otherList._this.firstChild$NULLASSERT, child);
}
} else {
for (var node in newNodes) {
this.insertBefore(node, child);
}
}
}
void _clearChildren() {
while (firstChild != null) {
_removeChild(firstChild$NULLASSERT);
}
}
/**
* Print out a String representation of this Node.
*/
String toString() {
String$NULLABLE value = nodeValue; // Fetch DOM Node property once.
return value == null ? super.toString() : value;
}
/**
* A list of this node's children.
*
* ## Other resources
*
* * [Node.childNodes](https://developer.mozilla.org/en-US/docs/Web/API/Node.childNodes)
* from MDN.
*/
@Returns('NodeList')
@Creates('NodeList')
List<Node> get childNodes native;
$!MEMBERS
}