From 3d7311d25462289d0614375b2778520d20601b8e Mon Sep 17 00:00:00 2001 From: ihor-romaniuk Date: Wed, 28 Sep 2022 18:02:48 +0300 Subject: [PATCH] fix: save scroll position on exit from video xblock fullscreen mode --- src/courseware/course/sequence/Unit.jsx | 14 +++++++++++++- src/courseware/course/sequence/Unit.test.jsx | 15 +++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/courseware/course/sequence/Unit.jsx b/src/courseware/course/sequence/Unit.jsx index 274bc68143..1926a36c46 100644 --- a/src/courseware/course/sequence/Unit.jsx +++ b/src/courseware/course/sequence/Unit.jsx @@ -93,6 +93,7 @@ const Unit = ({ const [showError, setShowError] = useState(false); const [modalOptions, setModalOptions] = useState({ open: false }); const [shouldDisplayHonorCode, setShouldDisplayHonorCode] = useState(false); + const [windowTopOffset, setWindowTopOffset] = useState(null); const unit = useModel('units', id); const course = useModel('coursewareMeta', courseId); @@ -120,6 +121,13 @@ const Unit = ({ } = data; if (type === 'plugin.resize') { setIframeHeight(payload.height); + + // We observe exit from the video xblock full screen mode + // and do page scroll to the previously saved scroll position + if (windowTopOffset !== null) { + window.scrollTo(0, Number(windowTopOffset)); + } + if (!hasLoaded && iframeHeight === 0 && payload.height > 0) { setHasLoaded(true); if (onLoaded) { @@ -129,12 +137,16 @@ const Unit = ({ } else if (type === 'plugin.modal') { payload.open = true; setModalOptions(payload); + } else if (type === 'plugin.videoFullScreen') { + // We listen for this message from LMS to know when we need to + // save or reset scroll position on toggle video xblock full screen mode. + setWindowTopOffset(payload.open ? window.scrollY : null); } else if (data.offset) { // We listen for this message from LMS to know when the page needs to // be scrolled to another location on the page. window.scrollTo(0, data.offset + document.getElementById('unit-iframe').offsetTop); } - }, [id, setIframeHeight, hasLoaded, iframeHeight, setHasLoaded, onLoaded]); + }, [id, setIframeHeight, hasLoaded, iframeHeight, setHasLoaded, onLoaded, setWindowTopOffset, windowTopOffset]); useEventListener('message', receiveMessage); useEffect(() => { sendUrlHashToFrame(document.getElementById('unit-iframe')); diff --git a/src/courseware/course/sequence/Unit.test.jsx b/src/courseware/course/sequence/Unit.test.jsx index dbb2fdd9f2..4bd692d253 100644 --- a/src/courseware/course/sequence/Unit.test.jsx +++ b/src/courseware/course/sequence/Unit.test.jsx @@ -129,6 +129,21 @@ describe('Unit', () => { expect(window.scrollY === testMessageWithOffset.offset); }); + it('scrolls page on MessagaeEvent when receiving videoFullScreen state', async () => { + // Set message to constain video full screen data. + const defaultTopOffset = 800; + const testMessageWithOtherHeight = { ...messageEvent, payload: { height: 500 } }; + const testMessageWithFullscreenState = (isOpen) => ({ type: 'plugin.videoFullScreen', payload: { open: isOpen } }); + render(); + Object.defineProperty(window, 'scrollY', { value: defaultTopOffset, writable: true }); + window.postMessage(testMessageWithFullscreenState(true), '*'); + window.postMessage(testMessageWithFullscreenState(false), '*'); + window.postMessage(testMessageWithOtherHeight, '*'); + + await expect(waitFor(() => expect(window.scrollTo()).toHaveBeenCalledTimes(1))); + expect(window.scrollY === defaultTopOffset); + }); + it('ignores MessageEvent with unhandled type', async () => { // Clone message and set different type. const testMessageWithUnhandledType = { ...messageEvent, type: 'wrong type' };