Greasy Fork Code Copy Button (AFU IT)

Adds a single floating copy button with a notification from code container on Greasy Fork

  1. // ==UserScript==
  2. // @name Greasy Fork Code Copy Button (AFU IT)
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.1
  5. // @description Adds a single floating copy button with a notification from code container on Greasy Fork
  6. // @author AFU IT
  7. // @match https://greasyfork.org/*
  8. // @license MIT
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14.  
  15. // Function to create and add copy buttons
  16. function addCopyButtons() {
  17. // Find all code containers that don't already have a button
  18. const codeContainers = document.querySelectorAll('div.code-container:not(.has-copy-button)');
  19.  
  20. codeContainers.forEach(container => {
  21. // Mark this container as processed
  22. container.classList.add('has-copy-button');
  23.  
  24. // Create the button container
  25. const buttonContainer = document.createElement('div');
  26. buttonContainer.style.display = 'flex';
  27. buttonContainer.style.flexDirection = 'column';
  28. buttonContainer.style.alignItems = 'center';
  29.  
  30. // Create the floating button
  31. const floatingButton = document.createElement('button');
  32. floatingButton.className = 'copy-code-button';
  33. floatingButton.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>';
  34. floatingButton.style.width = '35px';
  35. floatingButton.style.height = '35px';
  36. floatingButton.style.display = 'flex';
  37. floatingButton.style.alignItems = 'center';
  38. floatingButton.style.justifyContent = 'center';
  39. floatingButton.style.backgroundColor = 'rgba(51, 51, 51, 0.7)';
  40. floatingButton.style.color = 'white';
  41. floatingButton.style.border = '1px solid #222';
  42. floatingButton.style.borderRadius = '4px';
  43. floatingButton.style.cursor = 'pointer';
  44. floatingButton.style.zIndex = '1000';
  45. floatingButton.title = 'Copy code';
  46.  
  47. // Create notification text
  48. const notification = document.createElement('div');
  49. notification.textContent = 'Copied!';
  50. notification.style.color = 'white';
  51. notification.style.backgroundColor = 'rgba(51, 51, 51, 0.7)';
  52. notification.style.padding = '2px 5px';
  53. notification.style.borderRadius = '1px';
  54. notification.style.fontSize = '7px';
  55. notification.style.marginTop = '3px';
  56. notification.style.display = 'none';
  57. notification.style.fontWeight = 'normal';
  58. notification.style.letterSpacing = '0.3px';
  59. notification.style.fontFamily = 'Arial, sans-serif';
  60.  
  61. // Add hover effect
  62. floatingButton.addEventListener('mouseenter', function() {
  63. this.style.backgroundColor = 'rgba(51, 51, 51, 1)';
  64. });
  65.  
  66. floatingButton.addEventListener('mouseleave', function() {
  67. this.style.backgroundColor = 'rgba(51, 51, 51, 0.7)';
  68. });
  69.  
  70. // Add click event
  71. floatingButton.addEventListener('click', function() {
  72. const pre = container.querySelector('pre');
  73. if (pre) {
  74. let codeText = '';
  75. const codeLines = pre.querySelectorAll('li');
  76. if (codeLines.length > 0) {
  77. codeLines.forEach(line => {
  78. codeText += line.textContent + '\n';
  79. });
  80. } else {
  81. codeText = pre.textContent;
  82. }
  83.  
  84. navigator.clipboard.writeText(codeText).then(() => {
  85. // Change button icon to tick
  86. floatingButton.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>';
  87.  
  88. // Show notification
  89. notification.style.display = 'block';
  90.  
  91. // Reset after 2 seconds
  92. setTimeout(() => {
  93. floatingButton.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>';
  94. notification.style.display = 'none';
  95. }, 2000);
  96. });
  97. }
  98. });
  99.  
  100. // Add button and notification to container
  101. buttonContainer.appendChild(floatingButton);
  102. buttonContainer.appendChild(notification);
  103.  
  104. // Create a wrapper div for the floating button
  105. const floatingWrapper = document.createElement('div');
  106. floatingWrapper.style.position = 'sticky';
  107. floatingWrapper.style.top = '10px';
  108. floatingWrapper.style.float = 'right';
  109. floatingWrapper.style.marginRight = '10px';
  110. floatingWrapper.style.zIndex = '999';
  111. floatingWrapper.appendChild(buttonContainer);
  112.  
  113. // Insert at the beginning of the container
  114. container.insertBefore(floatingWrapper, container.firstChild);
  115. });
  116. }
  117.  
  118. // Run on page load
  119. setTimeout(addCopyButtons, 1000);
  120.  
  121. // Run again periodically to catch any new code blocks
  122. setInterval(addCopyButtons, 3000);
  123. })();