function bom(blob: any, opts: any) { if (typeof opts === "undefined") opts = { autoBom: false }; else if (typeof opts !== "object") { console.warn("Deprecated: Expected third argument to be a object"); opts = { autoBom: !opts }; } if ( opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test( blob.type ) ) { return new Blob([String.fromCharCode(0xfeff), blob], { type: blob.type }); } return blob; } function download(url: string, name: string, opts: any): Promise { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open("GET", url); xhr.responseType = "blob"; xhr.onload = function () { saveAs(xhr.response, name, opts).then(resolve); }; xhr.onerror = function () { reject("could not download file"); }; xhr.send(); }); } function corsEnabled(url: any) { const xhr = new XMLHttpRequest(); // use sync to avoid popup blocker xhr.open("HEAD", url, false); try { xhr.send(); } catch (e) {} return xhr.status >= 200 && xhr.status <= 299; } function click(node: any) { return new Promise((resolve) => { setTimeout(() => { try { node.dispatchEvent(new MouseEvent("click")); } catch (e) { const evt = document.createEvent("MouseEvents"); evt.initMouseEvent( "click", true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null ); node.dispatchEvent(evt); } resolve(); }, 0); }); } const isMacOSWebView = navigator && /Macintosh/.test(navigator.userAgent) && /AppleWebKit/.test(navigator.userAgent) && !/Safari/.test(navigator.userAgent); const global = window; type SaveAs = ( blob: Blob | string, name?: string, opts?: { autoBom: boolean } ) => Promise; export const saveAs: SaveAs = "download" in HTMLAnchorElement.prototype && !isMacOSWebView ? (blob, name = "download", opts) => { debugger; const URL = global.URL || global.webkitURL; const a = document.createElement("a"); a.download = name; a.rel = "noopener"; if (typeof blob === "string") { a.href = blob; // if (a.origin !== location.origin) { // if (corsEnabled(a.href)) { // return download(blob, name, opts); // } // a.target = "_blank"; // } return click(a); } else { a.href = URL.createObjectURL(blob); setTimeout(function () { URL.revokeObjectURL(a.href); }, 4e4); // 40s return click(a); } } : "msSaveOrOpenBlob" in navigator ? (blob, name = "download", opts) => { if (typeof blob === "string") { if (corsEnabled(blob)) { return download(blob, name, opts); } else { const a = document.createElement("a"); a.href = blob; a.target = "_blank"; return click(a); } } else { return (navigator as any).msSaveOrOpenBlob(bom(blob, opts), name) ? Promise.resolve() : Promise.reject("unknown"); } } : (blob, name, opts) => { if (typeof blob === "string") return download(blob, name as string, opts); const force = blob.type === "application/octet-stream"; const isSafari = /constructor/i.test(HTMLElement.toString()) || (global as any).safari; const isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent); if ( (isChromeIOS || (force && isSafari) || isMacOSWebView) && typeof FileReader !== "undefined" ) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onloadend = function () { let url = reader.result as string; url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, "data:attachment/file;"); location.href = url; resolve(); }; reader.onerror = function () { reject(); }; reader.readAsDataURL(blob); }); } else { const URL = global.URL || global.webkitURL; const url = URL.createObjectURL(blob); location.href = url; setTimeout(function () { URL.revokeObjectURL(url); }, 4e4); // 40s return Promise.resolve(); } }; export default saveAs;