From d10fec361c10bab4dabddc5e0f97f9c77aa34047 Mon Sep 17 00:00:00 2001 From: undefined Date: Mon, 11 Oct 2021 23:33:54 +0800 Subject: [PATCH] ui: change to ts & tsx --- packages/hydrooj/package.json | 2 +- packages/hydrooj/src/error.ts | 2 +- packages/hydrooj/src/handler/manage.ts | 15 ---- packages/hydrooj/src/handler/misc.ts | 30 -------- packages/hydrooj/src/interface.ts | 2 + packages/hydrooj/src/lib/mail.ts | 2 +- packages/hydrooj/src/model/setting.ts | 2 - packages/ui-default/.eslintrc.js | 14 +++- .../dialog/{DomDialog.js => DomDialog.ts} | 68 ++++++++++--------- .../components/dialog/{index.js => index.ts} | 14 ++-- .../components/zipDownloader/index.js | 21 +++++- packages/ui-default/package.json | 2 +- ...test_main.page.js => contest_main.page.ts} | 5 +- .../pages/discussion_detail.page.js | 10 --- .../ui-default/pages/discussion_node.page.js | 10 --- ...ge.js => domain_join_applications.page.ts} | 4 +- packages/ui-default/pages/domain_role.page.js | 4 +- .../ui-default/pages/problem_detail.page.jsx | 13 +--- .../ui-default/pages/problem_edit.page.js | 6 +- .../ui-default/pages/problem_files.page.js | 10 --- .../ui-default/pages/problem_sidebar.page.ts | 25 +++++++ .../ui-default/pages/problem_solution.page.js | 10 --- .../ui-default/pages/problem_submit.page.js | 5 -- ...d_detail.page.js => record_detail.page.ts} | 6 +- ...ecord_main.page.js => record_main.page.ts} | 10 ++- .../ui-default/pages/training_detail.page.js | 35 ---------- .../ui-default/pages/training_detail.page.ts | 24 +++++++ ...ing_edit.page.js => training_edit.page.ts} | 5 +- .../ui-default/templates/contest_main.html | 30 ++++---- 29 files changed, 165 insertions(+), 221 deletions(-) rename packages/ui-default/components/dialog/{DomDialog.js => DomDialog.ts} (70%) rename packages/ui-default/components/dialog/{index.js => index.ts} (89%) rename packages/ui-default/pages/{contest_main.page.js => contest_main.page.ts} (51%) delete mode 100644 packages/ui-default/pages/discussion_detail.page.js delete mode 100644 packages/ui-default/pages/discussion_node.page.js rename packages/ui-default/pages/{domain_join_applications.page.js => domain_join_applications.page.ts} (84%) create mode 100644 packages/ui-default/pages/problem_sidebar.page.ts delete mode 100644 packages/ui-default/pages/problem_solution.page.js rename packages/ui-default/pages/{record_detail.page.js => record_detail.page.ts} (81%) rename packages/ui-default/pages/{record_main.page.js => record_main.page.ts} (82%) delete mode 100644 packages/ui-default/pages/training_detail.page.js create mode 100644 packages/ui-default/pages/training_detail.page.ts rename packages/ui-default/pages/{training_edit.page.js => training_edit.page.ts} (88%) diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json index 8027cf518..13798dc79 100644 --- a/packages/hydrooj/package.json +++ b/packages/hydrooj/package.json @@ -1,6 +1,6 @@ { "name": "hydrooj", - "version": "2.39.18", + "version": "2.39.19", "bin": "bin/hydrooj.js", "main": "src/loader", "module": "src/loader", diff --git a/packages/hydrooj/src/error.ts b/packages/hydrooj/src/error.ts index 15880844c..d11164cc8 100644 --- a/packages/hydrooj/src/error.ts +++ b/packages/hydrooj/src/error.ts @@ -47,7 +47,7 @@ export const ForbiddenError = Err('ForbiddenError', UserFacingError, 'ForbiddenE export const NotFoundError = Err('NotFoundError', UserFacingError, 'NotFoundError', 404); export const MethodNotAllowedError = Err('MethodNotAllowedError', UserFacingError, 'MethodNotAllowedError', 405); export const RemoteOnlineJudgeError = Err('RemoteOnlineJudgeError', UserFacingError, 'RemoteOnlineJudgeError', 500); -export const SendMailError = Err('SendMailError', UserFacingError, 'Failed to send mail to {0}.', 500); +export const SendMailError = Err('SendMailError', UserFacingError, 'Failed to send mail to {0}. (1)', 500); export const AlreadyVotedError = Err('AlreadyVotedError', ForbiddenError, "You've already voted."); export const LoginError = Err('LoginError', ForbiddenError, 'Invalid password for user {0}.'); diff --git a/packages/hydrooj/src/handler/manage.ts b/packages/hydrooj/src/handler/manage.ts index a63425b3a..68bbf82fd 100644 --- a/packages/hydrooj/src/handler/manage.ts +++ b/packages/hydrooj/src/handler/manage.ts @@ -49,11 +49,6 @@ function set(key: string, value: any) { class SystemHandler extends Handler { async prepare() { this.checkPriv(PRIV.PRIV_EDIT_SYSTEM); - this.response.body = { - path: [ - ['Hydro', 'homepage'], - ], - }; } } @@ -86,12 +81,6 @@ class SystemCheckConnHandler extends ConnectionHandler { class SystemDashboardHandler extends SystemHandler { async get() { this.response.template = 'manage_dashboard.html'; - this.response.body.path.push(['manage_dashboard', null]); - } - - async postRestart() { - // TODO handle restart - this.back(); } } @@ -99,7 +88,6 @@ class SystemScriptHandler extends SystemHandler { async get() { this.response.template = 'manage_script.html'; this.response.body.scripts = global.Hydro.script; - this.response.body.path.push(['manage_script', null]); } @param('id', Types.Name) @@ -147,7 +135,6 @@ class SystemScriptHandler extends SystemHandler { class SystemSettingHandler extends SystemHandler { async get() { this.response.template = 'manage_setting.html'; - this.response.body.path.push(['manage_setting', null]); this.response.body.current = {}; this.response.body.settings = setting.SYSTEM_SETTINGS; for (const s of this.response.body.settings) { @@ -185,7 +172,6 @@ class SystemSettingHandler extends SystemHandler { class SystemUserImportHandler extends SystemHandler { async get() { this.response.body.users = []; - this.response.body.path.push(['manage_user_import']); this.response.template = 'manage_user_import.html'; } @@ -232,7 +218,6 @@ class SystemUserImportHandler extends SystemHandler { } } } - this.response.body.path.push(['manage_user_import']); this.response.body.users = udocs; this.response.body.messages = messages; } diff --git a/packages/hydrooj/src/handler/misc.ts b/packages/hydrooj/src/handler/misc.ts index 7d38362d1..afebfec6a 100644 --- a/packages/hydrooj/src/handler/misc.ts +++ b/packages/hydrooj/src/handler/misc.ts @@ -13,35 +13,6 @@ import { } from '../service/server'; import { sortFiles } from '../utils'; -class CheckInHandler extends Handler { - async prepare() { - const { checkincnt, lastcheckin } = this.user; - const today = new Date(); - today.setHours(0); - today.setMinutes(0); - today.setSeconds(0); - today.setMilliseconds(0); - if (lastcheckin === today.getTime()) throw new BadRequestError("You've already checked in today!"); - this.user.checkincnt++; - this.user.lastcheckin = today.getTime(); - await Promise.all([ - user.setById(this.user._id, { checkincnt, lastcheckin }), - user.inc(this.user._id, 'rpdelta', Math.round(Math.sqrt(checkincnt))), - ]); - } - - async get() { - this.response.redirect = '/'; - } - - async post() { - this.response.body = { - cnt: this.user.checkincnt, - last: this.user.lastcheckin, - }; - } -} - class SwitchLanguageHandler extends Handler { @param('lang', Types.Name) async get(domainId: string, lang: string) { @@ -132,7 +103,6 @@ export class FSDownloadHandler extends Handler { } export async function apply() { - Route('check_in', '/checkin', CheckInHandler, PRIV.PRIV_USER_PROFILE); Route('switch_language', '/language/:lang', SwitchLanguageHandler); Route('home_files', '/file', FilesHandler, PRIV.PRIV_CREATE_FILE); Route('fs_download', '/file/:uid/:filename', FSDownloadHandler); diff --git a/packages/hydrooj/src/interface.ts b/packages/hydrooj/src/interface.ts index 34814d367..6af4f13c2 100644 --- a/packages/hydrooj/src/interface.ts +++ b/packages/hydrooj/src/interface.ts @@ -677,6 +677,8 @@ declare global { addons: string[], } } + var Hydro: HydroGlobal; // eslint-disable-line + var addons: string[]; // eslint-disable-line } declare module 'koa' { diff --git a/packages/hydrooj/src/lib/mail.ts b/packages/hydrooj/src/lib/mail.ts index 4571fe631..dbaa5779c 100644 --- a/packages/hydrooj/src/lib/mail.ts +++ b/packages/hydrooj/src/lib/mail.ts @@ -33,7 +33,7 @@ export async function sendMail(to: string, subject: string, text: string, html: }); } catch (e) { logger.error(e); - throw new SendMailError(to); + throw new SendMailError(to, e.message); } return t; } diff --git a/packages/hydrooj/src/model/setting.ts b/packages/hydrooj/src/model/setting.ts index c3e6ff552..bc184d605 100644 --- a/packages/hydrooj/src/model/setting.ts +++ b/packages/hydrooj/src/model/setting.ts @@ -131,8 +131,6 @@ AccountSetting( '/components/profile/backgrounds/1.jpg', 'text', 'Profile Background Image', 'Choose the background image in your profile page.'), Setting('setting_storage', 'unreadMsg', 0, 'number', 'Unread Message Count', null, FLAG_DISABLED | FLAG_HIDDEN), - Setting('setting_storage', 'checkincnt', 0, 'number', 'Check In Counter', null, FLAG_DISABLED | FLAG_HIDDEN), - Setting('setting_storage', 'lastcheckin', 0, 'number', 'Last checkin time', null, FLAG_DISABLED | FLAG_HIDDEN), Setting('setting_storage', 'badge', '', 'text', 'badge info', null, FLAG_DISABLED | FLAG_HIDDEN), ); diff --git a/packages/ui-default/.eslintrc.js b/packages/ui-default/.eslintrc.js index be7a3fda7..154d8ae41 100644 --- a/packages/ui-default/.eslintrc.js +++ b/packages/ui-default/.eslintrc.js @@ -62,6 +62,16 @@ module.exports = { 'no-unused-vars': 'off', '@typescript-eslint/no-unused-vars': 'warn', + '@typescript-eslint/lines-between-class-members': [ + 'error', + 'always', + { exceptAfterSingleLine: true }, + ], + 'lines-between-class-members': [ + 'error', + 'always', + { exceptAfterSingleLine: true }, + ], 'comma-dangle': [ 'error', 'always-multiline', @@ -69,9 +79,7 @@ module.exports = { indent: [ 'error', 2, - { - SwitchCase: 0, - }, + { SwitchCase: 0 }, ], 'max-len': ['error', 150], quotes: 'warn', diff --git a/packages/ui-default/components/dialog/DomDialog.js b/packages/ui-default/components/dialog/DomDialog.ts similarity index 70% rename from packages/ui-default/components/dialog/DomDialog.js rename to packages/ui-default/components/dialog/DomDialog.ts index 21f6d0f7f..ab939d92d 100644 --- a/packages/ui-default/components/dialog/DomDialog.js +++ b/packages/ui-default/components/dialog/DomDialog.ts @@ -2,20 +2,33 @@ import _ from 'lodash'; import DOMAttachedObject from 'vj/components/DOMAttachedObject'; import zIndexManager from 'vj/utils/zIndexManager'; +export interface DialogOptions { + classes: string; + $body: HTMLElement; + $action: any; + width?: string; + height?: string; + cancelByClickingBack?: boolean; + cancelByEsc?: boolean; + canCancel?: boolean; + onDispatch?: (data: any) => any; +} + export default class DomDialog extends DOMAttachedObject { static DOMAttachKey = 'vjDomDialogInstance'; + isShown = false; + isAnimating = false; + options: DialogOptions; + _resolve: (value: string | PromiseLike) => void; - constructor($dom, options = {}) { + constructor($dom, options: Partial = {}) { super($dom); - this.isShown = false; - this.isAnimating = false; this.options = { cancelByClickingBack: false, cancelByEsc: false, onDispatch: () => { }, - ...options, + ...options as any, }; - this._defer = null; } async _show() { @@ -70,9 +83,7 @@ export default class DomDialog extends DOMAttachedObject { $(document).off(`keyup.${this.eventNS}`); this.$dom.off(`click.${this.eventNS}`); - this.$dom.css({ - opacity: 1, - }); + this.$dom.css({ opacity: 1 }); this.$dom.transition({ opacity: 0, }, { @@ -80,17 +91,15 @@ export default class DomDialog extends DOMAttachedObject { }); const $dgContent = this.$dom.find('.dialog__content'); - $dgContent.css({ - scale: 1, - }); + $dgContent.css({ scale: 1 }); await $dgContent - .transition({ - scale: 0.8, - }, { - duration: 200, - easing: 'easeOutCubic', - }) - .promise(); + .transition( + { scale: 0.8 }, + { + duration: 200, + easing: 'easeOutCubic', + }, + ).promise(); this.$dom.css('display', 'none'); @@ -103,28 +112,23 @@ export default class DomDialog extends DOMAttachedObject { if (this.isShown || this.isAnimating) { return Promise.reject(); } - this._defer = new $.Deferred(); + const promise = new Promise((resolve) => { + this._resolve = resolve; + }); this._show(); - return this._defer.promise(); + return promise; } hide() { - if (!this.isShown || this.isAnimating) { - return false; - } - if (this._defer.state() === 'pending') { - this._defer.resolve('cancel'); - } - this._defer = null; + if (!this.isShown || this.isAnimating) return false; + this._resolve('cancel'); this._hide(); return true; } - dispatchAction(data) { - if (this.options.onDispatch(data) === false) { - return; - } - this._defer.resolve(data); + dispatchAction(data: string) { + if (this.options.onDispatch(data) === false) return; + this._resolve(data); this.hide(); } diff --git a/packages/ui-default/components/dialog/index.js b/packages/ui-default/components/dialog/index.ts similarity index 89% rename from packages/ui-default/components/dialog/index.js rename to packages/ui-default/components/dialog/index.ts index 4d1b753f2..1aef54a92 100644 --- a/packages/ui-default/components/dialog/index.js +++ b/packages/ui-default/components/dialog/index.ts @@ -1,9 +1,13 @@ import tpl from 'vj/utils/tpl'; import i18n from 'vj/utils/i18n'; -import DomDialog from './DomDialog'; +import DomDialog, { DialogOptions } from './DomDialog'; export class Dialog { - constructor(options = {}) { + options: DialogOptions; + $dom: JQuery; + domDialogInstance: DomDialog; + + constructor(options: Partial = {}) { this.options = { classes: '', $body: null, @@ -60,7 +64,7 @@ const buttonYes = tpl``; export class InfoDialog extends Dialog { - constructor(options = {}) { + constructor(options: Partial = {}) { super({ $action: buttonOk, cancelByClickingBack: true, @@ -71,7 +75,7 @@ export class InfoDialog extends Dialog { } export class ActionDialog extends Dialog { - constructor(options = {}) { + constructor(options: Partial = {}) { super({ $action: [buttonCancel, buttonOk].join('\n'), cancelByClickingBack: true, @@ -82,7 +86,7 @@ export class ActionDialog extends Dialog { } export class ConfirmDialog extends Dialog { - constructor(options = {}) { + constructor(options: Partial = {}) { let buttons = []; if (options.canCancel) { buttons = [buttonCancel, buttonNo, buttonYes]; diff --git a/packages/ui-default/components/zipDownloader/index.js b/packages/ui-default/components/zipDownloader/index.js index 6fc457152..fa289e42d 100644 --- a/packages/ui-default/components/zipDownloader/index.js +++ b/packages/ui-default/components/zipDownloader/index.js @@ -5,6 +5,7 @@ import pipeStream from 'vj/utils/pipeStream'; import i18n from 'vj/utils/i18n'; import request from 'vj/utils/request'; import Notification from 'vj/components/notification'; +import api from 'vj/utils/api'; let isBeforeUnloadTriggeredByLibrary = !window.isSecureContext; function onBeforeUnload(e) { @@ -67,7 +68,24 @@ export async function downloadProblemSet(pids, name = 'Export') { const targets = []; try { for (const pid of pids) { - const { pdoc } = await request.get(`/d/${UiContext.domainId}/p/${pid}`); + const { pdoc } = await request.get(`/d/${UiContext.domainId}/api`); + await api(gql` + problem(id: ${pid}) { + pid + owner + title + content + tag + nSubmit + nAccept + data { + name + } + additional_file { + name + } + } + `); targets.push({ filename: `${pid}/problem.yaml`, content: dump({ @@ -77,7 +95,6 @@ export async function downloadProblemSet(pids, name = 'Export') { tag: pdoc.tag, nSubmit: pdoc.nSubmit, nAccept: pdoc.nAccept, - difficulty: pdoc.difficulty, }), }); targets.push({ diff --git a/packages/ui-default/package.json b/packages/ui-default/package.json index 938ddc165..74ee02829 100644 --- a/packages/ui-default/package.json +++ b/packages/ui-default/package.json @@ -1,6 +1,6 @@ { "name": "@hydrooj/ui-default", - "version": "4.24.5", + "version": "4.25.0", "author": "undefined ", "license": "AGPL-3.0", "main": "hydro.js", diff --git a/packages/ui-default/pages/contest_main.page.js b/packages/ui-default/pages/contest_main.page.ts similarity index 51% rename from packages/ui-default/pages/contest_main.page.js rename to packages/ui-default/pages/contest_main.page.ts index a6c5f4faf..8bfb602b2 100644 --- a/packages/ui-default/pages/contest_main.page.js +++ b/packages/ui-default/pages/contest_main.page.ts @@ -1,9 +1,8 @@ import { NamedPage } from 'vj/misc/Page'; const page = new NamedPage('contest_main', () => { - // Contest Filter - $('[name="filter-form"] [name="rule"]').change(() => { - $('[name="filter-form"]').submit(); + $('[name="filter-form"] [name="rule"]').on('change', () => { + $('[name="filter-form"]').trigger('submit'); }); }); diff --git a/packages/ui-default/pages/discussion_detail.page.js b/packages/ui-default/pages/discussion_detail.page.js deleted file mode 100644 index a08400019..000000000 --- a/packages/ui-default/pages/discussion_detail.page.js +++ /dev/null @@ -1,10 +0,0 @@ -import { NamedPage } from 'vj/misc/Page'; - -const page = new NamedPage('discussion_detail', async () => { - $(document).on('click', '[name="problem-sidebar__show-category"]', (ev) => { - $(ev.currentTarget).hide(); - $('[name="problem-sidebar__categories"]').show(); - }); -}); - -export default page; diff --git a/packages/ui-default/pages/discussion_node.page.js b/packages/ui-default/pages/discussion_node.page.js deleted file mode 100644 index eb1984a56..000000000 --- a/packages/ui-default/pages/discussion_node.page.js +++ /dev/null @@ -1,10 +0,0 @@ -import { NamedPage } from 'vj/misc/Page'; - -const page = new NamedPage('discussion_node', async () => { - $(document).on('click', '[name="problem-sidebar__show-category"]', (ev) => { - $(ev.currentTarget).hide(); - $('[name="problem-sidebar__categories"]').show(); - }); -}); - -export default page; diff --git a/packages/ui-default/pages/domain_join_applications.page.js b/packages/ui-default/pages/domain_join_applications.page.ts similarity index 84% rename from packages/ui-default/pages/domain_join_applications.page.js rename to packages/ui-default/pages/domain_join_applications.page.ts index 503145567..bb4a6528e 100644 --- a/packages/ui-default/pages/domain_join_applications.page.js +++ b/packages/ui-default/pages/domain_join_applications.page.ts @@ -6,13 +6,13 @@ const page = new NamedPage('domain_join_applications', () => { const $expire = $('[name="expire"]'); const $code = $('[name="invitationCode"]'); function updateFormState() { - const method = parseInt($('[name="method"]').val(), 10); + const method = +$('[name="method"]').val(); $role.prop('disabled', method === domainEnum.JOIN_METHOD_NONE).trigger('vjFormDisableUpdate'); $expire.prop('disabled', method === domainEnum.JOIN_METHOD_NONE).trigger('vjFormDisableUpdate'); $code.prop('disabled', method !== domainEnum.JOIN_METHOD_CODE).trigger('vjFormDisableUpdate'); } updateFormState(); - $('[name="method"]').change(() => updateFormState()); + $('[name="method"]').on('change', updateFormState); }); export default page; diff --git a/packages/ui-default/pages/domain_role.page.js b/packages/ui-default/pages/domain_role.page.js index 89bb81b06..e4c103244 100644 --- a/packages/ui-default/pages/domain_role.page.js +++ b/packages/ui-default/pages/domain_role.page.js @@ -40,9 +40,7 @@ const page = new NamedPage('domain_role', () => { async function handleClickCreateRole() { const action = await createRoleDialog.clear().open(); - if (action !== 'ok') { - return; - } + if (action !== 'ok') return; const role = createRoleDialog.$dom.find('[name="role"]').val(); try { await request.post('', { diff --git a/packages/ui-default/pages/problem_detail.page.jsx b/packages/ui-default/pages/problem_detail.page.jsx index 2e6758d76..491ed5ccf 100644 --- a/packages/ui-default/pages/problem_detail.page.jsx +++ b/packages/ui-default/pages/problem_detail.page.jsx @@ -1,9 +1,6 @@ import yaml from 'js-yaml'; import { getScoreColor } from '@hydrooj/utils/lib/status'; import { NamedPage } from 'vj/misc/Page'; -import tpl from 'vj/utils/tpl'; -import i18n from 'vj/utils/i18n'; -import { ConfirmDialog } from 'vj/components/dialog'; import { downloadProblemSet } from 'vj/components/zipDownloader'; import loadReactRedux from 'vj/utils/loadReactRedux'; import delay from 'vj/utils/delay'; @@ -263,15 +260,7 @@ const page = new NamedPage(['problem_detail', 'contest_detail_problem', 'homewor leaveScratchpadMode(); ev.preventDefault(); }); - $(document).on('click', '[name="problem-sidebar__rejudge"]', (ev) => { - ev.preventDefault(); - new ConfirmDialog({ - $body: tpl.typoMsg(i18n('Confirm rejudge this problem?')), - }).open().then((action) => { - if (action !== 'yes') return; - $(ev.currentTarget).closest('form').trigger('submit'); - }); - }); + $(document).on('click', '[name="show_tags"]', (ev) => { $(ev.currentTarget).hide(); $('span.tags').css('display', 'inline-block'); diff --git a/packages/ui-default/pages/problem_edit.page.js b/packages/ui-default/pages/problem_edit.page.js index 881a3c2b6..b5aa29c3f 100644 --- a/packages/ui-default/pages/problem_edit.page.js +++ b/packages/ui-default/pages/problem_edit.page.js @@ -144,10 +144,6 @@ function buildCategoryFilter() { } export default new NamedPage(['problem_create', 'problem_edit'], (pagename) => { - $(document).on('click', '[name="problem-sidebar__show-category"]', (ev) => { - $(ev.currentTarget).hide(); - $('[name="problem-sidebar__categories"]').show(); - }); let confirmed = false; $(document).on('click', '[name="operation"]', (ev) => { ev.preventDefault(); @@ -178,7 +174,7 @@ export default new NamedPage(['problem_create', 'problem_edit'], (pagename) => { $('img').each(function () { if (this.src.startsWith('file://')) this.setAttribute('src', this.src.replace('file://', './file/')); }); - }, 50); + }, 200); const $main = $('textarea[data-editor]'); const $field = $('textarea[data-markdown-upload]'); diff --git a/packages/ui-default/pages/problem_files.page.js b/packages/ui-default/pages/problem_files.page.js index 12d393168..2a599753e 100644 --- a/packages/ui-default/pages/problem_files.page.js +++ b/packages/ui-default/pages/problem_files.page.js @@ -235,16 +235,6 @@ const page = new NamedPage('problem_files', () => { await pjax.request({ push: false }); } - $(document).on('click', '[name="problem-sidebar__rejudge"]', (ev) => { - ev.preventDefault(); - new ConfirmDialog({ - $body: tpl.typoMsg(i18n('Confirm rejudge this problem?')), - }).open().then((action) => { - if (action !== 'yes') return; - $(ev.currentTarget).closest('form').trigger('submit'); - }); - }); - if ($('[name="upload_testdata"]').length) { $(document).on('click', '.problem-files-testdata .col--name', (ev) => handleEdit('testdata', ev)); $(document).on('click', '.problem-files-additional_file .col--name', (ev) => handleEdit('additional_file', ev)); diff --git a/packages/ui-default/pages/problem_sidebar.page.ts b/packages/ui-default/pages/problem_sidebar.page.ts new file mode 100644 index 000000000..0fc3cf3cd --- /dev/null +++ b/packages/ui-default/pages/problem_sidebar.page.ts @@ -0,0 +1,25 @@ +import { NamedPage } from 'vj/misc/Page'; +import tpl from 'vj/utils/tpl'; +import i18n from 'vj/utils/i18n'; +import { ConfirmDialog } from 'vj/components/dialog'; + +const page = new NamedPage([ + 'problem_create', 'problem_edit', 'problem_solution', 'problem_submit', + 'problem_files', 'discussion_node', 'discussion_detail', +], () => { + $(document).on('click', '[name="problem-sidebar__show-category"]', (ev) => { + $(ev.currentTarget).hide(); + $('[name="problem-sidebar__categories"]').show(); + }); + $(document).on('click', '[name="problem-sidebar__rejudge"]', (ev) => { + ev.preventDefault(); + new ConfirmDialog({ + $body: tpl.typoMsg(i18n('Confirm rejudge this problem?')), + }).open().then((action) => { + if (action !== 'yes') return; + $(ev.currentTarget).closest('form').trigger('submit'); + }); + }); +}); + +export default page; diff --git a/packages/ui-default/pages/problem_solution.page.js b/packages/ui-default/pages/problem_solution.page.js deleted file mode 100644 index f18b551b6..000000000 --- a/packages/ui-default/pages/problem_solution.page.js +++ /dev/null @@ -1,10 +0,0 @@ -import { NamedPage } from 'vj/misc/Page'; - -const page = new NamedPage('problem_solution', async () => { - $(document).on('click', '[name="problem-sidebar__show-category"]', (ev) => { - $(ev.currentTarget).hide(); - $('[name="problem-sidebar__categories"]').show(); - }); -}); - -export default page; diff --git a/packages/ui-default/pages/problem_submit.page.js b/packages/ui-default/pages/problem_submit.page.js index a119a3e2c..076338445 100644 --- a/packages/ui-default/pages/problem_submit.page.js +++ b/packages/ui-default/pages/problem_submit.page.js @@ -8,11 +8,6 @@ function setOptions($el, options) { } const page = new NamedPage(['problem_submit', 'contest_detail_problem_submit', 'homework_detail_problem_submit'], async () => { - $(document).on('click', '[name="problem-sidebar__show-category"]', (ev) => { - $(ev.currentTarget).hide(); - $('[name="problem-sidebar__categories"]').show(); - }); - const { domainId } = UiContext.pdocConfig; function onChangeMain(update = true) { diff --git a/packages/ui-default/pages/record_detail.page.js b/packages/ui-default/pages/record_detail.page.ts similarity index 81% rename from packages/ui-default/pages/record_detail.page.js rename to packages/ui-default/pages/record_detail.page.ts index 8293f801f..f04af9787 100644 --- a/packages/ui-default/pages/record_detail.page.js +++ b/packages/ui-default/pages/record_detail.page.ts @@ -1,8 +1,10 @@ import { NamedPage } from 'vj/misc/Page'; const page = new NamedPage('record_detail', async () => { - const { default: SockJs } = await import('../components/socket'); - const { DiffDOM } = await import('diff-dom'); + const [{ default: SockJs }, { DiffDOM }] = await Promise.all([ + import('../components/socket'), + import('diff-dom'), + ]); const sock = new SockJs(UiContext.socketUrl); const dd = new DiffDOM(); diff --git a/packages/ui-default/pages/record_main.page.js b/packages/ui-default/pages/record_main.page.ts similarity index 82% rename from packages/ui-default/pages/record_main.page.js rename to packages/ui-default/pages/record_main.page.ts index 0c5c3e7c6..023ddc6c0 100644 --- a/packages/ui-default/pages/record_main.page.js +++ b/packages/ui-default/pages/record_main.page.ts @@ -3,14 +3,18 @@ import UserSelectAutoComplete from 'vj/components/autocomplete/UserSelectAutoCom import ProblemSelectAutoComplete from 'vj/components/autocomplete/ProblemSelectAutoComplete'; const page = new NamedPage('record_main', async () => { - const { default: SockJs } = await import('../components/socket'); - const { DiffDOM } = await import('diff-dom'); + const [{ default: SockJs }, { DiffDOM }] = await Promise.all([ + import('../components/socket'), + import('diff-dom'), + ]); const sock = new SockJs(UiContext.socketUrl); const dd = new DiffDOM(); + let firstLoad = true; sock.onopen = () => { - sock.send(JSON.stringify({ rids: UiContext.rids })); + if (firstLoad) sock.send(JSON.stringify({ rids: UiContext.rids })); + firstLoad = false; }; sock.onmessage = (message) => { const msg = JSON.parse(message.data); diff --git a/packages/ui-default/pages/training_detail.page.js b/packages/ui-default/pages/training_detail.page.js deleted file mode 100644 index b84dfad8f..000000000 --- a/packages/ui-default/pages/training_detail.page.js +++ /dev/null @@ -1,35 +0,0 @@ -import { NamedPage } from 'vj/misc/Page'; -import { slideDown, slideUp } from 'vj/utils/slide'; - -async function handleSectionExpand(ev) { - const $section = $(ev.currentTarget).closest('.training__section'); - if ($section.is('.expanded, .animating')) { - return; - } - $section.addClass('animating'); - const $detail = $section.find('.training__section__detail'); - await slideDown($detail, 300, { opacity: 0 }, { opacity: 1 }); - $section.addClass('expanded'); - $section.removeClass('collapsed'); - $section.removeClass('animating'); -} - -async function handleSectionCollapse(ev) { - const $section = $(ev.currentTarget).closest('.training__section'); - if ($section.is('.collapsed, .animating')) { - return; - } - $section.addClass('animating'); - const $detail = $section.find('.training__section__detail'); - await slideUp($detail, 300, { opacity: 1 }, { opacity: 0 }); - $section.addClass('collapsed'); - $section.removeClass('expanded'); - $section.removeClass('animating'); -} - -const page = new NamedPage('training_detail', async () => { - $(document).on('click', '[name="training__section__expand"]', handleSectionExpand); - $(document).on('click', '[name="training__section__collapse"]', handleSectionCollapse); -}); - -export default page; diff --git a/packages/ui-default/pages/training_detail.page.ts b/packages/ui-default/pages/training_detail.page.ts new file mode 100644 index 000000000..febc17ca2 --- /dev/null +++ b/packages/ui-default/pages/training_detail.page.ts @@ -0,0 +1,24 @@ +import { NamedPage } from 'vj/misc/Page'; +import { slideDown, slideUp } from 'vj/utils/slide'; + +async function handleSection(ev, type: string) { + const $section = $(ev.currentTarget).closest('.training__section'); + if ($section.is(`.${type}d, .animating`)) return; + $section.addClass('animating'); + const $detail = $section.find('.training__section__detail'); + if (type === 'expand') { + await slideDown($detail, 300, { opacity: 0 }, { opacity: 1 }); + } else { + await slideUp($detail, 300, { opacity: 1 }, { opacity: 0 }); + } + $section.addClass(`${type}d`); + $section.removeClass(type === 'expand' ? 'collapsed' : 'expanded'); + $section.removeClass('animating'); +} + +const page = new NamedPage('training_detail', () => { + $(document).on('click', '[name="training__section__expand"]', (ev) => handleSection(ev, 'expand')); + $(document).on('click', '[name="training__section__collapse"]', (ev) => handleSection(ev, 'collapse')); +}); + +export default page; diff --git a/packages/ui-default/pages/training_edit.page.js b/packages/ui-default/pages/training_edit.page.ts similarity index 88% rename from packages/ui-default/pages/training_edit.page.js rename to packages/ui-default/pages/training_edit.page.ts index 883ca4662..6c8ed5c33 100644 --- a/packages/ui-default/pages/training_edit.page.js +++ b/packages/ui-default/pages/training_edit.page.ts @@ -15,10 +15,7 @@ export default new NamedPage('training_edit', () => { } const message = 'Confirm deleting this training? Its status will be deleted as well.'; return new ConfirmDialog({ - $body: tpl` -
-

${i18n(message)}

-
`, + $body: tpl.typoMsg(i18n(message)), }).open().then((action) => { if (action !== 'yes') return; confirmed = true; diff --git a/packages/ui-default/templates/contest_main.html b/packages/ui-default/templates/contest_main.html index 2dd5a2e60..87eaa82e2 100644 --- a/packages/ui-default/templates/contest_main.html +++ b/packages/ui-default/templates/contest_main.html @@ -33,11 +33,11 @@
{{ _('View Details') }}
- {% if tsdict[tdoc.docId].attend %} -

{{ _('Attended') }}

- {% else %} -

{{ _('Not Attended') }}

- {% endif %} + {% if tsdict[tdoc.docId].attend %} +

{{ _('Attended') }}

+ {% else %} +

{{ _('Not Attended') }}

+ {% endif %}
@@ -48,23 +48,25 @@
{%- for tdoc in tdocs -%} - {% if model.contest.isOngoing(tdoc) %} - {{ render_important_contest('live', 'Live...', tdoc) }} - {% elif model.contest.isUpcoming(tdoc) %} - {{ render_important_contest('ready', 'Ready (☆▽☆)', tdoc) }} - {% endif %} + {% if model.contest.isOngoing(tdoc) %} + {{ render_important_contest('live', 'Live...', tdoc) }} + {% elif model.contest.isUpcoming(tdoc) %} + {{ render_important_contest('ready', 'Ready (☆▽☆)', tdoc) }} + {% endif %} {%- endfor -%}
-

{% if not rule %}{{ _('All Contests') }}{% else %}{{ _('All {0} Contests').format(_(model.contest.RULES[rule].TEXT)) }}{% endif %}

+

{{ _('All Contests') if not rule else _('All {0} Contests').format(model.contest.RULES[rule].TEXT) }}

{{ _('Show') }}: