1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

VSCodeでMarkdownのソースコードをコピーできるようにする

Last updated at Posted at 2025-08-05

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>
コピーできるようになる

image.png

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?