feat(problem): add copy button to markdown code blocks

Add a copy button to markdown code blocks in the problem view for easier code snippet copying. The button appears in the top-right corner of code blocks and provides visual feedback on copy success or failure. This improves user experience by eliminating the need to manually select and copy code.
This commit is contained in:
2026-03-13 19:32:38 +08:00
parent 3256c00dcd
commit 055223bfdf

View File

@@ -33,6 +33,29 @@ if ($pr_flag) {
cursor: pointer;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05), 0 2px 4px rgba(0, 0, 0, 0.05);
}
.md pre {
position: relative;
}
.md-code-copy {
position: absolute;
top: 8px;
right: 8px;
z-index: 1;
font-size: 12px;
color: #4d4d4d;
background-color: #fff;
border: 1px solid #e0e0e0;
padding: 2px 8px;
border-radius: 4px;
cursor: pointer;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.md-code-copy:hover {
background-color: #f5f5f5;
}
</style>
<script src="<?php echo $OJ_CDN_URL . $path_fix . "template/$OJ_TEMPLATE/" ?>clipboard.min.js"></script>
<script src="<?php echo $OJ_CDN_URL . $path_fix . "template/bs3/" ?>marked.min.js"></script>
@@ -501,6 +524,56 @@ if ($pr_flag) {
$(document).ready(function () {
$("#creator").load("problem-ajax.php?pid=<?php echo $id ?>");
function copyText(content, onSuccess, onFail) {
if (navigator.clipboard && window.isSecureContext) {
navigator.clipboard.writeText(content).then(onSuccess).catch(onFail);
return;
}
const textarea = document.createElement('textarea');
textarea.value = content;
textarea.style.position = 'fixed';
textarea.style.left = '-9999px';
document.body.appendChild(textarea);
textarea.focus();
textarea.select();
try {
const copied = document.execCommand('copy');
copied ? onSuccess() : onFail();
} catch (err) {
onFail();
}
document.body.removeChild(textarea);
}
function initMarkdownCodeCopy() {
$('.md pre').each(function () {
const pre = $(this);
if (pre.find('.md-code-copy').length > 0) return;
const btn = $('<button type="button" class="md-code-copy"><?php echo $MSG_COPY; ?></button>');
btn.on('click', function () {
const code = pre.find('code').first();
const text = code.length > 0 ? code.text() : pre.text();
const currentBtn = $(this);
copyText(
text,
function () {
currentBtn.text('<?php echo $MSG_COPY . $MSG_SUCCESS; ?>!');
setTimeout(function () { currentBtn.text('<?php echo $MSG_COPY; ?>'); }, 1500);
},
function () {
currentBtn.text('<?php echo $MSG_COPY . $MSG_FAIL; ?>!');
setTimeout(function () { currentBtn.text('<?php echo $MSG_COPY; ?>'); }, 1500);
}
);
});
pre.prepend(btn);
});
}
<?php if (isset($OJ_MARKDOWN) && $OJ_MARKDOWN) { ?>
marked.use({
// 开启异步渲染
@@ -557,6 +630,8 @@ if ($pr_flag) {
"text-align": "center"
});
initMarkdownCodeCopy();
<?php } ?>
//单纯文本1. A. B. C. D. 自动变控件
$('span[class=auto_select]').each(function () {