From b8be70f6dca5d180a0738127c38032b3e4de69a9 Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Tue, 9 Mar 2021 17:06:35 +0100 Subject: [PATCH] Add a feedback when uploading a file --- assets/js/common/api.js | 14 ++++-- .../conversations/fileUploadProgress.js | 50 +++++++++++++++++++ .../js/components/conversations/interface.js | 5 +- assets/js/components/conversations/utils.js | 9 ++-- system/config/dev.config.php | 1 + 5 files changed, 70 insertions(+), 9 deletions(-) create mode 100644 assets/js/components/conversations/fileUploadProgress.js diff --git a/assets/js/common/api.js b/assets/js/common/api.js index 131888c0..3ece88f5 100644 --- a/assets/js/common/api.js +++ b/assets/js/common/api.js @@ -30,9 +30,10 @@ const APIClient = { }, /** + * @param {(number) => void} progressCallback Use this function to monitor upload * @returns {Promise} */ - execFormData: function(uri, data, withLogin) { + execFormData: function(uri, data, withLogin, progressCallback) { if (!data) data = new FormData(); @@ -43,7 +44,7 @@ const APIClient = { else res(result); - }) + }, progressCallback) }); }, @@ -108,8 +109,9 @@ const APIClient = { * @param {FormData} data The form data object * @param {Boolean} requireLoginTokens Specify if login tokens are required or not * @param {Function} nextAction What to do next + * @param {(number) => void} progressCallback Use this function to monitor upload */ - makeFormDatarequest: function(apiURI, data, requireLoginTokens, nextAction){ + makeFormDatarequest: function(apiURI, data, requireLoginTokens, nextAction, progressCallback){ //Prepare the request URL var requestURL = ComunicWeb.__config.apiURL + apiURI; @@ -134,6 +136,12 @@ const APIClient = { ComunicWeb.common.api._on_state_change(requestURL, apiXHR, nextAction); } + // Monitor upload progress, if required + if (progressCallback) + apiXHR.upload.addEventListener("progress", e => { + progressCallback(e.loaded/e.total); + }); + //Submit request apiXHR.send(data); }, diff --git a/assets/js/components/conversations/fileUploadProgress.js b/assets/js/components/conversations/fileUploadProgress.js new file mode 100644 index 00000000..b728e5e2 --- /dev/null +++ b/assets/js/components/conversations/fileUploadProgress.js @@ -0,0 +1,50 @@ +/** + * Conversation file upload progress + * + * Show a progress bar letting the user know when + * is file is sent. + * + * @author Pierre Hubert + */ + +class FileUploadProgress { + + /** + * Initialise a new progress bar + * + * @param {HTMLElement} target + */ + constructor(target) { + const progressContainerElem = createElem2({ + appendTo: target, + type: "div", + class: "progress progress-xs progress-striped active" + }); + progressContainerElem.style.marginBottom = "0px" + + this.progresselem = createElem2({ + appendTo: progressContainerElem, + type: "div", + class: "progress-bar progress-bar-success", + }) + + this.setProgress(0) + } + + /** + * Apply a new progress + * + * @param {number} progress Between 0 and 1 + */ + setProgress(progress) { + this.progresselem.style.width = Math.floor(progress*100) + "%" + } + + /** + * Remove the progress element + * from the page + */ + remove() { + this.progresselem.parentNode.remove() + } +} \ No newline at end of file diff --git a/assets/js/components/conversations/interface.js b/assets/js/components/conversations/interface.js index ae537db5..cd32e157 100644 --- a/assets/js/components/conversations/interface.js +++ b/assets/js/components/conversations/interface.js @@ -237,8 +237,9 @@ const ConversationsInterface = { * @param {number} convID The ID of the conversation * @param {string} message The message to send (if not a file) * @param {HTMLInputElement} file The file to send (if any) + * @param {(number) => void} progress Optional progress callback (if a file is sent) */ - sendMessage: async function(convID, message, file){ + sendMessage: async function(convID, message, file, progress){ //Perform an API request var apiURI = "conversations/sendMessage"; @@ -264,7 +265,7 @@ const ConversationsInterface = { fd.append("file", file.files[0], file.files[0].name); //Perform an API request - await APIClient.execFormData(apiURI, fd, true); + await APIClient.execFormData(apiURI, fd, true, progress); } }, diff --git a/assets/js/components/conversations/utils.js b/assets/js/components/conversations/utils.js index bcb82057..1db72af2 100644 --- a/assets/js/components/conversations/utils.js +++ b/assets/js/components/conversations/utils.js @@ -228,7 +228,7 @@ const ConversationsUtils = { * @param {HTMLInputElement} input * @param {HTMLElement} target */ - registerInputToSendFile: function(convID, fileInput, splashScreenTarget){ + registerInputToSendFile: function(convID, fileInput, progressTarget){ fileInput.addEventListener("change", async (e) => { e.preventDefault(); @@ -252,9 +252,10 @@ const ConversationsUtils = { return; } - el = Page.showTransparentWaitSplashScreen(splashScreenTarget); + el = new FileUploadProgress(progressTarget); - await ConversationsInterface.sendMessage(convID, null, fileInput); + + await ConversationsInterface.sendMessage(convID, null, fileInput, (progress) => el.setProgress(progress)); } catch(e) { @@ -262,7 +263,7 @@ const ConversationsUtils = { notify(tr("Failed to send file!"), "danger"); } - el.remove(); + el.remove() }); }, diff --git a/system/config/dev.config.php b/system/config/dev.config.php index 0824471d..4cc6b0c4 100644 --- a/system/config/dev.config.php +++ b/system/config/dev.config.php @@ -407,6 +407,7 @@ class Dev { "js/components/conversations/unreadDropdown.js", "js/components/conversations/messageEditor.js", "js/components/conversations/writingNotifier.js", + "js/components/conversations/fileUploadProgress.js", //User selector "js/components/userSelect/userSelect.js",