Dropzone: Swapped fetch for XHR for progress tracking
This commit is contained in:
parent
23915c3b1a
commit
36116a45d4
2 changed files with 61 additions and 12 deletions
|
@ -56,18 +56,17 @@ export class Dropzone extends Component {
|
|||
* @return {Upload}
|
||||
*/
|
||||
createUploadFromFile(file) {
|
||||
const {dom, status} = this.createDomForFile(file);
|
||||
const {dom, status, progress} = this.createDomForFile(file);
|
||||
this.container.append(dom);
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('file', file, file.name);
|
||||
|
||||
// TODO - Change to XMLHTTPRequest so we can track progress.
|
||||
const uploadPromise = window.$http.post(this.url, formData);
|
||||
|
||||
const upload = {
|
||||
file,
|
||||
dom,
|
||||
updateProgress(percentComplete) {
|
||||
console.log(`progress: ${percentComplete}%`);
|
||||
progress.textContent = `${percentComplete}%`;
|
||||
progress.style.width = `${percentComplete}%`;
|
||||
},
|
||||
markError(message) {
|
||||
status.setAttribute('data-status', 'error');
|
||||
status.textContent = message;
|
||||
|
@ -78,15 +77,43 @@ export class Dropzone extends Component {
|
|||
},
|
||||
};
|
||||
|
||||
uploadPromise.then(returnData => {
|
||||
upload.markSuccess(returnData.statusText);
|
||||
}).catch(err => {
|
||||
upload.markError(err?.data?.message || err.message);
|
||||
});
|
||||
this.startXhrForUpload(upload);
|
||||
|
||||
return upload;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Upload} upload
|
||||
*/
|
||||
startXhrForUpload(upload) {
|
||||
const formData = new FormData();
|
||||
formData.append('file', upload.file, upload.file.name);
|
||||
|
||||
const req = window.$http.createXMLHttpRequest('POST', this.url, {
|
||||
error() {
|
||||
upload.markError('Upload failed'); // TODO - Update text
|
||||
},
|
||||
readystatechange() {
|
||||
if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
|
||||
upload.markSuccess('Finished upload!');
|
||||
} else if (this.readyState === XMLHttpRequest.DONE && this.status >= 400) {
|
||||
const content = this.responseText;
|
||||
const data = content.startsWith('{') ? JSON.parse(content) : {message: content};
|
||||
const message = data?.message || content;
|
||||
upload.markError(message);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
req.upload.addEventListener('progress', evt => {
|
||||
const percent = Math.min(Math.ceil((evt.loaded / evt.total) * 100), 100);
|
||||
upload.updateProgress(percent);
|
||||
});
|
||||
|
||||
req.setRequestHeader('Accept', 'application/json');
|
||||
req.send(formData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {File} file
|
||||
* @return {{image: Element, dom: Element, progress: Element, label: Element, status: Element}}
|
||||
|
@ -121,6 +148,7 @@ export class Dropzone extends Component {
|
|||
* @typedef Upload
|
||||
* @property {File} file
|
||||
* @property {Element} dom
|
||||
* @property {function(Number)} updateProgress
|
||||
* @property {function(String)} markError
|
||||
* @property {function(String)} markSuccess
|
||||
*/
|
||||
|
|
|
@ -45,6 +45,27 @@ export class HttpError extends Error {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String} method
|
||||
* @param {String} url
|
||||
* @param {Object} events
|
||||
* @return {XMLHttpRequest}
|
||||
*/
|
||||
export function createXMLHttpRequest(method, url, events = {}) {
|
||||
const csrfToken = document.querySelector('meta[name=token]').getAttribute('content');
|
||||
const req = new XMLHttpRequest();
|
||||
|
||||
for (const [eventName, callback] of Object.entries(events)) {
|
||||
req.addEventListener(eventName, callback.bind(req));
|
||||
}
|
||||
|
||||
req.open(method, url);
|
||||
req.withCredentials = true;
|
||||
req.setRequestHeader('X-CSRF-TOKEN', csrfToken);
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new HTTP request, setting the required CSRF information
|
||||
* to communicate with the back-end. Parses & formats the response.
|
||||
|
|
Loading…
Reference in a new issue