diff --git a/web/app/controllers/group_manage.php b/web/app/controllers/group_manage.php index 3e76bb8..cd678cf 100644 --- a/web/app/controllers/group_manage.php +++ b/web/app/controllers/group_manage.php @@ -64,10 +64,9 @@ if ($cur_tab == 'profile') { 'option_div_class' => 'form-check d-inline-block ms-2', 'default_value' => UOJGroup::info('is_hidden'), ]); - $update_profile_form->addTextArea('announcement', [ + $update_profile_form->addMarkdownEditor('announcement', [ 'div_class' => 'mt-3', 'label' => '公告', - 'input_class' => 'form-control font-monospace', 'default_value' => UOJGroup::info('announcement'), 'help' => '公告支持 Markdown 语法。', 'validator_php' => function ($announcement, &$vdata) { @@ -287,11 +286,11 @@ if ($cur_tab == 'profile') {
-
-
- printHTML() ?> +
+
+ printHTML() ?>
-
+
注意事项
  • 隐藏的小组无法被普通用户查看,即使该用户属于本小组。
  • diff --git a/web/app/controllers/list_manage.php b/web/app/controllers/list_manage.php index 94f28b9..da5facf 100644 --- a/web/app/controllers/list_manage.php +++ b/web/app/controllers/list_manage.php @@ -25,6 +25,7 @@ if (!isset($tabs_info[$cur_tab])) { if ($cur_tab == 'profile') { $update_profile_form = new UOJForm('update_profile'); $update_profile_form->addInput('name', [ + 'div_class' => 'mb-3', 'label' => '标题', 'default_value' => HTML::unescape(UOJList::info('title')), 'validator_php' => function ($title, &$vdata) { @@ -47,7 +48,7 @@ if ($cur_tab == 'profile') { }, ]); $update_profile_form->addCheckboxes('is_hidden', [ - 'div_class' => 'mt-3', + 'div_class' => 'mb-3', 'label' => '可见性', 'label_class' => 'me-3', 'select_class' => 'd-inline-block', @@ -59,6 +60,7 @@ if ($cur_tab == 'profile') { ], ]); $update_profile_form->addInput('tags', [ + 'div_class' => 'mb-3', 'label' => '标签', 'default_value' => implode(', ', UOJList::cur()->queryTags()), 'validator_php' => function ($tags_str, &$vdata) { @@ -93,7 +95,7 @@ if ($cur_tab == 'profile') { }, 'help' => '多个标签请使用逗号隔开。' ]); - $update_profile_form->addTextArea('content_md', [ + $update_profile_form->addMarkdownEditor('content_md', [ 'label' => '描述', 'default_value' => UOJList::cur()->queryContent()['content_md'], 'validator_php' => function ($content_md, &$vdata) { @@ -237,11 +239,11 @@ if ($cur_tab == 'profile') {
    -
    -
    +
    +
    printHTML() ?>
    -
    +
    注意事项
    • 隐藏的题单无法被普通用户查看。
    • diff --git a/web/app/controllers/subdomain/api/markdown.php b/web/app/controllers/subdomain/api/markdown.php new file mode 100644 index 0000000..2ff856a --- /dev/null +++ b/web/app/controllers/subdomain/api/markdown.php @@ -0,0 +1,24 @@ +purify($parsedown->line(UOJRequest::post('markdown', 'is_string'))); +} else { + $html = $purifier->purify($parsedown->text(UOJRequest::post('markdown', 'is_string'))); +} + +die($html); diff --git a/web/app/controllers/subdomain/api/route.php b/web/app/controllers/subdomain/api/route.php index e4bde77..bbbe0eb 100644 --- a/web/app/controllers/subdomain/api/route.php +++ b/web/app/controllers/subdomain/api/route.php @@ -6,9 +6,14 @@ call_user_func(function () { // to prevent variable scope leak 'domain' => UOJConfig::$data['web']['main']['host'], ], function () { + // Remote Judge Route::post("/api/remote_judge/custom_account_validator", '/subdomain/api/remote_judge/custom_account_validator.php'); + // Submission Route::any('/api/submission/submission_status_details', '/subdomain/api/submission/submission_status_details.php'); + + // Misc + Route::post('/api/markdown', '/subdomain/api/markdown.php'); } ); }); diff --git a/web/app/controllers/subdomain/blog/blog.php b/web/app/controllers/subdomain/blog/blog.php index ec5aa6c..9202900 100644 --- a/web/app/controllers/subdomain/blog/blog.php +++ b/web/app/controllers/subdomain/blog/blog.php @@ -46,9 +46,9 @@ function getCommentContentToDisplay($comment) { } $comment_form = new UOJForm('comment'); -$comment_form->addTextArea('comment', [ +$comment_form->addMarkdownEditor('comment', [ 'label' => '内容', - 'help' => '评论支持 Markdown 语法。可以用 @mike 来提到 mike 这个用户,mike 会被高亮显示。如果你真的想打 @ 这个字符,请用 @@。', + 'help' => '评论支持 Markdown 语法。可以用 @mike 来提到 mike 这个用户,mike 会被高亮显示。', 'validator_php' => function ($comment) { if (!Auth::check()) { return '请先登录'; @@ -62,6 +62,7 @@ $comment_form->addTextArea('comment', [ return ''; }, ]); +$comment_form->config['ctrl_enter_submit'] = true; $comment_form->handle = function () { global $blog, $comment_form; $comment = $_POST['comment']; @@ -122,7 +123,7 @@ $reply_form->addHidden( }, null ); -$reply_form->addTextArea('reply_comment', [ +$reply_form->addMarkdownEditor('reply_comment', [ 'label' => '内容', 'validator_php' => function ($comment) { if (!Auth::check()) { diff --git a/web/app/models/UOJForm.php b/web/app/models/UOJForm.php index 68e02a6..2371f34 100644 --- a/web/app/models/UOJForm.php +++ b/web/app/models/UOJForm.php @@ -507,6 +507,50 @@ class UOJForm { $this->config['has_file'] = true; } + public function addMarkdownEditor($name, $config = []) { + $config += [ + 'div_class' => '', + 'default_value' => '', + 'label' => '', + 'label_class' => 'form-label', + 'placeholder' => '', + 'help' => '', + 'help_class' => 'form-text', + 'validator_php' => function ($str, &$vdata) { + return ''; + }, + 'validator_js' => null, + ]; + + $html = ''; + $html .= HTML::tag_begin('div', ['class' => $config['div_class'], 'id' => "div-$name"]); + + $default_value = json_encode($config['default_value']); + + if ($config['label']) { + $html .= HTML::tag('label', [ + 'class' => $config['label_class'], + 'for' => "input-$name", + 'id' => "label-$name" + ], $config['label']); + } + + $html .= <<
    + + EOD; + + if ($config['help']) { + $html .= HTML::tag('div', ['class' => $config['help_class']], $config['help']); + } + + $html .= HTML::tag_end('div'); + + $this->add($name, $html, $config['validator_php'], $config['validator_js']); + } + public function printHTML() { echo HTML::tag_begin('form', [ 'action' => UOJContext::requestURI(), diff --git a/web/js/uoj.js b/web/js/uoj.js index 4b3aef5..bece091 100644 --- a/web/js/uoj.js +++ b/web/js/uoj.js @@ -42,8 +42,16 @@ uojLocaleData = { }, "editor::upload from local": { "en": "Local file", - "zh-cn": "本地文件" - } + "zh-cn": "本地文件", + }, + "editor::edit": { + "en": "Edit", + "zh-cn": "编辑", + }, + "editor::preview": { + "en": "Preview", + "zh-cn": "预览", + }, }; function uojLocale(name) { @@ -873,7 +881,7 @@ $.fn.text_file_form_group = function(name, text) { monaco_editor_instance = monaco.editor.create(div_editor[0], { language: 'text', automaticLayout: true, - fontSize: "14px", + fontSize: "16px", }); $('#' + spinner_id).css('display', 'none !important'); @@ -1645,6 +1653,148 @@ function custom_test_onsubmit(response_text, div_result, url) { setTimeout(update, 500); } +// markdown input editor +$.fn.markdown_input_editor = function(name, type, text) { + return this.each(function() { + var input_editor_name = name; + var input_editor_id = 'input-' + name + '_editor'; + var spinner_id = 'spinner-' + name + '_editor'; + var div_editor_id = 'div-' + name + '_editor'; + var div_preview_id = 'div-' + name + '_preview'; + + var btn_editor = $('