feat: post component height to parent window [FC-0083] (#36477)

XBlock rendered in an iframe in frontend-app-authoring needs to resize automatically based on component size.

Updates xblock iframe template to post message to parent window on size change.
This commit is contained in:
Navin Karkera
2025-04-11 18:01:36 +00:00
committed by GitHub
parent 11bab7d2ed
commit b893b23ce9
2 changed files with 56 additions and 17 deletions

View File

@@ -180,8 +180,8 @@
<!-- The default stylesheet will set the body min-height to 100% (a common strategy to allow for background
images to fill the viewport), but this has the undesireable side-effect of causing an infinite loop via the onResize
event listeners below, in certain situations. Resetting it to the default "auto" skirts the problem.-->
<body style="min-height: auto; background-color: white;" class="view-container">
<div class="wrapper xblock-iframe-content">
<body style="background-color: white;" class="view-container">
<div id="content" class="wrapper xblock-iframe-content">
<!-- fragment body -->
{{ fragment.body_html | safe }}
<!-- fragment foot -->
@@ -360,7 +360,7 @@
error_message_div.html('Error: '+response.message);
error_message_div.css('display', 'block');
}
});
});
});
});
}
@@ -437,21 +437,55 @@
const rootNode = document.querySelector('.xblock, .xblock-v1'); // will always return the first matching element
initializeXBlockAndChildren(rootNode, () => {
});
(function() {
// If this view is rendered in an iframe within the authoring microfrontend app
// it will report the height of its contents to the parent window when the
// document loads, window resizes, or DOM mutates.
if (window !== window.parent) {
var lastHeight = window.parent[0].offsetHeight;
var lastWidth = window.parent[0].offsetWidth;
let lastHeight = -1;
function checkFrameHeight() {
const newHeight = document.documentElement.scrollHeight;
if (newHeight !== lastHeight) {
lastHeight = newHeight;
function dispatchResizeMessage(event) {
// Note: event is actually an Array of MutationRecord objects when fired from the MutationObserver
var newHeight = rootNode.scrollHeight;
var newWidth = rootNode.offsetWidth;
window.parent.postMessage(
{
type: 'plugin.resize',
payload: {
width: newWidth,
height: newHeight,
}
}, document.referrer
);
lastHeight = newHeight;
lastWidth = newWidth;
// Within the authoring microfrontend the iframe resizes to match the
// height of this document and it should never scroll. It does scroll
// ocassionally when javascript is used to focus elements on the page
// before the parent iframe has been resized to match the content
// height. This window.scrollTo is an attempt to keep the content at the
// top of the page.
window.scrollTo(0, 0);
}
// Create an observer instance linked to the callback function
const observer = new MutationObserver(dispatchResizeMessage);
// Start observing the target node for configured mutations
observer.observe(rootNode, { attributes: true, childList: true, subtree: true });
const resizeObserver = new ResizeObserver(dispatchResizeMessage);
resizeObserver.observe(rootNode);
}
}
// Check the size whenever the DOM changes:
new MutationObserver(checkFrameHeight).observe(document.body, { attributes: true, childList: true, subtree: true });
// And whenever the IFrame is resized
window.addEventListener('resize', checkFrameHeight);
}());
}
window.addEventListener('load', blockFrameJS);
</script>
</body>
</html>

View File

@@ -211,12 +211,17 @@ class LibraryXBlockMetadata(PublishableItem):
Class that represents the metadata about an XBlock in a content library.
"""
usage_key: LibraryUsageLocatorV2
# TODO: move tags_count to LibraryItem as all objects under a library can be tagged.
tags_count: int = 0
@classmethod
def from_component(cls, library_key, component, associated_collections=None):
"""
Construct a LibraryXBlockMetadata from a Component object.
"""
# Import content_tagging.api here to avoid circular imports
from openedx.core.djangoapps.content_tagging.api import get_object_tag_counts
last_publish_log = component.versioning.last_publish_log
published_by = None
@@ -227,12 +232,11 @@ class LibraryXBlockMetadata(PublishableItem):
published = component.versioning.published
last_draft_created = draft.created if draft else None
last_draft_created_by = draft.publishable_entity_version.created_by if draft else None
usage_key = library_component_usage_key(library_key, component)
tags = get_object_tag_counts(str(usage_key), count_implicit=True)
return cls(
usage_key=library_component_usage_key(
library_key,
component,
),
usage_key=usage_key,
display_name=draft.title,
created=component.created,
modified=draft.created,
@@ -245,6 +249,7 @@ class LibraryXBlockMetadata(PublishableItem):
has_unpublished_changes=component.versioning.has_unpublished_changes,
collections=associated_collections or [],
can_stand_alone=component.publishable_entity.can_stand_alone,
tags_count=tags.get(str(usage_key), 0),
)