diff --git a/.github/actions/unit-tests/action.yml b/.github/actions/unit-tests/action.yml index 404ab2cf5711..2a5429baff09 100644 --- a/.github/actions/unit-tests/action.yml +++ b/.github/actions/unit-tests/action.yml @@ -27,7 +27,7 @@ runs: - name: save pytest warnings json file if: success() - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: pytest-warnings-json path: | diff --git a/.github/workflows/js-tests.yml b/.github/workflows/js-tests.yml index 2346c705d06b..ddd5be1a15a7 100644 --- a/.github/workflows/js-tests.yml +++ b/.github/workflows/js-tests.yml @@ -73,7 +73,7 @@ jobs: xvfb-run --auto-servernum ./scripts/all-tests.sh - name: Save Job Artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: Build-Artifacts path: | diff --git a/.github/workflows/quality-checks.yml b/.github/workflows/quality-checks.yml index f6e99ffc92ea..4b6ac1218144 100644 --- a/.github/workflows/quality-checks.yml +++ b/.github/workflows/quality-checks.yml @@ -73,7 +73,7 @@ jobs: - name: Save Job Artifacts if: always() - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: Build-Artifacts path: | diff --git a/lms/static/completion/js/ViewedEvent.js b/lms/static/completion/js/ViewedEvent.js index 2a49e650fd44..5e45bb34174c 100644 --- a/lms/static/completion/js/ViewedEvent.js +++ b/lms/static/completion/js/ViewedEvent.js @@ -110,7 +110,13 @@ export class ViewedEventTracker { constructor() { this.elementViewings = new Set(); this.handlers = []; - this.registerDomHandlers(); + if (window === window.parent) { + // Preview (legacy LMS frontend). + this.registerDomHandlers(); + } else { + // Learning MFE. + window.addEventListener('message', this.handleVisibilityMessage.bind(this)); + } } /** Add an element to track. */ @@ -122,7 +128,11 @@ export class ViewedEventTracker { (el, event) => this.callHandlers(el, event), ), ); - this.updateVisible(); + // Update visibility status immediately after adding the element (in case it's already visible). + // We don't need this for the Learning MFE because it will send a message once the iframe is loaded. + if (window === window.parent) { + this.updateVisible(); + } } /** Register a new handler to be called when an element has been viewed. */ @@ -178,5 +188,37 @@ export class ViewedEventTracker { handler(el, event); }); } + + /** Handle a unit.visibilityStatus message from the Learning MFE. */ + handleVisibilityMessage(event) { + if (event.data.type === 'unit.visibilityStatus') { + const { topPosition, viewportHeight } = event.data.data; + + this.elementViewings.forEach((elv) => { + const rect = elv.getBoundingRect(); + let visible = false; + + // Convert iframe-relative rect coordinates to be relative to the parent's viewport. + const elTopPosition = rect.top + topPosition; + const elBottomPosition = rect.bottom + topPosition; + + // Check if the element is visible in the parent's viewport. + if (elTopPosition < viewportHeight && elTopPosition >= 0) { + elv.markTopSeen(); + visible = true; + } + if (elBottomPosition <= viewportHeight && elBottomPosition > 0) { + elv.markBottomSeen(); + visible = true; + } + + if (visible) { + elv.handleVisible(); + } else { + elv.handleNotVisible(); + } + }); + } + } }