Markdown Preview Enhancedをインストール
https://marketplace.visualstudio.com/items?itemName=shd101wyy.markdown-preview-enhanced
Ctrl + Shift + p
Preferences: Open User Settings (JSON)
"markdown-preview-enhanced.enableScriptExecution": true
Ctrl + Shift + p
Markdown Preview Enhanced: Customize Html Head (Grobal)
<!-- The content below will be included at the end of the <head> element. -->
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function () {
// your code here
});
</script>
<style>
pre {
position: relative !important;
margin: 16px 0 !important;
padding-right: 80px !important;
}
.copy-code-btn {
position: absolute !important;
top: 8px !important;
right: 8px !important;
background: #0078d4 !important;
color: white !important;
border: none !important;
padding: 6px 12px !important;
border-radius: 4px !important;
cursor: pointer !important;
font-size: 12px !important;
font-family: inherit !important;
opacity: 0.8 !important;
transition: all 0.2s ease !important;
z-index: 999 !important;
user-select: none !important;
}
.copy-code-btn:hover {
opacity: 1 !important;
background: #106ebe !important;
transform: scale(1.05) !important;
}
.copy-code-btn:active {
transform: scale(0.95) !important;
}
.copy-code-btn.success {
background: #107c10 !important;
}
.copy-code-btn.error {
background: #d13438 !important;
}
pre code {
display: block !important;
padding-right: 60px !important;
}
</style>
<script>
(function() {
'use strict';
console.log('Markdown copy button script loaded');
let isInitialized = false;
function addCopyButton(pre) {
if (pre.querySelector('.copy-code-btn')) {
return;
}
console.log('Adding copy button to:', pre);
const button = document.createElement('button');
button.className = 'copy-code-btn';
button.textContent = 'Copy';
button.setAttribute('type', 'button');
button.setAttribute('title', 'Copy code to clipboard');
button.addEventListener('click', async function(e) {
e.preventDefault();
e.stopPropagation();
console.log('Copy button clicked');
const codeElement = pre.querySelector('code');
const textContent = codeElement ? codeElement.textContent : pre.textContent;
console.log('Code to copy:', textContent.substring(0, 100) + '...');
try {
if (navigator.clipboard && navigator.clipboard.writeText) {
await navigator.clipboard.writeText(textContent);
console.log('Copied using Clipboard API');
} else {
const textarea = document.createElement('textarea');
textarea.value = textContent;
textarea.style.position = 'fixed';
textarea.style.left = '-9999px';
textarea.style.top = '-9999px';
document.body.appendChild(textarea);
textarea.select();
textarea.setSelectionRange(0, 99999);
document.execCommand('copy');
document.body.removeChild(textarea);
console.log('Copied using execCommand');
}
button.textContent = 'Copied!';
button.classList.add('success');
setTimeout(() => {
button.textContent = 'Copy';
button.classList.remove('success');
}, 2000);
} catch (err) {
console.error('Failed to copy:', err);
button.textContent = 'Error';
button.classList.add('error');
setTimeout(() => {
button.textContent = 'Copy';
button.classList.remove('error');
}, 2000);
}
});
pre.appendChild(button);
console.log('Copy button added successfully');
}
function initializeCopyButtons() {
console.log('Initializing copy buttons...');
const preElements = document.querySelectorAll('pre');
console.log('Found pre elements:', preElements.length);
preElements.forEach((pre, index) => {
console.log(`Processing pre element ${index + 1}:`, pre);
addCopyButton(pre);
});
isInitialized = true;
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function() {
console.log('DOM loaded, initializing...');
setTimeout(initializeCopyButtons, 500);
});
} else {
console.log('DOM already loaded, initializing immediately...');
setTimeout(initializeCopyButtons, 500);
}
const observer = new MutationObserver(function(mutations) {
let shouldReinit = false;
mutations.forEach(function(mutation) {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach(function(node) {
if (node.nodeType === 1) { // Element node
if (node.tagName === 'PRE' || node.querySelector('pre')) {
shouldReinit = true;
}
}
});
}
});
if (shouldReinit) {
console.log('Content changed, reinitializing copy buttons...');
setTimeout(initializeCopyButtons, 100);
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
console.log('Mutation observer started');
})();
</script>