Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(275)

Unified Diff: sdk/lib/html/dartium/html_dartium.dart

Issue 1894713002: Strong html (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: ptal Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
Download patch
« no previous file with comments | « sdk/lib/html/dart2js/html_dart2js.dart ('k') | sdk/lib/html/html_common/css_class_set.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sdk/lib/html/dartium/html_dartium.dart
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index e7587818a025e7a311b351dc0ce6dcfb3466e925..acdbbdb62e6c65d6fba55dae8505fabc52287079 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -805,12 +805,12 @@ abstract class AbstractWorker extends DartHtmlDomObject implements EventTarget {
*/
@DomName('AbstractWorker.errorEvent')
@DocsEditable()
- static const EventStreamProvider<ErrorEvent> errorEvent = const EventStreamProvider<ErrorEvent>('error');
+ static const EventStreamProvider<Event> errorEvent = const EventStreamProvider<Event>('error');
/// Stream of `error` events handled by this [AbstractWorker].
@DomName('AbstractWorker.onerror')
@DocsEditable()
- Stream<ErrorEvent> get onError => errorEvent.forTarget(this);
+ Stream<Event> get onError => errorEvent.forTarget(this);
}
// 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
@@ -4591,7 +4591,7 @@ class CompositorWorker extends EventTarget implements AbstractWorker {
@DomName('CompositorWorker.errorEvent')
@DocsEditable()
@Experimental() // untriaged
- static const EventStreamProvider<ErrorEvent> errorEvent = const EventStreamProvider<ErrorEvent>('error');
+ static const EventStreamProvider<Event> errorEvent = const EventStreamProvider<Event>('error');
@DomName('CompositorWorker.messageEvent')
@DocsEditable()
@@ -4629,7 +4629,7 @@ class CompositorWorker extends EventTarget implements AbstractWorker {
@DomName('CompositorWorker.onerror')
@DocsEditable()
@Experimental() // untriaged
- Stream<ErrorEvent> get onError => errorEvent.forTarget(this);
+ Stream<Event> get onError => errorEvent.forTarget(this);
@DomName('CompositorWorker.onmessage')
@DocsEditable()
@@ -10323,7 +10323,7 @@ class Document extends Node
@DomName('Document.visibilityState')
@DocsEditable()
@Experimental() // untriaged
- String get visibilityState => _blink.BlinkDocument.instance.visibilityState_Getter_(this);
+ String get _visibilityState => _blink.BlinkDocument.instance.visibilityState_Getter_(this);
@DomName('Document.webkitFullscreenElement')
@DocsEditable()
@@ -10985,6 +10985,13 @@ class Document extends Node
_blink.BlinkDocument.instance.createElementNS_Callback_3_(this, namespaceURI, qualifiedName, typeExtension);
}
+
+ @DomName('Document.visibilityState')
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.FIREFOX)
+ @SupportedBrowser(SupportedBrowser.IE, '10')
+ @Experimental()
+ String get visibilityState => _visibilityState;
}
// 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
@@ -11023,7 +11030,7 @@ class DocumentFragment extends Node implements NonElementParentNode, ParentNode
set children(List<Element> value) {
// Copy list first since we don't want liveness during iteration.
- List copy = new List.from(value);
+ var copy = value.toList();
var children = this.children;
children.clear();
children.addAll(copy);
@@ -12480,7 +12487,7 @@ class _ChildrenElementList extends ListBase<Element>
_filter(test, true);
}
- void _filter(bool test(var element), bool retainMatching) {
+ void _filter(bool test(Element element), bool retainMatching) {
var removed;
if (retainMatching) {
removed = _element.children.where((e) => !test(e));
@@ -13926,7 +13933,7 @@ class Element extends Node implements NonDocumentTypeChildNode, GlobalEventHandl
set children(List<Element> value) {
// Copy list first since we don't want liveness during iteration.
- List copy = new List.from(value);
+ var copy = value.toList();
var children = this.children;
children.clear();
children.addAll(copy);
@@ -14161,15 +14168,14 @@ class Element extends Node implements NonDocumentTypeChildNode, GlobalEventHandl
throw new ArgumentError("The frames parameter should be a List of Maps "
"with frame information");
}
- var convertedFrames = frames;
- if (convertedFrames is Iterable) {
+ var convertedFrames;
+ if (frames is Iterable) {
convertedFrames = convertDartToNative_List(
frames.map(convertDartToNative_Dictionary).toList());
+ } else {
+ convertedFrames = frames;
}
- var convertedTiming = timing;
- if (convertedTiming is Map) {
- convertedTiming = convertDartToNative_Dictionary(convertedTiming);
- }
+ var convertedTiming = timing is Map ? convertDartToNative_Dictionary(timing) : timing;
return convertedTiming == null
? _animate(convertedFrames)
: _animate(convertedFrames, convertedTiming);
@@ -18704,7 +18710,10 @@ class Geolocation extends DartHtmlDomObject {
}
int watchId;
- var controller;
+ // TODO(jacobr): it seems like a bug that we have to specifiy the static
+ // type here for controller.stream to have the right type.
+ // dartbug.com/26278
+ StreamController<Geoposition> controller;
controller = new StreamController<Geoposition>(sync: true,
onListen: () {
assert(watchId == null);
@@ -19755,11 +19764,11 @@ class HtmlCollection extends DartHtmlDomObject with ListMixin<Node>, ImmutableLi
@DomName('HTMLCollection.item')
@DocsEditable()
- Element item(int index) => _blink.BlinkHTMLCollection.instance.item_Callback_1_(this, index);
+ Node item(int index) => _blink.BlinkHTMLCollection.instance.item_Callback_1_(this, index);
@DomName('HTMLCollection.namedItem')
@DocsEditable()
- Element namedItem(String name) => _blink.BlinkHTMLCollection.instance.namedItem_Callback_1_(this, name);
+ Object namedItem(String name) => (_blink.BlinkHTMLCollection.instance.namedItem_Callback_1_(this, name));
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
@@ -19891,59 +19900,6 @@ class HtmlDocument extends Document {
_webkitExitFullscreen();
}
- /**
- * Returns the element, if any, that is currently displayed in fullscreen.
- *
- * Returns null if there is currently no fullscreen element. You can use
- * this to determine if the page is in fullscreen mode.
- *
- * myVideo = new VideoElement();
- * if (document.fullscreenElement == null) {
- * myVideo.requestFullscreen();
- * print(document.fullscreenElement == myVideo); // true
- * }
- *
- * ## Other resources
- *
- * * [Using the fullscreen
- * API](http://docs.webplatform.org/wiki/tutorials/using_the_full-screen_api)
- * from WebPlatform.org.
- * * [Fullscreen specification](http://www.w3.org/TR/fullscreen/) from W3C.
- */
- @DomName('Document.webkitFullscreenElement')
- @SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.SAFARI)
- @Experimental()
- Element get fullscreenElement => _webkitFullscreenElement;
-
- /**
- * Returns true if this document can display elements in fullscreen mode.
- *
- * ## Other resources
- *
- * * [Using the fullscreen
- * API](http://docs.webplatform.org/wiki/tutorials/using_the_full-screen_api)
- * from WebPlatform.org.
- * * [Fullscreen specification](http://www.w3.org/TR/fullscreen/) from W3C.
- */
- @DomName('Document.webkitFullscreenEnabled')
- @SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.SAFARI)
- @Experimental()
- bool get fullscreenEnabled => _webkitFullscreenEnabled;
-
- @DomName('Document.webkitHidden')
- @SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.SAFARI)
- @Experimental()
- bool get hidden => _webkitHidden;
-
- @DomName('Document.visibilityState')
- @SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.FIREFOX)
- @SupportedBrowser(SupportedBrowser.IE, '10')
- @Experimental()
- String get visibilityState => _webkitVisibilityState;
/**
* Internal routine to find the DOM JS class name being extended for custom
@@ -21398,7 +21354,7 @@ class HttpRequest extends HttpRequestEventTarget {
*/
@DomName('XMLHttpRequest.readystatechangeEvent')
@DocsEditable()
- static const EventStreamProvider<ProgressEvent> readyStateChangeEvent = const EventStreamProvider<ProgressEvent>('readystatechange');
+ static const EventStreamProvider<Event> readyStateChangeEvent = const EventStreamProvider<Event>('readystatechange');
/**
* General constructor for any type of request (GET, POST, etc).
@@ -21754,7 +21710,7 @@ class HttpRequest extends HttpRequestEventTarget {
*/
@DomName('XMLHttpRequest.onreadystatechange')
@DocsEditable()
- Stream<ProgressEvent> get onReadyStateChange => readyStateChangeEvent.forTarget(this);
+ Stream<Event> get onReadyStateChange => readyStateChangeEvent.forTarget(this);
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
@@ -22328,7 +22284,7 @@ class InputElement extends HtmlElement implements
ButtonInputElement {
factory InputElement({String type}) {
- var e = document.createElement("input");
+ InputElement e = document.createElement("input");
if (type != null) {
try {
// IE throws an exception for unknown types.
@@ -25903,7 +25859,7 @@ class MessageEvent extends Event {
factory MessageEvent(String type,
{bool canBubble: false, bool cancelable: false, Object data,
String origin, String lastEventId,
- Window source, List messagePorts}) {
+ Window source, List<MessagePort> messagePorts}) {
if (source == null) {
source = window;
}
@@ -27782,7 +27738,7 @@ class Node extends EventTarget {
set nodes(Iterable<Node> value) {
// Copy list first since we don't want liveness during iteration.
// TODO(jacobr): there is a better way to do this.
- List copy = new List.from(value);
+ var copy = value.toList();
text = '';
for (Node node in copy) {
append(node);
@@ -32910,8 +32866,7 @@ class SelectElement extends HtmlElement {
// Override default options, since IE returns SelectElement itself and it
// does not operate as a List.
List<OptionElement> get options {
- var options = this.querySelectorAll('option').where(
- (e) => e is OptionElement).toList();
+ var options = new List<OptionElement>.from(this.querySelectorAll('option'));
return new UnmodifiableListView(options);
}
@@ -33695,7 +33650,7 @@ class SharedWorker extends EventTarget implements AbstractWorker {
@DomName('SharedWorker.errorEvent')
@DocsEditable()
@Experimental() // untriaged
- static const EventStreamProvider<ErrorEvent> errorEvent = const EventStreamProvider<ErrorEvent>('error');
+ static const EventStreamProvider<Event> errorEvent = const EventStreamProvider<Event>('error');
@DomName('SharedWorker.SharedWorker')
@DocsEditable()
@@ -33723,7 +33678,7 @@ class SharedWorker extends EventTarget implements AbstractWorker {
@DomName('SharedWorker.onerror')
@DocsEditable()
@Experimental() // untriaged
- Stream<ErrorEvent> get onError => errorEvent.forTarget(this);
+ Stream<Event> get onError => errorEvent.forTarget(this);
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
@@ -35116,11 +35071,11 @@ class Storage extends DartHtmlDomObject
}
// TODO(nweiz): update this when maps support lazy iteration
- bool containsValue(String value) => values.any((e) => e == value);
+ bool containsValue(Object value) => values.any((e) => e == value);
- bool containsKey(String key) => _getItem(key) != null;
+ bool containsKey(Object key) => _getItem(key) != null;
- String operator [](String key) => _getItem(key);
+ String operator [](Object key) => _getItem(key);
void operator []=(String key, String value) { _setItem(key, value); }
@@ -35129,7 +35084,7 @@ class Storage extends DartHtmlDomObject
return this[key];
}
- String remove(String key) {
+ String remove(Object key) {
final value = this[key];
_removeItem(key);
return value;
@@ -35147,13 +35102,13 @@ class Storage extends DartHtmlDomObject
}
Iterable<String> get keys {
- final keys = [];
+ final keys = <String>[];
forEach((k, v) => keys.add(k));
return keys;
}
Iterable<String> get values {
- final values = [];
+ final values = <String>[];
forEach((k, v) => values.add(v));
return values;
}
@@ -40994,7 +40949,7 @@ class Worker extends EventTarget implements AbstractWorker {
@DomName('Worker.errorEvent')
@DocsEditable()
@Experimental() // untriaged
- static const EventStreamProvider<ErrorEvent> errorEvent = const EventStreamProvider<ErrorEvent>('error');
+ static const EventStreamProvider<Event> errorEvent = const EventStreamProvider<Event>('error');
/**
* Static factory designed to expose `message` events to event
@@ -41040,7 +40995,7 @@ class Worker extends EventTarget implements AbstractWorker {
@DomName('Worker.onerror')
@DocsEditable()
@Experimental() // untriaged
- Stream<ErrorEvent> get onError => errorEvent.forTarget(this);
+ Stream<Event> get onError => errorEvent.forTarget(this);
/// Stream of `message` events handled by this [Worker].
@DomName('Worker.onmessage')
@@ -41734,16 +41689,6 @@ class _Attr extends Node {
@Experimental() // untriaged
String get nodeValue => _blink.BlinkAttr.instance.nodeValue_Getter_(this);
- @DomName('Attr.textContent')
- @DocsEditable()
- @Experimental() // untriaged
- String get text => _blink.BlinkAttr.instance.textContent_Getter_(this);
-
- @DomName('Attr.textContent')
- @DocsEditable()
- @Experimental() // untriaged
- set text(String value) => _blink.BlinkAttr.instance.textContent_Setter_(this, value);
-
@DomName('Attr.value')
@DocsEditable()
String get value => _blink.BlinkAttr.instance.value_Getter_(this);
@@ -43341,7 +43286,7 @@ abstract class _AttributeMap implements Map<String, String> {
other.forEach((k, v) { this[k] = v; });
}
- bool containsValue(String value) {
+ bool containsValue(Object value) {
for (var v in this.values) {
if (value == v) {
return true;
@@ -43373,10 +43318,11 @@ abstract class _AttributeMap implements Map<String, String> {
Iterable<String> get keys {
// TODO: generate a lazy collection instead.
var attributes = _element._attributes;
- var keys = new List<String>();
+ var keys = <String>[];
for (int i = 0, len = attributes.length; i < len; i++) {
- if (_matches(attributes[i])) {
- keys.add(attributes[i].name);
+ _Attr attr = attributes[i];
+ if (_matches(attr)) {
+ keys.add(attr.name);
}
}
return keys;
@@ -43385,10 +43331,11 @@ abstract class _AttributeMap implements Map<String, String> {
Iterable<String> get values {
// TODO: generate a lazy collection instead.
var attributes = _element._attributes;
- var values = new List<String>();
+ var values = <String>[];
for (int i = 0, len = attributes.length; i < len; i++) {
- if (_matches(attributes[i])) {
- values.add(attributes[i].value);
+ _Attr attr = attributes[i];
+ if (_matches(attr)) {
+ values.add(attr.value);
}
}
return values;
@@ -43419,11 +43366,11 @@ class _ElementAttributeMap extends _AttributeMap {
_ElementAttributeMap(Element element): super(element);
- bool containsKey(String key) {
+ bool containsKey(Object key) {
return _element._hasAttribute(key);
}
- String operator [](String key) {
+ String operator [](Object key) {
return _element.getAttribute(key);
}
@@ -43431,7 +43378,7 @@ class _ElementAttributeMap extends _AttributeMap {
_element.setAttribute(key, value);
}
- String remove(String key) {
+ String remove(Object key) {
String value = _element.getAttribute(key);
_element._removeAttribute(key);
return value;
@@ -43456,11 +43403,11 @@ class _NamespacedAttributeMap extends _AttributeMap {
_NamespacedAttributeMap(Element element, this._namespace): super(element);
- bool containsKey(String key) {
+ bool containsKey(Object key) {
return _element._hasAttributeNS(_namespace, key);
}
- String operator [](String key) {
+ String operator [](Object key) {
return _element.getAttributeNS(_namespace, key);
}
@@ -43468,7 +43415,7 @@ class _NamespacedAttributeMap extends _AttributeMap {
_element.setAttributeNS(_namespace, key, value);
}
- String remove(String key) {
+ String remove(Object key) {
String value = this[key];
_element._removeAttributeNS(_namespace, key);
return value;
@@ -43502,11 +43449,11 @@ class _DataAttributeMap implements Map<String, String> {
}
// TODO: Use lazy iterator when it is available on Map.
- bool containsValue(String value) => values.any((v) => v == value);
+ bool containsValue(Object value) => values.any((v) => v == value);
- bool containsKey(String key) => _attributes.containsKey(_attr(key));
+ bool containsKey(Object key) => _attributes.containsKey(_attr(key));
- String operator [](String key) => _attributes[_attr(key)];
+ String operator [](Object key) => _attributes[_attr(key)];
void operator []=(String key, String value) {
_attributes[_attr(key)] = value;
@@ -43515,7 +43462,7 @@ class _DataAttributeMap implements Map<String, String> {
String putIfAbsent(String key, String ifAbsent()) =>
_attributes.putIfAbsent(_attr(key), ifAbsent);
- String remove(String key) => _attributes.remove(_attr(key));
+ String remove(Object key) => _attributes.remove(_attr(key));
void clear() {
// Needs to operate on a snapshot since we are mutating the collection.
@@ -43533,7 +43480,7 @@ class _DataAttributeMap implements Map<String, String> {
}
Iterable<String> get keys {
- final keys = new List<String>();
+ final keys = <String>[];
_attributes.forEach((String key, String value) {
if (_matches(key)) {
keys.add(_strip(key));
@@ -43543,7 +43490,7 @@ class _DataAttributeMap implements Map<String, String> {
}
Iterable<String> get values {
- final values = new List<String>();
+ final values = <String>[];
_attributes.forEach((String key, String value) {
if (_matches(key)) {
values.add(value);
@@ -43774,7 +43721,7 @@ abstract class WindowBase implements EventTarget {
* * [Cross-document messaging](https://html.spec.whatwg.org/multipage/comms.html#web-messaging)
* from WHATWG.
*/
- void postMessage(var message, String targetOrigin, [List messagePorts]);
+ void postMessage(var message, String targetOrigin, [List<MessagePort> messagePorts]);
}
abstract class LocationBase {
@@ -43828,7 +43775,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(String value);
+ bool contains(Object value);
/**
* Add the class [value] to element.
@@ -43880,7 +43827,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<String> iterable);
+ void removeAll(Iterable<Object> iterable);
/**
* Toggles all classes specified in [iterable] on element.
@@ -43996,7 +43943,7 @@ class _ElementCssClassSet extends CssClassSetImpl {
*/
class _ContentCssRect extends CssRect {
- _ContentCssRect(element) : super(element);
+ _ContentCssRect(Element element) : super(element);
num get height => _element.offsetHeight +
_addOrSubtractToBoxModel(_HEIGHT, _CONTENT);
@@ -44017,9 +43964,11 @@ class _ContentCssRect extends CssRect {
if (newHeight is Dimension) {
if (newHeight.value < 0) newHeight = new Dimension.px(0);
_element.style.height = newHeight.toString();
- } else {
+ } 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");
}
}
@@ -44035,9 +43984,11 @@ class _ContentCssRect extends CssRect {
if (newWidth is Dimension) {
if (newWidth.value < 0) newWidth = new Dimension.px(0);
_element.style.width = newWidth.toString();
- } else {
+ } 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");
}
}
@@ -44054,7 +44005,7 @@ class _ContentCssRect extends CssRect {
class _ContentCssListRect extends _ContentCssRect {
List<Element> _elementList;
- _ContentCssListRect(elementList) : super(elementList.first) {
+ _ContentCssListRect(List<Element> elementList) : super(elementList.first) {
_elementList = elementList;
}
@@ -44143,10 +44094,10 @@ class _MarginCssRect extends CssRect {
* animation frame is discouraged. See also:
* [Browser Reflow](https://developers.google.com/speed/articles/reflow)
*/
-abstract class CssRect extends MutableRectangle<num> {
+abstract class CssRect implements Rectangle<num> {
Element _element;
- CssRect(this._element) : super(0, 0, 0, 0);
+ CssRect(this._element);
num get left;
@@ -44239,6 +44190,102 @@ abstract class CssRect extends MutableRectangle<num> {
}
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) {
+ if (other is !Rectangle) return false;
+ return 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'];
@@ -44369,7 +44416,7 @@ class EventStreamProvider<T extends Event> {
* [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventListener)
*/
Stream<T> forTarget(EventTarget e, {bool useCapture: false}) =>
- new _EventStream(e, _eventType, useCapture);
+ new _EventStream<T>(e, _eventType, useCapture);
/**
* Gets an [ElementEventStream] for this event type, on the specified element.
@@ -44393,7 +44440,7 @@ class EventStreamProvider<T extends Event> {
* [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventListener)
*/
ElementStream<T> forElement(Element e, {bool useCapture: false}) {
- return new _ElementEventStreamImpl(e, _eventType, useCapture);
+ return new _ElementEventStreamImpl<T>(e, _eventType, useCapture);
}
/**
@@ -44464,8 +44511,8 @@ class _EventStream<T extends Event> extends Stream<T> {
_EventStream(this._target, this._eventType, this._useCapture);
// DOM events are inherently multi-subscribers.
- Stream<T> asBroadcastStream({void onListen(StreamSubscription subscription),
- void onCancel(StreamSubscription subscription)})
+ Stream<T> asBroadcastStream({void onListen(StreamSubscription<T> subscription),
+ void onCancel(StreamSubscription<T> subscription)})
=> this;
bool get isBroadcast => true;
@@ -44479,6 +44526,11 @@ class _EventStream<T extends Event> extends Stream<T> {
}
}
+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.
@@ -44489,7 +44541,7 @@ class _ElementEventStreamImpl<T extends Event> extends _EventStream<T>
super(target, eventType, useCapture);
Stream<T> matches(String selector) => this.where(
- (event) => event.target.matchesWithAncestors(selector)).map((e) {
+ (event) => _matchesWithAncestors(event, selector)).map((e) {
e._selector = selector;
return e;
});
@@ -44513,7 +44565,7 @@ class _ElementListEventStreamImpl<T extends Event> extends Stream<T>
this._targetList, this._eventType, this._useCapture);
Stream<T> matches(String selector) => this.where(
- (event) => event.target.matchesWithAncestors(selector)).map((e) {
+ (event) => _matchesWithAncestors(event, selector)).map((e) {
e._selector = selector;
return e;
});
@@ -44523,37 +44575,46 @@ class _ElementListEventStreamImpl<T extends Event> extends Stream<T>
{ Function onError,
void onDone(),
bool cancelOnError}) {
- var pool = new _StreamPool.broadcast();
+ var pool = new _StreamPool<T>.broadcast();
for (var target in _targetList) {
- pool.add(new _EventStream(target, _eventType, _useCapture));
+ 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.broadcast();
+ var pool = new _StreamPool<T>.broadcast();
for (var target in _targetList) {
- pool.add(new _EventStream(target, _eventType, true));
+ pool.add(new _EventStream<T>(target, _eventType, true));
}
return pool.stream.listen(onData);
}
- Stream<T> asBroadcastStream({void onListen(StreamSubscription subscription),
- void onCancel(StreamSubscription subscription)})
+ 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;
- var _onData;
+ EventListener _onData;
final bool _useCapture;
- _EventStreamSubscription(this._target, this._eventType, onData,
- this._useCapture) : _onData = _wrapZone(onData) {
+ // TODO(jacobr): for full strong mode correctness we should write
+ // _onData = onData == null ? null : _wrapZone/*<Event, dynamic>*/((e) => onData(e as T))
+ // but that breaks 114 co19 tests as well as multiple html tests as it is reasonable
+ // to pass the wrong type of event object to an event listener as part of a
+ // test.
+ _EventStreamSubscription(this._target, this._eventType, void onData(T event),
+ this._useCapture) : _onData = _wrapZone/*<Event, dynamic>*/(onData) {
_tryResume();
}
@@ -44575,8 +44636,7 @@ class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> {
}
// Remove current event listener.
_unlisten();
-
- _onData = _wrapZone(handleData);
+ _onData = _wrapZone/*<Event, dynamic>*/(handleData);
_tryResume();
}
@@ -44655,8 +44715,8 @@ class _CustomEventStreamImpl<T extends Event> extends Stream<T>
onDone: onDone, cancelOnError: cancelOnError);
}
- Stream<T> asBroadcastStream({void onListen(StreamSubscription subscription),
- void onCancel(StreamSubscription subscription)})
+ Stream<T> asBroadcastStream({void onListen(StreamSubscription<T> subscription),
+ void onCancel(StreamSubscription<T> subscription)})
=> _streamController.stream;
bool get isBroadcast => true;
@@ -44747,16 +44807,16 @@ class _CustomEventStreamProvider<T extends Event>
const _CustomEventStreamProvider(this._eventTypeGetter);
Stream<T> forTarget(EventTarget e, {bool useCapture: false}) {
- return new _EventStream(e, _eventTypeGetter(e), useCapture);
+ return new _EventStream<T>(e, _eventTypeGetter(e), useCapture);
}
ElementStream<T> forElement(Element e, {bool useCapture: false}) {
- return new _ElementEventStreamImpl(e, _eventTypeGetter(e), useCapture);
+ return new _ElementEventStreamImpl<T>(e, _eventTypeGetter(e), useCapture);
}
ElementStream<T> _forElementList(ElementList e,
{bool useCapture: false}) {
- return new _ElementListEventStreamImpl(e, _eventTypeGetter(e), useCapture);
+ return new _ElementListEventStreamImpl<T>(e, _eventTypeGetter(e), useCapture);
}
String getEventType(EventTarget target) {
@@ -46135,7 +46195,7 @@ class _KeyboardEventHandler extends EventStreamProvider<KeyEvent> {
* The set of keys that have been pressed down without seeing their
* corresponding keyup event.
*/
- final List<KeyboardEvent> _keyDownList = <KeyboardEvent>[];
+ final List<KeyEvent> _keyDownList = <KeyEvent>[];
/** The type of KeyEvent we are tracking (keyup, keydown, keypress). */
final String _type;
@@ -46194,8 +46254,9 @@ class _KeyboardEventHandler extends EventStreamProvider<KeyEvent> {
* General constructor, performs basic initialization for our improved
* KeyboardEvent controller.
*/
- _KeyboardEventHandler(this._type): super(_EVENT_TYPE),
- _stream = new _CustomKeyEventStreamImpl('event'), _target = null;
+ _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
@@ -46503,7 +46564,6 @@ class KeyboardEventStream {
// BSD-style license that can be found in the LICENSE file.
-
/**
* Class which helps construct standard node validation policies.
*
@@ -46521,11 +46581,9 @@ class KeyboardEventStream {
* appropriate.
*/
class NodeValidatorBuilder implements NodeValidator {
-
final List<NodeValidator> _validators = <NodeValidator>[];
- NodeValidatorBuilder() {
- }
+ NodeValidatorBuilder() {}
/**
* Creates a new NodeValidatorBuilder which accepts common constructs.
@@ -46654,29 +46712,17 @@ class NodeValidatorBuilder implements NodeValidator {
{UriPolicy uriPolicy,
Iterable<String> attributes,
Iterable<String> uriAttributes}) {
-
var tagNameUpper = tagName.toUpperCase();
- var attrs;
- if (attributes != null) {
- attrs =
- attributes.map((name) => '$tagNameUpper::${name.toLowerCase()}');
- }
- var uriAttrs;
- if (uriAttributes != null) {
- uriAttrs =
- uriAttributes.map((name) => '$tagNameUpper::${name.toLowerCase()}');
- }
+ 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));
+ uriPolicy, [tagNameUpper], attrs, uriAttrs, false, true));
}
/**
@@ -46691,37 +46737,26 @@ class NodeValidatorBuilder implements NodeValidator {
{UriPolicy uriPolicy,
Iterable<String> attributes,
Iterable<String> uriAttributes}) {
-
var baseNameUpper = baseName.toUpperCase();
var tagNameUpper = tagName.toUpperCase();
- var attrs;
- if (attributes != null) {
- attrs =
- attributes.map((name) => '$baseNameUpper::${name.toLowerCase()}');
- }
- var uriAttrs;
- if (uriAttributes != null) {
- uriAttrs =
- uriAttributes.map((name) => '$baseNameUpper::${name.toLowerCase()}');
- }
+ 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));
+ 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,
+ void allowElement(String tagName,
+ {UriPolicy uriPolicy,
+ Iterable<String> attributes,
+ Iterable<String> uriAttributes}) {
+ allowCustomElement(tagName,
+ uriPolicy: uriPolicy,
attributes: attributes,
uriAttributes: uriAttributes);
}
@@ -46752,8 +46787,8 @@ class NodeValidatorBuilder implements NodeValidator {
}
bool allowsAttribute(Element element, String attributeName, String value) {
- return _validators.any(
- (v) => v.allowsAttribute(element, attributeName, value));
+ return _validators
+ .any((v) => v.allowsAttribute(element, attributeName, value));
}
}
@@ -46764,76 +46799,70 @@ class _SimpleNodeValidator implements NodeValidator {
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',
- ]);
+ 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',
- ]);
+ 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',
- ]);
+ return new _SimpleNodeValidator(null, allowedElements: const [
+ 'B',
+ 'BLOCKQUOTE',
+ 'BR',
+ 'EM',
+ 'H1',
+ 'H2',
+ 'H3',
+ 'H4',
+ 'H5',
+ 'H6',
+ 'HR',
+ 'I',
+ 'LI',
+ 'OL',
+ 'P',
+ 'SPAN',
+ 'UL',
+ ]);
}
/**
@@ -46842,15 +46871,16 @@ 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 [];
- var legalAttributes = allowedAttributes.where(
- (x) => !_Html5NodeValidator._uriAttributes.contains(x));
- var extraUriAttributes = allowedAttributes.where(
- (x) => _Html5NodeValidator._uriAttributes.contains(x));
+ 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);
@@ -46883,19 +46913,19 @@ class _CustomElementNodeValidator extends _SimpleNodeValidator {
final bool allowTypeExtension;
final bool allowCustomTag;
- _CustomElementNodeValidator(UriPolicy uriPolicy,
+ _CustomElementNodeValidator(
+ UriPolicy uriPolicy,
Iterable<String> allowedElements,
Iterable<String> allowedAttributes,
Iterable<String> allowedUriAttributes,
bool allowTypeExtension,
- bool allowCustomTag):
-
- super(uriPolicy,
- allowedElements: allowedElements,
- allowedAttributes: allowedAttributes,
- allowedUriAttributes: allowedUriAttributes),
- this.allowTypeExtension = allowTypeExtension == true,
- this.allowCustomTag = allowCustomTag == true;
+ bool allowCustomTag)
+ : this.allowTypeExtension = allowTypeExtension == true,
+ this.allowCustomTag = allowCustomTag == true,
+ super(uriPolicy,
+ allowedElements: allowedElements,
+ allowedAttributes: allowedAttributes,
+ allowedUriAttributes: allowedUriAttributes);
bool allowsElement(Element element) {
if (allowTypeExtension) {
@@ -46905,12 +46935,14 @@ class _CustomElementNodeValidator extends _SimpleNodeValidator {
allowedElements.contains(Element._safeTagName(element));
}
}
- return allowCustomTag && 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' &&
+ if (allowsElement(element)) {
+ if (allowTypeExtension &&
+ attributeName == 'is' &&
allowedElements.contains(value.toUpperCase())) {
return true;
}
@@ -46921,19 +46953,22 @@ class _CustomElementNodeValidator extends _SimpleNodeValidator {
}
class _TemplatingNodeValidator extends _SimpleNodeValidator {
- static const _TEMPLATE_ATTRS =
- const <String>['bind', 'if', 'ref', 'repeat', 'syntax'];
+ static const _TEMPLATE_ATTRS = const <String>[
+ 'bind',
+ 'if',
+ 'ref',
+ 'repeat',
+ 'syntax'
+ ];
final Set<String> _templateAttrs;
- _TemplatingNodeValidator():
- super(null,
- allowedElements: [
- 'TEMPLATE'
- ],
- allowedAttributes: _TEMPLATE_ATTRS.map((attr) => 'TEMPLATE::$attr')),
- _templateAttrs = new Set<String>.from(_TEMPLATE_ATTRS) {
- }
+ _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)) {
@@ -46944,14 +46979,13 @@ class _TemplatingNodeValidator extends _SimpleNodeValidator {
return true;
}
- if (element.attributes['template'] == "" ) {
+ if (element.attributes['template'] == "") {
return _templateAttrs.contains(attributeName);
}
return false;
}
}
-
class _SvgNodeValidator implements NodeValidator {
bool allowsElement(Element element) {
if (element is svg.ScriptElement) {
@@ -46961,7 +46995,8 @@ class _SvgNodeValidator implements NodeValidator {
// 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') {
+ if (element is svg.SvgElement &&
+ Element._safeTagName(element) == 'foreignObject') {
return false;
}
if (element is svg.SvgElement) {
@@ -47308,7 +47343,7 @@ class _ValidatingTreeSanitizer implements NodeTreeSanitizer {
*/
class _WrappedList<E extends Node> extends ListBase<E>
implements NodeListWrapper {
- final List _list;
+ final List<Node> _list;
_WrappedList(this._list);
@@ -47328,13 +47363,13 @@ 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; }
set length(int newLength) { _list.length = newLength; }
- void sort([int compare(E a, E b)]) { _list.sort(compare); }
+ void sort([int compare(E a, E b)]) { _list.sort((Node a, Node b) => compare(a as E, b as E)); }
int indexOf(Object element, [int start = 0]) => _list.indexOf(element, start);
@@ -47342,7 +47377,7 @@ class _WrappedList<E extends Node> extends ListBase<E>
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);
@@ -47365,7 +47400,7 @@ class _WrappedList<E extends Node> extends ListBase<E>
* Iterator wrapper for _WrappedList.
*/
class _WrappedIterator<E> implements Iterator<E> {
- Iterator _iterator;
+ Iterator<Node> _iterator;
_WrappedIterator(this._iterator);
@@ -47373,7 +47408,7 @@ class _WrappedIterator<E> implements Iterator<E> {
return _iterator.moveNext();
}
- E get current => _iterator.current;
+ E get current => _iterator.current as E;
}
// 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
@@ -47815,17 +47850,25 @@ class _WrappedEvent implements Event {
// BSD-style license that can be found in the LICENSE file.
-_wrapZone(callback(arg)) {
+// TODO(jacobr): remove these typedefs when dart:async supports generic types.
+typedef R _wrapZoneCallback<A, R>(A a);
+typedef R _wrapZoneBinaryCallback<A, B, R>(A a, B b);
+
+_wrapZoneCallback/*<A, R>*/ _wrapZone/*<A, R>*/(_wrapZoneCallback/*<A, R>*/ 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.bindUnaryCallback(callback, runGuarded: true);
+ // TODO(jacobr): we cast to _wrapZoneCallback/*<A, R>*/ to hack around missing
+ // generic method support in zones.
+ return Zone.current.bindUnaryCallback(callback, runGuarded: true) as _wrapZoneCallback/*<A, R>*/;
}
-_wrapBinaryZone(callback(arg1, arg2)) {
+_wrapZoneBinaryCallback/*<A, B, R>*/ _wrapBinaryZone/*<A, B, R>*/(_wrapZoneBinaryCallback/*<A, B, R>*/ callback) {
if (Zone.current == Zone.ROOT) return callback;
if (callback == null) return null;
- return Zone.current.bindBinaryCallback(callback, runGuarded: true);
+ // We cast to _wrapZoneBinaryCallback/*<A, B, R>*/ to hack around missing
+ // generic method support in zones.
+ return Zone.current.bindBinaryCallback(callback, runGuarded: true) as _wrapZoneBinaryCallback/*<A, B, R>*/;
}
/**
« no previous file with comments | « sdk/lib/html/dart2js/html_dart2js.dart ('k') | sdk/lib/html/html_common/css_class_set.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698