From 0d1809c08ee4bbc2ed7a5040ae3038f5c82f80a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=97=A0=E9=99=90UCW?= <45730483+wuxianucw@users.noreply.github.com> Date: Tue, 18 May 2021 22:41:43 +0800 Subject: [PATCH] ui: add upload progress bar (#141) --- packages/ui-default/locales/en.yaml | 2 +- packages/ui-default/locales/zh.yaml | 6 +- packages/ui-default/locales/zh_TW.yaml | 2 +- .../ui-default/pages/problem_files.page.js | 57 +++++++++++++++++-- packages/ui-default/utils/request.js | 4 +- 5 files changed, 62 insertions(+), 9 deletions(-) diff --git a/packages/ui-default/locales/en.yaml b/packages/ui-default/locales/en.yaml index e19110aaf..f4067b77f 100644 --- a/packages/ui-default/locales/en.yaml +++ b/packages/ui-default/locales/en.yaml @@ -54,4 +54,4 @@ user_login: Login user_logout: Logout user_lostpass: Lost Password user_register: Register -wiki_help: Help \ No newline at end of file +wiki_help: Help diff --git a/packages/ui-default/locales/zh.yaml b/packages/ui-default/locales/zh.yaml index 962d2578d..548bf4694 100644 --- a/packages/ui-default/locales/zh.yaml +++ b/packages/ui-default/locales/zh.yaml @@ -24,6 +24,7 @@ __langname: 简体中文 'Copy failed :(': '复制失败 :(' 'Current dataset: {0}': '当前测试数据: {0}' 'Discussion: Terms Of Service': 讨论区服务条款 +'File upload failed: {0}': 文件上传失败:{0} 'Format: category 1, category 2, ..., category n': 格式:分类1, 分类2, ..., 分类n 'Hello, {0}! You can click following link to active your new email of your Hydro account:': 您好,{0}!您可以点击以下链接来激活您 Hydro 账户的新电子邮件地址: 'Hello, {0}! You can click following link to reset the password of your Hydro account:': 您好,{0}!您可以点击以下链接来重置您 Hydro 账户的密码: @@ -305,6 +306,7 @@ Failed to join the domain. You are already a member.: 加入域失败,您已 Feedback: 反馈 Field {0} or {1} validation failed.: 字段 {0} 或 {1} 验证失败。 Field {0} validation failed.: 字段 {0} 验证失败。 +File uploaded successfully.: 上传文件成功 File: 文件 Filename: 文件名 Files: 文件 @@ -760,6 +762,8 @@ Upload File: 上传文件 Upload Problem: 上传题目 Upload: 上传 Uploaded By: 上传者 +Uploading files...: 正在上传文件... +Uploading... ({0}%): 正在上传... ({0}%) Upvote: 好评 Usage exceeded.: 用量超限。 Use admin specificed: 由管理员指定 @@ -845,4 +849,4 @@ You've already attended this contest.: 您已经参加本次比赛。 You've already claimed this homework.: 您已认领过该作业。 You've already voted.: 您已经投过票。 Your permission: 您的权限 -Your role: 您的角色 \ No newline at end of file +Your role: 您的角色 diff --git a/packages/ui-default/locales/zh_TW.yaml b/packages/ui-default/locales/zh_TW.yaml index 1d67084d3..4940a629d 100644 --- a/packages/ui-default/locales/zh_TW.yaml +++ b/packages/ui-default/locales/zh_TW.yaml @@ -561,4 +561,4 @@ You've already attended this contest.: 您已經參加本次比賽。 You've already claimed this homework.: 您已認領該功課。 You've already voted.: 您已經投過票。 Your permission: 您的許可權 -Your role: 您的角色 \ No newline at end of file +Your role: 您的角色 diff --git a/packages/ui-default/pages/problem_files.page.js b/packages/ui-default/pages/problem_files.page.js index ad209a35a..fef82aa97 100644 --- a/packages/ui-default/pages/problem_files.page.js +++ b/packages/ui-default/pages/problem_files.page.js @@ -84,22 +84,69 @@ const page = new NamedPage('problem_files', () => { files = input.files; } try { - Notification.info('Uploading files...'); + Notification.info(i18n('Uploading files...')); const tasks = []; + const dialog = new Dialog({ + $body: `
+
+
+
+
+
+
+
`, + }); + const $uploadLabel = dialog.$dom.find('.dialog__body .upload-label'); + const $uploadProgress = dialog.$dom.find('.dialog__body .upload-progress'); + const $fileLabel = dialog.$dom.find('.dialog__body .file-label'); + const $fileProgress = dialog.$dom.find('.dialog__body .file-progress'); + let processed = 0; for (const file of files) { const data = new FormData(); data.append('filename', file.name); data.append('file', file); data.append('type', type); data.append('operation', 'upload_file'); - tasks.push(request.postFile('', data)); + tasks.push(request.postFile('', data, { + xhr() { + const xhr = new window.XMLHttpRequest(); + xhr.upload.addEventListener("loadstart", () => { + processed++; + $fileLabel.text(`[${processed}/${files.length}] ${file.name}`); + $fileProgress.css({ width: `${parseInt(processed / file.length * 100)}%` }); + $uploadLabel.text(i18n("Uploading... ({0}%)", 0)); + $uploadProgress.css({ width: 0 }); + }); + xhr.upload.addEventListener("progress", (e) => { + if (e.lengthComputable) { + let percentComplete = e.loaded / e.total; + percentComplete = parseInt(percentComplete * 100); + $uploadLabel.text(i18n("Uploading... ({0}%)", percentComplete)); + $uploadProgress.css({ width: `${percentComplete}%` }); + } + }, false); + return xhr; + }, + })); } + dialog.open(); + let isBeforeUnloadTriggeredByLibrary = !window.isSecureContext; + function onBeforeUnload(e) { + if (isBeforeUnloadTriggeredByLibrary) { + isBeforeUnloadTriggeredByLibrary = false; + return; + } + e.returnValue = ''; + } + window.addEventListener('beforeunload', onBeforeUnload); await Promise.all(tasks); - Notification.success('File uploaded successfully.'); - await pjax.request({ push: false }); + window.removeEventListener('beforeunload', onBeforeUnload); + Notification.success(i18n('File uploaded successfully.')); + await delay(2000); + window.location.reload(); } catch (e) { console.error(e); - Notification.error(`File upload fail: ${e.toString()}`); + Notification.error(i18n('File upload failed: {0}', e.toString())); } } diff --git a/packages/ui-default/utils/request.js b/packages/ui-default/utils/request.js index 18d6a0eca..929848619 100644 --- a/packages/ui-default/utils/request.js +++ b/packages/ui-default/utils/request.js @@ -41,8 +41,9 @@ const request = { /** * @param {string} url * @param {FormData} FormData + * @param {object} options */ - postFile(url, form) { + postFile(url, form, options = {}) { return this.ajax({ url, data: form, @@ -50,6 +51,7 @@ const request = { contentType: false, type: 'POST', dataType: undefined, + ...options, }); },