/*! * artplayer-plugin-document-pip.js v1.1.0 * Github: https://github.com/zhw2590582/ArtPlayer * (c) 2017-2026 Harvey Zhao * Released under the MIT License. */ const style = ".artplayer-document-pip.art-video-player {\n width: 100% !important;\n height: 100% !important;\n}\n"; function artplayerPluginDocumentPip(userOptions = {}) { const options = { width: 480, height: 270, fallbackToVideoPiP: true, placeholder: `Playing in Document Picture-in-Picture`, ...userOptions }; return (art) => { const isSupported = "documentPictureInPicture" in window && typeof window.documentPictureInPicture?.requestWindow === "function"; const { proxy, icons, i18n, template: { $player }, constructor: { utils: { append, tooltip, addClass, removeClass, sleep } } } = art; const state = { win: null, originalParent: null, originalNext: null, currentDoc: null, placeholder: null }; function copyStylesTo(targetDoc) { const base = targetDoc.createElement("style"); base.textContent = ` html, body { margin:0; padding:0; width:100%; height:100%; background:#000; overflow:hidden; } #__art_dpip_root { position:absolute; inset:0; display:flex; } #__art_dpip_root > * { width:100% !important; height:100% !important; } `; targetDoc.head.appendChild(base); if (!targetDoc.querySelector('meta[name="viewport"]')) { const meta = targetDoc.createElement("meta"); meta.name = "viewport"; meta.content = "width=device-width,initial-scale=1"; targetDoc.head.appendChild(meta); } try { document.querySelectorAll('link[rel="stylesheet"]').forEach((link) => { const clone = targetDoc.createElement("link"); clone.rel = "stylesheet"; clone.href = link.href; if (link.media) clone.media = link.media; if (link.crossOrigin) clone.crossOrigin = link.crossOrigin; if (link.referrerPolicy) clone.referrerPolicy = link.referrerPolicy; targetDoc.head.appendChild(clone); }); } catch { } try { document.querySelectorAll("style").forEach((style2) => { const clone = targetDoc.createElement("style"); clone.textContent = style2.textContent; targetDoc.head.appendChild(clone); }); } catch { } } async function open() { if (!isSupported && options.fallbackToVideoPiP) { art.pip = true; console.warn("[artplayer-plugin-document-pip] Document Picture-in-Picture is not supported, falling back to Video Picture-in-Picture"); return; } if (state.win) return; try { const pipWin = await window.documentPictureInPicture.requestWindow({ width: options.width, height: options.height }); state.win = pipWin; state.currentDoc = pipWin.document; state.placeholder = document.createElement("div"); state.placeholder.className = "artplayer-document-pip-placeholder"; state.placeholder.style.cssText = `display:flex;justify-content:center;align-items:center;width:100%;height:100%;`; state.placeholder.textContent = options.placeholder; state.originalParent = $player.parentNode; state.originalNext = $player.nextSibling; state.originalParent.insertBefore(state.placeholder, state.originalNext); const root = pipWin.document.createElement("div"); root.id = "__art_dpip_root"; pipWin.document.body.appendChild(root); copyStylesTo(pipWin.document); const adopted = pipWin.document.adoptNode($player); root.appendChild(adopted); state.currentDoc = pipWin.document; const onResize = () => art.resize?.(); const onClose = () => close(); pipWin.addEventListener("resize", onResize); pipWin.addEventListener("pagehide", onClose); pipWin.addEventListener("unload", onClose); state.cleanup = () => { pipWin.removeEventListener("resize", onResize); pipWin.removeEventListener("pagehide", onClose); pipWin.removeEventListener("unload", onClose); }; addClass($player, "artplayer-document-pip"); art.events.bindGlobalEvents?.(); art.emit("document-pip", true); await sleep(100); art.emit("resize"); } catch (err) { art.notice.show = "Document Picture-in-Picture open failed"; console.warn("[artplayer-plugin-document-pip] open failed:", err); } } function restoreToOriginalDocument() { if (!state.placeholder) return; const backDoc = state.placeholder.ownerDocument || document; const adoptedBack = backDoc.adoptNode($player); state.originalParent.insertBefore(adoptedBack, state.placeholder); state.placeholder.remove(); state.placeholder = null; state.currentDoc = backDoc; } async function close() { if (!state.win) return; try { state.cleanup?.(); restoreToOriginalDocument(); state.win.close(); state.win = null; removeClass($player, "artplayer-document-pip"); art.events.bindGlobalEvents?.(); art.emit("document-pip", false); await sleep(100); art.emit("resize"); } catch (err) { art.notice.show = "Document Picture-in-Picture close failed"; console.warn("[artplayer-plugin-document-pip] close failed:", err); } } function toggle() { if (state.win) { close(); } else { open(); } } art.controls.add({ name: "document-pip", position: "right", index: 40, tooltip: art.i18n.get("PIP Mode"), mounted: ($control) => { append($control, icons.pip); proxy($control, "click", toggle); art.on("document-pip", (value) => { tooltip($control, i18n.get(value ? "Exit PIP Mode" : "PIP Mode")); }); } }); art.on("destroy", close); return { name: "artplayerPluginDocumentPip", get isSupported() { return isSupported; }, get isActive() { return !!state.win; }, open, close, toggle }; }; } if (typeof document !== "undefined") { const id = "artplayer-plugin-document-pip"; let $style = document.getElementById(id); if (!$style) { $style = document.createElement("style"); $style.id = id; if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", () => { document.head.appendChild($style); }); } else { (document.head || document.documentElement).appendChild($style); } } $style.textContent = style; } export { artplayerPluginDocumentPip as default };