[dart:html] Modify scripts to always use NNBD
Since the sdk has been unforked, scripts should be updated to generate files by always using NNBD. As such, nnbd_src has been moved to src and the old src has been deleted. This does not address the nnbd tokens e.g. $NULLABLE. That will be done in a future CL. Change-Id: I00bead16a9d19569b07ad0601f581fc14400fdce Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/151864 Reviewed-by: Sigmund Cherem <sigmund@google.com> Commit-Queue: Srujan Gaddam <srujzs@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
4993179a62
commit
b5470ae013
@@ -1,299 +0,0 @@
|
||||
// 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 html;
|
||||
|
||||
abstract class _AttributeMap extends MapBase<String, String> {
|
||||
final Element _element;
|
||||
|
||||
_AttributeMap(this._element);
|
||||
|
||||
void addAll(Map<String, String> other) {
|
||||
other.forEach((k, v) {
|
||||
this[k] = v;
|
||||
});
|
||||
}
|
||||
|
||||
Map<K, V> cast<K, V>() => Map.castFrom<String, String, K, V>(this);
|
||||
bool containsValue(Object? value) {
|
||||
for (var v in this.values) {
|
||||
if (value == v) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
String putIfAbsent(String key, String ifAbsent()) {
|
||||
if (!containsKey(key)) {
|
||||
this[key] = ifAbsent();
|
||||
}
|
||||
return this[key] as String;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
for (var key in keys) {
|
||||
remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
void forEach(void f(String key, String value)) {
|
||||
for (var key in keys) {
|
||||
var value = this[key];
|
||||
f(key, value as String);
|
||||
}
|
||||
}
|
||||
|
||||
Iterable<String> get keys {
|
||||
// TODO: generate a lazy collection instead.
|
||||
var attributes = _element._attributes;
|
||||
var keys = <String>[];
|
||||
for (int i = 0, len = attributes.length; i < len; i++) {
|
||||
_Attr attr = attributes[i] as _Attr;
|
||||
if (_matches(attr)) {
|
||||
keys.add(attr.name);
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
Iterable<String> get values {
|
||||
// TODO: generate a lazy collection instead.
|
||||
var attributes = _element._attributes;
|
||||
var values = <String>[];
|
||||
for (int i = 0, len = attributes.length; i < len; i++) {
|
||||
_Attr attr = attributes[i] as _Attr;
|
||||
if (_matches(attr)) {
|
||||
values.add(attr.value);
|
||||
}
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if there is no {key, value} pair in the map.
|
||||
*/
|
||||
bool get isEmpty {
|
||||
return length == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if there is at least one {key, value} pair in the map.
|
||||
*/
|
||||
bool get isNotEmpty => !isEmpty;
|
||||
|
||||
/**
|
||||
* Checks to see if the node should be included in this map.
|
||||
*/
|
||||
bool _matches(_Attr node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper to expose [Element.attributes] as a typed map.
|
||||
*/
|
||||
class _ElementAttributeMap extends _AttributeMap {
|
||||
_ElementAttributeMap(Element element) : super(element);
|
||||
|
||||
bool containsKey(Object? key) {
|
||||
return key is String && _element._hasAttribute(key);
|
||||
}
|
||||
|
||||
String? operator [](Object? key) {
|
||||
return _element.getAttribute(key as String);
|
||||
}
|
||||
|
||||
void operator []=(String key, String value) {
|
||||
_element.setAttribute(key, value);
|
||||
}
|
||||
|
||||
@pragma('dart2js:tryInline')
|
||||
String? remove(Object? key) => key is String ? _remove(_element, key) : null;
|
||||
|
||||
/**
|
||||
* The number of {key, value} pairs in the map.
|
||||
*/
|
||||
int get length {
|
||||
return keys.length;
|
||||
}
|
||||
|
||||
bool _matches(_Attr node) => node._namespaceUri == null;
|
||||
|
||||
// Inline this because almost all call sites of [remove] do not use [value],
|
||||
// and the annotations on the `getAttribute` call allow it to be removed.
|
||||
@pragma('dart2js:tryInline')
|
||||
static String? _remove(Element element, String key) {
|
||||
String? value = JS(
|
||||
// throws:null(1) is not accurate since [key] could be malformed, but
|
||||
// [key] is checked again by `removeAttributeNS`.
|
||||
'returns:String|Null;depends:all;effects:none;throws:null(1)',
|
||||
'#.getAttribute(#)',
|
||||
element,
|
||||
key);
|
||||
JS('', '#.removeAttribute(#)', element, key);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper to expose namespaced attributes as a typed map.
|
||||
*/
|
||||
class _NamespacedAttributeMap extends _AttributeMap {
|
||||
final String? _namespace;
|
||||
|
||||
_NamespacedAttributeMap(Element element, this._namespace) : super(element);
|
||||
|
||||
bool containsKey(Object? key) {
|
||||
return key is String && _element._hasAttributeNS(_namespace, key);
|
||||
}
|
||||
|
||||
String? operator [](Object? key) {
|
||||
return _element.getAttributeNS(_namespace, key as String);
|
||||
}
|
||||
|
||||
void operator []=(String key, String value) {
|
||||
_element.setAttributeNS(_namespace, key, value);
|
||||
}
|
||||
|
||||
@pragma('dart2js:tryInline')
|
||||
String? remove(Object? key) =>
|
||||
key is String ? _remove(_namespace, _element, key) : null;
|
||||
|
||||
/**
|
||||
* The number of {key, value} pairs in the map.
|
||||
*/
|
||||
int get length {
|
||||
return keys.length;
|
||||
}
|
||||
|
||||
bool _matches(_Attr node) => node._namespaceUri == _namespace;
|
||||
|
||||
// Inline this because almost all call sites of [remove] do not use the
|
||||
// returned [value], and the annotations on the `getAttributeNS` call allow it
|
||||
// to be removed.
|
||||
@pragma('dart2js:tryInline')
|
||||
static String? _remove(String? namespace, Element element, String key) {
|
||||
String? value = JS(
|
||||
// throws:null(1) is not accurate since [key] could be malformed, but
|
||||
// [key] is checked again by `removeAttributeNS`.
|
||||
'returns:String|Null;depends:all;effects:none;throws:null(1)',
|
||||
'#.getAttributeNS(#, #)',
|
||||
element,
|
||||
namespace,
|
||||
key);
|
||||
JS('', '#.removeAttributeNS(#, #)', element, namespace, key);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a Map abstraction on top of data-* attributes, similar to the
|
||||
* dataSet in the old DOM.
|
||||
*/
|
||||
class _DataAttributeMap extends MapBase<String, String> {
|
||||
final Map<String, String> _attributes;
|
||||
|
||||
_DataAttributeMap(this._attributes);
|
||||
|
||||
// interface Map
|
||||
|
||||
void addAll(Map<String, String> other) {
|
||||
other.forEach((k, v) {
|
||||
this[k] = v;
|
||||
});
|
||||
}
|
||||
|
||||
Map<K, V> cast<K, V>() => Map.castFrom<String, String, K, V>(this);
|
||||
// TODO: Use lazy iterator when it is available on Map.
|
||||
bool containsValue(Object? value) => values.any((v) => v == value);
|
||||
|
||||
bool containsKey(Object? key) =>
|
||||
_attributes.containsKey(_attr(key as String));
|
||||
|
||||
String? operator [](Object? key) => _attributes[_attr(key as String)];
|
||||
|
||||
void operator []=(String key, String value) {
|
||||
_attributes[_attr(key)] = value;
|
||||
}
|
||||
|
||||
String putIfAbsent(String key, String ifAbsent()) =>
|
||||
_attributes.putIfAbsent(_attr(key), ifAbsent);
|
||||
|
||||
String? remove(Object? key) => _attributes.remove(_attr(key as String));
|
||||
|
||||
void clear() {
|
||||
// Needs to operate on a snapshot since we are mutating the collection.
|
||||
for (String key in keys) {
|
||||
remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
void forEach(void f(String key, String value)) {
|
||||
_attributes.forEach((String key, String value) {
|
||||
if (_matches(key)) {
|
||||
f(_strip(key), value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Iterable<String> get keys {
|
||||
final keys = <String>[];
|
||||
_attributes.forEach((String key, String value) {
|
||||
if (_matches(key)) {
|
||||
keys.add(_strip(key));
|
||||
}
|
||||
});
|
||||
return keys;
|
||||
}
|
||||
|
||||
Iterable<String> get values {
|
||||
final values = <String>[];
|
||||
_attributes.forEach((String key, String value) {
|
||||
if (_matches(key)) {
|
||||
values.add(value);
|
||||
}
|
||||
});
|
||||
return values;
|
||||
}
|
||||
|
||||
int get length => keys.length;
|
||||
|
||||
// TODO: Use lazy iterator when it is available on Map.
|
||||
bool get isEmpty => length == 0;
|
||||
|
||||
bool get isNotEmpty => !isEmpty;
|
||||
|
||||
// Helpers.
|
||||
String _attr(String key) => 'data-${_toHyphenedName(key)}';
|
||||
bool _matches(String key) => key.startsWith('data-');
|
||||
String _strip(String key) => _toCamelCase(key.substring(5));
|
||||
|
||||
/**
|
||||
* Converts a string name with hyphens into an identifier, by removing hyphens
|
||||
* and capitalizing the following letter. Optionally [startUppercase] to
|
||||
* capitalize the first letter.
|
||||
*/
|
||||
String _toCamelCase(String hyphenedName, {bool startUppercase: false}) {
|
||||
var segments = hyphenedName.split('-');
|
||||
int start = startUppercase ? 0 : 1;
|
||||
for (int i = start; i < segments.length; i++) {
|
||||
var segment = segments[i];
|
||||
if (segment.length > 0) {
|
||||
// Character between 'a'..'z' mapped to 'A'..'Z'
|
||||
segments[i] = '${segment[0].toUpperCase()}${segment.substring(1)}';
|
||||
}
|
||||
}
|
||||
return segments.join('');
|
||||
}
|
||||
|
||||
/** Reverse of [toCamelCase]. */
|
||||
String _toHyphenedName(String word) {
|
||||
var sb = new StringBuffer();
|
||||
for (int i = 0; i < word.length; i++) {
|
||||
var lower = word[i].toLowerCase();
|
||||
if (word[i] != lower && i > 0) sb.write('-');
|
||||
sb.write(lower);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
// 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 html;
|
||||
|
||||
/**
|
||||
* An object that can be drawn to a 2D canvas rendering context.
|
||||
*
|
||||
* The image drawn to the canvas depends on the type of this object:
|
||||
*
|
||||
* * If this object is an [ImageElement], then this element's image is
|
||||
* drawn to the canvas. If this element is an animated image, then this
|
||||
* element's poster frame is drawn. If this element has no poster frame, then
|
||||
* the first frame of animation is drawn.
|
||||
*
|
||||
* * If this object is a [VideoElement], then the frame at this element's current
|
||||
* playback position is drawn to the canvas.
|
||||
*
|
||||
* * If this object is a [CanvasElement], then this element's bitmap is drawn to
|
||||
* the canvas.
|
||||
*
|
||||
* **Note:** Currently all versions of Internet Explorer do not support
|
||||
* drawing a video element to a canvas. You may also encounter problems drawing
|
||||
* a video to a canvas in Firefox if the source of the video is a data URL.
|
||||
*
|
||||
* ## See also
|
||||
*
|
||||
* * [CanvasRenderingContext2D.drawImage]
|
||||
* * [CanvasRenderingContext2D.drawImageToRect]
|
||||
* * [CanvasRenderingContext2D.drawImageScaled]
|
||||
* * [CanvasRenderingContext2D.drawImageScaledFromSource]
|
||||
*
|
||||
* ## Other resources
|
||||
*
|
||||
* * [Image sources for 2D rendering
|
||||
* contexts](https://html.spec.whatwg.org/multipage/scripting.html#image-sources-for-2d-rendering-contexts)
|
||||
* from WHATWG.
|
||||
* * [Drawing images](https://html.spec.whatwg.org/multipage/scripting.html#dom-context-2d-drawimage)
|
||||
* from WHATWG.
|
||||
*/
|
||||
abstract class CanvasImageSource {}
|
||||
@@ -1,156 +0,0 @@
|
||||
// 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 html;
|
||||
|
||||
/**
|
||||
* Top-level container for a browser tab or window.
|
||||
*
|
||||
* In a web browser, a [WindowBase] object represents any browser window. This
|
||||
* object contains the window's state and its relation to other
|
||||
* windows, such as which window opened this window.
|
||||
*
|
||||
* **Note:** This class represents any window, while [Window] is
|
||||
* used to access the properties and content of the current window or tab.
|
||||
*
|
||||
* ## See also
|
||||
*
|
||||
* * [Window]
|
||||
*
|
||||
* ## Other resources
|
||||
*
|
||||
* * [DOM Window](https://developer.mozilla.org/en-US/docs/DOM/window) from MDN.
|
||||
* * [Window](http://www.w3.org/TR/Window/) from the W3C.
|
||||
*/
|
||||
abstract class WindowBase implements EventTarget {
|
||||
// Fields.
|
||||
|
||||
/**
|
||||
* The current location of this window.
|
||||
*
|
||||
* Location currentLocation = window.location;
|
||||
* print(currentLocation.href); // 'http://www.example.com:80/'
|
||||
*/
|
||||
LocationBase get location;
|
||||
|
||||
/**
|
||||
* The current session history for this window.
|
||||
*
|
||||
* ## Other resources
|
||||
*
|
||||
* * [Session history and navigation
|
||||
* specification](https://html.spec.whatwg.org/multipage/browsers.html#history)
|
||||
* from WHATWG.
|
||||
*/
|
||||
HistoryBase get history;
|
||||
|
||||
/**
|
||||
* Indicates whether this window has been closed.
|
||||
*
|
||||
* print(window.closed); // 'false'
|
||||
* window.close();
|
||||
* print(window.closed); // 'true'
|
||||
*/
|
||||
bool get closed;
|
||||
|
||||
/**
|
||||
* A reference to the window that opened this one.
|
||||
*
|
||||
* Window thisWindow = window;
|
||||
* WindowBase otherWindow = thisWindow.open('http://www.example.com/', 'foo');
|
||||
* print(otherWindow.opener == thisWindow); // 'true'
|
||||
*/
|
||||
WindowBase? get opener;
|
||||
|
||||
/**
|
||||
* A reference to the parent of this window.
|
||||
*
|
||||
* If this [WindowBase] has no parent, [parent] will return a reference to
|
||||
* the [WindowBase] itself.
|
||||
*
|
||||
* IFrameElement myIFrame = new IFrameElement();
|
||||
* window.document.body.elements.add(myIFrame);
|
||||
* print(myIframe.contentWindow.parent == window) // 'true'
|
||||
*
|
||||
* print(window.parent == window) // 'true'
|
||||
*/
|
||||
WindowBase? get parent;
|
||||
|
||||
/**
|
||||
* A reference to the topmost window in the window hierarchy.
|
||||
*
|
||||
* If this [WindowBase] is the topmost [WindowBase], [top] will return a
|
||||
* reference to the [WindowBase] itself.
|
||||
*
|
||||
* // Add an IFrame to the current window.
|
||||
* IFrameElement myIFrame = new IFrameElement();
|
||||
* window.document.body.elements.add(myIFrame);
|
||||
*
|
||||
* // Add an IFrame inside of the other IFrame.
|
||||
* IFrameElement innerIFrame = new IFrameElement();
|
||||
* myIFrame.elements.add(innerIFrame);
|
||||
*
|
||||
* print(myIframe.contentWindow.top == window) // 'true'
|
||||
* print(innerIFrame.contentWindow.top == window) // 'true'
|
||||
*
|
||||
* print(window.top == window) // 'true'
|
||||
*/
|
||||
WindowBase? get top;
|
||||
|
||||
// Methods.
|
||||
/**
|
||||
* Closes the window.
|
||||
*
|
||||
* This method should only succeed if the [WindowBase] object is
|
||||
* **script-closeable** and the window calling [close] is allowed to navigate
|
||||
* the window.
|
||||
*
|
||||
* A window is script-closeable if it is either a window
|
||||
* that was opened by another window, or if it is a window with only one
|
||||
* document in its history.
|
||||
*
|
||||
* A window might not be allowed to navigate, and therefore close, another
|
||||
* window due to browser security features.
|
||||
*
|
||||
* var other = window.open('http://www.example.com', 'foo');
|
||||
* // Closes other window, as it is script-closeable.
|
||||
* other.close();
|
||||
* print(other.closed); // 'true'
|
||||
*
|
||||
* var newLocation = window.location
|
||||
* ..href = 'http://www.mysite.com';
|
||||
* window.location = newLocation;
|
||||
* // Does not close this window, as the history has changed.
|
||||
* window.close();
|
||||
* print(window.closed); // 'false'
|
||||
*
|
||||
* See also:
|
||||
*
|
||||
* * [Window close discussion](http://www.w3.org/TR/html5/browsers.html#dom-window-close) from the W3C
|
||||
*/
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Sends a cross-origin message.
|
||||
*
|
||||
* ## Other resources
|
||||
*
|
||||
* * [window.postMessage](https://developer.mozilla.org/en-US/docs/Web/API/Window.postMessage)
|
||||
* from MDN.
|
||||
* * [Cross-document messaging](https://html.spec.whatwg.org/multipage/comms.html#web-messaging)
|
||||
* from WHATWG.
|
||||
*/
|
||||
void postMessage(var message, String targetOrigin,
|
||||
[List<MessagePort>? messagePorts]);
|
||||
}
|
||||
|
||||
abstract class LocationBase {
|
||||
void set href(String val);
|
||||
}
|
||||
|
||||
abstract class HistoryBase {
|
||||
void back();
|
||||
void forward();
|
||||
void go(int distance);
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
// 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 html;
|
||||
|
||||
/** A Set that stores the CSS class names for an element. */
|
||||
abstract class CssClassSet implements Set<String> {
|
||||
/**
|
||||
* Adds the class [value] to the element if it is not on it, removes it if it
|
||||
* is.
|
||||
*
|
||||
* If [shouldAdd] is true, then we always add that [value] to the element. If
|
||||
* [shouldAdd] is false then we always remove [value] from the element.
|
||||
*
|
||||
* If this corresponds to one element, returns `true` if [value] is present
|
||||
* after the operation, and returns `false` if [value] is absent after the
|
||||
* operation.
|
||||
*
|
||||
* If this CssClassSet corresponds to many elements, `false` is always
|
||||
* returned.
|
||||
*
|
||||
* [value] must be a valid 'token' representing a single class, i.e. a
|
||||
* non-empty string containing no whitespace. To toggle multiple classes, use
|
||||
* [toggleAll].
|
||||
*/
|
||||
bool toggle(String value, [bool? shouldAdd]);
|
||||
|
||||
/**
|
||||
* Returns [:true:] if classes cannot be added or removed from this
|
||||
* [:CssClassSet:].
|
||||
*/
|
||||
bool get frozen;
|
||||
|
||||
/**
|
||||
* Determine if this element contains the class [value].
|
||||
*
|
||||
* This is the Dart equivalent of jQuery's
|
||||
* [hasClass](http://api.jquery.com/hasClass/).
|
||||
*
|
||||
* [value] must be a valid 'token' representing a single class, i.e. a
|
||||
* non-empty string containing no whitespace.
|
||||
*/
|
||||
bool contains(Object? value);
|
||||
|
||||
/**
|
||||
* Add the class [value] to element.
|
||||
*
|
||||
* [add] and [addAll] are the Dart equivalent of jQuery's
|
||||
* [addClass](http://api.jquery.com/addClass/).
|
||||
*
|
||||
* If this CssClassSet corresponds to one element. Returns true if [value] was
|
||||
* added to the set, otherwise false.
|
||||
*
|
||||
* If this CssClassSet corresponds to many elements, `false` is always
|
||||
* returned.
|
||||
*
|
||||
* [value] must be a valid 'token' representing a single class, i.e. a
|
||||
* non-empty string containing no whitespace. To add multiple classes use
|
||||
* [addAll].
|
||||
*/
|
||||
bool add(String value);
|
||||
|
||||
/**
|
||||
* Remove the class [value] from element, and return true on successful
|
||||
* removal.
|
||||
*
|
||||
* [remove] and [removeAll] are the Dart equivalent of jQuery's
|
||||
* [removeClass](http://api.jquery.com/removeClass/).
|
||||
*
|
||||
* [value] must be a valid 'token' representing a single class, i.e. a
|
||||
* non-empty string containing no whitespace. To remove multiple classes, use
|
||||
* [removeAll].
|
||||
*/
|
||||
bool remove(Object? value);
|
||||
|
||||
/**
|
||||
* Add all classes specified in [iterable] to element.
|
||||
*
|
||||
* [add] and [addAll] are the Dart equivalent of jQuery's
|
||||
* [addClass](http://api.jquery.com/addClass/).
|
||||
*
|
||||
* Each element of [iterable] must be a valid 'token' representing a single
|
||||
* class, i.e. a non-empty string containing no whitespace.
|
||||
*/
|
||||
void addAll(Iterable<String> iterable);
|
||||
|
||||
/**
|
||||
* Remove all classes specified in [iterable] from element.
|
||||
*
|
||||
* [remove] and [removeAll] are the Dart equivalent of jQuery's
|
||||
* [removeClass](http://api.jquery.com/removeClass/).
|
||||
*
|
||||
* Each element of [iterable] must be a valid 'token' representing a single
|
||||
* class, i.e. a non-empty string containing no whitespace.
|
||||
*/
|
||||
void removeAll(Iterable<Object?> iterable);
|
||||
|
||||
/**
|
||||
* Toggles all classes specified in [iterable] on element.
|
||||
*
|
||||
* Iterate through [iterable]'s items, and add it if it is not on it, or
|
||||
* remove it if it is. This is the Dart equivalent of jQuery's
|
||||
* [toggleClass](http://api.jquery.com/toggleClass/).
|
||||
* If [shouldAdd] is true, then we always add all the classes in [iterable]
|
||||
* element. If [shouldAdd] is false then we always remove all the classes in
|
||||
* [iterable] from the element.
|
||||
*
|
||||
* Each element of [iterable] must be a valid 'token' representing a single
|
||||
* class, i.e. a non-empty string containing no whitespace.
|
||||
*/
|
||||
void toggleAll(Iterable<String> iterable, [bool? shouldAdd]);
|
||||
}
|
||||
@@ -1,372 +0,0 @@
|
||||
// Copyright (c) 2013, 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 html;
|
||||
|
||||
/**
|
||||
* A rectangle representing all the content of the element in the
|
||||
* [box model](http://www.w3.org/TR/CSS2/box.html).
|
||||
*/
|
||||
class _ContentCssRect extends CssRect {
|
||||
_ContentCssRect(Element element) : super(element);
|
||||
|
||||
num get height =>
|
||||
_element.offsetHeight + _addOrSubtractToBoxModel(_HEIGHT, _CONTENT);
|
||||
|
||||
num get width =>
|
||||
_element.offsetWidth + _addOrSubtractToBoxModel(_WIDTH, _CONTENT);
|
||||
|
||||
/**
|
||||
* Set the height to `newHeight`.
|
||||
*
|
||||
* newHeight can be either a [num] representing the height in pixels or a
|
||||
* [Dimension] object. Values of newHeight that are less than zero are
|
||||
* converted to effectively setting the height to 0. This is equivalent to the
|
||||
* `height` function in jQuery and the calculated `height` CSS value,
|
||||
* converted to a num in pixels.
|
||||
*/
|
||||
set height(dynamic newHeight) {
|
||||
if (newHeight is Dimension) {
|
||||
Dimension newHeightAsDimension = newHeight;
|
||||
if (newHeightAsDimension.value < 0) newHeight = new Dimension.px(0);
|
||||
_element.style.height = newHeight.toString();
|
||||
} else if (newHeight is num) {
|
||||
if (newHeight < 0) newHeight = 0;
|
||||
_element.style.height = '${newHeight}px';
|
||||
} else {
|
||||
throw new ArgumentError("newHeight is not a Dimension or num");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current computed width in pixels of this element.
|
||||
*
|
||||
* newWidth can be either a [num] representing the width in pixels or a
|
||||
* [Dimension] object. This is equivalent to the `width` function in jQuery
|
||||
* and the calculated
|
||||
* `width` CSS value, converted to a dimensionless num in pixels.
|
||||
*/
|
||||
set width(dynamic newWidth) {
|
||||
if (newWidth is Dimension) {
|
||||
Dimension newWidthAsDimension = newWidth;
|
||||
if (newWidthAsDimension.value < 0) newWidth = new Dimension.px(0);
|
||||
_element.style.width = newWidth.toString();
|
||||
} else if (newWidth is num) {
|
||||
if (newWidth < 0) newWidth = 0;
|
||||
_element.style.width = '${newWidth}px';
|
||||
} else {
|
||||
throw new ArgumentError("newWidth is not a Dimension or num");
|
||||
}
|
||||
}
|
||||
|
||||
num get left =>
|
||||
_element.getBoundingClientRect().left -
|
||||
_addOrSubtractToBoxModel(['left'], _CONTENT);
|
||||
num get top =>
|
||||
_element.getBoundingClientRect().top -
|
||||
_addOrSubtractToBoxModel(['top'], _CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of element content rectangles in the
|
||||
* [box model](http://www.w3.org/TR/CSS2/box.html).
|
||||
*/
|
||||
class _ContentCssListRect extends _ContentCssRect {
|
||||
List<Element> _elementList;
|
||||
|
||||
_ContentCssListRect(List<Element> elementList)
|
||||
: _elementList = elementList,
|
||||
super(elementList.first);
|
||||
|
||||
/**
|
||||
* Set the height to `newHeight`.
|
||||
*
|
||||
* Values of newHeight that are less than zero are converted to effectively
|
||||
* setting the height to 0. This is equivalent to the `height`
|
||||
* function in jQuery and the calculated `height` CSS value, converted to a
|
||||
* num in pixels.
|
||||
*/
|
||||
set height(newHeight) {
|
||||
_elementList.forEach((e) => e.contentEdge.height = newHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current computed width in pixels of this element.
|
||||
*
|
||||
* This is equivalent to the `width` function in jQuery and the calculated
|
||||
* `width` CSS value, converted to a dimensionless num in pixels.
|
||||
*/
|
||||
set width(newWidth) {
|
||||
_elementList.forEach((e) => e.contentEdge.width = newWidth);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A rectangle representing the dimensions of the space occupied by the
|
||||
* element's content + padding in the
|
||||
* [box model](http://www.w3.org/TR/CSS2/box.html).
|
||||
*/
|
||||
class _PaddingCssRect extends CssRect {
|
||||
_PaddingCssRect(element) : super(element);
|
||||
num get height =>
|
||||
_element.offsetHeight + _addOrSubtractToBoxModel(_HEIGHT, _PADDING);
|
||||
num get width =>
|
||||
_element.offsetWidth + _addOrSubtractToBoxModel(_WIDTH, _PADDING);
|
||||
|
||||
num get left =>
|
||||
_element.getBoundingClientRect().left -
|
||||
_addOrSubtractToBoxModel(['left'], _PADDING);
|
||||
num get top =>
|
||||
_element.getBoundingClientRect().top -
|
||||
_addOrSubtractToBoxModel(['top'], _PADDING);
|
||||
}
|
||||
|
||||
/**
|
||||
* A rectangle representing the dimensions of the space occupied by the
|
||||
* element's content + padding + border in the
|
||||
* [box model](http://www.w3.org/TR/CSS2/box.html).
|
||||
*/
|
||||
class _BorderCssRect extends CssRect {
|
||||
_BorderCssRect(element) : super(element);
|
||||
num get height => _element.offsetHeight;
|
||||
num get width => _element.offsetWidth;
|
||||
|
||||
num get left => _element.getBoundingClientRect().left;
|
||||
num get top => _element.getBoundingClientRect().top;
|
||||
}
|
||||
|
||||
/**
|
||||
* A rectangle representing the dimensions of the space occupied by the
|
||||
* element's content + padding + border + margin in the
|
||||
* [box model](http://www.w3.org/TR/CSS2/box.html).
|
||||
*/
|
||||
class _MarginCssRect extends CssRect {
|
||||
_MarginCssRect(element) : super(element);
|
||||
num get height =>
|
||||
_element.offsetHeight + _addOrSubtractToBoxModel(_HEIGHT, _MARGIN);
|
||||
num get width =>
|
||||
_element.offsetWidth + _addOrSubtractToBoxModel(_WIDTH, _MARGIN);
|
||||
|
||||
num get left =>
|
||||
_element.getBoundingClientRect().left -
|
||||
_addOrSubtractToBoxModel(['left'], _MARGIN);
|
||||
num get top =>
|
||||
_element.getBoundingClientRect().top -
|
||||
_addOrSubtractToBoxModel(['top'], _MARGIN);
|
||||
}
|
||||
|
||||
/**
|
||||
* A class for representing CSS dimensions.
|
||||
*
|
||||
* In contrast to the more general purpose [Rectangle] class, this class's
|
||||
* values are mutable, so one can change the height of an element
|
||||
* programmatically.
|
||||
*
|
||||
* _Important_ _note_: use of these methods will perform CSS calculations that
|
||||
* can trigger a browser reflow. Therefore, use of these properties _during_ an
|
||||
* animation frame is discouraged. See also:
|
||||
* [Browser Reflow](https://developers.google.com/speed/articles/reflow)
|
||||
*/
|
||||
abstract class CssRect implements Rectangle<num> {
|
||||
Element _element;
|
||||
|
||||
CssRect(this._element);
|
||||
|
||||
num get left;
|
||||
|
||||
num get top;
|
||||
|
||||
/**
|
||||
* The height of this rectangle.
|
||||
*
|
||||
* This is equivalent to the `height` function in jQuery and the calculated
|
||||
* `height` CSS value, converted to a dimensionless num in pixels. Unlike
|
||||
* [getBoundingClientRect], `height` will return the same numerical width if
|
||||
* the element is hidden or not.
|
||||
*/
|
||||
num get height;
|
||||
|
||||
/**
|
||||
* The width of this rectangle.
|
||||
*
|
||||
* This is equivalent to the `width` function in jQuery and the calculated
|
||||
* `width` CSS value, converted to a dimensionless num in pixels. Unlike
|
||||
* [getBoundingClientRect], `width` will return the same numerical width if
|
||||
* the element is hidden or not.
|
||||
*/
|
||||
num get width;
|
||||
|
||||
/**
|
||||
* Set the height to `newHeight`.
|
||||
*
|
||||
* newHeight can be either a [num] representing the height in pixels or a
|
||||
* [Dimension] object. Values of newHeight that are less than zero are
|
||||
* converted to effectively setting the height to 0. This is equivalent to the
|
||||
* `height` function in jQuery and the calculated `height` CSS value,
|
||||
* converted to a num in pixels.
|
||||
*
|
||||
* Note that only the content height can actually be set via this method.
|
||||
*/
|
||||
set height(dynamic newHeight) {
|
||||
throw new UnsupportedError("Can only set height for content rect.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current computed width in pixels of this element.
|
||||
*
|
||||
* newWidth can be either a [num] representing the width in pixels or a
|
||||
* [Dimension] object. This is equivalent to the `width` function in jQuery
|
||||
* and the calculated
|
||||
* `width` CSS value, converted to a dimensionless num in pixels.
|
||||
*
|
||||
* Note that only the content width can be set via this method.
|
||||
*/
|
||||
set width(dynamic newWidth) {
|
||||
throw new UnsupportedError("Can only set width for content rect.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a value that is used to modify the initial height or width
|
||||
* measurement of an element. Depending on the value (ideally an enum) passed
|
||||
* to augmentingMeasurement, we may need to add or subtract margin, padding,
|
||||
* or border values, depending on the measurement we're trying to obtain.
|
||||
*/
|
||||
num _addOrSubtractToBoxModel(
|
||||
List<String> dimensions, String augmentingMeasurement) {
|
||||
// getComputedStyle always returns pixel values (hence, computed), so we're
|
||||
// always dealing with pixels in this method.
|
||||
var styles = _element.getComputedStyle();
|
||||
|
||||
num val = 0;
|
||||
|
||||
for (String measurement in dimensions) {
|
||||
// The border-box and default box model both exclude margin in the regular
|
||||
// height/width calculation, so add it if we want it for this measurement.
|
||||
if (augmentingMeasurement == _MARGIN) {
|
||||
val += new Dimension.css(
|
||||
styles.getPropertyValue('$augmentingMeasurement-$measurement'))
|
||||
.value;
|
||||
}
|
||||
|
||||
// The border-box includes padding and border, so remove it if we want
|
||||
// just the content itself.
|
||||
if (augmentingMeasurement == _CONTENT) {
|
||||
val -= new Dimension.css(
|
||||
styles.getPropertyValue('${_PADDING}-$measurement'))
|
||||
.value;
|
||||
}
|
||||
|
||||
// At this point, we don't wan't to augment with border or margin,
|
||||
// so remove border.
|
||||
if (augmentingMeasurement != _MARGIN) {
|
||||
val -= new Dimension.css(
|
||||
styles.getPropertyValue('border-${measurement}-width'))
|
||||
.value;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
// TODO(jacobr): these methods are duplicated from _RectangleBase in dart:math
|
||||
// Ideally we would provide a RectangleMixin class that provides this
|
||||
// implementation. In an ideal world we would exp
|
||||
/** The x-coordinate of the right edge. */
|
||||
num get right => left + width;
|
||||
/** The y-coordinate of the bottom edge. */
|
||||
num get bottom => top + height;
|
||||
|
||||
String toString() {
|
||||
return 'Rectangle ($left, $top) $width x $height';
|
||||
}
|
||||
|
||||
bool operator ==(other) =>
|
||||
other is Rectangle &&
|
||||
left == other.left &&
|
||||
top == other.top &&
|
||||
right == other.right &&
|
||||
bottom == other.bottom;
|
||||
|
||||
int get hashCode => _JenkinsSmiHash.hash4(
|
||||
left.hashCode, top.hashCode, right.hashCode, bottom.hashCode);
|
||||
|
||||
/**
|
||||
* Computes the intersection of `this` and [other].
|
||||
*
|
||||
* The intersection of two axis-aligned rectangles, if any, is always another
|
||||
* axis-aligned rectangle.
|
||||
*
|
||||
* Returns the intersection of this and `other`, or `null` if they don't
|
||||
* intersect.
|
||||
*/
|
||||
Rectangle<num>? intersection(Rectangle<num> other) {
|
||||
var x0 = max(left, other.left);
|
||||
var x1 = min(left + width, other.left + other.width);
|
||||
|
||||
if (x0 <= x1) {
|
||||
var y0 = max(top, other.top);
|
||||
var y1 = min(top + height, other.top + other.height);
|
||||
|
||||
if (y0 <= y1) {
|
||||
return new Rectangle<num>(x0, y0, x1 - x0, y1 - y0);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if `this` intersects [other].
|
||||
*/
|
||||
bool intersects(Rectangle<num> other) {
|
||||
return (left <= other.left + other.width &&
|
||||
other.left <= left + width &&
|
||||
top <= other.top + other.height &&
|
||||
other.top <= top + height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new rectangle which completely contains `this` and [other].
|
||||
*/
|
||||
Rectangle<num> boundingBox(Rectangle<num> other) {
|
||||
var right = max(this.left + this.width, other.left + other.width);
|
||||
var bottom = max(this.top + this.height, other.top + other.height);
|
||||
|
||||
var left = min(this.left, other.left);
|
||||
var top = min(this.top, other.top);
|
||||
|
||||
return new Rectangle<num>(left, top, right - left, bottom - top);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether `this` entirely contains [another].
|
||||
*/
|
||||
bool containsRectangle(Rectangle<num> another) {
|
||||
return left <= another.left &&
|
||||
left + width >= another.left + another.width &&
|
||||
top <= another.top &&
|
||||
top + height >= another.top + another.height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether [another] is inside or along the edges of `this`.
|
||||
*/
|
||||
bool containsPoint(Point<num> another) {
|
||||
return another.x >= left &&
|
||||
another.x <= left + width &&
|
||||
another.y >= top &&
|
||||
another.y <= top + height;
|
||||
}
|
||||
|
||||
Point<num> get topLeft => new Point<num>(this.left, this.top);
|
||||
Point<num> get topRight => new Point<num>(this.left + this.width, this.top);
|
||||
Point<num> get bottomRight =>
|
||||
new Point<num>(this.left + this.width, this.top + this.height);
|
||||
Point<num> get bottomLeft =>
|
||||
new Point<num>(this.left, this.top + this.height);
|
||||
}
|
||||
|
||||
final _HEIGHT = ['top', 'bottom'];
|
||||
final _WIDTH = ['right', 'left'];
|
||||
final _CONTENT = 'content';
|
||||
final _PADDING = 'padding';
|
||||
final _MARGIN = 'margin';
|
||||
@@ -1,84 +0,0 @@
|
||||
part of html;
|
||||
|
||||
/**
|
||||
* Class representing a
|
||||
* [length measurement](https://developer.mozilla.org/en-US/docs/Web/CSS/length)
|
||||
* in CSS.
|
||||
*/
|
||||
class Dimension {
|
||||
num _value;
|
||||
String _unit;
|
||||
|
||||
/** Set this CSS Dimension to a percentage `value`. */
|
||||
Dimension.percent(this._value) : _unit = '%';
|
||||
|
||||
/** Set this CSS Dimension to a pixel `value`. */
|
||||
Dimension.px(this._value) : _unit = 'px';
|
||||
|
||||
/** Set this CSS Dimension to a pica `value`. */
|
||||
Dimension.pc(this._value) : _unit = 'pc';
|
||||
|
||||
/** Set this CSS Dimension to a point `value`. */
|
||||
Dimension.pt(this._value) : _unit = 'pt';
|
||||
|
||||
/** Set this CSS Dimension to an inch `value`. */
|
||||
Dimension.inch(this._value) : _unit = 'in';
|
||||
|
||||
/** Set this CSS Dimension to a centimeter `value`. */
|
||||
Dimension.cm(this._value) : _unit = 'cm';
|
||||
|
||||
/** Set this CSS Dimension to a millimeter `value`. */
|
||||
Dimension.mm(this._value) : _unit = 'mm';
|
||||
|
||||
/**
|
||||
* Set this CSS Dimension to the specified number of ems.
|
||||
*
|
||||
* 1em is equal to the current font size. (So 2ems is equal to double the font
|
||||
* size). This is useful for producing website layouts that scale nicely with
|
||||
* the user's desired font size.
|
||||
*/
|
||||
Dimension.em(this._value) : _unit = 'em';
|
||||
|
||||
/**
|
||||
* Set this CSS Dimension to the specified number of x-heights.
|
||||
*
|
||||
* One ex is equal to the x-height of a font's baseline to its mean line,
|
||||
* generally the height of the letter "x" in the font, which is usually about
|
||||
* half the font-size.
|
||||
*/
|
||||
Dimension.ex(this._value) : _unit = 'ex';
|
||||
|
||||
/**
|
||||
* Construct a Dimension object from the valid, simple CSS string `cssValue`
|
||||
* that represents a distance measurement.
|
||||
*
|
||||
* This constructor is intended as a convenience method for working with
|
||||
* simplistic CSS length measurements. Non-numeric values such as `auto` or
|
||||
* `inherit` or invalid CSS will cause this constructor to throw a
|
||||
* FormatError.
|
||||
*/
|
||||
Dimension.css(String cssValue)
|
||||
: _unit = '',
|
||||
_value = 0 {
|
||||
if (cssValue == '') cssValue = '0px';
|
||||
if (cssValue.endsWith('%')) {
|
||||
_unit = '%';
|
||||
} else {
|
||||
_unit = cssValue.substring(cssValue.length - 2);
|
||||
}
|
||||
if (cssValue.contains('.')) {
|
||||
_value =
|
||||
double.parse(cssValue.substring(0, cssValue.length - _unit.length));
|
||||
} else {
|
||||
_value = int.parse(cssValue.substring(0, cssValue.length - _unit.length));
|
||||
}
|
||||
}
|
||||
|
||||
/** Print out the CSS String representation of this value. */
|
||||
String toString() {
|
||||
return '${_value}${_unit}';
|
||||
}
|
||||
|
||||
/** Return a unitless, numerical value of this CSS value. */
|
||||
num get value => this._value;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
// Copyright (c) 2011, 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 html;
|
||||
|
||||
typedef EventListener(Event event);
|
||||
@@ -1,461 +0,0 @@
|
||||
// Copyright (c) 2013, 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 html;
|
||||
|
||||
/**
|
||||
* A factory to expose DOM events as Streams.
|
||||
*/
|
||||
class EventStreamProvider<T extends Event> {
|
||||
final String _eventType;
|
||||
|
||||
const EventStreamProvider(this._eventType);
|
||||
|
||||
/**
|
||||
* Gets a [Stream] for this event type, on the specified target.
|
||||
*
|
||||
* This will always return a broadcast stream so multiple listeners can be
|
||||
* used simultaneously.
|
||||
*
|
||||
* This may be used to capture DOM events:
|
||||
*
|
||||
* Element.keyDownEvent.forTarget(element, useCapture: true).listen(...);
|
||||
*
|
||||
* // Alternate method:
|
||||
* Element.keyDownEvent.forTarget(element).capture(...);
|
||||
*
|
||||
* Or for listening to an event which will bubble through the DOM tree:
|
||||
*
|
||||
* MediaElement.pauseEvent.forTarget(document.body).listen(...);
|
||||
*
|
||||
* See also:
|
||||
*
|
||||
* * [EventTarget.addEventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)
|
||||
* from MDN.
|
||||
*/
|
||||
Stream<T> forTarget(EventTarget? e, {bool useCapture: false}) =>
|
||||
new _EventStream<T>(e, _eventType, useCapture);
|
||||
|
||||
/**
|
||||
* Gets an [ElementEventStream] for this event type, on the specified element.
|
||||
*
|
||||
* This will always return a broadcast stream so multiple listeners can be
|
||||
* used simultaneously.
|
||||
*
|
||||
* This may be used to capture DOM events:
|
||||
*
|
||||
* Element.keyDownEvent.forElement(element, useCapture: true).listen(...);
|
||||
*
|
||||
* // Alternate method:
|
||||
* Element.keyDownEvent.forElement(element).capture(...);
|
||||
*
|
||||
* Or for listening to an event which will bubble through the DOM tree:
|
||||
*
|
||||
* MediaElement.pauseEvent.forElement(document.body).listen(...);
|
||||
*
|
||||
* See also:
|
||||
*
|
||||
* * [EventTarget.addEventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)
|
||||
* from MDN.
|
||||
*/
|
||||
ElementStream<T> forElement(Element e, {bool useCapture: false}) {
|
||||
return new _ElementEventStreamImpl<T>(e, _eventType, useCapture);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an [ElementEventStream] for this event type, on the list of elements.
|
||||
*
|
||||
* This will always return a broadcast stream so multiple listeners can be
|
||||
* used simultaneously.
|
||||
*
|
||||
* This may be used to capture DOM events:
|
||||
*
|
||||
* Element.keyDownEvent._forElementList(element, useCapture: true).listen(...);
|
||||
*
|
||||
* See also:
|
||||
*
|
||||
* * [EventTarget.addEventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)
|
||||
* from MDN.
|
||||
*/
|
||||
ElementStream<T> _forElementList(ElementList<Element> e,
|
||||
{bool useCapture: false}) {
|
||||
return new _ElementListEventStreamImpl<T>(e, _eventType, useCapture);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of the event which this would listen for on the specified
|
||||
* event target.
|
||||
*
|
||||
* The target is necessary because some browsers may use different event names
|
||||
* for the same purpose and the target allows differentiating browser support.
|
||||
*/
|
||||
String getEventType(EventTarget target) {
|
||||
return _eventType;
|
||||
}
|
||||
}
|
||||
|
||||
/** A specialized Stream available to [Element]s to enable event delegation. */
|
||||
abstract class ElementStream<T extends Event> implements Stream<T> {
|
||||
/**
|
||||
* Return a stream that only fires when the particular event fires for
|
||||
* elements matching the specified CSS selector.
|
||||
*
|
||||
* This is the Dart equivalent to jQuery's
|
||||
* [delegate](http://api.jquery.com/delegate/).
|
||||
*/
|
||||
Stream<T> matches(String selector);
|
||||
|
||||
/**
|
||||
* Adds a capturing subscription to this stream.
|
||||
*
|
||||
* If the target of the event is a descendant of the element from which this
|
||||
* stream derives then [onData] is called before the event propagates down to
|
||||
* the target. This is the opposite of bubbling behavior, where the event
|
||||
* is first processed for the event target and then bubbles upward.
|
||||
*
|
||||
* ## Other resources
|
||||
*
|
||||
* * [Event Capture](http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow-capture)
|
||||
* from the W3C DOM Events specification.
|
||||
*/
|
||||
StreamSubscription<T> capture(void onData(T event));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapter for exposing DOM events as Dart streams.
|
||||
*/
|
||||
class _EventStream<T extends Event> extends Stream<T> {
|
||||
final EventTarget? _target;
|
||||
final String _eventType;
|
||||
final bool _useCapture;
|
||||
|
||||
_EventStream(this._target, this._eventType, this._useCapture);
|
||||
|
||||
// DOM events are inherently multi-subscribers.
|
||||
Stream<T> asBroadcastStream(
|
||||
{void onListen(StreamSubscription<T> subscription)?,
|
||||
void onCancel(StreamSubscription<T> subscription)?}) =>
|
||||
this;
|
||||
bool get isBroadcast => true;
|
||||
|
||||
// TODO(9757): Inlining should be smart and inline only when inlining would
|
||||
// enable scalar replacement of an immediately allocated receiver.
|
||||
@pragma('dart2js:tryInline')
|
||||
StreamSubscription<T> listen(void onData(T event)?,
|
||||
{Function? onError, void onDone()?, bool? cancelOnError}) {
|
||||
return new _EventStreamSubscription<T>(
|
||||
this._target, this._eventType, onData, this._useCapture);
|
||||
}
|
||||
}
|
||||
|
||||
bool _matchesWithAncestors(Event event, String selector) {
|
||||
var target = event.target;
|
||||
return target is Element ? target.matchesWithAncestors(selector) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapter for exposing DOM Element events as streams, while also allowing
|
||||
* event delegation.
|
||||
*/
|
||||
class _ElementEventStreamImpl<T extends Event> extends _EventStream<T>
|
||||
implements ElementStream<T> {
|
||||
_ElementEventStreamImpl(target, eventType, useCapture)
|
||||
: super(target, eventType, useCapture);
|
||||
|
||||
Stream<T> matches(String selector) =>
|
||||
this.where((event) => _matchesWithAncestors(event, selector)).map((e) {
|
||||
e._selector = selector;
|
||||
return e;
|
||||
});
|
||||
|
||||
StreamSubscription<T> capture(void onData(T event)) =>
|
||||
new _EventStreamSubscription<T>(
|
||||
this._target, this._eventType, onData, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapter for exposing events on a collection of DOM Elements as streams,
|
||||
* while also allowing event delegation.
|
||||
*/
|
||||
class _ElementListEventStreamImpl<T extends Event> extends Stream<T>
|
||||
implements ElementStream<T> {
|
||||
final Iterable<Element> _targetList;
|
||||
final bool _useCapture;
|
||||
final String _eventType;
|
||||
|
||||
_ElementListEventStreamImpl(
|
||||
this._targetList, this._eventType, this._useCapture);
|
||||
|
||||
Stream<T> matches(String selector) =>
|
||||
this.where((event) => _matchesWithAncestors(event, selector)).map((e) {
|
||||
e._selector = selector;
|
||||
return e;
|
||||
});
|
||||
|
||||
// Delegate all regular Stream behavior to a wrapped Stream.
|
||||
StreamSubscription<T> listen(void onData(T event)?,
|
||||
{Function? onError, void onDone()?, bool? cancelOnError}) {
|
||||
var pool = new _StreamPool<T>.broadcast();
|
||||
for (var target in _targetList) {
|
||||
pool.add(new _EventStream<T>(target, _eventType, _useCapture));
|
||||
}
|
||||
return pool.stream.listen(onData,
|
||||
onError: onError, onDone: onDone, cancelOnError: cancelOnError);
|
||||
}
|
||||
|
||||
StreamSubscription<T> capture(void onData(T event)) {
|
||||
var pool = new _StreamPool<T>.broadcast();
|
||||
for (var target in _targetList) {
|
||||
pool.add(new _EventStream<T>(target, _eventType, true));
|
||||
}
|
||||
return pool.stream.listen(onData);
|
||||
}
|
||||
|
||||
Stream<T> asBroadcastStream(
|
||||
{void onListen(StreamSubscription<T> subscription)?,
|
||||
void onCancel(StreamSubscription<T> subscription)?}) =>
|
||||
this;
|
||||
bool get isBroadcast => true;
|
||||
}
|
||||
|
||||
// We would like this to just be EventListener<T> but that typdef cannot
|
||||
// use generics until dartbug/26276 is fixed.
|
||||
typedef _EventListener<T extends Event>(T event);
|
||||
|
||||
class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> {
|
||||
int _pauseCount = 0;
|
||||
EventTarget? _target;
|
||||
final String _eventType;
|
||||
EventListener? _onData;
|
||||
final bool _useCapture;
|
||||
|
||||
// TODO(leafp): It would be better to write this as
|
||||
// _onData = onData == null ? null :
|
||||
// onData is void Function(Event)
|
||||
// ? _wrapZone<Event>(onData)
|
||||
// : _wrapZone<Event>((e) => onData(e as T))
|
||||
// In order to support existing tests which pass the wrong type of events but
|
||||
// use a more general listener, without causing as much slowdown for things
|
||||
// which are typed correctly. But this currently runs afoul of restrictions
|
||||
// on is checks for compatibility with the VM.
|
||||
_EventStreamSubscription(
|
||||
this._target, this._eventType, void onData(T event)?, this._useCapture)
|
||||
: _onData = onData == null
|
||||
? null
|
||||
: _wrapZone<Event>((e) => (onData as dynamic)(e)) {
|
||||
_tryResume();
|
||||
}
|
||||
|
||||
Future cancel() {
|
||||
// Check for strong mode. This function can no longer return null in strong
|
||||
// mode, so only return null in weak mode to preserve synchronous timing.
|
||||
// See issue 41653 for more details.
|
||||
dynamic emptyFuture =
|
||||
typeAcceptsNull<Event>() ? null : Future<void>.value();
|
||||
if (_canceled) return emptyFuture as Future;
|
||||
|
||||
_unlisten();
|
||||
// Clear out the target to indicate this is complete.
|
||||
_target = null;
|
||||
_onData = null;
|
||||
return emptyFuture as Future;
|
||||
}
|
||||
|
||||
bool get _canceled => _target == null;
|
||||
|
||||
void onData(void handleData(T event)?) {
|
||||
if (_canceled) {
|
||||
throw new StateError("Subscription has been canceled.");
|
||||
}
|
||||
// Remove current event listener.
|
||||
_unlisten();
|
||||
_onData = handleData == null
|
||||
? null
|
||||
: _wrapZone<Event>((e) => (handleData as dynamic)(e));
|
||||
_tryResume();
|
||||
}
|
||||
|
||||
/// Has no effect.
|
||||
void onError(Function? handleError) {}
|
||||
|
||||
/// Has no effect.
|
||||
void onDone(void handleDone()?) {}
|
||||
|
||||
void pause([Future? resumeSignal]) {
|
||||
if (_canceled) return;
|
||||
++_pauseCount;
|
||||
_unlisten();
|
||||
|
||||
if (resumeSignal != null) {
|
||||
resumeSignal.whenComplete(resume);
|
||||
}
|
||||
}
|
||||
|
||||
bool get isPaused => _pauseCount > 0;
|
||||
|
||||
void resume() {
|
||||
if (_canceled || !isPaused) return;
|
||||
--_pauseCount;
|
||||
_tryResume();
|
||||
}
|
||||
|
||||
void _tryResume() {
|
||||
if (_onData != null && !isPaused) {
|
||||
_target!.addEventListener(_eventType, _onData, _useCapture);
|
||||
}
|
||||
}
|
||||
|
||||
void _unlisten() {
|
||||
if (_onData != null) {
|
||||
_target!.removeEventListener(_eventType, _onData, _useCapture);
|
||||
}
|
||||
}
|
||||
|
||||
Future<E> asFuture<E>([E? futureValue]) {
|
||||
// We just need a future that will never succeed or fail.
|
||||
var completer = new Completer<E>();
|
||||
return completer.future;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A stream of custom events, which enables the user to "fire" (add) their own
|
||||
* custom events to a stream.
|
||||
*/
|
||||
abstract class CustomStream<T extends Event> implements Stream<T> {
|
||||
/**
|
||||
* Add the following custom event to the stream for dispatching to interested
|
||||
* listeners.
|
||||
*/
|
||||
void add(T event);
|
||||
}
|
||||
|
||||
class _CustomEventStreamImpl<T extends Event> extends Stream<T>
|
||||
implements CustomStream<T> {
|
||||
StreamController<T> _streamController;
|
||||
/** The type of event this stream is providing (e.g. "keydown"). */
|
||||
String _type;
|
||||
|
||||
_CustomEventStreamImpl(String type)
|
||||
: _type = type,
|
||||
_streamController = new StreamController.broadcast(sync: true);
|
||||
|
||||
// Delegate all regular Stream behavior to our wrapped Stream.
|
||||
StreamSubscription<T> listen(void onData(T event)?,
|
||||
{Function? onError, void onDone()?, bool? cancelOnError}) {
|
||||
return _streamController.stream.listen(onData,
|
||||
onError: onError, onDone: onDone, cancelOnError: cancelOnError);
|
||||
}
|
||||
|
||||
Stream<T> asBroadcastStream(
|
||||
{void onListen(StreamSubscription<T> subscription)?,
|
||||
void onCancel(StreamSubscription<T> subscription)?}) =>
|
||||
_streamController.stream;
|
||||
|
||||
bool get isBroadcast => true;
|
||||
|
||||
void add(T event) {
|
||||
if (event.type == _type) _streamController.add(event);
|
||||
}
|
||||
}
|
||||
|
||||
class _CustomKeyEventStreamImpl extends _CustomEventStreamImpl<KeyEvent>
|
||||
implements CustomStream<KeyEvent> {
|
||||
_CustomKeyEventStreamImpl(String type) : super(type);
|
||||
|
||||
void add(KeyEvent event) {
|
||||
if (event.type == _type) {
|
||||
event.currentTarget!.dispatchEvent(event._parent);
|
||||
_streamController.add(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A pool of streams whose events are unified and emitted through a central
|
||||
* stream.
|
||||
*/
|
||||
// TODO (efortuna): Remove this when Issue 12218 is addressed.
|
||||
class _StreamPool<T> {
|
||||
StreamController<T>? _controller;
|
||||
|
||||
/// Subscriptions to the streams that make up the pool.
|
||||
var _subscriptions = new Map<Stream<T>, StreamSubscription<T>>();
|
||||
|
||||
/**
|
||||
* Creates a new stream pool where [stream] can be listened to more than
|
||||
* once.
|
||||
*
|
||||
* Any events from buffered streams in the pool will be emitted immediately,
|
||||
* regardless of whether [stream] has any subscribers.
|
||||
*/
|
||||
_StreamPool.broadcast() {
|
||||
_controller =
|
||||
new StreamController<T>.broadcast(sync: true, onCancel: close);
|
||||
}
|
||||
|
||||
/**
|
||||
* The stream through which all events from streams in the pool are emitted.
|
||||
*/
|
||||
Stream<T> get stream => _controller!.stream;
|
||||
|
||||
/**
|
||||
* Adds [stream] as a member of this pool.
|
||||
*
|
||||
* Any events from [stream] will be emitted through [this.stream]. If
|
||||
* [stream] is sync, they'll be emitted synchronously; if [stream] is async,
|
||||
* they'll be emitted asynchronously.
|
||||
*/
|
||||
void add(Stream<T> stream) {
|
||||
if (_subscriptions.containsKey(stream)) return;
|
||||
_subscriptions[stream] = stream.listen(_controller!.add,
|
||||
onError: _controller!.addError, onDone: () => remove(stream));
|
||||
}
|
||||
|
||||
/** Removes [stream] as a member of this pool. */
|
||||
void remove(Stream<T> stream) {
|
||||
var subscription = _subscriptions.remove(stream);
|
||||
if (subscription != null) subscription.cancel();
|
||||
}
|
||||
|
||||
/** Removes all streams from this pool and closes [stream]. */
|
||||
void close() {
|
||||
for (var subscription in _subscriptions.values) {
|
||||
subscription.cancel();
|
||||
}
|
||||
_subscriptions.clear();
|
||||
_controller!.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A factory to expose DOM events as streams, where the DOM event name has to
|
||||
* be determined on the fly (for example, mouse wheel events).
|
||||
*/
|
||||
class _CustomEventStreamProvider<T extends Event>
|
||||
implements EventStreamProvider<T> {
|
||||
final _eventTypeGetter;
|
||||
const _CustomEventStreamProvider(this._eventTypeGetter);
|
||||
|
||||
Stream<T> forTarget(EventTarget? e, {bool useCapture: false}) {
|
||||
return new _EventStream<T>(e, _eventTypeGetter(e), useCapture);
|
||||
}
|
||||
|
||||
ElementStream<T> forElement(Element e, {bool useCapture: false}) {
|
||||
return new _ElementEventStreamImpl<T>(e, _eventTypeGetter(e), useCapture);
|
||||
}
|
||||
|
||||
ElementStream<T> _forElementList(ElementList<Element> e,
|
||||
{bool useCapture: false}) {
|
||||
return new _ElementListEventStreamImpl<T>(
|
||||
e, _eventTypeGetter(e), useCapture);
|
||||
}
|
||||
|
||||
String getEventType(EventTarget target) {
|
||||
return _eventTypeGetter(target);
|
||||
}
|
||||
|
||||
String get _eventType =>
|
||||
throw new UnsupportedError('Access type through getEventType method.');
|
||||
}
|
||||
@@ -1,449 +0,0 @@
|
||||
// DO NOT EDIT- this file is generated from running tool/generator.sh.
|
||||
|
||||
// Copyright (c) 2013, 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 dart.dom.html;
|
||||
|
||||
/**
|
||||
* A Dart DOM validator generated from Caja whitelists.
|
||||
*
|
||||
* This contains a whitelist of known HTML tagNames and attributes and will only
|
||||
* accept known good values.
|
||||
*
|
||||
* See also:
|
||||
*
|
||||
* * <https://code.google.com/p/google-caja/wiki/CajaWhitelists>
|
||||
*/
|
||||
class _Html5NodeValidator implements NodeValidator {
|
||||
static final Set<String> _allowedElements = new Set.from([
|
||||
'A',
|
||||
'ABBR',
|
||||
'ACRONYM',
|
||||
'ADDRESS',
|
||||
'AREA',
|
||||
'ARTICLE',
|
||||
'ASIDE',
|
||||
'AUDIO',
|
||||
'B',
|
||||
'BDI',
|
||||
'BDO',
|
||||
'BIG',
|
||||
'BLOCKQUOTE',
|
||||
'BR',
|
||||
'BUTTON',
|
||||
'CANVAS',
|
||||
'CAPTION',
|
||||
'CENTER',
|
||||
'CITE',
|
||||
'CODE',
|
||||
'COL',
|
||||
'COLGROUP',
|
||||
'COMMAND',
|
||||
'DATA',
|
||||
'DATALIST',
|
||||
'DD',
|
||||
'DEL',
|
||||
'DETAILS',
|
||||
'DFN',
|
||||
'DIR',
|
||||
'DIV',
|
||||
'DL',
|
||||
'DT',
|
||||
'EM',
|
||||
'FIELDSET',
|
||||
'FIGCAPTION',
|
||||
'FIGURE',
|
||||
'FONT',
|
||||
'FOOTER',
|
||||
'FORM',
|
||||
'H1',
|
||||
'H2',
|
||||
'H3',
|
||||
'H4',
|
||||
'H5',
|
||||
'H6',
|
||||
'HEADER',
|
||||
'HGROUP',
|
||||
'HR',
|
||||
'I',
|
||||
'IFRAME',
|
||||
'IMG',
|
||||
'INPUT',
|
||||
'INS',
|
||||
'KBD',
|
||||
'LABEL',
|
||||
'LEGEND',
|
||||
'LI',
|
||||
'MAP',
|
||||
'MARK',
|
||||
'MENU',
|
||||
'METER',
|
||||
'NAV',
|
||||
'NOBR',
|
||||
'OL',
|
||||
'OPTGROUP',
|
||||
'OPTION',
|
||||
'OUTPUT',
|
||||
'P',
|
||||
'PRE',
|
||||
'PROGRESS',
|
||||
'Q',
|
||||
'S',
|
||||
'SAMP',
|
||||
'SECTION',
|
||||
'SELECT',
|
||||
'SMALL',
|
||||
'SOURCE',
|
||||
'SPAN',
|
||||
'STRIKE',
|
||||
'STRONG',
|
||||
'SUB',
|
||||
'SUMMARY',
|
||||
'SUP',
|
||||
'TABLE',
|
||||
'TBODY',
|
||||
'TD',
|
||||
'TEXTAREA',
|
||||
'TFOOT',
|
||||
'TH',
|
||||
'THEAD',
|
||||
'TIME',
|
||||
'TR',
|
||||
'TRACK',
|
||||
'TT',
|
||||
'U',
|
||||
'UL',
|
||||
'VAR',
|
||||
'VIDEO',
|
||||
'WBR',
|
||||
]);
|
||||
|
||||
static const _standardAttributes = const <String>[
|
||||
'*::class',
|
||||
'*::dir',
|
||||
'*::draggable',
|
||||
'*::hidden',
|
||||
'*::id',
|
||||
'*::inert',
|
||||
'*::itemprop',
|
||||
'*::itemref',
|
||||
'*::itemscope',
|
||||
'*::lang',
|
||||
'*::spellcheck',
|
||||
'*::title',
|
||||
'*::translate',
|
||||
'A::accesskey',
|
||||
'A::coords',
|
||||
'A::hreflang',
|
||||
'A::name',
|
||||
'A::shape',
|
||||
'A::tabindex',
|
||||
'A::target',
|
||||
'A::type',
|
||||
'AREA::accesskey',
|
||||
'AREA::alt',
|
||||
'AREA::coords',
|
||||
'AREA::nohref',
|
||||
'AREA::shape',
|
||||
'AREA::tabindex',
|
||||
'AREA::target',
|
||||
'AUDIO::controls',
|
||||
'AUDIO::loop',
|
||||
'AUDIO::mediagroup',
|
||||
'AUDIO::muted',
|
||||
'AUDIO::preload',
|
||||
'BDO::dir',
|
||||
'BODY::alink',
|
||||
'BODY::bgcolor',
|
||||
'BODY::link',
|
||||
'BODY::text',
|
||||
'BODY::vlink',
|
||||
'BR::clear',
|
||||
'BUTTON::accesskey',
|
||||
'BUTTON::disabled',
|
||||
'BUTTON::name',
|
||||
'BUTTON::tabindex',
|
||||
'BUTTON::type',
|
||||
'BUTTON::value',
|
||||
'CANVAS::height',
|
||||
'CANVAS::width',
|
||||
'CAPTION::align',
|
||||
'COL::align',
|
||||
'COL::char',
|
||||
'COL::charoff',
|
||||
'COL::span',
|
||||
'COL::valign',
|
||||
'COL::width',
|
||||
'COLGROUP::align',
|
||||
'COLGROUP::char',
|
||||
'COLGROUP::charoff',
|
||||
'COLGROUP::span',
|
||||
'COLGROUP::valign',
|
||||
'COLGROUP::width',
|
||||
'COMMAND::checked',
|
||||
'COMMAND::command',
|
||||
'COMMAND::disabled',
|
||||
'COMMAND::label',
|
||||
'COMMAND::radiogroup',
|
||||
'COMMAND::type',
|
||||
'DATA::value',
|
||||
'DEL::datetime',
|
||||
'DETAILS::open',
|
||||
'DIR::compact',
|
||||
'DIV::align',
|
||||
'DL::compact',
|
||||
'FIELDSET::disabled',
|
||||
'FONT::color',
|
||||
'FONT::face',
|
||||
'FONT::size',
|
||||
'FORM::accept',
|
||||
'FORM::autocomplete',
|
||||
'FORM::enctype',
|
||||
'FORM::method',
|
||||
'FORM::name',
|
||||
'FORM::novalidate',
|
||||
'FORM::target',
|
||||
'FRAME::name',
|
||||
'H1::align',
|
||||
'H2::align',
|
||||
'H3::align',
|
||||
'H4::align',
|
||||
'H5::align',
|
||||
'H6::align',
|
||||
'HR::align',
|
||||
'HR::noshade',
|
||||
'HR::size',
|
||||
'HR::width',
|
||||
'HTML::version',
|
||||
'IFRAME::align',
|
||||
'IFRAME::frameborder',
|
||||
'IFRAME::height',
|
||||
'IFRAME::marginheight',
|
||||
'IFRAME::marginwidth',
|
||||
'IFRAME::width',
|
||||
'IMG::align',
|
||||
'IMG::alt',
|
||||
'IMG::border',
|
||||
'IMG::height',
|
||||
'IMG::hspace',
|
||||
'IMG::ismap',
|
||||
'IMG::name',
|
||||
'IMG::usemap',
|
||||
'IMG::vspace',
|
||||
'IMG::width',
|
||||
'INPUT::accept',
|
||||
'INPUT::accesskey',
|
||||
'INPUT::align',
|
||||
'INPUT::alt',
|
||||
'INPUT::autocomplete',
|
||||
'INPUT::autofocus',
|
||||
'INPUT::checked',
|
||||
'INPUT::disabled',
|
||||
'INPUT::inputmode',
|
||||
'INPUT::ismap',
|
||||
'INPUT::list',
|
||||
'INPUT::max',
|
||||
'INPUT::maxlength',
|
||||
'INPUT::min',
|
||||
'INPUT::multiple',
|
||||
'INPUT::name',
|
||||
'INPUT::placeholder',
|
||||
'INPUT::readonly',
|
||||
'INPUT::required',
|
||||
'INPUT::size',
|
||||
'INPUT::step',
|
||||
'INPUT::tabindex',
|
||||
'INPUT::type',
|
||||
'INPUT::usemap',
|
||||
'INPUT::value',
|
||||
'INS::datetime',
|
||||
'KEYGEN::disabled',
|
||||
'KEYGEN::keytype',
|
||||
'KEYGEN::name',
|
||||
'LABEL::accesskey',
|
||||
'LABEL::for',
|
||||
'LEGEND::accesskey',
|
||||
'LEGEND::align',
|
||||
'LI::type',
|
||||
'LI::value',
|
||||
'LINK::sizes',
|
||||
'MAP::name',
|
||||
'MENU::compact',
|
||||
'MENU::label',
|
||||
'MENU::type',
|
||||
'METER::high',
|
||||
'METER::low',
|
||||
'METER::max',
|
||||
'METER::min',
|
||||
'METER::value',
|
||||
'OBJECT::typemustmatch',
|
||||
'OL::compact',
|
||||
'OL::reversed',
|
||||
'OL::start',
|
||||
'OL::type',
|
||||
'OPTGROUP::disabled',
|
||||
'OPTGROUP::label',
|
||||
'OPTION::disabled',
|
||||
'OPTION::label',
|
||||
'OPTION::selected',
|
||||
'OPTION::value',
|
||||
'OUTPUT::for',
|
||||
'OUTPUT::name',
|
||||
'P::align',
|
||||
'PRE::width',
|
||||
'PROGRESS::max',
|
||||
'PROGRESS::min',
|
||||
'PROGRESS::value',
|
||||
'SELECT::autocomplete',
|
||||
'SELECT::disabled',
|
||||
'SELECT::multiple',
|
||||
'SELECT::name',
|
||||
'SELECT::required',
|
||||
'SELECT::size',
|
||||
'SELECT::tabindex',
|
||||
'SOURCE::type',
|
||||
'TABLE::align',
|
||||
'TABLE::bgcolor',
|
||||
'TABLE::border',
|
||||
'TABLE::cellpadding',
|
||||
'TABLE::cellspacing',
|
||||
'TABLE::frame',
|
||||
'TABLE::rules',
|
||||
'TABLE::summary',
|
||||
'TABLE::width',
|
||||
'TBODY::align',
|
||||
'TBODY::char',
|
||||
'TBODY::charoff',
|
||||
'TBODY::valign',
|
||||
'TD::abbr',
|
||||
'TD::align',
|
||||
'TD::axis',
|
||||
'TD::bgcolor',
|
||||
'TD::char',
|
||||
'TD::charoff',
|
||||
'TD::colspan',
|
||||
'TD::headers',
|
||||
'TD::height',
|
||||
'TD::nowrap',
|
||||
'TD::rowspan',
|
||||
'TD::scope',
|
||||
'TD::valign',
|
||||
'TD::width',
|
||||
'TEXTAREA::accesskey',
|
||||
'TEXTAREA::autocomplete',
|
||||
'TEXTAREA::cols',
|
||||
'TEXTAREA::disabled',
|
||||
'TEXTAREA::inputmode',
|
||||
'TEXTAREA::name',
|
||||
'TEXTAREA::placeholder',
|
||||
'TEXTAREA::readonly',
|
||||
'TEXTAREA::required',
|
||||
'TEXTAREA::rows',
|
||||
'TEXTAREA::tabindex',
|
||||
'TEXTAREA::wrap',
|
||||
'TFOOT::align',
|
||||
'TFOOT::char',
|
||||
'TFOOT::charoff',
|
||||
'TFOOT::valign',
|
||||
'TH::abbr',
|
||||
'TH::align',
|
||||
'TH::axis',
|
||||
'TH::bgcolor',
|
||||
'TH::char',
|
||||
'TH::charoff',
|
||||
'TH::colspan',
|
||||
'TH::headers',
|
||||
'TH::height',
|
||||
'TH::nowrap',
|
||||
'TH::rowspan',
|
||||
'TH::scope',
|
||||
'TH::valign',
|
||||
'TH::width',
|
||||
'THEAD::align',
|
||||
'THEAD::char',
|
||||
'THEAD::charoff',
|
||||
'THEAD::valign',
|
||||
'TR::align',
|
||||
'TR::bgcolor',
|
||||
'TR::char',
|
||||
'TR::charoff',
|
||||
'TR::valign',
|
||||
'TRACK::default',
|
||||
'TRACK::kind',
|
||||
'TRACK::label',
|
||||
'TRACK::srclang',
|
||||
'UL::compact',
|
||||
'UL::type',
|
||||
'VIDEO::controls',
|
||||
'VIDEO::height',
|
||||
'VIDEO::loop',
|
||||
'VIDEO::mediagroup',
|
||||
'VIDEO::muted',
|
||||
'VIDEO::preload',
|
||||
'VIDEO::width',
|
||||
];
|
||||
|
||||
static const _uriAttributes = const <String>[
|
||||
'A::href',
|
||||
'AREA::href',
|
||||
'BLOCKQUOTE::cite',
|
||||
'BODY::background',
|
||||
'COMMAND::icon',
|
||||
'DEL::cite',
|
||||
'FORM::action',
|
||||
'IMG::src',
|
||||
'INPUT::src',
|
||||
'INS::cite',
|
||||
'Q::cite',
|
||||
'VIDEO::poster',
|
||||
];
|
||||
|
||||
final UriPolicy uriPolicy;
|
||||
|
||||
static final Map<String, Function> _attributeValidators = {};
|
||||
|
||||
/**
|
||||
* All known URI attributes will be validated against the UriPolicy, if
|
||||
* [uriPolicy] is null then a default UriPolicy will be used.
|
||||
*/
|
||||
_Html5NodeValidator({UriPolicy? uriPolicy})
|
||||
: uriPolicy = uriPolicy ?? UriPolicy() {
|
||||
if (_attributeValidators.isEmpty) {
|
||||
for (var attr in _standardAttributes) {
|
||||
_attributeValidators[attr] = _standardAttributeValidator;
|
||||
}
|
||||
|
||||
for (var attr in _uriAttributes) {
|
||||
_attributeValidators[attr] = _uriAttributeValidator;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool allowsElement(Element element) {
|
||||
return _allowedElements.contains(Element._safeTagName(element));
|
||||
}
|
||||
|
||||
bool allowsAttribute(Element element, String attributeName, String value) {
|
||||
var tagName = Element._safeTagName(element);
|
||||
var validator = _attributeValidators['$tagName::$attributeName'];
|
||||
if (validator == null) {
|
||||
validator = _attributeValidators['*::$attributeName'];
|
||||
}
|
||||
if (validator == null) {
|
||||
return false;
|
||||
}
|
||||
return validator(element, attributeName, value, this);
|
||||
}
|
||||
|
||||
static bool _standardAttributeValidator(Element element, String attributeName,
|
||||
String value, _Html5NodeValidator context) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _uriAttributeValidator(Element element, String attributeName,
|
||||
String value, _Html5NodeValidator context) {
|
||||
return context.uriPolicy.allowsUri(value);
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
// 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 dart.dom.html;
|
||||
|
||||
abstract class ImmutableListMixin<E> implements List<E> {
|
||||
// From Iterable<$E>:
|
||||
Iterator<E> get iterator {
|
||||
// Note: NodeLists are not fixed size. And most probably length shouldn't
|
||||
// be cached in both iterator _and_ forEach method. For now caching it
|
||||
// for consistency.
|
||||
return new FixedSizeListIterator<E>(this);
|
||||
}
|
||||
|
||||
// From List<E>:
|
||||
void add(E value) {
|
||||
throw new UnsupportedError("Cannot add to immutable List.");
|
||||
}
|
||||
|
||||
void addAll(Iterable<E> iterable) {
|
||||
throw new UnsupportedError("Cannot add to immutable List.");
|
||||
}
|
||||
|
||||
void sort([int compare(E a, E b)?]) {
|
||||
throw new UnsupportedError("Cannot sort immutable List.");
|
||||
}
|
||||
|
||||
void shuffle([Random? random]) {
|
||||
throw new UnsupportedError("Cannot shuffle immutable List.");
|
||||
}
|
||||
|
||||
void insert(int index, E element) {
|
||||
throw new UnsupportedError("Cannot add to immutable List.");
|
||||
}
|
||||
|
||||
void insertAll(int index, Iterable<E> iterable) {
|
||||
throw new UnsupportedError("Cannot add to immutable List.");
|
||||
}
|
||||
|
||||
void setAll(int index, Iterable<E> iterable) {
|
||||
throw new UnsupportedError("Cannot modify an immutable List.");
|
||||
}
|
||||
|
||||
E removeAt(int pos) {
|
||||
throw new UnsupportedError("Cannot remove from immutable List.");
|
||||
}
|
||||
|
||||
E removeLast() {
|
||||
throw new UnsupportedError("Cannot remove from immutable List.");
|
||||
}
|
||||
|
||||
bool remove(Object? object) {
|
||||
throw new UnsupportedError("Cannot remove from immutable List.");
|
||||
}
|
||||
|
||||
void removeWhere(bool test(E element)) {
|
||||
throw new UnsupportedError("Cannot remove from immutable List.");
|
||||
}
|
||||
|
||||
void retainWhere(bool test(E element)) {
|
||||
throw new UnsupportedError("Cannot remove from immutable List.");
|
||||
}
|
||||
|
||||
void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
|
||||
throw new UnsupportedError("Cannot setRange on immutable List.");
|
||||
}
|
||||
|
||||
void removeRange(int start, int end) {
|
||||
throw new UnsupportedError("Cannot removeRange on immutable List.");
|
||||
}
|
||||
|
||||
void replaceRange(int start, int end, Iterable<E> iterable) {
|
||||
throw new UnsupportedError("Cannot modify an immutable List.");
|
||||
}
|
||||
|
||||
void fillRange(int start, int end, [E? fillValue]) {
|
||||
throw new UnsupportedError("Cannot modify an immutable List.");
|
||||
}
|
||||
}
|
||||
@@ -1,331 +0,0 @@
|
||||
// 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 html;
|
||||
|
||||
/**
|
||||
* Defines the keycode values for keys that are returned by
|
||||
* KeyboardEvent.keyCode.
|
||||
*
|
||||
* Important note: There is substantial divergence in how different browsers
|
||||
* handle keycodes and their variants in different locales/keyboard layouts. We
|
||||
* provide these constants to help make code processing keys more readable.
|
||||
*/
|
||||
abstract class KeyCode {
|
||||
// These constant names were borrowed from Closure's Keycode enumeration
|
||||
// class.
|
||||
// https://github.com/google/closure-library/blob/master/closure/goog/events/keycodes.js
|
||||
static const int WIN_KEY_FF_LINUX = 0;
|
||||
static const int MAC_ENTER = 3;
|
||||
static const int BACKSPACE = 8;
|
||||
static const int TAB = 9;
|
||||
/** NUM_CENTER is also NUMLOCK for FF and Safari on Mac. */
|
||||
static const int NUM_CENTER = 12;
|
||||
static const int ENTER = 13;
|
||||
static const int SHIFT = 16;
|
||||
static const int CTRL = 17;
|
||||
static const int ALT = 18;
|
||||
static const int PAUSE = 19;
|
||||
static const int CAPS_LOCK = 20;
|
||||
static const int ESC = 27;
|
||||
static const int SPACE = 32;
|
||||
static const int PAGE_UP = 33;
|
||||
static const int PAGE_DOWN = 34;
|
||||
static const int END = 35;
|
||||
static const int HOME = 36;
|
||||
static const int LEFT = 37;
|
||||
static const int UP = 38;
|
||||
static const int RIGHT = 39;
|
||||
static const int DOWN = 40;
|
||||
static const int NUM_NORTH_EAST = 33;
|
||||
static const int NUM_SOUTH_EAST = 34;
|
||||
static const int NUM_SOUTH_WEST = 35;
|
||||
static const int NUM_NORTH_WEST = 36;
|
||||
static const int NUM_WEST = 37;
|
||||
static const int NUM_NORTH = 38;
|
||||
static const int NUM_EAST = 39;
|
||||
static const int NUM_SOUTH = 40;
|
||||
static const int PRINT_SCREEN = 44;
|
||||
static const int INSERT = 45;
|
||||
static const int NUM_INSERT = 45;
|
||||
static const int DELETE = 46;
|
||||
static const int NUM_DELETE = 46;
|
||||
static const int ZERO = 48;
|
||||
static const int ONE = 49;
|
||||
static const int TWO = 50;
|
||||
static const int THREE = 51;
|
||||
static const int FOUR = 52;
|
||||
static const int FIVE = 53;
|
||||
static const int SIX = 54;
|
||||
static const int SEVEN = 55;
|
||||
static const int EIGHT = 56;
|
||||
static const int NINE = 57;
|
||||
static const int FF_SEMICOLON = 59;
|
||||
static const int FF_EQUALS = 61;
|
||||
/**
|
||||
* CAUTION: The question mark is for US-keyboard layouts. It varies
|
||||
* for other locales and keyboard layouts.
|
||||
*/
|
||||
static const int QUESTION_MARK = 63;
|
||||
static const int A = 65;
|
||||
static const int B = 66;
|
||||
static const int C = 67;
|
||||
static const int D = 68;
|
||||
static const int E = 69;
|
||||
static const int F = 70;
|
||||
static const int G = 71;
|
||||
static const int H = 72;
|
||||
static const int I = 73;
|
||||
static const int J = 74;
|
||||
static const int K = 75;
|
||||
static const int L = 76;
|
||||
static const int M = 77;
|
||||
static const int N = 78;
|
||||
static const int O = 79;
|
||||
static const int P = 80;
|
||||
static const int Q = 81;
|
||||
static const int R = 82;
|
||||
static const int S = 83;
|
||||
static const int T = 84;
|
||||
static const int U = 85;
|
||||
static const int V = 86;
|
||||
static const int W = 87;
|
||||
static const int X = 88;
|
||||
static const int Y = 89;
|
||||
static const int Z = 90;
|
||||
static const int META = 91;
|
||||
static const int WIN_KEY_LEFT = 91;
|
||||
static const int WIN_KEY_RIGHT = 92;
|
||||
static const int CONTEXT_MENU = 93;
|
||||
static const int NUM_ZERO = 96;
|
||||
static const int NUM_ONE = 97;
|
||||
static const int NUM_TWO = 98;
|
||||
static const int NUM_THREE = 99;
|
||||
static const int NUM_FOUR = 100;
|
||||
static const int NUM_FIVE = 101;
|
||||
static const int NUM_SIX = 102;
|
||||
static const int NUM_SEVEN = 103;
|
||||
static const int NUM_EIGHT = 104;
|
||||
static const int NUM_NINE = 105;
|
||||
static const int NUM_MULTIPLY = 106;
|
||||
static const int NUM_PLUS = 107;
|
||||
static const int NUM_MINUS = 109;
|
||||
static const int NUM_PERIOD = 110;
|
||||
static const int NUM_DIVISION = 111;
|
||||
static const int F1 = 112;
|
||||
static const int F2 = 113;
|
||||
static const int F3 = 114;
|
||||
static const int F4 = 115;
|
||||
static const int F5 = 116;
|
||||
static const int F6 = 117;
|
||||
static const int F7 = 118;
|
||||
static const int F8 = 119;
|
||||
static const int F9 = 120;
|
||||
static const int F10 = 121;
|
||||
static const int F11 = 122;
|
||||
static const int F12 = 123;
|
||||
static const int NUMLOCK = 144;
|
||||
static const int SCROLL_LOCK = 145;
|
||||
|
||||
// OS-specific media keys like volume controls and browser controls.
|
||||
static const int FIRST_MEDIA_KEY = 166;
|
||||
static const int LAST_MEDIA_KEY = 183;
|
||||
|
||||
/**
|
||||
* CAUTION: This constant requires localization for other locales and keyboard
|
||||
* layouts.
|
||||
*/
|
||||
static const int SEMICOLON = 186;
|
||||
/**
|
||||
* CAUTION: This constant requires localization for other locales and keyboard
|
||||
* layouts.
|
||||
*/
|
||||
static const int DASH = 189;
|
||||
/**
|
||||
* CAUTION: This constant requires localization for other locales and keyboard
|
||||
* layouts.
|
||||
*/
|
||||
static const int EQUALS = 187;
|
||||
/**
|
||||
* CAUTION: This constant requires localization for other locales and keyboard
|
||||
* layouts.
|
||||
*/
|
||||
static const int COMMA = 188;
|
||||
/**
|
||||
* CAUTION: This constant requires localization for other locales and keyboard
|
||||
* layouts.
|
||||
*/
|
||||
static const int PERIOD = 190;
|
||||
/**
|
||||
* CAUTION: This constant requires localization for other locales and keyboard
|
||||
* layouts.
|
||||
*/
|
||||
static const int SLASH = 191;
|
||||
/**
|
||||
* CAUTION: This constant requires localization for other locales and keyboard
|
||||
* layouts.
|
||||
*/
|
||||
static const int APOSTROPHE = 192;
|
||||
/**
|
||||
* CAUTION: This constant requires localization for other locales and keyboard
|
||||
* layouts.
|
||||
*/
|
||||
static const int TILDE = 192;
|
||||
/**
|
||||
* CAUTION: This constant requires localization for other locales and keyboard
|
||||
* layouts.
|
||||
*/
|
||||
static const int SINGLE_QUOTE = 222;
|
||||
/**
|
||||
* CAUTION: This constant requires localization for other locales and keyboard
|
||||
* layouts.
|
||||
*/
|
||||
static const int OPEN_SQUARE_BRACKET = 219;
|
||||
/**
|
||||
* CAUTION: This constant requires localization for other locales and keyboard
|
||||
* layouts.
|
||||
*/
|
||||
static const int BACKSLASH = 220;
|
||||
/**
|
||||
* CAUTION: This constant requires localization for other locales and keyboard
|
||||
* layouts.
|
||||
*/
|
||||
static const int CLOSE_SQUARE_BRACKET = 221;
|
||||
static const int WIN_KEY = 224;
|
||||
static const int MAC_FF_META = 224;
|
||||
static const int WIN_IME = 229;
|
||||
|
||||
/** A sentinel value if the keycode could not be determined. */
|
||||
static const int UNKNOWN = -1;
|
||||
|
||||
/**
|
||||
* Returns true if the keyCode produces a (US keyboard) character.
|
||||
* Note: This does not (yet) cover characters on non-US keyboards (Russian,
|
||||
* Hebrew, etc.).
|
||||
*/
|
||||
static bool isCharacterKey(int keyCode) {
|
||||
if ((keyCode >= ZERO && keyCode <= NINE) ||
|
||||
(keyCode >= NUM_ZERO && keyCode <= NUM_MULTIPLY) ||
|
||||
(keyCode >= A && keyCode <= Z)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Safari sends zero key code for non-latin characters.
|
||||
if (Device.isWebKit && keyCode == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (keyCode == SPACE ||
|
||||
keyCode == QUESTION_MARK ||
|
||||
keyCode == NUM_PLUS ||
|
||||
keyCode == NUM_MINUS ||
|
||||
keyCode == NUM_PERIOD ||
|
||||
keyCode == NUM_DIVISION ||
|
||||
keyCode == SEMICOLON ||
|
||||
keyCode == FF_SEMICOLON ||
|
||||
keyCode == DASH ||
|
||||
keyCode == EQUALS ||
|
||||
keyCode == FF_EQUALS ||
|
||||
keyCode == COMMA ||
|
||||
keyCode == PERIOD ||
|
||||
keyCode == SLASH ||
|
||||
keyCode == APOSTROPHE ||
|
||||
keyCode == SINGLE_QUOTE ||
|
||||
keyCode == OPEN_SQUARE_BRACKET ||
|
||||
keyCode == BACKSLASH ||
|
||||
keyCode == CLOSE_SQUARE_BRACKET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Experimental helper function for converting keyCodes to keyNames for the
|
||||
* keyIdentifier attribute still used in browsers not updated with current
|
||||
* spec. This is an imperfect conversion! It will need to be refined, but
|
||||
* hopefully it can just completely go away once all the browsers update to
|
||||
* follow the DOM3 spec.
|
||||
*/
|
||||
static String _convertKeyCodeToKeyName(int keyCode) {
|
||||
switch (keyCode) {
|
||||
case KeyCode.ALT:
|
||||
return _KeyName.ALT;
|
||||
case KeyCode.BACKSPACE:
|
||||
return _KeyName.BACKSPACE;
|
||||
case KeyCode.CAPS_LOCK:
|
||||
return _KeyName.CAPS_LOCK;
|
||||
case KeyCode.CTRL:
|
||||
return _KeyName.CONTROL;
|
||||
case KeyCode.DELETE:
|
||||
return _KeyName.DEL;
|
||||
case KeyCode.DOWN:
|
||||
return _KeyName.DOWN;
|
||||
case KeyCode.END:
|
||||
return _KeyName.END;
|
||||
case KeyCode.ENTER:
|
||||
return _KeyName.ENTER;
|
||||
case KeyCode.ESC:
|
||||
return _KeyName.ESC;
|
||||
case KeyCode.F1:
|
||||
return _KeyName.F1;
|
||||
case KeyCode.F2:
|
||||
return _KeyName.F2;
|
||||
case KeyCode.F3:
|
||||
return _KeyName.F3;
|
||||
case KeyCode.F4:
|
||||
return _KeyName.F4;
|
||||
case KeyCode.F5:
|
||||
return _KeyName.F5;
|
||||
case KeyCode.F6:
|
||||
return _KeyName.F6;
|
||||
case KeyCode.F7:
|
||||
return _KeyName.F7;
|
||||
case KeyCode.F8:
|
||||
return _KeyName.F8;
|
||||
case KeyCode.F9:
|
||||
return _KeyName.F9;
|
||||
case KeyCode.F10:
|
||||
return _KeyName.F10;
|
||||
case KeyCode.F11:
|
||||
return _KeyName.F11;
|
||||
case KeyCode.F12:
|
||||
return _KeyName.F12;
|
||||
case KeyCode.HOME:
|
||||
return _KeyName.HOME;
|
||||
case KeyCode.INSERT:
|
||||
return _KeyName.INSERT;
|
||||
case KeyCode.LEFT:
|
||||
return _KeyName.LEFT;
|
||||
case KeyCode.META:
|
||||
return _KeyName.META;
|
||||
case KeyCode.NUMLOCK:
|
||||
return _KeyName.NUM_LOCK;
|
||||
case KeyCode.PAGE_DOWN:
|
||||
return _KeyName.PAGE_DOWN;
|
||||
case KeyCode.PAGE_UP:
|
||||
return _KeyName.PAGE_UP;
|
||||
case KeyCode.PAUSE:
|
||||
return _KeyName.PAUSE;
|
||||
case KeyCode.PRINT_SCREEN:
|
||||
return _KeyName.PRINT_SCREEN;
|
||||
case KeyCode.RIGHT:
|
||||
return _KeyName.RIGHT;
|
||||
case KeyCode.SCROLL_LOCK:
|
||||
return _KeyName.SCROLL;
|
||||
case KeyCode.SHIFT:
|
||||
return _KeyName.SHIFT;
|
||||
case KeyCode.SPACE:
|
||||
return _KeyName.SPACEBAR;
|
||||
case KeyCode.TAB:
|
||||
return _KeyName.TAB;
|
||||
case KeyCode.UP:
|
||||
return _KeyName.UP;
|
||||
case KeyCode.WIN_IME:
|
||||
case KeyCode.WIN_KEY:
|
||||
case KeyCode.WIN_KEY_LEFT:
|
||||
case KeyCode.WIN_KEY_RIGHT:
|
||||
return _KeyName.WIN;
|
||||
default:
|
||||
return _KeyName.UNIDENTIFIED;
|
||||
}
|
||||
return _KeyName.UNIDENTIFIED;
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
// Copyright (c) 2011, 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 html;
|
||||
|
||||
/**
|
||||
* Defines the standard key locations returned by
|
||||
* KeyboardEvent.getKeyLocation.
|
||||
*/
|
||||
abstract class KeyLocation {
|
||||
/**
|
||||
* The event key is not distinguished as the left or right version
|
||||
* of the key, and did not originate from the numeric keypad (or did not
|
||||
* originate with a virtual key corresponding to the numeric keypad).
|
||||
*/
|
||||
static const int STANDARD = 0;
|
||||
|
||||
/**
|
||||
* The event key is in the left key location.
|
||||
*/
|
||||
static const int LEFT = 1;
|
||||
|
||||
/**
|
||||
* The event key is in the right key location.
|
||||
*/
|
||||
static const int RIGHT = 2;
|
||||
|
||||
/**
|
||||
* The event key originated on the numeric keypad or with a virtual key
|
||||
* corresponding to the numeric keypad.
|
||||
*/
|
||||
static const int NUMPAD = 3;
|
||||
|
||||
/**
|
||||
* The event key originated on a mobile device, either on a physical
|
||||
* keypad or a virtual keyboard.
|
||||
*/
|
||||
static const int MOBILE = 4;
|
||||
|
||||
/**
|
||||
* The event key originated on a game controller or a joystick on a mobile
|
||||
* device.
|
||||
*/
|
||||
static const int JOYSTICK = 5;
|
||||
}
|
||||
@@ -1,494 +0,0 @@
|
||||
// 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 html;
|
||||
|
||||
/**
|
||||
* Defines the standard keyboard identifier names for keys that are returned
|
||||
* by KeyboardEvent.getKeyboardIdentifier when the key does not have a direct
|
||||
* unicode mapping.
|
||||
*/
|
||||
abstract class _KeyName {
|
||||
/** The Accept (Commit, OK) key */
|
||||
static const String ACCEPT = "Accept";
|
||||
|
||||
/** The Add key */
|
||||
static const String ADD = "Add";
|
||||
|
||||
/** The Again key */
|
||||
static const String AGAIN = "Again";
|
||||
|
||||
/** The All Candidates key */
|
||||
static const String ALL_CANDIDATES = "AllCandidates";
|
||||
|
||||
/** The Alphanumeric key */
|
||||
static const String ALPHANUMERIC = "Alphanumeric";
|
||||
|
||||
/** The Alt (Menu) key */
|
||||
static const String ALT = "Alt";
|
||||
|
||||
/** The Alt-Graph key */
|
||||
static const String ALT_GRAPH = "AltGraph";
|
||||
|
||||
/** The Application key */
|
||||
static const String APPS = "Apps";
|
||||
|
||||
/** The ATTN key */
|
||||
static const String ATTN = "Attn";
|
||||
|
||||
/** The Browser Back key */
|
||||
static const String BROWSER_BACK = "BrowserBack";
|
||||
|
||||
/** The Browser Favorites key */
|
||||
static const String BROWSER_FAVORTIES = "BrowserFavorites";
|
||||
|
||||
/** The Browser Forward key */
|
||||
static const String BROWSER_FORWARD = "BrowserForward";
|
||||
|
||||
/** The Browser Home key */
|
||||
static const String BROWSER_NAME = "BrowserHome";
|
||||
|
||||
/** The Browser Refresh key */
|
||||
static const String BROWSER_REFRESH = "BrowserRefresh";
|
||||
|
||||
/** The Browser Search key */
|
||||
static const String BROWSER_SEARCH = "BrowserSearch";
|
||||
|
||||
/** The Browser Stop key */
|
||||
static const String BROWSER_STOP = "BrowserStop";
|
||||
|
||||
/** The Camera key */
|
||||
static const String CAMERA = "Camera";
|
||||
|
||||
/** The Caps Lock (Capital) key */
|
||||
static const String CAPS_LOCK = "CapsLock";
|
||||
|
||||
/** The Clear key */
|
||||
static const String CLEAR = "Clear";
|
||||
|
||||
/** The Code Input key */
|
||||
static const String CODE_INPUT = "CodeInput";
|
||||
|
||||
/** The Compose key */
|
||||
static const String COMPOSE = "Compose";
|
||||
|
||||
/** The Control (Ctrl) key */
|
||||
static const String CONTROL = "Control";
|
||||
|
||||
/** The Crsel key */
|
||||
static const String CRSEL = "Crsel";
|
||||
|
||||
/** The Convert key */
|
||||
static const String CONVERT = "Convert";
|
||||
|
||||
/** The Copy key */
|
||||
static const String COPY = "Copy";
|
||||
|
||||
/** The Cut key */
|
||||
static const String CUT = "Cut";
|
||||
|
||||
/** The Decimal key */
|
||||
static const String DECIMAL = "Decimal";
|
||||
|
||||
/** The Divide key */
|
||||
static const String DIVIDE = "Divide";
|
||||
|
||||
/** The Down Arrow key */
|
||||
static const String DOWN = "Down";
|
||||
|
||||
/** The diagonal Down-Left Arrow key */
|
||||
static const String DOWN_LEFT = "DownLeft";
|
||||
|
||||
/** The diagonal Down-Right Arrow key */
|
||||
static const String DOWN_RIGHT = "DownRight";
|
||||
|
||||
/** The Eject key */
|
||||
static const String EJECT = "Eject";
|
||||
|
||||
/** The End key */
|
||||
static const String END = "End";
|
||||
|
||||
/**
|
||||
* The Enter key. Note: This key value must also be used for the Return
|
||||
* (Macintosh numpad) key
|
||||
*/
|
||||
static const String ENTER = "Enter";
|
||||
|
||||
/** The Erase EOF key */
|
||||
static const String ERASE_EOF = "EraseEof";
|
||||
|
||||
/** The Execute key */
|
||||
static const String EXECUTE = "Execute";
|
||||
|
||||
/** The Exsel key */
|
||||
static const String EXSEL = "Exsel";
|
||||
|
||||
/** The Function switch key */
|
||||
static const String FN = "Fn";
|
||||
|
||||
/** The F1 key */
|
||||
static const String F1 = "F1";
|
||||
|
||||
/** The F2 key */
|
||||
static const String F2 = "F2";
|
||||
|
||||
/** The F3 key */
|
||||
static const String F3 = "F3";
|
||||
|
||||
/** The F4 key */
|
||||
static const String F4 = "F4";
|
||||
|
||||
/** The F5 key */
|
||||
static const String F5 = "F5";
|
||||
|
||||
/** The F6 key */
|
||||
static const String F6 = "F6";
|
||||
|
||||
/** The F7 key */
|
||||
static const String F7 = "F7";
|
||||
|
||||
/** The F8 key */
|
||||
static const String F8 = "F8";
|
||||
|
||||
/** The F9 key */
|
||||
static const String F9 = "F9";
|
||||
|
||||
/** The F10 key */
|
||||
static const String F10 = "F10";
|
||||
|
||||
/** The F11 key */
|
||||
static const String F11 = "F11";
|
||||
|
||||
/** The F12 key */
|
||||
static const String F12 = "F12";
|
||||
|
||||
/** The F13 key */
|
||||
static const String F13 = "F13";
|
||||
|
||||
/** The F14 key */
|
||||
static const String F14 = "F14";
|
||||
|
||||
/** The F15 key */
|
||||
static const String F15 = "F15";
|
||||
|
||||
/** The F16 key */
|
||||
static const String F16 = "F16";
|
||||
|
||||
/** The F17 key */
|
||||
static const String F17 = "F17";
|
||||
|
||||
/** The F18 key */
|
||||
static const String F18 = "F18";
|
||||
|
||||
/** The F19 key */
|
||||
static const String F19 = "F19";
|
||||
|
||||
/** The F20 key */
|
||||
static const String F20 = "F20";
|
||||
|
||||
/** The F21 key */
|
||||
static const String F21 = "F21";
|
||||
|
||||
/** The F22 key */
|
||||
static const String F22 = "F22";
|
||||
|
||||
/** The F23 key */
|
||||
static const String F23 = "F23";
|
||||
|
||||
/** The F24 key */
|
||||
static const String F24 = "F24";
|
||||
|
||||
/** The Final Mode (Final) key used on some asian keyboards */
|
||||
static const String FINAL_MODE = "FinalMode";
|
||||
|
||||
/** The Find key */
|
||||
static const String FIND = "Find";
|
||||
|
||||
/** The Full-Width Characters key */
|
||||
static const String FULL_WIDTH = "FullWidth";
|
||||
|
||||
/** The Half-Width Characters key */
|
||||
static const String HALF_WIDTH = "HalfWidth";
|
||||
|
||||
/** The Hangul (Korean characters) Mode key */
|
||||
static const String HANGUL_MODE = "HangulMode";
|
||||
|
||||
/** The Hanja (Korean characters) Mode key */
|
||||
static const String HANJA_MODE = "HanjaMode";
|
||||
|
||||
/** The Help key */
|
||||
static const String HELP = "Help";
|
||||
|
||||
/** The Hiragana (Japanese Kana characters) key */
|
||||
static const String HIRAGANA = "Hiragana";
|
||||
|
||||
/** The Home key */
|
||||
static const String HOME = "Home";
|
||||
|
||||
/** The Insert (Ins) key */
|
||||
static const String INSERT = "Insert";
|
||||
|
||||
/** The Japanese-Hiragana key */
|
||||
static const String JAPANESE_HIRAGANA = "JapaneseHiragana";
|
||||
|
||||
/** The Japanese-Katakana key */
|
||||
static const String JAPANESE_KATAKANA = "JapaneseKatakana";
|
||||
|
||||
/** The Japanese-Romaji key */
|
||||
static const String JAPANESE_ROMAJI = "JapaneseRomaji";
|
||||
|
||||
/** The Junja Mode key */
|
||||
static const String JUNJA_MODE = "JunjaMode";
|
||||
|
||||
/** The Kana Mode (Kana Lock) key */
|
||||
static const String KANA_MODE = "KanaMode";
|
||||
|
||||
/**
|
||||
* The Kanji (Japanese name for ideographic characters of Chinese origin)
|
||||
* Mode key
|
||||
*/
|
||||
static const String KANJI_MODE = "KanjiMode";
|
||||
|
||||
/** The Katakana (Japanese Kana characters) key */
|
||||
static const String KATAKANA = "Katakana";
|
||||
|
||||
/** The Start Application One key */
|
||||
static const String LAUNCH_APPLICATION_1 = "LaunchApplication1";
|
||||
|
||||
/** The Start Application Two key */
|
||||
static const String LAUNCH_APPLICATION_2 = "LaunchApplication2";
|
||||
|
||||
/** The Start Mail key */
|
||||
static const String LAUNCH_MAIL = "LaunchMail";
|
||||
|
||||
/** The Left Arrow key */
|
||||
static const String LEFT = "Left";
|
||||
|
||||
/** The Menu key */
|
||||
static const String MENU = "Menu";
|
||||
|
||||
/**
|
||||
* The Meta key. Note: This key value shall be also used for the Apple
|
||||
* Command key
|
||||
*/
|
||||
static const String META = "Meta";
|
||||
|
||||
/** The Media Next Track key */
|
||||
static const String MEDIA_NEXT_TRACK = "MediaNextTrack";
|
||||
|
||||
/** The Media Play Pause key */
|
||||
static const String MEDIA_PAUSE_PLAY = "MediaPlayPause";
|
||||
|
||||
/** The Media Previous Track key */
|
||||
static const String MEDIA_PREVIOUS_TRACK = "MediaPreviousTrack";
|
||||
|
||||
/** The Media Stop key */
|
||||
static const String MEDIA_STOP = "MediaStop";
|
||||
|
||||
/** The Mode Change key */
|
||||
static const String MODE_CHANGE = "ModeChange";
|
||||
|
||||
/** The Next Candidate function key */
|
||||
static const String NEXT_CANDIDATE = "NextCandidate";
|
||||
|
||||
/** The Nonconvert (Don't Convert) key */
|
||||
static const String NON_CONVERT = "Nonconvert";
|
||||
|
||||
/** The Number Lock key */
|
||||
static const String NUM_LOCK = "NumLock";
|
||||
|
||||
/** The Page Down (Next) key */
|
||||
static const String PAGE_DOWN = "PageDown";
|
||||
|
||||
/** The Page Up key */
|
||||
static const String PAGE_UP = "PageUp";
|
||||
|
||||
/** The Paste key */
|
||||
static const String PASTE = "Paste";
|
||||
|
||||
/** The Pause key */
|
||||
static const String PAUSE = "Pause";
|
||||
|
||||
/** The Play key */
|
||||
static const String PLAY = "Play";
|
||||
|
||||
/**
|
||||
* The Power key. Note: Some devices may not expose this key to the
|
||||
* operating environment
|
||||
*/
|
||||
static const String POWER = "Power";
|
||||
|
||||
/** The Previous Candidate function key */
|
||||
static const String PREVIOUS_CANDIDATE = "PreviousCandidate";
|
||||
|
||||
/** The Print Screen (PrintScrn, SnapShot) key */
|
||||
static const String PRINT_SCREEN = "PrintScreen";
|
||||
|
||||
/** The Process key */
|
||||
static const String PROCESS = "Process";
|
||||
|
||||
/** The Props key */
|
||||
static const String PROPS = "Props";
|
||||
|
||||
/** The Right Arrow key */
|
||||
static const String RIGHT = "Right";
|
||||
|
||||
/** The Roman Characters function key */
|
||||
static const String ROMAN_CHARACTERS = "RomanCharacters";
|
||||
|
||||
/** The Scroll Lock key */
|
||||
static const String SCROLL = "Scroll";
|
||||
|
||||
/** The Select key */
|
||||
static const String SELECT = "Select";
|
||||
|
||||
/** The Select Media key */
|
||||
static const String SELECT_MEDIA = "SelectMedia";
|
||||
|
||||
/** The Separator key */
|
||||
static const String SEPARATOR = "Separator";
|
||||
|
||||
/** The Shift key */
|
||||
static const String SHIFT = "Shift";
|
||||
|
||||
/** The Soft1 key */
|
||||
static const String SOFT_1 = "Soft1";
|
||||
|
||||
/** The Soft2 key */
|
||||
static const String SOFT_2 = "Soft2";
|
||||
|
||||
/** The Soft3 key */
|
||||
static const String SOFT_3 = "Soft3";
|
||||
|
||||
/** The Soft4 key */
|
||||
static const String SOFT_4 = "Soft4";
|
||||
|
||||
/** The Stop key */
|
||||
static const String STOP = "Stop";
|
||||
|
||||
/** The Subtract key */
|
||||
static const String SUBTRACT = "Subtract";
|
||||
|
||||
/** The Symbol Lock key */
|
||||
static const String SYMBOL_LOCK = "SymbolLock";
|
||||
|
||||
/** The Up Arrow key */
|
||||
static const String UP = "Up";
|
||||
|
||||
/** The diagonal Up-Left Arrow key */
|
||||
static const String UP_LEFT = "UpLeft";
|
||||
|
||||
/** The diagonal Up-Right Arrow key */
|
||||
static const String UP_RIGHT = "UpRight";
|
||||
|
||||
/** The Undo key */
|
||||
static const String UNDO = "Undo";
|
||||
|
||||
/** The Volume Down key */
|
||||
static const String VOLUME_DOWN = "VolumeDown";
|
||||
|
||||
/** The Volume Mute key */
|
||||
static const String VOLUMN_MUTE = "VolumeMute";
|
||||
|
||||
/** The Volume Up key */
|
||||
static const String VOLUMN_UP = "VolumeUp";
|
||||
|
||||
/** The Windows Logo key */
|
||||
static const String WIN = "Win";
|
||||
|
||||
/** The Zoom key */
|
||||
static const String ZOOM = "Zoom";
|
||||
|
||||
/**
|
||||
* The Backspace (Back) key. Note: This key value shall be also used for the
|
||||
* key labeled 'delete' MacOS keyboards when not modified by the 'Fn' key
|
||||
*/
|
||||
static const String BACKSPACE = "Backspace";
|
||||
|
||||
/** The Horizontal Tabulation (Tab) key */
|
||||
static const String TAB = "Tab";
|
||||
|
||||
/** The Cancel key */
|
||||
static const String CANCEL = "Cancel";
|
||||
|
||||
/** The Escape (Esc) key */
|
||||
static const String ESC = "Esc";
|
||||
|
||||
/** The Space (Spacebar) key: */
|
||||
static const String SPACEBAR = "Spacebar";
|
||||
|
||||
/**
|
||||
* The Delete (Del) Key. Note: This key value shall be also used for the key
|
||||
* labeled 'delete' MacOS keyboards when modified by the 'Fn' key
|
||||
*/
|
||||
static const String DEL = "Del";
|
||||
|
||||
/** The Combining Grave Accent (Greek Varia, Dead Grave) key */
|
||||
static const String DEAD_GRAVE = "DeadGrave";
|
||||
|
||||
/**
|
||||
* The Combining Acute Accent (Stress Mark, Greek Oxia, Tonos, Dead Eacute)
|
||||
* key
|
||||
*/
|
||||
static const String DEAD_EACUTE = "DeadEacute";
|
||||
|
||||
/** The Combining Circumflex Accent (Hat, Dead Circumflex) key */
|
||||
static const String DEAD_CIRCUMFLEX = "DeadCircumflex";
|
||||
|
||||
/** The Combining Tilde (Dead Tilde) key */
|
||||
static const String DEAD_TILDE = "DeadTilde";
|
||||
|
||||
/** The Combining Macron (Long, Dead Macron) key */
|
||||
static const String DEAD_MACRON = "DeadMacron";
|
||||
|
||||
/** The Combining Breve (Short, Dead Breve) key */
|
||||
static const String DEAD_BREVE = "DeadBreve";
|
||||
|
||||
/** The Combining Dot Above (Derivative, Dead Above Dot) key */
|
||||
static const String DEAD_ABOVE_DOT = "DeadAboveDot";
|
||||
|
||||
/**
|
||||
* The Combining Diaeresis (Double Dot Abode, Umlaut, Greek Dialytika,
|
||||
* Double Derivative, Dead Diaeresis) key
|
||||
*/
|
||||
static const String DEAD_UMLAUT = "DeadUmlaut";
|
||||
|
||||
/** The Combining Ring Above (Dead Above Ring) key */
|
||||
static const String DEAD_ABOVE_RING = "DeadAboveRing";
|
||||
|
||||
/** The Combining Double Acute Accent (Dead Doubleacute) key */
|
||||
static const String DEAD_DOUBLEACUTE = "DeadDoubleacute";
|
||||
|
||||
/** The Combining Caron (Hacek, V Above, Dead Caron) key */
|
||||
static const String DEAD_CARON = "DeadCaron";
|
||||
|
||||
/** The Combining Cedilla (Dead Cedilla) key */
|
||||
static const String DEAD_CEDILLA = "DeadCedilla";
|
||||
|
||||
/** The Combining Ogonek (Nasal Hook, Dead Ogonek) key */
|
||||
static const String DEAD_OGONEK = "DeadOgonek";
|
||||
|
||||
/**
|
||||
* The Combining Greek Ypogegrammeni (Greek Non-Spacing Iota Below, Iota
|
||||
* Subscript, Dead Iota) key
|
||||
*/
|
||||
static const String DEAD_IOTA = "DeadIota";
|
||||
|
||||
/**
|
||||
* The Combining Katakana-Hiragana Voiced Sound Mark (Dead Voiced Sound) key
|
||||
*/
|
||||
static const String DEAD_VOICED_SOUND = "DeadVoicedSound";
|
||||
|
||||
/**
|
||||
* The Combining Katakana-Hiragana Semi-Voiced Sound Mark (Dead Semivoiced
|
||||
* Sound) key
|
||||
*/
|
||||
static const String DEC_SEMIVOICED_SOUND = "DeadSemivoicedSound";
|
||||
|
||||
/**
|
||||
* Key value used when an implementation is unable to identify another key
|
||||
* value, due to either hardware, platform, or software constraints
|
||||
*/
|
||||
static const String UNIDENTIFIED = "Unidentified";
|
||||
}
|
||||
@@ -1,394 +0,0 @@
|
||||
// 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 html;
|
||||
|
||||
/**
|
||||
* Internal class that does the actual calculations to determine keyCode and
|
||||
* charCode for keydown, keypress, and keyup events for all browsers.
|
||||
*/
|
||||
class _KeyboardEventHandler extends EventStreamProvider<KeyEvent> {
|
||||
// This code inspired by Closure's KeyHandling library.
|
||||
// https://github.com/google/closure-library/blob/master/closure/goog/events/keyhandler.js
|
||||
|
||||
/**
|
||||
* The set of keys that have been pressed down without seeing their
|
||||
* corresponding keyup event.
|
||||
*/
|
||||
final List<KeyEvent> _keyDownList = <KeyEvent>[];
|
||||
|
||||
/** The type of KeyEvent we are tracking (keyup, keydown, keypress). */
|
||||
final String _type;
|
||||
|
||||
/** The element we are watching for events to happen on. */
|
||||
final EventTarget? _target;
|
||||
|
||||
// The distance to shift from upper case alphabet Roman letters to lower case.
|
||||
static final int _ROMAN_ALPHABET_OFFSET = "a".codeUnits[0] - "A".codeUnits[0];
|
||||
|
||||
/** Custom Stream (Controller) to produce KeyEvents for the stream. */
|
||||
_CustomKeyEventStreamImpl _stream;
|
||||
|
||||
static const _EVENT_TYPE = 'KeyEvent';
|
||||
|
||||
/**
|
||||
* An enumeration of key identifiers currently part of the W3C draft for DOM3
|
||||
* and their mappings to keyCodes.
|
||||
* https://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/keyset.html#KeySet-Set
|
||||
*/
|
||||
static const Map<String, int> _keyIdentifier = const {
|
||||
'Up': KeyCode.UP,
|
||||
'Down': KeyCode.DOWN,
|
||||
'Left': KeyCode.LEFT,
|
||||
'Right': KeyCode.RIGHT,
|
||||
'Enter': KeyCode.ENTER,
|
||||
'F1': KeyCode.F1,
|
||||
'F2': KeyCode.F2,
|
||||
'F3': KeyCode.F3,
|
||||
'F4': KeyCode.F4,
|
||||
'F5': KeyCode.F5,
|
||||
'F6': KeyCode.F6,
|
||||
'F7': KeyCode.F7,
|
||||
'F8': KeyCode.F8,
|
||||
'F9': KeyCode.F9,
|
||||
'F10': KeyCode.F10,
|
||||
'F11': KeyCode.F11,
|
||||
'F12': KeyCode.F12,
|
||||
'U+007F': KeyCode.DELETE,
|
||||
'Home': KeyCode.HOME,
|
||||
'End': KeyCode.END,
|
||||
'PageUp': KeyCode.PAGE_UP,
|
||||
'PageDown': KeyCode.PAGE_DOWN,
|
||||
'Insert': KeyCode.INSERT
|
||||
};
|
||||
|
||||
/** Return a stream for KeyEvents for the specified target. */
|
||||
// Note: this actually functions like a factory constructor.
|
||||
CustomStream<KeyEvent> forTarget(EventTarget? e, {bool useCapture: false}) {
|
||||
var handler =
|
||||
new _KeyboardEventHandler.initializeAllEventListeners(_type, e);
|
||||
return handler._stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* General constructor, performs basic initialization for our improved
|
||||
* KeyboardEvent controller.
|
||||
*/
|
||||
_KeyboardEventHandler(this._type)
|
||||
: _stream = new _CustomKeyEventStreamImpl('event'),
|
||||
_target = null,
|
||||
super(_EVENT_TYPE);
|
||||
|
||||
/**
|
||||
* Hook up all event listeners under the covers so we can estimate keycodes
|
||||
* and charcodes when they are not provided.
|
||||
*/
|
||||
_KeyboardEventHandler.initializeAllEventListeners(this._type, this._target)
|
||||
: _stream = new _CustomKeyEventStreamImpl(_type),
|
||||
super(_EVENT_TYPE) {
|
||||
Element.keyDownEvent
|
||||
.forTarget(_target, useCapture: true)
|
||||
.listen(processKeyDown);
|
||||
Element.keyPressEvent
|
||||
.forTarget(_target, useCapture: true)
|
||||
.listen(processKeyPress);
|
||||
Element.keyUpEvent
|
||||
.forTarget(_target, useCapture: true)
|
||||
.listen(processKeyUp);
|
||||
}
|
||||
|
||||
/** Determine if caps lock is one of the currently depressed keys. */
|
||||
bool get _capsLockOn =>
|
||||
_keyDownList.any((var element) => element.keyCode == KeyCode.CAPS_LOCK);
|
||||
|
||||
/**
|
||||
* Given the previously recorded keydown key codes, see if we can determine
|
||||
* the keycode of this keypress [event]. (Generally browsers only provide
|
||||
* charCode information for keypress events, but with a little
|
||||
* reverse-engineering, we can also determine the keyCode.) Returns
|
||||
* KeyCode.UNKNOWN if the keycode could not be determined.
|
||||
*/
|
||||
int _determineKeyCodeForKeypress(KeyboardEvent event) {
|
||||
// Note: This function is a work in progress. We'll expand this function
|
||||
// once we get more information about other keyboards.
|
||||
for (var prevEvent in _keyDownList) {
|
||||
if (prevEvent._shadowCharCode == event.charCode) {
|
||||
return prevEvent.keyCode;
|
||||
}
|
||||
if ((event.shiftKey || _capsLockOn) &&
|
||||
event.charCode >= "A".codeUnits[0] &&
|
||||
event.charCode <= "Z".codeUnits[0] &&
|
||||
event.charCode + _ROMAN_ALPHABET_OFFSET ==
|
||||
prevEvent._shadowCharCode) {
|
||||
return prevEvent.keyCode;
|
||||
}
|
||||
}
|
||||
return KeyCode.UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the character code returned from a keyDown [event], try to ascertain
|
||||
* and return the corresponding charCode for the character that was pressed.
|
||||
* This information is not shown to the user, but used to help polyfill
|
||||
* keypress events.
|
||||
*/
|
||||
int _findCharCodeKeyDown(KeyboardEvent event) {
|
||||
if (event.location == 3) {
|
||||
// Numpad keys.
|
||||
switch (event.keyCode) {
|
||||
case KeyCode.NUM_ZERO:
|
||||
// Even though this function returns _charCodes_, for some cases the
|
||||
// KeyCode == the charCode we want, in which case we use the keycode
|
||||
// constant for readability.
|
||||
return KeyCode.ZERO;
|
||||
case KeyCode.NUM_ONE:
|
||||
return KeyCode.ONE;
|
||||
case KeyCode.NUM_TWO:
|
||||
return KeyCode.TWO;
|
||||
case KeyCode.NUM_THREE:
|
||||
return KeyCode.THREE;
|
||||
case KeyCode.NUM_FOUR:
|
||||
return KeyCode.FOUR;
|
||||
case KeyCode.NUM_FIVE:
|
||||
return KeyCode.FIVE;
|
||||
case KeyCode.NUM_SIX:
|
||||
return KeyCode.SIX;
|
||||
case KeyCode.NUM_SEVEN:
|
||||
return KeyCode.SEVEN;
|
||||
case KeyCode.NUM_EIGHT:
|
||||
return KeyCode.EIGHT;
|
||||
case KeyCode.NUM_NINE:
|
||||
return KeyCode.NINE;
|
||||
case KeyCode.NUM_MULTIPLY:
|
||||
return 42; // Char code for *
|
||||
case KeyCode.NUM_PLUS:
|
||||
return 43; // +
|
||||
case KeyCode.NUM_MINUS:
|
||||
return 45; // -
|
||||
case KeyCode.NUM_PERIOD:
|
||||
return 46; // .
|
||||
case KeyCode.NUM_DIVISION:
|
||||
return 47; // /
|
||||
}
|
||||
} else if (event.keyCode >= 65 && event.keyCode <= 90) {
|
||||
// Set the "char code" for key down as the lower case letter. Again, this
|
||||
// will not show up for the user, but will be helpful in estimating
|
||||
// keyCode locations and other information during the keyPress event.
|
||||
return event.keyCode + _ROMAN_ALPHABET_OFFSET;
|
||||
}
|
||||
switch (event.keyCode) {
|
||||
case KeyCode.SEMICOLON:
|
||||
return KeyCode.FF_SEMICOLON;
|
||||
case KeyCode.EQUALS:
|
||||
return KeyCode.FF_EQUALS;
|
||||
case KeyCode.COMMA:
|
||||
return 44; // Ascii value for ,
|
||||
case KeyCode.DASH:
|
||||
return 45; // -
|
||||
case KeyCode.PERIOD:
|
||||
return 46; // .
|
||||
case KeyCode.SLASH:
|
||||
return 47; // /
|
||||
case KeyCode.APOSTROPHE:
|
||||
return 96; // `
|
||||
case KeyCode.OPEN_SQUARE_BRACKET:
|
||||
return 91; // [
|
||||
case KeyCode.BACKSLASH:
|
||||
return 92; // \
|
||||
case KeyCode.CLOSE_SQUARE_BRACKET:
|
||||
return 93; // ]
|
||||
case KeyCode.SINGLE_QUOTE:
|
||||
return 39; // '
|
||||
}
|
||||
return event.keyCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the key fires a keypress event in the current browser.
|
||||
*/
|
||||
bool _firesKeyPressEvent(KeyEvent event) {
|
||||
if (!Device.isIE && !Device.isWebKit) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Device.userAgent.contains('Mac') && event.altKey) {
|
||||
return KeyCode.isCharacterKey(event.keyCode);
|
||||
}
|
||||
|
||||
// Alt but not AltGr which is represented as Alt+Ctrl.
|
||||
if (event.altKey && !event.ctrlKey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Saves Ctrl or Alt + key for IE and WebKit, which won't fire keypress.
|
||||
if (!event.shiftKey &&
|
||||
(_keyDownList.last.keyCode == KeyCode.CTRL ||
|
||||
_keyDownList.last.keyCode == KeyCode.ALT ||
|
||||
Device.userAgent.contains('Mac') &&
|
||||
_keyDownList.last.keyCode == KeyCode.META)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Some keys with Ctrl/Shift do not issue keypress in WebKit.
|
||||
if (Device.isWebKit &&
|
||||
event.ctrlKey &&
|
||||
event.shiftKey &&
|
||||
(event.keyCode == KeyCode.BACKSLASH ||
|
||||
event.keyCode == KeyCode.OPEN_SQUARE_BRACKET ||
|
||||
event.keyCode == KeyCode.CLOSE_SQUARE_BRACKET ||
|
||||
event.keyCode == KeyCode.TILDE ||
|
||||
event.keyCode == KeyCode.SEMICOLON ||
|
||||
event.keyCode == KeyCode.DASH ||
|
||||
event.keyCode == KeyCode.EQUALS ||
|
||||
event.keyCode == KeyCode.COMMA ||
|
||||
event.keyCode == KeyCode.PERIOD ||
|
||||
event.keyCode == KeyCode.SLASH ||
|
||||
event.keyCode == KeyCode.APOSTROPHE ||
|
||||
event.keyCode == KeyCode.SINGLE_QUOTE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (event.keyCode) {
|
||||
case KeyCode.ENTER:
|
||||
// IE9 does not fire keypress on ENTER.
|
||||
return !Device.isIE;
|
||||
case KeyCode.ESC:
|
||||
return !Device.isWebKit;
|
||||
}
|
||||
|
||||
return KeyCode.isCharacterKey(event.keyCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize the keycodes to the IE KeyCodes (this is what Chrome, IE, and
|
||||
* Opera all use).
|
||||
*/
|
||||
int _normalizeKeyCodes(KeyboardEvent event) {
|
||||
// Note: This may change once we get input about non-US keyboards.
|
||||
if (Device.isFirefox) {
|
||||
switch (event.keyCode) {
|
||||
case KeyCode.FF_EQUALS:
|
||||
return KeyCode.EQUALS;
|
||||
case KeyCode.FF_SEMICOLON:
|
||||
return KeyCode.SEMICOLON;
|
||||
case KeyCode.MAC_FF_META:
|
||||
return KeyCode.META;
|
||||
case KeyCode.WIN_KEY_FF_LINUX:
|
||||
return KeyCode.WIN_KEY;
|
||||
}
|
||||
}
|
||||
return event.keyCode;
|
||||
}
|
||||
|
||||
/** Handle keydown events. */
|
||||
void processKeyDown(KeyboardEvent e) {
|
||||
// Ctrl-Tab and Alt-Tab can cause the focus to be moved to another window
|
||||
// before we've caught a key-up event. If the last-key was one of these
|
||||
// we reset the state.
|
||||
if (_keyDownList.length > 0 &&
|
||||
(_keyDownList.last.keyCode == KeyCode.CTRL && !e.ctrlKey ||
|
||||
_keyDownList.last.keyCode == KeyCode.ALT && !e.altKey ||
|
||||
Device.userAgent.contains('Mac') &&
|
||||
_keyDownList.last.keyCode == KeyCode.META &&
|
||||
!e.metaKey)) {
|
||||
_keyDownList.clear();
|
||||
}
|
||||
|
||||
var event = new KeyEvent.wrap(e);
|
||||
event._shadowKeyCode = _normalizeKeyCodes(event);
|
||||
// Technically a "keydown" event doesn't have a charCode. This is
|
||||
// calculated nonetheless to provide us with more information in giving
|
||||
// as much information as possible on keypress about keycode and also
|
||||
// charCode.
|
||||
event._shadowCharCode = _findCharCodeKeyDown(event);
|
||||
if (_keyDownList.length > 0 &&
|
||||
event.keyCode != _keyDownList.last.keyCode &&
|
||||
!_firesKeyPressEvent(event)) {
|
||||
// Some browsers have quirks not firing keypress events where all other
|
||||
// browsers do. This makes them more consistent.
|
||||
processKeyPress(e);
|
||||
}
|
||||
_keyDownList.add(event);
|
||||
_stream.add(event);
|
||||
}
|
||||
|
||||
/** Handle keypress events. */
|
||||
void processKeyPress(KeyboardEvent event) {
|
||||
var e = new KeyEvent.wrap(event);
|
||||
// IE reports the character code in the keyCode field for keypress events.
|
||||
// There are two exceptions however, Enter and Escape.
|
||||
if (Device.isIE) {
|
||||
if (e.keyCode == KeyCode.ENTER || e.keyCode == KeyCode.ESC) {
|
||||
e._shadowCharCode = 0;
|
||||
} else {
|
||||
e._shadowCharCode = e.keyCode;
|
||||
}
|
||||
} else if (Device.isOpera) {
|
||||
// Opera reports the character code in the keyCode field.
|
||||
e._shadowCharCode = KeyCode.isCharacterKey(e.keyCode) ? e.keyCode : 0;
|
||||
}
|
||||
// Now we guesstimate about what the keycode is that was actually
|
||||
// pressed, given previous keydown information.
|
||||
e._shadowKeyCode = _determineKeyCodeForKeypress(e);
|
||||
|
||||
// Correct the key value for certain browser-specific quirks.
|
||||
if (e._shadowKeyIdentifier != null &&
|
||||
_keyIdentifier.containsKey(e._shadowKeyIdentifier)) {
|
||||
// This is needed for Safari Windows because it currently doesn't give a
|
||||
// keyCode/which for non printable keys.
|
||||
e._shadowKeyCode = _keyIdentifier[e._shadowKeyIdentifier]!;
|
||||
}
|
||||
e._shadowAltKey = _keyDownList.any((var element) => element.altKey);
|
||||
_stream.add(e);
|
||||
}
|
||||
|
||||
/** Handle keyup events. */
|
||||
void processKeyUp(KeyboardEvent event) {
|
||||
var e = new KeyEvent.wrap(event);
|
||||
KeyboardEvent? toRemove = null;
|
||||
for (var key in _keyDownList) {
|
||||
if (key.keyCode == e.keyCode) {
|
||||
toRemove = key;
|
||||
}
|
||||
}
|
||||
if (toRemove != null) {
|
||||
_keyDownList.removeWhere((element) => element == toRemove);
|
||||
} else if (_keyDownList.length > 0) {
|
||||
// This happens when we've reached some international keyboard case we
|
||||
// haven't accounted for or we haven't correctly eliminated all browser
|
||||
// inconsistencies. Filing bugs on when this is reached is welcome!
|
||||
_keyDownList.removeLast();
|
||||
}
|
||||
_stream.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Records KeyboardEvents that occur on a particular element, and provides a
|
||||
* stream of outgoing KeyEvents with cross-browser consistent keyCode and
|
||||
* charCode values despite the fact that a multitude of browsers that have
|
||||
* varying keyboard default behavior.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* KeyboardEventStream.onKeyDown(document.body).listen(
|
||||
* keydownHandlerTest);
|
||||
*
|
||||
* This class is very much a work in progress, and we'd love to get information
|
||||
* on how we can make this class work with as many international keyboards as
|
||||
* possible. Bugs welcome!
|
||||
*/
|
||||
class KeyboardEventStream {
|
||||
/** Named constructor to produce a stream for onKeyPress events. */
|
||||
static CustomStream<KeyEvent> onKeyPress(EventTarget target) =>
|
||||
new _KeyboardEventHandler('keypress').forTarget(target);
|
||||
|
||||
/** Named constructor to produce a stream for onKeyUp events. */
|
||||
static CustomStream<KeyEvent> onKeyUp(EventTarget target) =>
|
||||
new _KeyboardEventHandler('keyup').forTarget(target);
|
||||
|
||||
/** Named constructor to produce a stream for onKeyDown events. */
|
||||
static CustomStream<KeyEvent> onKeyDown(EventTarget target) =>
|
||||
new _KeyboardEventHandler('keydown').forTarget(target);
|
||||
}
|
||||
@@ -1,454 +0,0 @@
|
||||
// Copyright (c) 2013, 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 dart.dom.html;
|
||||
|
||||
/**
|
||||
* Class which helps construct standard node validation policies.
|
||||
*
|
||||
* By default this will not accept anything, but the 'allow*' functions can be
|
||||
* used to expand what types of elements or attributes are allowed.
|
||||
*
|
||||
* All allow functions are additive- elements will be accepted if they are
|
||||
* accepted by any specific rule.
|
||||
*
|
||||
* It is important to remember that sanitization is not just intended to prevent
|
||||
* cross-site scripting attacks, but also to prevent information from being
|
||||
* displayed in unexpected ways. For example something displaying basic
|
||||
* formatted text may not expect `<video>` tags to appear. In this case an
|
||||
* empty NodeValidatorBuilder with just [allowTextElements] might be
|
||||
* appropriate.
|
||||
*/
|
||||
class NodeValidatorBuilder implements NodeValidator {
|
||||
final List<NodeValidator> _validators = <NodeValidator>[];
|
||||
|
||||
NodeValidatorBuilder() {}
|
||||
|
||||
/**
|
||||
* Creates a new NodeValidatorBuilder which accepts common constructs.
|
||||
*
|
||||
* By default this will accept HTML5 elements and attributes with the default
|
||||
* [UriPolicy] and templating elements.
|
||||
*
|
||||
* Notable syntax which is filtered:
|
||||
*
|
||||
* * Only known-good HTML5 elements and attributes are allowed.
|
||||
* * All URLs must be same-origin, use [allowNavigation] and [allowImages] to
|
||||
* specify additional URI policies.
|
||||
* * Inline-styles are not allowed.
|
||||
* * Custom element tags are disallowed, use [allowCustomElement].
|
||||
* * Custom tags extensions are disallowed, use [allowTagExtension].
|
||||
* * SVG Elements are not allowed, use [allowSvg].
|
||||
*
|
||||
* For scenarios where the HTML should only contain formatted text
|
||||
* [allowTextElements] is more appropriate.
|
||||
*
|
||||
* Use [allowSvg] to allow SVG elements.
|
||||
*/
|
||||
NodeValidatorBuilder.common() {
|
||||
allowHtml5();
|
||||
allowTemplating();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows navigation elements- Form and Anchor tags, along with common
|
||||
* attributes.
|
||||
*
|
||||
* The UriPolicy can be used to restrict the locations the navigation elements
|
||||
* are allowed to direct to. By default this will use the default [UriPolicy].
|
||||
*/
|
||||
void allowNavigation([UriPolicy? uriPolicy]) {
|
||||
if (uriPolicy == null) {
|
||||
uriPolicy = new UriPolicy();
|
||||
}
|
||||
add(new _SimpleNodeValidator.allowNavigation(uriPolicy));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows image elements.
|
||||
*
|
||||
* The UriPolicy can be used to restrict the locations the images may be
|
||||
* loaded from. By default this will use the default [UriPolicy].
|
||||
*/
|
||||
void allowImages([UriPolicy? uriPolicy]) {
|
||||
if (uriPolicy == null) {
|
||||
uriPolicy = new UriPolicy();
|
||||
}
|
||||
add(new _SimpleNodeValidator.allowImages(uriPolicy));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow basic text elements.
|
||||
*
|
||||
* This allows a subset of HTML5 elements, specifically just these tags and
|
||||
* no attributes.
|
||||
*
|
||||
* * B
|
||||
* * BLOCKQUOTE
|
||||
* * BR
|
||||
* * EM
|
||||
* * H1
|
||||
* * H2
|
||||
* * H3
|
||||
* * H4
|
||||
* * H5
|
||||
* * H6
|
||||
* * HR
|
||||
* * I
|
||||
* * LI
|
||||
* * OL
|
||||
* * P
|
||||
* * SPAN
|
||||
* * UL
|
||||
*/
|
||||
void allowTextElements() {
|
||||
add(new _SimpleNodeValidator.allowTextElements());
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow inline styles on elements.
|
||||
*
|
||||
* If [tagName] is not specified then this allows inline styles on all
|
||||
* elements. Otherwise tagName limits the styles to the specified elements.
|
||||
*/
|
||||
void allowInlineStyles({String? tagName}) {
|
||||
if (tagName == null) {
|
||||
tagName = '*';
|
||||
} else {
|
||||
tagName = tagName.toUpperCase();
|
||||
}
|
||||
add(new _SimpleNodeValidator(null, allowedAttributes: ['$tagName::style']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow common safe HTML5 elements and attributes.
|
||||
*
|
||||
* This list is based off of the Caja whitelists at:
|
||||
* https://code.google.com/p/google-caja/wiki/CajaWhitelists.
|
||||
*
|
||||
* Common things which are not allowed are script elements, style attributes
|
||||
* and any script handlers.
|
||||
*/
|
||||
void allowHtml5({UriPolicy? uriPolicy}) {
|
||||
add(new _Html5NodeValidator(uriPolicy: uriPolicy));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow SVG elements and attributes except for known bad ones.
|
||||
*/
|
||||
void allowSvg() {
|
||||
add(new _SvgNodeValidator());
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow custom elements with the specified tag name and specified attributes.
|
||||
*
|
||||
* This will allow the elements as custom tags (such as <x-foo></x-foo>),
|
||||
* but will not allow tag extensions. Use [allowTagExtension] to allow
|
||||
* tag extensions.
|
||||
*/
|
||||
void allowCustomElement(String tagName,
|
||||
{UriPolicy? uriPolicy,
|
||||
Iterable<String>? attributes,
|
||||
Iterable<String>? uriAttributes}) {
|
||||
var tagNameUpper = tagName.toUpperCase();
|
||||
var attrs = attributes
|
||||
?.map<String>((name) => '$tagNameUpper::${name.toLowerCase()}');
|
||||
var uriAttrs = uriAttributes
|
||||
?.map<String>((name) => '$tagNameUpper::${name.toLowerCase()}');
|
||||
if (uriPolicy == null) {
|
||||
uriPolicy = new UriPolicy();
|
||||
}
|
||||
|
||||
add(new _CustomElementNodeValidator(
|
||||
uriPolicy, [tagNameUpper], attrs, uriAttrs, false, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow custom tag extensions with the specified type name and specified
|
||||
* attributes.
|
||||
*
|
||||
* This will allow tag extensions (such as <div is="x-foo"></div>),
|
||||
* but will not allow custom tags. Use [allowCustomElement] to allow
|
||||
* custom tags.
|
||||
*/
|
||||
void allowTagExtension(String tagName, String baseName,
|
||||
{UriPolicy? uriPolicy,
|
||||
Iterable<String>? attributes,
|
||||
Iterable<String>? uriAttributes}) {
|
||||
var baseNameUpper = baseName.toUpperCase();
|
||||
var tagNameUpper = tagName.toUpperCase();
|
||||
var attrs = attributes
|
||||
?.map<String>((name) => '$baseNameUpper::${name.toLowerCase()}');
|
||||
var uriAttrs = uriAttributes
|
||||
?.map<String>((name) => '$baseNameUpper::${name.toLowerCase()}');
|
||||
if (uriPolicy == null) {
|
||||
uriPolicy = new UriPolicy();
|
||||
}
|
||||
|
||||
add(new _CustomElementNodeValidator(uriPolicy,
|
||||
[tagNameUpper, baseNameUpper], attrs, uriAttrs, true, false));
|
||||
}
|
||||
|
||||
void allowElement(String tagName,
|
||||
{UriPolicy? uriPolicy,
|
||||
Iterable<String>? attributes,
|
||||
Iterable<String>? uriAttributes}) {
|
||||
allowCustomElement(tagName,
|
||||
uriPolicy: uriPolicy,
|
||||
attributes: attributes,
|
||||
uriAttributes: uriAttributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow templating elements (such as <template> and template-related
|
||||
* attributes.
|
||||
*
|
||||
* This still requires other validators to allow regular attributes to be
|
||||
* bound (such as [allowHtml5]).
|
||||
*/
|
||||
void allowTemplating() {
|
||||
add(new _TemplatingNodeValidator());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an additional validator to the current list of validators.
|
||||
*
|
||||
* Elements and attributes will be accepted if they are accepted by any
|
||||
* validators.
|
||||
*/
|
||||
void add(NodeValidator validator) {
|
||||
_validators.add(validator);
|
||||
}
|
||||
|
||||
bool allowsElement(Element element) {
|
||||
return _validators.any((v) => v.allowsElement(element));
|
||||
}
|
||||
|
||||
bool allowsAttribute(Element element, String attributeName, String value) {
|
||||
return _validators
|
||||
.any((v) => v.allowsAttribute(element, attributeName, value));
|
||||
}
|
||||
}
|
||||
|
||||
class _SimpleNodeValidator implements NodeValidator {
|
||||
final Set<String> allowedElements = new Set<String>();
|
||||
final Set<String> allowedAttributes = new Set<String>();
|
||||
final Set<String> allowedUriAttributes = new Set<String>();
|
||||
final UriPolicy? uriPolicy;
|
||||
|
||||
factory _SimpleNodeValidator.allowNavigation(UriPolicy uriPolicy) {
|
||||
return new _SimpleNodeValidator(uriPolicy, allowedElements: const [
|
||||
'A',
|
||||
'FORM'
|
||||
], allowedAttributes: const [
|
||||
'A::accesskey',
|
||||
'A::coords',
|
||||
'A::hreflang',
|
||||
'A::name',
|
||||
'A::shape',
|
||||
'A::tabindex',
|
||||
'A::target',
|
||||
'A::type',
|
||||
'FORM::accept',
|
||||
'FORM::autocomplete',
|
||||
'FORM::enctype',
|
||||
'FORM::method',
|
||||
'FORM::name',
|
||||
'FORM::novalidate',
|
||||
'FORM::target',
|
||||
], allowedUriAttributes: const [
|
||||
'A::href',
|
||||
'FORM::action',
|
||||
]);
|
||||
}
|
||||
|
||||
factory _SimpleNodeValidator.allowImages(UriPolicy uriPolicy) {
|
||||
return new _SimpleNodeValidator(uriPolicy, allowedElements: const [
|
||||
'IMG'
|
||||
], allowedAttributes: const [
|
||||
'IMG::align',
|
||||
'IMG::alt',
|
||||
'IMG::border',
|
||||
'IMG::height',
|
||||
'IMG::hspace',
|
||||
'IMG::ismap',
|
||||
'IMG::name',
|
||||
'IMG::usemap',
|
||||
'IMG::vspace',
|
||||
'IMG::width',
|
||||
], allowedUriAttributes: const [
|
||||
'IMG::src',
|
||||
]);
|
||||
}
|
||||
|
||||
factory _SimpleNodeValidator.allowTextElements() {
|
||||
return new _SimpleNodeValidator(null, allowedElements: const [
|
||||
'B',
|
||||
'BLOCKQUOTE',
|
||||
'BR',
|
||||
'EM',
|
||||
'H1',
|
||||
'H2',
|
||||
'H3',
|
||||
'H4',
|
||||
'H5',
|
||||
'H6',
|
||||
'HR',
|
||||
'I',
|
||||
'LI',
|
||||
'OL',
|
||||
'P',
|
||||
'SPAN',
|
||||
'UL',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Elements must be uppercased tag names. For example `'IMG'`.
|
||||
* Attributes must be uppercased tag name followed by :: followed by
|
||||
* lowercase attribute name. For example `'IMG:src'`.
|
||||
*/
|
||||
_SimpleNodeValidator(this.uriPolicy,
|
||||
{Iterable<String>? allowedElements,
|
||||
Iterable<String>? allowedAttributes,
|
||||
Iterable<String>? allowedUriAttributes}) {
|
||||
this.allowedElements.addAll(allowedElements ?? const []);
|
||||
allowedAttributes = allowedAttributes ?? const [];
|
||||
allowedUriAttributes = allowedUriAttributes ?? const [];
|
||||
var legalAttributes = allowedAttributes
|
||||
.where((x) => !_Html5NodeValidator._uriAttributes.contains(x));
|
||||
var extraUriAttributes = allowedAttributes
|
||||
.where((x) => _Html5NodeValidator._uriAttributes.contains(x));
|
||||
this.allowedAttributes.addAll(legalAttributes);
|
||||
this.allowedUriAttributes.addAll(allowedUriAttributes);
|
||||
this.allowedUriAttributes.addAll(extraUriAttributes);
|
||||
}
|
||||
|
||||
bool allowsElement(Element element) {
|
||||
return allowedElements.contains(Element._safeTagName(element));
|
||||
}
|
||||
|
||||
bool allowsAttribute(Element element, String attributeName, String value) {
|
||||
var tagName = Element._safeTagName(element);
|
||||
if (allowedUriAttributes.contains('$tagName::$attributeName')) {
|
||||
return uriPolicy!.allowsUri(value);
|
||||
} else if (allowedUriAttributes.contains('*::$attributeName')) {
|
||||
return uriPolicy!.allowsUri(value);
|
||||
} else if (allowedAttributes.contains('$tagName::$attributeName')) {
|
||||
return true;
|
||||
} else if (allowedAttributes.contains('*::$attributeName')) {
|
||||
return true;
|
||||
} else if (allowedAttributes.contains('$tagName::*')) {
|
||||
return true;
|
||||
} else if (allowedAttributes.contains('*::*')) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class _CustomElementNodeValidator extends _SimpleNodeValidator {
|
||||
final bool allowTypeExtension;
|
||||
final bool allowCustomTag;
|
||||
|
||||
_CustomElementNodeValidator(
|
||||
UriPolicy uriPolicy,
|
||||
Iterable<String> allowedElements,
|
||||
Iterable<String>? allowedAttributes,
|
||||
Iterable<String>? allowedUriAttributes,
|
||||
bool allowTypeExtension,
|
||||
bool allowCustomTag)
|
||||
: this.allowTypeExtension = allowTypeExtension == true,
|
||||
this.allowCustomTag = allowCustomTag == true,
|
||||
super(uriPolicy,
|
||||
allowedElements: allowedElements,
|
||||
allowedAttributes: allowedAttributes,
|
||||
allowedUriAttributes: allowedUriAttributes);
|
||||
|
||||
bool allowsElement(Element element) {
|
||||
if (allowTypeExtension) {
|
||||
var isAttr = element.attributes['is'];
|
||||
if (isAttr != null) {
|
||||
return allowedElements.contains(isAttr.toUpperCase()) &&
|
||||
allowedElements.contains(Element._safeTagName(element));
|
||||
}
|
||||
}
|
||||
return allowCustomTag &&
|
||||
allowedElements.contains(Element._safeTagName(element));
|
||||
}
|
||||
|
||||
bool allowsAttribute(Element element, String attributeName, String value) {
|
||||
if (allowsElement(element)) {
|
||||
if (allowTypeExtension &&
|
||||
attributeName == 'is' &&
|
||||
allowedElements.contains(value.toUpperCase())) {
|
||||
return true;
|
||||
}
|
||||
return super.allowsAttribute(element, attributeName, value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class _TemplatingNodeValidator extends _SimpleNodeValidator {
|
||||
static const _TEMPLATE_ATTRS = const <String>[
|
||||
'bind',
|
||||
'if',
|
||||
'ref',
|
||||
'repeat',
|
||||
'syntax'
|
||||
];
|
||||
|
||||
final Set<String> _templateAttrs;
|
||||
|
||||
_TemplatingNodeValidator()
|
||||
: _templateAttrs = new Set<String>.from(_TEMPLATE_ATTRS),
|
||||
super(null,
|
||||
allowedElements: ['TEMPLATE'],
|
||||
allowedAttributes:
|
||||
_TEMPLATE_ATTRS.map((attr) => 'TEMPLATE::$attr')) {}
|
||||
|
||||
bool allowsAttribute(Element element, String attributeName, String value) {
|
||||
if (super.allowsAttribute(element, attributeName, value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (attributeName == 'template' && value == "") {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (element.attributes['template'] == "") {
|
||||
return _templateAttrs.contains(attributeName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class _SvgNodeValidator implements NodeValidator {
|
||||
bool allowsElement(Element element) {
|
||||
if (element is svg.ScriptElement) {
|
||||
return false;
|
||||
}
|
||||
// Firefox 37 has issues with creating foreign elements inside a
|
||||
// foreignobject tag as SvgElement. We don't want foreignobject contents
|
||||
// anyway, so just remove the whole tree outright. And we can't rely
|
||||
// on IE recognizing the SvgForeignObject type, so go by tagName. Bug 23144
|
||||
if (element is svg.SvgElement &&
|
||||
Element._safeTagName(element) == 'foreignObject') {
|
||||
return false;
|
||||
}
|
||||
if (element is svg.SvgElement) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool allowsAttribute(Element element, String attributeName, String value) {
|
||||
if (attributeName == 'is' || attributeName.startsWith('on')) {
|
||||
return false;
|
||||
}
|
||||
return allowsElement(element);
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
// Copyright (c) 2011, 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 html;
|
||||
|
||||
/**
|
||||
* Contains the set of standard values returned by HTMLDocument.getReadyState.
|
||||
*/
|
||||
abstract class ReadyState {
|
||||
/**
|
||||
* Indicates the document is still loading and parsing.
|
||||
*/
|
||||
static const String LOADING = "loading";
|
||||
|
||||
/**
|
||||
* Indicates the document is finished parsing but is still loading
|
||||
* subresources.
|
||||
*/
|
||||
static const String INTERACTIVE = "interactive";
|
||||
|
||||
/**
|
||||
* Indicates the document and all subresources have been loaded.
|
||||
*/
|
||||
static const String COMPLETE = "complete";
|
||||
}
|
||||
@@ -1,321 +0,0 @@
|
||||
// Copyright (c) 2013, 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 dart.dom.html;
|
||||
|
||||
/**
|
||||
* Interface used to validate that only accepted elements and attributes are
|
||||
* allowed while parsing HTML strings into DOM nodes.
|
||||
*
|
||||
* In general, customization of validation behavior should be done via the
|
||||
* [NodeValidatorBuilder] class to mitigate the chances of incorrectly
|
||||
* implementing validation rules.
|
||||
*/
|
||||
abstract class NodeValidator {
|
||||
/**
|
||||
* Construct a default NodeValidator which only accepts whitelisted HTML5
|
||||
* elements and attributes.
|
||||
*
|
||||
* If a uriPolicy is not specified then the default uriPolicy will be used.
|
||||
*/
|
||||
factory NodeValidator({UriPolicy? uriPolicy}) =>
|
||||
new _Html5NodeValidator(uriPolicy: uriPolicy);
|
||||
|
||||
factory NodeValidator.throws(NodeValidator base) =>
|
||||
new _ThrowsNodeValidator(base);
|
||||
|
||||
/**
|
||||
* Returns true if the tagName is an accepted type.
|
||||
*/
|
||||
bool allowsElement(Element element);
|
||||
|
||||
/**
|
||||
* Returns true if the attribute is allowed.
|
||||
*
|
||||
* The attributeName parameter will always be in lowercase.
|
||||
*
|
||||
* See [allowsElement] for format of tagName.
|
||||
*/
|
||||
bool allowsAttribute(Element element, String attributeName, String value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs sanitization of a node tree after construction to ensure that it
|
||||
* does not contain any disallowed elements or attributes.
|
||||
*
|
||||
* In general custom implementations of this class should not be necessary and
|
||||
* all validation customization should be done in custom NodeValidators, but
|
||||
* custom implementations of this class can be created to perform more complex
|
||||
* tree sanitization.
|
||||
*/
|
||||
abstract class NodeTreeSanitizer {
|
||||
/**
|
||||
* Constructs a default tree sanitizer which will remove all elements and
|
||||
* attributes which are not allowed by the provided validator.
|
||||
*/
|
||||
factory NodeTreeSanitizer(NodeValidator validator) =>
|
||||
new _ValidatingTreeSanitizer(validator);
|
||||
|
||||
/**
|
||||
* Called with the root of the tree which is to be sanitized.
|
||||
*
|
||||
* This method needs to walk the entire tree and either remove elements and
|
||||
* attributes which are not recognized as safe or throw an exception which
|
||||
* will mark the entire tree as unsafe.
|
||||
*/
|
||||
void sanitizeTree(Node node);
|
||||
|
||||
/**
|
||||
* A sanitizer for trees that we trust. It does no validation and allows
|
||||
* any elements. It is also more efficient, since it can pass the text
|
||||
* directly through to the underlying APIs without creating a document
|
||||
* fragment to be sanitized.
|
||||
*/
|
||||
static const trusted = const _TrustedHtmlTreeSanitizer();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sanitizer for trees that we trust. It does no validation and allows
|
||||
* any elements.
|
||||
*/
|
||||
class _TrustedHtmlTreeSanitizer implements NodeTreeSanitizer {
|
||||
const _TrustedHtmlTreeSanitizer();
|
||||
|
||||
sanitizeTree(Node node) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the policy for what types of uris are allowed for particular
|
||||
* attribute values.
|
||||
*
|
||||
* This can be used to provide custom rules such as allowing all http:// URIs
|
||||
* for image attributes but only same-origin URIs for anchor tags.
|
||||
*/
|
||||
abstract class UriPolicy {
|
||||
/**
|
||||
* Constructs the default UriPolicy which is to only allow Uris to the same
|
||||
* origin as the application was launched from.
|
||||
*
|
||||
* This will block all ftp: mailto: URIs. It will also block accessing
|
||||
* https://example.com if the app is running from http://example.com.
|
||||
*/
|
||||
factory UriPolicy() => new _SameOriginUriPolicy();
|
||||
|
||||
/**
|
||||
* Checks if the uri is allowed on the specified attribute.
|
||||
*
|
||||
* The uri provided may or may not be a relative path.
|
||||
*/
|
||||
bool allowsUri(String uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows URIs to the same origin as the current application was loaded from
|
||||
* (such as https://example.com:80).
|
||||
*/
|
||||
class _SameOriginUriPolicy implements UriPolicy {
|
||||
final AnchorElement _hiddenAnchor = new AnchorElement();
|
||||
final Location _loc = window.location;
|
||||
|
||||
bool allowsUri(String uri) {
|
||||
_hiddenAnchor.href = uri;
|
||||
// IE leaves an empty hostname for same-origin URIs.
|
||||
return (_hiddenAnchor.hostname == _loc.hostname &&
|
||||
_hiddenAnchor.port == _loc.port &&
|
||||
_hiddenAnchor.protocol == _loc.protocol) ||
|
||||
(_hiddenAnchor.hostname == '' &&
|
||||
_hiddenAnchor.port == '' &&
|
||||
(_hiddenAnchor.protocol == ':' || _hiddenAnchor.protocol == ''));
|
||||
}
|
||||
}
|
||||
|
||||
class _ThrowsNodeValidator implements NodeValidator {
|
||||
final NodeValidator validator;
|
||||
|
||||
_ThrowsNodeValidator(this.validator) {}
|
||||
|
||||
bool allowsElement(Element element) {
|
||||
if (!validator.allowsElement(element)) {
|
||||
throw new ArgumentError(Element._safeTagName(element));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool allowsAttribute(Element element, String attributeName, String value) {
|
||||
if (!validator.allowsAttribute(element, attributeName, value)) {
|
||||
throw new ArgumentError(
|
||||
'${Element._safeTagName(element)}[$attributeName="$value"]');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard tree sanitizer which validates a node tree against the provided
|
||||
* validator and removes any nodes or attributes which are not allowed.
|
||||
*/
|
||||
class _ValidatingTreeSanitizer implements NodeTreeSanitizer {
|
||||
NodeValidator validator;
|
||||
|
||||
/// Did we modify the tree by removing anything.
|
||||
bool modifiedTree = false;
|
||||
_ValidatingTreeSanitizer(this.validator) {}
|
||||
|
||||
void sanitizeTree(Node node) {
|
||||
void walk(Node node, Node? parent) {
|
||||
sanitizeNode(node, parent);
|
||||
|
||||
var child = node.lastChild;
|
||||
while (null != child) {
|
||||
Node? nextChild;
|
||||
try {
|
||||
// Child may be removed during the walk, and we may not even be able
|
||||
// to get its previousNode. But it's also possible that previousNode
|
||||
// (i.e. previousSibling) is being spoofed, so double-check it.
|
||||
nextChild = child.previousNode;
|
||||
if (nextChild != null && nextChild.nextNode != child) {
|
||||
throw StateError("Corrupt HTML");
|
||||
}
|
||||
} catch (e) {
|
||||
// Child appears bad, remove it. We want to check the rest of the
|
||||
// children of node and, but we have no way of getting to the next
|
||||
// child, so start again from the last child.
|
||||
_removeNode(child, node);
|
||||
child = null;
|
||||
nextChild = node.lastChild;
|
||||
}
|
||||
if (child != null) walk(child, node);
|
||||
child = nextChild;
|
||||
}
|
||||
}
|
||||
|
||||
modifiedTree = false;
|
||||
walk(node, null);
|
||||
while (modifiedTree) {
|
||||
modifiedTree = false;
|
||||
walk(node, null);
|
||||
}
|
||||
}
|
||||
|
||||
/// Aggressively try to remove node.
|
||||
void _removeNode(Node node, Node? parent) {
|
||||
// If we have the parent, it's presumably already passed more sanitization
|
||||
// or is the fragment, so ask it to remove the child. And if that fails
|
||||
// try to set the outer html.
|
||||
modifiedTree = true;
|
||||
if (parent == null || parent != node.parentNode) {
|
||||
node.remove();
|
||||
} else {
|
||||
parent._removeChild(node);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sanitize the element, assuming we can't trust anything about it.
|
||||
void _sanitizeUntrustedElement(/* Element */ element, Node? parent) {
|
||||
// If the _hasCorruptedAttributes does not successfully return false,
|
||||
// then we consider it corrupted and remove.
|
||||
// TODO(alanknight): This is a workaround because on Firefox
|
||||
// embed/object
|
||||
// tags typeof is "function", not "object". We don't recognize them, and
|
||||
// can't call methods. This does mean that you can't explicitly allow an
|
||||
// embed tag. The only thing that will let it through is a null
|
||||
// sanitizer that doesn't traverse the tree at all. But sanitizing while
|
||||
// allowing embeds seems quite unlikely. This is also the reason that we
|
||||
// can't declare the type of element, as an embed won't pass any type
|
||||
// check in dart2js.
|
||||
var corrupted = true;
|
||||
var attrs;
|
||||
var isAttr;
|
||||
try {
|
||||
// If getting/indexing attributes throws, count that as corrupt.
|
||||
attrs = element.attributes;
|
||||
isAttr = attrs['is'];
|
||||
var corruptedTest1 = Element._hasCorruptedAttributes(element);
|
||||
|
||||
// On IE, erratically, the hasCorruptedAttributes test can return false,
|
||||
// even though it clearly is corrupted. A separate copy of the test
|
||||
// inlining just the basic check seems to help.
|
||||
corrupted = corruptedTest1
|
||||
? true
|
||||
: Element._hasCorruptedAttributesAdditionalCheck(element);
|
||||
} catch (e) {}
|
||||
var elementText = 'element unprintable';
|
||||
try {
|
||||
elementText = element.toString();
|
||||
} catch (e) {}
|
||||
try {
|
||||
var elementTagName = Element._safeTagName(element);
|
||||
_sanitizeElement(element, parent, corrupted, elementText, elementTagName,
|
||||
attrs, isAttr);
|
||||
} on ArgumentError {
|
||||
// Thrown by _ThrowsNodeValidator
|
||||
rethrow;
|
||||
} catch (e) {
|
||||
// Unexpected exception sanitizing -> remove
|
||||
_removeNode(element, parent);
|
||||
window.console.warn('Removing corrupted element $elementText');
|
||||
}
|
||||
}
|
||||
|
||||
/// Having done basic sanity checking on the element, and computed the
|
||||
/// important attributes we want to check, remove it if it's not valid
|
||||
/// or not allowed, either as a whole or particular attributes.
|
||||
void _sanitizeElement(Element element, Node? parent, bool corrupted,
|
||||
String text, String tag, Map attrs, String? isAttr) {
|
||||
if (false != corrupted) {
|
||||
_removeNode(element, parent);
|
||||
window.console
|
||||
.warn('Removing element due to corrupted attributes on <$text>');
|
||||
return;
|
||||
}
|
||||
if (!validator.allowsElement(element)) {
|
||||
_removeNode(element, parent);
|
||||
window.console.warn('Removing disallowed element <$tag> from $parent');
|
||||
return;
|
||||
}
|
||||
|
||||
if (isAttr != null) {
|
||||
if (!validator.allowsAttribute(element, 'is', isAttr)) {
|
||||
_removeNode(element, parent);
|
||||
window.console.warn('Removing disallowed type extension '
|
||||
'<$tag is="$isAttr">');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(blois): Need to be able to get all attributes, irrespective of
|
||||
// XMLNS.
|
||||
var keys = attrs.keys.toList();
|
||||
for (var i = attrs.length - 1; i >= 0; --i) {
|
||||
var name = keys[i];
|
||||
if (!validator.allowsAttribute(
|
||||
element, name.toLowerCase(), attrs[name])) {
|
||||
window.console.warn('Removing disallowed attribute '
|
||||
'<$tag $name="${attrs[name]}">');
|
||||
attrs.remove(name);
|
||||
}
|
||||
}
|
||||
|
||||
if (element is TemplateElement) {
|
||||
TemplateElement template = element;
|
||||
sanitizeTree(template.content);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sanitize the node and its children recursively.
|
||||
void sanitizeNode(Node node, Node? parent) {
|
||||
switch (node.nodeType) {
|
||||
case Node.ELEMENT_NODE:
|
||||
_sanitizeUntrustedElement(node, parent);
|
||||
break;
|
||||
case Node.COMMENT_NODE:
|
||||
case Node.DOCUMENT_FRAGMENT_NODE:
|
||||
case Node.TEXT_NODE:
|
||||
case Node.CDATA_SECTION_NODE:
|
||||
break;
|
||||
default:
|
||||
_removeNode(node, parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
// Copyright (c) 2013, 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 dart.dom.html;
|
||||
|
||||
/**
|
||||
* A list which just wraps another list, for either intercepting list calls or
|
||||
* retyping the list (for example, from List<A> to List<B> where B extends A).
|
||||
*/
|
||||
class _WrappedList<E extends Node> extends ListBase<E>
|
||||
implements NodeListWrapper {
|
||||
final List<Node> _list;
|
||||
|
||||
_WrappedList(this._list);
|
||||
|
||||
// Iterable APIs
|
||||
|
||||
Iterator<E> get iterator => new _WrappedIterator<E>(_list.iterator);
|
||||
|
||||
int get length => _list.length;
|
||||
|
||||
// Collection APIs
|
||||
|
||||
void add(E element) {
|
||||
_list.add(element);
|
||||
}
|
||||
|
||||
bool remove(Object? element) => _list.remove(element);
|
||||
|
||||
void clear() {
|
||||
_list.clear();
|
||||
}
|
||||
|
||||
// List APIs
|
||||
|
||||
E operator [](int index) => _list[index] as E;
|
||||
|
||||
void operator []=(int index, E value) {
|
||||
_list[index] = value;
|
||||
}
|
||||
|
||||
set length(int newLength) {
|
||||
_list.length = newLength;
|
||||
}
|
||||
|
||||
void sort([int compare(E a, E b)?]) {
|
||||
if (compare == null) {
|
||||
_list.sort();
|
||||
} else {
|
||||
_list.sort((Node a, Node b) => compare(a as E, b as E));
|
||||
}
|
||||
}
|
||||
|
||||
int indexOf(Object? element, [int start = 0]) =>
|
||||
_list.indexOf(element as Node, start);
|
||||
|
||||
int lastIndexOf(Object? element, [int? start]) =>
|
||||
_list.lastIndexOf(element as Node, start);
|
||||
|
||||
void insert(int index, E element) => _list.insert(index, element);
|
||||
|
||||
E removeAt(int index) => _list.removeAt(index) as E;
|
||||
|
||||
void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
|
||||
_list.setRange(start, end, iterable, skipCount);
|
||||
}
|
||||
|
||||
void removeRange(int start, int end) {
|
||||
_list.removeRange(start, end);
|
||||
}
|
||||
|
||||
void replaceRange(int start, int end, Iterable<E> iterable) {
|
||||
_list.replaceRange(start, end, iterable);
|
||||
}
|
||||
|
||||
void fillRange(int start, int end, [E? fillValue]) {
|
||||
_list.fillRange(start, end, fillValue);
|
||||
}
|
||||
|
||||
List<Node> get rawList => _list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterator wrapper for _WrappedList.
|
||||
*/
|
||||
class _WrappedIterator<E extends Node> implements Iterator<E> {
|
||||
Iterator<Node> _iterator;
|
||||
|
||||
_WrappedIterator(this._iterator);
|
||||
|
||||
bool moveNext() {
|
||||
return _iterator.moveNext();
|
||||
}
|
||||
|
||||
E get current => _iterator.current as E;
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
// 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 html;
|
||||
|
||||
class _HttpRequestUtils {
|
||||
// Helper for factory HttpRequest.get
|
||||
static HttpRequest get(
|
||||
String url, onComplete(HttpRequest request), bool withCredentials) {
|
||||
final request = new HttpRequest();
|
||||
request.open('GET', url, async: true);
|
||||
|
||||
request.withCredentials = withCredentials;
|
||||
|
||||
request.onReadyStateChange.listen((e) {
|
||||
if (request.readyState == HttpRequest.DONE) {
|
||||
onComplete(request);
|
||||
}
|
||||
});
|
||||
|
||||
request.send();
|
||||
|
||||
return request;
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
// Copyright (c) 2011, 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 html;
|
||||
|
||||
// Iterator for arrays with fixed size.
|
||||
class FixedSizeListIterator<T> implements Iterator<T> {
|
||||
final List<T> _array;
|
||||
final int _length; // Cache array length for faster access.
|
||||
int _position;
|
||||
T? _current;
|
||||
|
||||
FixedSizeListIterator(List<T> array)
|
||||
: _array = array,
|
||||
_position = -1,
|
||||
_length = array.length;
|
||||
|
||||
bool moveNext() {
|
||||
int nextPosition = _position + 1;
|
||||
if (nextPosition < _length) {
|
||||
_current = _array[nextPosition];
|
||||
_position = nextPosition;
|
||||
return true;
|
||||
}
|
||||
_current = null;
|
||||
_position = _length;
|
||||
return false;
|
||||
}
|
||||
|
||||
T get current => _current as T;
|
||||
}
|
||||
|
||||
// Iterator for arrays with variable size.
|
||||
class _VariableSizeListIterator<T> implements Iterator<T> {
|
||||
final List<T> _array;
|
||||
int _position;
|
||||
T? _current;
|
||||
|
||||
_VariableSizeListIterator(List<T> array)
|
||||
: _array = array,
|
||||
_position = -1;
|
||||
|
||||
bool moveNext() {
|
||||
int nextPosition = _position + 1;
|
||||
if (nextPosition < _array.length) {
|
||||
_current = _array[nextPosition];
|
||||
_position = nextPosition;
|
||||
return true;
|
||||
}
|
||||
_current = null;
|
||||
_position = _array.length;
|
||||
return false;
|
||||
}
|
||||
|
||||
T get current => _current as T;
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
// Copyright (c) 2017, 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 html;
|
||||
|
||||
class Console {
|
||||
const Console._safe();
|
||||
static const Console _safeConsole = const Console._safe();
|
||||
|
||||
bool get _isConsoleDefined => JS('bool', 'typeof console != "undefined"');
|
||||
|
||||
MemoryInfo? get memory =>
|
||||
_isConsoleDefined ? JS('MemoryInfo', 'window.console.memory') : null;
|
||||
|
||||
void assertCondition(bool condition, Object arg) => _isConsoleDefined
|
||||
? JS('void', 'window.console.assertCondition(#, #)', condition, arg)
|
||||
: null;
|
||||
|
||||
void clear(Object arg) =>
|
||||
_isConsoleDefined ? JS('void', 'window.console.clear(#)', arg) : null;
|
||||
|
||||
void count(Object arg) =>
|
||||
_isConsoleDefined ? JS('void', 'window.console.count(#)', arg) : null;
|
||||
|
||||
void debug(Object arg) =>
|
||||
_isConsoleDefined ? JS('void', 'window.console.debug(#)', arg) : null;
|
||||
|
||||
void dir(Object arg) =>
|
||||
_isConsoleDefined ? JS('void', 'window.console.dir(#)', arg) : null;
|
||||
|
||||
void dirxml(Object arg) =>
|
||||
_isConsoleDefined ? JS('void', 'window.console.dirxml(#)', arg) : null;
|
||||
|
||||
void error(Object arg) =>
|
||||
_isConsoleDefined ? JS('void', 'window.console.error(#)', arg) : null;
|
||||
|
||||
void group(Object arg) =>
|
||||
_isConsoleDefined ? JS('void', 'window.console.group(#)', arg) : null;
|
||||
|
||||
void groupCollapsed(Object arg) => _isConsoleDefined
|
||||
? JS('void', 'window.console.groupCollapsed(#)', arg)
|
||||
: null;
|
||||
|
||||
void groupEnd() =>
|
||||
_isConsoleDefined ? JS('void', 'window.console.groupEnd()') : null;
|
||||
|
||||
void info(Object arg) =>
|
||||
_isConsoleDefined ? JS('void', 'window.console.info(#)', arg) : null;
|
||||
|
||||
void log(Object arg) =>
|
||||
_isConsoleDefined ? JS('void', 'window.console.log(#)', arg) : null;
|
||||
|
||||
void markTimeline(Object arg) => _isConsoleDefined
|
||||
? JS('void', 'window.console.markTimeline(#)', arg)
|
||||
: null;
|
||||
|
||||
void profile(String title) =>
|
||||
_isConsoleDefined ? JS('void', 'window.console.profile(#)', title) : null;
|
||||
|
||||
void profileEnd(String title) => _isConsoleDefined
|
||||
? JS('void', 'window.console.profileEnd(#)', title)
|
||||
: null;
|
||||
|
||||
void table(Object arg) =>
|
||||
_isConsoleDefined ? JS('void', 'window.console.table(#)', arg) : null;
|
||||
|
||||
void time(String title) =>
|
||||
_isConsoleDefined ? JS('void', 'window.console.time(#)', title) : null;
|
||||
|
||||
void timeEnd(String title) =>
|
||||
_isConsoleDefined ? JS('void', 'window.console.timeEnd(#)', title) : null;
|
||||
|
||||
void timeStamp(Object arg) =>
|
||||
_isConsoleDefined ? JS('void', 'window.console.timeStamp(#)', arg) : null;
|
||||
|
||||
void trace(Object arg) =>
|
||||
_isConsoleDefined ? JS('void', 'window.console.trace(#)', arg) : null;
|
||||
|
||||
void warn(Object arg) =>
|
||||
_isConsoleDefined ? JS('void', 'window.console.warn(#)', arg) : null;
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
// 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.
|
||||
|
||||
// Conversions for Window. These check if the window is the local
|
||||
// window, and if it's not, wraps or unwraps it with a secure wrapper.
|
||||
// We need to test for EventTarget here as well as it's a base type.
|
||||
// We omit an unwrapper for Window as no methods take a non-local
|
||||
// window as a parameter.
|
||||
|
||||
part of html;
|
||||
|
||||
WindowBase? _convertNativeToDart_Window(win) {
|
||||
if (win == null) return null;
|
||||
return _DOMWindowCrossFrame._createSafe(win);
|
||||
}
|
||||
|
||||
EventTarget? _convertNativeToDart_EventTarget(e) {
|
||||
if (e == null) {
|
||||
return null;
|
||||
}
|
||||
// Assume it's a Window if it contains the postMessage property. It may be
|
||||
// from a different frame - without a patched prototype - so we cannot
|
||||
// rely on Dart type checking.
|
||||
if (JS('bool', r'"postMessage" in #', e)) {
|
||||
var window = _DOMWindowCrossFrame._createSafe(e);
|
||||
// If it's a native window.
|
||||
if (window is EventTarget) {
|
||||
return window;
|
||||
}
|
||||
return null;
|
||||
} else
|
||||
return e;
|
||||
}
|
||||
|
||||
EventTarget? _convertDartToNative_EventTarget(e) {
|
||||
if (e is _DOMWindowCrossFrame) {
|
||||
return e._window;
|
||||
} else {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
_convertNativeToDart_XHR_Response(o) {
|
||||
if (o is Document) {
|
||||
return o;
|
||||
}
|
||||
return convertNativeToDart_SerializedScriptValue(o);
|
||||
}
|
||||
@@ -1,260 +0,0 @@
|
||||
// Copyright (c) 2015, 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 html;
|
||||
|
||||
/**
|
||||
* A set (union) of the CSS classes that are present in a set of elements.
|
||||
* Implemented separately from _ElementCssClassSet for performance.
|
||||
*/
|
||||
class _MultiElementCssClassSet extends CssClassSetImpl {
|
||||
final Iterable<Element> _elementIterable;
|
||||
|
||||
// TODO(sra): Perhaps we should store the DomTokenList instead.
|
||||
final List<CssClassSetImpl> _sets;
|
||||
|
||||
factory _MultiElementCssClassSet(Iterable<Element> elements) {
|
||||
return new _MultiElementCssClassSet._(elements,
|
||||
new List<CssClassSetImpl>.from(elements.map((Element e) => e.classes)));
|
||||
}
|
||||
|
||||
_MultiElementCssClassSet._(this._elementIterable, this._sets);
|
||||
|
||||
Set<String> readClasses() {
|
||||
var s = new LinkedHashSet<String>();
|
||||
_sets.forEach((CssClassSetImpl e) => s.addAll(e.readClasses()));
|
||||
return s;
|
||||
}
|
||||
|
||||
void writeClasses(Set<String> s) {
|
||||
var classes = s.join(' ');
|
||||
for (Element e in _elementIterable) {
|
||||
e.className = classes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method used to modify the set of css classes on this element.
|
||||
*
|
||||
* f - callback with:
|
||||
* s - a Set of all the css class name currently on this element.
|
||||
*
|
||||
* After f returns, the modified set is written to the
|
||||
* className property of this element.
|
||||
*/
|
||||
modify(f(Set<String> s)) {
|
||||
_sets.forEach((CssClassSetImpl e) => e.modify(f));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the class [value] to the element if it is not on it, removes it if it
|
||||
* is.
|
||||
*
|
||||
* TODO(sra): It seems wrong to collect a 'changed' flag like this when the
|
||||
* underlying toggle returns an 'is set' flag.
|
||||
*/
|
||||
bool toggle(String value, [bool? shouldAdd]) => _sets.fold(
|
||||
false,
|
||||
(bool changed, CssClassSetImpl e) =>
|
||||
e.toggle(value, shouldAdd) || changed);
|
||||
|
||||
/**
|
||||
* Remove the class [value] from element, and return true on successful
|
||||
* removal.
|
||||
*
|
||||
* This is the Dart equivalent of jQuery's
|
||||
* [removeClass](http://api.jquery.com/removeClass/).
|
||||
*/
|
||||
bool remove(Object? value) => _sets.fold(
|
||||
false, (bool changed, CssClassSetImpl e) => e.remove(value) || changed);
|
||||
}
|
||||
|
||||
class _ElementCssClassSet extends CssClassSetImpl {
|
||||
final Element _element;
|
||||
|
||||
_ElementCssClassSet(this._element);
|
||||
|
||||
Set<String> readClasses() {
|
||||
var s = new LinkedHashSet<String>();
|
||||
var classname = _element.className;
|
||||
|
||||
for (String name in classname.split(' ')) {
|
||||
String trimmed = name.trim();
|
||||
if (!trimmed.isEmpty) {
|
||||
s.add(trimmed);
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void writeClasses(Set<String> s) {
|
||||
_element.className = s.join(' ');
|
||||
}
|
||||
|
||||
int get length => _classListLength(_classListOf(_element));
|
||||
bool get isEmpty => length == 0;
|
||||
bool get isNotEmpty => length != 0;
|
||||
|
||||
void clear() {
|
||||
_element.className = '';
|
||||
}
|
||||
|
||||
bool contains(Object? value) {
|
||||
return _contains(_element, value);
|
||||
}
|
||||
|
||||
bool add(String value) {
|
||||
return _add(_element, value);
|
||||
}
|
||||
|
||||
bool remove(Object? value) {
|
||||
return value is String && _remove(_element, value);
|
||||
}
|
||||
|
||||
bool toggle(String value, [bool? shouldAdd]) {
|
||||
return _toggle(_element, value, shouldAdd);
|
||||
}
|
||||
|
||||
void addAll(Iterable<String> iterable) {
|
||||
_addAll(_element, iterable);
|
||||
}
|
||||
|
||||
void removeAll(Iterable<Object?> iterable) {
|
||||
_removeAll(_element, iterable);
|
||||
}
|
||||
|
||||
void retainAll(Iterable<Object?> iterable) {
|
||||
_removeWhere(_element, iterable.toSet().contains, false);
|
||||
}
|
||||
|
||||
void removeWhere(bool test(String name)) {
|
||||
_removeWhere(_element, test, true);
|
||||
}
|
||||
|
||||
void retainWhere(bool test(String name)) {
|
||||
_removeWhere(_element, test, false);
|
||||
}
|
||||
|
||||
static bool _contains(Element _element, Object? value) {
|
||||
return value is String && _classListContains(_classListOf(_element), value);
|
||||
}
|
||||
|
||||
@pragma('dart2js:tryInline')
|
||||
static bool _add(Element _element, String value) {
|
||||
DomTokenList list = _classListOf(_element);
|
||||
// Compute returned result independently of action upon the set.
|
||||
bool added = !_classListContainsBeforeAddOrRemove(list, value);
|
||||
_classListAdd(list, value);
|
||||
return added;
|
||||
}
|
||||
|
||||
@pragma('dart2js:tryInline')
|
||||
static bool _remove(Element _element, String value) {
|
||||
DomTokenList list = _classListOf(_element);
|
||||
bool removed = _classListContainsBeforeAddOrRemove(list, value);
|
||||
_classListRemove(list, value);
|
||||
return removed;
|
||||
}
|
||||
|
||||
static bool _toggle(Element _element, String value, bool? shouldAdd) {
|
||||
// There is no value that can be passed as the second argument of
|
||||
// DomTokenList.toggle that behaves the same as passing one argument.
|
||||
// `null` is seen as false, meaning 'remove'.
|
||||
return shouldAdd == null
|
||||
? _toggleDefault(_element, value)
|
||||
: _toggleOnOff(_element, value, shouldAdd);
|
||||
}
|
||||
|
||||
static bool _toggleDefault(Element _element, String value) {
|
||||
DomTokenList list = _classListOf(_element);
|
||||
return _classListToggle1(list, value);
|
||||
}
|
||||
|
||||
static bool _toggleOnOff(Element _element, String value, bool? shouldAdd) {
|
||||
DomTokenList list = _classListOf(_element);
|
||||
// IE's toggle does not take a second parameter. We would prefer:
|
||||
//
|
||||
// return _classListToggle2(list, value, shouldAdd);
|
||||
//
|
||||
if (shouldAdd ?? false) {
|
||||
_classListAdd(list, value);
|
||||
return true;
|
||||
} else {
|
||||
_classListRemove(list, value);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void _addAll(Element _element, Iterable<String> iterable) {
|
||||
DomTokenList list = _classListOf(_element);
|
||||
for (String value in iterable) {
|
||||
_classListAdd(list, value);
|
||||
}
|
||||
}
|
||||
|
||||
static void _removeAll(Element _element, Iterable<Object?> iterable) {
|
||||
DomTokenList list = _classListOf(_element);
|
||||
for (Object? value in iterable) {
|
||||
_classListRemove(list, value as String);
|
||||
}
|
||||
}
|
||||
|
||||
static void _removeWhere(
|
||||
Element _element, bool test(String name), bool doRemove) {
|
||||
DomTokenList list = _classListOf(_element);
|
||||
int i = 0;
|
||||
while (i < _classListLength(list)) {
|
||||
String item = list.item(i)!;
|
||||
if (doRemove == test(item)) {
|
||||
_classListRemove(list, item);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A collection of static methods for DomTokenList. These methods are a
|
||||
// work-around for the lack of annotations to express the full behaviour of
|
||||
// the DomTokenList methods.
|
||||
|
||||
static DomTokenList _classListOf(Element e) => JS(
|
||||
'returns:DomTokenList;creates:DomTokenList;effects:none;depends:all;',
|
||||
'#.classList',
|
||||
e);
|
||||
|
||||
static int _classListLength(DomTokenList list) =>
|
||||
JS('returns:JSUInt31;effects:none;depends:all;', '#.length', list);
|
||||
|
||||
static bool _classListContains(DomTokenList list, String value) =>
|
||||
JS('returns:bool;effects:none;depends:all', '#.contains(#)', list, value);
|
||||
|
||||
static bool _classListContainsBeforeAddOrRemove(
|
||||
DomTokenList list, String value) =>
|
||||
// 'throws:never' is a lie, since 'contains' will throw on an illegal
|
||||
// token. However, we always call this function immediately prior to
|
||||
// add/remove/toggle with the same token. Often the result of 'contains'
|
||||
// is unused and the lie makes it possible for the 'contains' instruction
|
||||
// to be removed.
|
||||
JS('returns:bool;effects:none;depends:all;throws:null(1)',
|
||||
'#.contains(#)', list, value);
|
||||
|
||||
static void _classListAdd(DomTokenList list, String value) {
|
||||
// list.add(value);
|
||||
JS('', '#.add(#)', list, value);
|
||||
}
|
||||
|
||||
static void _classListRemove(DomTokenList list, String value) {
|
||||
// list.remove(value);
|
||||
JS('', '#.remove(#)', list, value);
|
||||
}
|
||||
|
||||
static bool _classListToggle1(DomTokenList list, String value) {
|
||||
return JS('bool', '#.toggle(#)', list, value);
|
||||
}
|
||||
|
||||
static bool _classListToggle2(
|
||||
DomTokenList list, String value, bool? shouldAdd) {
|
||||
return JS('bool', '#.toggle(#, #)', list, value, shouldAdd);
|
||||
}
|
||||
}
|
||||
@@ -1,214 +0,0 @@
|
||||
// Copyright (c) 2013, 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 dart.dom.html;
|
||||
|
||||
_callConstructor(constructor, interceptor) {
|
||||
return (receiver) {
|
||||
setNativeSubclassDispatchRecord(receiver, interceptor);
|
||||
|
||||
// Mirrors uses the constructor property to cache lookups, so we need it to
|
||||
// be set correctly, including on IE where it is not automatically picked
|
||||
// up from the __proto__.
|
||||
JS('', '#.constructor = #.__proto__.constructor', receiver, receiver);
|
||||
return JS('', '#(#)', constructor, receiver);
|
||||
};
|
||||
}
|
||||
|
||||
_callAttached(receiver) {
|
||||
return receiver.attached();
|
||||
}
|
||||
|
||||
_callDetached(receiver) {
|
||||
return receiver.detached();
|
||||
}
|
||||
|
||||
_callAttributeChanged(receiver, name, oldValue, newValue) {
|
||||
return receiver.attributeChanged(name, oldValue, newValue);
|
||||
}
|
||||
|
||||
_makeCallbackMethod(callback) {
|
||||
return JS(
|
||||
'',
|
||||
'''((function(invokeCallback) {
|
||||
return function() {
|
||||
return invokeCallback(this);
|
||||
};
|
||||
})(#))''',
|
||||
convertDartClosureToJS(callback, 1));
|
||||
}
|
||||
|
||||
_makeCallbackMethod3(callback) {
|
||||
return JS(
|
||||
'',
|
||||
'''((function(invokeCallback) {
|
||||
return function(arg1, arg2, arg3) {
|
||||
return invokeCallback(this, arg1, arg2, arg3);
|
||||
};
|
||||
})(#))''',
|
||||
convertDartClosureToJS(callback, 4));
|
||||
}
|
||||
|
||||
/// Checks whether the given [element] correctly extends from the native class
|
||||
/// with the given [baseClassName]. This method will throw if the base class
|
||||
/// doesn't match, except when the element extends from `template` and it's base
|
||||
/// class is `HTMLUnknownElement`. This exclusion is needed to support extension
|
||||
/// of template elements (used heavily in Polymer 1.0) on IE11 when using the
|
||||
/// webcomponents-lite.js polyfill.
|
||||
void _checkExtendsNativeClassOrTemplate(
|
||||
Element element, String extendsTag, String baseClassName) {
|
||||
if (!JS('bool', '(# instanceof window[#])', element, baseClassName) &&
|
||||
!((extendsTag == 'template' &&
|
||||
JS('bool', '(# instanceof window["HTMLUnknownElement"])',
|
||||
element)))) {
|
||||
throw new UnsupportedError('extendsTag does not match base native class');
|
||||
}
|
||||
}
|
||||
|
||||
Function _registerCustomElement(context, document, String tag, [Map? options]) {
|
||||
// Function follows the same pattern as the following JavaScript code for
|
||||
// registering a custom element.
|
||||
//
|
||||
// var proto = Object.create(HTMLElement.prototype, {
|
||||
// createdCallback: {
|
||||
// value: function() {
|
||||
// window.console.log('here');
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// document.registerElement('x-foo', { prototype: proto });
|
||||
// ...
|
||||
// var e = document.createElement('x-foo');
|
||||
|
||||
var extendsTagName = '';
|
||||
Type? type;
|
||||
if (options != null) {
|
||||
extendsTagName = options['extends'];
|
||||
type = options['prototype'];
|
||||
}
|
||||
|
||||
var interceptorClass = findInterceptorConstructorForType(type);
|
||||
if (interceptorClass == null) {
|
||||
throw new ArgumentError(type);
|
||||
}
|
||||
|
||||
var interceptor = JS('=Object', '#.prototype', interceptorClass);
|
||||
|
||||
var constructor = findConstructorForNativeSubclassType(type, 'created');
|
||||
if (constructor == null) {
|
||||
throw new ArgumentError("$type has no constructor called 'created'");
|
||||
}
|
||||
|
||||
// Workaround for 13190- use an article element to ensure that HTMLElement's
|
||||
// interceptor is resolved correctly.
|
||||
getNativeInterceptor(new Element.tag('article'));
|
||||
|
||||
String baseClassName = findDispatchTagForInterceptorClass(interceptorClass);
|
||||
if (baseClassName == null) {
|
||||
throw new ArgumentError(type);
|
||||
}
|
||||
|
||||
if (extendsTagName == null) {
|
||||
if (baseClassName != 'HTMLElement') {
|
||||
throw new UnsupportedError('Class must provide extendsTag if base '
|
||||
'native class is not HtmlElement');
|
||||
}
|
||||
} else {
|
||||
var element = document.createElement(extendsTagName);
|
||||
_checkExtendsNativeClassOrTemplate(element, extendsTagName, baseClassName);
|
||||
}
|
||||
|
||||
var baseConstructor = JS('=Object', '#[#]', context, baseClassName);
|
||||
|
||||
var properties = JS('=Object', '{}');
|
||||
|
||||
JS(
|
||||
'void',
|
||||
'#.createdCallback = #',
|
||||
properties,
|
||||
JS('=Object', '{value: #}',
|
||||
_makeCallbackMethod(_callConstructor(constructor, interceptor))));
|
||||
JS('void', '#.attachedCallback = #', properties,
|
||||
JS('=Object', '{value: #}', _makeCallbackMethod(_callAttached)));
|
||||
JS('void', '#.detachedCallback = #', properties,
|
||||
JS('=Object', '{value: #}', _makeCallbackMethod(_callDetached)));
|
||||
JS('void', '#.attributeChangedCallback = #', properties,
|
||||
JS('=Object', '{value: #}', _makeCallbackMethod3(_callAttributeChanged)));
|
||||
|
||||
var baseProto = JS('=Object', '#.prototype', baseConstructor);
|
||||
var proto = JS('=Object', 'Object.create(#, #)', baseProto, properties);
|
||||
|
||||
setNativeSubclassDispatchRecord(proto, interceptor);
|
||||
|
||||
var opts = JS('=Object', '{prototype: #}', proto);
|
||||
|
||||
if (extendsTagName != null) {
|
||||
JS('=Object', '#.extends = #', opts, extendsTagName);
|
||||
}
|
||||
|
||||
return JS(
|
||||
'JavaScriptFunction', '#.registerElement(#, #)', document, tag, opts);
|
||||
}
|
||||
|
||||
//// Called by Element.created to do validation & initialization.
|
||||
void _initializeCustomElement(Element e) {
|
||||
// TODO(blois): Add validation that this is only in response to an upgrade.
|
||||
}
|
||||
|
||||
/// Dart2JS implementation of ElementUpgrader
|
||||
class _JSElementUpgrader implements ElementUpgrader {
|
||||
var _interceptor;
|
||||
var _constructor;
|
||||
var _nativeType;
|
||||
|
||||
_JSElementUpgrader(Document document, Type type, String? extendsTag) {
|
||||
var interceptorClass = findInterceptorConstructorForType(type);
|
||||
if (interceptorClass == null) {
|
||||
throw new ArgumentError(type);
|
||||
}
|
||||
|
||||
_constructor = findConstructorForNativeSubclassType(type, 'created');
|
||||
if (_constructor == null) {
|
||||
throw new ArgumentError("$type has no constructor called 'created'");
|
||||
}
|
||||
|
||||
// Workaround for 13190- use an article element to ensure that HTMLElement's
|
||||
// interceptor is resolved correctly.
|
||||
getNativeInterceptor(new Element.tag('article'));
|
||||
|
||||
var baseClassName = findDispatchTagForInterceptorClass(interceptorClass);
|
||||
if (baseClassName == null) {
|
||||
throw new ArgumentError(type);
|
||||
}
|
||||
|
||||
if (extendsTag == null) {
|
||||
if (baseClassName != 'HTMLElement') {
|
||||
throw new UnsupportedError('Class must provide extendsTag if base '
|
||||
'native class is not HtmlElement');
|
||||
}
|
||||
_nativeType = HtmlElement;
|
||||
} else {
|
||||
var element = document.createElement(extendsTag);
|
||||
_checkExtendsNativeClassOrTemplate(element, extendsTag, baseClassName);
|
||||
_nativeType = element.runtimeType;
|
||||
}
|
||||
|
||||
_interceptor = JS('=Object', '#.prototype', interceptorClass);
|
||||
}
|
||||
|
||||
Element upgrade(Element element) {
|
||||
// Only exact type matches are supported- cannot be a subclass.
|
||||
if (element.runtimeType != _nativeType) {
|
||||
// Some browsers may represent non-upgraded elements <x-foo> as
|
||||
// UnknownElement and not a plain HtmlElement.
|
||||
if (_nativeType != HtmlElement || element.runtimeType != UnknownElement) {
|
||||
throw new ArgumentError('element is not subclass of $_nativeType');
|
||||
}
|
||||
}
|
||||
|
||||
setNativeSubclassDispatchRecord(element, _interceptor);
|
||||
JS('', '#(#)', _constructor, element);
|
||||
return element;
|
||||
}
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
// 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 html;
|
||||
|
||||
// TODO(vsm): Unify with Dartium version.
|
||||
class _DOMWindowCrossFrame implements WindowBase {
|
||||
// Private window. Note, this is a window in another frame, so it
|
||||
// cannot be typed as "Window" as its prototype is not patched
|
||||
// properly. Its fields and methods can only be accessed via JavaScript.
|
||||
final _window;
|
||||
|
||||
// Fields.
|
||||
HistoryBase get history =>
|
||||
_HistoryCrossFrame._createSafe(JS('HistoryBase', '#.history', _window));
|
||||
LocationBase get location => _LocationCrossFrame._createSafe(
|
||||
JS('LocationBase', '#.location', _window));
|
||||
|
||||
// TODO(vsm): Add frames to navigate subframes. See 2312.
|
||||
|
||||
bool get closed => JS('bool', '#.closed', _window);
|
||||
|
||||
WindowBase get opener => _createSafe(JS('WindowBase', '#.opener', _window));
|
||||
|
||||
WindowBase get parent => _createSafe(JS('WindowBase', '#.parent', _window));
|
||||
|
||||
WindowBase get top => _createSafe(JS('WindowBase', '#.top', _window));
|
||||
|
||||
// Methods.
|
||||
void close() => JS('void', '#.close()', _window);
|
||||
|
||||
void postMessage(var message, String targetOrigin, [List? messagePorts]) {
|
||||
if (messagePorts == null) {
|
||||
JS('void', '#.postMessage(#,#)', _window,
|
||||
convertDartToNative_SerializedScriptValue(message), targetOrigin);
|
||||
} else {
|
||||
JS(
|
||||
'void',
|
||||
'#.postMessage(#,#,#)',
|
||||
_window,
|
||||
convertDartToNative_SerializedScriptValue(message),
|
||||
targetOrigin,
|
||||
messagePorts);
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation support.
|
||||
_DOMWindowCrossFrame(this._window);
|
||||
|
||||
static WindowBase _createSafe(w) {
|
||||
if (identical(w, window)) {
|
||||
return w;
|
||||
} else {
|
||||
// TODO(vsm): Cache or implement equality.
|
||||
registerGlobalObject(w);
|
||||
return new _DOMWindowCrossFrame(w);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(efortuna): Remove this method. dartbug.com/16814
|
||||
Events get on => throw new UnsupportedError(
|
||||
'You can only attach EventListeners to your own window.');
|
||||
// TODO(efortuna): Remove this method. dartbug.com/16814
|
||||
void _addEventListener(String? type, EventListener? listener,
|
||||
[bool? useCapture]) =>
|
||||
throw new UnsupportedError(
|
||||
'You can only attach EventListeners to your own window.');
|
||||
// TODO(efortuna): Remove this method. dartbug.com/16814
|
||||
void addEventListener(String type, EventListener? listener,
|
||||
[bool? useCapture]) =>
|
||||
throw new UnsupportedError(
|
||||
'You can only attach EventListeners to your own window.');
|
||||
// TODO(efortuna): Remove this method. dartbug.com/16814
|
||||
bool dispatchEvent(Event event) => throw new UnsupportedError(
|
||||
'You can only attach EventListeners to your own window.');
|
||||
// TODO(efortuna): Remove this method. dartbug.com/16814
|
||||
void _removeEventListener(String? type, EventListener? listener,
|
||||
[bool? useCapture]) =>
|
||||
throw new UnsupportedError(
|
||||
'You can only attach EventListeners to your own window.');
|
||||
// TODO(efortuna): Remove this method. dartbug.com/16814
|
||||
void removeEventListener(String type, EventListener? listener,
|
||||
[bool? useCapture]) =>
|
||||
throw new UnsupportedError(
|
||||
'You can only attach EventListeners to your own window.');
|
||||
}
|
||||
|
||||
class _LocationCrossFrame implements LocationBase {
|
||||
// Private location. Note, this is a location object in another frame, so it
|
||||
// cannot be typed as "Location" as its prototype is not patched
|
||||
// properly. Its fields and methods can only be accessed via JavaScript.
|
||||
var _location;
|
||||
|
||||
set href(String val) => _setHref(_location, val);
|
||||
static void _setHref(location, val) {
|
||||
JS('void', '#.href = #', location, val);
|
||||
}
|
||||
|
||||
// Implementation support.
|
||||
_LocationCrossFrame(this._location);
|
||||
|
||||
static LocationBase _createSafe(location) {
|
||||
if (identical(location, window.location)) {
|
||||
return location;
|
||||
} else {
|
||||
// TODO(vsm): Cache or implement equality.
|
||||
return new _LocationCrossFrame(location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _HistoryCrossFrame implements HistoryBase {
|
||||
// Private history. Note, this is a history object in another frame, so it
|
||||
// cannot be typed as "History" as its prototype is not patched
|
||||
// properly. Its fields and methods can only be accessed via JavaScript.
|
||||
var _history;
|
||||
|
||||
void back() => JS('void', '#.back()', _history);
|
||||
|
||||
void forward() => JS('void', '#.forward()', _history);
|
||||
|
||||
void go(int distance) => JS('void', '#.go(#)', _history, distance);
|
||||
|
||||
// Implementation support.
|
||||
_HistoryCrossFrame(this._history);
|
||||
|
||||
static HistoryBase _createSafe(h) {
|
||||
if (identical(h, window.history)) {
|
||||
return h;
|
||||
} else {
|
||||
// TODO(vsm): Cache or implement equality.
|
||||
return new _HistoryCrossFrame(h);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,243 +0,0 @@
|
||||
/**
|
||||
* A custom KeyboardEvent that attempts to eliminate cross-browser
|
||||
* inconsistencies, and also provide both keyCode and charCode information
|
||||
* for all key events (when such information can be determined).
|
||||
*
|
||||
* KeyEvent tries to provide a higher level, more polished keyboard event
|
||||
* information on top of the "raw" [KeyboardEvent].
|
||||
*
|
||||
* The mechanics of using KeyEvents is a little different from the underlying
|
||||
* [KeyboardEvent]. To use KeyEvents, you need to create a stream and then add
|
||||
* KeyEvents to the stream, rather than using the [EventTarget.dispatchEvent].
|
||||
* Here's an example usage:
|
||||
*
|
||||
* // Initialize a stream for the KeyEvents:
|
||||
* var stream = KeyEvent.keyPressEvent.forTarget(document.body);
|
||||
* // Start listening to the stream of KeyEvents.
|
||||
* stream.listen((keyEvent) =>
|
||||
* window.console.log('KeyPress event detected ${keyEvent.charCode}'));
|
||||
* ...
|
||||
* // Add a new KeyEvent of someone pressing the 'A' key to the stream so
|
||||
* // listeners can know a KeyEvent happened.
|
||||
* stream.add(new KeyEvent('keypress', keyCode: 65, charCode: 97));
|
||||
*
|
||||
* This class is very much a work in progress, and we'd love to get information
|
||||
* on how we can make this class work with as many international keyboards as
|
||||
* possible. Bugs welcome!
|
||||
*/
|
||||
class KeyEvent extends _WrappedEvent implements KeyboardEvent {
|
||||
/** The parent KeyboardEvent that this KeyEvent is wrapping and "fixing". */
|
||||
KeyboardEvent _parent;
|
||||
|
||||
/** The "fixed" value of whether the alt key is being pressed. */
|
||||
bool _shadowAltKey;
|
||||
|
||||
/** Calculated value of what the estimated charCode is for this event. */
|
||||
int _shadowCharCode;
|
||||
|
||||
/** Calculated value of what the estimated keyCode is for this event. */
|
||||
int _shadowKeyCode;
|
||||
|
||||
/** Calculated value of what the estimated keyCode is for this event. */
|
||||
int get keyCode => _shadowKeyCode;
|
||||
|
||||
/** Calculated value of what the estimated charCode is for this event. */
|
||||
int get charCode => this.type == 'keypress' ? _shadowCharCode : 0;
|
||||
|
||||
/** Calculated value of whether the alt key is pressed is for this event. */
|
||||
bool get altKey => _shadowAltKey;
|
||||
|
||||
/** Calculated value of what the estimated keyCode is for this event. */
|
||||
int get which => keyCode;
|
||||
|
||||
/** Accessor to the underlying keyCode value is the parent event. */
|
||||
int get _realKeyCode => JS('int', '#.keyCode', _parent);
|
||||
|
||||
/** Accessor to the underlying charCode value is the parent event. */
|
||||
int get _realCharCode => JS('int', '#.charCode', _parent);
|
||||
|
||||
/** Accessor to the underlying altKey value is the parent event. */
|
||||
bool get _realAltKey => JS('bool', '#.altKey', _parent);
|
||||
|
||||
/** Shadows on top of the parent's currentTarget. */
|
||||
EventTarget? _currentTarget;
|
||||
|
||||
InputDeviceCapabilities? get sourceCapabilities =>
|
||||
JS('InputDeviceCapabilities', '#.sourceCapabilities', this);
|
||||
|
||||
/**
|
||||
* The value we want to use for this object's dispatch. Created here so it is
|
||||
* only invoked once.
|
||||
*/
|
||||
static final _keyboardEventDispatchRecord = _makeRecord();
|
||||
|
||||
/** Helper to statically create the dispatch record. */
|
||||
static _makeRecord() {
|
||||
var interceptor = JS_INTERCEPTOR_CONSTANT(KeyboardEvent);
|
||||
return makeLeafDispatchRecord(interceptor);
|
||||
}
|
||||
|
||||
/** Construct a KeyEvent with [parent] as the event we're emulating. */
|
||||
KeyEvent.wrap(KeyboardEvent parent)
|
||||
: _parent = parent,
|
||||
_shadowAltKey = false,
|
||||
_shadowCharCode = 0,
|
||||
_shadowKeyCode = 0,
|
||||
super(parent) {
|
||||
_parent = parent;
|
||||
_shadowAltKey = _realAltKey;
|
||||
_shadowCharCode = _realCharCode;
|
||||
_shadowKeyCode = _realKeyCode;
|
||||
_currentTarget = _parent.currentTarget;
|
||||
}
|
||||
|
||||
/** Programmatically create a new KeyEvent (and KeyboardEvent). */
|
||||
factory KeyEvent(String type,
|
||||
{Window? view,
|
||||
bool canBubble: true,
|
||||
bool cancelable: true,
|
||||
int keyCode: 0,
|
||||
int charCode: 0,
|
||||
int location: 1,
|
||||
bool ctrlKey: false,
|
||||
bool altKey: false,
|
||||
bool shiftKey: false,
|
||||
bool metaKey: false,
|
||||
EventTarget? currentTarget}) {
|
||||
if (view == null) {
|
||||
view = window;
|
||||
}
|
||||
|
||||
dynamic eventObj;
|
||||
|
||||
// Currently this works on everything but Safari. Safari throws an
|
||||
// "Attempting to change access mechanism for an unconfigurable property"
|
||||
// TypeError when trying to do the Object.defineProperty hack, so we avoid
|
||||
// this branch if possible.
|
||||
// Also, if we want this branch to work in FF, we also need to modify
|
||||
// _initKeyboardEvent to also take charCode and keyCode values to
|
||||
// initialize initKeyEvent.
|
||||
|
||||
eventObj = new Event.eventType('KeyboardEvent', type,
|
||||
canBubble: canBubble, cancelable: cancelable);
|
||||
|
||||
// Chromium Hack
|
||||
JS(
|
||||
'void',
|
||||
"Object.defineProperty(#, 'keyCode', {"
|
||||
" get : function() { return this.keyCodeVal; } })",
|
||||
eventObj);
|
||||
JS(
|
||||
'void',
|
||||
"Object.defineProperty(#, 'which', {"
|
||||
" get : function() { return this.keyCodeVal; } })",
|
||||
eventObj);
|
||||
JS(
|
||||
'void',
|
||||
"Object.defineProperty(#, 'charCode', {"
|
||||
" get : function() { return this.charCodeVal; } })",
|
||||
eventObj);
|
||||
|
||||
var keyIdentifier = _convertToHexString(charCode, keyCode);
|
||||
eventObj._initKeyboardEvent(type, canBubble, cancelable, view,
|
||||
keyIdentifier, location, ctrlKey, altKey, shiftKey, metaKey);
|
||||
JS('void', '#.keyCodeVal = #', eventObj, keyCode);
|
||||
JS('void', '#.charCodeVal = #', eventObj, charCode);
|
||||
|
||||
// Tell dart2js that it smells like a KeyboardEvent!
|
||||
setDispatchProperty(eventObj, _keyboardEventDispatchRecord);
|
||||
|
||||
var keyEvent = new KeyEvent.wrap(eventObj);
|
||||
if (keyEvent._currentTarget == null) {
|
||||
keyEvent._currentTarget = currentTarget == null ? window : currentTarget;
|
||||
}
|
||||
return keyEvent;
|
||||
}
|
||||
|
||||
// Currently known to work on all browsers but IE.
|
||||
static bool get canUseDispatchEvent => JS(
|
||||
'bool',
|
||||
'(typeof document.body.dispatchEvent == "function")'
|
||||
'&& document.body.dispatchEvent.length > 0');
|
||||
|
||||
/** The currently registered target for this event. */
|
||||
EventTarget? get currentTarget => _currentTarget;
|
||||
|
||||
// This is an experimental method to be sure.
|
||||
static String _convertToHexString(int charCode, int keyCode) {
|
||||
if (charCode != -1) {
|
||||
var hex = charCode.toRadixString(16); // Convert to hexadecimal.
|
||||
StringBuffer sb = new StringBuffer('U+');
|
||||
for (int i = 0; i < 4 - hex.length; i++) sb.write('0');
|
||||
sb.write(hex);
|
||||
return sb.toString();
|
||||
} else {
|
||||
return KeyCode._convertKeyCodeToKeyName(keyCode);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(efortuna): If KeyEvent is sufficiently successful that we want to make
|
||||
// it the default keyboard event handling, move these methods over to Element.
|
||||
/** Accessor to provide a stream of KeyEvents on the desired target. */
|
||||
static EventStreamProvider<KeyEvent> keyDownEvent =
|
||||
new _KeyboardEventHandler('keydown');
|
||||
/** Accessor to provide a stream of KeyEvents on the desired target. */
|
||||
static EventStreamProvider<KeyEvent> keyUpEvent =
|
||||
new _KeyboardEventHandler('keyup');
|
||||
/** Accessor to provide a stream of KeyEvents on the desired target. */
|
||||
static EventStreamProvider<KeyEvent> keyPressEvent =
|
||||
new _KeyboardEventHandler('keypress');
|
||||
|
||||
String get code => _parent.code;
|
||||
/** True if the ctrl key is pressed during this event. */
|
||||
bool get ctrlKey => _parent.ctrlKey;
|
||||
int get detail => _parent.detail;
|
||||
bool get isComposing => _parent.isComposing;
|
||||
String get key => _parent.key;
|
||||
/**
|
||||
* Accessor to the part of the keyboard that the key was pressed from (one of
|
||||
* KeyLocation.STANDARD, KeyLocation.RIGHT, KeyLocation.LEFT,
|
||||
* KeyLocation.NUMPAD, KeyLocation.MOBILE, KeyLocation.JOYSTICK).
|
||||
*/
|
||||
int get location => _parent.location;
|
||||
/** True if the Meta (or Mac command) key is pressed during this event. */
|
||||
bool get metaKey => _parent.metaKey;
|
||||
/** True if the shift key was pressed during this event. */
|
||||
bool get shiftKey => _parent.shiftKey;
|
||||
WindowBase? get view => _parent.view;
|
||||
void _initUIEvent(
|
||||
String type, bool canBubble, bool cancelable, Window? view, int detail) {
|
||||
throw new UnsupportedError("Cannot initialize a UI Event from a KeyEvent.");
|
||||
}
|
||||
|
||||
String get _shadowKeyIdentifier => JS('String', '#.keyIdentifier', _parent);
|
||||
|
||||
int get _charCode => charCode;
|
||||
int get _keyCode => keyCode;
|
||||
int get _which => which;
|
||||
|
||||
String get _keyIdentifier {
|
||||
throw new UnsupportedError("keyIdentifier is unsupported.");
|
||||
}
|
||||
|
||||
void _initKeyboardEvent(
|
||||
String type,
|
||||
bool canBubble,
|
||||
bool cancelable,
|
||||
Window? view,
|
||||
String keyIdentifier,
|
||||
int? location,
|
||||
bool ctrlKey,
|
||||
bool altKey,
|
||||
bool shiftKey,
|
||||
bool metaKey) {
|
||||
throw new UnsupportedError(
|
||||
"Cannot initialize a KeyboardEvent from a KeyEvent.");
|
||||
}
|
||||
|
||||
bool getModifierState(String keyArgument) => throw new UnimplementedError();
|
||||
|
||||
bool get repeat => throw new UnimplementedError();
|
||||
bool get isComposed => throw new UnimplementedError();
|
||||
dynamic get _get_view => throw new UnimplementedError();
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// Copyright (c) 2013, 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 html;
|
||||
|
||||
class Platform {
|
||||
/**
|
||||
* Returns true if dart:typed_data types are supported on this
|
||||
* browser. If false, using these types will generate a runtime
|
||||
* error.
|
||||
*/
|
||||
static final bool supportsTypedData = JS('bool', '!!(window.ArrayBuffer)');
|
||||
|
||||
/**
|
||||
* Returns true if SIMD types in dart:typed_data types are supported
|
||||
* on this browser. If false, using these types will generate a runtime
|
||||
* error.
|
||||
*/
|
||||
static final supportsSimd = false;
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
// 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 html;
|
||||
|
||||
class _TypedArrayFactoryProvider {
|
||||
static ByteData createByteData(int length) => _B8(length);
|
||||
static ByteData createByteData_fromBuffer(ByteBuffer buffer,
|
||||
[int byteOffset = 0, int length]) {
|
||||
if (length == null) return _B8_2(buffer, byteOffset);
|
||||
return _B8_3(buffer, byteOffset, length);
|
||||
}
|
||||
|
||||
static Float32List createFloat32List(int length) => _F32(length);
|
||||
static Float32List createFloat32List_fromList(List<num> list) =>
|
||||
_F32(ensureNative(list));
|
||||
static Float32List createFloat32List_fromBuffer(ByteBuffer buffer,
|
||||
[int byteOffset = 0, int length]) {
|
||||
if (length == null) return _F32_2(buffer, byteOffset);
|
||||
return _F32_3(buffer, byteOffset, length);
|
||||
}
|
||||
|
||||
static Float64List createFloat64List(int length) => _F64(length);
|
||||
static Float64List createFloat64List_fromList(List<num> list) =>
|
||||
_F64(ensureNative(list));
|
||||
static Float64List createFloat64List_fromBuffer(ByteBuffer buffer,
|
||||
[int byteOffset = 0, int length]) {
|
||||
if (length == null) return _F64_2(buffer, byteOffset);
|
||||
return _F64_3(buffer, byteOffset, length);
|
||||
}
|
||||
|
||||
static Int8List createInt8List(int length) => _I8(length);
|
||||
static Int8List createInt8List_fromList(List<num> list) =>
|
||||
_I8(ensureNative(list));
|
||||
static Int8List createInt8List_fromBuffer(ByteBuffer buffer,
|
||||
[int byteOffset = 0, int length]) {
|
||||
if (length == null) return _I8_2(buffer, byteOffset);
|
||||
return _I8_3(buffer, byteOffset, length);
|
||||
}
|
||||
|
||||
static Int16List createInt16List(int length) => _I16(length);
|
||||
static Int16List createInt16List_fromList(List<num> list) =>
|
||||
_I16(ensureNative(list));
|
||||
static Int16List createInt16List_fromBuffer(ByteBuffer buffer,
|
||||
[int byteOffset = 0, int length]) {
|
||||
if (length == null) return _I16_2(buffer, byteOffset);
|
||||
return _I16_3(buffer, byteOffset, length);
|
||||
}
|
||||
|
||||
static Int32List createInt32List(int length) => _I32(length);
|
||||
static Int32List createInt32List_fromList(List<num> list) =>
|
||||
_I32(ensureNative(list));
|
||||
static Int32List createInt32List_fromBuffer(ByteBuffer buffer,
|
||||
[int byteOffset = 0, int length]) {
|
||||
if (length == null) return _I32_2(buffer, byteOffset);
|
||||
return _I32_3(buffer, byteOffset, length);
|
||||
}
|
||||
|
||||
static Uint8List createUint8List(int length) => _U8(length);
|
||||
static Uint8List createUint8List_fromList(List<num> list) =>
|
||||
_U8(ensureNative(list));
|
||||
static Uint8List createUint8List_fromBuffer(ByteBuffer buffer,
|
||||
[int byteOffset = 0, int length]) {
|
||||
if (length == null) return _U8_2(buffer, byteOffset);
|
||||
return _U8_3(buffer, byteOffset, length);
|
||||
}
|
||||
|
||||
static Uint16List createUint16List(int length) => _U16(length);
|
||||
static Uint16List createUint16List_fromList(List<num> list) =>
|
||||
_U16(ensureNative(list));
|
||||
static Uint16List createUint16List_fromBuffer(ByteBuffer buffer,
|
||||
[int byteOffset = 0, int length]) {
|
||||
if (length == null) return _U16_2(buffer, byteOffset);
|
||||
return _U16_3(buffer, byteOffset, length);
|
||||
}
|
||||
|
||||
static Uint32List createUint32List(int length) => _U32(length);
|
||||
static Uint32List createUint32List_fromList(List<num> list) =>
|
||||
_U32(ensureNative(list));
|
||||
static Uint32List createUint32List_fromBuffer(ByteBuffer buffer,
|
||||
[int byteOffset = 0, int length]) {
|
||||
if (length == null) return _U32_2(buffer, byteOffset);
|
||||
return _U32_3(buffer, byteOffset, length);
|
||||
}
|
||||
|
||||
static Uint8ClampedList createUint8ClampedList(int length) => _U8C(length);
|
||||
static Uint8ClampedList createUint8ClampedList_fromList(List<num> list) =>
|
||||
_U8C(ensureNative(list));
|
||||
static Uint8ClampedList createUint8ClampedList_fromBuffer(ByteBuffer buffer,
|
||||
[int byteOffset = 0, int length]) {
|
||||
if (length == null) return _U8C_2(buffer, byteOffset);
|
||||
return _U8C_3(buffer, byteOffset, length);
|
||||
}
|
||||
|
||||
static ByteData _B8(arg) =>
|
||||
JS('ByteData', 'new DataView(new ArrayBuffer(#))', arg);
|
||||
static Float32List _F32(arg) => JS('Float32List', 'new Float32Array(#)', arg);
|
||||
static Float64List _F64(arg) => JS('Float64List', 'new Float64Array(#)', arg);
|
||||
static Int8List _I8(arg) => JS('Int8List', 'new Int8Array(#)', arg);
|
||||
static Int16List _I16(arg) => JS('Int16List', 'new Int16Array(#)', arg);
|
||||
static Int32List _I32(arg) => JS('Int32List', 'new Int32Array(#)', arg);
|
||||
static Uint8List _U8(arg) => JS('Uint8List', 'new Uint8Array(#)', arg);
|
||||
static Uint16List _U16(arg) => JS('Uint16List', 'new Uint16Array(#)', arg);
|
||||
static Uint32List _U32(arg) => JS('Uint32List', 'new Uint32Array(#)', arg);
|
||||
static Uint8ClampedList _U8C(arg) =>
|
||||
JS('Uint8ClampedList', 'new Uint8ClampedArray(#)', arg);
|
||||
|
||||
static ByteData _B8_2(arg1, arg2) =>
|
||||
JS('ByteData', 'new DataView(#, #)', arg1, arg2);
|
||||
static Float32List _F32_2(arg1, arg2) =>
|
||||
JS('Float32List', 'new Float32Array(#, #)', arg1, arg2);
|
||||
static Float64List _F64_2(arg1, arg2) =>
|
||||
JS('Float64List', 'new Float64Array(#, #)', arg1, arg2);
|
||||
static Int8List _I8_2(arg1, arg2) =>
|
||||
JS('Int8List', 'new Int8Array(#, #)', arg1, arg2);
|
||||
static Int16List _I16_2(arg1, arg2) =>
|
||||
JS('Int16List', 'new Int16Array(#, #)', arg1, arg2);
|
||||
static Int32List _I32_2(arg1, arg2) =>
|
||||
JS('Int32List', 'new Int32Array(#, #)', arg1, arg2);
|
||||
static Uint8List _U8_2(arg1, arg2) =>
|
||||
JS('Uint8List', 'new Uint8Array(#, #)', arg1, arg2);
|
||||
static Uint16List _U16_2(arg1, arg2) =>
|
||||
JS('Uint16List', 'new Uint16Array(#, #)', arg1, arg2);
|
||||
static Uint32List _U32_2(arg1, arg2) =>
|
||||
JS('Uint32List', 'new Uint32Array(#, #)', arg1, arg2);
|
||||
static Uint8ClampedList _U8C_2(arg1, arg2) =>
|
||||
JS('Uint8ClampedList', 'new Uint8ClampedArray(#, #)', arg1, arg2);
|
||||
|
||||
static ByteData _B8_3(arg1, arg2, arg3) =>
|
||||
JS('ByteData', 'new DataView(#, #, #)', arg1, arg2, arg3);
|
||||
static Float32List _F32_3(arg1, arg2, arg3) =>
|
||||
JS('Float32List', 'new Float32Array(#, #, #)', arg1, arg2, arg3);
|
||||
static Float64List _F64_3(arg1, arg2, arg3) =>
|
||||
JS('Float64List', 'new Float64Array(#, #, #)', arg1, arg2, arg3);
|
||||
static Int8List _I8_3(arg1, arg2, arg3) =>
|
||||
JS('Int8List', 'new Int8Array(#, #, #)', arg1, arg2, arg3);
|
||||
static Int16List _I16_3(arg1, arg2, arg3) =>
|
||||
JS('Int16List', 'new Int16Array(#, #, #)', arg1, arg2, arg3);
|
||||
static Int32List _I32_3(arg1, arg2, arg3) =>
|
||||
JS('Int32List', 'new Int32Array(#, #, #)', arg1, arg2, arg3);
|
||||
static Uint8List _U8_3(arg1, arg2, arg3) =>
|
||||
JS('Uint8List', 'new Uint8Array(#, #, #)', arg1, arg2, arg3);
|
||||
static Uint16List _U16_3(arg1, arg2, arg3) =>
|
||||
JS('Uint16List', 'new Uint16Array(#, #, #)', arg1, arg2, arg3);
|
||||
static Uint32List _U32_3(arg1, arg2, arg3) =>
|
||||
JS('Uint32List', 'new Uint32Array(#, #, #)', arg1, arg2, arg3);
|
||||
static Uint8ClampedList _U8C_3(arg1, arg2, arg3) => JS(
|
||||
'Uint8ClampedList', 'new Uint8ClampedArray(#, #, #)', arg1, arg2, arg3);
|
||||
|
||||
// Ensures that [list] is a JavaScript Array or a typed array. If necessary,
|
||||
// copies the list.
|
||||
static ensureNative(List list) => list; // TODO: make sure.
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
// Copyright (c) 2013, 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 dart.html;
|
||||
|
||||
/**
|
||||
* Helper class to implement custom events which wrap DOM events.
|
||||
*/
|
||||
class _WrappedEvent implements Event {
|
||||
final Event wrapped;
|
||||
|
||||
/** The CSS selector involved with event delegation. */
|
||||
String? _selector;
|
||||
|
||||
_WrappedEvent(this.wrapped);
|
||||
|
||||
bool get bubbles => wrapped.bubbles;
|
||||
|
||||
bool get cancelable => wrapped.cancelable;
|
||||
|
||||
bool get composed => wrapped.composed;
|
||||
|
||||
EventTarget? get currentTarget => wrapped.currentTarget;
|
||||
|
||||
bool get defaultPrevented => wrapped.defaultPrevented;
|
||||
|
||||
int get eventPhase => wrapped.eventPhase;
|
||||
|
||||
bool get isTrusted => wrapped.isTrusted;
|
||||
|
||||
EventTarget? get target => wrapped.target;
|
||||
|
||||
double get timeStamp => wrapped.timeStamp as double;
|
||||
|
||||
String get type => wrapped.type;
|
||||
|
||||
void _initEvent(String type, [bool? bubbles, bool? cancelable]) {
|
||||
throw new UnsupportedError('Cannot initialize this Event.');
|
||||
}
|
||||
|
||||
void preventDefault() {
|
||||
wrapped.preventDefault();
|
||||
}
|
||||
|
||||
void stopImmediatePropagation() {
|
||||
wrapped.stopImmediatePropagation();
|
||||
}
|
||||
|
||||
void stopPropagation() {
|
||||
wrapped.stopPropagation();
|
||||
}
|
||||
|
||||
List<EventTarget> composedPath() => wrapped.composedPath();
|
||||
|
||||
/**
|
||||
* A pointer to the element whose CSS selector matched within which an event
|
||||
* was fired. If this Event was not associated with any Event delegation,
|
||||
* accessing this value will throw an [UnsupportedError].
|
||||
*/
|
||||
Element get matchingTarget {
|
||||
if (_selector == null) {
|
||||
throw new UnsupportedError('Cannot call matchingTarget if this Event did'
|
||||
' not arise as a result of event delegation.');
|
||||
}
|
||||
Element? currentTarget = this.currentTarget as Element?;
|
||||
Element? target = this.target as Element?;
|
||||
do {
|
||||
if (target!.matches(_selector!)) return target;
|
||||
target = target.parent;
|
||||
} while (target != null && target != currentTarget!.parent);
|
||||
throw new StateError('No selector matched for populating matchedTarget.');
|
||||
}
|
||||
|
||||
/**
|
||||
* This event's path, taking into account shadow DOM.
|
||||
*
|
||||
* ## Other resources
|
||||
*
|
||||
* * [Shadow DOM extensions to
|
||||
* Event](http://w3c.github.io/webcomponents/spec/shadow/#extensions-to-event)
|
||||
* from W3C.
|
||||
*/
|
||||
// https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#extensions-to-event
|
||||
List<Node> get path => wrapped.path as List<Node>;
|
||||
|
||||
dynamic get _get_currentTarget => wrapped._get_currentTarget;
|
||||
|
||||
dynamic get _get_target => wrapped._get_target;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +0,0 @@
|
||||
// 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 dart.dom.svg;
|
||||
|
||||
class _SvgElementFactoryProvider {
|
||||
static SvgElement createSvgElement_tag(String tag) {
|
||||
final Element temp =
|
||||
document.createElementNS("http://www.w3.org/2000/svg", tag);
|
||||
return temp as SvgElement;
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
// Copyright (c) 2013, 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 dart.dom.html;
|
||||
|
||||
void Function(T)? _wrapZone<T>(void Function(T)? callback) {
|
||||
// For performance reasons avoid wrapping if we are in the root zone.
|
||||
if (Zone.current == Zone.root) return callback;
|
||||
if (callback == null) return null;
|
||||
return Zone.current.bindUnaryCallbackGuarded(callback);
|
||||
}
|
||||
|
||||
void Function(T1, T2)? _wrapBinaryZone<T1, T2>(
|
||||
void Function(T1, T2)? callback) {
|
||||
// For performance reasons avoid wrapping if we are in the root zone.
|
||||
if (Zone.current == Zone.root) return callback;
|
||||
if (callback == null) return null;
|
||||
return Zone.current.bindBinaryCallbackGuarded(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the first descendant element of this document that matches the
|
||||
* specified group of selectors.
|
||||
*
|
||||
* Unless your webpage contains multiple documents, the top-level
|
||||
* [querySelector]
|
||||
* method behaves the same as this method, so you should use it instead to
|
||||
* save typing a few characters.
|
||||
*
|
||||
* [selectors] should be a string using CSS selector syntax.
|
||||
*
|
||||
* var element1 = document.querySelector('.className');
|
||||
* var element2 = document.querySelector('#id');
|
||||
*
|
||||
* For details about CSS selector syntax, see the
|
||||
* [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
|
||||
*/
|
||||
Element? querySelector(String selectors) => document.querySelector(selectors);
|
||||
|
||||
/**
|
||||
* Finds all descendant elements of this document that match the specified
|
||||
* group of selectors.
|
||||
*
|
||||
* Unless your webpage contains multiple documents, the top-level
|
||||
* [querySelectorAll]
|
||||
* method behaves the same as this method, so you should use it instead to
|
||||
* save typing a few characters.
|
||||
*
|
||||
* [selectors] should be a string using CSS selector syntax.
|
||||
*
|
||||
* var items = document.querySelectorAll('.itemClassName');
|
||||
*
|
||||
* For details about CSS selector syntax, see the
|
||||
* [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
|
||||
*/
|
||||
ElementList<T> querySelectorAll<T extends Element>(String selectors) =>
|
||||
document.querySelectorAll(selectors);
|
||||
|
||||
/// A utility for changing the Dart wrapper type for elements.
|
||||
abstract class ElementUpgrader {
|
||||
/// Upgrade the specified element to be of the Dart type this was created for.
|
||||
///
|
||||
/// After upgrading the element passed in is invalid and the returned value
|
||||
/// should be used instead.
|
||||
Element upgrade(Element element);
|
||||
}
|
||||
@@ -73,14 +73,13 @@ _logger = logging.getLogger('dartdomgenerator')
|
||||
class GeneratorOptions(object):
|
||||
|
||||
def __init__(self, templates, database, type_registry, renamer, metadata,
|
||||
dart_js_interop, nnbd):
|
||||
dart_js_interop):
|
||||
self.templates = templates
|
||||
self.database = database
|
||||
self.type_registry = type_registry
|
||||
self.renamer = renamer
|
||||
self.metadata = metadata
|
||||
self.dart_js_interop = dart_js_interop
|
||||
self.nnbd = nnbd
|
||||
|
||||
|
||||
def LoadDatabase(database_dir, use_database_cache):
|
||||
@@ -96,18 +95,14 @@ def GenerateFromDatabase(common_database,
|
||||
dart2js_output_dir,
|
||||
update_dom_metadata=False,
|
||||
logging_level=logging.WARNING,
|
||||
dart_js_interop=False,
|
||||
nnbd=False):
|
||||
dart_js_interop=False):
|
||||
print '\n ----- Accessing DOM using %s -----\n' % (
|
||||
'dart:js' if dart_js_interop else 'C++')
|
||||
|
||||
start_time = time.time()
|
||||
|
||||
current_dir = os.path.dirname(__file__)
|
||||
if nnbd:
|
||||
auxiliary_dir = os.path.join(current_dir, '..', 'nnbd_src')
|
||||
else:
|
||||
auxiliary_dir = os.path.join(current_dir, '..', 'src')
|
||||
auxiliary_dir = os.path.join(current_dir, '..', 'src')
|
||||
template_dir = os.path.join(current_dir, '..', 'templates')
|
||||
|
||||
_logger.setLevel(logging_level)
|
||||
@@ -142,7 +137,7 @@ def GenerateFromDatabase(common_database,
|
||||
backend_factory, dart_js_interop):
|
||||
options = GeneratorOptions(template_loader, webkit_database,
|
||||
type_registry, renamer, metadata,
|
||||
dart_js_interop, nnbd)
|
||||
dart_js_interop)
|
||||
dart_library_emitter = DartLibraryEmitter(emitters, dart_output_dir,
|
||||
dart_libraries)
|
||||
event_generator = HtmlEventGenerator(webkit_database, renamer, metadata,
|
||||
@@ -167,11 +162,11 @@ def GenerateFromDatabase(common_database,
|
||||
'DARTIUM': False,
|
||||
'DART2JS': True,
|
||||
'JSINTEROP': False,
|
||||
'NNBD': nnbd
|
||||
'NNBD': True,
|
||||
})
|
||||
backend_options = GeneratorOptions(template_loader, webkit_database,
|
||||
type_registry, renamer, metadata,
|
||||
dart_js_interop, nnbd)
|
||||
dart_js_interop)
|
||||
backend_factory = lambda interface:\
|
||||
Dart2JSBackend(interface, backend_options, logging_level)
|
||||
|
||||
@@ -267,12 +262,6 @@ def main():
|
||||
type='string',
|
||||
default=None,
|
||||
help='Directory to put the generated files')
|
||||
parser.add_option(
|
||||
'--nnbd',
|
||||
dest='nnbd',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='Generate code with non-nullability annotations')
|
||||
parser.add_option(
|
||||
'--use-database-cache',
|
||||
dest='use_database_cache',
|
||||
@@ -348,7 +337,7 @@ def main():
|
||||
|
||||
GenerateFromDatabase(database, dart2js_output_dir,
|
||||
options.update_dom_metadata, logging_level,
|
||||
options.dart_js_interop, options.nnbd)
|
||||
options.dart_js_interop)
|
||||
|
||||
file_generation_start_time = time.time()
|
||||
|
||||
|
||||
@@ -13,13 +13,6 @@ import re
|
||||
from htmlrenamer import custom_html_constructors, html_interface_renames, \
|
||||
typed_array_renames
|
||||
|
||||
# TODO(srujzs): Pass options flag through to emitter functions.
|
||||
class GlobalOptionsHack(object):
|
||||
nnbd = False
|
||||
|
||||
global_options_hack = GlobalOptionsHack()
|
||||
|
||||
|
||||
_pure_interfaces = monitored.Set('generator._pure_interfaces', [
|
||||
'AbstractWorker',
|
||||
'CanvasPath',
|
||||
@@ -688,7 +681,7 @@ def TypeOrNothing(dart_type, comment=None, nullable=False):
|
||||
where a type may be omitted.
|
||||
The string is empty or has a trailing space.
|
||||
"""
|
||||
nullability_operator = '?' if global_options_hack.nnbd and nullable else ''
|
||||
nullability_operator = '?' if nullable else ''
|
||||
if dart_type == 'dynamic':
|
||||
if comment:
|
||||
return '/*%s*/ ' % comment # Just a comment foo(/*T*/ x)
|
||||
@@ -1274,8 +1267,7 @@ class InterfaceIDLTypeInfo(IDLTypeInfo):
|
||||
if self._data.dart_type:
|
||||
return self._data.dart_type
|
||||
if self.list_item_type() and not self.has_generated_interface():
|
||||
item_nullable = '?' if self._data.item_type_nullable and \
|
||||
global_options_hack.nnbd else ''
|
||||
item_nullable = '?' if self._data.item_type_nullable else ''
|
||||
return 'List<%s%s>' % (self._type_registry.TypeInfo(
|
||||
self._data.item_type).dart_type(), item_nullable)
|
||||
return self._dart_interface_name
|
||||
|
||||
@@ -114,7 +114,6 @@ class HtmlDartGenerator(object):
|
||||
for id in sorted(operationsByName.keys()):
|
||||
operations = operationsByName[id]
|
||||
info = AnalyzeOperation(interface, operations)
|
||||
info.nnbd = self._nnbd
|
||||
self.AddOperation(info, declare_only, dart_js_interop)
|
||||
if ('%s.%s' % (interface.id,
|
||||
info.declared_name) in convert_to_future_members):
|
||||
@@ -519,8 +518,7 @@ class HtmlDartGenerator(object):
|
||||
if self._interface_type_info.list_item_type():
|
||||
item_type = self._type_registry.TypeInfo(
|
||||
self._interface_type_info.list_item_type()).dart_type()
|
||||
if self._nnbd and \
|
||||
self._interface_type_info.list_item_type_nullable():
|
||||
if self._interface_type_info.list_item_type_nullable():
|
||||
item_type += '?'
|
||||
implements.append('List<%s>' % item_type)
|
||||
return implements
|
||||
@@ -530,8 +528,7 @@ class HtmlDartGenerator(object):
|
||||
if self._interface_type_info.list_item_type():
|
||||
item_type = self._type_registry.TypeInfo(
|
||||
self._interface_type_info.list_item_type()).dart_type()
|
||||
if self._nnbd and \
|
||||
self._interface_type_info.list_item_type_nullable():
|
||||
if self._interface_type_info.list_item_type_nullable():
|
||||
item_type += '?'
|
||||
mixins.append('ListMixin<%s>' % item_type)
|
||||
mixins.append('ImmutableListMixin<%s>' % item_type)
|
||||
@@ -907,8 +904,7 @@ class HtmlDartGenerator(object):
|
||||
})
|
||||
if nullable:
|
||||
element_js = element_name + "|Null"
|
||||
if self._nnbd:
|
||||
element_name += '?'
|
||||
element_name += '?'
|
||||
else:
|
||||
element_js = element_name
|
||||
self._members_emitter.Emit(
|
||||
@@ -938,11 +934,10 @@ class HtmlDartGenerator(object):
|
||||
assert (dart_name != 'HistoryBase' and dart_name != 'LocationBase')
|
||||
if dart_name == 'Window':
|
||||
dart_name = _secure_base_types[dart_name]
|
||||
if self._nnbd:
|
||||
if type_name == 'any':
|
||||
dart_name = 'Object'
|
||||
if nullable and dart_name != 'dynamic':
|
||||
dart_name = dart_name + '?'
|
||||
if type_name == 'any':
|
||||
dart_name = 'Object'
|
||||
if nullable and dart_name != 'dynamic':
|
||||
dart_name = dart_name + '?'
|
||||
return dart_name
|
||||
|
||||
def SecureBaseName(self, type_name):
|
||||
@@ -1006,7 +1001,7 @@ class HtmlDartGenerator(object):
|
||||
NAME=temp_name,
|
||||
CONVERT=conversion.function_name,
|
||||
ARG=info.param_infos[position].name,
|
||||
NULLASSERT='!' if null_assert_needed and self._nnbd else '',
|
||||
NULLASSERT='!' if null_assert_needed else '',
|
||||
ARITY=callBackInfo)
|
||||
converted_arguments.append(temp_name)
|
||||
param_type = temp_type
|
||||
|
||||
@@ -591,11 +591,6 @@ class HtmlDartInterfaceGenerator(object):
|
||||
self._template_loader = options.templates
|
||||
self._type_registry = options.type_registry
|
||||
self._options = options
|
||||
# TODO(srujzs): This sets the nnbd option globally inside generator.py
|
||||
# since there is no options object there. This should should be cleaned
|
||||
# up and passed as an option instead.
|
||||
global_options_hack.nnbd = options.nnbd
|
||||
self._nnbd = options.nnbd
|
||||
self._library_emitter = library_emitter
|
||||
self._event_generator = event_generator
|
||||
self._interface = interface
|
||||
@@ -808,9 +803,9 @@ class HtmlDartInterfaceGenerator(object):
|
||||
NATIVESPEC=native_spec,
|
||||
KEYTYPE=maplikeKeyType,
|
||||
VALUETYPE=maplikeValueType,
|
||||
NULLABLE='?' if self._options.nnbd else '',
|
||||
NULLSAFECAST=True if self._options.nnbd else False,
|
||||
NULLASSERT='!' if self._options.nnbd else '')
|
||||
NULLABLE='?',
|
||||
NULLSAFECAST=True,
|
||||
NULLASSERT='!')
|
||||
stream_getter_signatures_emitter = None
|
||||
element_stream_getters_emitter = None
|
||||
if type(implementation_members_emitter) == tuple:
|
||||
@@ -1159,7 +1154,6 @@ class Dart2JSBackend(HtmlDartGenerator):
|
||||
self._type_registry = options.type_registry
|
||||
self._renamer = options.renamer
|
||||
self._metadata = options.metadata
|
||||
self._nnbd = options.nnbd
|
||||
self._interface_type_info = self._type_registry.TypeInfo(
|
||||
self._interface.id)
|
||||
self._current_secondary_parent = None
|
||||
@@ -1181,8 +1175,7 @@ class Dart2JSBackend(HtmlDartGenerator):
|
||||
):
|
||||
item_type = self._type_registry.TypeInfo(
|
||||
self._interface_type_info.list_item_type()).dart_type()
|
||||
if self._nnbd and \
|
||||
self._interface_type_info.list_item_type_nullable():
|
||||
if self._interface_type_info.list_item_type_nullable():
|
||||
item_type += '?'
|
||||
implements.append('JavaScriptIndexingBehavior<%s>' % item_type)
|
||||
return implements
|
||||
@@ -1241,19 +1234,17 @@ class Dart2JSBackend(HtmlDartGenerator):
|
||||
"JS$CAST("
|
||||
"'returns:$INTERFACE_NAME;creates:$INTERFACE_NAME;new:true',"
|
||||
" '#.$METHOD(#)', $FACTORY, $ARGUMENTS)",
|
||||
CAST='<' + self._interface_type_info.interface_name() +
|
||||
'>' if self._nnbd else '',
|
||||
CAST='<' + self._interface_type_info.interface_name() + '>',
|
||||
INTERFACE_NAME=self._interface_type_info.interface_name(),
|
||||
FACTORY=factory,
|
||||
METHOD=method,
|
||||
ARGUMENTS=arguments)
|
||||
return emitter.Format(
|
||||
'$FACTORY.$METHOD($ARGUMENTS)$CAST',
|
||||
FACTORY=factory,
|
||||
METHOD=method,
|
||||
ARGUMENTS=arguments,
|
||||
CAST=' as ' + self._interface_type_info.interface_name() \
|
||||
if self._nnbd else '')
|
||||
return emitter.Format('$FACTORY.$METHOD($ARGUMENTS)$CAST',
|
||||
FACTORY=factory,
|
||||
METHOD=method,
|
||||
ARGUMENTS=arguments,
|
||||
CAST=' as ' +
|
||||
self._interface_type_info.interface_name())
|
||||
|
||||
def _HasUnreliableFactoryConstructor(self):
|
||||
return self._interface.doc_js_name in _js_unreliable_element_factories
|
||||
@@ -1361,8 +1352,8 @@ class Dart2JSBackend(HtmlDartGenerator):
|
||||
nullable=nullable),
|
||||
# If the type of the operation is not nullable but the getter
|
||||
# is, we must assert non-null.
|
||||
NULLASSERT='!' if self._nnbd and not nullable and \
|
||||
indexed_getter_nullable else '')
|
||||
NULLASSERT='!' if not nullable and indexed_getter_nullable \
|
||||
else '')
|
||||
|
||||
if 'CustomIndexedSetter' in self._interface.ext_attrs:
|
||||
self._members_emitter.Emit(
|
||||
@@ -1370,7 +1361,7 @@ class Dart2JSBackend(HtmlDartGenerator):
|
||||
' void operator[]=(int index, $TYPE$NULLABLE value) {'
|
||||
' JS("void", "#[#] = #", this, index, value); }',
|
||||
TYPE=self._NarrowInputType(element_type),
|
||||
NULLABLE='?' if self._nnbd and nullable else '')
|
||||
NULLABLE='?' if nullable else '')
|
||||
else:
|
||||
theType = self._NarrowInputType(element_type)
|
||||
if theType == 'DomRectList':
|
||||
@@ -1382,7 +1373,7 @@ class Dart2JSBackend(HtmlDartGenerator):
|
||||
' throw new UnsupportedError("Cannot assign element of immutable List.");\n'
|
||||
' }\n',
|
||||
TYPE=theType,
|
||||
NULLABLE='?' if self._nnbd and nullable else '')
|
||||
NULLABLE='?' if nullable else '')
|
||||
|
||||
self.EmitListMixin(self._DartType(element_type), nullable)
|
||||
|
||||
@@ -1460,7 +1451,7 @@ class Dart2JSBackend(HtmlDartGenerator):
|
||||
return
|
||||
|
||||
input_type = self._NarrowInputType(attribute.type.id)
|
||||
if self._nnbd and attribute.type.nullable:
|
||||
if attribute.type.nullable:
|
||||
input_type += '?'
|
||||
if not read_only:
|
||||
if attribute.type.id == 'Promise':
|
||||
@@ -1483,8 +1474,8 @@ class Dart2JSBackend(HtmlDartGenerator):
|
||||
promiseCall = 'promiseToFutureAsMap'
|
||||
output_conversion = self._OutputConversion("Dictionary",
|
||||
None)
|
||||
nullability = '?' if self._nnbd and \
|
||||
output_conversion.nullable_output else ''
|
||||
nullability = '?' if output_conversion.nullable_output \
|
||||
else ''
|
||||
promiseType = 'Future<Map<String, dynamic>' + \
|
||||
nullability + '>'
|
||||
else:
|
||||
@@ -1492,7 +1483,7 @@ class Dart2JSBackend(HtmlDartGenerator):
|
||||
promiseCall = 'promiseToFuture<%s>' % paramType
|
||||
promiseType = 'Future<%s>' % paramType
|
||||
|
||||
if self._nnbd and attribute.type.nullable:
|
||||
if attribute.type.nullable:
|
||||
promiseType += '?'
|
||||
|
||||
template = '\n $RENAME$(ANNOTATIONS)$TYPE get $NAME => $PROMISE_CALL(JS("", "#.$NAME", this));\n'
|
||||
@@ -1592,11 +1583,11 @@ class Dart2JSBackend(HtmlDartGenerator):
|
||||
HTML_NAME=html_name,
|
||||
NAME=attr.id,
|
||||
RETURN_TYPE=conversion.output_type,
|
||||
NULLABLE_OUT='?' if nullable_out and self._nnbd else '',
|
||||
NULLABLE_OUT='?' if nullable_out else '',
|
||||
NATIVE_TYPE=conversion.input_type,
|
||||
NULLABLE_IN='?' if nullable_in and self._nnbd else '',
|
||||
NULLABLE_IN='?' if nullable_in else '',
|
||||
NULLASSERT='!' if nullable_in and \
|
||||
not conversion.nullable_input and self._nnbd else '')
|
||||
not conversion.nullable_input else '')
|
||||
|
||||
def _AddConvertingSetter(self, attr, html_name, conversion):
|
||||
# If the attribute is nullable, the setter should be nullable.
|
||||
@@ -1617,11 +1608,11 @@ class Dart2JSBackend(HtmlDartGenerator):
|
||||
HTML_NAME=html_name,
|
||||
NAME=attr.id,
|
||||
INPUT_TYPE=conversion.input_type,
|
||||
NULLABLE_IN='?' if nullable_in and self._nnbd else '',
|
||||
NULLABLE_IN='?' if nullable_in else '',
|
||||
NATIVE_TYPE=conversion.output_type,
|
||||
NULLABLE_OUT='?' if nullable_out and self._nnbd else '',
|
||||
NULLABLE_OUT='?' if nullable_out else '',
|
||||
NULLASSERT='!' if nullable_in and \
|
||||
not conversion.nullable_input and self._nnbd else '')
|
||||
not conversion.nullable_input else '')
|
||||
|
||||
def AmendIndexer(self, element_type):
|
||||
pass
|
||||
@@ -1765,8 +1756,8 @@ class Dart2JSBackend(HtmlDartGenerator):
|
||||
promiseCall = 'promiseToFutureAsMap'
|
||||
output_conversion = self._OutputConversion("Dictionary",
|
||||
None)
|
||||
nullability = '?' if self._nnbd and \
|
||||
output_conversion.nullable_output else ''
|
||||
nullability = '?' if output_conversion.nullable_output \
|
||||
else ''
|
||||
promiseType = 'Future<Map<String, dynamic>' + \
|
||||
nullability + '>'
|
||||
else:
|
||||
@@ -1777,7 +1768,7 @@ class Dart2JSBackend(HtmlDartGenerator):
|
||||
dictionary_argument = info.dictionaryArgumentName()
|
||||
codeTemplate = self._promiseToFutureCode(argsNames,
|
||||
dictionary_argument)
|
||||
if self._nnbd and info.type_nullable:
|
||||
if info.type_nullable:
|
||||
promiseType += '?'
|
||||
self._members_emitter.Emit(
|
||||
codeTemplate,
|
||||
@@ -1852,8 +1843,7 @@ class Dart2JSBackend(HtmlDartGenerator):
|
||||
|
||||
if output_conversion:
|
||||
call = '%s(%s)' % (output_conversion.function_name, call)
|
||||
if self._nnbd and output_conversion.nullable_output and \
|
||||
not info.type_nullable:
|
||||
if output_conversion.nullable_output and not info.type_nullable:
|
||||
# Return type of operation is not nullable while conversion
|
||||
# is, so we need to assert non-null.
|
||||
call += '!'
|
||||
@@ -1904,7 +1894,7 @@ class Dart2JSBackend(HtmlDartGenerator):
|
||||
html_name.startswith('_')) else True
|
||||
|
||||
nullsafe_return_type = return_type;
|
||||
if self._nnbd and info.type_nullable:
|
||||
if info.type_nullable:
|
||||
nullsafe_return_type += '?'
|
||||
|
||||
declaration = '%s%s%s %s(%s)' % (
|
||||
@@ -1970,18 +1960,15 @@ class Dart2JSBackend(HtmlDartGenerator):
|
||||
return_type = self.SecureOutputType(idl_type)
|
||||
native_type = self._NarrowToImplementationType(idl_type)
|
||||
|
||||
null_union = '' if self._nnbd and not nullable else '|Null'
|
||||
null_union = '' if not nullable else '|Null'
|
||||
if native_type != return_type:
|
||||
anns = anns + [
|
||||
"@Returns('%s%s')" % (native_type, null_union),
|
||||
"@Creates('%s')" % native_type,
|
||||
]
|
||||
if dart_type == 'dynamic' or \
|
||||
(not self._nnbd and dart_type == 'Object') or \
|
||||
(self._nnbd and dart_type == 'Object?'):
|
||||
# If we're generating nnbd code, we emit non-nullable Object
|
||||
# annotations but exclude nullable Object annotations since that's
|
||||
# the default.
|
||||
if dart_type == 'dynamic' or dart_type == 'Object?':
|
||||
# We emit non-nullable Object annotations but exclude nullable
|
||||
# Object annotations since that's the default.
|
||||
|
||||
def js_type_annotation(ann):
|
||||
return re.search('^@.*Returns', ann) or re.search(
|
||||
@@ -2097,7 +2084,7 @@ class DartLibrary():
|
||||
emitters = library_emitter.Emit(
|
||||
self._template,
|
||||
AUXILIARY_DIR=massage_path(auxiliary_dir),
|
||||
NULLABLE='?' if global_options_hack.nnbd else '')
|
||||
NULLABLE='?')
|
||||
if isinstance(emitters, tuple):
|
||||
imports_emitter, map_emitter = emitters
|
||||
else:
|
||||
|
||||
@@ -16,7 +16,7 @@ abstract class _AttributeMap extends MapBase<String, String> {
|
||||
}
|
||||
|
||||
Map<K, V> cast<K, V>() => Map.castFrom<String, String, K, V>(this);
|
||||
bool containsValue(Object value) {
|
||||
bool containsValue(Object? value) {
|
||||
for (var v in this.values) {
|
||||
if (value == v) {
|
||||
return true;
|
||||
@@ -29,7 +29,7 @@ abstract class _AttributeMap extends MapBase<String, String> {
|
||||
if (!containsKey(key)) {
|
||||
this[key] = ifAbsent();
|
||||
}
|
||||
return this[key];
|
||||
return this[key] as String;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
@@ -41,7 +41,7 @@ abstract class _AttributeMap extends MapBase<String, String> {
|
||||
void forEach(void f(String key, String value)) {
|
||||
for (var key in keys) {
|
||||
var value = this[key];
|
||||
f(key, value);
|
||||
f(key, value as String);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ abstract class _AttributeMap extends MapBase<String, String> {
|
||||
var attributes = _element._attributes;
|
||||
var keys = <String>[];
|
||||
for (int i = 0, len = attributes.length; i < len; i++) {
|
||||
_Attr attr = attributes[i];
|
||||
_Attr attr = attributes[i] as _Attr;
|
||||
if (_matches(attr)) {
|
||||
keys.add(attr.name);
|
||||
}
|
||||
@@ -63,7 +63,7 @@ abstract class _AttributeMap extends MapBase<String, String> {
|
||||
var attributes = _element._attributes;
|
||||
var values = <String>[];
|
||||
for (int i = 0, len = attributes.length; i < len; i++) {
|
||||
_Attr attr = attributes[i];
|
||||
_Attr attr = attributes[i] as _Attr;
|
||||
if (_matches(attr)) {
|
||||
values.add(attr.value);
|
||||
}
|
||||
@@ -95,12 +95,12 @@ abstract class _AttributeMap extends MapBase<String, String> {
|
||||
class _ElementAttributeMap extends _AttributeMap {
|
||||
_ElementAttributeMap(Element element) : super(element);
|
||||
|
||||
bool containsKey(Object key) {
|
||||
return _element._hasAttribute(key);
|
||||
bool containsKey(Object? key) {
|
||||
return key is String && _element._hasAttribute(key);
|
||||
}
|
||||
|
||||
String operator [](Object key) {
|
||||
return _element.getAttribute(key);
|
||||
String? operator [](Object? key) {
|
||||
return _element.getAttribute(key as String);
|
||||
}
|
||||
|
||||
void operator []=(String key, String value) {
|
||||
@@ -108,7 +108,7 @@ class _ElementAttributeMap extends _AttributeMap {
|
||||
}
|
||||
|
||||
@pragma('dart2js:tryInline')
|
||||
String remove(Object key) => key is String ? _remove(_element, key) : null;
|
||||
String? remove(Object? key) => key is String ? _remove(_element, key) : null;
|
||||
|
||||
/**
|
||||
* The number of {key, value} pairs in the map.
|
||||
@@ -122,8 +122,8 @@ class _ElementAttributeMap extends _AttributeMap {
|
||||
// Inline this because almost all call sites of [remove] do not use [value],
|
||||
// and the annotations on the `getAttribute` call allow it to be removed.
|
||||
@pragma('dart2js:tryInline')
|
||||
static String _remove(Element element, String key) {
|
||||
String value = JS(
|
||||
static String? _remove(Element element, String key) {
|
||||
String? value = JS(
|
||||
// throws:null(1) is not accurate since [key] could be malformed, but
|
||||
// [key] is checked again by `removeAttributeNS`.
|
||||
'returns:String|Null;depends:all;effects:none;throws:null(1)',
|
||||
@@ -139,16 +139,16 @@ class _ElementAttributeMap extends _AttributeMap {
|
||||
* Wrapper to expose namespaced attributes as a typed map.
|
||||
*/
|
||||
class _NamespacedAttributeMap extends _AttributeMap {
|
||||
final String _namespace;
|
||||
final String? _namespace;
|
||||
|
||||
_NamespacedAttributeMap(Element element, this._namespace) : super(element);
|
||||
|
||||
bool containsKey(Object key) {
|
||||
return _element._hasAttributeNS(_namespace, key);
|
||||
bool containsKey(Object? key) {
|
||||
return key is String && _element._hasAttributeNS(_namespace, key);
|
||||
}
|
||||
|
||||
String operator [](Object key) {
|
||||
return _element.getAttributeNS(_namespace, key);
|
||||
String? operator [](Object? key) {
|
||||
return _element.getAttributeNS(_namespace, key as String);
|
||||
}
|
||||
|
||||
void operator []=(String key, String value) {
|
||||
@@ -156,7 +156,7 @@ class _NamespacedAttributeMap extends _AttributeMap {
|
||||
}
|
||||
|
||||
@pragma('dart2js:tryInline')
|
||||
String remove(Object key) =>
|
||||
String? remove(Object? key) =>
|
||||
key is String ? _remove(_namespace, _element, key) : null;
|
||||
|
||||
/**
|
||||
@@ -172,8 +172,8 @@ class _NamespacedAttributeMap extends _AttributeMap {
|
||||
// returned [value], and the annotations on the `getAttributeNS` call allow it
|
||||
// to be removed.
|
||||
@pragma('dart2js:tryInline')
|
||||
static String _remove(String namespace, Element element, String key) {
|
||||
String value = JS(
|
||||
static String? _remove(String? namespace, Element element, String key) {
|
||||
String? value = JS(
|
||||
// throws:null(1) is not accurate since [key] could be malformed, but
|
||||
// [key] is checked again by `removeAttributeNS`.
|
||||
'returns:String|Null;depends:all;effects:none;throws:null(1)',
|
||||
@@ -205,11 +205,12 @@ class _DataAttributeMap extends MapBase<String, String> {
|
||||
|
||||
Map<K, V> cast<K, V>() => Map.castFrom<String, String, K, V>(this);
|
||||
// TODO: Use lazy iterator when it is available on Map.
|
||||
bool containsValue(Object value) => values.any((v) => v == value);
|
||||
bool containsValue(Object? value) => values.any((v) => v == value);
|
||||
|
||||
bool containsKey(Object key) => _attributes.containsKey(_attr(key));
|
||||
bool containsKey(Object? key) =>
|
||||
_attributes.containsKey(_attr(key as String));
|
||||
|
||||
String operator [](Object key) => _attributes[_attr(key)];
|
||||
String? operator [](Object? key) => _attributes[_attr(key as String)];
|
||||
|
||||
void operator []=(String key, String value) {
|
||||
_attributes[_attr(key)] = value;
|
||||
@@ -218,7 +219,7 @@ class _DataAttributeMap extends MapBase<String, String> {
|
||||
String putIfAbsent(String key, String ifAbsent()) =>
|
||||
_attributes.putIfAbsent(_attr(key), ifAbsent);
|
||||
|
||||
String remove(Object key) => _attributes.remove(_attr(key));
|
||||
String? remove(Object? key) => _attributes.remove(_attr(key as String));
|
||||
|
||||
void clear() {
|
||||
// Needs to operate on a snapshot since we are mutating the collection.
|
||||
|
||||
@@ -61,7 +61,7 @@ abstract class WindowBase implements EventTarget {
|
||||
* WindowBase otherWindow = thisWindow.open('http://www.example.com/', 'foo');
|
||||
* print(otherWindow.opener == thisWindow); // 'true'
|
||||
*/
|
||||
WindowBase get opener;
|
||||
WindowBase? get opener;
|
||||
|
||||
/**
|
||||
* A reference to the parent of this window.
|
||||
@@ -75,7 +75,7 @@ abstract class WindowBase implements EventTarget {
|
||||
*
|
||||
* print(window.parent == window) // 'true'
|
||||
*/
|
||||
WindowBase get parent;
|
||||
WindowBase? get parent;
|
||||
|
||||
/**
|
||||
* A reference to the topmost window in the window hierarchy.
|
||||
@@ -96,7 +96,7 @@ abstract class WindowBase implements EventTarget {
|
||||
*
|
||||
* print(window.top == window) // 'true'
|
||||
*/
|
||||
WindowBase get top;
|
||||
WindowBase? get top;
|
||||
|
||||
// Methods.
|
||||
/**
|
||||
@@ -142,7 +142,7 @@ abstract class WindowBase implements EventTarget {
|
||||
* from WHATWG.
|
||||
*/
|
||||
void postMessage(var message, String targetOrigin,
|
||||
[List<MessagePort> messagePorts]);
|
||||
[List<MessagePort>? messagePorts]);
|
||||
}
|
||||
|
||||
abstract class LocationBase {
|
||||
|
||||
@@ -24,7 +24,7 @@ abstract class CssClassSet implements Set<String> {
|
||||
* non-empty string containing no whitespace. To toggle multiple classes, use
|
||||
* [toggleAll].
|
||||
*/
|
||||
bool toggle(String value, [bool shouldAdd]);
|
||||
bool toggle(String value, [bool? shouldAdd]);
|
||||
|
||||
/**
|
||||
* Returns [:true:] if classes cannot be added or removed from this
|
||||
@@ -41,7 +41,7 @@ abstract class CssClassSet implements Set<String> {
|
||||
* [value] must be a valid 'token' representing a single class, i.e. a
|
||||
* non-empty string containing no whitespace.
|
||||
*/
|
||||
bool contains(Object value);
|
||||
bool contains(Object? value);
|
||||
|
||||
/**
|
||||
* Add the class [value] to element.
|
||||
@@ -72,7 +72,7 @@ abstract class CssClassSet implements Set<String> {
|
||||
* non-empty string containing no whitespace. To remove multiple classes, use
|
||||
* [removeAll].
|
||||
*/
|
||||
bool remove(Object value);
|
||||
bool remove(Object? value);
|
||||
|
||||
/**
|
||||
* Add all classes specified in [iterable] to element.
|
||||
@@ -94,7 +94,7 @@ abstract class CssClassSet implements Set<String> {
|
||||
* Each element of [iterable] must be a valid 'token' representing a single
|
||||
* class, i.e. a non-empty string containing no whitespace.
|
||||
*/
|
||||
void removeAll(Iterable<Object> iterable);
|
||||
void removeAll(Iterable<Object?> iterable);
|
||||
|
||||
/**
|
||||
* Toggles all classes specified in [iterable] on element.
|
||||
@@ -109,5 +109,5 @@ abstract class CssClassSet implements Set<String> {
|
||||
* Each element of [iterable] must be a valid 'token' representing a single
|
||||
* class, i.e. a non-empty string containing no whitespace.
|
||||
*/
|
||||
void toggleAll(Iterable<String> iterable, [bool shouldAdd]);
|
||||
void toggleAll(Iterable<String> iterable, [bool? shouldAdd]);
|
||||
}
|
||||
|
||||
@@ -75,9 +75,9 @@ class _ContentCssRect extends CssRect {
|
||||
class _ContentCssListRect extends _ContentCssRect {
|
||||
List<Element> _elementList;
|
||||
|
||||
_ContentCssListRect(List<Element> elementList) : super(elementList.first) {
|
||||
_elementList = elementList;
|
||||
}
|
||||
_ContentCssListRect(List<Element> elementList)
|
||||
: _elementList = elementList,
|
||||
super(elementList.first);
|
||||
|
||||
/**
|
||||
* Set the height to `newHeight`.
|
||||
@@ -299,7 +299,7 @@ abstract class CssRect implements Rectangle<num> {
|
||||
* Returns the intersection of this and `other`, or `null` if they don't
|
||||
* intersect.
|
||||
*/
|
||||
Rectangle<num> intersection(Rectangle<num> other) {
|
||||
Rectangle<num>? intersection(Rectangle<num> other) {
|
||||
var x0 = max(left, other.left);
|
||||
var x1 = min(left + width, other.left + other.width);
|
||||
|
||||
|
||||
@@ -57,7 +57,9 @@ class Dimension {
|
||||
* `inherit` or invalid CSS will cause this constructor to throw a
|
||||
* FormatError.
|
||||
*/
|
||||
Dimension.css(String cssValue) {
|
||||
Dimension.css(String cssValue)
|
||||
: _unit = '',
|
||||
_value = 0 {
|
||||
if (cssValue == '') cssValue = '0px';
|
||||
if (cssValue.endsWith('%')) {
|
||||
_unit = '%';
|
||||
|
||||
@@ -34,7 +34,7 @@ class EventStreamProvider<T extends Event> {
|
||||
* * [EventTarget.addEventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)
|
||||
* from MDN.
|
||||
*/
|
||||
Stream<T> forTarget(EventTarget e, {bool useCapture: false}) =>
|
||||
Stream<T> forTarget(EventTarget? e, {bool useCapture: false}) =>
|
||||
new _EventStream<T>(e, _eventType, useCapture);
|
||||
|
||||
/**
|
||||
@@ -126,7 +126,7 @@ abstract class ElementStream<T extends Event> implements Stream<T> {
|
||||
* Adapter for exposing DOM events as Dart streams.
|
||||
*/
|
||||
class _EventStream<T extends Event> extends Stream<T> {
|
||||
final EventTarget _target;
|
||||
final EventTarget? _target;
|
||||
final String _eventType;
|
||||
final bool _useCapture;
|
||||
|
||||
@@ -134,16 +134,16 @@ class _EventStream<T extends Event> extends Stream<T> {
|
||||
|
||||
// DOM events are inherently multi-subscribers.
|
||||
Stream<T> asBroadcastStream(
|
||||
{void onListen(StreamSubscription<T> subscription),
|
||||
void onCancel(StreamSubscription<T> subscription)}) =>
|
||||
{void onListen(StreamSubscription<T> subscription)?,
|
||||
void onCancel(StreamSubscription<T> subscription)?}) =>
|
||||
this;
|
||||
bool get isBroadcast => true;
|
||||
|
||||
// TODO(9757): Inlining should be smart and inline only when inlining would
|
||||
// enable scalar replacement of an immediately allocated receiver.
|
||||
@pragma('dart2js:tryInline')
|
||||
StreamSubscription<T> listen(void onData(T event),
|
||||
{Function onError, void onDone(), bool cancelOnError}) {
|
||||
StreamSubscription<T> listen(void onData(T event)?,
|
||||
{Function? onError, void onDone()?, bool? cancelOnError}) {
|
||||
return new _EventStreamSubscription<T>(
|
||||
this._target, this._eventType, onData, this._useCapture);
|
||||
}
|
||||
@@ -194,8 +194,8 @@ class _ElementListEventStreamImpl<T extends Event> extends Stream<T>
|
||||
});
|
||||
|
||||
// Delegate all regular Stream behavior to a wrapped Stream.
|
||||
StreamSubscription<T> listen(void onData(T event),
|
||||
{Function onError, void onDone(), bool cancelOnError}) {
|
||||
StreamSubscription<T> listen(void onData(T event)?,
|
||||
{Function? onError, void onDone()?, bool? cancelOnError}) {
|
||||
var pool = new _StreamPool<T>.broadcast();
|
||||
for (var target in _targetList) {
|
||||
pool.add(new _EventStream<T>(target, _eventType, _useCapture));
|
||||
@@ -213,8 +213,8 @@ class _ElementListEventStreamImpl<T extends Event> extends Stream<T>
|
||||
}
|
||||
|
||||
Stream<T> asBroadcastStream(
|
||||
{void onListen(StreamSubscription<T> subscription),
|
||||
void onCancel(StreamSubscription<T> subscription)}) =>
|
||||
{void onListen(StreamSubscription<T> subscription)?,
|
||||
void onCancel(StreamSubscription<T> subscription)?}) =>
|
||||
this;
|
||||
bool get isBroadcast => true;
|
||||
}
|
||||
@@ -225,9 +225,9 @@ typedef _EventListener<T extends Event>(T event);
|
||||
|
||||
class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> {
|
||||
int _pauseCount = 0;
|
||||
EventTarget _target;
|
||||
EventTarget? _target;
|
||||
final String _eventType;
|
||||
EventListener _onData;
|
||||
EventListener? _onData;
|
||||
final bool _useCapture;
|
||||
|
||||
// TODO(leafp): It would be better to write this as
|
||||
@@ -240,7 +240,7 @@ class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> {
|
||||
// which are typed correctly. But this currently runs afoul of restrictions
|
||||
// on is checks for compatibility with the VM.
|
||||
_EventStreamSubscription(
|
||||
this._target, this._eventType, void onData(T event), this._useCapture)
|
||||
this._target, this._eventType, void onData(T event)?, this._useCapture)
|
||||
: _onData = onData == null
|
||||
? null
|
||||
: _wrapZone<Event>((e) => (onData as dynamic)(e)) {
|
||||
@@ -248,18 +248,23 @@ class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> {
|
||||
}
|
||||
|
||||
Future cancel() {
|
||||
if (_canceled) return null;
|
||||
// Check for strong mode. This function can no longer return null in strong
|
||||
// mode, so only return null in weak mode to preserve synchronous timing.
|
||||
// See issue 41653 for more details.
|
||||
dynamic emptyFuture =
|
||||
typeAcceptsNull<Event>() ? null : Future<void>.value();
|
||||
if (_canceled) return emptyFuture as Future;
|
||||
|
||||
_unlisten();
|
||||
// Clear out the target to indicate this is complete.
|
||||
_target = null;
|
||||
_onData = null;
|
||||
return null;
|
||||
return emptyFuture as Future;
|
||||
}
|
||||
|
||||
bool get _canceled => _target == null;
|
||||
|
||||
void onData(void handleData(T event)) {
|
||||
void onData(void handleData(T event)?) {
|
||||
if (_canceled) {
|
||||
throw new StateError("Subscription has been canceled.");
|
||||
}
|
||||
@@ -272,12 +277,12 @@ class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> {
|
||||
}
|
||||
|
||||
/// Has no effect.
|
||||
void onError(Function handleError) {}
|
||||
void onError(Function? handleError) {}
|
||||
|
||||
/// Has no effect.
|
||||
void onDone(void handleDone()) {}
|
||||
void onDone(void handleDone()?) {}
|
||||
|
||||
void pause([Future resumeSignal]) {
|
||||
void pause([Future? resumeSignal]) {
|
||||
if (_canceled) return;
|
||||
++_pauseCount;
|
||||
_unlisten();
|
||||
@@ -297,17 +302,17 @@ class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> {
|
||||
|
||||
void _tryResume() {
|
||||
if (_onData != null && !isPaused) {
|
||||
_target.addEventListener(_eventType, _onData, _useCapture);
|
||||
_target!.addEventListener(_eventType, _onData, _useCapture);
|
||||
}
|
||||
}
|
||||
|
||||
void _unlisten() {
|
||||
if (_onData != null) {
|
||||
_target.removeEventListener(_eventType, _onData, _useCapture);
|
||||
_target!.removeEventListener(_eventType, _onData, _useCapture);
|
||||
}
|
||||
}
|
||||
|
||||
Future<E> asFuture<E>([E futureValue]) {
|
||||
Future<E> asFuture<E>([E? futureValue]) {
|
||||
// We just need a future that will never succeed or fail.
|
||||
var completer = new Completer<E>();
|
||||
return completer.future;
|
||||
@@ -332,21 +337,20 @@ class _CustomEventStreamImpl<T extends Event> extends Stream<T>
|
||||
/** The type of event this stream is providing (e.g. "keydown"). */
|
||||
String _type;
|
||||
|
||||
_CustomEventStreamImpl(String type) {
|
||||
_type = type;
|
||||
_streamController = new StreamController.broadcast(sync: true);
|
||||
}
|
||||
_CustomEventStreamImpl(String type)
|
||||
: _type = type,
|
||||
_streamController = new StreamController.broadcast(sync: true);
|
||||
|
||||
// Delegate all regular Stream behavior to our wrapped Stream.
|
||||
StreamSubscription<T> listen(void onData(T event),
|
||||
{Function onError, void onDone(), bool cancelOnError}) {
|
||||
StreamSubscription<T> listen(void onData(T event)?,
|
||||
{Function? onError, void onDone()?, bool? cancelOnError}) {
|
||||
return _streamController.stream.listen(onData,
|
||||
onError: onError, onDone: onDone, cancelOnError: cancelOnError);
|
||||
}
|
||||
|
||||
Stream<T> asBroadcastStream(
|
||||
{void onListen(StreamSubscription<T> subscription),
|
||||
void onCancel(StreamSubscription<T> subscription)}) =>
|
||||
{void onListen(StreamSubscription<T> subscription)?,
|
||||
void onCancel(StreamSubscription<T> subscription)?}) =>
|
||||
_streamController.stream;
|
||||
|
||||
bool get isBroadcast => true;
|
||||
@@ -362,7 +366,7 @@ class _CustomKeyEventStreamImpl extends _CustomEventStreamImpl<KeyEvent>
|
||||
|
||||
void add(KeyEvent event) {
|
||||
if (event.type == _type) {
|
||||
event.currentTarget.dispatchEvent(event._parent);
|
||||
event.currentTarget!.dispatchEvent(event._parent);
|
||||
_streamController.add(event);
|
||||
}
|
||||
}
|
||||
@@ -374,7 +378,7 @@ class _CustomKeyEventStreamImpl extends _CustomEventStreamImpl<KeyEvent>
|
||||
*/
|
||||
// TODO (efortuna): Remove this when Issue 12218 is addressed.
|
||||
class _StreamPool<T> {
|
||||
StreamController<T> _controller;
|
||||
StreamController<T>? _controller;
|
||||
|
||||
/// Subscriptions to the streams that make up the pool.
|
||||
var _subscriptions = new Map<Stream<T>, StreamSubscription<T>>();
|
||||
@@ -394,7 +398,7 @@ class _StreamPool<T> {
|
||||
/**
|
||||
* The stream through which all events from streams in the pool are emitted.
|
||||
*/
|
||||
Stream<T> get stream => _controller.stream;
|
||||
Stream<T> get stream => _controller!.stream;
|
||||
|
||||
/**
|
||||
* Adds [stream] as a member of this pool.
|
||||
@@ -405,8 +409,8 @@ class _StreamPool<T> {
|
||||
*/
|
||||
void add(Stream<T> stream) {
|
||||
if (_subscriptions.containsKey(stream)) return;
|
||||
_subscriptions[stream] = stream.listen(_controller.add,
|
||||
onError: _controller.addError, onDone: () => remove(stream));
|
||||
_subscriptions[stream] = stream.listen(_controller!.add,
|
||||
onError: _controller!.addError, onDone: () => remove(stream));
|
||||
}
|
||||
|
||||
/** Removes [stream] as a member of this pool. */
|
||||
@@ -421,7 +425,7 @@ class _StreamPool<T> {
|
||||
subscription.cancel();
|
||||
}
|
||||
_subscriptions.clear();
|
||||
_controller.close();
|
||||
_controller!.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,7 +438,7 @@ class _CustomEventStreamProvider<T extends Event>
|
||||
final _eventTypeGetter;
|
||||
const _CustomEventStreamProvider(this._eventTypeGetter);
|
||||
|
||||
Stream<T> forTarget(EventTarget e, {bool useCapture: false}) {
|
||||
Stream<T> forTarget(EventTarget? e, {bool useCapture: false}) {
|
||||
return new _EventStream<T>(e, _eventTypeGetter(e), useCapture);
|
||||
}
|
||||
|
||||
|
||||
@@ -408,8 +408,8 @@ class _Html5NodeValidator implements NodeValidator {
|
||||
* All known URI attributes will be validated against the UriPolicy, if
|
||||
* [uriPolicy] is null then a default UriPolicy will be used.
|
||||
*/
|
||||
_Html5NodeValidator({UriPolicy uriPolicy})
|
||||
: uriPolicy = uriPolicy != null ? uriPolicy : new UriPolicy() {
|
||||
_Html5NodeValidator({UriPolicy? uriPolicy})
|
||||
: uriPolicy = uriPolicy ?? UriPolicy() {
|
||||
if (_attributeValidators.isEmpty) {
|
||||
for (var attr in _standardAttributes) {
|
||||
_attributeValidators[attr] = _standardAttributeValidator;
|
||||
|
||||
@@ -22,11 +22,11 @@ abstract class ImmutableListMixin<E> implements List<E> {
|
||||
throw new UnsupportedError("Cannot add to immutable List.");
|
||||
}
|
||||
|
||||
void sort([int compare(E a, E b)]) {
|
||||
void sort([int compare(E a, E b)?]) {
|
||||
throw new UnsupportedError("Cannot sort immutable List.");
|
||||
}
|
||||
|
||||
void shuffle([Random random]) {
|
||||
void shuffle([Random? random]) {
|
||||
throw new UnsupportedError("Cannot shuffle immutable List.");
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ abstract class ImmutableListMixin<E> implements List<E> {
|
||||
throw new UnsupportedError("Cannot remove from immutable List.");
|
||||
}
|
||||
|
||||
bool remove(Object object) {
|
||||
bool remove(Object? object) {
|
||||
throw new UnsupportedError("Cannot remove from immutable List.");
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ abstract class ImmutableListMixin<E> implements List<E> {
|
||||
throw new UnsupportedError("Cannot modify an immutable List.");
|
||||
}
|
||||
|
||||
void fillRange(int start, int end, [E fillValue]) {
|
||||
void fillRange(int start, int end, [E? fillValue]) {
|
||||
throw new UnsupportedError("Cannot modify an immutable List.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ class _KeyboardEventHandler extends EventStreamProvider<KeyEvent> {
|
||||
final String _type;
|
||||
|
||||
/** The element we are watching for events to happen on. */
|
||||
final EventTarget _target;
|
||||
final EventTarget? _target;
|
||||
|
||||
// The distance to shift from upper case alphabet Roman letters to lower case.
|
||||
static final int _ROMAN_ALPHABET_OFFSET = "a".codeUnits[0] - "A".codeUnits[0];
|
||||
@@ -65,7 +65,7 @@ class _KeyboardEventHandler extends EventStreamProvider<KeyEvent> {
|
||||
|
||||
/** Return a stream for KeyEvents for the specified target. */
|
||||
// Note: this actually functions like a factory constructor.
|
||||
CustomStream<KeyEvent> forTarget(EventTarget e, {bool useCapture: false}) {
|
||||
CustomStream<KeyEvent> forTarget(EventTarget? e, {bool useCapture: false}) {
|
||||
var handler =
|
||||
new _KeyboardEventHandler.initializeAllEventListeners(_type, e);
|
||||
return handler._stream;
|
||||
@@ -85,7 +85,8 @@ class _KeyboardEventHandler extends EventStreamProvider<KeyEvent> {
|
||||
* and charcodes when they are not provided.
|
||||
*/
|
||||
_KeyboardEventHandler.initializeAllEventListeners(this._type, this._target)
|
||||
: super(_EVENT_TYPE) {
|
||||
: _stream = new _CustomKeyEventStreamImpl(_type),
|
||||
super(_EVENT_TYPE) {
|
||||
Element.keyDownEvent
|
||||
.forTarget(_target, useCapture: true)
|
||||
.listen(processKeyDown);
|
||||
@@ -95,7 +96,6 @@ class _KeyboardEventHandler extends EventStreamProvider<KeyEvent> {
|
||||
Element.keyUpEvent
|
||||
.forTarget(_target, useCapture: true)
|
||||
.listen(processKeyUp);
|
||||
_stream = new _CustomKeyEventStreamImpl(_type);
|
||||
}
|
||||
|
||||
/** Determine if caps lock is one of the currently depressed keys. */
|
||||
@@ -337,7 +337,7 @@ class _KeyboardEventHandler extends EventStreamProvider<KeyEvent> {
|
||||
_keyIdentifier.containsKey(e._shadowKeyIdentifier)) {
|
||||
// This is needed for Safari Windows because it currently doesn't give a
|
||||
// keyCode/which for non printable keys.
|
||||
e._shadowKeyCode = _keyIdentifier[e._shadowKeyIdentifier];
|
||||
e._shadowKeyCode = _keyIdentifier[e._shadowKeyIdentifier]!;
|
||||
}
|
||||
e._shadowAltKey = _keyDownList.any((var element) => element.altKey);
|
||||
_stream.add(e);
|
||||
@@ -346,7 +346,7 @@ class _KeyboardEventHandler extends EventStreamProvider<KeyEvent> {
|
||||
/** Handle keyup events. */
|
||||
void processKeyUp(KeyboardEvent event) {
|
||||
var e = new KeyEvent.wrap(event);
|
||||
KeyboardEvent toRemove = null;
|
||||
KeyboardEvent? toRemove = null;
|
||||
for (var key in _keyDownList) {
|
||||
if (key.keyCode == e.keyCode) {
|
||||
toRemove = key;
|
||||
|
||||
@@ -58,7 +58,7 @@ class NodeValidatorBuilder implements NodeValidator {
|
||||
* The UriPolicy can be used to restrict the locations the navigation elements
|
||||
* are allowed to direct to. By default this will use the default [UriPolicy].
|
||||
*/
|
||||
void allowNavigation([UriPolicy uriPolicy]) {
|
||||
void allowNavigation([UriPolicy? uriPolicy]) {
|
||||
if (uriPolicy == null) {
|
||||
uriPolicy = new UriPolicy();
|
||||
}
|
||||
@@ -71,7 +71,7 @@ class NodeValidatorBuilder implements NodeValidator {
|
||||
* The UriPolicy can be used to restrict the locations the images may be
|
||||
* loaded from. By default this will use the default [UriPolicy].
|
||||
*/
|
||||
void allowImages([UriPolicy uriPolicy]) {
|
||||
void allowImages([UriPolicy? uriPolicy]) {
|
||||
if (uriPolicy == null) {
|
||||
uriPolicy = new UriPolicy();
|
||||
}
|
||||
@@ -112,7 +112,7 @@ class NodeValidatorBuilder implements NodeValidator {
|
||||
* If [tagName] is not specified then this allows inline styles on all
|
||||
* elements. Otherwise tagName limits the styles to the specified elements.
|
||||
*/
|
||||
void allowInlineStyles({String tagName}) {
|
||||
void allowInlineStyles({String? tagName}) {
|
||||
if (tagName == null) {
|
||||
tagName = '*';
|
||||
} else {
|
||||
@@ -130,7 +130,7 @@ class NodeValidatorBuilder implements NodeValidator {
|
||||
* Common things which are not allowed are script elements, style attributes
|
||||
* and any script handlers.
|
||||
*/
|
||||
void allowHtml5({UriPolicy uriPolicy}) {
|
||||
void allowHtml5({UriPolicy? uriPolicy}) {
|
||||
add(new _Html5NodeValidator(uriPolicy: uriPolicy));
|
||||
}
|
||||
|
||||
@@ -149,9 +149,9 @@ class NodeValidatorBuilder implements NodeValidator {
|
||||
* tag extensions.
|
||||
*/
|
||||
void allowCustomElement(String tagName,
|
||||
{UriPolicy uriPolicy,
|
||||
Iterable<String> attributes,
|
||||
Iterable<String> uriAttributes}) {
|
||||
{UriPolicy? uriPolicy,
|
||||
Iterable<String>? attributes,
|
||||
Iterable<String>? uriAttributes}) {
|
||||
var tagNameUpper = tagName.toUpperCase();
|
||||
var attrs = attributes
|
||||
?.map<String>((name) => '$tagNameUpper::${name.toLowerCase()}');
|
||||
@@ -174,9 +174,9 @@ class NodeValidatorBuilder implements NodeValidator {
|
||||
* custom tags.
|
||||
*/
|
||||
void allowTagExtension(String tagName, String baseName,
|
||||
{UriPolicy uriPolicy,
|
||||
Iterable<String> attributes,
|
||||
Iterable<String> uriAttributes}) {
|
||||
{UriPolicy? uriPolicy,
|
||||
Iterable<String>? attributes,
|
||||
Iterable<String>? uriAttributes}) {
|
||||
var baseNameUpper = baseName.toUpperCase();
|
||||
var tagNameUpper = tagName.toUpperCase();
|
||||
var attrs = attributes
|
||||
@@ -192,9 +192,9 @@ class NodeValidatorBuilder implements NodeValidator {
|
||||
}
|
||||
|
||||
void allowElement(String tagName,
|
||||
{UriPolicy uriPolicy,
|
||||
Iterable<String> attributes,
|
||||
Iterable<String> uriAttributes}) {
|
||||
{UriPolicy? uriPolicy,
|
||||
Iterable<String>? attributes,
|
||||
Iterable<String>? uriAttributes}) {
|
||||
allowCustomElement(tagName,
|
||||
uriPolicy: uriPolicy,
|
||||
attributes: attributes,
|
||||
@@ -236,7 +236,7 @@ class _SimpleNodeValidator implements NodeValidator {
|
||||
final Set<String> allowedElements = new Set<String>();
|
||||
final Set<String> allowedAttributes = new Set<String>();
|
||||
final Set<String> allowedUriAttributes = new Set<String>();
|
||||
final UriPolicy uriPolicy;
|
||||
final UriPolicy? uriPolicy;
|
||||
|
||||
factory _SimpleNodeValidator.allowNavigation(UriPolicy uriPolicy) {
|
||||
return new _SimpleNodeValidator(uriPolicy, allowedElements: const [
|
||||
@@ -311,9 +311,9 @@ class _SimpleNodeValidator implements NodeValidator {
|
||||
* lowercase attribute name. For example `'IMG:src'`.
|
||||
*/
|
||||
_SimpleNodeValidator(this.uriPolicy,
|
||||
{Iterable<String> allowedElements,
|
||||
Iterable<String> allowedAttributes,
|
||||
Iterable<String> allowedUriAttributes}) {
|
||||
{Iterable<String>? allowedElements,
|
||||
Iterable<String>? allowedAttributes,
|
||||
Iterable<String>? allowedUriAttributes}) {
|
||||
this.allowedElements.addAll(allowedElements ?? const []);
|
||||
allowedAttributes = allowedAttributes ?? const [];
|
||||
allowedUriAttributes = allowedUriAttributes ?? const [];
|
||||
@@ -333,9 +333,9 @@ class _SimpleNodeValidator implements NodeValidator {
|
||||
bool allowsAttribute(Element element, String attributeName, String value) {
|
||||
var tagName = Element._safeTagName(element);
|
||||
if (allowedUriAttributes.contains('$tagName::$attributeName')) {
|
||||
return uriPolicy.allowsUri(value);
|
||||
return uriPolicy!.allowsUri(value);
|
||||
} else if (allowedUriAttributes.contains('*::$attributeName')) {
|
||||
return uriPolicy.allowsUri(value);
|
||||
return uriPolicy!.allowsUri(value);
|
||||
} else if (allowedAttributes.contains('$tagName::$attributeName')) {
|
||||
return true;
|
||||
} else if (allowedAttributes.contains('*::$attributeName')) {
|
||||
@@ -356,8 +356,8 @@ class _CustomElementNodeValidator extends _SimpleNodeValidator {
|
||||
_CustomElementNodeValidator(
|
||||
UriPolicy uriPolicy,
|
||||
Iterable<String> allowedElements,
|
||||
Iterable<String> allowedAttributes,
|
||||
Iterable<String> allowedUriAttributes,
|
||||
Iterable<String>? allowedAttributes,
|
||||
Iterable<String>? allowedUriAttributes,
|
||||
bool allowTypeExtension,
|
||||
bool allowCustomTag)
|
||||
: this.allowTypeExtension = allowTypeExtension == true,
|
||||
|
||||
@@ -19,7 +19,7 @@ abstract class NodeValidator {
|
||||
*
|
||||
* If a uriPolicy is not specified then the default uriPolicy will be used.
|
||||
*/
|
||||
factory NodeValidator({UriPolicy uriPolicy}) =>
|
||||
factory NodeValidator({UriPolicy? uriPolicy}) =>
|
||||
new _Html5NodeValidator(uriPolicy: uriPolicy);
|
||||
|
||||
factory NodeValidator.throws(NodeValidator base) =>
|
||||
@@ -163,12 +163,12 @@ class _ValidatingTreeSanitizer implements NodeTreeSanitizer {
|
||||
_ValidatingTreeSanitizer(this.validator) {}
|
||||
|
||||
void sanitizeTree(Node node) {
|
||||
void walk(Node node, Node parent) {
|
||||
void walk(Node node, Node? parent) {
|
||||
sanitizeNode(node, parent);
|
||||
|
||||
var child = node.lastChild;
|
||||
while (null != child) {
|
||||
Node nextChild;
|
||||
Node? nextChild;
|
||||
try {
|
||||
// Child may be removed during the walk, and we may not even be able
|
||||
// to get its previousNode. But it's also possible that previousNode
|
||||
@@ -199,7 +199,7 @@ class _ValidatingTreeSanitizer implements NodeTreeSanitizer {
|
||||
}
|
||||
|
||||
/// Aggressively try to remove node.
|
||||
void _removeNode(Node node, Node parent) {
|
||||
void _removeNode(Node node, Node? parent) {
|
||||
// If we have the parent, it's presumably already passed more sanitization
|
||||
// or is the fragment, so ask it to remove the child. And if that fails
|
||||
// try to set the outer html.
|
||||
@@ -212,7 +212,7 @@ class _ValidatingTreeSanitizer implements NodeTreeSanitizer {
|
||||
}
|
||||
|
||||
/// Sanitize the element, assuming we can't trust anything about it.
|
||||
void _sanitizeUntrustedElement(/* Element */ element, Node parent) {
|
||||
void _sanitizeUntrustedElement(/* Element */ element, Node? parent) {
|
||||
// If the _hasCorruptedAttributes does not successfully return false,
|
||||
// then we consider it corrupted and remove.
|
||||
// TODO(alanknight): This is a workaround because on Firefox
|
||||
@@ -261,8 +261,8 @@ class _ValidatingTreeSanitizer implements NodeTreeSanitizer {
|
||||
/// Having done basic sanity checking on the element, and computed the
|
||||
/// important attributes we want to check, remove it if it's not valid
|
||||
/// or not allowed, either as a whole or particular attributes.
|
||||
void _sanitizeElement(Element element, Node parent, bool corrupted,
|
||||
String text, String tag, Map attrs, String isAttr) {
|
||||
void _sanitizeElement(Element element, Node? parent, bool corrupted,
|
||||
String text, String tag, Map attrs, String? isAttr) {
|
||||
if (false != corrupted) {
|
||||
_removeNode(element, parent);
|
||||
window.console
|
||||
@@ -304,7 +304,7 @@ class _ValidatingTreeSanitizer implements NodeTreeSanitizer {
|
||||
}
|
||||
|
||||
/// Sanitize the node and its children recursively.
|
||||
void sanitizeNode(Node node, Node parent) {
|
||||
void sanitizeNode(Node node, Node? parent) {
|
||||
switch (node.nodeType) {
|
||||
case Node.ELEMENT_NODE:
|
||||
_sanitizeUntrustedElement(node, parent);
|
||||
|
||||
@@ -26,7 +26,7 @@ class _WrappedList<E extends Node> extends ListBase<E>
|
||||
_list.add(element);
|
||||
}
|
||||
|
||||
bool remove(Object element) => _list.remove(element);
|
||||
bool remove(Object? element) => _list.remove(element);
|
||||
|
||||
void clear() {
|
||||
_list.clear();
|
||||
@@ -34,7 +34,7 @@ class _WrappedList<E extends Node> extends ListBase<E>
|
||||
|
||||
// List APIs
|
||||
|
||||
E operator [](int index) => _list[index];
|
||||
E operator [](int index) => _list[index] as E;
|
||||
|
||||
void operator []=(int index, E value) {
|
||||
_list[index] = value;
|
||||
@@ -44,19 +44,23 @@ class _WrappedList<E extends Node> extends ListBase<E>
|
||||
_list.length = newLength;
|
||||
}
|
||||
|
||||
void sort([int compare(E a, E b)]) {
|
||||
// Implicit downcast on argument from Node to E-extends-Node.
|
||||
_list.sort((Node a, Node b) => compare(a, b));
|
||||
void sort([int compare(E a, E b)?]) {
|
||||
if (compare == null) {
|
||||
_list.sort();
|
||||
} else {
|
||||
_list.sort((Node a, Node b) => compare(a as E, b as E));
|
||||
}
|
||||
}
|
||||
|
||||
int indexOf(Object element, [int start = 0]) => _list.indexOf(element, start);
|
||||
int indexOf(Object? element, [int start = 0]) =>
|
||||
_list.indexOf(element as Node, start);
|
||||
|
||||
int lastIndexOf(Object element, [int start]) =>
|
||||
_list.lastIndexOf(element, start);
|
||||
int lastIndexOf(Object? element, [int? start]) =>
|
||||
_list.lastIndexOf(element as Node, start);
|
||||
|
||||
void insert(int index, E element) => _list.insert(index, element);
|
||||
|
||||
E removeAt(int index) => _list.removeAt(index);
|
||||
E removeAt(int index) => _list.removeAt(index) as E;
|
||||
|
||||
void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
|
||||
_list.setRange(start, end, iterable, skipCount);
|
||||
@@ -70,7 +74,7 @@ class _WrappedList<E extends Node> extends ListBase<E>
|
||||
_list.replaceRange(start, end, iterable);
|
||||
}
|
||||
|
||||
void fillRange(int start, int end, [E fillValue]) {
|
||||
void fillRange(int start, int end, [E? fillValue]) {
|
||||
_list.fillRange(start, end, fillValue);
|
||||
}
|
||||
|
||||
@@ -89,5 +93,5 @@ class _WrappedIterator<E extends Node> implements Iterator<E> {
|
||||
return _iterator.moveNext();
|
||||
}
|
||||
|
||||
E get current => _iterator.current;
|
||||
E get current => _iterator.current as E;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ class FixedSizeListIterator<T> implements Iterator<T> {
|
||||
final List<T> _array;
|
||||
final int _length; // Cache array length for faster access.
|
||||
int _position;
|
||||
T _current;
|
||||
T? _current;
|
||||
|
||||
FixedSizeListIterator(List<T> array)
|
||||
: _array = array,
|
||||
@@ -28,14 +28,14 @@ class FixedSizeListIterator<T> implements Iterator<T> {
|
||||
return false;
|
||||
}
|
||||
|
||||
T get current => _current;
|
||||
T get current => _current as T;
|
||||
}
|
||||
|
||||
// Iterator for arrays with variable size.
|
||||
class _VariableSizeListIterator<T> implements Iterator<T> {
|
||||
final List<T> _array;
|
||||
int _position;
|
||||
T _current;
|
||||
T? _current;
|
||||
|
||||
_VariableSizeListIterator(List<T> array)
|
||||
: _array = array,
|
||||
@@ -53,5 +53,5 @@ class _VariableSizeListIterator<T> implements Iterator<T> {
|
||||
return false;
|
||||
}
|
||||
|
||||
T get current => _current;
|
||||
T get current => _current as T;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ class Console {
|
||||
|
||||
bool get _isConsoleDefined => JS('bool', 'typeof console != "undefined"');
|
||||
|
||||
MemoryInfo get memory =>
|
||||
MemoryInfo? get memory =>
|
||||
_isConsoleDefined ? JS('MemoryInfo', 'window.console.memory') : null;
|
||||
|
||||
void assertCondition(bool condition, Object arg) => _isConsoleDefined
|
||||
|
||||
@@ -10,12 +10,12 @@
|
||||
|
||||
part of html;
|
||||
|
||||
WindowBase _convertNativeToDart_Window(win) {
|
||||
WindowBase? _convertNativeToDart_Window(win) {
|
||||
if (win == null) return null;
|
||||
return _DOMWindowCrossFrame._createSafe(win);
|
||||
}
|
||||
|
||||
EventTarget _convertNativeToDart_EventTarget(e) {
|
||||
EventTarget? _convertNativeToDart_EventTarget(e) {
|
||||
if (e == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -33,7 +33,7 @@ EventTarget _convertNativeToDart_EventTarget(e) {
|
||||
return e;
|
||||
}
|
||||
|
||||
EventTarget _convertDartToNative_EventTarget(e) {
|
||||
EventTarget? _convertDartToNative_EventTarget(e) {
|
||||
if (e is _DOMWindowCrossFrame) {
|
||||
return e._window;
|
||||
} else {
|
||||
|
||||
@@ -54,7 +54,7 @@ class _MultiElementCssClassSet extends CssClassSetImpl {
|
||||
* TODO(sra): It seems wrong to collect a 'changed' flag like this when the
|
||||
* underlying toggle returns an 'is set' flag.
|
||||
*/
|
||||
bool toggle(String value, [bool shouldAdd]) => _sets.fold(
|
||||
bool toggle(String value, [bool? shouldAdd]) => _sets.fold(
|
||||
false,
|
||||
(bool changed, CssClassSetImpl e) =>
|
||||
e.toggle(value, shouldAdd) || changed);
|
||||
@@ -66,7 +66,7 @@ class _MultiElementCssClassSet extends CssClassSetImpl {
|
||||
* This is the Dart equivalent of jQuery's
|
||||
* [removeClass](http://api.jquery.com/removeClass/).
|
||||
*/
|
||||
bool remove(Object value) => _sets.fold(
|
||||
bool remove(Object? value) => _sets.fold(
|
||||
false, (bool changed, CssClassSetImpl e) => e.remove(value) || changed);
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ class _ElementCssClassSet extends CssClassSetImpl {
|
||||
_element.className = '';
|
||||
}
|
||||
|
||||
bool contains(Object value) {
|
||||
bool contains(Object? value) {
|
||||
return _contains(_element, value);
|
||||
}
|
||||
|
||||
@@ -108,11 +108,11 @@ class _ElementCssClassSet extends CssClassSetImpl {
|
||||
return _add(_element, value);
|
||||
}
|
||||
|
||||
bool remove(Object value) {
|
||||
bool remove(Object? value) {
|
||||
return value is String && _remove(_element, value);
|
||||
}
|
||||
|
||||
bool toggle(String value, [bool shouldAdd]) {
|
||||
bool toggle(String value, [bool? shouldAdd]) {
|
||||
return _toggle(_element, value, shouldAdd);
|
||||
}
|
||||
|
||||
@@ -120,11 +120,11 @@ class _ElementCssClassSet extends CssClassSetImpl {
|
||||
_addAll(_element, iterable);
|
||||
}
|
||||
|
||||
void removeAll(Iterable<Object> iterable) {
|
||||
void removeAll(Iterable<Object?> iterable) {
|
||||
_removeAll(_element, iterable);
|
||||
}
|
||||
|
||||
void retainAll(Iterable<Object> iterable) {
|
||||
void retainAll(Iterable<Object?> iterable) {
|
||||
_removeWhere(_element, iterable.toSet().contains, false);
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ class _ElementCssClassSet extends CssClassSetImpl {
|
||||
_removeWhere(_element, test, false);
|
||||
}
|
||||
|
||||
static bool _contains(Element _element, Object value) {
|
||||
static bool _contains(Element _element, Object? value) {
|
||||
return value is String && _classListContains(_classListOf(_element), value);
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ class _ElementCssClassSet extends CssClassSetImpl {
|
||||
return removed;
|
||||
}
|
||||
|
||||
static bool _toggle(Element _element, String value, bool shouldAdd) {
|
||||
static bool _toggle(Element _element, String value, bool? shouldAdd) {
|
||||
// There is no value that can be passed as the second argument of
|
||||
// DomTokenList.toggle that behaves the same as passing one argument.
|
||||
// `null` is seen as false, meaning 'remove'.
|
||||
@@ -171,13 +171,13 @@ class _ElementCssClassSet extends CssClassSetImpl {
|
||||
return _classListToggle1(list, value);
|
||||
}
|
||||
|
||||
static bool _toggleOnOff(Element _element, String value, bool shouldAdd) {
|
||||
static bool _toggleOnOff(Element _element, String value, bool? shouldAdd) {
|
||||
DomTokenList list = _classListOf(_element);
|
||||
// IE's toggle does not take a second parameter. We would prefer:
|
||||
//
|
||||
// return _classListToggle2(list, value, shouldAdd);
|
||||
//
|
||||
if (shouldAdd) {
|
||||
if (shouldAdd ?? false) {
|
||||
_classListAdd(list, value);
|
||||
return true;
|
||||
} else {
|
||||
@@ -193,10 +193,10 @@ class _ElementCssClassSet extends CssClassSetImpl {
|
||||
}
|
||||
}
|
||||
|
||||
static void _removeAll(Element _element, Iterable<Object> iterable) {
|
||||
static void _removeAll(Element _element, Iterable<Object?> iterable) {
|
||||
DomTokenList list = _classListOf(_element);
|
||||
for (String value in iterable) {
|
||||
_classListRemove(list, value);
|
||||
for (Object? value in iterable) {
|
||||
_classListRemove(list, value as String);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ class _ElementCssClassSet extends CssClassSetImpl {
|
||||
DomTokenList list = _classListOf(_element);
|
||||
int i = 0;
|
||||
while (i < _classListLength(list)) {
|
||||
String item = list.item(i);
|
||||
String item = list.item(i)!;
|
||||
if (doRemove == test(item)) {
|
||||
_classListRemove(list, item);
|
||||
} else {
|
||||
@@ -254,7 +254,7 @@ class _ElementCssClassSet extends CssClassSetImpl {
|
||||
}
|
||||
|
||||
static bool _classListToggle2(
|
||||
DomTokenList list, String value, bool shouldAdd) {
|
||||
DomTokenList list, String value, bool? shouldAdd) {
|
||||
return JS('bool', '#.toggle(#, #)', list, value, shouldAdd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ void _checkExtendsNativeClassOrTemplate(
|
||||
}
|
||||
}
|
||||
|
||||
Function _registerCustomElement(context, document, String tag, [Map options]) {
|
||||
Function _registerCustomElement(context, document, String tag, [Map? options]) {
|
||||
// Function follows the same pattern as the following JavaScript code for
|
||||
// registering a custom element.
|
||||
//
|
||||
@@ -82,7 +82,7 @@ Function _registerCustomElement(context, document, String tag, [Map options]) {
|
||||
// var e = document.createElement('x-foo');
|
||||
|
||||
var extendsTagName = '';
|
||||
Type type;
|
||||
Type? type;
|
||||
if (options != null) {
|
||||
extendsTagName = options['extends'];
|
||||
type = options['prototype'];
|
||||
@@ -162,7 +162,7 @@ class _JSElementUpgrader implements ElementUpgrader {
|
||||
var _constructor;
|
||||
var _nativeType;
|
||||
|
||||
_JSElementUpgrader(Document document, Type type, String extendsTag) {
|
||||
_JSElementUpgrader(Document document, Type type, String? extendsTag) {
|
||||
var interceptorClass = findInterceptorConstructorForType(type);
|
||||
if (interceptorClass == null) {
|
||||
throw new ArgumentError(type);
|
||||
|
||||
@@ -14,8 +14,8 @@ class _DOMWindowCrossFrame implements WindowBase {
|
||||
// Fields.
|
||||
HistoryBase get history =>
|
||||
_HistoryCrossFrame._createSafe(JS('HistoryBase', '#.history', _window));
|
||||
LocationBase get location => _LocationCrossFrame
|
||||
._createSafe(JS('LocationBase', '#.location', _window));
|
||||
LocationBase get location => _LocationCrossFrame._createSafe(
|
||||
JS('LocationBase', '#.location', _window));
|
||||
|
||||
// TODO(vsm): Add frames to navigate subframes. See 2312.
|
||||
|
||||
@@ -30,8 +30,7 @@ class _DOMWindowCrossFrame implements WindowBase {
|
||||
// Methods.
|
||||
void close() => JS('void', '#.close()', _window);
|
||||
|
||||
void postMessage(var message, String targetOrigin,
|
||||
[List messagePorts = null]) {
|
||||
void postMessage(var message, String targetOrigin, [List? messagePorts]) {
|
||||
if (messagePorts == null) {
|
||||
JS('void', '#.postMessage(#,#)', _window,
|
||||
convertDartToNative_SerializedScriptValue(message), targetOrigin);
|
||||
@@ -63,26 +62,26 @@ class _DOMWindowCrossFrame implements WindowBase {
|
||||
Events get on => throw new UnsupportedError(
|
||||
'You can only attach EventListeners to your own window.');
|
||||
// TODO(efortuna): Remove this method. dartbug.com/16814
|
||||
void _addEventListener(String type, EventListener listener,
|
||||
[bool useCapture]) =>
|
||||
void _addEventListener(String? type, EventListener? listener,
|
||||
[bool? useCapture]) =>
|
||||
throw new UnsupportedError(
|
||||
'You can only attach EventListeners to your own window.');
|
||||
// TODO(efortuna): Remove this method. dartbug.com/16814
|
||||
void addEventListener(String type, EventListener listener,
|
||||
[bool useCapture]) =>
|
||||
void addEventListener(String type, EventListener? listener,
|
||||
[bool? useCapture]) =>
|
||||
throw new UnsupportedError(
|
||||
'You can only attach EventListeners to your own window.');
|
||||
// TODO(efortuna): Remove this method. dartbug.com/16814
|
||||
bool dispatchEvent(Event event) => throw new UnsupportedError(
|
||||
'You can only attach EventListeners to your own window.');
|
||||
// TODO(efortuna): Remove this method. dartbug.com/16814
|
||||
void _removeEventListener(String type, EventListener listener,
|
||||
[bool useCapture]) =>
|
||||
void _removeEventListener(String? type, EventListener? listener,
|
||||
[bool? useCapture]) =>
|
||||
throw new UnsupportedError(
|
||||
'You can only attach EventListeners to your own window.');
|
||||
// TODO(efortuna): Remove this method. dartbug.com/16814
|
||||
void removeEventListener(String type, EventListener listener,
|
||||
[bool useCapture]) =>
|
||||
void removeEventListener(String type, EventListener? listener,
|
||||
[bool? useCapture]) =>
|
||||
throw new UnsupportedError(
|
||||
'You can only attach EventListeners to your own window.');
|
||||
}
|
||||
|
||||
@@ -60,9 +60,10 @@ class KeyEvent extends _WrappedEvent implements KeyboardEvent {
|
||||
bool get _realAltKey => JS('bool', '#.altKey', _parent);
|
||||
|
||||
/** Shadows on top of the parent's currentTarget. */
|
||||
EventTarget _currentTarget;
|
||||
EventTarget? _currentTarget;
|
||||
|
||||
final InputDeviceCapabilities sourceCapabilities;
|
||||
InputDeviceCapabilities? get sourceCapabilities =>
|
||||
JS('InputDeviceCapabilities', '#.sourceCapabilities', this);
|
||||
|
||||
/**
|
||||
* The value we want to use for this object's dispatch. Created here so it is
|
||||
@@ -77,7 +78,12 @@ class KeyEvent extends _WrappedEvent implements KeyboardEvent {
|
||||
}
|
||||
|
||||
/** Construct a KeyEvent with [parent] as the event we're emulating. */
|
||||
KeyEvent.wrap(KeyboardEvent parent) : super(parent) {
|
||||
KeyEvent.wrap(KeyboardEvent parent)
|
||||
: _parent = parent,
|
||||
_shadowAltKey = false,
|
||||
_shadowCharCode = 0,
|
||||
_shadowKeyCode = 0,
|
||||
super(parent) {
|
||||
_parent = parent;
|
||||
_shadowAltKey = _realAltKey;
|
||||
_shadowCharCode = _realCharCode;
|
||||
@@ -87,7 +93,7 @@ class KeyEvent extends _WrappedEvent implements KeyboardEvent {
|
||||
|
||||
/** Programmatically create a new KeyEvent (and KeyboardEvent). */
|
||||
factory KeyEvent(String type,
|
||||
{Window view,
|
||||
{Window? view,
|
||||
bool canBubble: true,
|
||||
bool cancelable: true,
|
||||
int keyCode: 0,
|
||||
@@ -97,12 +103,12 @@ class KeyEvent extends _WrappedEvent implements KeyboardEvent {
|
||||
bool altKey: false,
|
||||
bool shiftKey: false,
|
||||
bool metaKey: false,
|
||||
EventTarget currentTarget}) {
|
||||
EventTarget? currentTarget}) {
|
||||
if (view == null) {
|
||||
view = window;
|
||||
}
|
||||
|
||||
var eventObj;
|
||||
dynamic eventObj;
|
||||
|
||||
// Currently this works on everything but Safari. Safari throws an
|
||||
// "Attempting to change access mechanism for an unconfigurable property"
|
||||
@@ -119,17 +125,17 @@ class KeyEvent extends _WrappedEvent implements KeyboardEvent {
|
||||
JS(
|
||||
'void',
|
||||
"Object.defineProperty(#, 'keyCode', {"
|
||||
" get : function() { return this.keyCodeVal; } })",
|
||||
" get : function() { return this.keyCodeVal; } })",
|
||||
eventObj);
|
||||
JS(
|
||||
'void',
|
||||
"Object.defineProperty(#, 'which', {"
|
||||
" get : function() { return this.keyCodeVal; } })",
|
||||
" get : function() { return this.keyCodeVal; } })",
|
||||
eventObj);
|
||||
JS(
|
||||
'void',
|
||||
"Object.defineProperty(#, 'charCode', {"
|
||||
" get : function() { return this.charCodeVal; } })",
|
||||
" get : function() { return this.charCodeVal; } })",
|
||||
eventObj);
|
||||
|
||||
var keyIdentifier = _convertToHexString(charCode, keyCode);
|
||||
@@ -152,10 +158,10 @@ class KeyEvent extends _WrappedEvent implements KeyboardEvent {
|
||||
static bool get canUseDispatchEvent => JS(
|
||||
'bool',
|
||||
'(typeof document.body.dispatchEvent == "function")'
|
||||
'&& document.body.dispatchEvent.length > 0');
|
||||
'&& document.body.dispatchEvent.length > 0');
|
||||
|
||||
/** The currently registered target for this event. */
|
||||
EventTarget get currentTarget => _currentTarget;
|
||||
EventTarget? get currentTarget => _currentTarget;
|
||||
|
||||
// This is an experimental method to be sure.
|
||||
static String _convertToHexString(int charCode, int keyCode) {
|
||||
@@ -198,9 +204,9 @@ class KeyEvent extends _WrappedEvent implements KeyboardEvent {
|
||||
bool get metaKey => _parent.metaKey;
|
||||
/** True if the shift key was pressed during this event. */
|
||||
bool get shiftKey => _parent.shiftKey;
|
||||
Window get view => _parent.view;
|
||||
WindowBase? get view => _parent.view;
|
||||
void _initUIEvent(
|
||||
String type, bool canBubble, bool cancelable, Window view, int detail) {
|
||||
String type, bool canBubble, bool cancelable, Window? view, int detail) {
|
||||
throw new UnsupportedError("Cannot initialize a UI Event from a KeyEvent.");
|
||||
}
|
||||
|
||||
@@ -218,9 +224,9 @@ class KeyEvent extends _WrappedEvent implements KeyboardEvent {
|
||||
String type,
|
||||
bool canBubble,
|
||||
bool cancelable,
|
||||
Window view,
|
||||
Window? view,
|
||||
String keyIdentifier,
|
||||
int location,
|
||||
int? location,
|
||||
bool ctrlKey,
|
||||
bool altKey,
|
||||
bool shiftKey,
|
||||
|
||||
@@ -10,7 +10,7 @@ class Platform {
|
||||
* browser. If false, using these types will generate a runtime
|
||||
* error.
|
||||
*/
|
||||
static final supportsTypedData = JS('bool', '!!(window.ArrayBuffer)');
|
||||
static final bool supportsTypedData = JS('bool', '!!(window.ArrayBuffer)');
|
||||
|
||||
/**
|
||||
* Returns true if SIMD types in dart:typed_data types are supported
|
||||
|
||||
@@ -11,7 +11,7 @@ class _WrappedEvent implements Event {
|
||||
final Event wrapped;
|
||||
|
||||
/** The CSS selector involved with event delegation. */
|
||||
String _selector;
|
||||
String? _selector;
|
||||
|
||||
_WrappedEvent(this.wrapped);
|
||||
|
||||
@@ -21,7 +21,7 @@ class _WrappedEvent implements Event {
|
||||
|
||||
bool get composed => wrapped.composed;
|
||||
|
||||
EventTarget get currentTarget => wrapped.currentTarget;
|
||||
EventTarget? get currentTarget => wrapped.currentTarget;
|
||||
|
||||
bool get defaultPrevented => wrapped.defaultPrevented;
|
||||
|
||||
@@ -29,13 +29,13 @@ class _WrappedEvent implements Event {
|
||||
|
||||
bool get isTrusted => wrapped.isTrusted;
|
||||
|
||||
EventTarget get target => wrapped.target;
|
||||
EventTarget? get target => wrapped.target;
|
||||
|
||||
double get timeStamp => wrapped.timeStamp;
|
||||
double get timeStamp => wrapped.timeStamp as double;
|
||||
|
||||
String get type => wrapped.type;
|
||||
|
||||
void _initEvent(String type, [bool bubbles, bool cancelable]) {
|
||||
void _initEvent(String type, [bool? bubbles, bool? cancelable]) {
|
||||
throw new UnsupportedError('Cannot initialize this Event.');
|
||||
}
|
||||
|
||||
@@ -63,13 +63,12 @@ class _WrappedEvent implements Event {
|
||||
throw new UnsupportedError('Cannot call matchingTarget if this Event did'
|
||||
' not arise as a result of event delegation.');
|
||||
}
|
||||
Element currentTarget = this.currentTarget;
|
||||
Element target = this.target;
|
||||
var matchedTarget;
|
||||
Element? currentTarget = this.currentTarget as Element?;
|
||||
Element? target = this.target as Element?;
|
||||
do {
|
||||
if (target.matches(_selector)) return target;
|
||||
if (target!.matches(_selector!)) return target;
|
||||
target = target.parent;
|
||||
} while (target != null && target != currentTarget.parent);
|
||||
} while (target != null && target != currentTarget!.parent);
|
||||
throw new StateError('No selector matched for populating matchedTarget.');
|
||||
}
|
||||
|
||||
@@ -83,7 +82,7 @@ class _WrappedEvent implements Event {
|
||||
* from W3C.
|
||||
*/
|
||||
// https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#extensions-to-event
|
||||
List<Node> get path => wrapped.path;
|
||||
List<Node> get path => wrapped.path as List<Node>;
|
||||
|
||||
dynamic get _get_currentTarget => wrapped._get_currentTarget;
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ class _LibraryManager {
|
||||
return matches.toList();
|
||||
}
|
||||
|
||||
static setLibrary([String name]) {
|
||||
static setLibrary([String? name]) {
|
||||
// Bust cache in case library list has changed. Ideally we would listen for
|
||||
// when libraries are loaded and invalidate based on that.
|
||||
_validCache = false;
|
||||
@@ -1084,16 +1084,16 @@ class _DOMWindowCrossFrame extends DartHtmlDomObject implements WindowBase {
|
||||
var history = _blink.BlinkWindow.instance.history_Getter_(this);
|
||||
return history is _HistoryCrossFrame
|
||||
? history
|
||||
: _blink.Blink_Utils
|
||||
.setInstanceInterceptor(history, _HistoryCrossFrame);
|
||||
: _blink.Blink_Utils.setInstanceInterceptor(
|
||||
history, _HistoryCrossFrame);
|
||||
}
|
||||
|
||||
LocationBase get location {
|
||||
var location = _blink.BlinkWindow.instance.location_Getter_(this);
|
||||
return location is _LocationCrossFrame
|
||||
? location
|
||||
: _blink.Blink_Utils
|
||||
.setInstanceInterceptor(location, _LocationCrossFrame);
|
||||
: _blink.Blink_Utils.setInstanceInterceptor(
|
||||
location, _LocationCrossFrame);
|
||||
}
|
||||
|
||||
bool get closed => _blink.BlinkWindow.instance.closed_Getter_(this);
|
||||
@@ -1107,7 +1107,7 @@ class _DOMWindowCrossFrame extends DartHtmlDomObject implements WindowBase {
|
||||
// Methods.
|
||||
void close() => _blink.BlinkWindow.instance.close_Callback_0_(this);
|
||||
void postMessage(Object message, String targetOrigin,
|
||||
[List<MessagePort> transfer]) =>
|
||||
[List<MessagePort>? transfer]) =>
|
||||
_blink.BlinkWindow.instance.postMessage_Callback_3_(
|
||||
this,
|
||||
convertDartToNative_SerializedScriptValue(message),
|
||||
@@ -1122,12 +1122,12 @@ class _DOMWindowCrossFrame extends DartHtmlDomObject implements WindowBase {
|
||||
'You can only attach EventListeners to your own window.');
|
||||
// TODO(efortuna): Remove this method. dartbug.com/16814
|
||||
void _addEventListener(
|
||||
[String type, EventListener listener, bool useCapture]) =>
|
||||
[String? type, EventListener? listener, bool? useCapture]) =>
|
||||
throw new UnsupportedError(
|
||||
'You can only attach EventListeners to your own window.');
|
||||
// TODO(efortuna): Remove this method. dartbug.com/16814
|
||||
void addEventListener(String type, EventListener listener,
|
||||
[bool useCapture]) =>
|
||||
void addEventListener(String type, EventListener? listener,
|
||||
[bool? useCapture]) =>
|
||||
throw new UnsupportedError(
|
||||
'You can only attach EventListeners to your own window.');
|
||||
// TODO(efortuna): Remove this method. dartbug.com/16814
|
||||
@@ -1135,12 +1135,12 @@ class _DOMWindowCrossFrame extends DartHtmlDomObject implements WindowBase {
|
||||
'You can only attach EventListeners to your own window.');
|
||||
// TODO(efortuna): Remove this method. dartbug.com/16814
|
||||
void _removeEventListener(
|
||||
[String type, EventListener listener, bool useCapture]) =>
|
||||
[String? type, EventListener? listener, bool? useCapture]) =>
|
||||
throw new UnsupportedError(
|
||||
'You can only attach EventListeners to your own window.');
|
||||
// TODO(efortuna): Remove this method. dartbug.com/16814
|
||||
void removeEventListener(String type, EventListener listener,
|
||||
[bool useCapture]) =>
|
||||
void removeEventListener(String type, EventListener? listener,
|
||||
[bool? useCapture]) =>
|
||||
throw new UnsupportedError(
|
||||
'You can only attach EventListeners to your own window.');
|
||||
}
|
||||
@@ -1151,7 +1151,7 @@ class _HistoryCrossFrame extends DartHtmlDomObject implements HistoryBase {
|
||||
// Methods.
|
||||
void back() => _blink.BlinkHistory.instance.back_Callback_0_(this);
|
||||
void forward() => _blink.BlinkHistory.instance.forward_Callback_0_(this);
|
||||
void go([int delta]) {
|
||||
void go([int? delta]) {
|
||||
if (delta != null) {
|
||||
_blink.BlinkHistory.instance.go_Callback_1_(this, delta);
|
||||
return;
|
||||
|
||||
@@ -8,6 +8,6 @@ class _SvgElementFactoryProvider {
|
||||
static SvgElement createSvgElement_tag(String tag) {
|
||||
final Element temp =
|
||||
document.createElementNS("http://www.w3.org/2000/svg", tag);
|
||||
return temp;
|
||||
return temp as SvgElement;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,14 +4,15 @@
|
||||
|
||||
part of dart.dom.html;
|
||||
|
||||
void Function(T) _wrapZone<T>(void Function(T) callback) {
|
||||
void Function(T)? _wrapZone<T>(void Function(T)? callback) {
|
||||
// For performance reasons avoid wrapping if we are in the root zone.
|
||||
if (Zone.current == Zone.root) return callback;
|
||||
if (callback == null) return null;
|
||||
return Zone.current.bindUnaryCallbackGuarded(callback);
|
||||
}
|
||||
|
||||
void Function(T1, T2) _wrapBinaryZone<T1, T2>(void Function(T1, T2) callback) {
|
||||
void Function(T1, T2)? _wrapBinaryZone<T1, T2>(
|
||||
void Function(T1, T2)? callback) {
|
||||
// For performance reasons avoid wrapping if we are in the root zone.
|
||||
if (Zone.current == Zone.root) return callback;
|
||||
if (callback == null) return null;
|
||||
@@ -35,7 +36,7 @@ void Function(T1, T2) _wrapBinaryZone<T1, T2>(void Function(T1, T2) callback) {
|
||||
* For details about CSS selector syntax, see the
|
||||
* [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
|
||||
*/
|
||||
Element querySelector(String selectors) => document.querySelector(selectors);
|
||||
Element? querySelector(String selectors) => document.querySelector(selectors);
|
||||
|
||||
/**
|
||||
* Finds all descendant elements of this document that match the specified
|
||||
|
||||
Reference in New Issue
Block a user