Files
ArtPlayer/docs/compiled/artplayer-plugin-document-pip.mjs
T
Harvey Zhao 65e51751cd feat: add danmuku plugin and i18n setup documentation
- Created a new documentation file for the danmuku plugin with code examples.
- Added a new documentation file for language settings (i18n) with detailed instructions on language imports, default languages, and how to add or modify languages.
- Included code snippets for initializing the Artplayer with different language settings.
2026-03-12 22:23:44 +08:00

195 lines
6.8 KiB
JavaScript

/*!
* 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
};