diff --git a/web/app/controllers/new_remote_problem.php b/web/app/controllers/new_remote_problem.php index 0cb4562..f5f750b 100644 --- a/web/app/controllers/new_remote_problem.php +++ b/web/app/controllers/new_remote_problem.php @@ -98,6 +98,12 @@ $new_remote_problem_form->handle = function (&$vdata) { ]); $id = DB::insert_id(); + dataNewProblem($id); + + if ($data['type'] == 'pdf') { + file_put_contents(UOJContext::storagePath() , "/problem_resources/$id/statement.pdf", $data['pdf_data']); + $data['statement'] = "
\n" . $data['statement']; + } DB::insert([ "insert into problems_contents", @@ -105,7 +111,6 @@ $new_remote_problem_form->handle = function (&$vdata) { "values", DB::tuple([$id, HTML::purifier(['a' => ['target' => 'Enum#_blank']])->purify($data['statement']), '', '']) ]); - dataNewProblem($id); DB::insert([ "insert into problems_tags", diff --git a/web/app/controllers/problem.php b/web/app/controllers/problem.php index 70abace..1575b6d 100644 --- a/web/app/controllers/problem.php +++ b/web/app/controllers/problem.php @@ -2,6 +2,7 @@ requireLib('bootstrap5'); requireLib('hljs'); requireLib('mathjax'); +requireLib('pdf.js'); requirePHPLib('form'); requirePHPLib('judger'); diff --git a/web/app/controllers/problem_statement_manage.php b/web/app/controllers/problem_statement_manage.php index a97ac67..e4a6d77 100644 --- a/web/app/controllers/problem_statement_manage.php +++ b/web/app/controllers/problem_statement_manage.php @@ -144,6 +144,11 @@ if (UOJProblem::info('type') == 'remote') { ], ]); + if ($data['type'] == 'pdf') { + file_put_contents(UOJContext::storagePath() . "/problem_resources/" . UOJProblem::info('id') . "/statement.pdf", $data['pdf_data']); + $data['statement'] = '
' . "\n" . $data['statement']; + } + DB::update([ "update problems_contents", "set", [ diff --git a/web/app/models/HTML.php b/web/app/models/HTML.php index 7ac1312..a3c839b 100644 --- a/web/app/models/HTML.php +++ b/web/app/models/HTML.php @@ -436,6 +436,10 @@ class HTML { $def->addElement('footer', 'Block', 'Flow', 'Common'); mergeConfig($extra_allowed_html, [ + 'div' => [ + 'data-pdf' => 'Text', + 'data-src' => 'URI', + ], 'span' => [ 'class' => 'Enum#uoj-username', 'data-realname' => 'Text', diff --git a/web/app/models/UOJBlogEditor.php b/web/app/models/UOJBlogEditor.php index d4e23f1..7d9bc21 100644 --- a/web/app/models/UOJBlogEditor.php +++ b/web/app/models/UOJBlogEditor.php @@ -9,7 +9,7 @@ class UOJBlogEditor { public $post_data = []; public $show_editor = true; public $show_tags = true; - + public $label_text = [ 'title' => '标题', 'tags' => '标签(多个标签用逗号隔开)', @@ -19,15 +19,15 @@ class UOJBlogEditor { 'private' => '未公开', 'public' => '公开' ]; - + public $validator = array(); - + function __construct() { global $REQUIRE_LIB; $REQUIRE_LIB['blog-editor'] = ''; - + $this->validator = [ - 'title' => function(&$title) { + 'title' => function (&$title) { if ($title == '') { return '标题不能为空'; } @@ -39,13 +39,13 @@ class UOJBlogEditor { } return ''; }, - 'content_md' => function(&$content_md) { + 'content_md' => function (&$content_md) { if (strlen($content_md) > 1000000) { return '内容过长'; } return ''; }, - 'tags' => function(&$tags) { + 'tags' => function (&$tags) { $tags = str_replace(',', ',', $tags); $tags_raw = explode(',', $tags); if (count($tags_raw) > 10) { @@ -58,10 +58,10 @@ class UOJBlogEditor { continue; } if (strlen($tag) > 30) { - return '标签 “' . HTML::escape($tag) .'” 太长'; + return '标签 “' . HTML::escape($tag) . '” 太长'; } if (in_array($tag, $tags, true)) { - return '标签 “' . HTML::escape($tag) .'” 重复出现'; + return '标签 “' . HTML::escape($tag) . '” 重复出现'; } $tags[] = $tag; } @@ -69,7 +69,7 @@ class UOJBlogEditor { } ]; } - + public function validate($name) { if (!isset($_POST["{$this->name}_{$name}"])) { return '不能为空'; @@ -98,14 +98,14 @@ class UOJBlogEditor { die(json_encode($errors)); } crsf_defend(); - + $this->post_data['is_hidden'] = isset($_POST["{$this->name}_is_hidden"]) ? 1 : 0; - + $purifier = HTML::purifier(); $parsedown = HTML::parsedown(); - + $this->post_data['title'] = HTML::escape($this->post_data['title']); - + if ($this->show_editor) { if ($this->type == 'blog') { $this->post_data['content'] = $parsedown->text($this->post_data['content_md']); @@ -113,7 +113,7 @@ class UOJBlogEditor { if (preg_match('/^.*.*$/m', $this->post_data['content'], $matches, PREG_OFFSET_CAPTURE)) { $content_less = substr($this->post_data['content'], 0, $matches[0][1]); $content_more = substr($this->post_data['content'], $matches[0][1] + strlen($matches[0][0])); - $this->post_data['content'] = $purifier->purify($content_less).''.$purifier->purify($content_more); + $this->post_data['content'] = $purifier->purify($content_less) . '' . $purifier->purify($content_more); } else { $this->post_data['content'] = $purifier->purify($this->post_data['content']); } @@ -122,20 +122,22 @@ class UOJBlogEditor { if ($content_array === false || !is_array($content_array)) { die(json_encode(array('content_md' => '不合法的 YAML 格式'))); } - - $marked = function($md) use ($parsedown, $purifier) { + + $marked = function ($md) use ($parsedown, $purifier) { $dom = new DOMDocument; $dom->loadHTML(mb_convert_encoding($parsedown->text($md), 'HTML-ENTITIES', 'UTF-8')); $elements = $dom->getElementsByTagName('li'); - + foreach ($elements as $element) { - $element->setAttribute('class', - $element->getAttribute('class') . ' fragment'); + $element->setAttribute( + 'class', + $element->getAttribute('class') . ' fragment' + ); } return $purifier->purify($dom->saveHTML()); }; - + $config = array(); $this->post_data['content'] = ''; foreach ($content_array as $slide_name => $slide_content) { @@ -147,9 +149,9 @@ class UOJBlogEditor { } continue; } - + $this->post_data['content'] .= '
'; - + if (is_string($slide_content)) { $this->post_data['content'] .= $marked($slide_content); } elseif (is_array($slide_content)) { @@ -167,7 +169,7 @@ class UOJBlogEditor { } } } - + public function handleSave() { global $REQUIRE_LIB; @@ -177,11 +179,14 @@ class UOJBlogEditor { if (!$ret) { $ret = array(); } - + if (isset($_POST['need_preview'])) { ob_start(); if ($this->type == 'blog') { - $req_lib = array('mathjax' => ''); + $req_lib = [ + 'mathjax' => '', + 'pdf.js' => '', + ]; if (isset($REQUIRE_LIB['bootstrap5'])) { $req_lib['bootstrap5'] = ''; @@ -210,10 +215,10 @@ class UOJBlogEditor { $ret['html'] = ob_get_contents(); ob_end_clean(); } - + die(json_encode($ret)); } - + public function runAtServer() { if (isset($_POST["save-{$this->name}"])) { $this->handleSave(); @@ -221,7 +226,7 @@ class UOJBlogEditor { } public function printHTML() { global $REQUIRE_LIB; - + uojIncludeView('blog-editor', ['editor' => $this, 'REQUIRE_LIB' => $REQUIRE_LIB]); } } diff --git a/web/app/models/UOJMarkdown.php b/web/app/models/UOJMarkdown.php index 6528f81..8592721 100644 --- a/web/app/models/UOJMarkdown.php +++ b/web/app/models/UOJMarkdown.php @@ -7,9 +7,12 @@ class UOJMarkdown extends ParsedownMath { $this->options['username_with_color'] = $options['username_with_color'] ?: false; + // Special Block + $this->inlineMarkerList .= '@'; + $this->InlineTypes['@'][] = 'SpecialBlock'; + // https://gist.github.com/ShNURoK42/b5ce8baa570975db487c $this->InlineTypes['@'][] = 'UserMention'; - $this->inlineMarkerList .= '@'; } // https://github.com/taufik-nurrohman/parsedown-extra-plugin/blob/1653418c5a9cf5277cd28b0b23ba2d95d18e9bc4/ParsedownExtraPlugin.php#L340-L345 @@ -85,4 +88,35 @@ class UOJMarkdown extends ParsedownMath { ]; } } + + protected function inlineSpecialBlock($Excerpt) { + if (!isset($Excerpt['text'][1]) or $Excerpt['text'][1] !== '[') { + return; + } + + $Excerpt['text'] = substr($Excerpt['text'], 1); + + $Link = $this->inlineLink($Excerpt); + + if ($Link === null) { + return; + } + + $Inline = [ + 'extent' => $Link['extent'] + 1, + 'element' => [ + 'name' => 'div', + 'attributes' => [ + 'data-src' => $Link['element']['attributes']['href'], + "data-{$Link['element']['text']}" => $Link['element']['text'], + ], + ], + ]; + + $Inline['element']['attributes'] += $Link['element']['attributes']; + + unset($Inline['element']['attributes']['href']); + + return $Inline; + } } diff --git a/web/app/models/UOJRemoteProblem.php b/web/app/models/UOJRemoteProblem.php index b5f0ac9..9347620 100644 --- a/web/app/models/UOJRemoteProblem.php +++ b/web/app/models/UOJRemoteProblem.php @@ -196,13 +196,14 @@ class UOJRemoteProblem { 'time_limit' => null, 'memory_limit' => null, 'difficulty' => -1, + 'pdf_data' => $res['response'], 'statement' => HTML::tag('h3', [], '提示') . HTML::tag( 'p', [], - '本题题面为 PDF 题面,请' . + '若无法正常加载 PDF,请' . HTML::tag('a', ['href' => static::getCodeforcesProblemUrl($id), 'target' => '_blank'], '点此') . - '以查看题面。' + '查看原题面。' ), ]; } else { diff --git a/web/app/views/page-header.php b/web/app/views/page-header.php index b584153..c6d1af3 100644 --- a/web/app/views/page-header.php +++ b/web/app/views/page-header.php @@ -265,6 +265,54 @@ if (!isset($ShowPageHeader)) { + + + + + +