LeetCode 描述內容複製器

複製 LeetCode 題目描述內容到剪貼簿的輕巧按鈕。

当前为 2025-03-21 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name LeetCode 描述內容複製器
  3. // @namespace https://abc0922001.github.io/leetcode-userscripts
  4. // @version 2.0
  5. // @description 複製 LeetCode 題目描述內容到剪貼簿的輕巧按鈕。
  6. // @author abc0922001
  7. // @match https://leetcode.com/problems/*
  8. // @grant none
  9. // @license MIT
  10. // ==/UserScript==
  11.  
  12. (() => {
  13. 'use strict';
  14.  
  15. /**
  16. * 等待指定元素出現後回傳該元素
  17. * @param {string} selector - CSS 選擇器
  18. * @param {number} timeout - 最長等待毫秒數
  19. * @returns {Promise<Element>}
  20. */
  21. function waitForElement(selector, timeout = 5000) {
  22. return new Promise((resolve, reject) => {
  23. const found = document.querySelector(selector);
  24. if (found) return resolve(found);
  25.  
  26. const observer = new MutationObserver(() => {
  27. const el = document.querySelector(selector);
  28. if (el) {
  29. observer.disconnect();
  30. resolve(el);
  31. }
  32. });
  33.  
  34. observer.observe(document.body, { childList: true, subtree: true });
  35.  
  36. setTimeout(() => {
  37. observer.disconnect();
  38. reject(new Error(`等待元素 "${selector}" 超時 (${timeout}ms)`));
  39. }, timeout);
  40. });
  41. }
  42.  
  43. /**
  44. * 顯示提示訊息
  45. * @param {string} message - 顯示內容
  46. */
  47. function showAlert(message) {
  48. window.alert(message);
  49. }
  50.  
  51. /**
  52. * 將 HTML 內容複製至剪貼簿
  53. * @param {string} content - 要複製的 HTML
  54. */
  55. function copyToClipboard(content) {
  56. navigator.clipboard.writeText(content)
  57. .then(() => showAlert('✅ 描述內容已複製到剪貼簿!'))
  58. .catch(err => showAlert(`❌ 複製失敗:${err.message}`));
  59. }
  60.  
  61. /**
  62. * 初始化按鈕並綁定點擊事件
  63. */
  64. function createCopyButton() {
  65. const button = document.createElement('button');
  66. button.textContent = '📋 複製描述';
  67. Object.assign(button.style, {
  68. position: 'fixed',
  69. top: '10px',
  70. right: '10px',
  71. zIndex: 1000,
  72. padding: '6px 10px',
  73. fontSize: '14px',
  74. backgroundColor: '#2b7de9',
  75. color: '#fff',
  76. border: 'none',
  77. borderRadius: '4px',
  78. cursor: 'pointer',
  79. });
  80.  
  81. button.addEventListener('click', () => {
  82. const selector = 'div.elfjS[data-track-load="description_content"]';
  83. waitForElement(selector)
  84. .then(el => copyToClipboard(el.innerHTML))
  85. .catch(err => {
  86. showAlert('⚠️ 找不到描述內容區塊。');
  87. console.error(err);
  88. });
  89. });
  90.  
  91. document.body.appendChild(button);
  92. }
  93.  
  94. // 🚀 啟動腳本
  95. createCopyButton();
  96. })();