diff --git a/lib/web_ui/lib/src/engine/dom.dart b/lib/web_ui/lib/src/engine/dom.dart index 4a5ad17889a90..26ed2f9674025 100644 --- a/lib/web_ui/lib/src/engine/dom.dart +++ b/lib/web_ui/lib/src/engine/dom.dart @@ -520,6 +520,8 @@ extension DomElementExtension on DomElement { Iterable get children => createDomListWrapper(_children); + external DomElement? get firstElementChild; + @JS('clientHeight') external JSNumber get _clientHeight; double get clientHeight => _clientHeight.toDart; 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 28aeb8da0855e..b6ef99a39d965 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 @@ -60,6 +60,17 @@ class PlatformViewManager { return _contents.containsKey(viewId); } + /// Returns the HTML element created by a registered factory for [viewId]. + /// + /// Throws an [AssertionError] if [viewId] hasn't been rendered before. + DomElement getViewById(int viewId) { + assert(knowsViewId(viewId), 'No view has been rendered for viewId: $viewId'); + // `_contents[viewId]` is the element created by us. The + // first (and only) child of that is the element created by the user-supplied + // factory function. + return _contents[viewId]!.firstElementChild!; + } + /// Registers a `factoryFunction` that knows how to render a Platform View of `viewType`. /// /// `viewType` is selected by the programmer, but it can't be overridden once @@ -119,12 +130,13 @@ class PlatformViewManager { ..setAttribute('slot', slotName); final Function factoryFunction = _factories[viewType]!; - late DomElement content; + final DomElement content; if (factoryFunction is ParameterizedPlatformViewFactory) { content = factoryFunction(viewId, params: params); } else { - content = (factoryFunction as PlatformViewFactory).call(viewId); + factoryFunction as PlatformViewFactory; + content = factoryFunction(viewId); } _ensureContentCorrectlySized(content, viewType); 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 1d4e77d23d588..45bb823b23597 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 @@ -23,4 +23,11 @@ class PlatformViewRegistry { isVisible: isVisible, ); } + + /// Returns the view previously created for [viewId]. + /// + /// Throws if no view has been created for [viewId]. + Object getViewById(int viewId) { + return platformViewManager.getViewById(viewId); + } } 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 354471a0459aa..0502984a61b3f 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 @@ -145,5 +145,63 @@ void testMain() { expect(firstRender, same(anotherRender)); }); }); + + group('getViewById', () { + test('finds created views', () async { + final Map views1 = { + 1: createDomHTMLDivElement(), + 2: createDomHTMLDivElement(), + 5: createDomHTMLDivElement(), + }; + final Map views2 = { + 3: createDomHTMLDivElement(), + 4: createDomHTMLDivElement(), + }; + + contentManager.registerFactory('forTest1', (int id) => views1[id]!); + contentManager.registerFactory('forTest2', (int id) => views2[id]!); + + // Render all 5 views. + for (final int id in views1.keys) { + contentManager.renderContent('forTest1', id, null); + } + for (final int id in views2.keys) { + contentManager.renderContent('forTest2', id, null); + } + + // Check all 5 views. + for (final int id in views1.keys) { + expect(contentManager.getViewById(id), views1[id]); + } + for (final int id in views2.keys) { + expect(contentManager.getViewById(id), views2[id]); + } + + // Throws for unknown viewId. + expect(() { + contentManager.getViewById(99); + }, throwsA(isA())); + }); + + test('throws if view has been cleared', () { + final DomHTMLDivElement view = createDomHTMLDivElement(); + contentManager.registerFactory(viewType, (int id) => view); + + // Throws before viewId is rendered. + expect(() { + contentManager.getViewById(viewId); + }, throwsA(isA())); + + contentManager.renderContent(viewType, viewId, null); + // Succeeds after viewId is rendered. + expect(contentManager.getViewById(viewId), view); + + contentManager.clearPlatformView(viewId); + // Throws after viewId is cleared. + expect(() { + contentManager.getViewById(viewId); + }, throwsA(isA())); + }); + }); }); }