UNPKG

shadow-function

Version:

ioing lib - shadow Function, worker Function

90 lines (81 loc) 2.87 kB
'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<object> if (typeof func === 'function') { promise = func(params) } else { promise = func } if (promise instanceof Promise) { promise.then(postToSandbox) } else { postToSandbox(promise) } } }, false) return ` <meta http-equiv="Content-Security-Policy" content="${csp}"> <script> window.requestParentAction = function (method, params) { parent.postMessage({ method: method, params: params, hash: '${hash}' }, '${location.origin}') return new Promise(function (reslove, reject) { function callback (data) { if (data && data.data && data.data.data) { if (method + ':' + JSON.stringify(params) === data.data.key) { window.removeEventListener('message', callback) reslove(data.data.data) } } else { reject() } } window.addEventListener('message', callback) }) } </script> ` } 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 }