diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json
index b43580369..52d2708f0 100644
--- a/packages/hydrooj/package.json
+++ b/packages/hydrooj/package.json
@@ -1,6 +1,6 @@
{
"name": "hydrooj",
- "version": "2.21.17",
+ "version": "2.21.18",
"bin": "bin/hydrooj.js",
"main": "dist/loader.js",
"typings": "dist/loader.d.ts",
@@ -11,7 +11,7 @@
"node": ">=14"
},
"dependencies": {
- "@hydrooj/utils": "^1.0.0",
+ "@hydrooj/utils": "^1.0.1",
"adm-zip": "^0.5.5",
"ansi_up": "^5.0.0",
"cookies": "^0.8.0",
diff --git a/packages/hydrooj/src/model/problem.ts b/packages/hydrooj/src/model/problem.ts
index 693024dde..223ea7d75 100644
--- a/packages/hydrooj/src/model/problem.ts
+++ b/packages/hydrooj/src/model/problem.ts
@@ -62,6 +62,9 @@ export class ProblemModel {
if (pid) args.pid = pid;
await bus.serial('problem/before-add', args);
const result = await document.add(domainId, content, owner, document.TYPE_PROBLEM, docId, null, null, args);
+ args.content = content;
+ args.owner = owner;
+ args.docType = document.TYPE_PROBLEM;
await bus.emit('problem/add', args, result);
return result;
}
diff --git a/packages/ui-default/components/subjective-question/index.jsx b/packages/ui-default/components/subjective-question/index.jsx
new file mode 100644
index 000000000..dea8f9e87
--- /dev/null
+++ b/packages/ui-default/components/subjective-question/index.jsx
@@ -0,0 +1,43 @@
+import React from 'react';
+
+export default class MessagePadContainer extends React.PureComponent {
+ Textbox(args, name) {
+ return (
+
+ );
+ }
+
+ Radio(args, name) {
+ return (
+ <>
+ {args.desc}
+ {args.choices.map((i) => (
+
+ ))}
+ >
+ );
+ }
+
+ render() {
+ return (
+
+ );
+ }
+}
diff --git a/packages/ui-default/package.json b/packages/ui-default/package.json
index 0a255a24b..4cbd2255e 100644
--- a/packages/ui-default/package.json
+++ b/packages/ui-default/package.json
@@ -1,6 +1,6 @@
{
"name": "@hydrooj/ui-default",
- "version": "4.5.10",
+ "version": "4.5.11",
"author": "undefined ",
"license": "AGPL-3.0",
"main": "hydro.js",
@@ -31,7 +31,6 @@
"babel-loader": "^8.2.2",
"babel-plugin-lodash": "^3.3.4",
"babel-plugin-prismjs": "^2.0.1",
- "base-64": "^1.0.0",
"chalk": "^4.1.0",
"classnames": "^2.3.1",
"clipboard": "^2.0.8",
diff --git a/packages/ui-default/pages/problem_detail.page.jsx b/packages/ui-default/pages/problem_detail.page.jsx
index 39300e668..4d068a600 100644
--- a/packages/ui-default/pages/problem_detail.page.jsx
+++ b/packages/ui-default/pages/problem_detail.page.jsx
@@ -1,3 +1,4 @@
+import yaml from 'js-yaml';
import { NamedPage } from 'vj/misc/Page';
import Navigation from 'vj/components/navigation';
import { ActionDialog } from 'vj/components/dialog';
@@ -5,6 +6,7 @@ import loadReactRedux from 'vj/utils/loadReactRedux';
import delay from 'vj/utils/delay';
import i18n from 'vj/utils/i18n';
import request from 'vj/utils/request';
+import base64 from 'vj/utils/base64';
class ProblemPageExtender {
constructor() {
@@ -211,6 +213,27 @@ const page = new NamedPage(['problem_detail', 'contest_detail_problem', 'homewor
unmountReact();
}
+ async function loadSubjective() {
+ try {
+ const props = yaml.load(base64.decode(document.getElementsByClassName('section__body typo')[0].innerText));
+ $('.loader-container').show();
+ const { default: Subjective } = await import('vj/components/subjective-question/index');
+ const React = await import('react');
+ const ReactDOM = await import('react-dom');
+
+ ReactDOM.render(
+
+
+
,
+ $('.problem-content').get(0),
+ );
+ $('.loader-container').hide();
+ // eslint-disable-next-line no-empty
+ } catch (e) {
+ console.error(e);
+ }
+ }
+
$(document).on('click', '[name="problem-sidebar__open-scratchpad"]', (ev) => {
enterScratchpadMode();
ev.preventDefault();
@@ -224,6 +247,7 @@ const page = new NamedPage(['problem_detail', 'contest_detail_problem', 'homewor
$('[name="problem-sidebar__categories"]').show();
});
$('[name="problem-sidebar__send-to"]').click(() => handleClickCopyProblem());
+ loadSubjective();
});
export default page;
diff --git a/packages/ui-default/pages/user_detail.page.js b/packages/ui-default/pages/user_detail.page.js
index 626aed2b9..2ba61480c 100644
--- a/packages/ui-default/pages/user_detail.page.js
+++ b/packages/ui-default/pages/user_detail.page.js
@@ -1,10 +1,10 @@
-import base64 from 'base-64';
import Clipboard from 'clipboard';
import { NamedPage } from 'vj/misc/Page';
import substitute from 'vj/utils/substitute';
import Notification from 'vj/components/notification';
import i18n from 'vj/utils/i18n';
+import base64 from 'vj/utils/base64';
const page = new NamedPage('user_detail', async () => {
$('[name="profile_contact_copy"]').get().forEach((el) => {
diff --git a/packages/ui-default/utils/base64.js b/packages/ui-default/utils/base64.js
new file mode 100644
index 000000000..22535703c
--- /dev/null
+++ b/packages/ui-default/utils/base64.js
@@ -0,0 +1,105 @@
+const Base64 = {
+ _keyStr: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
+
+ encode(input) {
+ let output = '';
+ let chr1;
+ let chr2;
+ let chr3;
+ let enc1;
+ let enc2;
+ let enc3;
+ let enc4;
+ let i = 0;
+ input = Base64._utf8_encode(input);
+ while (i < input.length) {
+ chr1 = input.charCodeAt(i++);
+ chr2 = input.charCodeAt(i++);
+ chr3 = input.charCodeAt(i++);
+ enc1 = chr1 >> 2;
+ enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
+ enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
+ enc4 = chr3 & 63;
+ if (Number.isNaN(chr2)) enc3 = enc4 = 64;
+ else if (Number.isNaN(chr3)) enc4 = 64;
+ output = output
+ + this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2)
+ + this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
+ }
+ return output;
+ },
+
+ decode(input) {
+ let output = '';
+ let chr1;
+ let chr2;
+ let chr3;
+ let enc1;
+ let enc2;
+ let enc3;
+ let enc4;
+ let i = 0;
+ input = input.replace(/[^A-Za-z0-9+/=]/g, '');
+ while (i < input.length) {
+ enc1 = this._keyStr.indexOf(input.charAt(i++));
+ enc2 = this._keyStr.indexOf(input.charAt(i++));
+ enc3 = this._keyStr.indexOf(input.charAt(i++));
+ enc4 = this._keyStr.indexOf(input.charAt(i++));
+ chr1 = (enc1 << 2) | (enc2 >> 4);
+ chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
+ chr3 = ((enc3 & 3) << 6) | enc4;
+ output += String.fromCharCode(chr1);
+ if (enc3 !== 64) output += String.fromCharCode(chr2);
+ if (enc4 !== 64) output += String.fromCharCode(chr3);
+ }
+ output = Base64._utf8_decode(output);
+ return output;
+ },
+
+ _utf8_encode(string) {
+ string = string.replace(/\r\n/g, '\n');
+ let utftext = '';
+ for (let n = 0; n < string.length; n++) {
+ const c = string.charCodeAt(n);
+ if (c < 128) {
+ utftext += String.fromCharCode(c);
+ } else if ((c > 127) && (c < 2048)) {
+ utftext += String.fromCharCode((c >> 6) | 192);
+ utftext += String.fromCharCode((c & 63) | 128);
+ } else {
+ utftext += String.fromCharCode((c >> 12) | 224);
+ utftext += String.fromCharCode(((c >> 6) & 63) | 128);
+ utftext += String.fromCharCode((c & 63) | 128);
+ }
+ }
+ return utftext;
+ },
+
+ _utf8_decode(utftext) {
+ let string = '';
+ let i = 0;
+ let c = 0;
+ let c2 = 0;
+ let c3 = 0;
+ while (i < utftext.length) {
+ c = utftext.charCodeAt(i);
+ if (c < 128) {
+ string += String.fromCharCode(c);
+ i++;
+ } else if ((c > 191) && (c < 224)) {
+ c2 = utftext.charCodeAt(i + 1);
+ string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
+ i += 2;
+ } else {
+ c2 = utftext.charCodeAt(i + 1);
+ c3 = utftext.charCodeAt(i + 2);
+ string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
+ i += 3;
+ }
+ }
+ return string;
+ },
+};
+
+export default Base64;
+window.Hydro.utils.base64 = Base64;