From de04a852ed3ab4d9b406bf50ce32324d697a1ad4 Mon Sep 17 00:00:00 2001 From: undefined Date: Sat, 23 Jul 2022 17:36:09 +0800 Subject: [PATCH] ui: language select component --- .../ui-default/components/languageselect.tsx | 86 +++++++++++++++++++ packages/ui-default/package.json | 2 +- .../ui-default/pages/home_preference.page.jsx | 68 +++------------ .../ui-default/pages/problem_submit.page.tsx | 81 ++--------------- 4 files changed, 109 insertions(+), 128 deletions(-) create mode 100644 packages/ui-default/components/languageselect.tsx 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;