diff --git a/package.json b/package.json index f0b82a50..bea229a6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "impro", - "version": "0.17.128", + "version": "0.17.129", "type": "module", "scripts": { "start": "rm -rf \"${BUILD_DIR:-build}\" && NODE_ENV=development eleventy --serve", diff --git a/src/js/components/streaming-video.js b/src/js/components/streaming-video.js index 15a68928..7304777f 100644 --- a/src/js/components/streaming-video.js +++ b/src/js/components/streaming-video.js @@ -19,6 +19,7 @@ const streamingVideoObserver = new IntersectionObserver( ); class StreamingVideo extends Component { + // Pause on navigate handlePageTransition = () => { const video = this.querySelector("video"); if (!video) { diff --git a/src/js/components/youtube-embed.js b/src/js/components/youtube-embed.js index 98e1ec13..82a25243 100644 --- a/src/js/components/youtube-embed.js +++ b/src/js/components/youtube-embed.js @@ -6,7 +6,19 @@ const YOUTUBE_EMBED_BASE_URL = "https://www.youtube-nocookie.com/embed"; const DEFAULT_ASPECT_RATIO = String(16 / 9); class YoutubeEmbed extends Component { + // Pause on navigate + handlePageTransition = () => { + if (!this.playing) { + return; + } + this.querySelector("iframe")?.contentWindow?.postMessage( + JSON.stringify({ event: "command", func: "pauseVideo", args: [] }), + "https://www.youtube-nocookie.com", + ); + }; + connectedCallback() { + window.addEventListener("page-transition", this.handlePageTransition); if (this._initialized) { return; } @@ -23,11 +35,15 @@ class YoutubeEmbed extends Component { this._initialized = true; } + disconnectedCallback() { + window.removeEventListener("page-transition", this.handlePageTransition); + } + getPlayerSrc() { const startSeconds = /^\d+$/.test(this.start ?? "") ? this.start : "0"; return `${YOUTUBE_EMBED_BASE_URL}/${encodeURIComponent( this.videoId, - )}?autoplay=1&start=${startSeconds}&rel=0&playsinline=1`; + )}?autoplay=1&start=${startSeconds}&rel=0&playsinline=1&enablejsapi=1&origin=${encodeURIComponent(window.location.origin)}`; } play() { diff --git a/tests/unit/specs/components/youtube-embed.test.js b/tests/unit/specs/components/youtube-embed.test.js index 777a6cdd..b02f77c2 100644 --- a/tests/unit/specs/components/youtube-embed.test.js +++ b/tests/unit/specs/components/youtube-embed.test.js @@ -105,7 +105,7 @@ t.describe("YoutubeEmbed - playing state", (it) => { assert(iframe !== null); assertEquals( iframe.getAttribute("src"), - "https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ?autoplay=1&start=32&rel=0&playsinline=1", + `https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ?autoplay=1&start=32&rel=0&playsinline=1&enablejsapi=1&origin=${encodeURIComponent(window.location.origin)}`, ); assertEquals(element.dataset.teststate, "playing"); assert(element.classList.contains("is-playing")); @@ -156,4 +156,43 @@ t.describe("YoutubeEmbed - playing state", (it) => { }); }); +t.describe("YoutubeEmbed - page transitions", (it) => { + function capturePostedMessages(element) { + const messages = []; + const iframe = element.querySelector("iframe"); + iframe.contentWindow.postMessage = (message, targetOrigin) => { + messages.push({ message, targetOrigin }); + }; + return messages; + } + + it("sends a pauseVideo command to the player on page-transition", () => { + const element = createEmbed(); + getCardLink(element).click(); + const messages = capturePostedMessages(element); + window.dispatchEvent(new window.CustomEvent("page-transition")); + assertEquals(messages.length, 1); + assertEquals( + messages[0].message, + JSON.stringify({ event: "command", func: "pauseVideo", args: [] }), + ); + assertEquals(messages[0].targetOrigin, "https://www.youtube-nocookie.com"); + }); + + it("does nothing on page-transition while in the preview state", () => { + const element = createEmbed(); + window.dispatchEvent(new window.CustomEvent("page-transition")); + assertEquals(element.dataset.teststate, "preview"); + }); + + it("stops listening for page-transition after being removed", () => { + const element = createEmbed(); + getCardLink(element).click(); + const messages = capturePostedMessages(element); + element.remove(); + window.dispatchEvent(new window.CustomEvent("page-transition")); + assertEquals(messages.length, 0); + }); +}); + await t.run();