feat(web/problem/manage/statement): allow select tags to fill
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Baoshuo Ren 2023-01-12 10:06:12 +08:00
parent ee0ff210bb
commit 8417f362e8
Signed by: baoshuo
GPG Key ID: 00CB9680AB29F51A
3 changed files with 324 additions and 1 deletions

View File

@ -174,6 +174,85 @@ $difficulty_form->runAtServer();
</ul>
</div>
<div class="card mt-3">
<div class="card-header fw-bold">
标签填充
</div>
<div class="card-body">
<script>
function fillTag(tags) {
if (typeof tags === 'string') tags = [tags];
tags = tags.map(tag => tag.trim()).filter(Boolean);
var originalTags = $('#input-problem_tags')
.val()
.replace(//g, ',')
.split(',')
.map(tag => tag.trim())
.filter(Boolean);
var newTagsSet = new Set(originalTags.concat(tags));
$('#input-problem_tags').val(Array.from(newTagsSet.values()).join(', '));
$('#input-problem_tags').trigger('input');
}
</script>
<div class="row row-cols-4 row-cols-lg-2 g-2">
<?php foreach (UOJProblem::$categories as $category => $tags) : ?>
<?php $category_id = uniqid('category-'); ?>
<div class="d-inline-block" id="category-container-<?= $category_id ?>">
<button id="category-button-<?= $category_id ?>" class="btn btn-sm btn-light w-100" type="button"><?= $category ?></button>
</div>
<script>
$(document).ready(function() {
bootstrap.Popover.jQueryInterface.call($('#category-button-<?= $category_id ?>'), {
container: $('#category-container-<?= $category_id ?>'),
html: true,
placement: 'left',
animation: false,
trigger: 'manual',
fallbackPlacements: ['bottom', 'right'],
content: [
<?php foreach ($tags as $tag) : ?> '<?= $tag ?>', <?php endforeach ?>
].map(tag => ('<button class="btn btn-sm btn-light d-inline-block mr-1 mb-1" onclick="fillTag([\'<?= $category ?>\', \'' + tag + '\'])">' + tag + '</button>')).join(' '),
sanitizeFn(content) {
return content;
},
}).on("mouseenter", function() {
var _this = this;
$(this).popover("show");
$(this).siblings(".popover").on("mouseleave", function() {
$(_this).popover('hide');
});
}).on("mouseleave", function() {
var _this = this;
var check_popover_status = function() {
setTimeout(function() {
if (!$(".popover:hover").length) {
$(_this).popover("hide")
} else {
check_popover_status();
}
}, 50);
};
check_popover_status();
});
});
</script>
<?php endforeach ?>
</div>
</div>
<div class="card-footer text-muted small bg-transparent">
将鼠标悬浮至主分类上,点击弹出框中的对应标签即可将其填充至题目标签中。
</div>
</div>
<div class="card mt-3">
<div class="card-header fw-bold">
题目难度
@ -183,7 +262,6 @@ $difficulty_form->runAtServer();
</div>
</div>
</aside>
</div>
<?php echoUOJPageFooter() ?>

View File

@ -52,6 +52,246 @@ class UOJProblem {
3500 => '#aa0000',
];
public static array $categories = [
'算法基础' => [
'暴力',
'枚举',
'模拟',
'递归与分治',
'贪心',
'排序',
'前缀和与差分',
'二分',
'倍增',
'构造',
'打表',
],
'搜索' => [
'深度优先搜索',
'广度优先搜索',
'双向搜索',
'启发式搜索',
'A*',
'IDA*',
'迭代加深',
'回溯法',
'Dancing Links',
],
'动态规划' => [
'记忆化搜索',
'线性 DP',
'背包 DP',
'区间 DP',
'树形 DP',
'状压 DP',
'数位 DP',
'DAG 上 DP',
'插头 DP',
'概率 DP',
'单调队列优化 DP',
'斜率优化 DP',
'四边形不等式优化 DP',
],
'计算几何' => [
'Pick 定理',
'三角剖分',
'凸包',
'扫描线',
'旋转卡壳',
'半平面交',
'平面最近点对',
'随机增量法',
'反演变换',
],
'数学' => [
'位运算',
'快速幂',
'高精度',
'生成函数',
'指数生成函数',
'向量',
'矩阵',
'高斯消元',
'线性基',
'线性规划',
'容斥',
'组合计数',
'离散对数',
'单纯形算法',
'概率',
'置换群',
'斐波那契数列',
'牛顿迭代法',
'数值积分',
'分块打表',
],
'数论' => [
'最大公约数',
'分解质因数',
'欧拉函数',
'筛法',
'欧拉定理',
'费马小定理',
'类欧几里得算法',
'翡蜀定理',
'乘法逆元',
'线性同余方程',
'Meissel-Lehmer 算法',
'二次剩余',
'BSGS',
'原根',
'卢卡斯定理',
'莫比乌斯反演',
'拉格朗日反演',
'杜教筛',
'Powerful Number 筛',
'Min_25 筛',
'洲阁筛',
'连分数',
'Stern-Brocot 数与 Farey 序列',
'Pell 方程',
],
'字符串' => [
'字符串哈希',
'字典树',
'KMP',
'Boyer-Moore',
'Z 函数(扩展 KMP',
'AC 自动机',
'后缀数组',
'后缀自动机',
'后缀平衡树',
'广义后缀自动机',
'Manacher',
'回文树',
'序列自动机',
'最小表示法',
'Lyndon 分解',
],
'图论' => [
'拓扑排序',
'最短路',
'K 短路',
'同余最短路',
'虚树',
'树分治',
'动态树分治',
'树哈希',
'树上启发式合并',
'AHU 算法',
'矩阵树定理',
'最小生成树',
'最小树形图',
'最小直径生成树',
'斯坦纳树',
'拆点',
'差分约束',
'强连通分量',
'双连通分量',
'割点与桥',
'圆方树',
'2-SAT',
'欧拉图',
'哈密顿图',
'最小环',
'平面图',
'网络流',
'最大流',
'最小割',
'费用流',
'上下界网络流',
'Stoer-Wagner 算法',
'二分图',
'二分图最大匹配',
'二分图最大权匹配',
'一般图最大匹配',
'一般图最大权匹配',
'Prufer 序列',
'LGV 引理',
'弦图',
],
'组合数学' => [
'排列组合',
'卡特兰数',
'斯特林数',
'贝尔数',
'伯努利数',
'康托展开',
'容斥原理',
'抽屉原理',
'欧拉数',
],
'数据结构' => [
'栈',
'队列',
'链表',
'哈希表',
'并查集',
'二叉堆',
'配对堆',
'树状数组',
'线段树',
'平衡树',
'左偏树',
'块状数组',
'块状链表',
'树分块',
'Sqrt Tree',
'可持久化数据结构',
'单调栈',
'单调队列',
'ST 表',
'树套树',
'李超线段树',
'区间最值操作与区间历史最值',
'划分树',
'跳表',
'K-D Tree',
'珂朵莉树',
'动态树',
'析合树',
],
'多项式' => [
'拉格朗日插值',
'快速傅里叶变换',
'快速数论变换',
'快速沃尔什变换',
'多项式求逆',
'多项式开方',
'多项式除法与取模',
'多项式对数函数与指数函数',
'多项式牛顿迭代',
'多项式多点求值与快速插值',
'多项式三角函数',
'多项式反三角函数',
'常系数齐次线性递推',
],
'博弈论' => [
'不平等博弈',
'SG 函数',
'Nim 游戏',
'Anti-Nim',
'纳什均衡',
],
'杂项' => [
'构造',
'离散化',
'CDQ 分治',
'整体二分',
'分块',
'莫队',
'分数规划',
'随机化',
'模拟退火',
'爬山法',
'悬线法',
'编译原理',
'复杂度分析',
'语义分析',
'底层优化',
],
];
public static function query($id) {
if (!isset($id) || !validateUInt($id)) {
return null;

View File

@ -1109,6 +1109,11 @@ $(document).ready(function() {
[...document.querySelectorAll('[data-bs-toggle="tooltip"]')].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl));
});
// Popovers
$(document).ready(function() {
[...document.querySelectorAll('[data-bs-toggle="popover"]')].map(popoverTriggerEl => new bootstrap.Popover(popoverTriggerEl));
});
// Copy button
$(document).ready(function() {
$('.markdown-body pre, .copy-button-container pre').each(function () {