From 44b63ca0d31ecc6eafcb8a7c86e57dc2a3dd2aad Mon Sep 17 00:00:00 2001 From: Mouad Debbar Date: Wed, 19 Jul 2023 16:05:51 -0400 Subject: [PATCH 1/4] [web] Provide convenient default factories for platform views --- .../platform_views/content_manager.dart | 32 +++++++++++ .../platform_views/content_manager_test.dart | 56 ++++++++++++++++--- 2 files changed, 80 insertions(+), 8 deletions(-) diff --git a/lib/web_ui/lib/src/engine/platform_views/content_manager.dart b/lib/web_ui/lib/src/engine/platform_views/content_manager.dart index 288ab4374a32e..8889b06a52714 100644 --- a/lib/web_ui/lib/src/engine/platform_views/content_manager.dart +++ b/lib/web_ui/lib/src/engine/platform_views/content_manager.dart @@ -10,6 +10,10 @@ import '../embedder.dart'; import '../util.dart'; import 'slots.dart'; +// Keep these values in sync with the ones used in the framework's `HtmlElementView`. +const String _kDefaultVisibleViewType = '_default_document_create_element_visible'; +const String _kDefaultInvisibleViewType = '_default_document_create_element_invisible'; + /// This class handles the lifecycle of Platform Views in the DOM of a Flutter Web App. /// /// There are three important parts of Platform Views. This class manages two of @@ -25,6 +29,19 @@ import 'slots.dart'; /// This class keeps a registry of `factories`, `contents` so the framework can /// CRUD Platform Views as needed, regardless of the rendering backend. class PlatformViewManager { + PlatformViewManager() { + // Register some default factories. + registerFactory( + _kDefaultVisibleViewType, + _defaultFactory, + ); + registerFactory( + _kDefaultInvisibleViewType, + _defaultFactory, + isVisible: false, + ); + } + // The factory functions, indexed by the viewType final Map _factories = {}; @@ -223,3 +240,18 @@ class PlatformViewManager { return result; } } + +DomElement _defaultFactory( + int viewId, { + Object? params, +}) { + params!; + params as _DefaultFactoryParams; + return domDocument.createElement(params.tagName); +} + +typedef _DefaultFactoryParams = Map; + +extension on _DefaultFactoryParams { + String get tagName => this['tagName']! as String; +} diff --git a/lib/web_ui/test/engine/platform_views/content_manager_test.dart b/lib/web_ui/test/engine/platform_views/content_manager_test.dart index 0502984a61b3f..4c481c171efd5 100644 --- a/lib/web_ui/test/engine/platform_views/content_manager_test.dart +++ b/lib/web_ui/test/engine/platform_views/content_manager_test.dart @@ -6,7 +6,8 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; -import '../../common/matchers.dart'; +const String _kDefaultVisibleViewType = '_default_document_create_element_visible'; +const String _kDefaultInvisibleViewType = '_default_document_create_element_invisible'; void main() { internalBootstrapBrowserTest(() => testMain); @@ -97,13 +98,14 @@ void testMain() { }); test('refuse to render views for unregistered factories', () async { - try { - contentManager.renderContent(unregisteredViewType, viewId, null); - fail('renderContent should have thrown an Assertion error!'); - } catch (e) { - expect(e, isAssertionError); - expect((e as AssertionError).message, contains(unregisteredViewType)); - } + expect( + () => contentManager.renderContent(unregisteredViewType, viewId, null), + throwsA(const TypeMatcher().having( + (AssertionError error) => error.message, + 'assertion message', + contains(unregisteredViewType), + )), + ); }); test('rendered markup contains required attributes', () async { @@ -203,5 +205,43 @@ void testMain() { }, throwsA(isA())); }); }); + + test('default factories', () { + final DomElement content0 = contentManager.renderContent( + _kDefaultVisibleViewType, + viewId, + {'tagName': 'table'}, + ); + expect( + contentManager.getViewById(viewId), + content0.querySelector('table'), + ); + expect(contentManager.isVisible(viewId), isTrue); + expect(contentManager.isInvisible(viewId), isFalse); + + final DomElement content1 = contentManager.renderContent( + _kDefaultInvisibleViewType, + viewId + 1, + {'tagName': 'script'}, + ); + expect( + contentManager.getViewById(viewId + 1), + content1.querySelector('script'), + ); + expect(contentManager.isVisible(viewId + 1), isFalse); + expect(contentManager.isInvisible(viewId + 1), isTrue); + + final DomElement content2 = contentManager.renderContent( + _kDefaultVisibleViewType, + viewId + 2, + {'tagName': 'p'}, + ); + expect( + contentManager.getViewById(viewId + 2), + content2.querySelector('p'), + ); + expect(contentManager.isVisible(viewId + 2), isTrue); + expect(contentManager.isInvisible(viewId + 2), isFalse); + }); }); } From 3d183aeb70ce1f567b5dcc7c7917a587f4b94927 Mon Sep 17 00:00:00 2001 From: Mouad Debbar Date: Tue, 25 Jul 2023 13:14:56 -0400 Subject: [PATCH 2/4] move view types to dart:ui_web --- .../src/engine/platform_views/content_manager.dart | 8 ++------ .../ui_web/src/ui_web/platform_view_registry.dart | 12 ++++++++++++ .../engine/platform_views/content_manager_test.dart | 10 ++++------ 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/lib/web_ui/lib/src/engine/platform_views/content_manager.dart b/lib/web_ui/lib/src/engine/platform_views/content_manager.dart index 8889b06a52714..0b83440ed9df2 100644 --- a/lib/web_ui/lib/src/engine/platform_views/content_manager.dart +++ b/lib/web_ui/lib/src/engine/platform_views/content_manager.dart @@ -10,10 +10,6 @@ import '../embedder.dart'; import '../util.dart'; import 'slots.dart'; -// Keep these values in sync with the ones used in the framework's `HtmlElementView`. -const String _kDefaultVisibleViewType = '_default_document_create_element_visible'; -const String _kDefaultInvisibleViewType = '_default_document_create_element_invisible'; - /// This class handles the lifecycle of Platform Views in the DOM of a Flutter Web App. /// /// There are three important parts of Platform Views. This class manages two of @@ -32,11 +28,11 @@ class PlatformViewManager { PlatformViewManager() { // Register some default factories. registerFactory( - _kDefaultVisibleViewType, + ui_web.kDefaultVisibleViewType, _defaultFactory, ); registerFactory( - _kDefaultInvisibleViewType, + ui_web.kDefaultInvisibleViewType, _defaultFactory, isVisible: false, ); diff --git a/lib/web_ui/lib/ui_web/src/ui_web/platform_view_registry.dart b/lib/web_ui/lib/ui_web/src/ui_web/platform_view_registry.dart index ff9312f11da09..15e8cfd2eff7f 100644 --- a/lib/web_ui/lib/ui_web/src/ui_web/platform_view_registry.dart +++ b/lib/web_ui/lib/ui_web/src/ui_web/platform_view_registry.dart @@ -4,6 +4,18 @@ import 'package:ui/src/engine.dart'; +/// The view type of the factory that creates visible platform view DOM elements. +/// +/// There's no need to register this view type with [PlatformViewRegistry] +/// because it is registered by default. +const String kDefaultVisibleViewType = '_default_document_create_element_visible'; + +/// The view type of the factory that creates invisible platform view DOM elements. +/// +/// There's no need to register this view type with [PlatformViewRegistry] +/// because it is registered by default. +const String kDefaultInvisibleViewType = '_default_document_create_element_invisible'; + /// A function which takes a unique `id` and some `params` and creates an HTML /// element. typedef ParameterizedPlatformViewFactory = Object Function( diff --git a/lib/web_ui/test/engine/platform_views/content_manager_test.dart b/lib/web_ui/test/engine/platform_views/content_manager_test.dart index 4c481c171efd5..a252b4bf8ef5c 100644 --- a/lib/web_ui/test/engine/platform_views/content_manager_test.dart +++ b/lib/web_ui/test/engine/platform_views/content_manager_test.dart @@ -5,9 +5,7 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; - -const String _kDefaultVisibleViewType = '_default_document_create_element_visible'; -const String _kDefaultInvisibleViewType = '_default_document_create_element_invisible'; +import 'package:ui/ui_web/src/ui_web.dart' as ui_web; void main() { internalBootstrapBrowserTest(() => testMain); @@ -208,7 +206,7 @@ void testMain() { test('default factories', () { final DomElement content0 = contentManager.renderContent( - _kDefaultVisibleViewType, + ui_web.kDefaultVisibleViewType, viewId, {'tagName': 'table'}, ); @@ -220,7 +218,7 @@ void testMain() { expect(contentManager.isInvisible(viewId), isFalse); final DomElement content1 = contentManager.renderContent( - _kDefaultInvisibleViewType, + ui_web.kDefaultInvisibleViewType, viewId + 1, {'tagName': 'script'}, ); @@ -232,7 +230,7 @@ void testMain() { expect(contentManager.isInvisible(viewId + 1), isTrue); final DomElement content2 = contentManager.renderContent( - _kDefaultVisibleViewType, + ui_web.kDefaultVisibleViewType, viewId + 2, {'tagName': 'p'}, ); From 44ffc05c453d02252f88d022292844783e561167 Mon Sep 17 00:00:00 2001 From: Mouad Debbar Date: Tue, 25 Jul 2023 13:15:15 -0400 Subject: [PATCH 3/4] remove unnecessary extension --- .../lib/src/engine/platform_views/content_manager.dart | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/lib/web_ui/lib/src/engine/platform_views/content_manager.dart b/lib/web_ui/lib/src/engine/platform_views/content_manager.dart index 0b83440ed9df2..85074a06b3c49 100644 --- a/lib/web_ui/lib/src/engine/platform_views/content_manager.dart +++ b/lib/web_ui/lib/src/engine/platform_views/content_manager.dart @@ -242,12 +242,6 @@ DomElement _defaultFactory( Object? params, }) { params!; - params as _DefaultFactoryParams; - return domDocument.createElement(params.tagName); -} - -typedef _DefaultFactoryParams = Map; - -extension on _DefaultFactoryParams { - String get tagName => this['tagName']! as String; + params as Map; + return domDocument.createElement(params.readString('tagName')); } From ad3774e56fde0499141b13cb5a6e4e61bb9e466a Mon Sep 17 00:00:00 2001 From: Mouad Debbar Date: Wed, 26 Jul 2023 10:22:02 -0400 Subject: [PATCH 4/4] make constants into statics on PlatformViewRegistry --- .../platform_views/content_manager.dart | 4 +-- .../src/ui_web/platform_view_registry.dart | 26 ++++++++++--------- .../platform_views/content_manager_test.dart | 6 ++--- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/lib/web_ui/lib/src/engine/platform_views/content_manager.dart b/lib/web_ui/lib/src/engine/platform_views/content_manager.dart index 85074a06b3c49..b5579bc4def25 100644 --- a/lib/web_ui/lib/src/engine/platform_views/content_manager.dart +++ b/lib/web_ui/lib/src/engine/platform_views/content_manager.dart @@ -28,11 +28,11 @@ class PlatformViewManager { PlatformViewManager() { // Register some default factories. registerFactory( - ui_web.kDefaultVisibleViewType, + ui_web.PlatformViewRegistry.defaultVisibleViewType, _defaultFactory, ); registerFactory( - ui_web.kDefaultInvisibleViewType, + ui_web.PlatformViewRegistry.defaultInvisibleViewType, _defaultFactory, isVisible: false, ); diff --git a/lib/web_ui/lib/ui_web/src/ui_web/platform_view_registry.dart b/lib/web_ui/lib/ui_web/src/ui_web/platform_view_registry.dart index 15e8cfd2eff7f..e33e8ebc53199 100644 --- a/lib/web_ui/lib/ui_web/src/ui_web/platform_view_registry.dart +++ b/lib/web_ui/lib/ui_web/src/ui_web/platform_view_registry.dart @@ -4,18 +4,6 @@ import 'package:ui/src/engine.dart'; -/// The view type of the factory that creates visible platform view DOM elements. -/// -/// There's no need to register this view type with [PlatformViewRegistry] -/// because it is registered by default. -const String kDefaultVisibleViewType = '_default_document_create_element_visible'; - -/// The view type of the factory that creates invisible platform view DOM elements. -/// -/// There's no need to register this view type with [PlatformViewRegistry] -/// because it is registered by default. -const String kDefaultInvisibleViewType = '_default_document_create_element_invisible'; - /// A function which takes a unique `id` and some `params` and creates an HTML /// element. typedef ParameterizedPlatformViewFactory = Object Function( @@ -31,6 +19,20 @@ final PlatformViewRegistry platformViewRegistry = PlatformViewRegistry(); /// A registry for factories that create platform views. class PlatformViewRegistry { + /// The view type of the built-in factory that creates visible platform view + /// DOM elements. + /// + /// There's no need to register this view type with [PlatformViewRegistry] + /// because it is registered by default. + static const String defaultVisibleViewType = '_default_document_create_element_visible'; + + /// The view type of the built-in factory that creates invisible platform view + /// DOM elements. + /// + /// There's no need to register this view type with [PlatformViewRegistry] + /// because it is registered by default. + static const String defaultInvisibleViewType = '_default_document_create_element_invisible'; + /// Register [viewType] as being created by the given [viewFactory]. /// /// [viewFactory] can be any function that takes an integer and optional diff --git a/lib/web_ui/test/engine/platform_views/content_manager_test.dart b/lib/web_ui/test/engine/platform_views/content_manager_test.dart index a252b4bf8ef5c..214d46d079dc0 100644 --- a/lib/web_ui/test/engine/platform_views/content_manager_test.dart +++ b/lib/web_ui/test/engine/platform_views/content_manager_test.dart @@ -206,7 +206,7 @@ void testMain() { test('default factories', () { final DomElement content0 = contentManager.renderContent( - ui_web.kDefaultVisibleViewType, + ui_web.PlatformViewRegistry.defaultVisibleViewType, viewId, {'tagName': 'table'}, ); @@ -218,7 +218,7 @@ void testMain() { expect(contentManager.isInvisible(viewId), isFalse); final DomElement content1 = contentManager.renderContent( - ui_web.kDefaultInvisibleViewType, + ui_web.PlatformViewRegistry.defaultInvisibleViewType, viewId + 1, {'tagName': 'script'}, ); @@ -230,7 +230,7 @@ void testMain() { expect(contentManager.isInvisible(viewId + 1), isTrue); final DomElement content2 = contentManager.renderContent( - ui_web.kDefaultVisibleViewType, + ui_web.PlatformViewRegistry.defaultVisibleViewType, viewId + 2, {'tagName': 'p'}, );