From d330a5447d0152d5952249ee288cfdfa5a3cac8d Mon Sep 17 00:00:00 2001 From: Martin Brennan Date: Tue, 21 Dec 2021 15:02:10 +1000 Subject: [PATCH] DEV: Remove old backup uploader and resumable.js (#15365) Now that d5e380e5c14ac1d24f1f5f32d082fdbfbd1a15db has been committed there is nothing in the codebase that uses either resumable.js or the old backup-uploader component. R.I.P resumable.js --- .../addon/components/resumable-upload.js | 140 --- .../app/components/backup-uploader.js | 54 - .../templates/components/backup-uploader.hbs | 4 - .../javascripts/discourse/ember-cli-build.js | 6 +- app/assets/javascripts/main_include_admin.js | 1 - lib/tasks/javascript.rake | 2 - package.json | 3 +- vendor/assets/javascripts/resumable.js | 1084 ----------------- yarn.lock | 5 - 9 files changed, 2 insertions(+), 1297 deletions(-) delete mode 100644 app/assets/javascripts/admin/addon/components/resumable-upload.js delete mode 100644 app/assets/javascripts/discourse/app/components/backup-uploader.js delete mode 100644 app/assets/javascripts/discourse/app/templates/components/backup-uploader.hbs delete mode 100644 vendor/assets/javascripts/resumable.js diff --git a/app/assets/javascripts/admin/addon/components/resumable-upload.js b/app/assets/javascripts/admin/addon/components/resumable-upload.js deleted file mode 100644 index 8e3ce18e8cc..00000000000 --- a/app/assets/javascripts/admin/addon/components/resumable-upload.js +++ /dev/null @@ -1,140 +0,0 @@ -import discourseComputed, { on } from "discourse-common/utils/decorators"; -import { later, schedule } from "@ember/runloop"; -import Component from "@ember/component"; -import I18n from "I18n"; -import getURL from "discourse-common/lib/get-url"; -import { iconHTML } from "discourse-common/lib/icon-library"; - -/*global Resumable:true */ - -/** - Example usage: - - {{resumable-upload - target="/admin/backups/upload" - success=(action "successAction") - error=(action "errorAction") - uploadText="UPLOAD" - }} -**/ -export default Component.extend({ - tagName: "button", - classNames: ["btn", "ru"], - classNameBindings: ["isUploading"], - attributeBindings: ["translatedTitle:title"], - resumable: null, - isUploading: false, - progress: 0, - rerenderTriggers: ["isUploading", "progress"], - uploadingIcon: null, - progressBar: null, - - @on("init") - _initialize() { - this.resumable = new Resumable({ - target: getURL(this.target), - maxFiles: 1, // only 1 file at a time - headers: { - "X-CSRF-Token": document.querySelector("meta[name='csrf-token']") - .content, - }, - }); - - this.resumable.on("fileAdded", () => { - // automatically upload the selected file - this.resumable.upload(); - - // mark as uploading - later(() => { - this.set("isUploading", true); - this._updateIcon(); - }); - }); - - this.resumable.on("fileProgress", (file) => { - // update progress - later(() => { - this.set("progress", parseInt(file.progress() * 100, 10)); - this._updateProgressBar(); - }); - }); - - this.resumable.on("fileSuccess", (file) => { - later(() => { - // mark as not uploading anymore - this._reset(); - - // fire an event to allow the parent route to reload its model - this.success(file.fileName); - }); - }); - - this.resumable.on("fileError", (file, message) => { - later(() => { - // mark as not uploading anymore - this._reset(); - - // fire an event to allow the parent route to display the error message - this.error(file.fileName, message); - }); - }); - }, - - @on("didInsertElement") - _assignBrowse() { - schedule("afterRender", () => this.resumable.assignBrowse($(this.element))); - }, - - @on("willDestroyElement") - _teardown() { - if (this.resumable) { - this.resumable.cancel(); - this.resumable = null; - } - }, - - @discourseComputed("title", "text") - translatedTitle(title, text) { - return title ? I18n.t(title) : text; - }, - - @discourseComputed("isUploading", "progress") - text(isUploading, progress) { - if (isUploading) { - return progress + " %"; - } else { - return this.uploadText; - } - }, - - didReceiveAttrs() { - this._super(...arguments); - this._updateIcon(); - }, - - click() { - if (this.isUploading) { - this.resumable.cancel(); - later(() => this._reset()); - return false; - } else { - return true; - } - }, - - _updateIcon() { - const icon = this.isUploading ? "times" : "upload"; - this.set("uploadingIcon", `${iconHTML(icon)}`.htmlSafe()); - }, - - _updateProgressBar() { - const pb = `${"width:" + this.progress + "%"}`.htmlSafe(); - this.set("progressBar", pb); - }, - - _reset() { - this.setProperties({ isUploading: false, progress: 0 }); - this._updateIcon(); - this._updateProgressBar(); - }, -}); diff --git a/app/assets/javascripts/discourse/app/components/backup-uploader.js b/app/assets/javascripts/discourse/app/components/backup-uploader.js deleted file mode 100644 index 69e9ba6db09..00000000000 --- a/app/assets/javascripts/discourse/app/components/backup-uploader.js +++ /dev/null @@ -1,54 +0,0 @@ -import Component from "@ember/component"; -import I18n from "I18n"; -import UploadMixin from "discourse/mixins/upload"; -import { ajax } from "discourse/lib/ajax"; -import discourseComputed from "discourse-common/utils/decorators"; -import { on } from "@ember/object/evented"; -import { popupAjaxError } from "discourse/lib/ajax-error"; - -export default Component.extend(UploadMixin, { - tagName: "span", - - @discourseComputed("uploading", "uploadProgress") - uploadButtonText(uploading, progress) { - return uploading - ? I18n.t("admin.backups.upload.uploading_progress", { progress }) - : I18n.t("admin.backups.upload.label"); - }, - - validateUploadedFilesOptions() { - return { skipValidation: true }; - }, - - uploadDone() { - this.done(); - }, - - calculateUploadUrl() { - return ""; - }, - - uploadOptions() { - return { - type: "PUT", - dataType: "xml", - autoUpload: false, - multipart: false, - }; - }, - - _init: on("didInsertElement", function () { - const $upload = $(this.element); - - $upload.on("fileuploadadd", (e, data) => { - ajax("/admin/backups/upload_url", { - data: { filename: data.files[0].name }, - }) - .then((result) => { - data.url = result.url; - data.submit(); - }) - .catch(popupAjaxError); - }); - }), -}); diff --git a/app/assets/javascripts/discourse/app/templates/components/backup-uploader.hbs b/app/assets/javascripts/discourse/app/templates/components/backup-uploader.hbs deleted file mode 100644 index e4e8304b520..00000000000 --- a/app/assets/javascripts/discourse/app/templates/components/backup-uploader.hbs +++ /dev/null @@ -1,4 +0,0 @@ - diff --git a/app/assets/javascripts/discourse/ember-cli-build.js b/app/assets/javascripts/discourse/ember-cli-build.js index 60d47a3cfc2..a643bc1ddf0 100644 --- a/app/assets/javascripts/discourse/ember-cli-build.js +++ b/app/assets/javascripts/discourse/ember-cli-build.js @@ -50,10 +50,6 @@ module.exports = function (defaults) { }); app.import(discourseRoot + "/app/assets/javascripts/polyfills.js"); - let adminVendor = funnel(vendorJs, { - files: ["resumable.js"], - }); - return mergeTrees([ discourseScss(`${discourseRoot}/app/assets/stylesheets`, "testem.scss"), createI18nTree(discourseRoot, vendorJs), @@ -64,7 +60,7 @@ module.exports = function (defaults) { destDir: "assets/highlightjs", }), digest( - concat(mergeTrees([app.options.adminTree, adminVendor]), { + concat(mergeTrees([app.options.adminTree]), { outputFile: `assets/admin.js`, }) ), diff --git a/app/assets/javascripts/main_include_admin.js b/app/assets/javascripts/main_include_admin.js index 3b275bd8f59..18afb3ba119 100644 --- a/app/assets/javascripts/main_include_admin.js +++ b/app/assets/javascripts/main_include_admin.js @@ -1,3 +1,2 @@ //= require discourse/app/lib/export-result //= require_tree ./admin/addon -//= require resumable.js diff --git a/lib/tasks/javascript.rake b/lib/tasks/javascript.rake index a8db2fa31c5..d1ecd861e72 100644 --- a/lib/tasks/javascript.rake +++ b/lib/tasks/javascript.rake @@ -131,8 +131,6 @@ def dependencies }, { source: 'moment-timezone-names-translations/locales/.', destination: 'moment-timezone-names-locale' - }, { - source: 'resumablejs/resumable.js' }, { source: 'workbox-sw/build/.', destination: 'workbox', diff --git a/package.json b/package.json index fab7aa0a965..a830aebef44 100644 --- a/package.json +++ b/package.json @@ -12,10 +12,10 @@ "@json-editor/json-editor": "^2.6.1", "@popperjs/core": "v2.10.2", "@uppy/aws-s3": "^2.0.4", - "@uppy/utils": "^4.0.3", "@uppy/aws-s3-multipart": "^2.1.0", "@uppy/core": "^2.1.0", "@uppy/drop-target": "^1.1.0", + "@uppy/utils": "^4.0.3", "@uppy/xhr-upload": "^2.0.4", "ace-builds": "1.4.12", "blueimp-file-upload": "10.13.0", @@ -33,7 +33,6 @@ "moment-timezone": "0.5.31", "moment-timezone-names-translations": "https://github.com/discourse/moment-timezone-names-translations", "pikaday": "1.8.0", - "resumablejs": "1.1.0", "spectrum-colorpicker": "1.8.0", "workbox-cacheable-response": "^4.3.1", "workbox-core": "^4.3.1", diff --git a/vendor/assets/javascripts/resumable.js b/vendor/assets/javascripts/resumable.js deleted file mode 100644 index 649e6a2a317..00000000000 --- a/vendor/assets/javascripts/resumable.js +++ /dev/null @@ -1,1084 +0,0 @@ -/* -* MIT Licensed -* http://www.23developer.com/opensource -* http://github.com/23/resumable.js -* Steffen Tiedemann Christensen, steffen@23company.com -*/ - -(function(){ -"use strict"; - - var Resumable = function(opts){ - if ( !(this instanceof Resumable) ) { - return new Resumable(opts); - } - this.version = 1.0; - // SUPPORTED BY BROWSER? - // Check if these features are support by the browser: - // - File object type - // - Blob object type - // - FileList object type - // - slicing files - this.support = ( - (typeof(File)!=='undefined') - && - (typeof(Blob)!=='undefined') - && - (typeof(FileList)!=='undefined') - && - (!!Blob.prototype.webkitSlice||!!Blob.prototype.mozSlice||!!Blob.prototype.slice||false) - ); - if(!this.support) return(false); - - - // PROPERTIES - var $ = this; - $.files = []; - $.defaults = { - chunkSize:1*1024*1024, - forceChunkSize:false, - simultaneousUploads:3, - fileParameterName:'file', - chunkNumberParameterName: 'resumableChunkNumber', - chunkSizeParameterName: 'resumableChunkSize', - currentChunkSizeParameterName: 'resumableCurrentChunkSize', - totalSizeParameterName: 'resumableTotalSize', - typeParameterName: 'resumableType', - identifierParameterName: 'resumableIdentifier', - fileNameParameterName: 'resumableFilename', - relativePathParameterName: 'resumableRelativePath', - totalChunksParameterName: 'resumableTotalChunks', - throttleProgressCallbacks: 0.5, - query:{}, - headers:{}, - preprocess:null, - method:'multipart', - uploadMethod: 'POST', - testMethod: 'GET', - prioritizeFirstAndLastChunk:false, - target:'/', - testTarget: null, - parameterNamespace:'', - testChunks:true, - generateUniqueIdentifier:null, - getTarget:null, - maxChunkRetries:100, - chunkRetryInterval:undefined, - permanentErrors:[400, 404, 415, 500, 501], - maxFiles:undefined, - withCredentials:false, - xhrTimeout:0, - clearInput:true, - chunkFormat:'blob', - setChunkTypeFromFile:false, - maxFilesErrorCallback:function (files, errorCount) { - var maxFiles = $.getOpt('maxFiles'); - alert('Please upload no more than ' + maxFiles + ' file' + (maxFiles === 1 ? '' : 's') + ' at a time.'); - }, - minFileSize:1, - minFileSizeErrorCallback:function(file, errorCount) { - alert(file.fileName||file.name +' is too small, please upload files larger than ' + $h.formatSize($.getOpt('minFileSize')) + '.'); - }, - maxFileSize:undefined, - maxFileSizeErrorCallback:function(file, errorCount) { - alert(file.fileName||file.name +' is too large, please upload files less than ' + $h.formatSize($.getOpt('maxFileSize')) + '.'); - }, - fileType: [], - fileTypeErrorCallback: function(file, errorCount) { - alert(file.fileName||file.name +' has type not allowed, please upload files of type ' + $.getOpt('fileType') + '.'); - } - }; - $.opts = opts||{}; - $.getOpt = function(o) { - var $opt = this; - // Get multiple option if passed an array - if(o instanceof Array) { - var options = {}; - $h.each(o, function(option){ - options[option] = $opt.getOpt(option); - }); - return options; - } - // Otherwise, just return a simple option - if ($opt instanceof ResumableChunk) { - if (typeof $opt.opts[o] !== 'undefined') { return $opt.opts[o]; } - else { $opt = $opt.fileObj; } - } - if ($opt instanceof ResumableFile) { - if (typeof $opt.opts[o] !== 'undefined') { return $opt.opts[o]; } - else { $opt = $opt.resumableObj; } - } - if ($opt instanceof Resumable) { - if (typeof $opt.opts[o] !== 'undefined') { return $opt.opts[o]; } - else { return $opt.defaults[o]; } - } - }; - - // EVENTS - // catchAll(event, ...) - // fileSuccess(file), fileProgress(file), fileAdded(file, event), filesAdded(files, filesSkipped), fileRetry(file), - // fileError(file, message), complete(), progress(), error(message, file), pause() - $.events = []; - $.on = function(event,callback){ - $.events.push(event.toLowerCase(), callback); - }; - $.fire = function(){ - // `arguments` is an object, not array, in FF, so: - var args = []; - for (var i=0; i 0){ - var fileTypeFound = false; - for(var index in o.fileType){ - var extension = '.' + o.fileType[index]; - if(fileName.toLowerCase().indexOf(extension.toLowerCase(), fileName.length - extension.length) !== -1){ - fileTypeFound = true; - break; - } - } - if (!fileTypeFound) { - o.fileTypeErrorCallback(file, errorCount++); - return false; - } - } - - if (typeof(o.minFileSize)!=='undefined' && file.sizeo.maxFileSize) { - o.maxFileSizeErrorCallback(file, errorCount++); - return false; - } - - function addFile(uniqueIdentifier){ - if (!$.getFromUniqueIdentifier(uniqueIdentifier)) {(function(){ - file.uniqueIdentifier = uniqueIdentifier; - var f = new ResumableFile($, file, uniqueIdentifier); - $.files.push(f); - files.push(f); - f.container = (typeof event != 'undefined' ? event.srcElement : null); - window.setTimeout(function(){ - $.fire('fileAdded', f, event) - },0); - })()} else { - filesSkipped.push(file); - }; - decreaseReamining(); - } - // directories have size == 0 - var uniqueIdentifier = $h.generateUniqueIdentifier(file, event); - if(uniqueIdentifier && typeof uniqueIdentifier.then === 'function'){ - // Promise or Promise-like object provided as unique identifier - uniqueIdentifier - .then( - function(uniqueIdentifier){ - // unique identifier generation succeeded - addFile(uniqueIdentifier); - }, - function(){ - // unique identifier generation failed - // skip further processing, only decrease file count - decreaseReamining(); - } - ); - }else{ - // non-Promise provided as unique identifier, process synchronously - addFile(uniqueIdentifier); - } - }); - }; - - // INTERNAL OBJECT TYPES - function ResumableFile(resumableObj, file, uniqueIdentifier){ - var $ = this; - $.opts = {}; - $.getOpt = resumableObj.getOpt; - $._prevProgress = 0; - $.resumableObj = resumableObj; - $.file = file; - $.fileName = file.fileName||file.name; // Some confusion in different versions of Firefox - $.size = file.size; - $.relativePath = file.relativePath || file.webkitRelativePath || $.fileName; - $.uniqueIdentifier = uniqueIdentifier; - $._pause = false; - $.container = ''; - var _error = uniqueIdentifier !== undefined; - - // Callback when something happens within the chunk - var chunkEvent = function(event, message){ - // event can be 'progress', 'success', 'error' or 'retry' - switch(event){ - case 'progress': - $.resumableObj.fire('fileProgress', $, message); - break; - case 'error': - $.abort(); - _error = true; - $.chunks = []; - $.resumableObj.fire('fileError', $, message); - break; - case 'success': - if(_error) return; - $.resumableObj.fire('fileProgress', $); // it's at least progress - if($.isComplete()) { - $.resumableObj.fire('fileSuccess', $, message); - } - break; - case 'retry': - $.resumableObj.fire('fileRetry', $); - break; - } - }; - - // Main code to set up a file object with chunks, - // packaged to be able to handle retries if needed. - $.chunks = []; - $.abort = function(){ - // Stop current uploads - var abortCount = 0; - $h.each($.chunks, function(c){ - if(c.status()=='uploading') { - c.abort(); - abortCount++; - } - }); - if(abortCount>0) $.resumableObj.fire('fileProgress', $); - }; - $.cancel = function(){ - // Reset this file to be void - var _chunks = $.chunks; - $.chunks = []; - // Stop current uploads - $h.each(_chunks, function(c){ - if(c.status()=='uploading') { - c.abort(); - $.resumableObj.uploadNextChunk(); - } - }); - $.resumableObj.removeFile($); - $.resumableObj.fire('fileProgress', $); - }; - $.retry = function(){ - $.bootstrap(); - var firedRetry = false; - $.resumableObj.on('chunkingComplete', function(){ - if(!firedRetry) $.resumableObj.upload(); - firedRetry = true; - }); - }; - $.bootstrap = function(){ - $.abort(); - _error = false; - // Rebuild stack of chunks from file - $.chunks = []; - $._prevProgress = 0; - var round = $.getOpt('forceChunkSize') ? Math.ceil : Math.floor; - var maxOffset = Math.max(round($.file.size/$.getOpt('chunkSize')),1); - for (var offset=0; offset0.99999 ? 1 : ret)); - ret = Math.max($._prevProgress, ret); // We don't want to lose percentages when an upload is paused - $._prevProgress = ret; - return(ret); - }; - $.isUploading = function(){ - var uploading = false; - $h.each($.chunks, function(chunk){ - if(chunk.status()=='uploading') { - uploading = true; - return(false); - } - }); - return(uploading); - }; - $.isComplete = function(){ - var outstanding = false; - $h.each($.chunks, function(chunk){ - var status = chunk.status(); - if(status=='pending' || status=='uploading' || chunk.preprocessState === 1) { - outstanding = true; - return(false); - } - }); - return(!outstanding); - }; - $.pause = function(pause){ - if(typeof(pause)==='undefined'){ - $._pause = ($._pause ? false : true); - }else{ - $._pause = pause; - } - }; - $.isPaused = function() { - return $._pause; - }; - - - // Bootstrap and return - $.resumableObj.fire('chunkingStart', $); - $.bootstrap(); - return(this); - } - - - function ResumableChunk(resumableObj, fileObj, offset, callback){ - var $ = this; - $.opts = {}; - $.getOpt = resumableObj.getOpt; - $.resumableObj = resumableObj; - $.fileObj = fileObj; - $.fileObjSize = fileObj.size; - $.fileObjType = fileObj.file.type; - $.offset = offset; - $.callback = callback; - $.lastProgressCallback = (new Date); - $.tested = false; - $.retries = 0; - $.pendingRetry = false; - $.preprocessState = 0; // 0 = unprocessed, 1 = processing, 2 = finished - - // Computed properties - var chunkSize = $.getOpt('chunkSize'); - $.loaded = 0; - $.startByte = $.offset*chunkSize; - $.endByte = Math.min($.fileObjSize, ($.offset+1)*chunkSize); - if ($.fileObjSize-$.endByte < chunkSize && !$.getOpt('forceChunkSize')) { - // The last chunk will be bigger than the chunk size, but less than 2*chunkSize - $.endByte = $.fileObjSize; - } - $.xhr = null; - - // test() makes a GET request without any data to see if the chunk has already been uploaded in a previous session - $.test = function(){ - // Set up request and listen for event - $.xhr = new XMLHttpRequest(); - - var testHandler = function(e){ - $.tested = true; - var status = $.status(); - if(status=='success') { - $.callback(status, $.message()); - $.resumableObj.uploadNextChunk(); - } else { - $.send(); - } - }; - $.xhr.addEventListener('load', testHandler, false); - $.xhr.addEventListener('error', testHandler, false); - $.xhr.addEventListener('timeout', testHandler, false); - - // Add data from the query options - var params = []; - var parameterNamespace = $.getOpt('parameterNamespace'); - var customQuery = $.getOpt('query'); - if(typeof customQuery == 'function') customQuery = customQuery($.fileObj, $); - $h.each(customQuery, function(k,v){ - params.push([encodeURIComponent(parameterNamespace+k), encodeURIComponent(v)].join('=')); - }); - // Add extra data to identify chunk - params = params.concat( - [ - // define key/value pairs for additional parameters - ['chunkNumberParameterName', $.offset + 1], - ['chunkSizeParameterName', $.getOpt('chunkSize')], - ['currentChunkSizeParameterName', $.endByte - $.startByte], - ['totalSizeParameterName', $.fileObjSize], - ['typeParameterName', $.fileObjType], - ['identifierParameterName', $.fileObj.uniqueIdentifier], - ['fileNameParameterName', $.fileObj.fileName], - ['relativePathParameterName', $.fileObj.relativePath], - ['totalChunksParameterName', $.fileObj.chunks.length] - ].filter(function(pair){ - // include items that resolve to truthy values - // i.e. exclude false, null, undefined and empty strings - return $.getOpt(pair[0]); - }) - .map(function(pair){ - // map each key/value pair to its final form - return [ - parameterNamespace + $.getOpt(pair[0]), - encodeURIComponent(pair[1]) - ].join('='); - }) - ); - // Append the relevant chunk and send it - $.xhr.open($.getOpt('testMethod'), $h.getTarget('test', params)); - $.xhr.timeout = $.getOpt('xhrTimeout'); - $.xhr.withCredentials = $.getOpt('withCredentials'); - // Add data from header options - var customHeaders = $.getOpt('headers'); - if(typeof customHeaders === 'function') { - customHeaders = customHeaders($.fileObj, $); - } - $h.each(customHeaders, function(k,v) { - $.xhr.setRequestHeader(k, v); - }); - $.xhr.send(null); - }; - - $.preprocessFinished = function(){ - $.preprocessState = 2; - $.send(); - }; - - // send() uploads the actual data in a POST call - $.send = function(){ - var preprocess = $.getOpt('preprocess'); - if(typeof preprocess === 'function') { - switch($.preprocessState) { - case 0: $.preprocessState = 1; preprocess($); return; - case 1: return; - case 2: break; - } - } - if($.getOpt('testChunks') && !$.tested) { - $.test(); - return; - } - - // Set up request and listen for event - $.xhr = new XMLHttpRequest(); - - // Progress - $.xhr.upload.addEventListener('progress', function(e){ - if( (new Date) - $.lastProgressCallback > $.getOpt('throttleProgressCallbacks') * 1000 ) { - $.callback('progress'); - $.lastProgressCallback = (new Date); - } - $.loaded=e.loaded||0; - }, false); - $.loaded = 0; - $.pendingRetry = false; - $.callback('progress'); - - // Done (either done, failed or retry) - var doneHandler = function(e){ - var status = $.status(); - if(status=='success'||status=='error') { - $.callback(status, $.message()); - $.resumableObj.uploadNextChunk(); - } else { - $.callback('retry', $.message()); - $.abort(); - $.retries++; - var retryInterval = $.getOpt('chunkRetryInterval'); - if(retryInterval !== undefined) { - $.pendingRetry = true; - setTimeout($.send, retryInterval); - } else { - $.send(); - } - } - }; - $.xhr.addEventListener('load', doneHandler, false); - $.xhr.addEventListener('error', doneHandler, false); - $.xhr.addEventListener('timeout', doneHandler, false); - - // Set up the basic query data from Resumable - var query = [ - ['chunkNumberParameterName', $.offset + 1], - ['chunkSizeParameterName', $.getOpt('chunkSize')], - ['currentChunkSizeParameterName', $.endByte - $.startByte], - ['totalSizeParameterName', $.fileObjSize], - ['typeParameterName', $.fileObjType], - ['identifierParameterName', $.fileObj.uniqueIdentifier], - ['fileNameParameterName', $.fileObj.fileName], - ['relativePathParameterName', $.fileObj.relativePath], - ['totalChunksParameterName', $.fileObj.chunks.length], - ].filter(function(pair){ - // include items that resolve to truthy values - // i.e. exclude false, null, undefined and empty strings - return $.getOpt(pair[0]); - }) - .reduce(function(query, pair){ - // assign query key/value - query[$.getOpt(pair[0])] = pair[1]; - return query; - }, {}); - // Mix in custom data - var customQuery = $.getOpt('query'); - if(typeof customQuery == 'function') customQuery = customQuery($.fileObj, $); - $h.each(customQuery, function(k,v){ - query[k] = v; - }); - - var func = ($.fileObj.file.slice ? 'slice' : ($.fileObj.file.mozSlice ? 'mozSlice' : ($.fileObj.file.webkitSlice ? 'webkitSlice' : 'slice'))); - var bytes = $.fileObj.file[func]($.startByte, $.endByte, $.getOpt('setChunkTypeFromFile') ? $.fileObj.file.type : ""); - var data = null; - var params = []; - - var parameterNamespace = $.getOpt('parameterNamespace'); - if ($.getOpt('method') === 'octet') { - // Add data from the query options - data = bytes; - $h.each(query, function (k, v) { - params.push([encodeURIComponent(parameterNamespace + k), encodeURIComponent(v)].join('=')); - }); - } else { - // Add data from the query options - data = new FormData(); - $h.each(query, function (k, v) { - data.append(parameterNamespace + k, v); - params.push([encodeURIComponent(parameterNamespace + k), encodeURIComponent(v)].join('=')); - }); - if ($.getOpt('chunkFormat') == 'blob') { - data.append(parameterNamespace + $.getOpt('fileParameterName'), bytes, $.fileObj.fileName); - } - else if ($.getOpt('chunkFormat') == 'base64') { - var fr = new FileReader(); - fr.onload = function (e) { - data.append(parameterNamespace + $.getOpt('fileParameterName'), fr.result); - $.xhr.send(data); - } - fr.readAsDataURL(bytes); - } - } - - var target = $h.getTarget('upload', params); - var method = $.getOpt('uploadMethod'); - - $.xhr.open(method, target); - if ($.getOpt('method') === 'octet') { - $.xhr.setRequestHeader('Content-Type', 'application/octet-stream'); - } - $.xhr.timeout = $.getOpt('xhrTimeout'); - $.xhr.withCredentials = $.getOpt('withCredentials'); - // Add data from header options - var customHeaders = $.getOpt('headers'); - if(typeof customHeaders === 'function') { - customHeaders = customHeaders($.fileObj, $); - } - - $h.each(customHeaders, function(k,v) { - $.xhr.setRequestHeader(k, v); - }); - - if ($.getOpt('chunkFormat') == 'blob') { - $.xhr.send(data); - } - }; - $.abort = function(){ - // Abort and reset - if($.xhr) $.xhr.abort(); - $.xhr = null; - }; - $.status = function(){ - // Returns: 'pending', 'uploading', 'success', 'error' - if($.pendingRetry) { - // if pending retry then that's effectively the same as actively uploading, - // there might just be a slight delay before the retry starts - return('uploading'); - } else if(!$.xhr) { - return('pending'); - } else if($.xhr.readyState<4) { - // Status is really 'OPENED', 'HEADERS_RECEIVED' or 'LOADING' - meaning that stuff is happening - return('uploading'); - } else { - if($.xhr.status == 200 || $.xhr.status == 201) { - // HTTP 200, 201 (created) - return('success'); - } else if($h.contains($.getOpt('permanentErrors'), $.xhr.status) || $.retries >= $.getOpt('maxChunkRetries')) { - // HTTP 415/500/501, permanent error - return('error'); - } else { - // this should never happen, but we'll reset and queue a retry - // a likely case for this would be 503 service unavailable - $.abort(); - return('pending'); - } - } - }; - $.message = function(){ - return($.xhr ? $.xhr.responseText : ''); - }; - $.progress = function(relative){ - if(typeof(relative)==='undefined') relative = false; - var factor = (relative ? ($.endByte-$.startByte)/$.fileObjSize : 1); - if($.pendingRetry) return(0); - if(!$.xhr || !$.xhr.status) factor*=.95; - var s = $.status(); - switch(s){ - case 'success': - case 'error': - return(1*factor); - case 'pending': - return(0*factor); - default: - return($.loaded/($.endByte-$.startByte)*factor); - } - }; - return(this); - } - - // QUEUE - $.uploadNextChunk = function(){ - var found = false; - - // In some cases (such as videos) it's really handy to upload the first - // and last chunk of a file quickly; this let's the server check the file's - // metadata and determine if there's even a point in continuing. - if ($.getOpt('prioritizeFirstAndLastChunk')) { - $h.each($.files, function(file){ - if(file.chunks.length && file.chunks[0].status()=='pending' && file.chunks[0].preprocessState === 0) { - file.chunks[0].send(); - found = true; - return(false); - } - if(file.chunks.length>1 && file.chunks[file.chunks.length-1].status()=='pending' && file.chunks[file.chunks.length-1].preprocessState === 0) { - file.chunks[file.chunks.length-1].send(); - found = true; - return(false); - } - }); - if(found) return(true); - } - - // Now, simply look for the next, best thing to upload - $h.each($.files, function(file){ - if(file.isPaused()===false){ - $h.each(file.chunks, function(chunk){ - if(chunk.status()=='pending' && chunk.preprocessState === 0) { - chunk.send(); - found = true; - return(false); - } - }); - } - if(found) return(false); - }); - if(found) return(true); - - // The are no more outstanding chunks to upload, check is everything is done - var outstanding = false; - $h.each($.files, function(file){ - if(!file.isComplete()) { - outstanding = true; - return(false); - } - }); - if(!outstanding) { - // All chunks have been uploaded, complete - $.fire('complete'); - } - return(false); - }; - - - // PUBLIC METHODS FOR RESUMABLE.JS - $.assignBrowse = function(domNodes, isDirectory){ - if(typeof(domNodes.length)=='undefined') domNodes = [domNodes]; - - $h.each(domNodes, function(domNode) { - var input; - if(domNode.tagName==='INPUT' && domNode.type==='file'){ - input = domNode; - } else { - input = document.createElement('input'); - input.setAttribute('type', 'file'); - input.style.display = 'none'; - domNode.addEventListener('click', function(){ - input.style.opacity = 0; - input.style.display='block'; - input.focus(); - input.click(); - input.style.display='none'; - }, false); - domNode.appendChild(input); - } - var maxFiles = $.getOpt('maxFiles'); - if (typeof(maxFiles)==='undefined'||maxFiles!=1){ - input.setAttribute('multiple', 'multiple'); - } else { - input.removeAttribute('multiple'); - } - if(isDirectory){ - input.setAttribute('webkitdirectory', 'webkitdirectory'); - } else { - input.removeAttribute('webkitdirectory'); - } - var fileTypes = $.getOpt('fileType'); - if (typeof (fileTypes) !== 'undefined' && fileTypes.length >= 1) { - input.setAttribute('accept', fileTypes.map(function (e) { return '.' + e }).join(',')); - } - else { - input.removeAttribute('accept'); - } - // When new files are added, simply append them to the overall list - input.addEventListener('change', function(e){ - appendFilesFromFileList(e.target.files,e); - var clearInput = $.getOpt('clearInput'); - if (clearInput) { - e.target.value = ''; - } - }, false); - }); - }; - $.assignDrop = function(domNodes){ - if(typeof(domNodes.length)=='undefined') domNodes = [domNodes]; - - $h.each(domNodes, function(domNode) { - domNode.addEventListener('dragover', preventDefault, false); - domNode.addEventListener('dragenter', preventDefault, false); - domNode.addEventListener('drop', onDrop, false); - }); - }; - $.unAssignDrop = function(domNodes) { - if (typeof(domNodes.length) == 'undefined') domNodes = [domNodes]; - - $h.each(domNodes, function(domNode) { - domNode.removeEventListener('dragover', preventDefault); - domNode.removeEventListener('dragenter', preventDefault); - domNode.removeEventListener('drop', onDrop); - }); - }; - $.isUploading = function(){ - var uploading = false; - $h.each($.files, function(file){ - if (file.isUploading()) { - uploading = true; - return(false); - } - }); - return(uploading); - }; - $.upload = function(){ - // Make sure we don't start too many uploads at once - if($.isUploading()) return; - // Kick off the queue - $.fire('uploadStart'); - for (var num=1; num<=$.getOpt('simultaneousUploads'); num++) { - $.uploadNextChunk(); - } - }; - $.pause = function(){ - // Resume all chunks currently being uploaded - $h.each($.files, function(file){ - file.abort(); - }); - $.fire('pause'); - }; - $.cancel = function(){ - $.fire('beforeCancel'); - for(var i = $.files.length - 1; i >= 0; i--) { - $.files[i].cancel(); - } - $.fire('cancel'); - }; - $.progress = function(){ - var totalDone = 0; - var totalSize = 0; - // Resume all chunks currently being uploaded - $h.each($.files, function(file){ - totalDone += file.progress()*file.size; - totalSize += file.size; - }); - return(totalSize>0 ? totalDone/totalSize : 0); - }; - $.addFile = function(file, event){ - appendFilesFromFileList([file], event); - }; - $.addFiles = function(files, event){ - appendFilesFromFileList(files, event); - }; - $.removeFile = function(file){ - for(var i = $.files.length - 1; i >= 0; i--) { - if($.files[i] === file) { - $.files.splice(i, 1); - } - } - }; - $.getFromUniqueIdentifier = function(uniqueIdentifier){ - var ret = false; - $h.each($.files, function(f){ - if(f.uniqueIdentifier==uniqueIdentifier) ret = f; - }); - return(ret); - }; - $.getSize = function(){ - var totalSize = 0; - $h.each($.files, function(file){ - totalSize += file.size; - }); - return(totalSize); - }; - $.handleDropEvent = function (e) { - onDrop(e); - }; - $.handleChangeEvent = function (e) { - appendFilesFromFileList(e.target.files, e); - e.target.value = ''; - }; - $.updateQuery = function(query){ - $.opts.query = query; - }; - - return(this); - }; - - - // Node.js-style export for Node and Component - if (typeof module != 'undefined') { - module.exports = Resumable; - } else if (typeof define === "function" && define.amd) { - // AMD/requirejs: Define the module - define(function(){ - return Resumable; - }); - } else { - // Browser: Expose to window - window.Resumable = Resumable; - } - -})(); diff --git a/yarn.lock b/yarn.lock index ac89a473be1..20d51373a63 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3640,11 +3640,6 @@ restore-cursor@^3.1.0: onetime "^5.1.0" signal-exit "^3.0.2" -resumablejs@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/resumablejs/-/resumablejs-1.1.0.tgz#3160633688ac35bc2a0f119803c190ec369ef4d2" - integrity sha512-gUTWTtJ2aheRb5svHDGHMtQsBkGxTILpZApT11ODoxEe5D75GhYL7Nc/WYgCcJXY+5RVmm2BEsp2qriCkKWRRg== - ret@~0.1.10: version "0.1.15" resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"