mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
ui: change to ts & tsx
This commit is contained in:
1 parent
36cce6d1bd
commit
d10fec361c
29 files changed
+165
-221
No files matched your search
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hydrooj",
|
"name": "hydrooj",
|
||||||
"version": "2.39.18",
|
"version": "2.39.19",
|
||||||
"bin": "bin/hydrooj.js",
|
"bin": "bin/hydrooj.js",
|
||||||
"main": "src/loader",
|
"main": "src/loader",
|
||||||
"module": "src/loader",
|
"module": "src/loader",
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export const ForbiddenError = Err('ForbiddenError', UserFacingError, 'ForbiddenE
|
|||||||
export const NotFoundError = Err('NotFoundError', UserFacingError, 'NotFoundError', 404);
|
export const NotFoundError = Err('NotFoundError', UserFacingError, 'NotFoundError', 404);
|
||||||
export const MethodNotAllowedError = Err('MethodNotAllowedError', UserFacingError, 'MethodNotAllowedError', 405);
|
export const MethodNotAllowedError = Err('MethodNotAllowedError', UserFacingError, 'MethodNotAllowedError', 405);
|
||||||
export const RemoteOnlineJudgeError = Err('RemoteOnlineJudgeError', UserFacingError, 'RemoteOnlineJudgeError', 500);
|
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 AlreadyVotedError = Err('AlreadyVotedError', ForbiddenError, "You've already voted.");
|
||||||
export const LoginError = Err('LoginError', ForbiddenError, 'Invalid password for user {0}.');
|
export const LoginError = Err('LoginError', ForbiddenError, 'Invalid password for user {0}.');
|
||||||
|
|||||||
@@ -49,11 +49,6 @@ function set(key: string, value: any) {
|
|||||||
class SystemHandler extends Handler {
|
class SystemHandler extends Handler {
|
||||||
async prepare() {
|
async prepare() {
|
||||||
this.checkPriv(PRIV.PRIV_EDIT_SYSTEM);
|
this.checkPriv(PRIV.PRIV_EDIT_SYSTEM);
|
||||||
this.response.body = {
|
|
||||||
path: [
|
|
||||||
['Hydro', 'homepage'],
|
|
||||||
],
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,12 +81,6 @@ class SystemCheckConnHandler extends ConnectionHandler {
|
|||||||
class SystemDashboardHandler extends SystemHandler {
|
class SystemDashboardHandler extends SystemHandler {
|
||||||
async get() {
|
async get() {
|
||||||
this.response.template = 'manage_dashboard.html';
|
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() {
|
async get() {
|
||||||
this.response.template = 'manage_script.html';
|
this.response.template = 'manage_script.html';
|
||||||
this.response.body.scripts = global.Hydro.script;
|
this.response.body.scripts = global.Hydro.script;
|
||||||
this.response.body.path.push(['manage_script', null]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@param('id', Types.Name)
|
@param('id', Types.Name)
|
||||||
@@ -147,7 +135,6 @@ class SystemScriptHandler extends SystemHandler {
|
|||||||
class SystemSettingHandler extends SystemHandler {
|
class SystemSettingHandler extends SystemHandler {
|
||||||
async get() {
|
async get() {
|
||||||
this.response.template = 'manage_setting.html';
|
this.response.template = 'manage_setting.html';
|
||||||
this.response.body.path.push(['manage_setting', null]);
|
|
||||||
this.response.body.current = {};
|
this.response.body.current = {};
|
||||||
this.response.body.settings = setting.SYSTEM_SETTINGS;
|
this.response.body.settings = setting.SYSTEM_SETTINGS;
|
||||||
for (const s of this.response.body.settings) {
|
for (const s of this.response.body.settings) {
|
||||||
@@ -185,7 +172,6 @@ class SystemSettingHandler extends SystemHandler {
|
|||||||
class SystemUserImportHandler extends SystemHandler {
|
class SystemUserImportHandler extends SystemHandler {
|
||||||
async get() {
|
async get() {
|
||||||
this.response.body.users = [];
|
this.response.body.users = [];
|
||||||
this.response.body.path.push(['manage_user_import']);
|
|
||||||
this.response.template = 'manage_user_import.html';
|
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.users = udocs;
|
||||||
this.response.body.messages = messages;
|
this.response.body.messages = messages;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,35 +13,6 @@ import {
|
|||||||
} from '../service/server';
|
} from '../service/server';
|
||||||
import { sortFiles } from '../utils';
|
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 {
|
class SwitchLanguageHandler extends Handler {
|
||||||
@param('lang', Types.Name)
|
@param('lang', Types.Name)
|
||||||
async get(domainId: string, lang: string) {
|
async get(domainId: string, lang: string) {
|
||||||
@@ -132,7 +103,6 @@ export class FSDownloadHandler extends Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function apply() {
|
export async function apply() {
|
||||||
Route('check_in', '/checkin', CheckInHandler, PRIV.PRIV_USER_PROFILE);
|
|
||||||
Route('switch_language', '/language/:lang', SwitchLanguageHandler);
|
Route('switch_language', '/language/:lang', SwitchLanguageHandler);
|
||||||
Route('home_files', '/file', FilesHandler, PRIV.PRIV_CREATE_FILE);
|
Route('home_files', '/file', FilesHandler, PRIV.PRIV_CREATE_FILE);
|
||||||
Route('fs_download', '/file/:uid/:filename', FSDownloadHandler);
|
Route('fs_download', '/file/:uid/:filename', FSDownloadHandler);
|
||||||
|
|||||||
@@ -677,6 +677,8 @@ declare global {
|
|||||||
addons: string[],
|
addons: string[],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var Hydro: HydroGlobal; // eslint-disable-line
|
||||||
|
var addons: string[]; // eslint-disable-line
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module 'koa' {
|
declare module 'koa' {
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ export async function sendMail(to: string, subject: string, text: string, html:
|
|||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(e);
|
logger.error(e);
|
||||||
throw new SendMailError(to);
|
throw new SendMailError(to, e.message);
|
||||||
}
|
}
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,8 +131,6 @@ AccountSetting(
|
|||||||
'/components/profile/backgrounds/1.jpg', 'text', 'Profile Background Image',
|
'/components/profile/backgrounds/1.jpg', 'text', 'Profile Background Image',
|
||||||
'Choose the background image in your profile page.'),
|
'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', '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),
|
Setting('setting_storage', 'badge', '', 'text', 'badge info', null, FLAG_DISABLED | FLAG_HIDDEN),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,16 @@ module.exports = {
|
|||||||
'no-unused-vars': 'off',
|
'no-unused-vars': 'off',
|
||||||
'@typescript-eslint/no-unused-vars': 'warn',
|
'@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': [
|
'comma-dangle': [
|
||||||
'error',
|
'error',
|
||||||
'always-multiline',
|
'always-multiline',
|
||||||
@@ -69,9 +79,7 @@ module.exports = {
|
|||||||
indent: [
|
indent: [
|
||||||
'error',
|
'error',
|
||||||
2,
|
2,
|
||||||
{
|
{ SwitchCase: 0 },
|
||||||
SwitchCase: 0,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
'max-len': ['error', 150],
|
'max-len': ['error', 150],
|
||||||
quotes: 'warn',
|
quotes: 'warn',
|
||||||
|
|||||||
+36
-32
@@ -2,20 +2,33 @@ import _ from 'lodash';
|
|||||||
import DOMAttachedObject from 'vj/components/DOMAttachedObject';
|
import DOMAttachedObject from 'vj/components/DOMAttachedObject';
|
||||||
import zIndexManager from 'vj/utils/zIndexManager';
|
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 {
|
export default class DomDialog extends DOMAttachedObject {
|
||||||
static DOMAttachKey = 'vjDomDialogInstance';
|
static DOMAttachKey = 'vjDomDialogInstance';
|
||||||
|
isShown = false;
|
||||||
|
isAnimating = false;
|
||||||
|
options: DialogOptions;
|
||||||
|
_resolve: (value: string | PromiseLike<string>) => void;
|
||||||
|
|
||||||
constructor($dom, options = {}) {
|
constructor($dom, options: Partial<DialogOptions> = {}) {
|
||||||
super($dom);
|
super($dom);
|
||||||
this.isShown = false;
|
|
||||||
this.isAnimating = false;
|
|
||||||
this.options = {
|
this.options = {
|
||||||
cancelByClickingBack: false,
|
cancelByClickingBack: false,
|
||||||
cancelByEsc: false,
|
cancelByEsc: false,
|
||||||
onDispatch: () => { },
|
onDispatch: () => { },
|
||||||
...options,
|
...options as any,
|
||||||
};
|
};
|
||||||
this._defer = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async _show() {
|
async _show() {
|
||||||
@@ -70,9 +83,7 @@ export default class DomDialog extends DOMAttachedObject {
|
|||||||
$(document).off(`keyup.${this.eventNS}`);
|
$(document).off(`keyup.${this.eventNS}`);
|
||||||
this.$dom.off(`click.${this.eventNS}`);
|
this.$dom.off(`click.${this.eventNS}`);
|
||||||
|
|
||||||
this.$dom.css({
|
this.$dom.css({ opacity: 1 });
|
||||||
opacity: 1,
|
|
||||||
});
|
|
||||||
this.$dom.transition({
|
this.$dom.transition({
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
}, {
|
}, {
|
||||||
@@ -80,17 +91,15 @@ export default class DomDialog extends DOMAttachedObject {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const $dgContent = this.$dom.find('.dialog__content');
|
const $dgContent = this.$dom.find('.dialog__content');
|
||||||
$dgContent.css({
|
$dgContent.css({ scale: 1 });
|
||||||
scale: 1,
|
|
||||||
});
|
|
||||||
await $dgContent
|
await $dgContent
|
||||||
.transition({
|
.transition(
|
||||||
scale: 0.8,
|
{ scale: 0.8 },
|
||||||
}, {
|
{
|
||||||
duration: 200,
|
duration: 200,
|
||||||
easing: 'easeOutCubic',
|
easing: 'easeOutCubic',
|
||||||
})
|
},
|
||||||
.promise();
|
).promise();
|
||||||
|
|
||||||
this.$dom.css('display', 'none');
|
this.$dom.css('display', 'none');
|
||||||
|
|
||||||
@@ -103,28 +112,23 @@ export default class DomDialog extends DOMAttachedObject {
|
|||||||
if (this.isShown || this.isAnimating) {
|
if (this.isShown || this.isAnimating) {
|
||||||
return Promise.reject();
|
return Promise.reject();
|
||||||
}
|
}
|
||||||
this._defer = new $.Deferred();
|
const promise = new Promise<string>((resolve) => {
|
||||||
|
this._resolve = resolve;
|
||||||
|
});
|
||||||
this._show();
|
this._show();
|
||||||
return this._defer.promise();
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
hide() {
|
hide() {
|
||||||
if (!this.isShown || this.isAnimating) {
|
if (!this.isShown || this.isAnimating) return false;
|
||||||
return false;
|
this._resolve('cancel');
|
||||||
}
|
|
||||||
if (this._defer.state() === 'pending') {
|
|
||||||
this._defer.resolve('cancel');
|
|
||||||
}
|
|
||||||
this._defer = null;
|
|
||||||
this._hide();
|
this._hide();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatchAction(data) {
|
dispatchAction(data: string) {
|
||||||
if (this.options.onDispatch(data) === false) {
|
if (this.options.onDispatch(data) === false) return;
|
||||||
return;
|
this._resolve(data);
|
||||||
}
|
|
||||||
this._defer.resolve(data);
|
|
||||||
this.hide();
|
this.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
+9
-5
@@ -1,9 +1,13 @@
|
|||||||
import tpl from 'vj/utils/tpl';
|
import tpl from 'vj/utils/tpl';
|
||||||
import i18n from 'vj/utils/i18n';
|
import i18n from 'vj/utils/i18n';
|
||||||
import DomDialog from './DomDialog';
|
import DomDialog, { DialogOptions } from './DomDialog';
|
||||||
|
|
||||||
export class Dialog {
|
export class Dialog {
|
||||||
constructor(options = {}) {
|
options: DialogOptions;
|
||||||
|
$dom: JQuery<any>;
|
||||||
|
domDialogInstance: DomDialog;
|
||||||
|
|
||||||
|
constructor(options: Partial<DialogOptions> = {}) {
|
||||||
this.options = {
|
this.options = {
|
||||||
classes: '',
|
classes: '',
|
||||||
$body: null,
|
$body: null,
|
||||||
@@ -60,7 +64,7 @@ const buttonYes = tpl`<button class="primary rounded button" data-action="yes">$
|
|||||||
const buttonNo = tpl`<button class="rounded button" data-action="no">${i18n('No')}</button>`;
|
const buttonNo = tpl`<button class="rounded button" data-action="no">${i18n('No')}</button>`;
|
||||||
|
|
||||||
export class InfoDialog extends Dialog {
|
export class InfoDialog extends Dialog {
|
||||||
constructor(options = {}) {
|
constructor(options: Partial<DialogOptions> = {}) {
|
||||||
super({
|
super({
|
||||||
$action: buttonOk,
|
$action: buttonOk,
|
||||||
cancelByClickingBack: true,
|
cancelByClickingBack: true,
|
||||||
@@ -71,7 +75,7 @@ export class InfoDialog extends Dialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ActionDialog extends Dialog {
|
export class ActionDialog extends Dialog {
|
||||||
constructor(options = {}) {
|
constructor(options: Partial<DialogOptions> = {}) {
|
||||||
super({
|
super({
|
||||||
$action: [buttonCancel, buttonOk].join('\n'),
|
$action: [buttonCancel, buttonOk].join('\n'),
|
||||||
cancelByClickingBack: true,
|
cancelByClickingBack: true,
|
||||||
@@ -82,7 +86,7 @@ export class ActionDialog extends Dialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ConfirmDialog extends Dialog {
|
export class ConfirmDialog extends Dialog {
|
||||||
constructor(options = {}) {
|
constructor(options: Partial<DialogOptions> = {}) {
|
||||||
let buttons = [];
|
let buttons = [];
|
||||||
if (options.canCancel) {
|
if (options.canCancel) {
|
||||||
buttons = [buttonCancel, buttonNo, buttonYes];
|
buttons = [buttonCancel, buttonNo, buttonYes];
|
||||||
@@ -5,6 +5,7 @@ import pipeStream from 'vj/utils/pipeStream';
|
|||||||
import i18n from 'vj/utils/i18n';
|
import i18n from 'vj/utils/i18n';
|
||||||
import request from 'vj/utils/request';
|
import request from 'vj/utils/request';
|
||||||
import Notification from 'vj/components/notification';
|
import Notification from 'vj/components/notification';
|
||||||
|
import api from 'vj/utils/api';
|
||||||
|
|
||||||
let isBeforeUnloadTriggeredByLibrary = !window.isSecureContext;
|
let isBeforeUnloadTriggeredByLibrary = !window.isSecureContext;
|
||||||
function onBeforeUnload(e) {
|
function onBeforeUnload(e) {
|
||||||
@@ -67,7 +68,24 @@ export async function downloadProblemSet(pids, name = 'Export') {
|
|||||||
const targets = [];
|
const targets = [];
|
||||||
try {
|
try {
|
||||||
for (const pid of pids) {
|
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({
|
targets.push({
|
||||||
filename: `${pid}/problem.yaml`,
|
filename: `${pid}/problem.yaml`,
|
||||||
content: dump({
|
content: dump({
|
||||||
@@ -77,7 +95,6 @@ export async function downloadProblemSet(pids, name = 'Export') {
|
|||||||
tag: pdoc.tag,
|
tag: pdoc.tag,
|
||||||
nSubmit: pdoc.nSubmit,
|
nSubmit: pdoc.nSubmit,
|
||||||
nAccept: pdoc.nAccept,
|
nAccept: pdoc.nAccept,
|
||||||
difficulty: pdoc.difficulty,
|
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
targets.push({
|
targets.push({
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@hydrooj/ui-default",
|
"name": "@hydrooj/ui-default",
|
||||||
"version": "4.24.5",
|
"version": "4.25.0",
|
||||||
"author": "undefined <i@undefined.moe>",
|
"author": "undefined <i@undefined.moe>",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"main": "hydro.js",
|
"main": "hydro.js",
|
||||||
|
|||||||
+2
-3
@@ -1,9 +1,8 @@
|
|||||||
import { NamedPage } from 'vj/misc/Page';
|
import { NamedPage } from 'vj/misc/Page';
|
||||||
|
|
||||||
const page = new NamedPage('contest_main', () => {
|
const page = new NamedPage('contest_main', () => {
|
||||||
// Contest Filter
|
$('[name="filter-form"] [name="rule"]').on('change', () => {
|
||||||
$('[name="filter-form"] [name="rule"]').change(() => {
|
$('[name="filter-form"]').trigger('submit');
|
||||||
$('[name="filter-form"]').submit();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -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;
|
|
||||||
@@ -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;
|
|
||||||
+2
-2
@@ -6,13 +6,13 @@ const page = new NamedPage('domain_join_applications', () => {
|
|||||||
const $expire = $('[name="expire"]');
|
const $expire = $('[name="expire"]');
|
||||||
const $code = $('[name="invitationCode"]');
|
const $code = $('[name="invitationCode"]');
|
||||||
function updateFormState() {
|
function updateFormState() {
|
||||||
const method = parseInt($('[name="method"]').val(), 10);
|
const method = +$('[name="method"]').val();
|
||||||
$role.prop('disabled', method === domainEnum.JOIN_METHOD_NONE).trigger('vjFormDisableUpdate');
|
$role.prop('disabled', method === domainEnum.JOIN_METHOD_NONE).trigger('vjFormDisableUpdate');
|
||||||
$expire.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');
|
$code.prop('disabled', method !== domainEnum.JOIN_METHOD_CODE).trigger('vjFormDisableUpdate');
|
||||||
}
|
}
|
||||||
updateFormState();
|
updateFormState();
|
||||||
$('[name="method"]').change(() => updateFormState());
|
$('[name="method"]').on('change', updateFormState);
|
||||||
});
|
});
|
||||||
|
|
||||||
export default page;
|
export default page;
|
||||||
@@ -40,9 +40,7 @@ const page = new NamedPage('domain_role', () => {
|
|||||||
|
|
||||||
async function handleClickCreateRole() {
|
async function handleClickCreateRole() {
|
||||||
const action = await createRoleDialog.clear().open();
|
const action = await createRoleDialog.clear().open();
|
||||||
if (action !== 'ok') {
|
if (action !== 'ok') return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
const role = createRoleDialog.$dom.find('[name="role"]').val();
|
const role = createRoleDialog.$dom.find('[name="role"]').val();
|
||||||
try {
|
try {
|
||||||
await request.post('', {
|
await request.post('', {
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
import yaml from 'js-yaml';
|
import yaml from 'js-yaml';
|
||||||
import { getScoreColor } from '@hydrooj/utils/lib/status';
|
import { getScoreColor } from '@hydrooj/utils/lib/status';
|
||||||
import { NamedPage } from 'vj/misc/Page';
|
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 { downloadProblemSet } from 'vj/components/zipDownloader';
|
||||||
import loadReactRedux from 'vj/utils/loadReactRedux';
|
import loadReactRedux from 'vj/utils/loadReactRedux';
|
||||||
import delay from 'vj/utils/delay';
|
import delay from 'vj/utils/delay';
|
||||||
@@ -263,15 +260,7 @@ const page = new NamedPage(['problem_detail', 'contest_detail_problem', 'homewor
|
|||||||
leaveScratchpadMode();
|
leaveScratchpadMode();
|
||||||
ev.preventDefault();
|
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) => {
|
$(document).on('click', '[name="show_tags"]', (ev) => {
|
||||||
$(ev.currentTarget).hide();
|
$(ev.currentTarget).hide();
|
||||||
$('span.tags').css('display', 'inline-block');
|
$('span.tags').css('display', 'inline-block');
|
||||||
|
|||||||
@@ -144,10 +144,6 @@ function buildCategoryFilter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default new NamedPage(['problem_create', 'problem_edit'], (pagename) => {
|
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;
|
let confirmed = false;
|
||||||
$(document).on('click', '[name="operation"]', (ev) => {
|
$(document).on('click', '[name="operation"]', (ev) => {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
@@ -178,7 +174,7 @@ export default new NamedPage(['problem_create', 'problem_edit'], (pagename) => {
|
|||||||
$('img').each(function () {
|
$('img').each(function () {
|
||||||
if (this.src.startsWith('file://')) this.setAttribute('src', this.src.replace('file://', './file/'));
|
if (this.src.startsWith('file://')) this.setAttribute('src', this.src.replace('file://', './file/'));
|
||||||
});
|
});
|
||||||
}, 50);
|
}, 200);
|
||||||
|
|
||||||
const $main = $('textarea[data-editor]');
|
const $main = $('textarea[data-editor]');
|
||||||
const $field = $('textarea[data-markdown-upload]');
|
const $field = $('textarea[data-markdown-upload]');
|
||||||
|
|||||||
@@ -235,16 +235,6 @@ const page = new NamedPage('problem_files', () => {
|
|||||||
await pjax.request({ push: false });
|
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) {
|
if ($('[name="upload_testdata"]').length) {
|
||||||
$(document).on('click', '.problem-files-testdata .col--name', (ev) => handleEdit('testdata', ev));
|
$(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));
|
$(document).on('click', '.problem-files-additional_file .col--name', (ev) => handleEdit('additional_file', ev));
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -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;
|
|
||||||
@@ -8,11 +8,6 @@ function setOptions($el, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const page = new NamedPage(['problem_submit', 'contest_detail_problem_submit', 'homework_detail_problem_submit'], async () => {
|
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;
|
const { domainId } = UiContext.pdocConfig;
|
||||||
|
|
||||||
function onChangeMain(update = true) {
|
function onChangeMain(update = true) {
|
||||||
|
|||||||
+4
-2
@@ -1,8 +1,10 @@
|
|||||||
import { NamedPage } from 'vj/misc/Page';
|
import { NamedPage } from 'vj/misc/Page';
|
||||||
|
|
||||||
const page = new NamedPage('record_detail', async () => {
|
const page = new NamedPage('record_detail', async () => {
|
||||||
const { default: SockJs } = await import('../components/socket');
|
const [{ default: SockJs }, { DiffDOM }] = await Promise.all([
|
||||||
const { DiffDOM } = await import('diff-dom');
|
import('../components/socket'),
|
||||||
|
import('diff-dom'),
|
||||||
|
]);
|
||||||
|
|
||||||
const sock = new SockJs(UiContext.socketUrl);
|
const sock = new SockJs(UiContext.socketUrl);
|
||||||
const dd = new DiffDOM();
|
const dd = new DiffDOM();
|
||||||
+7
-3
@@ -3,14 +3,18 @@ import UserSelectAutoComplete from 'vj/components/autocomplete/UserSelectAutoCom
|
|||||||
import ProblemSelectAutoComplete from 'vj/components/autocomplete/ProblemSelectAutoComplete';
|
import ProblemSelectAutoComplete from 'vj/components/autocomplete/ProblemSelectAutoComplete';
|
||||||
|
|
||||||
const page = new NamedPage('record_main', async () => {
|
const page = new NamedPage('record_main', async () => {
|
||||||
const { default: SockJs } = await import('../components/socket');
|
const [{ default: SockJs }, { DiffDOM }] = await Promise.all([
|
||||||
const { DiffDOM } = await import('diff-dom');
|
import('../components/socket'),
|
||||||
|
import('diff-dom'),
|
||||||
|
]);
|
||||||
|
|
||||||
const sock = new SockJs(UiContext.socketUrl);
|
const sock = new SockJs(UiContext.socketUrl);
|
||||||
const dd = new DiffDOM();
|
const dd = new DiffDOM();
|
||||||
|
|
||||||
|
let firstLoad = true;
|
||||||
sock.onopen = () => {
|
sock.onopen = () => {
|
||||||
sock.send(JSON.stringify({ rids: UiContext.rids }));
|
if (firstLoad) sock.send(JSON.stringify({ rids: UiContext.rids }));
|
||||||
|
firstLoad = false;
|
||||||
};
|
};
|
||||||
sock.onmessage = (message) => {
|
sock.onmessage = (message) => {
|
||||||
const msg = JSON.parse(message.data);
|
const msg = JSON.parse(message.data);
|
||||||
@@ -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;
|
|
||||||
@@ -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;
|
||||||
+1
-4
@@ -15,10 +15,7 @@ export default new NamedPage('training_edit', () => {
|
|||||||
}
|
}
|
||||||
const message = 'Confirm deleting this training? Its status will be deleted as well.';
|
const message = 'Confirm deleting this training? Its status will be deleted as well.';
|
||||||
return new ConfirmDialog({
|
return new ConfirmDialog({
|
||||||
$body: tpl`
|
$body: tpl.typoMsg(i18n(message)),
|
||||||
<div class="typo">
|
|
||||||
<p>${i18n(message)}</p>
|
|
||||||
</div>`,
|
|
||||||
}).open().then((action) => {
|
}).open().then((action) => {
|
||||||
if (action !== 'yes') return;
|
if (action !== 'yes') return;
|
||||||
confirmed = true;
|
confirmed = true;
|
||||||
@@ -33,11 +33,11 @@
|
|||||||
<div class="section__body">
|
<div class="section__body">
|
||||||
<a href="{{ url('contest_detail', tid=tdoc.docId) }}" class="detail-button">{{ _('View Details') }}</a>
|
<a href="{{ url('contest_detail', tid=tdoc.docId) }}" class="detail-button">{{ _('View Details') }}</a>
|
||||||
<div class="typo text-center">
|
<div class="typo text-center">
|
||||||
{% if tsdict[tdoc.docId].attend %}
|
{% if tsdict[tdoc.docId].attend %}
|
||||||
<p><span class="icon icon-check"></span> {{ _('Attended') }}</p>
|
<p><span class="icon icon-check"></span> {{ _('Attended') }}</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p><span class="icon icon-schedule"></span> {{ _('Not Attended') }}</p>
|
<p><span class="icon icon-schedule"></span> {{ _('Not Attended') }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -48,23 +48,25 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="medium-9 columns">
|
<div class="medium-9 columns">
|
||||||
{%- for tdoc in tdocs -%}
|
{%- for tdoc in tdocs -%}
|
||||||
{% if model.contest.isOngoing(tdoc) %}
|
{% if model.contest.isOngoing(tdoc) %}
|
||||||
{{ render_important_contest('live', 'Live...', tdoc) }}
|
{{ render_important_contest('live', 'Live...', tdoc) }}
|
||||||
{% elif model.contest.isUpcoming(tdoc) %}
|
{% elif model.contest.isUpcoming(tdoc) %}
|
||||||
{{ render_important_contest('ready', 'Ready (☆▽☆)', tdoc) }}
|
{{ render_important_contest('ready', 'Ready (☆▽☆)', tdoc) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{%- endfor -%}
|
{%- endfor -%}
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<div class="section__header">
|
<div class="section__header">
|
||||||
<h1 class="section__title">{% if not rule %}{{ _('All Contests') }}{% else %}{{ _('All {0} Contests').format(_(model.contest.RULES[rule].TEXT)) }}{% endif %}</h1>
|
<h1 class="section__title">{{ _('All Contests') if not rule else _('All {0} Contests').format(model.contest.RULES[rule].TEXT) }}</h1>
|
||||||
<div class="section__tools">
|
<div class="section__tools">
|
||||||
<form method="get" name="filter-form">
|
<form method="get" name="filter-form">
|
||||||
{{ _('Show') }}:
|
{{ _('Show') }}:
|
||||||
<select class="inline compact select" name="rule">
|
<select class="inline compact select" name="rule">
|
||||||
<option value="0"{% if not rule %} selected{% endif %}>{{ _('All') }}</option>
|
<option value="0"{% if not rule %} selected{% endif %}>{{ _('All') }}</option>
|
||||||
{%- for k, v in model.contest.RULES -%}
|
{%- for k, v in model.contest.RULES -%}
|
||||||
<option value="{{ k }}"{% if rule == k %} selected{% endif %}>{{ _('All {0} Contests').format(_(v.TEXT)) }}</option>
|
{% if k != 'homework' %}
|
||||||
{%- endfor -%}
|
<option value="{{ k }}"{% if rule == k %} selected{% endif %}>{{ _('All {0} Contests').format(v.TEXT) }}</option>
|
||||||
|
{% endif %}
|
||||||
|
{%- endfor -%}
|
||||||
</select>
|
</select>
|
||||||
<button type="submit" class="button hasjs--hide">
|
<button type="submit" class="button hasjs--hide">
|
||||||
{{ _('Search') }}
|
{{ _('Search') }}
|
||||||
|
|||||||
Reference in new issue
Block a user