Strong html

BUG=
R=alanknight@google.com

Review URL: https://codereview.chromium.org/1894713002 .
This commit is contained in:
Jacob Richman 2016-04-19 15:08:45 -07:00
parent e072ae33c6
commit 864b64fd5e
33 changed files with 1224 additions and 1069 deletions

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -56,11 +56,13 @@ abstract class CssClassSetImpl implements CssClassSet {
String join([String separator = ""]) => readClasses().join(separator);
Iterable map(f(String element)) => readClasses().map(f);
Iterable/*<T>*/ map/*<T>*/(/*=T*/ f(String e)) =>
readClasses().map/*<T>*/(f);
Iterable<String> where(bool f(String element)) => readClasses().where(f);
Iterable expand(Iterable f(String element)) => readClasses().expand(f);
Iterable/*<T>*/ expand/*<T>*/(Iterable/*<T>*/ f(String element)) =>
readClasses().expand/*<T>*/(f);
bool every(bool f(String element)) => readClasses().every(f);
@ -76,10 +78,11 @@ abstract class CssClassSetImpl implements CssClassSet {
return readClasses().reduce(combine);
}
dynamic fold(dynamic initialValue,
dynamic combine(dynamic previousValue, String element)) {
return readClasses().fold(initialValue, combine);
dynamic/*=T*/ fold/*<T>*/(var/*=T*/ initialValue,
dynamic/*=T*/ combine(var/*=T*/ previousValue, String element)) {
return readClasses().fold/*<T>*/(initialValue, combine);
}
// interface Collection - END
// interface Set - BEGIN
@ -145,7 +148,7 @@ abstract class CssClassSetImpl implements CssClassSet {
* [removeClass](http://api.jquery.com/removeClass/).
*/
void removeAll(Iterable<Object> iterable) {
modify((s) => s.removeAll(iterable.map(_validateToken)));
modify((s) => s.removeAll(iterable));
}
/**
@ -183,7 +186,7 @@ abstract class CssClassSetImpl implements CssClassSet {
Set<String> union(Set<String> other) =>
readClasses().union(other);
Set<String> difference(Set<String> other) =>
Set<String> difference(Set<Object> other) =>
readClasses().difference(other);
String get first => readClasses().first;
@ -221,7 +224,7 @@ abstract class CssClassSetImpl implements CssClassSet {
* After f returns, the modified set is written to the
* className property of this element.
*/
modify( f(Set<String> s)) {
modify(f(Set<String> s)) {
Set<String> s = readClasses();
var ret = f(s);
writeClasses(s);

View file

@ -26,12 +26,8 @@ class FilteredElementList extends ListBase<Element> implements NodeListWrapper {
// We can't memoize this, since it's possible that children will be messed
// with externally to this class.
//
// We can't use where directly because the types don't agree and there's
// no way to cast it, so take advantage of being in the SDK to construct
// a WhereIterable directly. Even so it has to be of dynamic.
Iterable<Element> get _iterable =>
new WhereIterable(_childNodes, (n) => n is Element);
_childNodes.where((n) => n is Element).map/*<Element>*/((n) => n as Element);
List<Element> get _filtered =>
new List<Element>.from(_iterable, growable: false);

View file

@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
library ElementTest;
import 'package:unittest/unittest.dart';
import 'package:unittest/html_individual_config.dart';
import 'dart:async';
@ -47,7 +48,7 @@ main() {
Element makeElement() => new Element.tag('div');
Element makeElementWithChildren() =>
new Element.html("<div><br/><img/><input/></div>");
new Element.html("<div><br/><img/><input/></div>");
group('position', () {
test('computedStyle', () {
@ -87,8 +88,8 @@ main() {
expect(() => new Element.html('<br/><br/>'), throwsStateError);
});
test('.html has no parent', () =>
expect(new Element.html('<br/>').parent, isNull));
test('.html has no parent',
() => expect(new Element.html('<br/>').parent, isNull));
test('.html table', () {
// http://developers.whatwg.org/tabular-data.html#tabular-data
@ -126,8 +127,10 @@ main() {
test('.html caption', () {
var table = new TableElement();
var node = table.createFragment('<caption><p>Table 1.').nodes.single;
expect(node, predicate((x) => x is TableCaptionElement,
'is a TableCaptionElement'));
expect(
node,
predicate(
(x) => x is TableCaptionElement, 'is a TableCaptionElement'));
expect(node.tagName, 'CAPTION');
expect(node.parent, isNull);
expect(node.innerHtml, '<p>Table 1.</p>');
@ -137,8 +140,8 @@ main() {
var table = new TableElement();
var node =
table.createFragment('<colgroup> <col> <col> <col>').nodes.single;
expect(node, predicate((x) => x is TableColElement,
'is a TableColElement'));
expect(
node, predicate((x) => x is TableColElement, 'is a TableColElement'));
expect(node.tagName, 'COLGROUP');
expect(node.parent, isNull);
expect(node.innerHtml, ' <col> <col> <col>');
@ -148,8 +151,10 @@ main() {
var innerHtml = '<tr><td headers="n r1">Sad</td><td>Happy</td></tr>';
var table = new TableElement();
var node = table.createFragment('<tbody>$innerHtml').nodes.single;
expect(node, predicate((x) => x is TableSectionElement,
'is a TableSectionElement'));
expect(
node,
predicate(
(x) => x is TableSectionElement, 'is a TableSectionElement'));
expect(node.tagName, 'TBODY');
expect(node.parent, isNull);
expect(node.rows.length, 1);
@ -161,8 +166,10 @@ main() {
var innerHtml = '<tr><th id="n">Negative</th><th>Positive</th></tr>';
var table = new TableElement();
var node = table.createFragment('<thead>$innerHtml').nodes.single;
expect(node, predicate((x) => x is TableSectionElement,
'is a TableSectionElement'));
expect(
node,
predicate(
(x) => x is TableSectionElement, 'is a TableSectionElement'));
expect(node.tagName, 'THEAD');
expect(node.parent, isNull);
expect(node.rows.length, 1);
@ -174,8 +181,10 @@ main() {
var innerHtml = '<tr><th>percentage</th><td>34.3%</td></tr>';
var table = new TableElement();
var node = table.createFragment('<tfoot>$innerHtml').nodes.single;
expect(node, predicate((x) => x is TableSectionElement,
'is a TableSectionElement'));
expect(
node,
predicate(
(x) => x is TableSectionElement, 'is a TableSectionElement'));
expect(node.tagName, 'TFOOT');
expect(node.parent, isNull);
expect(node.rows.length, 1);
@ -188,8 +197,8 @@ main() {
document.body.append(table);
var tBody = table.createTBody();
var node = tBody.createFragment('<tr><td>foo<td>bar').nodes.single;
expect(node, predicate((x) => x is TableRowElement,
'is a TableRowElement'));
expect(
node, predicate((x) => x is TableRowElement, 'is a TableRowElement'));
expect(node.tagName, 'TR');
expect(node.parent, isNull);
expect(node.cells.map((c) => c.innerHtml), ['foo', 'bar']);
@ -201,8 +210,8 @@ main() {
var tBody = table.createTBody();
var tRow = tBody.addRow();
var node = tRow.createFragment('<td>foobar').nodes.single;
expect(node, predicate((x) => x is TableCellElement,
'is a TableCellElement'));
expect(node,
predicate((x) => x is TableCellElement, 'is a TableCellElement'));
expect(node.tagName, 'TD');
expect(node.parent, isNull);
expect(node.innerHtml, 'foobar');
@ -214,8 +223,8 @@ main() {
var tBody = table.createTBody();
var tRow = tBody.addRow();
var node = tRow.createFragment('<th>foobar').nodes.single;
expect(node, predicate((x) => x is TableCellElement,
'is a TableCellElement'));
expect(node,
predicate((x) => x is TableCellElement, 'is a TableCellElement'));
expect(node.tagName, 'TH');
expect(node.parent, isNull);
expect(node.innerHtml, 'foobar');
@ -234,15 +243,15 @@ main() {
group('eventListening', () {
test('streams', () {
final target = new Element.tag('div');
final target = new TextAreaElement();
void testEvent(Stream stream, String type) {
void testEvent(Stream stream, String type, [createEvent(String type)]) {
var firedOnEvent = false;
stream.listen((e) {
firedOnEvent = true;
});
expect(firedOnEvent, isFalse);
var event = new Event(type);
var event = createEvent != null ? createEvent(type) : new Event(type);
target.dispatchEvent(event);
expect(firedOnEvent, isTrue);
@ -254,38 +263,53 @@ main() {
testEvent(target.onBeforePaste, 'beforepaste');
testEvent(target.onBlur, 'blur');
testEvent(target.onChange, 'change');
testEvent(target.onContextMenu, 'contextmenu');
testEvent(
target.onContextMenu, 'contextmenu', (type) => new MouseEvent(type));
// We cannot test dispatching a true ClipboardEvent as the DOM does not
// provide a way to create a fake ClipboardEvent.
testEvent(target.onCopy, 'copy');
testEvent(target.onCut, 'cut');
testEvent(target.onDoubleClick, 'dblclick');
testEvent(target.onDrag, 'drag');
testEvent(target.onDragEnd, 'dragend');
testEvent(target.onDragEnter, 'dragenter');
testEvent(target.onDragLeave, 'dragleave');
testEvent(target.onDragOver, 'dragover');
testEvent(target.onDragStart, 'dragstart');
testEvent(target.onDrop, 'drop');
testEvent(target.onPaste, 'paste');
testEvent(
target.onDoubleClick, 'dblclick', (type) => new MouseEvent(type));
testEvent(target.onDrag, 'drag', (type) => new MouseEvent(type));
testEvent(target.onDragEnd, 'dragend', (type) => new MouseEvent(type));
testEvent(
target.onDragEnter, 'dragenter', (type) => new MouseEvent(type));
testEvent(
target.onDragLeave, 'dragleave', (type) => new MouseEvent(type));
testEvent(target.onDragOver, 'dragover', (type) => new MouseEvent(type));
testEvent(
target.onDragStart, 'dragstart', (type) => new MouseEvent(type));
testEvent(target.onDrop, 'drop', (type) => new MouseEvent(type));
testEvent(target.onError, 'error');
testEvent(target.onFocus, 'focus');
testEvent(target.onFullscreenChange, 'webkitfullscreenchange');
testEvent(target.onInput, 'input');
testEvent(target.onInvalid, 'invalid');
testEvent(target.onKeyDown, 'keydown');
testEvent(target.onKeyPress, 'keypress');
testEvent(target.onKeyUp, 'keyup');
testEvent(target.onKeyDown, 'keydown', (type) => new KeyboardEvent(type));
testEvent(
target.onKeyPress, 'keypress', (type) => new KeyboardEvent(type));
testEvent(target.onKeyUp, 'keyup', (type) => new KeyboardEvent(type));
testEvent(target.onLoad, 'load');
testEvent(target.onMouseDown, 'mousedown');
testEvent(target.onMouseMove, 'mousemove');
testEvent(target.onMouseOut, 'mouseout');
testEvent(target.onMouseOver, 'mouseover');
testEvent(target.onMouseUp, 'mouseup');
testEvent(target.onPaste, 'paste');
testEvent(
target.onMouseDown, 'mousedown', (type) => new MouseEvent(type));
testEvent(
target.onMouseMove, 'mousemove', (type) => new MouseEvent(type));
testEvent(target.onMouseOut, 'mouseout', (type) => new MouseEvent(type));
testEvent(
target.onMouseOver, 'mouseover', (type) => new MouseEvent(type));
testEvent(target.onMouseUp, 'mouseup', (type) => new MouseEvent(type));
testEvent(target.onReset, 'reset');
testEvent(target.onScroll, 'scroll');
testEvent(target.onSearch, 'search');
testEvent(target.onSelect, 'select');
testEvent(target.onSelectStart, 'selectstart');
testEvent(target.onSubmit, 'submit');
// We would prefer to create new touch events for this test via
// new TouchEvent(null, null, null, type)
// but that fails on desktop browsers as touch is not enabled.
testEvent(target.onTouchCancel, 'touchcancel');
testEvent(target.onTouchEnd, 'touchend');
testEvent(target.onTouchLeave, 'touchleave');
@ -319,66 +343,67 @@ main() {
});
group('attributes', () {
test('manipulation', () {
final element = new Element.html(
'''<div class="foo" style="overflow: hidden" data-foo="bar"
test('manipulation', () {
final element = new Element.html(
'''<div class="foo" style="overflow: hidden" data-foo="bar"
data-foo2="bar2" dir="rtl">
</div>''', treeSanitizer: new NullTreeSanitizer());
final attributes = element.attributes;
expect(attributes['class'], 'foo');
expect(attributes['style'], startsWith('overflow: hidden'));
expect(attributes['data-foo'], 'bar');
expect(attributes['data-foo2'], 'bar2');
expect(attributes.length, 5);
expect(element.dataset.length, 2);
element.dataset['foo'] = 'baz';
expect(element.dataset['foo'], 'baz');
expect(attributes['data-foo'], 'baz');
attributes['data-foo2'] = 'baz2';
expect(attributes['data-foo2'], 'baz2');
expect(element.dataset['foo2'], 'baz2');
expect(attributes['dir'], 'rtl');
</div>''',
treeSanitizer: new NullTreeSanitizer());
final attributes = element.attributes;
expect(attributes['class'], 'foo');
expect(attributes['style'], startsWith('overflow: hidden'));
expect(attributes['data-foo'], 'bar');
expect(attributes['data-foo2'], 'bar2');
expect(attributes.length, 5);
expect(element.dataset.length, 2);
element.dataset['foo'] = 'baz';
expect(element.dataset['foo'], 'baz');
expect(attributes['data-foo'], 'baz');
attributes['data-foo2'] = 'baz2';
expect(attributes['data-foo2'], 'baz2');
expect(element.dataset['foo2'], 'baz2');
expect(attributes['dir'], 'rtl');
final dataset = element.dataset;
dataset.remove('foo2');
expect(attributes.length, 4);
expect(dataset.length, 1);
attributes.remove('style');
expect(attributes.length, 3);
dataset['foo3'] = 'baz3';
expect(dataset.length, 2);
expect(attributes.length, 4);
attributes['style'] = 'width: 300px;';
expect(attributes.length, 5);
});
final dataset = element.dataset;
dataset.remove('foo2');
expect(attributes.length, 4);
expect(dataset.length, 1);
attributes.remove('style');
expect(attributes.length, 3);
dataset['foo3'] = 'baz3';
expect(dataset.length, 2);
expect(attributes.length, 4);
attributes['style'] = 'width: 300px;';
expect(attributes.length, 5);
});
test('namespaces', () {
var element = new svg.SvgElement.svg(
'''<svg xmlns="http://www.w3.org/2000/svg"
test('namespaces', () {
var element =
new svg.SvgElement.svg('''<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<image xlink:href="foo" data-foo="bar"/>
</svg>''').children[0];
var attributes = element.attributes;
expect(attributes.length, 1);
expect(attributes['data-foo'], 'bar');
var attributes = element.attributes;
expect(attributes.length, 1);
expect(attributes['data-foo'], 'bar');
var xlinkAttrs =
element.getNamespacedAttributes('http://www.w3.org/1999/xlink');
expect(xlinkAttrs.length, 1);
expect(xlinkAttrs['href'], 'foo');
var xlinkAttrs =
element.getNamespacedAttributes('http://www.w3.org/1999/xlink');
expect(xlinkAttrs.length, 1);
expect(xlinkAttrs['href'], 'foo');
xlinkAttrs.remove('href');
expect(xlinkAttrs.length, 0);
xlinkAttrs.remove('href');
expect(xlinkAttrs.length, 0);
xlinkAttrs['href'] = 'bar';
expect(xlinkAttrs['href'], 'bar');
xlinkAttrs['href'] = 'bar';
expect(xlinkAttrs['href'], 'bar');
var randomAttrs = element.getNamespacedAttributes('http://example.com');
expect(randomAttrs.length, 0);
randomAttrs['href'] = 'bar';
expect(randomAttrs.length, 1);
});
var randomAttrs = element.getNamespacedAttributes('http://example.com');
expect(randomAttrs.length, 0);
randomAttrs['href'] = 'bar';
expect(randomAttrs.length, 1);
});
});
group('children', () {
@ -421,8 +446,8 @@ main() {
});
test('where', () {
var filtered = makeElementWithChildren().children.
where((n) => n is ImageElement);
var filtered =
makeElementWithChildren().children.where((n) => n is ImageElement);
expect(1, filtered.length);
expect(filtered.first, isImageElement);
expect(filtered, isElementIterable);
@ -764,25 +789,27 @@ main() {
test('matches', () {
Element clickOne = new Element.a();
Element selectorOne = new Element.div()
..classes.add('selector')
..children.add(clickOne);
..classes.add('selector')
..children.add(clickOne);
Element clickTwo = new Element.a();
Element selectorTwo = new Element.div()
..classes.add('selector')
..children.add(clickTwo);
..classes.add('selector')
..children.add(clickTwo);
document.body.append(selectorOne);
document.body.append(selectorTwo);
document.body.onClick.matches('.selector').listen(expectAsync(
(Event event) {
document.body.onClick
.matches('.selector')
.listen(expectAsync((Event event) {
expect(event.currentTarget, document.body);
expect(event.target, clickOne);
expect(event.matchingTarget, selectorOne);
}));
selectorOne.onClick.matches('.selector').listen(expectAsync(
(Event event) {
selectorOne.onClick
.matches('.selector')
.listen(expectAsync((Event event) {
expect(event.currentTarget, selectorOne);
expect(event.target, clickOne);
expect(event.matchingTarget, selectorOne);
@ -896,12 +923,8 @@ main() {
var event = new Event('custom_event', canBubble: true);
c.dispatchEvent(event);
expect(eventOrder, [
'a capture',
'b capture',
'b no-capture',
'a no-capture'
]);
expect(eventOrder,
['a capture', 'b capture', 'b no-capture', 'a no-capture']);
});
});
@ -917,7 +940,7 @@ main() {
ElementList<Element> makeElementList() =>
(new Element.html("<div>Foo<br/><!--baz--><br/><br/></div>"))
.queryAll('br');
.queryAll('br');
test('hashCode', () {
var nodes = makeElementList();
@ -934,7 +957,7 @@ main() {
var a = [makeElementList(), makeElementList(), null];
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a.length; j++) {
expect(i == j, a[i] == a[j]);
expect(i == j, a[i] == a[j]);
}
}
});
@ -973,6 +996,5 @@ main() {
expect(range[0], isBRElement);
expect(range[1], isBRElement);
});
});
}

View file

@ -51,7 +51,7 @@ main() {
element.dispatchEvent(event);
expect(invocationCounter, isZero);
var provider = new EventStreamProvider<CustomEvent>('test');
var provider = new EventStreamProvider<Event>('test');
var sub = provider.forTarget(element).listen(handler);
invocationCounter = 0;

View file

@ -425,6 +425,18 @@ interface MIDIOutput : MIDIPort {
[DartSuppress]
interface MutationEvent {};
// Tweaks types required for Dart strong mode.
[DartSupplemental]
interface HTMLCollection {
// FIXME: The index argument should not be optional.
getter Node? item([Default=Undefined] optional unsigned long index);
getter any namedItem(DOMString name);
[DartSuppress] getter Element? item([Default=Undefined] optional unsigned long index);
[DartSuppress] getter Element? namedItem(DOMString name);
};
Element implements GlobalEventHandlers;

View file

@ -114,7 +114,7 @@ _html_event_types = monitored.Dict('htmleventgenerator._html_event_types', {
'*.webkitfullscreenchange': ('fullscreenChange', 'Event'),
'*.webkitfullscreenerror': ('fullscreenError', 'Event'),
'*.wheel': ('wheel', 'WheelEvent'),
'AbstractWorker.error': ('error', 'ErrorEvent'),
'AbstractWorker.error': ('error', 'Event'),
'AudioContext.complete': ('complete', 'Event'),
'ApplicationCache.cached': ('cached', 'Event'),
'ApplicationCache.checking': ('checking', 'Event'),
@ -123,7 +123,7 @@ _html_event_types = monitored.Dict('htmleventgenerator._html_event_types', {
'ApplicationCache.obsolete': ('obsolete', 'Event'),
'ApplicationCache.progress': ('progress', 'ProgressEvent'),
'ApplicationCache.updateready': ('updateReady', 'Event'),
'CompositorWorker.error': ('error', 'ErrorEvent'),
'CompositorWorker.error': ('error', 'Event'),
'Document.readystatechange': ('readyStateChange', 'Event'),
'Document.securitypolicyviolation': ('securityPolicyViolation', 'SecurityPolicyViolationEvent'),
'Document.selectionchange': ('selectionChange', 'Event'),
@ -191,7 +191,7 @@ _html_event_types = monitored.Dict('htmleventgenerator._html_event_types', {
'RTCPeerConnection.removestream': ('removeStream', 'MediaStreamEvent'),
'RTCPeerConnection.signalingstatechange': ('signalingStateChange', 'Event'),
'ScriptProcessorNode.audioprocess': ('audioProcess', 'AudioProcessingEvent'),
'SharedWorker.error': ('error', 'ErrorEvent'),
'SharedWorker.error': ('error', 'Event'),
'SharedWorkerGlobalScope.connect': ('connect', 'Event'),
'SpeechRecognition.audioend': ('audioEnd', 'Event'),
'SpeechRecognition.audiostart': ('audioStart', 'Event'),
@ -223,7 +223,7 @@ _html_event_types = monitored.Dict('htmleventgenerator._html_event_types', {
'Window.pageshow': ('pageShow', 'Event'),
'Window.progress': ('progress', 'Event'),
'Window.webkittransitionend': ('webkitTransitionEnd', 'TransitionEvent'),
'Worker.error': ('error', 'ErrorEvent'),
'Worker.error': ('error', 'Event'),
'XMLHttpRequestEventTarget.abort': ('abort', 'ProgressEvent'),
'XMLHttpRequestEventTarget.error': ('error', 'ProgressEvent'),
'XMLHttpRequestEventTarget.load': ('load', 'ProgressEvent'),
@ -231,7 +231,7 @@ _html_event_types = monitored.Dict('htmleventgenerator._html_event_types', {
'XMLHttpRequestEventTarget.loadstart': ('loadStart', 'ProgressEvent'),
'XMLHttpRequestEventTarget.progress': ('progress', 'ProgressEvent'),
'XMLHttpRequestEventTarget.timeout': ('timeout', 'ProgressEvent'),
'XMLHttpRequest.readystatechange': ('readyStateChange', 'ProgressEvent'),
'XMLHttpRequest.readystatechange': ('readyStateChange', 'Event'),
})
# These classes require an explicit declaration for the "on" method even though

View file

@ -241,11 +241,14 @@ private_html_members = monitored.Set('htmlrenamer.private_html_members', [
'Document.title',
'Document.webkitCancelFullScreen',
'Document.webkitExitFullscreen',
# Not prefixed.
'Document.webkitFullscreenElement',
'Document.webkitFullscreenEnabled',
'Document.webkitHidden',
'Document.webkitIsFullScreen',
'Document.webkitVisibilityState',
# Not prefixed but requires custom implementation for cross-browser compatibility.
'Document.visibilityState',
'Element.animate',
'Element.children',
@ -509,6 +512,7 @@ for member in convert_to_future_members:
# subclasses.
# TODO(jacobr): cleanup and augment this list.
removed_html_members = monitored.Set('htmlrenamer.removed_html_members', [
'Attr.textContent', # Not needed as it is the same as Node.textContent.
'AudioBufferSourceNode.looping', # TODO(vsm): Use deprecated IDL annotation
'CSSStyleDeclaration.getPropertyCSSValue',
'CanvasRenderingContext2D.clearShadow',

View file

@ -58,6 +58,10 @@ _js_custom_members = monitored.Set('systemhtml._js_custom_members', [
'Document.createTreeWalker',
'DOMException.name',
'DOMException.toString',
# ListMixin already provides this method although the implementation
# is slower. As this class is obsolete anyway, we ignore the slowdown in
# DOMStringList performance.
'DOMStringList.contains',
'Element.animate',
'Element.createShadowRoot',
'Element.insertAdjacentElement',
@ -913,7 +917,8 @@ class Dart2JSBackend(HtmlDartGenerator):
# DomMatrixReadOnly and its subclass DomMatrix. Force the superclass
# to generate getters. Hardcoding the known problem classes for now.
# TODO(alanknight): Fix this more generally.
if (self._interface.id == 'DOMMatrixReadOnly' or self._interface.id == 'DOMPointReadOnly'):
if (self._interface.id == 'DOMMatrixReadOnly' or self._interface.id == 'DOMPointReadOnly'
or self._interface.id == 'DOMRectReadOnly'):
self._AddAttributeUsingProperties(attribute, html_name, read_only)
return

View file

@ -13,7 +13,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;
@ -45,10 +45,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;
@ -57,10 +58,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;
@ -91,11 +93,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);
}
@ -103,7 +105,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;
@ -128,11 +130,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);
}
@ -140,7 +142,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;
@ -174,11 +176,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;
@ -187,7 +189,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.
@ -205,7 +207,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));
@ -215,7 +217,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);

View file

@ -139,7 +139,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 {

View file

@ -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(String value);
bool contains(Object value);
/**
* Add the class [value] to element.
@ -93,7 +93,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.

View file

@ -10,7 +10,7 @@ part of html;
*/
class _ContentCssRect extends CssRect {
_ContentCssRect(element) : super(element);
_ContentCssRect(Element element) : super(element);
num get height => _element.offsetHeight +
_addOrSubtractToBoxModel(_HEIGHT, _CONTENT);
@ -31,9 +31,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");
}
}
@ -49,9 +51,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");
}
}
@ -68,7 +72,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;
}
@ -157,10 +161,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;
@ -253,6 +257,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'];

View file

@ -34,7 +34,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.
@ -58,7 +58,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);
}
/**
@ -129,8 +129,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;
@ -144,6 +144,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.
@ -154,7 +159,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;
});
@ -178,7 +183,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;
});
@ -188,37 +193,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();
}
@ -240,8 +254,7 @@ class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> {
}
// Remove current event listener.
_unlisten();
_onData = _wrapZone(handleData);
_onData = _wrapZone/*<Event, dynamic>*/(handleData);
_tryResume();
}
@ -320,8 +333,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;
@ -412,16 +425,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) {

View file

@ -16,7 +16,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;
@ -75,8 +75,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

View file

@ -4,7 +4,6 @@
part of dart.dom.html;
/**
* Class which helps construct standard node validation policies.
*
@ -22,11 +21,9 @@ part of dart.dom.html;
* appropriate.
*/
class NodeValidatorBuilder implements NodeValidator {
final List<NodeValidator> _validators = <NodeValidator>[];
NodeValidatorBuilder() {
}
NodeValidatorBuilder() {}
/**
* Creates a new NodeValidatorBuilder which accepts common constructs.
@ -155,29 +152,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));
}
/**
@ -192,37 +177,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);
}
@ -253,8 +227,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));
}
}
@ -265,76 +239,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',
]);
}
/**
@ -343,15 +311,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);
@ -384,19 +353,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) {
@ -406,12 +375,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;
}
@ -422,19 +393,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)) {
@ -445,14 +419,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) {
@ -462,7 +435,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) {

View file

@ -10,7 +10,7 @@ part of dart.dom.html;
*/
class _WrappedList<E extends Node> extends ListBase<E>
implements NodeListWrapper {
final List _list;
final List<Node> _list;
_WrappedList(this._list);
@ -30,13 +30,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);
@ -44,7 +44,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);
@ -67,7 +67,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);
@ -75,5 +75,5 @@ class _WrappedIterator<E> implements Iterator<E> {
return _iterator.moveNext();
}
E get current => _iterator.current;
E get current => _iterator.current as E;
}

View file

@ -120,11 +120,11 @@ class _ElementCssClassSet extends CssClassSetImpl {
_addAll(_element, iterable);
}
void removeAll(Iterable<String> iterable) {
void removeAll(Iterable<Object> iterable) {
_removeAll(_element, iterable);
}
void retainAll(Iterable<String> iterable) {
void retainAll(Iterable<Object> iterable) {
_removeWhere(_element, iterable.toSet().contains, false);
}

View file

@ -57,7 +57,7 @@ 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
@ -68,8 +68,8 @@ class _DOMWindowCrossFrame implements WindowBase {
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(
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,

View file

@ -59,8 +59,8 @@ class _WrappedEvent implements Event {
throw new UnsupportedError('Cannot call matchingTarget if this Event did'
' not arise as a result of event delegation.');
}
var currentTarget = this.currentTarget;
var target = this.target;
Element currentTarget = this.currentTarget;
Element target = this.target;
var matchedTarget;
do {
if (target.matches(_selector)) return target;

View file

@ -4,17 +4,25 @@
part of dart.dom.html;
_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>*/;
}
/**

View file

@ -115,4 +115,17 @@ $if DART2JS
=> JS('TreeWalker', '#.createTreeWalker(#, #, #, false)',
this, root, whatToShow, filter);
$endif
@DomName('Document.visibilityState')
@SupportedBrowser(SupportedBrowser.CHROME)
@SupportedBrowser(SupportedBrowser.FIREFOX)
@SupportedBrowser(SupportedBrowser.IE, '10')
@Experimental()
$if DART2JS
String get visibilityState => JS('String',
'(#.visibilityState || #.mozVisibilityState || #.msVisibilityState ||'
'#.webkitVisibilityState)', this, this, this, this);
$else
String get visibilityState => _visibilityState;
$endif
}

View file

@ -40,7 +40,7 @@ $endif
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);

View file

@ -71,7 +71,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));
@ -593,7 +593,7 @@ $endif
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);
@ -828,19 +828,18 @@ $endif
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) {
$if DART2JS
convertedFrames = frames.map(convertDartToNative_Dictionary).toList();
$else
convertedFrames = convertDartToNative_List(
frames.map(convertDartToNative_Dictionary).toList());
$endif
} 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);

View file

@ -52,7 +52,10 @@ $(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$IMPLEMENTS
}
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);

View file

@ -127,65 +127,6 @@ $endif
_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()
$if DART2JS
String get visibilityState => JS('String',
'(#.visibilityState || #.mozVisibilityState || #.msVisibilityState ||'
'#.webkitVisibilityState)', this, this, this, this);
$else
String get visibilityState => _webkitVisibilityState;
$endif
$if DARTIUM
/**

View file

@ -28,7 +28,7 @@ $(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS 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.

View file

@ -10,8 +10,7 @@ $!MEMBERS
// 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);
}

View file

@ -10,7 +10,7 @@ $(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$IMPLEMENTS
factory $CLASSNAME(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;
}

View file

@ -213,7 +213,7 @@ $endif
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);

View file

@ -37,11 +37,11 @@ $(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS
}
// 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); }
@ -50,7 +50,7 @@ $(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS
return this[key];
}
String remove(String key) {
String remove(Object key) {
final value = this[key];
_removeItem(key);
return value;
@ -68,13 +68,13 @@ $(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS
}
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;
}

View file

@ -115,7 +115,7 @@ $if DART2JS
@DomName('Window.requestAnimationFrame')
int requestAnimationFrame(FrameRequestCallback callback) {
_ensureRequestAnimationFrame();
return _requestAnimationFrame(_wrapZone(callback));
return _requestAnimationFrame(_wrapZone/*<num, dynamic>*/(callback));
}
/**
@ -341,12 +341,11 @@ class _BeforeUnloadEventStreamProvider implements
Stream<BeforeUnloadEvent> forTarget(EventTarget e, {bool useCapture: false}) {
var stream = new _EventStream(e, _eventType, useCapture);
$if DART2JS
var controller = new StreamController(sync: true);
var controller = new StreamController<BeforeUnloadEvent>(sync: true);
stream.listen((event) {
var wrapped = new _BeforeUnloadEvent(event);
controller.add(wrapped);
return wrapped.returnValue;
});
return controller.stream;