import { __awaiter, __generator } from "tslib";
import { isBlob, isPromiseLike } from 'ut2';
import dataURLToBlob from './dataURLToBlob';
import isUrl from './isUrl';
import ajax from './ajax';
import { createObjectURL, nativeUndefined, revokeObjectURL } from './utils/native';
// 下载文件到本地
function saver(blobUrl, fileName) {
if (fileName === void 0) { fileName = ''; }
var anchor = document.createElement('a');
// anchor.href = decodeURIComponent(blobUrl);
anchor.href = blobUrl;
anchor.style.display = 'none';
anchor.setAttribute('download', fileName);
// 处理点击事件,防止事件冒泡到 body/html 的点击事件。
function handleClick(e) {
e.stopPropagation();
anchor.removeEventListener('click', handleClick);
}
anchor.addEventListener('click', handleClick);
document.body.appendChild(anchor);
anchor.click();
document.body.removeChild(anchor);
}
/**
* @callback TransformRequest
* @param {AjaxOptions} options ajax 配置项
* @returns {AjaxOptions | Promise<AjaxOptions>}
*/
/**
* @callback TransformResponse
* @param {Blob} res 响应的Blob对象。如果你通过 transformRequest 修改了 responseType ,该参数将是该类型响应值。
* @returns {Blob | Promise<Blob>}
*/
/**
* @typedef {Object} DownloadOptions 下载配置项
* @property {string} [options.fileName] 文件名称
* @property {string} [options.type] MIME 类型
* @property {'url'|'text'} [options.dataType] 手动设置数据类型,默认会根据传入的数据判断类型,主要是为了区分 url 和 text 。<br/>如果你要下载的文本是 url ,请设置 'text' ;如果你要下载的 url 是绝对/相对路径,请设置 'url' 。
* @property {TransformRequest} [options.transformRequest] 请求前触发,XHR 对象或配置调整
* @property {TransformResponse} [options.transformResponse] 请求成功后触发,在传递给 then/catch 前,允许修改响应数据
*/
/**
* 下载
*
* <em style="font-weight: bold;">注意:该方法仅适用于浏览器端,兼容 IE10+ 和现代浏览器。</em>
*
* <em style="font-weight: bold;">注意:微信浏览器不支持H5下载文件。</em>
*
* @static
* @alias module:Other.download
* @since 4.16.0
* @see {@link https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Access-Control-Expose-Headers | Access-Control-Expose-Headers}
* @see {@link https://zh.wikipedia.org/wiki/多用途互聯網郵件擴展 | MIME}
* @see {@link https://9ykc9s.csb.app/ | 在线示例}
* @param {string|Blob|ArrayBuffer|TypedArray} data 字符串、blob数据或url地址
* @param {string|DownloadOptions} [options] 文件名称 或 配置项
* @returns {Promise<void>}
* @example
* // 文本
* download('hello world', 'text.txt');
*
* // 远程文件1
* // 不带协议的绝对地址,需要通过 dataType 指定为 url 类型
* download('/xxx.jpg', { dataType: 'url', fileName: 'test.jpg' });
*
* // 远程文件2
* download('https://example.com/xxx.jpg');
*
* // base64
* download('data:image/png;base64,PGEgaWQ9ImEiPjxiIGlkPSJiIj5oZXkhPC9iPjwvYT4=', 'test.png');
*
* // blob文件
* download(new Blob(['hello world']), 'text.txt');
*
* // 本地文件
* download(File, 'filename.ext');
*
*/
function download(data, options) {
return __awaiter(this, void 0, void 0, function () {
var config, fileName, type, dataType, transformRequest, transformResponse, payload, asyncTransformRequest, asyncTransformResponse, ajaxOptions, ev, res, currentFileName, url;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
config = typeof options === 'object' ? options : {};
if (typeof options === 'string') {
config.fileName = options;
}
fileName = config.fileName, type = config.type, dataType = config.dataType, transformRequest = config.transformRequest, transformResponse = config.transformResponse;
if (!(typeof data === 'string')) return [3 /*break*/, 8];
if (!(!dataType && /^blob:.*?\/.*/.test(data))) return [3 /*break*/, 1];
// blob url
saver(data, fileName);
return [2 /*return*/, Promise.resolve()];
case 1:
if (!(!dataType && /^data:([\w+-]+\/[\w+.-]+)?[,;]/.test(data))) return [3 /*break*/, 2];
// dataURLs
payload = dataURLToBlob(data);
return [3 /*break*/, 7];
case 2:
if (!(dataType === 'url' || (!dataType && isUrl(data)))) return [3 /*break*/, 6];
asyncTransformRequest = function (opts) {
// 请求前配置调整
var tempOptions = typeof transformRequest === 'function' ? transformRequest(opts) : opts;
return isPromiseLike(tempOptions) ? tempOptions : Promise.resolve(tempOptions);
};
asyncTransformResponse = function (res) {
var tempRes = typeof transformResponse === 'function' ? transformResponse(res) : res;
return isPromiseLike(tempRes) ? tempRes : Promise.resolve(tempRes);
};
return [4 /*yield*/, asyncTransformRequest({ responseType: 'blob' })];
case 3:
ajaxOptions = _a.sent();
return [4 /*yield*/, ajax(data, ajaxOptions)];
case 4:
ev = _a.sent();
return [4 /*yield*/, asyncTransformResponse(ev.target.response)];
case 5:
res = _a.sent();
currentFileName = fileName || data.split('?')[0].split('#')[0].split('/').pop();
return [2 /*return*/, download(res, { fileName: currentFileName, type: type || (isBlob(res) ? res.type : nativeUndefined) })];
case 6:
// string
payload = new Blob([data], { type: type || 'text/plain' });
_a.label = 7;
case 7: return [3 /*break*/, 9];
case 8:
if (data instanceof Blob) {
// File or Blob
payload = data;
}
_a.label = 9;
case 9:
// html、TypedArray
if (!payload) {
payload = new Blob([data], { type: type });
}
// @ts-ignore
if (navigator.msSaveBlob) {
// @ts-ignore
navigator.msSaveBlob(payload, fileName || 'download');
}
else {
url = createObjectURL(payload);
saver(url, fileName);
revokeObjectURL(url);
}
return [2 /*return*/, Promise.resolve()];
}
});
});
}
export default download;