Added support for members of type Promise.
Fixes #31046
R=sra@google.com
Change-Id: Id1e8d415b91a842bd8e2f50c6064c24aaaed9d98
Reviewed-on: https://dart-review.googlesource.com/59460
Reviewed-by: Stephen Adams <sra@google.com>
Commit-Queue: Terry Lucas <terry@google.com>
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 843e633..ee8e653 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -870,7 +870,8 @@
@DomName('Animation.finished')
@DocsEditable()
@Experimental() // untriaged
- final Future finished;
+ Future<Animation> get finished =>
+ promiseToFuture<Animation>(JS("", "#.finished", this));
@DomName('Animation.id')
@DocsEditable()
@@ -890,7 +891,8 @@
@DomName('Animation.ready')
@DocsEditable()
@Experimental() // untriaged
- final Future ready;
+ Future<Animation> get ready =>
+ promiseToFuture<Animation>(JS("", "#.ready", this));
@DomName('Animation.startTime')
@DocsEditable()
@@ -2118,7 +2120,8 @@
@DomName('BeforeInstallPromptEvent.userChoice')
@DocsEditable()
@Experimental() // untriaged
- final Future userChoice;
+ Future<Map<String, dynamic>> get userChoice =>
+ promiseToFutureAsMap(JS("", "#.userChoice", this));
@DomName('BeforeInstallPromptEvent.prompt')
@DocsEditable()
@@ -19387,7 +19390,8 @@
@DomName('FetchEvent.preloadResponse')
@DocsEditable()
@Experimental() // untriaged
- final Future preloadResponse;
+ Future get preloadResponse =>
+ promiseToFuture(JS("", "#.preloadResponse", this));
@DomName('FetchEvent.request')
@DocsEditable()
@@ -20108,7 +20112,8 @@
@DomName('FontFace.loaded')
@DocsEditable()
@Experimental() // untriaged
- final Future loaded;
+ Future<FontFace> get loaded =>
+ promiseToFuture<FontFace>(JS("", "#.loaded", this));
@DomName('FontFace.status')
@DocsEditable()
@@ -25820,7 +25825,7 @@
@DomName('MediaKeySession.closed')
@DocsEditable()
@Experimental() // untriaged
- final Future closed;
+ Future<void> get closed => promiseToFuture<void>(JS("", "#.closed", this));
@DomName('MediaKeySession.expiration')
@DocsEditable()
@@ -33137,7 +33142,9 @@
@DomName('PresentationReceiver.connectionList')
@DocsEditable()
@Experimental() // untriaged
- final Future connectionList;
+ Future<PresentationConnectionList> get connectionList =>
+ promiseToFuture<PresentationConnectionList>(
+ JS("", "#.connectionList", this));
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
@@ -33330,7 +33337,7 @@
@DomName('PromiseRejectionEvent.promise')
@DocsEditable()
@Experimental() // untriaged
- final Future promise;
+ Future get promise => promiseToFuture(JS("", "#.promise", this));
@DomName('PromiseRejectionEvent.reason')
@DocsEditable()
@@ -36013,7 +36020,8 @@
@DomName('ServiceWorkerContainer.ready')
@DocsEditable()
@Experimental() // untriaged
- final Future ready;
+ Future<ServiceWorkerRegistration> get ready =>
+ promiseToFuture<ServiceWorkerRegistration>(JS("", "#.ready", this));
@DomName('ServiceWorkerContainer.getRegistration')
@DocsEditable()
diff --git a/tests/html/html.status b/tests/html/html.status
index 9fe79e4..f83e0c7 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -401,7 +401,6 @@
[ $compiler == dart2js && $browser ]
custom/created_callback_test: Fail # Support for created constructor. Issue 14835
-fontface_loaded_test: Fail # Support for promises.
[ $compiler == dart2js && $browser && $csp ]
custom/element_upgrade_test: Fail # Issue 17298
diff --git a/tests/lib_2/html/fontface_loaded_test.dart b/tests/lib_2/html/fontface_loaded_test.dart
index a9334b6..a4670e7 100644
--- a/tests/lib_2/html/fontface_loaded_test.dart
+++ b/tests/lib_2/html/fontface_loaded_test.dart
@@ -32,22 +32,28 @@
treeSanitizer: new NullTreeSanitizer());
document.head.append(style);
- test('document fonts - temporary', () {
+ test('document fonts - temporary', () async {
var atLeastOneFont = false;
- var loaded = <Future>[];
- document.fonts.forEach((FontFace fontFace, _, __) {
+ var loaded = <Future<FontFace>>[];
+ document.fonts.forEach((FontFace fontFace, _, __) async {
atLeastOneFont = true;
- Future f1 = fontFace.loaded;
- Future f2 = fontFace.loaded;
+ var f1 = fontFace.loaded;
+ var f2 = fontFace.loaded;
loaded.add(fontFace.load());
loaded.add(f1);
loaded.add(f2);
});
expect(atLeastOneFont, isTrue);
- return Future.wait(loaded).then(expectAsync((_) {
+ return Future.wait(loaded).then(expectAsync((_) async {
document.fonts.forEach((fontFace, _, __) {
expect(fontFace.status, 'loaded');
});
+ expect(loaded.length, 3);
+ for (var loadedEntry in loaded) {
+ var fontFace = await loadedEntry;
+ expect(fontFace.status, 'loaded');
+ expect(fontFace.family, 'Ahem');
+ }
}));
});
}
diff --git a/tests/lib_2/lib_2_dart2js.status b/tests/lib_2/lib_2_dart2js.status
index e3b55be..695151b 100644
--- a/tests/lib_2/lib_2_dart2js.status
+++ b/tests/lib_2/lib_2_dart2js.status
@@ -186,6 +186,7 @@
html/fileapi_supported_throws_test: RuntimeError
html/filereader_test: RuntimeError
html/filteredelementlist_test: RuntimeError
+html/fontface_loaded_test: RuntimeError
html/fontface_test: RuntimeError
html/form_data_test: RuntimeError
html/form_element_test: RuntimeError
@@ -339,7 +340,6 @@
collection/list_test: RuntimeError
[ $compiler == dart2js && $runtime != d8 && $runtime != jsshell ]
-html/fontface_loaded_test: RuntimeError
html/html_mock_test: RuntimeError # Issue 31038
html/input_element_attributes_test: RuntimeError
html/js_dart_functions_test: RuntimeError # does not implement Dart 2 implicit `.call` tearoff
@@ -474,7 +474,6 @@
[ $compiler == dart2js && $browser ]
html/custom/created_callback_test: RuntimeError
-html/fontface_loaded_test: Fail # Support for promises.
html/js_typed_interop_lazy_test/01: RuntimeError
html/notification_permission_test: Timeout, Pass # Issue 32002
html/private_extension_member_test: RuntimeError
@@ -688,7 +687,6 @@
[ $compiler == dart2js && $fasta && $host_checked ]
html/custom/mirrors_2_test: Crash # 'file:*/pkg/compiler/lib/src/common_elements.dart': Failed assertion: line 405 pos 12: 'element.name == '=='': is not true.
html/custom/mirrors_test: Crash # 'file:*/pkg/compiler/lib/src/common_elements.dart': Failed assertion: line 405 pos 12: 'element.name == '=='': is not true.
-html/fontface_loaded_test: RuntimeError # TypeError: Cannot read property 'createFragment$3$treeSanitizer$validator' of undefined
html/indexeddb_3_test: Crash # 'file:*/pkg/compiler/lib/src/common_elements.dart': Failed assertion: line 405 pos 12: 'element.name == '=='': is not true.
html/indexeddb_5_test: Crash # 'file:*/pkg/compiler/lib/src/common_elements.dart': Failed assertion: line 405 pos 12: 'element.name == '=='': is not true.
html/js_array_test: CompileTimeError
@@ -725,7 +723,6 @@
html/event_customevent_test: RuntimeError
html/file_sample_test: RuntimeError
html/fileapi_entry_test: RuntimeError
-html/fontface_loaded_test: RuntimeError
html/indexeddb_1_test/functional: RuntimeError
html/indexeddb_2_test: RuntimeError
html/indexeddb_3_test: RuntimeError
diff --git a/tests/lib_2/lib_2_dartdevc.status b/tests/lib_2/lib_2_dartdevc.status
index bbfa3a4..db43afe 100644
--- a/tests/lib_2/lib_2_dartdevc.status
+++ b/tests/lib_2/lib_2_dartdevc.status
@@ -82,7 +82,6 @@
html/custom_elements_test: Skip # Issue 29922
html/deferred_multi_app_htmltest: Skip # Issue 29919
html/element_classes_test: RuntimeError # Issue 29922
-html/fontface_loaded_test: RuntimeError
html/isolates_test: RuntimeError # Issue 29922
html/js_typed_interop_default_arg_test/default_value: MissingCompileTimeError # Issue 29922
html/js_typed_interop_side_cast_exp_test/01: RuntimeError # Requires --experimental-trust-js-interop-type-annotations flag.
diff --git a/tools/dom/scripts/systemhtml.py b/tools/dom/scripts/systemhtml.py
index 324900c..458d810 100644
--- a/tools/dom/scripts/systemhtml.py
+++ b/tools/dom/scripts/systemhtml.py
@@ -771,12 +771,14 @@
parameterized Promise type.
'''
promise_attributes = monitored.Dict('systemhtml.promise_attr_type', {
- "Animation.finished": {"type": "Animation"},
- "Animation.ready": {"type": "Animation"},
- "FontFace.loaded": {"type": "FontFace"},
- "FontFaceSet.ready": {"type": "FontFaceSet"},
- "PresentationReceiver.connectionList": {"type": "PresentationConnectionList"},
- "ServiceWorkerContainer.ready": {"type": "ServiceWorkerRegistration"},
+ "Animation.finished": {"type": "Animation"},
+ "Animation.ready": {"type": "Animation"},
+ "BeforeInstallPromptEvent.userChoice": {"type": "dictionary"},
+ "FontFace.loaded": {"type": "FontFace"},
+ "FontFaceSet.ready": {"type": "FontFaceSet"},
+ "MediaKeySession.closed": {"type": "void"},
+ "PresentationReceiver.connectionList": {"type": "PresentationConnectionList"},
+ "ServiceWorkerContainer.ready": {"type": "ServiceWorkerRegistration"},
})
promise_operations = monitored.Dict('systemhtml.promise_oper_type', {
@@ -1125,6 +1127,8 @@
metadata = self._Metadata(attribute.type.id, attribute.id, output_type)
rename = self._RenamingAnnotation(attribute.id, html_name)
if not read_only:
+ if attribute.type.id == 'Promise':
+ _logger.warn('R/W member is a Promise: %s.%s' % (self._interface.id, html_name))
self._members_emitter.Emit(
'\n $RENAME$METADATA$TYPE $NAME;'
'\n',
@@ -1134,17 +1138,44 @@
TYPE=output_type)
else:
template = '\n $RENAME$(ANNOTATIONS)final $TYPE $NAME;\n'
- # Need to use a getter for list.length properties so we can add a
- # setter which throws an exception, satisfying List API.
- if self._interface_type_info.list_item_type() and html_name == 'length':
- template = ('\n $RENAME$(ANNOTATIONS)$TYPE get $NAME => ' +
- 'JS("$TYPE", "#.$NAME", this);\n')
- self._members_emitter.Emit(
- template,
- RENAME=rename,
- ANNOTATIONS=metadata,
- NAME=html_name,
- TYPE=input_type if output_type == 'double' else output_type)
+ if attribute.type.id == 'Promise':
+ lookupOp = "%s.%s" % (self._interface.id, html_name)
+ promiseFound = _GetPromiseAttributeType(lookupOp)
+ promiseType = 'Future'
+ promiseCall = 'promiseToFuture'
+ if promiseFound is not (None):
+ if 'maplike' in promiseFound:
+ promiseCall = 'promiseToFuture<dynamic>'
+ promiseType = 'Future'
+ elif promiseFound['type'] == 'dictionary':
+ # It's a dictionary so return as a Map.
+ promiseCall = 'promiseToFutureAsMap'
+ promiseType = 'Future<Map<String, dynamic>>'
+ else:
+ paramType = promiseFound['type']
+ promiseCall = 'promiseToFuture<%s>' % paramType
+ promiseType = 'Future<%s>' % paramType
+
+ template = '\n $RENAME$(ANNOTATIONS)$TYPE get $NAME => $PROMISE_CALL(JS("", "#.$NAME", this));\n'
+
+ self._members_emitter.Emit(template,
+ RENAME=rename,
+ ANNOTATIONS=metadata,
+ TYPE=promiseType,
+ PROMISE_CALL=promiseCall,
+ NAME=html_name)
+ else:
+ # Need to use a getter for list.length properties so we can add a
+ # setter which throws an exception, satisfying List API.
+ if self._interface_type_info.list_item_type() and html_name == 'length':
+ template = ('\n $RENAME$(ANNOTATIONS)$TYPE get $NAME => ' +
+ 'JS("$TYPE", "#.$NAME", this);\n')
+ self._members_emitter.Emit(
+ template,
+ RENAME=rename,
+ ANNOTATIONS=metadata,
+ NAME=html_name,
+ TYPE=input_type if output_type == 'double' else output_type)
def _AddAttributeUsingProperties(self, attribute, html_name, read_only):
self._AddRenamingGetter(attribute, html_name)