diff --git a/packages/ui-default/components/languageselect.tsx b/packages/ui-default/components/languageselect.tsx
new file mode 100644
index 000000000..9ec2d95f7
--- /dev/null
+++ b/packages/ui-default/components/languageselect.tsx
@@ -0,0 +1,86 @@
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import i18n from 'vj/utils/i18n';
+
+export default function LanguageSelect({
+ fieldSelector, firstLoadMain, firstLoadSub, availableLangs, mainLangs,
+}) {
+ const [main, setMain] = React.useState(firstLoadMain);
+ const [sub, setSub] = React.useState(firstLoadSub);
+
+ const options = {};
+ for (const key in availableLangs) {
+ if (key.startsWith(`${main}.`)) options[key.split('.')[1]] = availableLangs[key].display;
+ }
+ React.useEffect(() => {
+ $(fieldSelector).val(sub ? `${main}.${sub}` : main);
+ }, [main, sub]);
+ React.useEffect(() => {
+ const subselections = Object.keys(options).length;
+ if (options[sub]) return;
+ if (!subselections) setSub('');
+ if (subselections === 1) setSub(Object.keys(options)[0]);
+ }, [main]);
+
+ return (
+ <>
+ {(Object.keys(mainLangs).length > 1 || Object.keys(options).length === 1) && (
+
+
+
+ )}
+ {(Object.keys(options).length > 1 || Object.keys(mainLangs).length === 1) && (
+
+
+
+ )}
+ >
+ );
+}
+
+export function renderLanguageSelect(onElement, fieldSelector, availableLangs, mainLangs, preferences) {
+ const [firstLoadMain, firstLoadSub] = (() => {
+ for (const preference of preferences) {
+ if (preference.includes('.')) {
+ const [l, r] = preference.split('.');
+ if (availableLangs[preference]) return [l, r];
+ if (availableLangs[l]) return [l, ''];
+ } else if (availableLangs[preference]) {
+ return [preference, ''];
+ }
+ }
+ const selected = Object.keys(mainLangs)[0];
+ for (const key in availableLangs) {
+ if (key.startsWith(`${selected}.`)) return [selected, key.split('.')[1]];
+ }
+ return [selected, ''];
+ })();
+
+ ReactDOM.createRoot(onElement).render(
+ ,
+ );
+}
diff --git a/packages/ui-default/package.json b/packages/ui-default/package.json
index f2198a9dd..97519d389 100644
--- a/packages/ui-default/package.json
+++ b/packages/ui-default/package.json
@@ -1,6 +1,6 @@
{
"name": "@hydrooj/ui-default",
- "version": "4.38.20",
+ "version": "4.38.21",
"author": "undefined ",
"license": "AGPL-3.0",
"main": "hydro.js",
diff --git a/packages/ui-default/pages/home_preference.page.jsx b/packages/ui-default/pages/home_preference.page.jsx
index 2938f969f..16adcc01d 100644
--- a/packages/ui-default/pages/home_preference.page.jsx
+++ b/packages/ui-default/pages/home_preference.page.jsx
@@ -1,71 +1,31 @@
import { NamedPage } from 'vj/misc/Page';
import i18n from 'vj/utils/i18n';
import tpl from 'vj/utils/tpl';
+import getAvailableLangs from 'vj/utils/availableLangs';
+import { renderLanguageSelect } from 'vj/components/languageselect';
+import delay from 'vj/utils/delay';
-function initCodeLangHelper() {
- function setOptions($el, options) {
- $el.empty();
- $.each(options, (key, value) => {
- $el.append($('').attr('value', key).text(value));
- });
- }
-
- const $el = $(tpl`\
-
-`);
+async function initCodeLangHelper() {
+ const $el = $(tpl``);
$('[name="codeLang"]')
.parent().parent().parent()
.parent()
.hide()
.after($el);
- function onChangeMain(update = true) {
- const options = {};
- for (const key in window.LANGS) {
- if (key.startsWith(`${this.value}.`) && key !== this.value) options[key] = window.LANGS[key].display;
- }
- if (Object.keys(options).length > 1) {
- setOptions($('#codelang-sub-select'), options);
- $('#codelang-sub-container').show();
- if (update) $('[name="codeLang"]').val($('#codelang-sub-select').val());
- } else {
- $('#codelang-sub-container').hide();
- if (update) $('[name="codeLang"]').val(this.value);
- }
- }
const main = {};
for (const key in window.LANGS) {
if (!key.includes('.') && !window.LANGS[key].hidden) main[key] = window.LANGS[key].display;
}
- setOptions($('#codelang-main-select'), main);
- const current = $('[name="codeLang"]').val();
- if (current.includes('.')) {
- const [m] = current.split('.');
- $('#codelang-main-select').val(m);
- onChangeMain.call({ value: m }, false);
- $('#codelang-sub-select').val(current);
- } else $('#codelang-main-select').val(current);
- $('#codelang-main-select').on('change', onChangeMain);
- $('#codelang-sub-select').on('change', function () {
- $('[name="codeLang"]').val(this.value);
- });
+
+ await delay(50);
+ renderLanguageSelect(
+ document.getElementById('codelang-select'),
+ $('[name="codeLang"]'),
+ getAvailableLangs(),
+ main,
+ [$('[name="codeLang"]').val()],
+ );
}
function supportFontFamily(f) {
diff --git a/packages/ui-default/pages/problem_submit.page.tsx b/packages/ui-default/pages/problem_submit.page.tsx
index 09f43e4a0..80be18380 100644
--- a/packages/ui-default/pages/problem_submit.page.tsx
+++ b/packages/ui-default/pages/problem_submit.page.tsx
@@ -1,8 +1,6 @@
-import React from 'react';
-import ReactDOM from 'react-dom/client';
-import i18n from 'vj/utils/i18n';
import { NamedPage } from 'vj/misc/Page';
import getAvailableLangs from 'vj/utils/availableLangs';
+import { renderLanguageSelect } from 'vj/components/languageselect';
const page = new NamedPage(['problem_submit', 'contest_detail_problem_submit', 'homework_detail_problem_submit'], async () => {
const { config } = UiContext.pdoc;
@@ -23,76 +21,13 @@ const page = new NamedPage(['problem_submit', 'contest_detail_problem_submit', '
if (window.LANGS[key].pretest?.split('.')[0] === preferences[0].split('.')[0]) preferences.push(key);
}
- const [firstLoadMain, firstLoadSub] = (() => {
- for (const preference of preferences) {
- if (preference.includes('.')) {
- const [l, r] = preference.split('.');
- if (availableLangs[preference]) return [l, r];
- if (availableLangs[l]) return [l, ''];
- } else if (availableLangs[preference]) {
- return [preference, ''];
- }
- }
- const selected = Object.keys(mainLangs)[0];
- for (const key in availableLangs) {
- if (key.startsWith(`${selected}.`)) return [selected, key.split('.')[1]];
- }
- return [selected, ''];
- })();
-
- function LanguageSelect() {
- const [main, setMain] = React.useState(firstLoadMain);
- const [sub, setSub] = React.useState(firstLoadSub);
-
- const options = {};
- for (const key in availableLangs) {
- if (key.startsWith(`${main}.`)) options[key.split('.')[1]] = availableLangs[key].display;
- }
- React.useEffect(() => {
- $('[name="lang"]').val(sub ? `${main}.${sub}` : main);
- }, [main, sub]);
- React.useEffect(() => {
- const subselections = Object.keys(options).length;
- if (options[sub]) return;
- if (!subselections) setSub('');
- if (subselections === 1) setSub(Object.keys(options)[0]);
- }, [main]);
-
- return (
- <>
- {(Object.keys(mainLangs).length > 1 || Object.keys(options).length === 1) && (
-
-
-
- )}
- {(Object.keys(options).length > 1 || Object.keys(mainLangs).length === 1) && (
-
-
-
- )}
- >
- );
- }
-
- ReactDOM.createRoot(document.getElementById('codelang-selector')).render();
+ renderLanguageSelect(
+ document.getElementById('codelang-selector'),
+ '[name="lang"]',
+ availableLangs,
+ mainLangs,
+ preferences,
+ );
});
export default page;