diff --git a/docs/assets/example/pip.js b/docs/assets/example/pip.js
new file mode 100644
index 000000000..56705b221
--- /dev/null
+++ b/docs/assets/example/pip.js
@@ -0,0 +1,18 @@
+// npm i artplayer-plugin-pip
+// import artplayerPluginPip from 'artplayer-plugin-pip';
+
+let art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ plugins: [
+ artplayerPluginPip({
+ width: 480,
+ height: 270,
+ placeholder: `Playing in Document Picture-in-Picture`,
+ }),
+ ],
+})
+
+art.on('document-pip', (state) => {
+ console.log('Document Picture-in-Picture', state)
+})
diff --git a/docs/assets/js/common.js b/docs/assets/js/common.js
index f175583f3..fb4eeeb84 100644
--- a/docs/assets/js/common.js
+++ b/docs/assets/js/common.js
@@ -1,305 +1,309 @@
(function () {
- Artplayer.DEBUG = true;
+ Artplayer.DEBUG = true
- if (Artplayer.utils.isMobile) {
- window.location.href = './mobile.html' + location.search;
+ if (Artplayer.utils.isMobile) {
+ window.location.href = `./mobile.html${location.search}`
+ }
+
+ let $codeMirror = document.querySelector('.codeMirrorWrap')
+ let $lib = document.querySelector('.libsInput')
+ let $run = document.querySelector('.run')
+ let $popups = document.querySelector('.popups')
+ let $console = document.querySelector('.console')
+ let $prod = document.querySelector('#prod')
+ let $ts = document.querySelector('#ts')
+ let $code = document.querySelector('#code')
+ let $log = document.querySelector('#log')
+ let $file = document.querySelector('#file')
+ let $editor = document.querySelector('#editor')
+
+ window.consoleLog($console)
+
+ $prod.checked = localStorage.getItem('prod') === 'true'
+ $ts.checked = localStorage.getItem('ts') === 'true'
+ $code.checked = localStorage.getItem('code') === 'true'
+ $log.checked = localStorage.getItem('log') === 'true'
+
+ if ($code.checked) {
+ $editor.style.display = 'none'
+ }
+
+ if ($log.checked) {
+ $console.style.display = 'none'
+ }
+
+ let editor = null
+ let loadedLibs = []
+ require.config({ paths: { vs: './assets/js/vs' } })
+ require(['vs/editor/editor.main'], async () => {
+ monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
+ noSemanticValidation: true,
+ noSyntaxValidation: false,
+ })
+
+ monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
+ target: monaco.languages.typescript.ScriptTarget.ES6,
+ allowNonTsExtensions: true,
+ })
+
+ let libUris = [
+ './assets/ts/artplayer-plugin-ads.d.ts',
+ './assets/ts/artplayer-plugin-asr.d.ts',
+ './assets/ts/artplayer-plugin-ambilight.d.ts',
+ './assets/ts/artplayer-plugin-auto-thumbnail.d.ts',
+ './assets/ts/artplayer-plugin-chapter.d.ts',
+ './assets/ts/artplayer-plugin-chromecast.d.ts',
+ './assets/ts/artplayer-plugin-danmuku-mask.d.ts',
+ './assets/ts/artplayer-plugin-danmuku.d.ts',
+ './assets/ts/artplayer-plugin-dash-control.d.ts',
+ './assets/ts/artplayer-plugin-hls-control.d.ts',
+ './assets/ts/artplayer-plugin-iframe.d.ts',
+ './assets/ts/artplayer-plugin-libass.d.ts',
+ './assets/ts/artplayer-plugin-multiple-subtitles.d.ts',
+ './assets/ts/artplayer-plugin-vast.d.ts',
+ './assets/ts/artplayer-plugin-vtt-thumbnail.d.ts',
+ './assets/ts/artplayer-plugin-pip.d.ts',
+ './assets/ts/artplayer.d.ts',
+ ]
+
+ for (let index = 0; index < libUris.length; index++) {
+ let libUri = libUris[index]
+ let libSource = await (await fetch(libUri)).text()
+ monaco.languages.typescript.javascriptDefaults.addExtraLib(libSource, libUri)
+ monaco.editor.createModel(libSource, 'typescript', monaco.Uri.parse(libUri))
}
- var $codeMirror = document.querySelector('.codeMirrorWrap');
- var $lib = document.querySelector('.libsInput');
- var $run = document.querySelector('.run');
- var $popups = document.querySelector('.popups');
- var $console = document.querySelector('.console');
- var $prod = document.querySelector('#prod');
- var $ts = document.querySelector('#ts');
- var $code = document.querySelector('#code');
- var $log = document.querySelector('#log');
- var $file = document.querySelector('#file');
- var $editor = document.querySelector('#editor');
+ var disposable = monaco.editor.onDidCreateEditor(() => {
+ disposable.dispose()
+ setTimeout(initApp, 1000)
+ })
- window['consoleLog']($console);
+ editor = monaco.editor.create($codeMirror, {
+ theme: 'vs-dark',
+ folding: true,
+ automaticLayout: true,
+ quickSuggestions: {
+ other: true,
+ comments: true,
+ strings: true,
+ },
+ model: monaco.editor.createModel(
+ [
+ 'var art = new Artplayer({',
+ '\tcontainer: \'.artplayer-app\',',
+ '\turl: \'/assets/sample/video.mp4\',',
+ '});',
+ ].join('\n'),
+ $ts.checked ? 'typescript' : 'javascript',
+ ),
+ })
+ })
- $prod.checked = localStorage.getItem('prod') === 'true';
- $ts.checked = localStorage.getItem('ts') === 'true';
- $code.checked = localStorage.getItem('code') === 'true';
- $log.checked = localStorage.getItem('log') === 'true';
+ function getURLParameters(url) {
+ return (url.match(/([^?=&]+)(=([^&]*))/g) || []).reduce((a, v) => {
+ return (a[v.slice(0, v.indexOf('='))] = v.slice(v.indexOf('=') + 1)), a
+ }, {})
+ }
- if ($code.checked) {
- $editor.style.display = 'none';
+ function getExt(url) {
+ if (url.includes('?')) {
+ return getExt(url.split('?')[0])
}
- if ($log.checked) {
- $console.style.display = 'none';
+ if (url.includes('#')) {
+ return getExt(url.split('#')[0])
}
- var editor = null;
- var loadedLibs = [];
- require.config({ paths: { vs: './assets/js/vs' } });
- require(['vs/editor/editor.main'], async function () {
- monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
- noSemanticValidation: true,
- noSyntaxValidation: false,
- });
+ return url.trim().toLowerCase().split('.').pop()
+ }
- monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
- target: monaco.languages.typescript.ScriptTarget.ES6,
- allowNonTsExtensions: true,
- });
+ function loadScript(url) {
+ return new Promise((resolve, reject) => {
+ let define2 = window.define
+ window.define = undefined
+ let script = document.createElement('script')
+ script.type = 'text/javascript'
+ script.src = url
+ script.onload = function () {
+ window.define = define2
+ resolve(url)
+ }
+ script.onerror = function () {
+ reject(new Error(`Loading script failed:${url}`))
+ }
+ document.querySelector('head').appendChild(script)
+ })
+ }
- var libUris = [
- './assets/ts/artplayer-plugin-ads.d.ts',
- './assets/ts/artplayer-plugin-asr.d.ts',
- './assets/ts/artplayer-plugin-ambilight.d.ts',
- './assets/ts/artplayer-plugin-auto-thumbnail.d.ts',
- './assets/ts/artplayer-plugin-chapter.d.ts',
- './assets/ts/artplayer-plugin-chromecast.d.ts',
- './assets/ts/artplayer-plugin-danmuku-mask.d.ts',
- './assets/ts/artplayer-plugin-danmuku.d.ts',
- './assets/ts/artplayer-plugin-dash-control.d.ts',
- './assets/ts/artplayer-plugin-hls-control.d.ts',
- './assets/ts/artplayer-plugin-iframe.d.ts',
- './assets/ts/artplayer-plugin-libass.d.ts',
- './assets/ts/artplayer-plugin-multiple-subtitles.d.ts',
- './assets/ts/artplayer-plugin-vast.d.ts',
- './assets/ts/artplayer-plugin-vtt-thumbnail.d.ts',
- './assets/ts/artplayer.d.ts',
- ];
-
- for (let index = 0; index < libUris.length; index++) {
- var libUri = libUris[index];
- var libSource = await (await fetch(libUri)).text();
- monaco.languages.typescript.javascriptDefaults.addExtraLib(libSource, libUri);
- monaco.editor.createModel(libSource, 'typescript', monaco.Uri.parse(libUri));
+ function loadStyle(url) {
+ return new Promise((resolve, reject) => {
+ let link = document.createElement('link')
+ link.rel = 'stylesheet'
+ link.href = url
+ link.onload = function () {
+ resolve(url)
+ }
+ link.onerror = function () {
+ reject(new Error(`Loading style failed:${url}`))
+ }
+ document.querySelector('head').appendChild(link)
+ })
+ }
+
+ function loadLib(libs) {
+ let libPromise = []
+ let libsDecode = decodeURIComponent(libs || '')
+ libsDecode
+ .split(/\r?\n/)
+ .filter((url) => {
+ return !loadedLibs.includes(url)
+ })
+ .forEach((url) => {
+ let ext = getExt(url)
+ if (ext === 'js') {
+ libPromise.push(loadScript(url))
}
-
- var disposable = monaco.editor.onDidCreateEditor(function () {
- disposable.dispose();
- setTimeout(initApp, 1000);
- });
-
- editor = monaco.editor.create($codeMirror, {
- theme: 'vs-dark',
- folding: true,
- automaticLayout: true,
- quickSuggestions: {
- other: true,
- comments: true,
- strings: true,
- },
- model: monaco.editor.createModel(
- [
- 'var art = new Artplayer({',
- "\tcontainer: '.artplayer-app',",
- "\turl: '/assets/sample/video.mp4',",
- '});',
- ].join('\n'),
- $ts.checked ? 'typescript' : 'javascript',
- ),
- });
- });
-
- function getURLParameters(url) {
- return (url.match(/([^?=&]+)(=([^&]*))/g) || []).reduce(function (a, v) {
- return (a[v.slice(0, v.indexOf('='))] = v.slice(v.indexOf('=') + 1)), a;
- }, {});
- }
-
- function getExt(url) {
- if (url.includes('?')) {
- return getExt(url.split('?')[0]);
+ else if (ext === 'css') {
+ libPromise.push(loadStyle(url))
}
+ })
+ $lib.value = libsDecode
+ return Promise.all(libPromise)
+ }
- if (url.includes('#')) {
- return getExt(url.split('#')[0]);
- }
+ function runExample(name) {
+ fetch(`./assets/example/${name}.js`)
+ .then((response) => {
+ return response.text()
+ })
+ .then((text) => {
+ editor.setValue(text)
+ runCode()
+ })
+ .catch((err) => {
+ console.error(err)
+ })
+ }
- return url.trim().toLowerCase().split('.').pop();
+ function loadCode(code, example) {
+ if (example) {
+ runExample(example)
}
-
- function loadScript(url) {
- return new Promise(function (resolve, reject) {
- var define2 = window.define;
- window.define = undefined;
- var script = document.createElement('script');
- script.type = 'text/javascript';
- script.src = url;
- script.onload = function () {
- window.define = define2;
- resolve(url);
- };
- script.onerror = function () {
- reject(new Error('Loading script failed:' + url));
- };
- document.querySelector('head').appendChild(script);
- });
+ else if (code) {
+ editor.setValue(decodeURIComponent(code).trim())
+ runCode()
}
-
- function loadStyle(url) {
- return new Promise(function (resolve, reject) {
- var link = document.createElement('link');
- link.rel = 'stylesheet';
- link.href = url;
- link.onload = function () {
- resolve(url);
- };
- link.onerror = function () {
- reject(new Error('Loading style failed:' + url));
- };
- document.querySelector('head').appendChild(link);
- });
+ else {
+ runExample('index')
}
+ }
- function loadLib(libs) {
- var libPromise = [];
- var libsDecode = decodeURIComponent(libs || '');
- libsDecode
- .split(/\r?\n/)
- .filter(function (url) {
- return !loadedLibs.includes(url);
- })
- .forEach(function (url) {
- var ext = getExt(url);
- if (ext === 'js') {
- libPromise.push(loadScript(url));
- } else if (ext === 'css') {
- libPromise.push(loadStyle(url));
- }
- });
- $lib.value = libsDecode;
- return Promise.all(libPromise);
+ function runCode() {
+ [...Artplayer.instances].forEach((art) => {
+ art.destroy(true)
+ })
+ const value = editor.getValue()
+ eval(value)
+ window.art = Artplayer.instances[0]
+ }
+
+ function initApp() {
+ let _getURLParameters = getURLParameters(window.location.href)
+ let code = _getURLParameters.code
+ let libs = _getURLParameters.libs
+ example = _getURLParameters.example
+
+ loadLib(libs)
+ .then((result) => {
+ loadedLibs = loadedLibs.concat(result)
+ loadCode(code, example)
+ })
+ .catch((err) => {
+ console.error(err)
+ })
+ }
+
+ function restart() {
+ let libs = encodeURIComponent($lib.value)
+ let code = encodeURIComponent(editor.getValue())
+ let url = `${window.location.origin + window.location.pathname}?libs=${libs}&code=${code}`
+ history.pushState(null, null, url)
+ initApp()
+ }
+
+ function readFile(file) {
+ return new Promise((resolve) => {
+ const reader = new FileReader()
+ reader.onload = () => resolve(reader.result)
+ reader.readAsText(file)
+ })
+ }
+
+ $run.addEventListener('click', () => {
+ restart()
+ })
+
+ $popups.addEventListener('click', function (event) {
+ if (event.target === this) {
+ this.style.display = 'none'
}
+ })
- function runExample(name) {
- fetch('./assets/example/' + name + '.js')
- .then(function (response) {
- return response.text();
- })
- .then(function (text) {
- editor.setValue(text);
- runCode();
- })
- .catch(function (err) {
- console.error(err);
- });
+ $prod.addEventListener('change', () => {
+ localStorage.setItem('prod', $prod.checked ? 'true' : 'false')
+ window.location.reload()
+ })
+
+ $ts.addEventListener('change', () => {
+ localStorage.setItem('ts', $ts.checked ? 'true' : 'false')
+ window.location.reload()
+ })
+
+ $code.addEventListener('change', () => {
+ localStorage.setItem('code', $code.checked ? 'true' : 'false')
+ window.location.reload()
+ })
+
+ $log.addEventListener('change', () => {
+ localStorage.setItem('log', $log.checked ? 'true' : 'false')
+ window.location.reload()
+ })
+
+ $file.addEventListener('change', async () => {
+ for (let index = 0; index < $file.files.length; index++) {
+ const file = $file.files[index]
+ const name = file.name.toLowerCase().trim()
+ if (name.endsWith('.css')) {
+ const text = await readFile(file)
+ const $style = document.createElement('style')
+ $style.textContent = text
+ document.body.appendChild($style)
+ $lib.value = `\n[${name}]`
+ $lib.value = $lib.value.trim()
+ }
+ if (name.endsWith('.js')) {
+ const text = await readFile(file)
+ const $script = document.createElement('script')
+ $script.textContent = text
+ document.body.appendChild($script)
+ $lib.value = `\n[${name}]`
+ $lib.value = $lib.value.trim()
+ }
}
+ })
- function loadCode(code, example) {
- if (example) {
- runExample(example);
- } else if (code) {
- editor.setValue(decodeURIComponent(code).trim());
- runCode();
- } else {
- runExample('index');
- }
+ window.addEventListener('error', (err) => {
+ console.error(err)
+ })
+
+ window.addEventListener('unhandledrejection', (err) => {
+ console.error(err)
+ })
+
+ document.addEventListener('keydown', (event) => {
+ if ((event.ctrlKey || event.metaKey) && event.key === 's') {
+ event.preventDefault()
+ restart()
}
-
- function runCode() {
- [...Artplayer.instances].forEach(function (art) {
- art.destroy(true);
- });
- const value = editor.getValue();
- eval(value);
- window.art = Artplayer.instances[0];
- }
-
- function initApp() {
- var _getURLParameters = getURLParameters(window.location.href),
- code = _getURLParameters.code,
- libs = _getURLParameters.libs;
- example = _getURLParameters.example;
-
- loadLib(libs)
- .then(function (result) {
- loadedLibs = loadedLibs.concat(result);
- loadCode(code, example);
- })
- .catch(function (err) {
- console.error(err);
- });
- }
-
- function restart() {
- var libs = encodeURIComponent($lib.value);
- var code = encodeURIComponent(editor.getValue());
- var url = window.location.origin + window.location.pathname + '?libs=' + libs + '&code=' + code;
- history.pushState(null, null, url);
- initApp();
- }
-
- function readFile(file) {
- return new Promise((resolve) => {
- const reader = new FileReader();
- reader.onload = () => resolve(reader.result);
- reader.readAsText(file);
- })
- }
-
- $run.addEventListener('click', function () {
- restart();
- });
-
- $popups.addEventListener('click', function (event) {
- if (event.target === this) {
- this.style.display = 'none';
- }
- });
-
- $prod.addEventListener('change', function () {
- localStorage.setItem('prod', $prod.checked ? 'true' : 'false');
- window.location.reload();
- });
-
- $ts.addEventListener('change', function () {
- localStorage.setItem('ts', $ts.checked ? 'true' : 'false');
- window.location.reload();
- });
-
- $code.addEventListener('change', function () {
- localStorage.setItem('code', $code.checked ? 'true' : 'false');
- window.location.reload();
- });
-
- $log.addEventListener('change', function () {
- localStorage.setItem('log', $log.checked ? 'true' : 'false');
- window.location.reload();
- });
-
- $file.addEventListener('change', async function () {
- for (let index = 0; index < $file.files.length; index++) {
- const file = $file.files[index];
- const name = file.name.toLowerCase().trim()
- if (name.endsWith('.css')) {
- const text = await readFile(file);
- const $style = document.createElement('style');
- $style.textContent = text;
- document.body.appendChild($style);
- $lib.value = `\n[${name}]`;
- $lib.value = $lib.value.trim();
- }
- if (name.endsWith('.js')) {
- const text = await readFile(file);
- const $script = document.createElement('script');
- $script.textContent = text;
- document.body.appendChild($script);
- $lib.value = `\n[${name}]`;
- $lib.value = $lib.value.trim();
- }
- }
- });
-
- window.addEventListener('error', function (err) {
- console.error(err);
- });
-
- window.addEventListener('unhandledrejection', function (err) {
- console.error(err);
- });
-
- document.addEventListener('keydown', function (event) {
- if ((event.ctrlKey || event.metaKey) && event.key === 's') {
- event.preventDefault();
- restart();
- }
- });
-})();
\ No newline at end of file
+ })
+})()
diff --git a/docs/assets/ts/artplayer-plugin-pip.d.ts b/docs/assets/ts/artplayer-plugin-pip.d.ts
new file mode 100644
index 000000000..50bafc3cf
--- /dev/null
+++ b/docs/assets/ts/artplayer-plugin-pip.d.ts
@@ -0,0 +1,16 @@
+interface Option {
+ width?: number
+ height?: number
+ placeholder?: string
+}
+
+interface Result {
+ name: 'artplayerPluginPip'
+}
+
+declare const artplayerPluginPip: (option: Option) => (art: Artplayer) => Result
+
+export default artplayerPluginPip
+
+export = artplayerPluginPip;
+export as namespace artplayerPluginPip;
\ No newline at end of file
diff --git a/docs/assets/ts/artplayer.d.ts b/docs/assets/ts/artplayer.d.ts
index 11588d07b..b4db11be2 100644
--- a/docs/assets/ts/artplayer.d.ts
+++ b/docs/assets/ts/artplayer.d.ts
@@ -1054,6 +1054,8 @@ export interface ComponentOption {
+export type { Config, Events, I18n, Icons, Option, Player, Setting, SettingOption, Subtitle, Template, Utils }
+
export default class Artplayer extends Player {
constructor(option: Option, readyCallback?: (this: Artplayer, art: Artplayer) => unknown)
diff --git a/docs/index.html b/docs/index.html
index c03f7c9c6..814df1206 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -111,6 +111,9 @@
artplayer-plugin-asr
+
+ artplayer-plugin-pip
+
- Proxys
diff --git a/docs/uncompiled/artplayer-plugin-pip/index.js b/docs/uncompiled/artplayer-plugin-pip/index.js
new file mode 100644
index 000000000..e73028cc8
--- /dev/null
+++ b/docs/uncompiled/artplayer-plugin-pip/index.js
@@ -0,0 +1,321 @@
+// modules are defined as an array
+// [ module function, map of requires ]
+//
+// map of requires is short require name -> numeric require
+//
+// anything defined in a previous bundle is accessed via the
+// orig method which is the require for previous bundles
+
+(function (
+ modules,
+ entry,
+ mainEntry,
+ parcelRequireName,
+ externals,
+ distDir,
+ publicUrl,
+ devServer
+) {
+ /* eslint-disable no-undef */
+ var globalObject =
+ typeof globalThis !== 'undefined'
+ ? globalThis
+ : typeof self !== 'undefined'
+ ? self
+ : typeof window !== 'undefined'
+ ? window
+ : typeof global !== 'undefined'
+ ? global
+ : {};
+ /* eslint-enable no-undef */
+
+ // Save the require from previous bundle to this closure if any
+ var previousRequire =
+ typeof globalObject[parcelRequireName] === 'function' &&
+ globalObject[parcelRequireName];
+
+ var importMap = previousRequire.i || {};
+ var cache = previousRequire.cache || {};
+ // Do not use `require` to prevent Webpack from trying to bundle this call
+ var nodeRequire =
+ typeof module !== 'undefined' &&
+ typeof module.require === 'function' &&
+ module.require.bind(module);
+
+ function newRequire(name, jumped) {
+ if (!cache[name]) {
+ if (!modules[name]) {
+ if (externals[name]) {
+ return externals[name];
+ }
+ // if we cannot find the module within our internal map or
+ // cache jump to the current global require ie. the last bundle
+ // that was added to the page.
+ var currentRequire =
+ typeof globalObject[parcelRequireName] === 'function' &&
+ globalObject[parcelRequireName];
+ if (!jumped && currentRequire) {
+ return currentRequire(name, true);
+ }
+
+ // If there are other bundles on this page the require from the
+ // previous one is saved to 'previousRequire'. Repeat this as
+ // many times as there are bundles until the module is found or
+ // we exhaust the require chain.
+ if (previousRequire) {
+ return previousRequire(name, true);
+ }
+
+ // Try the node require function if it exists.
+ if (nodeRequire && typeof name === 'string') {
+ return nodeRequire(name);
+ }
+
+ var err = new Error("Cannot find module '" + name + "'");
+ err.code = 'MODULE_NOT_FOUND';
+ throw err;
+ }
+
+ localRequire.resolve = resolve;
+ localRequire.cache = {};
+
+ var module = (cache[name] = new newRequire.Module(name));
+
+ modules[name][0].call(
+ module.exports,
+ localRequire,
+ module,
+ module.exports,
+ globalObject
+ );
+ }
+
+ return cache[name].exports;
+
+ function localRequire(x) {
+ var res = localRequire.resolve(x);
+ return res === false ? {} : newRequire(res);
+ }
+
+ function resolve(x) {
+ var id = modules[name][1][x];
+ return id != null ? id : x;
+ }
+ }
+
+ function Module(moduleName) {
+ this.id = moduleName;
+ this.bundle = newRequire;
+ this.require = nodeRequire;
+ this.exports = {};
+ }
+
+ newRequire.isParcelRequire = true;
+ newRequire.Module = Module;
+ newRequire.modules = modules;
+ newRequire.cache = cache;
+ newRequire.parent = previousRequire;
+ newRequire.distDir = distDir;
+ newRequire.publicUrl = publicUrl;
+ newRequire.devServer = devServer;
+ newRequire.i = importMap;
+ newRequire.register = function (id, exports) {
+ modules[id] = [
+ function (require, module) {
+ module.exports = exports;
+ },
+ {},
+ ];
+ };
+
+ // Only insert newRequire.load when it is actually used.
+ // The code in this file is linted against ES5, so dynamic import is not allowed.
+ // INSERT_LOAD_HERE
+
+ Object.defineProperty(newRequire, 'root', {
+ get: function () {
+ return globalObject[parcelRequireName];
+ },
+ });
+
+ globalObject[parcelRequireName] = newRequire;
+
+ for (var i = 0; i < entry.length; i++) {
+ newRequire(entry[i]);
+ }
+
+ if (mainEntry) {
+ // Expose entry point to Node, AMD or browser globals
+ // Based on https://github.com/ForbesLindesay/umd/blob/master/template.js
+ var mainExports = newRequire(mainEntry);
+
+ // CommonJS
+ if (typeof exports === 'object' && typeof module !== 'undefined') {
+ module.exports = mainExports;
+
+ // RequireJS
+ } else if (typeof define === 'function' && define.amd) {
+ define(function () {
+ return mainExports;
+ });
+ }
+ }
+})({"55Mmu":[function(require,module,exports,__globalThis) {
+var parcelHelpers = require("@parcel/transformer-js/src/esmodule-helpers.js");
+parcelHelpers.defineInteropFlag(exports);
+parcelHelpers.export(exports, "default", ()=>artplayerPluginPip);
+function artplayerPluginPip(userOptions = {}) {
+ const options = {
+ width: 480,
+ height: 270,
+ placeholder: `Playing in Document Picture-in-Picture`,
+ ...userOptions
+ };
+ return (art)=>{
+ if (!('documentPictureInPicture' in window)) {
+ art.notice.show = 'Document Picture-in-Picture is not supported';
+ return;
+ }
+ const { proxy, icons, i18n, template: { $container }, constructor: { utils: { append, tooltip } } } = art;
+ const state = {
+ win: null,
+ originalParent: null,
+ originalNext: null,
+ currentDoc: null,
+ placeholder: null
+ };
+ function copyStylesTo(targetDoc) {
+ const baseStyle = `
+ 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; }
+ `;
+ const $style = document.querySelector('#artplayer-style');
+ const clone = targetDoc.createElement('style');
+ clone.textContent = baseStyle + $style.textContent;
+ targetDoc.head.appendChild(clone);
+ const meta = targetDoc.createElement('meta');
+ meta.name = 'viewport';
+ meta.content = 'width=device-width,initial-scale=1';
+ targetDoc.head.appendChild(meta);
+ }
+ async function open() {
+ 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-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 = $container.parentNode;
+ state.originalNext = $container.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($container);
+ root.appendChild(adopted);
+ state.currentDoc = pipWin.document;
+ const onResize = ()=>art.resize?.();
+ const onPageHide = ()=>close();
+ pipWin.addEventListener('resize', onResize);
+ pipWin.addEventListener('pagehide', onPageHide);
+ state.cleanup = ()=>{
+ pipWin.removeEventListener('resize', onResize);
+ pipWin.removeEventListener('pagehide', onPageHide);
+ };
+ art.emit('document-pip', true);
+ } catch (err) {
+ art.notice.show = 'Document Picture-in-Picture open failed';
+ console.warn('[artplayer-plugin-pip] open failed:', err);
+ }
+ }
+ function restoreToOriginalDocument() {
+ if (!state.placeholder) return;
+ const backDoc = state.placeholder.ownerDocument || document;
+ const adoptedBack = backDoc.adoptNode($container);
+ state.originalParent.insertBefore(adoptedBack, state.placeholder);
+ state.placeholder.remove();
+ state.placeholder = null;
+ state.currentDoc = backDoc;
+ }
+ function close() {
+ if (!state.win) return;
+ try {
+ state.cleanup?.();
+ restoreToOriginalDocument();
+ state.win.close();
+ state.win = null;
+ art.emit('document-pip', false);
+ } catch (err) {
+ art.notice.show = 'Document Picture-in-Picture close failed';
+ console.warn('[artplayer-plugin-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: 'artplayerPluginPip',
+ open,
+ close,
+ toggle
+ };
+ };
+}
+if (typeof window !== 'undefined') window.artplayerPluginPip = artplayerPluginPip;
+
+},{"@parcel/transformer-js/src/esmodule-helpers.js":"8oCsH"}],"8oCsH":[function(require,module,exports,__globalThis) {
+exports.interopDefault = function(a) {
+ return a && a.__esModule ? a : {
+ default: a
+ };
+};
+exports.defineInteropFlag = function(a) {
+ Object.defineProperty(a, '__esModule', {
+ value: true
+ });
+};
+exports.exportAll = function(source, dest) {
+ Object.keys(source).forEach(function(key) {
+ if (key === 'default' || key === '__esModule' || Object.prototype.hasOwnProperty.call(dest, key)) return;
+ Object.defineProperty(dest, key, {
+ enumerable: true,
+ get: function() {
+ return source[key];
+ }
+ });
+ });
+ return dest;
+};
+exports.export = function(dest, destName, get) {
+ Object.defineProperty(dest, destName, {
+ enumerable: true,
+ get: get
+ });
+};
+
+},{}]},["55Mmu"], "55Mmu", "parcelRequire4dc0", {})
+
+//# sourceMappingURL=index.js.map
diff --git a/docs/uncompiled/artplayer-plugin-pip/index.js.map b/docs/uncompiled/artplayer-plugin-pip/index.js.map
new file mode 100644
index 000000000..bc0871b4f
--- /dev/null
+++ b/docs/uncompiled/artplayer-plugin-pip/index.js.map
@@ -0,0 +1 @@
+{"mappings":"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","sources":["packages/artplayer-plugin-pip/src/index.js","node_modules/@parcel/transformer-js/src/esmodule-helpers.js"],"sourcesContent":["export default function artplayerPluginPip(userOptions = {}) {\n const options = {\n width: 480,\n height: 270,\n placeholder: `Playing in Document Picture-in-Picture`,\n ...userOptions,\n }\n\n return (art) => {\n if (!('documentPictureInPicture' in window)) {\n art.notice.show = 'Document Picture-in-Picture is not supported'\n return\n }\n\n const { proxy, icons, i18n, template: { $container }, constructor: { utils: { append, tooltip } } } = art\n\n const state = {\n win: null,\n originalParent: null,\n originalNext: null,\n currentDoc: null,\n placeholder: null,\n }\n\n function copyStylesTo(targetDoc) {\n const baseStyle = `\n html, body { margin:0; padding:0; width:100%; height:100%; background:#000; overflow:hidden; }\n #__art_dpip_root { position:absolute; inset:0; display:flex; }\n #__art_dpip_root > * { width:100% !important; height:100% !important; }\n `\n\n const $style = document.querySelector('#artplayer-style')\n const clone = targetDoc.createElement('style')\n clone.textContent = baseStyle + $style.textContent\n targetDoc.head.appendChild(clone)\n\n const meta = targetDoc.createElement('meta')\n meta.name = 'viewport'\n meta.content = 'width=device-width,initial-scale=1'\n targetDoc.head.appendChild(meta)\n }\n\n async function open() {\n if (state.win)\n return\n\n try {\n const pipWin = await window.documentPictureInPicture.requestWindow({\n width: options.width,\n height: options.height,\n })\n\n state.win = pipWin\n state.currentDoc = pipWin.document\n\n state.placeholder = document.createElement('div')\n state.placeholder.className = 'artplayer-pip-placeholder'\n state.placeholder.style.cssText = `display:flex;justify-content:center;align-items:center;width:100%;height:100%;`\n state.placeholder.textContent = options.placeholder\n state.originalParent = $container.parentNode\n state.originalNext = $container.nextSibling\n state.originalParent.insertBefore(state.placeholder, state.originalNext)\n\n const root = pipWin.document.createElement('div')\n root.id = '__art_dpip_root'\n pipWin.document.body.appendChild(root)\n\n copyStylesTo(pipWin.document)\n\n const adopted = pipWin.document.adoptNode($container)\n root.appendChild(adopted)\n state.currentDoc = pipWin.document\n\n const onResize = () => art.resize?.()\n const onPageHide = () => close()\n\n pipWin.addEventListener('resize', onResize)\n pipWin.addEventListener('pagehide', onPageHide)\n\n state.cleanup = () => {\n pipWin.removeEventListener('resize', onResize)\n pipWin.removeEventListener('pagehide', onPageHide)\n }\n\n art.emit('document-pip', true)\n }\n catch (err) {\n art.notice.show = 'Document Picture-in-Picture open failed'\n console.warn('[artplayer-plugin-pip] open failed:', err)\n }\n }\n\n function restoreToOriginalDocument() {\n if (!state.placeholder)\n return\n const backDoc = state.placeholder.ownerDocument || document\n const adoptedBack = backDoc.adoptNode($container)\n state.originalParent.insertBefore(adoptedBack, state.placeholder)\n state.placeholder.remove()\n state.placeholder = null\n state.currentDoc = backDoc\n }\n\n function close() {\n if (!state.win)\n return\n try {\n state.cleanup?.()\n restoreToOriginalDocument()\n state.win.close()\n state.win = null\n art.emit('document-pip', false)\n }\n catch (err) {\n art.notice.show = 'Document Picture-in-Picture close failed'\n console.warn('[artplayer-plugin-pip] close failed:', err)\n }\n }\n\n function toggle() {\n if (state.win) {\n close()\n }\n else {\n open()\n }\n }\n\n art.controls.add({\n name: 'document-pip',\n position: 'right',\n index: 40,\n tooltip: art.i18n.get('PIP Mode'),\n mounted: ($control) => {\n append($control, icons.pip)\n proxy($control, 'click', toggle)\n art.on('document-pip', (value) => {\n tooltip($control, i18n.get(value ? 'Exit PIP Mode' : 'PIP Mode'))\n })\n },\n })\n\n art.on('destroy', close)\n\n return {\n name: 'artplayerPluginPip',\n open,\n close,\n toggle,\n }\n }\n}\n\nif (typeof window !== 'undefined') {\n window.artplayerPluginPip = artplayerPluginPip\n}\n","exports.interopDefault = function (a) {\n return a && a.__esModule ? a : {default: a};\n};\n\nexports.defineInteropFlag = function (a) {\n Object.defineProperty(a, '__esModule', {value: true});\n};\n\nexports.exportAll = function (source, dest) {\n Object.keys(source).forEach(function (key) {\n if (\n key === 'default' ||\n key === '__esModule' ||\n Object.prototype.hasOwnProperty.call(dest, key)\n ) {\n return;\n }\n\n Object.defineProperty(dest, key, {\n enumerable: true,\n get: function () {\n return source[key];\n },\n });\n });\n\n return dest;\n};\n\nexports.export = function (dest, destName, get) {\n Object.defineProperty(dest, destName, {\n enumerable: true,\n get: get,\n });\n};\n"],"names":[],"version":3,"file":"index.js.map","sourceRoot":"../../../"}
\ No newline at end of file
diff --git a/packages/artplayer-plugin-pip/README.md b/packages/artplayer-plugin-pip/README.md
new file mode 100644
index 000000000..52acc366e
--- /dev/null
+++ b/packages/artplayer-plugin-pip/README.md
@@ -0,0 +1,11 @@
+# artplayer-plugin-pip
+
+pip plugin for ArtPlayer
+
+## Demo
+
+[https://artplayer.org](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-pip/index.js&example=pip)
+
+## License
+
+MIT © Harvey Zack
diff --git a/packages/artplayer-plugin-pip/package.json b/packages/artplayer-plugin-pip/package.json
new file mode 100644
index 000000000..20de2b492
--- /dev/null
+++ b/packages/artplayer-plugin-pip/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "artplayer-plugin-pip",
+ "version": "1.0.0",
+ "description": "pip plugin for ArtPlayer",
+ "author": "Harvey Zack ",
+ "license": "MIT",
+ "homepage": "https://artplayer.org",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/zhw2590582/ArtPlayer.git"
+ },
+ "bugs": {
+ "url": "https://github.com/zhw2590582/ArtPlayer/issues"
+ },
+ "keywords": [
+ "html5",
+ "video",
+ "player"
+ ],
+ "main": "dist/artplayer-plugin-pip.js",
+ "types": "types/artplayer-plugin-pip.d.ts",
+ "legacy": "dist/artplayer-plugin-pip.legacy.js",
+ "browserslist": "last 1 Chrome version"
+}
diff --git a/packages/artplayer-plugin-pip/src/index.js b/packages/artplayer-plugin-pip/src/index.js
new file mode 100644
index 000000000..fc749d4b7
--- /dev/null
+++ b/packages/artplayer-plugin-pip/src/index.js
@@ -0,0 +1,156 @@
+export default function artplayerPluginPip(userOptions = {}) {
+ const options = {
+ width: 480,
+ height: 270,
+ placeholder: `Playing in Document Picture-in-Picture`,
+ ...userOptions,
+ }
+
+ return (art) => {
+ if (!('documentPictureInPicture' in window)) {
+ art.notice.show = 'Document Picture-in-Picture is not supported'
+ return
+ }
+
+ const { proxy, icons, i18n, template: { $container }, constructor: { utils: { append, tooltip } } } = art
+
+ const state = {
+ win: null,
+ originalParent: null,
+ originalNext: null,
+ currentDoc: null,
+ placeholder: null,
+ }
+
+ function copyStylesTo(targetDoc) {
+ const baseStyle = `
+ 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; }
+ `
+
+ const $style = document.querySelector('#artplayer-style')
+ const clone = targetDoc.createElement('style')
+ clone.textContent = baseStyle + $style.textContent
+ targetDoc.head.appendChild(clone)
+
+ const meta = targetDoc.createElement('meta')
+ meta.name = 'viewport'
+ meta.content = 'width=device-width,initial-scale=1'
+ targetDoc.head.appendChild(meta)
+ }
+
+ async function open() {
+ 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-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 = $container.parentNode
+ state.originalNext = $container.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($container)
+ root.appendChild(adopted)
+ state.currentDoc = pipWin.document
+
+ const onResize = () => art.resize?.()
+ const onPageHide = () => close()
+
+ pipWin.addEventListener('resize', onResize)
+ pipWin.addEventListener('pagehide', onPageHide)
+
+ state.cleanup = () => {
+ pipWin.removeEventListener('resize', onResize)
+ pipWin.removeEventListener('pagehide', onPageHide)
+ }
+
+ art.emit('document-pip', true)
+ }
+ catch (err) {
+ art.notice.show = 'Document Picture-in-Picture open failed'
+ console.warn('[artplayer-plugin-pip] open failed:', err)
+ }
+ }
+
+ function restoreToOriginalDocument() {
+ if (!state.placeholder)
+ return
+ const backDoc = state.placeholder.ownerDocument || document
+ const adoptedBack = backDoc.adoptNode($container)
+ state.originalParent.insertBefore(adoptedBack, state.placeholder)
+ state.placeholder.remove()
+ state.placeholder = null
+ state.currentDoc = backDoc
+ }
+
+ function close() {
+ if (!state.win)
+ return
+ try {
+ state.cleanup?.()
+ restoreToOriginalDocument()
+ state.win.close()
+ state.win = null
+ art.emit('document-pip', false)
+ }
+ catch (err) {
+ art.notice.show = 'Document Picture-in-Picture close failed'
+ console.warn('[artplayer-plugin-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: 'artplayerPluginPip',
+ open,
+ close,
+ toggle,
+ }
+ }
+}
+
+if (typeof window !== 'undefined') {
+ window.artplayerPluginPip = artplayerPluginPip
+}
diff --git a/packages/artplayer-plugin-pip/src/style.less b/packages/artplayer-plugin-pip/src/style.less
new file mode 100644
index 000000000..b25fb8ec9
--- /dev/null
+++ b/packages/artplayer-plugin-pip/src/style.less
@@ -0,0 +1,3 @@
+.artplayer-plugin-pip {
+ //
+}
diff --git a/packages/artplayer-plugin-pip/types/artplayer-plugin-pip.d.ts b/packages/artplayer-plugin-pip/types/artplayer-plugin-pip.d.ts
new file mode 100644
index 000000000..114cf46e8
--- /dev/null
+++ b/packages/artplayer-plugin-pip/types/artplayer-plugin-pip.d.ts
@@ -0,0 +1,15 @@
+import type Artplayer from 'artplayer'
+
+interface Option {
+ width?: number
+ height?: number
+ placeholder?: string
+}
+
+interface Result {
+ name: 'artplayerPluginPip'
+}
+
+declare const artplayerPluginPip: (option: Option) => (art: Artplayer) => Result
+
+export default artplayerPluginPip