mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-12 23:36:15 -08:00
refactor(iframe): [PKG-IFRAME-03] scope requests to active documents
This commit is contained in:
1 parent
b8cdafedd1
commit
1342de94ef
27 files changed
+10860
-69
No files matched your search
@@ -4,4 +4,4 @@
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.ArtplayerToolIframe=t(),define(function(){return e.ArtplayerToolIframe})):(e="undefined"!==typeof globalThis?globalThis:e||self).ArtplayerToolIframe=t()}(this,function(){"use strict";const e=new WeakMap;let t=0;const s=new WeakMap;function o(t){const o=s.get(t);s.delete(t);try{o?.()}finally{!function(t){const s=e.get(t);if(s)for(const e of[...s])e.callbacks.reject(new Error("The instance has been destroyed"))}(t)}}function r(e,t){if(void 0!==e.source&&null!==e.source&&e.source!==t)return!1;const s=e.data;return"object"===typeof s&&null!==s&&"type"in s&&"string"===typeof s.type}class n{static get iframe(){return window.top!==window}static postMessage({type:e,data:t,id:s=0}){if(!n.iframe)throw new Error('The "ArtplayerToolIframe.postMessage" method can only be used in iframe');window.parent.postMessage({type:e,data:t,id:s},"*")}static async onMessage(e){if(!n.iframe)throw new Error('The "ArtplayerToolIframe.onMessage" method can only be used in iframe');if(!r(e,window.parent))return;const{type:t,data:s,id:o}=e.data;if("commit"===t)try{if(s.match(/\bresolve\((.*?)\)/)){const e=`return new Promise(function(resolve){\n${s}\n})`,t=await new Function(e)();n.postMessage({type:"response",data:t,id:o})}else{const e=new Function(s)();n.postMessage({type:"response",data:e,id:o})}}catch(i){throw n.postMessage({type:"error",data:i.message,id:o}),i}}static inject(){if(!n.iframe)throw new Error('The "ArtplayerToolIframe.inject" method can only be used in iframe');n.postMessage({type:"inject"}),window.addEventListener("message",n.onMessage)}constructor({iframe:e,url:t}){if(e instanceof HTMLIFrameElement===!1)throw new TypeError('"option.iframe" needs to be a HTMLIFrameElement');if("string"!==typeof t)throw new TypeError('"option.url" needs to be a string');this.url=t,this.$iframe=e,this.promises={},this.injected=!1,this.destroyed=!1,this.messageCallback=()=>null,this.onMessage=this.onMessage.bind(this);try{!function(e){const t=window,o=e.onMessage;s.set(e,()=>t.removeEventListener("message",o)),t.addEventListener("message",o),e.$iframe.src=e.url}(this)}catch(r){this.destroyed=!0;try{o(this)}catch{}throw r}}onMessage(e){if(this.destroyed||!r(e,this.$iframe.contentWindow))return;const{type:t,data:s,id:o}=e.data;if("inject"===t)this.injected=!0;void 0!==o&&Object.prototype.hasOwnProperty.call(this.promises,o)&&this.promises[o]&&("error"===t?this.promises[o].reject(new Error(s)):this.promises[o].resove(s),delete this.promises[o]),this.messageCallback&&this.messageCallback({type:t,data:s})}postMessage(s){return function(s,{type:o,data:r}){return new Promise((n,i)=>{if(s.destroyed)return void i(new Error("The instance has been destroyed"));const a=e.get(s)||new Set;e.set(s,a);const c=t=>!!a.delete(t)&&(void 0!==t.timer&&clearTimeout(t.timer),void 0!==t.id&&delete s.promises[t.id],a.size||e.delete(s),!0),d={callbacks:{resove(e){c(d)&&n(e)},reject(e){c(d)&&i(e)}}};a.add(d);const l=()=>{if(d.timer=void 0,a.has(d))if(s.destroyed)d.callbacks.reject(new Error("The instance has been destroyed"));else try{if(s.injected){const e=Math.max(Date.now(),t+1);t=e,d.id=e,s.promises[e]=d.callbacks,s.$iframe.contentWindow.postMessage({type:o,data:r,id:e},"*")}else d.timer=setTimeout(l,200)}catch(e){d.callbacks.reject(e)}};l()})}(this,s)}commit(e){if("function"!==typeof e)throw new TypeError('"commit.callback" needs to be a function');const t=e.toString(),s=t.substring(t.indexOf("{")+1,t.lastIndexOf("}"));return this.postMessage({type:"commit",data:s})}message(e){if("function"!==typeof e)throw new TypeError('"message.callback" needs to be a function');this.messageCallback=e}destroy(){this.destroyed=!0,o(this)}}return n});
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.ArtplayerToolIframe=t(),define(function(){return e.ArtplayerToolIframe})):(e="undefined"!==typeof globalThis?globalThis:e||self).ArtplayerToolIframe=t()}(this,function(){"use strict";const e="artplayer-tool-iframe:session";function t(e){const t=e.__artplayerIframe;if(1===t?.version&&"string"===typeof t.document&&t.document&&["inject","message","ack","leave","resume","fragment"].includes(t.phase))return t}function n(e,t,n){return{...e,__artplayerIframe:{version:1,document:t,phase:n}}}function r(e,t){if(void 0!==e.source&&null!==e.source&&e.source!==t)return!1;const n=e.data;return"object"===typeof n&&null!==n&&"type"in n&&"string"===typeof n.type}let o;const s=new WeakMap,i=new WeakMap;let a=0;function c(e,t){t?i.set(e,t):i.delete(e)}function d(e,t=new Error("The instance has been destroyed")){const n=s.get(e);if(n)for(const r of[...n])r.cancel(t)}const u=new WeakMap;function f(e){const t=e.$iframe;return t.hasAttribute?.("srcdoc")?`srcdoc:${t.getAttribute("srcdoc")}`:`src:${n=t.src||"",n.split("#")[0]}`;var n}function m(e){const t=e.$iframe;return t.hasAttribute?.("srcdoc")?`srcdoc:${t.getAttribute("srcdoc")}`:`src:${t.getAttribute?.("src")??t.src??""}`}function h(e,t){t.waiting||(t.documentId?t.cancelPrevious=function(e){const t=[...s.get(e)||[]];return e=>{for(const n of t)n.cancel(e)}}(e):d(e,new Error("The iframe document has changed"))),t.waiting=!0,e.injected=!1}function l(e,t,n){const r=m(e);if(!n.length&&r===t.rawSource)return;const o=function(e,t,n){return f(e)!==t.source||!!t.documentId&&(m(e)!==t.rawSource||n.some(t=>"srcdoc"===t.attributeName||"src"===t.attributeName&&!e.$iframe.hasAttribute?.("srcdoc")))}(e,t,n);t.rawSource=r,t.source=f(e),o&&h(e,t)}function w(e){const t=u.get(e);if(!t||e.destroyed)return;const n=t.observer?.takeRecords()||[];l(e,t,n)}function p(t,r,o){r.hasHandshake&&r.documentId!==o&&(r.cancelPrevious?r.cancelPrevious(new Error("The iframe document has changed")):r.waiting||d(t,new Error("The iframe document has changed"))),r.cancelPrevious=void 0,r.documentId=o,r.hasHandshake=!0,r.waiting=!1,t.injected=!0;try{t.$iframe.contentWindow?.postMessage(n({type:e,data:void 0,id:0},o,"ack"),"*")}catch{}}function g(n,r){const o=u.get(n);if(!o)return!1;w(n);const s=t(r);if(s&&r.type===e)return"resume"===s.phase?p(n,o,s.document):s.document===o.documentId&&("leave"===s.phase?function(e,t){t.cancelPrevious?t.cancelPrevious(new Error("The iframe document has changed")):t.waiting||d(e,new Error("The iframe document has changed")),t.cancelPrevious=void 0,t.waiting=!0,e.injected=!1}(n,o):"fragment"===s.phase&&o.cancelPrevious&&!n.$iframe.hasAttribute?.("srcdoc")&&r.data===n.$iframe.src&&p(n,o,s.document)),!0;if("inject"===r.type){if("inject"===s?.phase){if(o.waiting&&s.document===o.documentId)return!0;p(n,o,s.document)}else o.waiting&&(o.cancelPrevious?.(new Error("The iframe document has changed")),o.cancelPrevious=void 0,o.documentId=void 0),o.hasHandshake=!0,o.waiting=!1;return!1}return Boolean(s&&(o.waiting&&!o.cancelPrevious||s.document!==o.documentId))}const y=new WeakMap;function v(e){const t=window,r=e.onMessage,o=[()=>t.removeEventListener("message",r)];y.set(e,()=>{let e,t=!1;for(const r of o)try{r()}catch(n){t||(t=!0,e=n)}if(t)throw e}),t.addEventListener("message",r),e.$iframe.src=e.url;const s=function(e){const t={source:f(e),rawSource:m(e),hasHandshake:!1,waiting:!1};return u.set(e,t),c(e,{prepare:()=>w(e),envelope:e=>t.documentId?n(e,t.documentId,"message"):e}),{start(){"function"===typeof window.MutationObserver&&(t.observer=new window.MutationObserver(n=>{e.destroyed||l(e,t,n)}),t.observer.observe(e.$iframe,{attributes:!0,attributeOldValue:!0,attributeFilter:["src","srcdoc"]}))},dispose(){u.delete(e),c(e,void 0),t.cancelPrevious=void 0,t.observer?.disconnect()}}}(e);o.push(s.dispose),s.start()}function b(e){const t=y.get(e);y.delete(e);try{t?.()}finally{d(e)}}class E{static get iframe(){return window.top!==window}static postMessage({type:e,data:t,id:r=0}){if(!E.iframe)throw new Error('The "ArtplayerToolIframe.postMessage" method can only be used in iframe');var s;window.parent.postMessage((s={type:e,data:t,id:r},o&&("inject"===s.type||o.acknowledged)?n(s,o.id,"inject"===s.type?"inject":"message"):s),"*")}static async onMessage(n){if(!E.iframe)throw new Error('The "ArtplayerToolIframe.onMessage" method can only be used in iframe');if(!r(n,window.parent)||function(n){const r=t(n);return!!r&&(n.type===e?(o&&r.document===o.id&&"ack"===r.phase&&(o.acknowledged=!0),!0):!o||r.document!==o.id)}(n.data))return;const{type:s,data:i,id:a}=n.data;if("commit"===s)try{if(i.match(/\bresolve\((.*?)\)/)){const e=`return new Promise(function(resolve){\n${i}\n})`,t=await new Function(e)();E.postMessage({type:"response",data:t,id:a})}else{const e=new Function(i)();E.postMessage({type:"response",data:e,id:a})}}catch(c){throw E.postMessage({type:"error",data:c.message,Line truncated
|
||||
@@ -4,4 +4,4 @@
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.ArtplayerToolIframe=t(),define(function(){return e.ArtplayerToolIframe})):(e="undefined"!==typeof globalThis?globalThis:e||self).ArtplayerToolIframe=t()}(this,function(){"use strict";const e=new WeakMap;let t=0;const s=new WeakMap;function o(t){const o=s.get(t);s.delete(t);try{null==o||o()}finally{!function(t){const s=e.get(t);if(s)for(const e of[...s])e.callbacks.reject(new Error("The instance has been destroyed"))}(t)}}function r(e,t){if(void 0!==e.source&&null!==e.source&&e.source!==t)return!1;const s=e.data;return"object"===typeof s&&null!==s&&"type"in s&&"string"===typeof s.type}class n{static get iframe(){return window.top!==window}static postMessage({type:e,data:t,id:s=0}){if(!n.iframe)throw new Error('The "ArtplayerToolIframe.postMessage" method can only be used in iframe');window.parent.postMessage({type:e,data:t,id:s},"*")}static onMessage(e){return t=this,s=null,o=function*(){if(!n.iframe)throw new Error('The "ArtplayerToolIframe.onMessage" method can only be used in iframe');if(!r(e,window.parent))return;const{type:t,data:s,id:o}=e.data;if("commit"===t)try{if(s.match(/\bresolve\((.*?)\)/)){const e=`return new Promise(function(resolve){\n${s}\n})`,t=yield new Function(e)();n.postMessage({type:"response",data:t,id:o})}else{const e=new Function(s)();n.postMessage({type:"response",data:e,id:o})}}catch(i){throw n.postMessage({type:"error",data:i.message,id:o}),i}},new Promise((e,r)=>{var n=e=>{try{a(o.next(e))}catch(t){r(t)}},i=e=>{try{a(o.throw(e))}catch(t){r(t)}},a=t=>t.done?e(t.value):Promise.resolve(t.value).then(n,i);a((o=o.apply(t,s)).next())});var t,s,o}static inject(){if(!n.iframe)throw new Error('The "ArtplayerToolIframe.inject" method can only be used in iframe');n.postMessage({type:"inject"}),window.addEventListener("message",n.onMessage)}constructor({iframe:e,url:t}){if(e instanceof HTMLIFrameElement===!1)throw new TypeError('"option.iframe" needs to be a HTMLIFrameElement');if("string"!==typeof t)throw new TypeError('"option.url" needs to be a string');this.url=t,this.$iframe=e,this.promises={},this.injected=!1,this.destroyed=!1,this.messageCallback=()=>null,this.onMessage=this.onMessage.bind(this);try{!function(e){const t=window,o=e.onMessage;s.set(e,()=>t.removeEventListener("message",o)),t.addEventListener("message",o),e.$iframe.src=e.url}(this)}catch(r){this.destroyed=!0;try{o(this)}catch(n){}throw r}}onMessage(e){if(this.destroyed||!r(e,this.$iframe.contentWindow))return;const{type:t,data:s,id:o}=e.data;if("inject"===t)this.injected=!0;void 0!==o&&Object.prototype.hasOwnProperty.call(this.promises,o)&&this.promises[o]&&("error"===t?this.promises[o].reject(new Error(s)):this.promises[o].resove(s),delete this.promises[o]),this.messageCallback&&this.messageCallback({type:t,data:s})}postMessage(s){return function(s,{type:o,data:r}){return new Promise((n,i)=>{if(s.destroyed)return void i(new Error("The instance has been destroyed"));const a=e.get(s)||new Set;e.set(s,a);const c=t=>!!a.delete(t)&&(void 0!==t.timer&&clearTimeout(t.timer),void 0!==t.id&&delete s.promises[t.id],a.size||e.delete(s),!0),d={callbacks:{resove(e){c(d)&&n(e)},reject(e){c(d)&&i(e)}}};a.add(d);const l=()=>{if(d.timer=void 0,a.has(d))if(s.destroyed)d.callbacks.reject(new Error("The instance has been destroyed"));else try{if(s.injected){const e=Math.max(Date.now(),t+1);t=e,d.id=e,s.promises[e]=d.callbacks,s.$iframe.contentWindow.postMessage({type:o,data:r,id:e},"*")}else d.timer=setTimeout(l,200)}catch(e){d.callbacks.reject(e)}};l()})}(this,s)}commit(e){if("function"!==typeof e)throw new TypeError('"commit.callback" needs to be a function');const t=e.toString(),s=t.substring(t.indexOf("{")+1,t.lastIndexOf("}"));return this.postMessage({type:"commit",data:s})}message(e){if("function"!==typeof e)throw new TypeError('"message.callback" needs to be a function');this.messageCallback=e}destroy(){this.destroyed=!0,o(this)}}return n});
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.ArtplayerToolIframe=t(),define(function(){return e.ArtplayerToolIframe})):(e="undefined"!==typeof globalThis?globalThis:e||self).ArtplayerToolIframe=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.defineProperties,n=Object.getOwnPropertyDescriptors,r=Object.getOwnPropertySymbols,o=Object.prototype.hasOwnProperty,s=Object.prototype.propertyIsEnumerable,i=(t,n,r)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[n]=r;const a="artplayer-tool-iframe:session";function c(e){const t=e.__artplayerIframe;if(1===(null==t?void 0:t.version)&&"string"===typeof t.document&&t.document&&["inject","message","ack","leave","resume","fragment"].includes(t.phase))return t}function d(e,a,c){return d=((e,t)=>{for(var n in t||(t={}))o.call(t,n)&&i(e,n,t[n]);if(r)for(var n of r(t))s.call(t,n)&&i(e,n,t[n]);return e})({},e),t(d,n({__artplayerIframe:{version:1,document:a,phase:c}}));var d}function u(e,t){if(void 0!==e.source&&null!==e.source&&e.source!==t)return!1;const n=e.data;return"object"===typeof n&&null!==n&&"type"in n&&"string"===typeof n.type}let l;const f=new WeakMap,m=new WeakMap;let h=0;function p(e,t){t?m.set(e,t):m.delete(e)}function w(e,t=new Error("The instance has been destroyed")){const n=f.get(e);if(n)for(const r of[...n])r.cancel(t)}const v=new WeakMap;function y(e){var t;const n=e.$iframe;return(null==(t=n.hasAttribute)?void 0:t.call(n,"srcdoc"))?`srcdoc:${n.getAttribute("srcdoc")}`:`src:${r=n.src||"",r.split("#")[0]}`;var r}function g(e){var t,n,r,o;const s=e.$iframe;return(null==(t=s.hasAttribute)?void 0:t.call(s,"srcdoc"))?`srcdoc:${s.getAttribute("srcdoc")}`:`src:${null!=(o=null!=(r=null==(n=s.getAttribute)?void 0:n.call(s,"src"))?r:s.src)?o:""}`}function b(e,t){t.waiting||(t.documentId?t.cancelPrevious=function(e){const t=[...f.get(e)||[]];return e=>{for(const n of t)n.cancel(e)}}(e):w(e,new Error("The iframe document has changed"))),t.waiting=!0,e.injected=!1}function E(e,t,n){const r=g(e);if(!n.length&&r===t.rawSource)return;const o=function(e,t,n){return y(e)!==t.source||!!t.documentId&&(g(e)!==t.rawSource||n.some(t=>{var n,r;return"srcdoc"===t.attributeName||"src"===t.attributeName&&!(null==(r=(n=e.$iframe).hasAttribute)?void 0:r.call(n,"srcdoc"))}))}(e,t,n);t.rawSource=r,t.source=y(e),o&&b(e,t)}function M(e){var t;const n=v.get(e);if(!n||e.destroyed)return;E(e,n,(null==(t=n.observer)?void 0:t.takeRecords())||[])}function j(e,t,n){var r;t.hasHandshake&&t.documentId!==n&&(t.cancelPrevious?t.cancelPrevious(new Error("The iframe document has changed")):t.waiting||w(e,new Error("The iframe document has changed"))),t.cancelPrevious=void 0,t.documentId=n,t.hasHandshake=!0,t.waiting=!1,e.injected=!0;try{null==(r=e.$iframe.contentWindow)||r.postMessage(d({type:a,data:void 0,id:0},n,"ack"),"*")}catch(o){}}function T(e,t){var n,r,o;const s=v.get(e);if(!s)return!1;M(e);const i=c(t);if(i&&t.type===a)return"resume"===i.phase?j(e,s,i.document):i.document===s.documentId&&("leave"===i.phase?function(e,t){t.cancelPrevious?t.cancelPrevious(new Error("The iframe document has changed")):t.waiting||w(e,new Error("The iframe document has changed")),t.cancelPrevious=void 0,t.waiting=!0,e.injected=!1}(e,s):"fragment"===i.phase&&s.cancelPrevious&&!(null==(r=(n=e.$iframe).hasAttribute)?void 0:r.call(n,"srcdoc"))&&t.data===e.$iframe.src&&j(e,s,i.document)),!0;if("inject"===t.type){if("inject"===(null==i?void 0:i.phase)){if(s.waiting&&i.document===s.documentId)return!0;j(e,s,i.document)}else s.waiting&&(null==(o=s.cancelPrevious)||o.call(s,new Error("The iframe document has changed")),s.cancelPrevious=void 0,s.documentId=void 0),s.hasHandshake=!0,s.waiting=!1;return!1}return Boolean(i&&(s.waiting&&!s.cancelPrevious||i.document!==s.documentId))}const k=new WeakMap;function P(e){const t=window,n=e.onMessage,r=[()=>t.removeEventListener("message",n)];k.set(e,()=>{let e,t=!1;for(const o of r)try{o()}catch(n){t||(t=!0,e=n)}if(t)throw e}),t.addEventListener("message",n),e.$iframe.src=e.url;const o=function(e){const t={source:y(e),rawSource:g(e),hasHandshake:!1,waiting:!1};return v.set(e,t),p(e,{prepare:()=>M(e),envelope:e=>t.documentId?d(e,t.documentId,"message"):e}),{start(){"function"===typeof window.MutationObserver&&(t.observer=new window.MutationObserver(n=>{e.destroyed||E(e,t,n)}),t.observer.observe(e.$iframe,{attributes:!0,attributeOldValue:!0,attributeFilter:["src","srcdoc"]}))},dispose(){var n;v.delete(e),p(e,void 0),t.cancelPrevious=void 0,null==(n=t.observer)||n.disconnect()}}}(e);r.push(o.dispose),o.start()}function I(e){const t=k.get(e);k.delete(e);try{null==t||t()}finally{w(e)}}class ${static get iframe(){return window.top!==window}static postMessage({type:e,data:t,id:n=0}){if(!$.iframe)throw new Error('The "ArtplayerToolIframe.postMessage" method can only be used in iframe');var r;window.parent.postMessage((r={type:e,data:t,id:n},l&&("inject"===r.type||lLine truncated
|
||||
@@ -4,8 +4,104 @@
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
const sessionType = "artplayer-tool-iframe:session";
|
||||
function sessionMetadata(packet) {
|
||||
const value = packet.__artplayerIframe;
|
||||
if (value?.version === 1 && typeof value.document === "string" && value.document && ["inject", "message", "ack", "leave", "resume", "fragment"].includes(value.phase))
|
||||
return value;
|
||||
}
|
||||
function withSession(packet, documentId, phase) {
|
||||
return { ...packet, __artplayerIframe: { version: 1, document: documentId, phase } };
|
||||
}
|
||||
function acceptsMessage(event, peer) {
|
||||
if (event.source !== void 0 && event.source !== null && event.source !== peer)
|
||||
return false;
|
||||
const data = event.data;
|
||||
return typeof data === "object" && data !== null && "type" in data && typeof data.type === "string";
|
||||
}
|
||||
let session;
|
||||
function prepareChildSession() {
|
||||
if (session?.owner === window.document && session)
|
||||
return;
|
||||
const random = new Uint32Array(4);
|
||||
if (window.crypto?.getRandomValues)
|
||||
window.crypto.getRandomValues(random);
|
||||
else
|
||||
random.forEach((_, index) => random[index] = Math.floor(Math.random() * 4294967296));
|
||||
session = { owner: window.document, id: `${Date.now()}-${Array.from(random).join("-")}`, acknowledged: false, lifecycle: false, receivers: /* @__PURE__ */ new Set() };
|
||||
}
|
||||
function childEnvelope(packet) {
|
||||
if (session && (packet.type === "inject" || session.acknowledged))
|
||||
return withSession(packet, session.id, packet.type === "inject" ? "inject" : "message");
|
||||
return packet;
|
||||
}
|
||||
function consumeChildSession(packet) {
|
||||
const metadata = sessionMetadata(packet);
|
||||
if (!metadata)
|
||||
return false;
|
||||
if (packet.type === sessionType) {
|
||||
if (session && metadata.document === session.id && metadata.phase === "ack")
|
||||
session.acknowledged = true;
|
||||
return true;
|
||||
}
|
||||
return !session || metadata.document !== session.id;
|
||||
}
|
||||
function connectChildSession(receiver) {
|
||||
const current = session;
|
||||
const added = !current.receivers.has(receiver);
|
||||
const installing = !current.lifecycle;
|
||||
const notify = (phase, data) => {
|
||||
if (!current.acknowledged)
|
||||
return;
|
||||
try {
|
||||
window.parent.postMessage(withSession({ type: sessionType, data, id: 0 }, current.id, phase), "*");
|
||||
} catch {
|
||||
}
|
||||
};
|
||||
const leave = () => notify("leave");
|
||||
const fragment = () => notify("fragment", window.location.href);
|
||||
const resume = (event) => {
|
||||
if (event.persisted)
|
||||
notify("resume");
|
||||
};
|
||||
try {
|
||||
window.addEventListener("message", receiver);
|
||||
current.receivers.add(receiver);
|
||||
if (!installing)
|
||||
return;
|
||||
window.addEventListener("pagehide", leave);
|
||||
window.addEventListener("pageshow", resume);
|
||||
window.addEventListener("hashchange", fragment);
|
||||
current.lifecycle = true;
|
||||
} catch (error) {
|
||||
const cleanups = [];
|
||||
if (installing) {
|
||||
cleanups.push(() => window.removeEventListener("pagehide", leave));
|
||||
cleanups.push(() => window.removeEventListener("pageshow", resume));
|
||||
cleanups.push(() => window.removeEventListener("hashchange", fragment));
|
||||
}
|
||||
if (added)
|
||||
cleanups.push(() => window.removeEventListener("message", receiver));
|
||||
for (const cleanup of cleanups) {
|
||||
try {
|
||||
cleanup();
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
if (added)
|
||||
current.receivers.delete(receiver);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
const requests = /* @__PURE__ */ new WeakMap();
|
||||
const boundaries = /* @__PURE__ */ new WeakMap();
|
||||
let lastId = 0;
|
||||
function setRequestBoundary(host, boundary) {
|
||||
if (boundary)
|
||||
boundaries.set(host, boundary);
|
||||
else
|
||||
boundaries.delete(host);
|
||||
}
|
||||
function postRequest(host, { type, data }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (host.destroyed) {
|
||||
@@ -35,6 +131,10 @@ function postRequest(host, { type, data }) {
|
||||
if (finish(request))
|
||||
reject(error);
|
||||
}
|
||||
},
|
||||
cancel(error) {
|
||||
if (finish(request))
|
||||
reject(error);
|
||||
}
|
||||
};
|
||||
pending.add(request);
|
||||
@@ -43,40 +143,209 @@ function postRequest(host, { type, data }) {
|
||||
if (!pending.has(request))
|
||||
return;
|
||||
if (host.destroyed) {
|
||||
request.callbacks.reject(new Error("The instance has been destroyed"));
|
||||
request.cancel(new Error("The instance has been destroyed"));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
boundaries.get(host)?.prepare();
|
||||
if (!pending.has(request))
|
||||
return;
|
||||
if (host.injected) {
|
||||
const id = Math.max(Date.now(), lastId + 1);
|
||||
lastId = id;
|
||||
request.id = id;
|
||||
host.promises[id] = request.callbacks;
|
||||
host.$iframe.contentWindow.postMessage({ type, data, id }, "*");
|
||||
const packet = { type, data, id };
|
||||
host.$iframe.contentWindow.postMessage(boundaries.get(host)?.envelope(packet) || packet, "*");
|
||||
} else {
|
||||
request.timer = setTimeout(loop, 200);
|
||||
}
|
||||
} catch (error) {
|
||||
request.callbacks.reject(error);
|
||||
request.cancel(error);
|
||||
}
|
||||
};
|
||||
loop();
|
||||
});
|
||||
}
|
||||
function cancelRequests(host) {
|
||||
function cancelRequests(host, reason = new Error("The instance has been destroyed")) {
|
||||
const pending = requests.get(host);
|
||||
if (!pending)
|
||||
return;
|
||||
for (const request of [...pending])
|
||||
request.callbacks.reject(new Error("The instance has been destroyed"));
|
||||
request.cancel(reason);
|
||||
}
|
||||
function captureRequests(host) {
|
||||
const captured = [...requests.get(host) || []];
|
||||
return (reason) => {
|
||||
for (const request of captured)
|
||||
request.cancel(reason);
|
||||
};
|
||||
}
|
||||
const navigations = /* @__PURE__ */ new WeakMap();
|
||||
const withoutHash = (value) => value.split("#")[0];
|
||||
function sourceOf(host) {
|
||||
const frame = host.$iframe;
|
||||
return frame.hasAttribute?.("srcdoc") ? `srcdoc:${frame.getAttribute("srcdoc")}` : `src:${withoutHash(frame.src || "")}`;
|
||||
}
|
||||
function rawSourceOf(host) {
|
||||
const frame = host.$iframe;
|
||||
return frame.hasAttribute?.("srcdoc") ? `srcdoc:${frame.getAttribute("srcdoc")}` : `src:${frame.getAttribute?.("src") ?? frame.src ?? ""}`;
|
||||
}
|
||||
function invalidate(host, state) {
|
||||
if (!state.waiting) {
|
||||
if (state.documentId)
|
||||
state.cancelPrevious = captureRequests(host);
|
||||
else
|
||||
cancelRequests(host, new Error("The iframe document has changed"));
|
||||
}
|
||||
state.waiting = true;
|
||||
host.injected = false;
|
||||
}
|
||||
function leaveDocument(host, state) {
|
||||
if (state.cancelPrevious)
|
||||
state.cancelPrevious(new Error("The iframe document has changed"));
|
||||
else if (!state.waiting)
|
||||
cancelRequests(host, new Error("The iframe document has changed"));
|
||||
state.cancelPrevious = void 0;
|
||||
state.waiting = true;
|
||||
host.injected = false;
|
||||
}
|
||||
function sourceChanged(host, state, records) {
|
||||
if (sourceOf(host) !== state.source)
|
||||
return true;
|
||||
if (!state.documentId)
|
||||
return false;
|
||||
if (rawSourceOf(host) !== state.rawSource)
|
||||
return true;
|
||||
return records.some((record) => {
|
||||
if (record.attributeName === "srcdoc")
|
||||
return true;
|
||||
if (record.attributeName !== "src" || host.$iframe.hasAttribute?.("srcdoc"))
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
function observeSource(host, state, records) {
|
||||
const rawSource = rawSourceOf(host);
|
||||
if (!records.length && rawSource === state.rawSource)
|
||||
return;
|
||||
const changed = sourceChanged(host, state, records);
|
||||
state.rawSource = rawSource;
|
||||
state.source = sourceOf(host);
|
||||
if (changed)
|
||||
invalidate(host, state);
|
||||
}
|
||||
function prepareNavigation(host) {
|
||||
const state = navigations.get(host);
|
||||
if (!state || host.destroyed)
|
||||
return;
|
||||
const records = state.observer?.takeRecords() || [];
|
||||
observeSource(host, state, records);
|
||||
}
|
||||
function createNavigation(host) {
|
||||
const state = { source: sourceOf(host), rawSource: rawSourceOf(host), hasHandshake: false, waiting: false };
|
||||
navigations.set(host, state);
|
||||
setRequestBoundary(host, {
|
||||
prepare: () => prepareNavigation(host),
|
||||
envelope: (packet) => state.documentId ? withSession(packet, state.documentId, "message") : packet
|
||||
});
|
||||
return {
|
||||
start() {
|
||||
if (typeof window.MutationObserver !== "function")
|
||||
return;
|
||||
state.observer = new window.MutationObserver((records) => {
|
||||
if (host.destroyed)
|
||||
return;
|
||||
observeSource(host, state, records);
|
||||
});
|
||||
state.observer.observe(host.$iframe, { attributes: true, attributeOldValue: true, attributeFilter: ["src", "srcdoc"] });
|
||||
},
|
||||
dispose() {
|
||||
navigations.delete(host);
|
||||
setRequestBoundary(host, void 0);
|
||||
state.cancelPrevious = void 0;
|
||||
state.observer?.disconnect();
|
||||
}
|
||||
};
|
||||
}
|
||||
function activate(host, state, documentId) {
|
||||
if (state.hasHandshake && state.documentId !== documentId) {
|
||||
if (state.cancelPrevious)
|
||||
state.cancelPrevious(new Error("The iframe document has changed"));
|
||||
else if (!state.waiting)
|
||||
cancelRequests(host, new Error("The iframe document has changed"));
|
||||
}
|
||||
state.cancelPrevious = void 0;
|
||||
state.documentId = documentId;
|
||||
state.hasHandshake = true;
|
||||
state.waiting = false;
|
||||
host.injected = true;
|
||||
try {
|
||||
host.$iframe.contentWindow?.postMessage(withSession({ type: sessionType, data: void 0, id: 0 }, documentId, "ack"), "*");
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
function consumeNavigation(host, packet) {
|
||||
const state = navigations.get(host);
|
||||
if (!state)
|
||||
return false;
|
||||
prepareNavigation(host);
|
||||
const metadata = sessionMetadata(packet);
|
||||
if (metadata && packet.type === sessionType) {
|
||||
if (metadata.phase === "resume") {
|
||||
activate(host, state, metadata.document);
|
||||
} else if (metadata.document === state.documentId) {
|
||||
if (metadata.phase === "leave")
|
||||
leaveDocument(host, state);
|
||||
else if (metadata.phase === "fragment" && state.cancelPrevious && !host.$iframe.hasAttribute?.("srcdoc") && packet.data === host.$iframe.src)
|
||||
activate(host, state, metadata.document);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (packet.type === "inject") {
|
||||
if (metadata?.phase === "inject") {
|
||||
if (state.waiting && metadata.document === state.documentId)
|
||||
return true;
|
||||
activate(host, state, metadata.document);
|
||||
} else {
|
||||
if (state.waiting) {
|
||||
state.cancelPrevious?.(new Error("The iframe document has changed"));
|
||||
state.cancelPrevious = void 0;
|
||||
state.documentId = void 0;
|
||||
}
|
||||
state.hasHandshake = true;
|
||||
state.waiting = false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return Boolean(metadata && (state.waiting && !state.cancelPrevious || metadata.document !== state.documentId));
|
||||
}
|
||||
const connections = /* @__PURE__ */ new WeakMap();
|
||||
function connect(host) {
|
||||
const owner = window;
|
||||
const receiver = host.onMessage;
|
||||
connections.set(host, () => owner.removeEventListener("message", receiver));
|
||||
const cleanups = [() => owner.removeEventListener("message", receiver)];
|
||||
connections.set(host, () => {
|
||||
let failed = false;
|
||||
let failure;
|
||||
for (const cleanup of cleanups) {
|
||||
try {
|
||||
cleanup();
|
||||
} catch (error) {
|
||||
if (!failed) {
|
||||
failed = true;
|
||||
failure = error;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (failed)
|
||||
throw failure;
|
||||
});
|
||||
owner.addEventListener("message", receiver);
|
||||
host.$iframe.src = host.url;
|
||||
const navigation = createNavigation(host);
|
||||
cleanups.push(navigation.dispose);
|
||||
navigation.start();
|
||||
}
|
||||
function releaseConnection(host) {
|
||||
const disconnect = connections.get(host);
|
||||
@@ -87,12 +356,6 @@ function releaseConnection(host) {
|
||||
cancelRequests(host);
|
||||
}
|
||||
}
|
||||
function acceptsMessage(event, peer) {
|
||||
if (event.source !== void 0 && event.source !== null && event.source !== peer)
|
||||
return false;
|
||||
const data = event.data;
|
||||
return typeof data === "object" && data !== null && "type" in data && typeof data.type === "string";
|
||||
}
|
||||
class ArtplayerToolIframe {
|
||||
static get iframe() {
|
||||
return window.top !== window;
|
||||
@@ -102,11 +365,11 @@ class ArtplayerToolIframe {
|
||||
throw new Error('The "ArtplayerToolIframe.postMessage" method can only be used in iframe');
|
||||
}
|
||||
window.parent.postMessage(
|
||||
{
|
||||
childEnvelope({
|
||||
type,
|
||||
data,
|
||||
id
|
||||
},
|
||||
}),
|
||||
"*"
|
||||
);
|
||||
}
|
||||
@@ -114,7 +377,7 @@ class ArtplayerToolIframe {
|
||||
if (!ArtplayerToolIframe.iframe) {
|
||||
throw new Error('The "ArtplayerToolIframe.onMessage" method can only be used in iframe');
|
||||
}
|
||||
if (!acceptsMessage(event, window.parent))
|
||||
if (!acceptsMessage(event, window.parent) || consumeChildSession(event.data))
|
||||
return;
|
||||
const { type, data, id } = event.data;
|
||||
switch (type) {
|
||||
@@ -141,8 +404,9 @@ ${data}
|
||||
if (!ArtplayerToolIframe.iframe) {
|
||||
throw new Error('The "ArtplayerToolIframe.inject" method can only be used in iframe');
|
||||
}
|
||||
prepareChildSession();
|
||||
ArtplayerToolIframe.postMessage({ type: "inject" });
|
||||
window.addEventListener("message", ArtplayerToolIframe.onMessage);
|
||||
connectChildSession(ArtplayerToolIframe.onMessage);
|
||||
}
|
||||
constructor({ iframe, url }) {
|
||||
if (iframe instanceof HTMLIFrameElement === false) {
|
||||
@@ -170,7 +434,7 @@ ${data}
|
||||
}
|
||||
}
|
||||
onMessage(event) {
|
||||
if (this.destroyed || !acceptsMessage(event, this.$iframe.contentWindow))
|
||||
if (this.destroyed || !acceptsMessage(event, this.$iframe.contentWindow) || consumeNavigation(this, event.data))
|
||||
return;
|
||||
const { type, data, id } = event.data;
|
||||
switch (type) {
|
||||
@@ -191,6 +455,7 @@ ${data}
|
||||
}
|
||||
}
|
||||
postMessage(message) {
|
||||
prepareNavigation(this);
|
||||
return postRequest(this, message);
|
||||
}
|
||||
commit(callback) {
|
||||
|
||||
Reference in new issue
Block a user