/*! * Name: vue-upload-component * Version: 2.8.22 * Author: LianYue */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global.VueUploadComponent = factory()); }(this, (function () { 'use strict'; /** * Creates a XHR request * * @param {Object} options */ var createRequest = function createRequest(options) { var xhr = new XMLHttpRequest(); xhr.open(options.method || 'GET', options.url); xhr.responseType = 'json'; if (options.headers) { Object.keys(options.headers).forEach(function (key) { xhr.setRequestHeader(key, options.headers[key]); }); } return xhr; }; /** * Sends a XHR request with certain body * * @param {XMLHttpRequest} xhr * @param {Object} body */ var sendRequest = function sendRequest(xhr, body) { return new Promise(function (resolve, reject) { xhr.onload = function () { if (xhr.status >= 200 && xhr.status < 300) { var response; try { response = JSON.parse(xhr.response); } catch (err) { response = xhr.response; } resolve(response); } else { reject(xhr.response); } }; xhr.onerror = function () { return reject(xhr.response); }; xhr.send(JSON.stringify(body)); }); }; /** * Sends a XHR request with certain form data * * @param {XMLHttpRequest} xhr * @param {Object} data */ var sendFormRequest = function sendFormRequest(xhr, data) { var body = new FormData(); for (var name in data) { body.append(name, data[name]); } return new Promise(function (resolve, reject) { xhr.onload = function () { if (xhr.status >= 200 && xhr.status < 300) { var response; try { response = JSON.parse(xhr.response); } catch (err) { response = xhr.response; } resolve(response); } else { reject(xhr.response); } }; xhr.onerror = function () { return reject(xhr.response); }; xhr.send(body); }); }; /** * Creates and sends XHR request * * @param {Object} options * * @returns Promise */ function request (options) { var xhr = createRequest(options); return sendRequest(xhr, options.body); } var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var ChunkUploadHandler = function () { /** * Constructor * * @param {File} file * @param {Object} options */ function ChunkUploadHandler(file, options) { _classCallCheck(this, ChunkUploadHandler); this.file = file; this.options = options; this.chunks = []; this.sessionId = null; this.chunkSize = null; this.speedInterval = null; } /** * Gets the max retries from options */ _createClass(ChunkUploadHandler, [{ key: 'createChunks', /** * Creates all the chunks in the initial state */ value: function createChunks() { this.chunks = []; var start = 0; var end = this.chunkSize; while (start < this.fileSize) { this.chunks.push({ blob: this.file.file.slice(start, end), startOffset: start, active: false, retries: this.maxRetries }); start = end; end = start + this.chunkSize; } } /** * Updates the progress of the file with the handler's progress */ }, { key: 'updateFileProgress', value: function updateFileProgress() { this.file.progress = this.progress; } /** * Paues the upload process * - Stops all active requests * - Sets the file not active */ }, { key: 'pause', value: function pause() { this.file.active = false; this.stopChunks(); } /** * Stops all the current chunks */ }, { key: 'stopChunks', value: function stopChunks() { this.chunksUploading.forEach(function (chunk) { chunk.xhr.abort(); chunk.active = false; }); this.stopSpeedCalc(); } /** * Resumes the file upload * - Sets the file active * - Starts the following chunks */ }, { key: 'resume', value: function resume() { this.file.active = true; this.startChunking(); } /** * Starts the file upload * * @returns Promise * - resolve The file was uploaded * - reject The file upload failed */ }, { key: 'upload', value: function upload() { var _this = this; this.promise = new Promise(function (resolve, reject) { _this.resolve = resolve; _this.reject = reject; }); this.start(); return this.promise; } /** * Start phase * Sends a request to the backend to initialise the chunks */ }, { key: 'start', value: function start() { var _this2 = this; request({ method: 'POST', headers: Object.assign({}, this.headers, { 'Content-Type': 'application/json' }), url: this.action, body: Object.assign(this.startBody, { phase: 'start', mime_type: this.fileType, size: this.fileSize, name: this.fileName }) }).then(function (res) { if (res.status !== 'success') { _this2.file.response = res; return _this2.reject('server'); } _this2.sessionId = res.data.session_id; _this2.chunkSize = res.data.end_offset; _this2.createChunks(); _this2.startChunking(); }).catch(function (res) { _this2.file.response = res; _this2.reject('server'); }); } /** * Starts to upload chunks */ }, { key: 'startChunking', value: function startChunking() { for (var i = 0; i < this.maxActiveChunks; i++) { this.uploadNextChunk(); } this.startSpeedCalc(); } /** * Uploads the next chunk * - Won't do anything if the process is paused * - Will start finish phase if there are no more chunks to upload */ }, { key: 'uploadNextChunk', value: function uploadNextChunk() { if (this.file.active) { if (this.hasChunksToUpload) { return this.uploadChunk(this.chunksToUpload[0]); } if (this.chunksUploading.length === 0) { return this.finish(); } } } /** * Uploads a chunk * - Sends the chunk to the backend * - Sets the chunk as uploaded if everything went well * - Decreases the number of retries if anything went wrong * - Fails if there are no more retries * * @param {Object} chunk */ }, { key: 'uploadChunk', value: function uploadChunk(chunk) { var _this3 = this; chunk.progress = 0; chunk.active = true; this.updateFileProgress(); chunk.xhr = createRequest({ method: 'POST', headers: this.headers, url: this.action }); chunk.xhr.upload.addEventListener('progress', function (evt) { if (evt.lengthComputable) { chunk.progress = Math.round(evt.loaded / evt.total * 100); } }, false); sendFormRequest(chunk.xhr, Object.assign(this.uploadBody, { phase: 'upload', session_id: this.sessionId, start_offset: chunk.startOffset, chunk: chunk.blob })).then(function (res) { chunk.active = false; if (res.status === 'success') { chunk.uploaded = true; } else { if (chunk.retries-- <= 0) { _this3.stopChunks(); return _this3.reject('upload'); } } _this3.uploadNextChunk(); }).catch(function () { chunk.active = false; if (chunk.retries-- <= 0) { _this3.stopChunks(); return _this3.reject('upload'); } _this3.uploadNextChunk(); }); } /** * Finish phase * Sends a request to the backend to finish the process */ }, { key: 'finish', value: function finish() { var _this4 = this; this.updateFileProgress(); this.stopSpeedCalc(); request({ method: 'POST', headers: Object.assign({}, this.headers, { 'Content-Type': 'application/json' }), url: this.action, body: Object.assign(this.finishBody, { phase: 'finish', session_id: this.sessionId }) }).then(function (res) { _this4.file.response = res; if (res.status !== 'success') { return _this4.reject('server'); } _this4.resolve(res); }).catch(function (res) { _this4.file.response = res; _this4.reject('server'); }); } /** * Sets an interval to calculate and * set upload speed every 3 seconds */ }, { key: 'startSpeedCalc', value: function startSpeedCalc() { var _this5 = this; this.file.speed = 0; var lastUploadedBytes = 0; if (!this.speedInterval) { this.speedInterval = window.setInterval(function () { var uploadedBytes = _this5.progress / 100 * _this5.fileSize; _this5.file.speed = uploadedBytes - lastUploadedBytes; lastUploadedBytes = uploadedBytes; }, 1000); } } /** * Removes the upload speed interval */ }, { key: 'stopSpeedCalc', value: function stopSpeedCalc() { this.speedInterval && window.clearInterval(this.speedInterval); this.speedInterval = null; this.file.speed = 0; } }, { key: 'maxRetries', get: function get() { return parseInt(this.options.maxRetries, 10); } /** * Gets the max number of active chunks being uploaded at once from options */ }, { key: 'maxActiveChunks', get: function get() { return parseInt(this.options.maxActive, 10); } /** * Gets the file type */ }, { key: 'fileType', get: function get() { return this.file.type; } /** * Gets the file size */ }, { key: 'fileSize', get: function get() { return this.file.size; } /** * Gets the file name */ }, { key: 'fileName', get: function get() { return this.file.name; } /** * Gets action (url) to upload the file */ }, { key: 'action', get: function get() { return this.options.action || null; } /** * Gets the body to be merged when sending the request in start phase */ }, { key: 'startBody', get: function get() { return this.options.startBody || {}; } /** * Gets the body to be merged when sending the request in upload phase */ }, { key: 'uploadBody', get: function get() { return this.options.uploadBody || {}; } /** * Gets the body to be merged when sending the request in finish phase */ }, { key: 'finishBody', get: function get() { return this.options.finishBody || {}; } /** * Gets the headers of the requests from options */ }, { key: 'headers', get: function get() { return this.options.headers || {}; } /** * Whether it's ready to upload files or not */ }, { key: 'readyToUpload', get: function get() { return !!this.chunks; } /** * Gets the progress of the chunk upload * - Gets all the completed chunks * - Gets the progress of all the chunks that are being uploaded */ }, { key: 'progress', get: function get() { var _this6 = this; var completedProgress = this.chunksUploaded.length / this.chunks.length * 100; var uploadingProgress = this.chunksUploading.reduce(function (progress, chunk) { return progress + (chunk.progress | 0) / _this6.chunks.length; }, 0); return Math.min(completedProgress + uploadingProgress, 100); } /** * Gets all the chunks that are pending to be uploaded */ }, { key: 'chunksToUpload', get: function get() { return this.chunks.filter(function (chunk) { return !chunk.active && !chunk.uploaded; }); } /** * Whether there are chunks to upload or not */ }, { key: 'hasChunksToUpload', get: function get() { return this.chunksToUpload.length > 0; } /** * Gets all the chunks that are uploading */ }, { key: 'chunksUploading', get: function get() { return this.chunks.filter(function (chunk) { return !!chunk.xhr && !!chunk.active; }); } /** * Gets all the chunks that have finished uploading */ }, { key: 'chunksUploaded', get: function get() { return this.chunks.filter(function (chunk) { return !!chunk.uploaded; }); } }]); return ChunkUploadHandler; }(); // // // // // // // // // // // // // // var script = { methods: { change: function change(e) { this.$parent.addInputFile(e.target); if (e.target.files) { e.target.value = ''; if (e.target.files.length && !/safari/i.test(navigator.userAgent)) { e.target.type = ''; e.target.type = 'file'; } } else { // ie9 fix #219 this.$destroy(); // eslint-disable-next-line new this.constructor({ parent: this.$parent, el: this.$el }); } } } }; function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier /* server only */ , shadowMode, createInjector, createInjectorSSR, createInjectorShadow) { if (typeof shadowMode !== 'boolean') { createInjectorSSR = createInjector; createInjector = shadowMode; shadowMode = false; } // Vue.extend constructor export interop. var options = typeof script === 'function' ? script.options : script; // render functions if (template && template.render) { options.render = template.render; options.staticRenderFns = template.staticRenderFns; options._compiled = true; // functional template if (isFunctionalTemplate) { options.functional = true; } } // scopedId if (scopeId) { options._scopeId = scopeId; } var hook; if (moduleIdentifier) { // server build hook = function hook(context) { // 2.3 injection context = context || // cached call this.$vnode && this.$vnode.ssrContext || // stateful this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext; // functional // 2.2 with runInNewContext: true if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') { context = __VUE_SSR_CONTEXT__; } // inject component styles if (style) { style.call(this, createInjectorSSR(context)); } // register component module identifier for async chunk inference if (context && context._registeredComponents) { context._registeredComponents.add(moduleIdentifier); } }; // used by ssr in case component is cached and beforeCreate // never gets called options._ssrRegister = hook; } else if (style) { hook = shadowMode ? function () { style.call(this, createInjectorShadow(this.$root.$options.shadowRoot)); } : function (context) { style.call(this, createInjector(context)); }; } if (hook) { if (options.functional) { // register for functional component in vue file var originalRender = options.render; options.render = function renderWithStyleInjection(h, context) { hook.call(context); return originalRender(h, context); }; } else { // inject component registration as beforeCreate hook var existing = options.beforeCreate; options.beforeCreate = existing ? [].concat(existing, hook) : [hook]; } } return script; } var normalizeComponent_1 = normalizeComponent; /* script */ var __vue_script__ = script; /* template */ var __vue_render__ = function __vue_render__() { var _vm = this;var _h = _vm.$createElement;var _c = _vm._self._c || _h;return _c('input', { attrs: { "type": "file", "name": _vm.$parent.name, "id": _vm.$parent.inputId || _vm.$parent.name, "accept": _vm.$parent.accept, "capture": _vm.$parent.capture, "disabled": _vm.$parent.disabled, "webkitdirectory": _vm.$parent.directory && _vm.$parent.features.directory ? true : undefined, "directory": _vm.$parent.directory && _vm.$parent.features.directory ? true : undefined, "multiple": _vm.$parent.multiple && _vm.$parent.features.html5 }, on: { "change": _vm.change } }); }; var __vue_staticRenderFns__ = []; /* style */ var __vue_inject_styles__ = undefined; /* scoped */ var __vue_scope_id__ = undefined; /* module identifier */ var __vue_module_identifier__ = undefined; /* functional template */ var __vue_is_functional_template__ = false; /* style inject */ /* style inject SSR */ var InputFile = normalizeComponent_1({ render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ }, __vue_inject_styles__, __vue_script__, __vue_scope_id__, __vue_is_functional_template__, __vue_module_identifier__, undefined, undefined); var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } var CHUNK_DEFAULT_OPTIONS = { headers: {}, action: '', minSize: 1048576, maxActive: 3, maxRetries: 5, handler: ChunkUploadHandler }; var script$1 = { components: { InputFile: InputFile }, props: { inputId: { type: String }, name: { type: String, default: 'file' }, accept: { type: String }, capture: {}, disabled: {}, multiple: { type: Boolean }, maximum: { type: Number, default: function _default() { return this.multiple ? 0 : 1; } }, addIndex: { type: [Boolean, Number] }, directory: { type: Boolean }, postAction: { type: String }, putAction: { type: String }, customAction: { type: Function }, headers: { type: Object, default: Object }, data: { type: Object, default: Object }, timeout: { type: Number, default: 0 }, drop: { default: false }, dropDirectory: { type: Boolean, default: true }, size: { type: Number, default: 0 }, extensions: { default: Array }, value: { type: Array, default: Array }, thread: { type: Number, default: 1 }, // Chunk upload enabled chunkEnabled: { type: Boolean, default: false }, // Chunk upload properties chunk: { type: Object, default: function _default() { return CHUNK_DEFAULT_OPTIONS; } } }, data: function data() { return { files: this.value, features: { html5: true, directory: false, drop: false }, active: false, dropActive: false, uploading: 0, destroy: false }; }, /** * mounted * @return {[type]} [description] */ mounted: function mounted() { var input = document.createElement('input'); input.type = 'file'; input.multiple = true; // html5 特征 if (window.FormData && input.files) { // 上传目录特征 if (typeof input.webkitdirectory === 'boolean' || typeof input.directory === 'boolean') { this.features.directory = true; } // 拖拽特征 if (this.features.html5 && typeof input.ondrop !== 'undefined') { this.features.drop = true; } } else { this.features.html5 = false; } // files 定位缓存 this.maps = {}; if (this.files) { for (var i = 0; i < this.files.length; i++) { var file = this.files[i]; this.maps[file.id] = file; } } this.$nextTick(function () { var _this = this; // 更新下父级 if (this.$parent) { this.$parent.$forceUpdate(); // 拖拽渲染 this.$parent.$nextTick(function () { _this.watchDrop(_this.drop); }); } else { // 拖拽渲染 this.watchDrop(this.drop); } }); }, /** * beforeDestroy * @return {[type]} [description] */ beforeDestroy: function beforeDestroy() { // 已销毁 this.destroy = true; // 设置成不激活 this.active = false; // 销毁拖拽事件 this.watchDrop(false); }, computed: { /** * uploading 正在上传的线程 * @return {[type]} [description] */ /** * uploaded 文件列表是否全部已上传 * @return {[type]} [description] */ uploaded: function uploaded() { var file = void 0; for (var i = 0; i < this.files.length; i++) { file = this.files[i]; if (file.fileObject && !file.error && !file.success) { return false; } } return true; }, chunkOptions: function chunkOptions() { return Object.assign(CHUNK_DEFAULT_OPTIONS, this.chunk); }, className: function className() { return ['file-uploads', this.features.html5 ? 'file-uploads-html5' : 'file-uploads-html4', this.features.directory && this.directory ? 'file-uploads-directory' : undefined, this.features.drop && this.drop ? 'file-uploads-drop' : undefined, this.disabled ? 'file-uploads-disabled' : undefined]; } }, watch: { active: function active(_active) { this.watchActive(_active); }, dropActive: function dropActive(value) { this.watchDropActive(value); if (this.$parent) { this.$parent.$forceUpdate(); } }, drop: function drop(value) { this.watchDrop(value); }, value: function value(files) { if (this.files === files) { return; } this.files = files; var oldMaps = this.maps; // 重写 maps 缓存 this.maps = {}; for (var i = 0; i < this.files.length; i++) { var file = this.files[i]; this.maps[file.id] = file; } // add, update for (var key in this.maps) { var newFile = this.maps[key]; var oldFile = oldMaps[key]; if (newFile !== oldFile) { this.emitFile(newFile, oldFile); } } // delete for (var _key in oldMaps) { if (!this.maps[_key]) { this.emitFile(undefined, oldMaps[_key]); } } } }, methods: { // 清空 clear: function clear() { if (this.files.length) { var files = this.files; this.files = []; // 定位 this.maps = {}; // 事件 this.emitInput(); for (var i = 0; i < files.length; i++) { this.emitFile(undefined, files[i]); } } return true; }, // 选择 get: function get(id) { if (!id) { return false; } if ((typeof id === 'undefined' ? 'undefined' : _typeof(id)) === 'object') { return this.maps[id.id] || false; } return this.maps[id] || false; }, // 添加 add: function add(_files) { var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.addIndex; var files = _files; var isArray = files instanceof Array; // 不是数组整理成数组 if (!isArray) { files = [files]; } // 遍历规范对象 var addFiles = []; for (var i = 0; i < files.length; i++) { var file = files[i]; if (this.features.html5 && file instanceof Blob) { file = { file: file, size: file.size, name: file.webkitRelativePath || file.relativePath || file.name || 'unknown', type: file.type }; } var fileObject = false; if (file.fileObject === false) ; else if (file.fileObject) { fileObject = true; } else if (typeof Element !== 'undefined' && file.el instanceof Element) { fileObject = true; } else if (typeof Blob !== 'undefined' && file.file instanceof Blob) { fileObject = true; } if (fileObject) { file = _extends({ fileObject: true, size: -1, name: 'Filename', type: '', active: false, error: '', success: false, putAction: this.putAction, postAction: this.postAction, timeout: this.timeout }, file, { response: {}, progress: '0.00', // 只读 speed: 0 // 只读 // xhr: false, // 只读 // iframe: false, // 只读 }); file.data = _extends({}, this.data, file.data ? file.data : {}); file.headers = _extends({}, this.headers, file.headers ? file.headers : {}); } // 必须包含 id if (!file.id) { file.id = Math.random().toString(36).substr(2); } if (this.emitFilter(file, undefined)) { continue; } // 最大数量限制 if (this.maximum > 1 && addFiles.length + this.files.length >= this.maximum) { break; } addFiles.push(file); // 最大数量限制 if (this.maximum === 1) { break; } } // 没有文件 if (!addFiles.length) { return false; } // 如果是 1 清空 if (this.maximum === 1) { this.clear(); } // 添加进去 files var newFiles = void 0; if (index === true || index === 0) { newFiles = addFiles.concat(this.files); } else if (index) { var _newFiles; newFiles = this.files.concat([]); (_newFiles = newFiles).splice.apply(_newFiles, [index, 0].concat(addFiles)); } else { newFiles = this.files.concat(addFiles); } this.files = newFiles; // 定位 for (var _i = 0; _i < addFiles.length; _i++) { var _file2 = addFiles[_i]; this.maps[_file2.id] = _file2; } // 事件 this.emitInput(); for (var _i2 = 0; _i2 < addFiles.length; _i2++) { this.emitFile(addFiles[_i2], undefined); } return isArray ? addFiles : addFiles[0]; }, // 添加表单文件 addInputFile: function addInputFile(el) { var files = []; if (el.files) { for (var i = 0; i < el.files.length; i++) { var file = el.files[i]; files.push({ size: file.size, name: file.webkitRelativePath || file.relativePath || file.name, type: file.type, file: file }); } } else { var names = el.value.replace(/\\/g, '/').split('/'); delete el.__vuex__; files.push({ name: names[names.length - 1], el: el }); } return this.add(files); }, // 添加 DataTransfer addDataTransfer: function addDataTransfer(dataTransfer) { var _this2 = this; var files = []; if (dataTransfer.items && dataTransfer.items.length) { var items = []; for (var i = 0; i < dataTransfer.items.length; i++) { var item = dataTransfer.items[i]; if (item.getAsEntry) { item = item.getAsEntry() || item.getAsFile(); } else if (item.webkitGetAsEntry) { item = item.webkitGetAsEntry() || item.getAsFile(); } else { item = item.getAsFile(); } if (item) { items.push(item); } } return new Promise(function (resolve, reject) { var forEach = function forEach(i) { var item = items[i]; // 结束 文件数量大于 最大数量 if (!item || _this2.maximum > 0 && files.length >= _this2.maximum) { return resolve(_this2.add(files)); } _this2.getEntry(item).then(function (results) { files.push.apply(files, _toConsumableArray(results)); forEach(i + 1); }); }; forEach(0); }); } if (dataTransfer.files.length) { for (var _i3 = 0; _i3 < dataTransfer.files.length; _i3++) { files.push(dataTransfer.files[_i3]); if (this.maximum > 0 && files.length >= this.maximum) { break; } } return Promise.resolve(this.add(files)); } return Promise.resolve([]); }, // 获得 entry getEntry: function getEntry(entry) { var _this3 = this; var path = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; return new Promise(function (resolve, reject) { if (entry.isFile) { entry.file(function (file) { resolve([{ size: file.size, name: path + file.name, type: file.type, file: file }]); }); } else if (entry.isDirectory && _this3.dropDirectory) { var files = []; var dirReader = entry.createReader(); var readEntries = function readEntries() { dirReader.readEntries(function (entries) { var forEach = function forEach(i) { if (!entries[i] && i === 0 || _this3.maximum > 0 && files.length >= _this3.maximum) { return resolve(files); } if (!entries[i]) { return readEntries(); } _this3.getEntry(entries[i], path + entry.name + '/').then(function (results) { files.push.apply(files, _toConsumableArray(results)); forEach(i + 1); }); }; forEach(0); }); }; readEntries(); } else { resolve([]); } }); }, replace: function replace(id1, id2) { var file1 = this.get(id1); var file2 = this.get(id2); if (!file1 || !file2 || file1 === file2) { return false; } var files = this.files.concat([]); var index1 = files.indexOf(file1); var index2 = files.indexOf(file2); if (index1 === -1 || index2 === -1) { return false; } files[index1] = file2; files[index2] = file1; this.files = files; this.emitInput(); return true; }, // 移除 remove: function remove(id) { var file = this.get(id); if (file) { if (this.emitFilter(undefined, file)) { return false; } var files = this.files.concat([]); var index = files.indexOf(file); if (index === -1) { console.error('remove', file); return false; } files.splice(index, 1); this.files = files; // 定位 delete this.maps[file.id]; // 事件 this.emitInput(); this.emitFile(undefined, file); } return file; }, // 更新 update: function update(id, data) { var file = this.get(id); if (file) { var newFile = _extends({}, file, data); // 停用必须加上错误 if (file.fileObject && file.active && !newFile.active && !newFile.error && !newFile.success) { newFile.error = 'abort'; } if (this.emitFilter(newFile, file)) { return false; } var files = this.files.concat([]); var index = files.indexOf(file); if (index === -1) { console.error('update', file); return false; } files.splice(index, 1, newFile); this.files = files; // 删除 旧定位 写入 新定位 (已便支持修改id) delete this.maps[file.id]; this.maps[newFile.id] = newFile; // 事件 this.emitInput(); this.emitFile(newFile, file); return newFile; } return false; }, // 预处理 事件 过滤器 emitFilter: function emitFilter(newFile, oldFile) { var isPrevent = false; this.$emit('input-filter', newFile, oldFile, function () { isPrevent = true; return isPrevent; }); return isPrevent; }, // 处理后 事件 分发 emitFile: function emitFile(newFile, oldFile) { this.$emit('input-file', newFile, oldFile); if (newFile && newFile.fileObject && newFile.active && (!oldFile || !oldFile.active)) { this.uploading++; // 激活 this.$nextTick(function () { var _this4 = this; setTimeout(function () { _this4.upload(newFile).then(function () { // eslint-disable-next-line newFile = _this4.get(newFile); if (newFile && newFile.fileObject) { _this4.update(newFile, { active: false, success: !newFile.error }); } }).catch(function (e) { _this4.update(newFile, { active: false, success: false, error: e.code || e.error || e.message || e }); }); }, parseInt(Math.random() * 50 + 50, 10)); }); } else if ((!newFile || !newFile.fileObject || !newFile.active) && oldFile && oldFile.fileObject && oldFile.active) { // 停止 this.uploading--; } // 自动延续激活 if (this.active && (Boolean(newFile) !== Boolean(oldFile) || newFile.active !== oldFile.active)) { this.watchActive(true); } }, emitInput: function emitInput() { this.$emit('input', this.files); }, // 上传 upload: function upload(id) { var file = this.get(id); // 被删除 if (!file) { return Promise.reject('not_exists'); } // 不是文件对象 if (!file.fileObject) { return Promise.reject('file_object'); } // 有错误直接响应 if (file.error) { return Promise.reject(file.error); } // 已完成直接响应 if (file.success) { return Promise.resolve(file); } // 后缀 var extensions = this.extensions; if (extensions && (extensions.length || typeof extensions.length === 'undefined')) { if ((typeof extensions === 'undefined' ? 'undefined' : _typeof(extensions)) !== 'object' || !(extensions instanceof RegExp)) { if (typeof extensions === 'string') { extensions = extensions.split(',').map(function (value) { return value.trim(); }).filter(function (value) { return value; }); } extensions = new RegExp('\\.(' + extensions.join('|').replace(/\./g, '\\.') + ')$', 'i'); } if (file.name.search(extensions) === -1) { return Promise.reject('extension'); } } // 大小 if (this.size > 0 && file.size >= 0 && file.size > this.size) { return Promise.reject('size'); } if (this.customAction) { return this.customAction(file, this); } if (this.features.html5) { if (this.shouldUseChunkUpload(file)) { return this.uploadChunk(file); } if (file.putAction) { return this.uploadPut(file); } if (file.postAction) { return this.uploadHtml5(file); } } if (file.postAction) { return this.uploadHtml4(file); } return Promise.reject('No action configured'); }, /** * Whether this file should be uploaded using chunk upload or not * * @param Object file */ shouldUseChunkUpload: function shouldUseChunkUpload(file) { return this.chunkEnabled && !!this.chunkOptions.handler && file.size > this.chunkOptions.minSize; }, /** * Upload a file using Chunk method * * @param File file */ uploadChunk: function uploadChunk(file) { var HandlerClass = this.chunkOptions.handler; file.chunk = new HandlerClass(file, this.chunkOptions); return file.chunk.upload(); }, uploadPut: function uploadPut(file) { var querys = []; var value = void 0; for (var key in file.data) { value = file.data[key]; if (value !== null && value !== undefined) { querys.push(encodeURIComponent(key) + '=' + encodeURIComponent(value)); } } var queryString = querys.length ? (file.putAction.indexOf('?') === -1 ? '?' : '&') + querys.join('&') : ''; var xhr = new XMLHttpRequest(); xhr.open('PUT', file.putAction + queryString); return this.uploadXhr(xhr, file, file.file); }, uploadHtml5: function uploadHtml5(file) { var form = new window.FormData(); var value = void 0; for (var key in file.data) { value = file.data[key]; if (value && (typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object' && typeof value.toString !== 'function') { if (value instanceof File) { form.append(key, value, value.name); } else { form.append(key, JSON.stringify(value)); } } else if (value !== null && value !== undefined) { form.append(key, value); } } form.append(this.name, file.file, file.file.filename || file.name); var xhr = new XMLHttpRequest(); xhr.open('POST', file.postAction); return this.uploadXhr(xhr, file, form); }, uploadXhr: function uploadXhr(xhr, _file, body) { var _this5 = this; var file = _file; var speedTime = 0; var speedLoaded = 0; // 进度条 xhr.upload.onprogress = function (e) { // 还未开始上传 已删除 未激活 file = _this5.get(file); if (!e.lengthComputable || !file || !file.fileObject || !file.active) { return; } // 进度 速度 每秒更新一次 var speedTime2 = Math.round(Date.now() / 1000); if (speedTime2 === speedTime) { return; } speedTime = speedTime2; file = _this5.update(file, { progress: (e.loaded / e.total * 100).toFixed(2), speed: e.loaded - speedLoaded }); speedLoaded = e.loaded; }; // 检查激活状态 var interval = setInterval(function () { file = _this5.get(file); if (file && file.fileObject && !file.success && !file.error && file.active) { return; } if (interval) { clearInterval(interval); interval = false; } try { xhr.abort(); xhr.timeout = 1; } catch (e) {} }, 100); return new Promise(function (resolve, reject) { var complete = void 0; var fn = function fn(e) { // 已经处理过了 if (complete) { return; } complete = true; if (interval) { clearInterval(interval); interval = false; } file = _this5.get(file); // 不存在直接响应 if (!file) { return reject('not_exists'); } // 不是文件对象 if (!file.fileObject) { return reject('file_object'); } // 有错误自动响应 if (file.error) { return reject(file.error); } // 未激活 if (!file.active) { return reject('abort'); } // 已完成 直接相应 if (file.success) { return resolve(file); } var data = {}; switch (e.type) { case 'timeout': case 'abort': data.error = e.type; break; case 'error': if (!xhr.status) { data.error = 'network'; } else if (xhr.status >= 500) { data.error = 'server'; } else if (xhr.status >= 400) { data.error = 'denied'; } break; default: if (xhr.status >= 500) { data.error = 'server'; } else if (xhr.status >= 400) { data.error = 'denied'; } else { data.progress = '100.00'; } } if (xhr.responseText) { var contentType = xhr.getResponseHeader('Content-Type'); if (contentType && contentType.indexOf('/json') !== -1) { data.response = JSON.parse(xhr.responseText); } else { data.response = xhr.responseText; } } // 更新 file = _this5.update(file, data); // 相应错误 if (file.error) { return reject(file.error); } // 响应 return resolve(file); }; // 事件 xhr.onload = fn; xhr.onerror = fn; xhr.onabort = fn; xhr.ontimeout = fn; // 超时 if (file.timeout) { xhr.timeout = file.timeout; } // headers for (var key in file.headers) { xhr.setRequestHeader(key, file.headers[key]); } // 更新 xhr file = _this5.update(file, { xhr: xhr }); // 开始上传 xhr.send(body); }); }, uploadHtml4: function uploadHtml4(_file) { var _this6 = this; var file = _file; var onKeydown = function onKeydown(e) { if (e.keyCode === 27) { e.preventDefault(); } }; var iframe = document.createElement('iframe'); iframe.id = 'upload-iframe-' + file.id; iframe.name = 'upload-iframe-' + file.id; iframe.src = 'about:blank'; iframe.setAttribute('style', 'width:1px;height:1px;top:-999em;position:absolute; margin-top:-999em;'); var form = document.createElement('form'); form.action = file.postAction; form.name = 'upload-form-' + file.id; form.setAttribute('method', 'POST'); form.setAttribute('target', 'upload-iframe-' + file.id); form.setAttribute('enctype', 'multipart/form-data'); var value = void 0; var input = void 0; for (var key in file.data) { value = file.data[key]; if (value && (typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object' && typeof value.toString !== 'function') { value = JSON.stringify(value); } if (value !== null && value !== undefined) { input = document.createElement('input'); input.type = 'hidden'; input.name = key; input.value = value; form.appendChild(input); } } form.appendChild(file.el); document.body.appendChild(iframe).appendChild(form); var getResponseData = function getResponseData() { var doc = void 0; try { if (iframe.contentWindow) { doc = iframe.contentWindow.document; } } catch (err) {} if (!doc) { try { doc = iframe.contentDocument ? iframe.contentDocument : iframe.document; } catch (err) { doc = iframe.document; } } if (doc && doc.body) { return doc.body.innerHTML; } return null; }; return new Promise(function (resolve, reject) { setTimeout(function () { file = _this6.update(file, { iframe: iframe }); // 不存在 if (!file) { return reject('not_exists'); } // 定时检查 var interval = setInterval(function () { file = _this6.get(file); if (file && file.fileObject && !file.success && !file.error && file.active) { return; } if (interval) { clearInterval(interval); interval = false; } iframe.onabort({ type: file ? 'abort' : 'not_exists' }); }, 100); var complete = void 0; var fn = function fn(e) { // 已经处理过了 if (complete) { return; } complete = true; if (interval) { clearInterval(interval); interval = false; } // 关闭 esc 事件 document.body.removeEventListener('keydown', onKeydown); file = _this6.get(file); // 不存在直接响应 if (!file) { return reject('not_exists'); } // 不是文件对象 if (!file.fileObject) { return reject('file_object'); } // 有错误自动响应 if (file.error) { return reject(file.error); } // 未激活 if (!file.active) { return reject('abort'); } // 已完成 直接相应 if (file.success) { return resolve(file); } var response = getResponseData(); var data = {}; switch (e.type) { case 'abort': data.error = 'abort'; break; case 'error': if (file.error) { data.error = file.error; } else if (response === null) { data.error = 'network'; } else { data.error = 'denied'; } break; default: if (file.error) { data.error = file.error; } else if (data === null) { data.error = 'network'; } else { data.progress = '100.00'; } } if (response !== null) { if (response && response.substr(0, 1) === '{' && response.substr(response.length - 1, 1) === '}') { try { response = JSON.parse(response); } catch (err) {} } data.response = response; } // 更新 file = _this6.update(file, data); if (file.error) { return reject(file.error); } // 响应 return resolve(file); }; // 添加事件 iframe.onload = fn; iframe.onerror = fn; iframe.onabort = fn; // 禁止 esc 键 document.body.addEventListener('keydown', onKeydown); // 提交 form.submit(); }, 50); }).then(function (res) { iframe.parentNode && iframe.parentNode.removeChild(iframe); return res; }).catch(function (res) { iframe.parentNode && iframe.parentNode.removeChild(iframe); return res; }); }, watchActive: function watchActive(active) { var file = void 0; var index = 0; while (file = this.files[index]) { index++; if (!file.fileObject) ; else if (active && !this.destroy) { if (this.uploading >= this.thread || this.uploading && !this.features.html5) { break; } if (!file.active && !file.error && !file.success) { this.update(file, { active: true }); } } else { if (file.active) { this.update(file, { active: false }); } } } if (this.uploading === 0) { this.active = false; } }, watchDrop: function watchDrop(_el) { var el = _el; if (!this.features.drop) { return; } // 移除挂载 if (this.dropElement) { try { document.removeEventListener('dragenter', this.onDocumentDragenter, false); document.removeEventListener('dragleave', this.onDocumentDragleave, false); document.removeEventListener('dragover', this.onDocumentDragover, false); document.removeEventListener('drop', this.onDocumentDrop, false); this.dropElement.removeEventListener('dragover', this.onDragover, false); this.dropElement.removeEventListener('drop', this.onDrop, false); } catch (e) {} } if (!el) { el = false; } else if (typeof el === 'string') { el = document.querySelector(el) || this.$root.$el.querySelector(el); } else if (el === true) { el = this.$parent.$el; } this.dropElement = el; if (this.dropElement) { document.addEventListener('dragenter', this.onDocumentDragenter, false); document.addEventListener('dragleave', this.onDocumentDragleave, false); document.addEventListener('dragover', this.onDocumentDragover, false); document.addEventListener('drop', this.onDocumentDrop, false); this.dropElement.addEventListener('dragover', this.onDragover, false); this.dropElement.addEventListener('drop', this.onDrop, false); } }, watchDropActive: function watchDropActive(newDropActive, oldDropActive) { if (newDropActive === oldDropActive) { return; } if (this.dropTimeout) { clearTimeout(this.dropTimeout); this.dropTimeout = null; } if (newDropActive) { this.dropTimeout = setTimeout(this.onDocumentDrop, 1000); } }, onDocumentDragenter: function onDocumentDragenter(e) { if (this.dropActive) { return; } if (!e.dataTransfer) { return; } var dt = e.dataTransfer; if (dt.files && dt.files.length) { this.dropActive = true; } else if (!dt.types) { this.dropActive = true; } else if (dt.types.indexOf && dt.types.indexOf('Files') !== -1) { this.dropActive = true; } else if (dt.types.contains && dt.types.contains('Files')) { this.dropActive = true; } if (this.dropActive) { this.watchDropActive(true); } }, onDocumentDragleave: function onDocumentDragleave(e) { if (!this.dropActive) { return; } if (e.target === e.explicitOriginalTarget || !e.fromElement && (e.clientX <= 0 || e.clientY <= 0 || e.clientX >= window.innerWidth || e.clientY >= window.innerHeight)) { this.dropActive = false; this.watchDropActive(false); } }, onDocumentDragover: function onDocumentDragover() { this.watchDropActive(true); }, onDocumentDrop: function onDocumentDrop() { this.dropActive = false; this.watchDropActive(false); }, onDragover: function onDragover(e) { e.preventDefault(); }, onDrop: function onDrop(e) { e.preventDefault(); e.dataTransfer && this.addDataTransfer(e.dataTransfer); } } }; var isOldIE = typeof navigator !== 'undefined' && /msie [6-9]\\b/.test(navigator.userAgent.toLowerCase()); function createInjector(context) { return function (id, style) { return addStyle(id, style); }; } var HEAD = document.head || document.getElementsByTagName('head')[0]; var styles = {}; function addStyle(id, css) { var group = isOldIE ? css.media || 'default' : id; var style = styles[group] || (styles[group] = { ids: new Set(), styles: [] }); if (!style.ids.has(id)) { style.ids.add(id); var code = css.source; if (css.map) { // https://developer.chrome.com/devtools/docs/javascript-debugging // this makes source maps inside style tags work properly in Chrome code += '\n/*# sourceURL=' + css.map.sources[0] + ' */'; // http://stackoverflow.com/a/26603875 code += '\n/*# sourceMappingURL=data:application/json;base64,' + btoa(unescape(encodeURIComponent(JSON.stringify(css.map)))) + ' */'; } if (!style.element) { style.element = document.createElement('style'); style.element.type = 'text/css'; if (css.media) style.element.setAttribute('media', css.media); HEAD.appendChild(style.element); } if ('styleSheet' in style.element) { style.styles.push(code); style.element.styleSheet.cssText = style.styles.filter(Boolean).join('\n'); } else { var index = style.ids.size - 1; var textNode = document.createTextNode(code); var nodes = style.element.childNodes; if (nodes[index]) style.element.removeChild(nodes[index]); if (nodes.length) style.element.insertBefore(textNode, nodes[index]);else style.element.appendChild(textNode); } } } var browser = createInjector; /* script */ var __vue_script__$1 = script$1; /* template */ var __vue_render__$1 = function __vue_render__() { var _vm = this;var _h = _vm.$createElement;var _c = _vm._self._c || _h;return _c('span', { class: _vm.className }, [_vm._t("default"), _vm._v(" "), _c('label', { attrs: { "for": _vm.inputId || _vm.name } }), _vm._v(" "), _c('input-file')], 2); }; var __vue_staticRenderFns__$1 = []; /* style */ var __vue_inject_styles__$1 = function __vue_inject_styles__(inject) { if (!inject) return; inject("data-v-939ffe40_0", { source: ".file-uploads{overflow:hidden;position:relative;text-align:center;display:inline-block}.file-uploads.file-uploads-html4 input,.file-uploads.file-uploads-html5 label{background:#fff;opacity:0;font-size:20em;z-index:1;top:0;left:0;right:0;bottom:0;position:absolute;width:100%;height:100%}.file-uploads.file-uploads-html4 label,.file-uploads.file-uploads-html5 input{background:rgba(255,255,255,0);overflow:hidden;position:fixed;width:1px;height:1px;z-index:-1;opacity:0}", map: undefined, media: undefined }); }; /* scoped */ var __vue_scope_id__$1 = undefined; /* module identifier */ var __vue_module_identifier__$1 = undefined; /* functional template */ var __vue_is_functional_template__$1 = false; /* style inject SSR */ var FileUpload = normalizeComponent_1({ render: __vue_render__$1, staticRenderFns: __vue_staticRenderFns__$1 }, __vue_inject_styles__$1, __vue_script__$1, __vue_scope_id__$1, __vue_is_functional_template__$1, __vue_module_identifier__$1, browser, undefined); var FileUpload$1 = /*#__PURE__*/Object.freeze({ default: FileUpload }); function getCjsExportFromNamespace (n) { return n && n['default'] || n; } var require$$0 = getCjsExportFromNamespace(FileUpload$1); var src = require$$0; return src; }))); //# sourceMappingURL=vue-upload-component.js.map