diff --git a/src/btn.ts b/src/btn.ts index 0bd6a9c..47b543f 100644 --- a/src/btn.ts +++ b/src/btn.ts @@ -1,7 +1,7 @@ import { ScoreInfo } from './scoreinfo' import { loadMscore, WebMscore } from './mscore' -import { useTimeout, windowOpen, console, attachShadow } from './utils' +import { useTimeout, windowOpenAsync, console, attachShadow } from './utils' import i18n from './i18n' // @ts-ignore import btnListCss from './btn.css' @@ -116,7 +116,7 @@ export class BtnList { /** * replace the template button with the list of new buttons */ - commit (mode: BtnListMode = BtnListMode.InPage): void { + async commit (mode: BtnListMode = BtnListMode.InPage): Promise { switch (mode) { case BtnListMode.InPage: { // fallback to BtnListMode.ExtWindow @@ -148,7 +148,7 @@ export class BtnList { case BtnListMode.ExtWindow: { const div = this._commit() - const w = windowOpen('', undefined, 'resizable,width=230,height=270') + const w = await windowOpenAsync('', undefined, 'resizable,width=230,height=270') // eslint-disable-next-line no-unused-expressions w?.document.body.append(div) window.addEventListener('unload', () => w?.close()) @@ -176,7 +176,7 @@ export namespace BtnAction { export const openUrl = (url: UrlInput): BtnAction => { return process(async (): Promise => { - windowOpen(await normalizeUrlInput(url)) + return windowOpenAsync(await normalizeUrlInput(url)) }) } @@ -195,7 +195,7 @@ export namespace BtnAction { btn.onclick = null setText(i18n('PROCESSING')()) - const w = windowOpen('') as Window + const w = await windowOpenAsync('') as Window const txt = document.createTextNode(i18n('PROCESSING')()) w.document.body.append(txt) diff --git a/src/utils.ts b/src/utils.ts index 857be1a..5fdaf79 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -47,6 +47,21 @@ export const useTimeout = async (promise: T | Promise, ms: number): Promi }) } +export const getSandboxWindowAsync = async (): Promise => { + if (typeof document === 'undefined') return {} as any as Window + + return new Promise((resolve) => { + window.onmouseover = () => { + const iframe = document.createElement('iframe') + iframe.style.display = 'none' + document.body.append(iframe) + const w = iframe.contentWindow + window.onmouseover = null + resolve(w as Window) + } + }) +} + export const getUnsafeWindow = (): Window => { // eslint-disable-next-line no-eval return window.eval('window') as Window @@ -54,8 +69,8 @@ export const getUnsafeWindow = (): Window => { export const console: Console = (window || global).console // Object.is(window.console, unsafeWindow.console) == false -export const windowOpen: Window['open'] = (...args): Window | null => { - return window.open(...args) // Object.is(window.open, unsafeWindow.open) == false +export const windowOpenAsync = (...args: Parameters): Promise => { + return getSandboxWindowAsync().then(w => w.open(...args)) } export const attachShadow = (el: Element): ShadowRoot => {