GitHub Copy Code Snippet

A userscript adds a copy to clipboard button on hover of markdown code snippets

目前為 2020-03-28 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name GitHub Copy Code Snippet
  3. // @version 0.3.5
  4. // @description A userscript adds a copy to clipboard button on hover of markdown code snippets
  5. // @license MIT
  6. // @author Rob Garrison
  7. // @namespace https://github.com/Mottie
  8. // @include https://github.com/*
  9. // @include https://gist.github.com/*
  10. // @run-at document-idle
  11. // @grant GM_addStyle
  12. // @require https://greasyfork.org/scripts/28721-mutations/code/mutations.js?version=666427
  13. // @icon https://github.githubassets.com/pinned-octocat.svg
  14. // ==/UserScript==
  15. (() => {
  16. "use strict";
  17.  
  18. let copyId = 0;
  19. const markdownSelector = ".markdown-body, .markdown-format",
  20. codeSelector = "pre:not(.gh-csc-pre)",
  21.  
  22. copyButton = document.createElement("clipboard-copy");
  23. copyButton.className = "btn btn-sm btn-blue tooltipped tooltipped-w gh-csc-button";
  24. copyButton.setAttribute("aria-label", "Copy to clipboard");
  25. // This hint isn't working yet (GitHub needs to fix it)
  26. copyButton.setAttribute("data-copied-hint", "Copied!");
  27. copyButton.innerHTML = `
  28. <svg aria-hidden="true" class="octicon octicon-clippy" height="16" viewBox="0 0 14 16" width="14">
  29. <path fill-rule="evenodd" d="M2 13h4v1H2v-1zm5-6H2v1h5V7zm2 3V8l-3 3 3 3v-2h5v-2H9zM4.5 9H2v1h2.5V9zM2 12h2.5v-1H2v1zm9 1h1v2c-.02.28-.11.52-.3.7-.19.18-.42.28-.7.3H1c-.55 0-1-.45-1-1V4c0-.55.45-1 1-1h3c0-1.11.89-2 2-2 1.11 0 2 .89 2 2h3c.55 0 1 .45 1 1v5h-1V6H1v9h10v-2zM2 5h8c0-.55-.45-1-1-1H8c-.55 0-1-.45-1-1s-.45-1-1-1-1 .45-1 1-.45 1-1 1H3c-.55 0-1 .45-1 1z"></path>
  30. </svg>`;
  31.  
  32. GM_addStyle(`
  33. .gh-csc-wrap {
  34. position: relative;
  35. }
  36. .gh-csc-wrap:hover .gh-csc-button {
  37. display: block;
  38. }
  39. .gh-csc-button {
  40. display: none;
  41. padding: 3px 6px;
  42. position: absolute;
  43. top: 3px;
  44. right: 3px;
  45. z-index: 20;
  46. }
  47. .gh-csc-wrap.ghd-code-wrapper .gh-csc-button {
  48. right: 31px;
  49. }
  50. .gh-csc-button svg {
  51. vertical-align: text-bottom;
  52. }
  53. `);
  54.  
  55. function addButton(wrap, code) {
  56. if (!wrap.classList.contains("gh-csc-wrap")) {
  57. copyId++;
  58. // See comments from sindresorhus/refined-github/issues/1278
  59. code.id = `gh-csc-${copyId}`;
  60. copyButton.setAttribute("for", `gh-csc-${copyId}`);
  61. wrap.classList.add("gh-csc-wrap");
  62. wrap.insertBefore(copyButton.cloneNode(true), wrap.childNodes[0]);
  63. }
  64. }
  65.  
  66. function init() {
  67. const markdown = document.querySelector(markdownSelector);
  68. if (markdown) {
  69. [...document.querySelectorAll(markdownSelector)].forEach(md => {
  70. [...md.querySelectorAll(codeSelector)].forEach(pre => {
  71. let code = pre.querySelector("code");
  72. let wrap = pre.parentNode;
  73. if (code) {
  74. // pre > code
  75. addButton(pre, code);
  76. } else if (wrap.classList.contains("highlight")) {
  77. // div.highlight > pre
  78. addButton(wrap, pre);
  79. }
  80. });
  81. });
  82. }
  83. }
  84.  
  85. document.addEventListener("ghmo:container", init);
  86. document.addEventListener("ghmo:comments", init);
  87. init();
  88. })();