'use strict' class BlackDocument { public root: Element public methods!: Object public sandbox!: HTMLIFrameElement constructor (template: string, root: Element = document.body, csp: string = `default-src 'self';`, type?: string) { this.root = root this.create(template, csp, type) // @ts-ignore return this.run.bind(this) } hashSource () { return (new Array(8 + Math.round(Math.random() * 8))).join(',').split(',').map(() => { return String.fromCharCode(97 + Math.round(Math.random() * 25)) }).join('') } injectRequestParentAction (csp: string) { let hash = this.hashSource() window.addEventListener('message', (data) => { let result = data.data || {} let method = result.method let params = result.params let postToSandbox = (data: object) => { if (this.sandbox.contentWindow) { this.sandbox.contentWindow.postMessage({ data, key: method + ':' + JSON.stringify(params) }, '*') } } if (result.hash === hash) { let func = this.methods[method] let promise: object | Promise if (typeof func === 'function') { promise = func(params) } else { promise = func } if (promise instanceof Promise) { promise.then(postToSandbox) } else { postToSandbox(promise) } } }, false) return ` ` } create (template: string, csp: string, type = 'fullscreen') { let iframe = document.createElement('iframe') iframe.csp = csp iframe.src = URL.createObjectURL(new Blob([`${this.injectRequestParentAction(csp)} ;\n ${template}`], { type: 'text/html' })) iframe.setAttribute('sandbox', 'allow-scripts') if (type === 'fullscreen') iframe.setAttribute('style', `position: fixed; top: 0; right: 0; bottom: 0; left: 0; width: 100%; height: 100%`) this.sandbox = iframe } run (methods: object) { this.methods = methods this.root.appendChild(this.sandbox) } } export { BlackDocument }