diff --git a/cms/static/js/base.js b/cms/static/js/base.js index 5f970a89d5..8b6bca95f3 100644 --- a/cms/static/js/base.js +++ b/cms/static/js/base.js @@ -73,6 +73,18 @@ function( // nav - dropdown related $body.click(function() { + // Reset iframe height to default when the XBlock action dropdown is closed + if ($('.nav-dd .nav-item .wrapper-nav-sub.is-shown').length && window.self !== window.top) { + try { + window.parent.postMessage({ + type: 'toggleCourseXBlockDropdown', + message: 'Adjust the height of the dropdown menu', + payload: { courseXBlockDropdownHeight: 0 } + }, document.referrer); + } catch (e) { + console.error('Failed to post message:', e); + } + } $('.nav-dd .nav-item .wrapper-nav-sub').removeClass('is-shown'); $('.nav-dd .nav-item .title').removeClass('is-selected'); $('.custom-dropdown .dropdown-options').hide(); diff --git a/cms/static/js/views/pages/container.js b/cms/static/js/views/pages/container.js index b483b98f11..39b6ba30a3 100644 --- a/cms/static/js/views/pages/container.js +++ b/cms/static/js/views/pages/container.js @@ -678,33 +678,35 @@ function($, _, Backbone, gettext, BasePage, // Calculate the viewport height and the dropdown menu height. // Check if the dropdown would overflow beyond the iframe height based on the user's click position. // If the dropdown overflows, adjust its position to display above the click point. - const courseUnitXBlockIframeHeight = window.innerHeight; - const courseXBlockDropdownHeight = subMenu.offsetHeight; - const clickYPosition = event.clientY; + const iframeHeight = window.innerHeight; + const dropdownHeight = subMenu.offsetHeight; + const offsetBuffer = 10; - if (courseUnitXBlockIframeHeight < courseXBlockDropdownHeight) { - // If the dropdown menu is taller than the iframe, adjust the height of the dropdown menu. + const targetRect = event.target.getBoundingClientRect(); + const targetBottom = targetRect.bottom; + const targetTop = targetRect.top; + + // Calculate total space needed below the target to fit dropdown + const dropdownBottom = targetBottom + dropdownHeight + offsetBuffer; + + const dropdownFitsBelow = dropdownBottom <= iframeHeight; + const dropdownFitsAbove = dropdownHeight + offsetBuffer < targetTop; + + if (!dropdownFitsBelow) { + if (dropdownFitsAbove && this.options.isIframeEmbed) { + // Display the dropdown above the button + subMenu.style.top = `-${dropdownHeight}px`; + } else { + // Request parent to expand iframe height to fit dropdown + const requiredExtraHeight = dropdownBottom - iframeHeight; this.postMessageToParent({ - type: 'toggleCourseXBlockDropdown', - message: 'Adjust the height of the dropdown menu', - payload: { courseXBlockDropdownHeight }, + type: 'toggleCourseXBlockDropdown', + message: 'Expand iframe to fit dropdown', + payload: { + courseXBlockDropdownHeight: requiredExtraHeight, + }, }); - } else if ((courseXBlockDropdownHeight + clickYPosition) > courseUnitXBlockIframeHeight) { - if (courseXBlockDropdownHeight > courseUnitXBlockIframeHeight / 2) { - // If the dropdown menu is taller than half the iframe, send a message to adjust its height. - this.postMessageToParent({ - type: 'toggleCourseXBlockDropdown', - message: 'Adjust the height of the dropdown menu', - payload: { - courseXBlockDropdownHeight: courseXBlockDropdownHeight / 2, - }, - }); - } else { - // Move the dropdown menu upward to prevent it from overflowing out of the viewport. - if (this.options.isIframeEmbed) { - subMenu.style.top = `-${courseXBlockDropdownHeight}px`; - } - } + } } // if propagation is not stopped, the event will bubble up to the diff --git a/common/templates/xblock_v2/xblock_iframe.html b/common/templates/xblock_v2/xblock_iframe.html index 39eb044b18..ba4828df02 100644 --- a/common/templates/xblock_v2/xblock_iframe.html +++ b/common/templates/xblock_v2/xblock_iframe.html @@ -455,9 +455,6 @@ // 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; - function dispatchResizeMessage(event) { // Note: event is actually an Array of MutationRecord objects when fired from the MutationObserver var newHeight = rootNode.scrollHeight; @@ -472,10 +469,6 @@ } }, 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 diff --git a/xmodule/modulestore/tests/test_api.py b/xmodule/modulestore/tests/test_api.py index 4e665c9eec..03dd79d4ff 100644 --- a/xmodule/modulestore/tests/test_api.py +++ b/xmodule/modulestore/tests/test_api.py @@ -57,7 +57,7 @@ def test_file_paths_api(): Test the `get_python_locale_root` returned path. """ root = get_python_locale_root() - assert root.endswith('edx-platform/conf/plugins-locale/xblock.v1'), 'Needs to match Makefile and other code' + assert root.endswith('/conf/plugins-locale/xblock.v1'), 'Needs to match Makefile and other code' def test_get_javascript_i18n_file_name():