Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/web_ui/lib/src/engine/dom.dart
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,8 @@ extension DomElementExtension on DomElement {
Iterable<DomElement> get children =>
createDomListWrapper<DomElement>(_children);

external DomElement? get firstElementChild;

@JS('clientHeight')
external JSNumber get _clientHeight;
double get clientHeight => _clientHeight.toDart;
Expand Down
16 changes: 14 additions & 2 deletions lib/web_ui/lib/src/engine/platform_views/content_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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 <flt-platform-view> 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!;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, document that we return the firstElementChild because we cache the created view wrapped with the <flt-slot-content> tag (right?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_contents[viewId] is the wrapper (i.e. the slot element). The first child of the slot is the element created by the factory.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I think this is exactly what you are saying. Sorry I misread your comment.

Sounds good, I'll document why I'm returning 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
Expand Down Expand Up @@ -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);
Expand Down
7 changes: 7 additions & 0 deletions lib/web_ui/lib/ui_web/src/ui_web/platform_view_registry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
58 changes: 58 additions & 0 deletions lib/web_ui/test/engine/platform_views/content_manager_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -145,5 +145,63 @@ void testMain() {
expect(firstRender, same(anotherRender));
});
});

group('getViewById', () {
test('finds created views', () async {
final Map<int, DomElement> views1 = <int, DomElement>{
1: createDomHTMLDivElement(),
2: createDomHTMLDivElement(),
5: createDomHTMLDivElement(),
};
final Map<int, DomElement> views2 = <int, DomElement>{
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<AssertionError>()));
});

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<AssertionError>()));

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<AssertionError>()));
});
});
});
}