Greasy Fork is available in English.

gist-copy

Copy gist code with one-click.

  1. // ==UserScript==
  2. // @name gist-copy
  3. // @namespace hakurouken/tamper-scripts/gist-copy
  4. // @version 1.0.1
  5. // @description Copy gist code with one-click.
  6. // @author Hakurouken
  7. // @homepage https://github.com/hakurouken/tamper-scripts/packages/gist-copy
  8. // @supportURL https://github.com/hakurouken/tamper-scripts/issues
  9. // @license MIT
  10. // @run-at document-end
  11. // @match https://gist.github.com/*
  12. // @grant GM_setClipboard
  13. // @grant window.onurlchange
  14. // ==/UserScript==
  15.  
  16. function noop() { }
  17. function debounce(f, delay) {
  18. let timeoutId = null;
  19. return function (...args) {
  20. if (timeoutId) {
  21. clearTimeout(timeoutId);
  22. }
  23. timeoutId = setTimeout(() => {
  24. f.apply(this, args);
  25. }, delay);
  26. };
  27. }
  28. function createCopyButton(fileElement) {
  29. const fileActionElement = fileElement.querySelector('.file-actions');
  30. const source = fileActionElement?.querySelector('a.Button');
  31. const url = source?.href;
  32. if (!url) {
  33. return noop;
  34. }
  35. const dummy = document.createElement('div');
  36. dummy.innerHTML = `
  37. <a class="Button--secondary Button--small Button gist-copy-button">
  38. <span class="Button-content">
  39. <span class="Button-label">Copy</span>
  40. </span>
  41. </a>
  42. `;
  43. const button = dummy.firstElementChild.cloneNode(true);
  44. let lockedTimeoutId = null;
  45. const copyHandler = (e) => {
  46. if (lockedTimeoutId) {
  47. return;
  48. }
  49. e.preventDefault();
  50. const rawContent = fileElement.querySelector('.blob-code-content')
  51. ?.innerText || '';
  52. const content = rawContent
  53. .split('\n')
  54. .map((line) => line.replace(/^\t/, ''))
  55. .join('\n');
  56. GM_setClipboard(content, { type: 'text', mimetype: 'text/plain' });
  57. button.style.filter = 'brightness(0.8)';
  58. button.innerText = 'Copied!';
  59. lockedTimeoutId = setTimeout(() => {
  60. button.style.filter = '';
  61. button.innerText = 'Copy';
  62. lockedTimeoutId = null;
  63. }, 1500);
  64. };
  65. button.addEventListener('click', copyHandler);
  66. fileActionElement.prepend(button);
  67. return () => {
  68. button.removeEventListener('click', copyHandler);
  69. if (lockedTimeoutId) {
  70. clearTimeout(lockedTimeoutId);
  71. }
  72. button.remove();
  73. };
  74. }
  75. function run() {
  76. let removeAllListeners = noop;
  77. function tryCreateCopyButtons() {
  78. removeAllListeners();
  79. const fileElements = [...document.querySelectorAll('.file')];
  80. const removeListeners = fileElements.map(createCopyButton);
  81. removeAllListeners = () => {
  82. removeListeners.map((f) => f());
  83. [...document.querySelectorAll('.gist-copy-button')].forEach((el) => {
  84. el.remove();
  85. });
  86. };
  87. }
  88. window.addEventListener('urlchange', debounce(tryCreateCopyButtons, 16));
  89. }
  90. run();