diff --git a/src/btn.ts b/src/btn.ts index 63b30c6..9571fee 100644 --- a/src/btn.ts +++ b/src/btn.ts @@ -1,5 +1,6 @@ import { loadMscore, WebMscore } from './mscore' +import { useTimeout } from './utils' import i18n from './i18n' // @ts-ignore import btnListCss from './btn.css' @@ -159,12 +160,18 @@ export namespace BtnAction { }) } - export const download = (url: UrlInput): BtnAction => { - return process(async (): Promise => { - const _url = await normalizeUrlInput(url) - const a = document.createElement('a') - a.href = _url - a.dispatchEvent(new MouseEvent('click')) + export const download = (url: UrlInput, fallback?: () => Promisable, timeout = 30 * 1000): BtnAction => { + return process(async (): Promise => { + try { + const _url = await useTimeout(normalizeUrlInput(url), timeout) + const a = document.createElement('a') + a.href = _url + a.dispatchEvent(new MouseEvent('click')) + } catch (err) { + // use fallback + console.error(err) + return fallback?.() + } }) } diff --git a/src/main.ts b/src/main.ts index 9cbce7c..d68aed8 100644 --- a/src/main.ts +++ b/src/main.ts @@ -13,6 +13,8 @@ const main = (): void => { const btnList = new BtnList() const filename = scoreinfo.fileName + let indvPartBtn: HTMLButtonElement | null = null + btnList.add({ name: i18n('DOWNLOAD')('MSCZ'), action: BtnAction.process(downloadMscz), @@ -35,15 +37,15 @@ const main = (): void => { btnList.add({ name: i18n('DOWNLOAD')('MIDI'), - action: BtnAction.download(() => getFileUrl('midi')), + action: BtnAction.download(() => getFileUrl('midi'), () => indvPartBtn?.click()), }) btnList.add({ name: i18n('DOWNLOAD')('MP3'), - action: BtnAction.download(() => getFileUrl('mp3')), + action: BtnAction.download(() => getFileUrl('mp3'), () => indvPartBtn?.click()), }) - btnList.add({ + indvPartBtn = btnList.add({ name: i18n('IND_PARTS')(), tooltip: i18n('IND_PARTS_TOOLTIP')(), action: BtnAction.mscoreWindow(async (w, score, txt) => { diff --git a/src/utils.ts b/src/utils.ts index ee5b88e..2665295 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -19,6 +19,19 @@ export const fetchData = async (url: string, init?: RequestInit): Promise (promise: T | Promise, ms: number): Promise => { + if (!(promise instanceof Promise)) { + return promise + } + + return new Promise((resolve, reject) => { + const i = setTimeout(() => { + reject(new Error('timeout')) + }, ms) + promise.then(resolve, reject).finally(() => clearTimeout(i)) + }) +} + export const waitForDocumentLoaded = (): Promise => { if (document.readyState !== 'complete') { return new Promise(resolve => {