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:
@@ -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>
|
||||
|
||||
@@ -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),
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user