diff --git a/packages/ui-default/.eslintrc.js b/packages/ui-default/.eslintrc.js index 6306c4bff..811f1ac0e 100644 --- a/packages/ui-default/.eslintrc.js +++ b/packages/ui-default/.eslintrc.js @@ -137,5 +137,6 @@ module.exports = { 'jsx-a11y/no-static-element-interactions': 'off', 'jsx-a11y/anchor-is-valid': 'off', 'jsx-a11y/click-events-have-key-events': 'off', + 'jsx-a11y/label-has-associated-control': 'off', }, }; diff --git a/packages/ui-default/components/scratchpad/ScratchpadToolbarContainer.jsx b/packages/ui-default/components/scratchpad/ScratchpadToolbarContainer.jsx index a2875d084..b6dcd59b1 100644 --- a/packages/ui-default/components/scratchpad/ScratchpadToolbarContainer.jsx +++ b/packages/ui-default/components/scratchpad/ScratchpadToolbarContainer.jsx @@ -87,7 +87,8 @@ export default connect(mapStateToProps, mapDispatchToProps)(class ScratchpadTool super(props); if (!availableLangs[this.props.editorLang]) { // preference not allowed - const key = keys.find((i) => availableLangs[i].pretest === this.props.editorLang); + const key = keys.filter((i) => availableLangs[i].pretest) + .find((i) => availableLangs[i].pretest.split('.')[0] === this.props.editorLang.split('.')[0]); this.props.setEditorLanguage(key || keys[0]); } } diff --git a/packages/ui-default/package.json b/packages/ui-default/package.json index 38463b56d..dc4b55fcd 100644 --- a/packages/ui-default/package.json +++ b/packages/ui-default/package.json @@ -1,6 +1,6 @@ { "name": "@hydrooj/ui-default", - "version": "4.38.14", + "version": "4.38.15", "author": "undefined ", "license": "AGPL-3.0", "main": "hydro.js", diff --git a/packages/ui-default/pages/problem_submit.page.js b/packages/ui-default/pages/problem_submit.page.js deleted file mode 100644 index 0544ab97e..000000000 --- a/packages/ui-default/pages/problem_submit.page.js +++ /dev/null @@ -1,71 +0,0 @@ -import { NamedPage } from 'vj/misc/Page'; -import getAvailableLangs from 'vj/utils/availableLangs'; - -function setOptions($el, options) { - $el.empty(); - $.each(options, (key, value) => { - $el.append($('').attr('value', key).text(value)); - }); -} - -const page = new NamedPage(['problem_submit', 'contest_detail_problem_submit', 'homework_detail_problem_submit'], async () => { - const { config } = UiContext.pdoc; - const availableLangs = getAvailableLangs(config.langs); - - function onChangeMain(update = true) { - const options = {}; - for (const key in availableLangs) { - if (key.startsWith(`${this.value}.`) && key !== this.value) options[key] = availableLangs[key].display; - } - setOptions($('#codelang-sub-select'), options); - if (Object.keys(options).length) { - $('#codelang-sub-container').show(); - if (update) $('[name="lang"]').val($('#codelang-sub-select').val()); - } else { - $('#codelang-sub-container').hide(); - if (update) $('[name="lang"]').val(this.value); - } - return Object.keys(options)[0]; - } - const main = {}; - for (const key in availableLangs) { - if (config.langs && !config.langs.filter((i) => i === key || i.startsWith(`${key}.`)).length) continue; - if (!key.includes('.')) main[key] = window.LANGS[key].display; - else { - const a = key.split('.')[0]; - main[a] = window.LANGS[a].display; - } - } - setOptions($('#codelang-main-select'), main); - - let isFallback = false; - const current = $('[name="lang"]').val(); - if (current.includes('.')) { - const [m] = current.split('.'); - if (main[m]) { - $('#codelang-main-select').val(m); - const fallback = onChangeMain.call({ value: m }, false); - $('#codelang-sub-select').val(current); - if (fallback && !$('#codelang-sub-select').val()) { - $('#codelang-sub-select').val(fallback); - $('[name="lang"]').val(fallback); - } - } else isFallback = true; - } else if (main[current]) { - $('#codelang-main-select').val(current); - onChangeMain.call({ value: $('#codelang-main-select').val() }, false); - } else isFallback = true; - - if (isFallback) { - $('#codelang-main-select').val(Object.keys(main)[0]); - onChangeMain.call({ value: Object.keys(main)[0] }, true); - } - - $('#codelang-main-select').on('change', onChangeMain); - $('#codelang-sub-select').on('change', function () { - $('[name="lang"]').val(this.value); - }); - if (Object.keys(main).length === 1) $('#codelang-main-container').hide(); -}); - -export default page; diff --git a/packages/ui-default/pages/problem_submit.page.tsx b/packages/ui-default/pages/problem_submit.page.tsx new file mode 100644 index 000000000..e3e6bd2eb --- /dev/null +++ b/packages/ui-default/pages/problem_submit.page.tsx @@ -0,0 +1,92 @@ +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'; + +const page = new NamedPage(['problem_submit', 'contest_detail_problem_submit', 'homework_detail_problem_submit'], async () => { + const { config } = UiContext.pdoc; + const availableLangs = getAvailableLangs(config.langs); + const mainLangs = {}; + const preferences = [($('[name="lang"]').val() as string) || '']; + for (const key in availableLangs) { + if (config.langs && !config.langs.filter((i) => i === key || i.startsWith(`${key}.`)).length) continue; + if (window.LANGS[key].pretest === preferences[0]) preferences.push(key); + if (!key.includes('.')) mainLangs[key] = window.LANGS[key].display; + else { + const a = key.split('.')[0]; + mainLangs[a] = window.LANGS[a].display; + } + } + for (const key in availableLangs) { + if (config.langs && !config.langs.filter((i) => i === key || i.startsWith(`${key}.`)).length) continue; + 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, '']; + } + } + return [Object.keys(mainLangs)[0], '']; + })(); + + 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(options).length > 1 && ( +
+ +
+ )} + + ); + } + + ReactDOM.createRoot(document.getElementById('codelang-selector')).render(); +}); + +export default page; diff --git a/packages/ui-default/templates/problem_submit.html b/packages/ui-default/templates/problem_submit.html index 6c37ca92c..ae0952ced 100644 --- a/packages/ui-default/templates/problem_submit.html +++ b/packages/ui-default/templates/problem_submit.html @@ -17,24 +17,7 @@ value:handler.user.codeLang }) }} -
-
- -
- -
+
{{ form.form_textarea({label:'Code', columns:12, name:'code', extra_class:'monospace', autofocus:true}) }}