fix(ui): avoid duplicate header copy buttons (#1096)

From PR #1324.

Co-authored-by: Dennis Soong <dso2ng@gmail.com>
This commit is contained in:
nesquena-hermes
2026-04-30 15:24:32 +00:00
parent eb95c6a341
commit 1ccd958e23
2 changed files with 19 additions and 3 deletions

View File

@@ -3712,7 +3712,8 @@ function addCopyButtons(container){
if(!el) return;
el.querySelectorAll('pre > code').forEach(codeEl=>{
const pre=codeEl.parentElement;
if(pre.querySelector('.code-copy-btn')) return;
const header=pre.previousElementSibling;
if(pre.querySelector('.code-copy-btn')||(header&&header.classList.contains('pre-header')&&header.querySelector('.code-copy-btn'))) return;
const btn=document.createElement('button');
btn.className='code-copy-btn';
btn.textContent=t('copy');
@@ -3723,7 +3724,6 @@ function addCopyButtons(container){
setTimeout(()=>{btn.textContent=t('copy');},1500);
}).catch(()=>{btn.textContent=t('copy_failed');setTimeout(()=>{btn.textContent=t('copy');},1500);});
};
const header=pre.previousElementSibling;
if(header&&header.classList.contains('pre-header')){
header.style.display='flex';
header.style.justifyContent='space-between';

View File

@@ -88,12 +88,28 @@ class TestCodeCopyButton:
# Find addCopyButtons function
m = re.search(r"function addCopyButtons", src)
assert m, "addCopyButtons must exist"
fn = src[m.start():m.start() + 800]
fn = src[m.start():m.start() + 1000]
assert "_copyText" in fn, \
"Code copy button must use _copyText function"
assert "codeEl.textContent" in fn, \
"Code copy must copy the code element's textContent"
def test_code_copy_button_is_idempotent_for_header_blocks(self):
"""Repeated post-render passes must not append duplicate header buttons.
addCopyButtons() can be called multiple times after render/cache/streaming
updates. For fenced blocks with a language header, the copy button is
appended to the sibling .pre-header, not inside <pre>, so the duplicate
guard must check the header as well as the <pre>.
"""
src = _src("ui.js")
m = re.search(r"function addCopyButtons", src)
assert m, "addCopyButtons must exist"
fn = src[m.start():m.start() + 1200]
assert "const header=pre.previousElementSibling;" in fn
assert "header.querySelector('.code-copy-btn')" in fn
assert fn.index("header.querySelector('.code-copy-btn')") < fn.index("document.createElement('button')")
class TestCopyFailedI18n:
def test_copy_failed_in_all_locales(self):