UNPKG

web-portals

Version:

web-portals

137 lines (127 loc) 4.41 kB
import { ModuleState } from './state' import { ModuleManifest, Application } from '../types' class ModuleMount extends ModuleState { constructor (id: string, model: ModuleManifest, application: Application) { super(id, model, application) } public timeTick () { if (Date.now() - this.createTime > (this.config.timeout || 3600000)) { if (this.shadowView) this.destroy() } } public show () { if (this.viewType !== 'iframe') return const sandbox = this.shadowView as HTMLIFrameElement const contentWindow = sandbox?.contentWindow if (contentWindow) { contentWindow.window.postMessage({ type: 'module-visible', historyDirection: this.application.transform.historyDirection }, '*') if (this.sameOrigin) { contentWindow.window['moduleVisibilityState'] = 'visible' } } } public hide () { if (this.viewType !== 'iframe') return const sandbox = this.shadowView as HTMLIFrameElement const contentWindow = sandbox?.contentWindow?.window if (contentWindow) { contentWindow.postMessage({ type: 'module-hidden', historyDirection: this.application.transform.historyDirection }, '*') if (this.sameOrigin) { contentWindow['moduleVisibilityState'] = 'visible' } } } public destroy () { return new Promise<void>((resolve, reject) => { if (this.rel !== 'module') return reject() if (this.application.transform?.id === this.id) return reject() if (this.viewType === 'iframe') this.unload().catch(reject) this.elements.container.parentElement?.removeChild(this.elements.container) this.status.prefetch = this.status.preload = this.status.prerender = false this.shadowView = null this.status.init = false this.events?.destroy.bind(this)() resolve() }) } public fate () { return new Promise<void>((resolve, reject) => { if (this.rel !== 'module') return reject() if (this.config.background === false) return resolve() if (this.viewType !== 'iframe') return resolve() if (this.sameOrigin === false) return resolve() const sandbox = this.shadowView as HTMLIFrameElement if (!sandbox) return try { const contentDocumentElement = sandbox.contentDocument?.documentElement if (document.getElementsByTagName('video')[0]) return resolve() if (document.getElementsByTagName('source')[0]) return resolve() if (document.getElementsByTagName('object')[0]) return resolve() if (document.getElementsByTagName('audio')[0]) return resolve() if (document.getElementsByTagName('embed')[0]) return resolve() if (document.getElementsByTagName('applet')[0]) return resolve() if (document.getElementsByTagName('iframe')[0]) return resolve() if (contentDocumentElement) { const counter = { times: 0 } this.mutationObserver = new MutationObserver(() => { counter.times++ if (counter.times > 1000) { resolve() this.mutationObserver.disconnect() } }) this.mutationObserver.observe(contentDocumentElement, { subtree: true, attributes: true, childList: true, characterData: true, attributeOldValue: true, characterDataOldValue: true }) setTimeout(() => { if (counter.times > 10) resolve() }, 3000) } else { reject() } } catch (error) { reject() } }) } public unfate () { this.mutationObserver?.disconnect() } private unload () { return new Promise<void>((resolve, reject) => { this.unfate() const sandbox = this.shadowView as HTMLIFrameElement if (!sandbox) return resolve() sandbox.style.display = 'none' sandbox.src = 'about:blank' try { const contentWindow = sandbox.contentWindow?.window const contentDocument = sandbox.contentDocument contentWindow?.location.reload() contentDocument?.open() contentDocument?.write('') contentDocument?.close() } catch (error) { reject() } sandbox.parentElement?.removeChild(sandbox) resolve() }) } } export { ModuleMount }