+
注意事项
- 隐藏的题单无法被普通用户查看。
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 = $('
').attr('data-bs-target', '#' + div_editor_id + '_edit').attr('data-bs-toggle', 'tab').text(uojLocale('editor::edit')).addClass('active');
+ var btn_preview = $('
').attr('data-bs-target', '#' + div_editor_id + '_preview').attr('data-bs-toggle', 'tab').text(uojLocale('editor::preview'));
+
+ var div_editor = $('
')
+ .append(
+ $('
')
+ .append('
')
+ );
+ var div_preview = $('
');
+
+ var monaco_editor_instance = null;
+ var monaco_editor_init = function() {
+ require_monaco({ markdown: true }, function() {
+ if (monaco_editor_instance != null) {
+ return;
+ }
+
+ $(div_editor).empty();
+
+ monaco_editor_instance = monaco.editor.create(div_editor[0], {
+ language: 'markdown-math',
+ automaticLayout: true,
+ fontSize: "16px",
+ minimap: {
+ enabled: false,
+ },
+ wordWrap: 'on',
+ unicodeHighlight: {
+ ambiguousCharacters: false,
+ },
+ });
+
+ $('#' + spinner_id).css('display', 'none !important');
+ $(div_editor).addClass('overflow-hidden rounded-bottom').show();
+
+ monaco_editor_instance.getModel().setValue(text);
+ monaco_editor_instance.onDidChangeModelContent(function () {
+ $('#' + input_editor_id).val(monaco_editor_instance.getModel().getValue());
+ });
+
+ require(['MonacoMarkdown'], function(MonacoMarkdown) {
+ var extension = new MonacoMarkdown.MonacoMarkdownExtension();
+ extension.activate(monaco_editor_instance);
+ });
+ });
+ }
+
+ $(this)
+ .append(
+ $('
')
+ .append(
+ $('').append(
+ $('