mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 04:57:43 +00:00
Strong html
BUG= R=alanknight@google.com Review URL: https://codereview.chromium.org/1894713002 .
This commit is contained in:
parent
e072ae33c6
commit
864b64fd5e
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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'];
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>*/;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
/**
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue