Greasy Fork 还支持 简体中文。

Expand Code to Fullscreen on StackExchange Site

Toggle fullscreen for code blocks on hover

目前為 2024-05-24 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name Expand Code to Fullscreen on StackExchange Site
  3. // @namespace http://tampermonkey.net/
  4. // @author aspen138
  5. // @version 0.1.3
  6. // @description Toggle fullscreen for code blocks on hover
  7. // @match *://*.stackexchange.com/*
  8. // @match *://*.stackoverflow.com/questions/*
  9. // @match *://superuser.com/questions/*
  10. // @match *://meta.superuser.com/questions/*
  11. // @match *://serverfault.com/questions/*
  12. // @match *://meta.serverfault.com/questions/*
  13. // @match *://askubuntu.com/questions/*
  14. // @match *://meta.askubuntu.com/questions/*
  15. // @match *://mathoverflow.net/questions/*
  16. // @match *://meta.mathoverflow.net/questions/*
  17. // @match *://*.stackexchange.com/questions/*
  18. // @match *://answers.onstartups.com/questions/*
  19. // @match *://meta.answers.onstartups.com/questions/*
  20. // @match *://stackapps.com/questions/*
  21. // @match *://*.stackoverflow.com/review/*
  22. // @match *://superuser.com/review/*
  23. // @match *://meta.superuser.com/review/*
  24. // @match *://serverfault.com/review/*
  25. // @match *://meta.serverfault.com/review/*
  26. // @match *://askubuntu.com/review/*
  27. // @match *://meta.askubuntu.com/review/*
  28. // @match *://mathoverflow.net/review/*
  29. // @match *://meta.mathoverflow.net/review/*
  30. // @match *://*.stackexchange.com/review/*
  31. // @match *://answers.onstartups.com/review/*
  32. // @match *://meta.answers.onstartups.com/review/*
  33. // @match *://stackapps.com/review/*
  34. // @match *://*.stackoverflow.com/search*
  35. // @match *://superuser.com/search*
  36. // @match *://meta.superuser.com/search*
  37. // @match *://serverfault.com/search*
  38. // @match *://meta.serverfault.com/search*
  39. // @match *://askubuntu.com/search*
  40. // @match *://meta.askubuntu.com/search*
  41. // @match *://mathoverflow.net/search*
  42. // @match *://meta.mathoverflow.net/search*
  43. // @match *://*.stackexchange.com/search*
  44. // @match *://answers.onstartups.com/search*
  45. // @match *://meta.answers.onstartups.com/search*
  46. // @match *://stackapps.com/search*
  47. // @grant none
  48. // @license MIT
  49. // ==/UserScript==
  50.  
  51.  
  52.  
  53. function Toast(msg, duration) {
  54. let p1 = new Promise((resolve,reject)=>{
  55. duration = isNaN(duration) ? 3000 : duration;
  56. var m = document.createElement('div');
  57. m.innerHTML = msg;
  58. m.style.cssText = "font-family:siyuan;max-width:60%;min-width: 150px;padding:0 14px;height: 40px;color: rgb(255, 255, 255);line-height: 40px;text-align: center;border-radius: 4px;position: fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);z-index: 999999;background: rgba(0, 0, 0,.7);font-size: 16px;";
  59. document.body.appendChild(m);
  60. setTimeout(function() {
  61. var d = 0.5;
  62. m.style.webkitTransition = '-webkit-transform ' + d + 's ease-in, opacity ' + d + 's ease-in';
  63. m.style.opacity = '0';
  64. setTimeout(function() {
  65. document.body.removeChild(m)
  66. }, d * 1000);
  67. }, duration);
  68. });
  69. }
  70.  
  71.  
  72.  
  73. (function() {
  74. 'use strict';
  75.  
  76. // Function to inject styles
  77. function addStyles() {
  78. const style = document.createElement('style');
  79. style.type = 'text/css';
  80. style.innerHTML = `
  81. .code-wrapper {
  82. position: relative;
  83. }
  84. .button {
  85. position: absolute;
  86. top: 0;
  87. z-index: 10;
  88. padding: 4px 8px;
  89. background-color: #eee;
  90. border: none;
  91. cursor: pointer;
  92. border-radius: 4px;
  93. font-size: 12px;
  94. display: none;
  95. }
  96. .fullscreen-btn {
  97. right: 0;
  98. }
  99. .copy-btn {
  100. right: 80px; /* Adjust based on the size of the fullscreen button */
  101. }
  102. .button:hover {
  103. background-color: #ddd;
  104. }
  105. .code-wrapper:hover .button {
  106. display: block;
  107. }
  108. .code-wrapper.fullscreen {
  109. background: white;
  110. color: black;
  111. width: 100%;
  112. height: 100%;
  113. overflow: auto;
  114. margin: 0;
  115. padding: 20px;
  116. }
  117. .code-wrapper.fullscreen .hljs {
  118. display: block;
  119. overflow-x: auto;
  120. padding: 0.5em;
  121. color: inherit;
  122. background: inherit;
  123. }
  124. `;
  125. document.head.appendChild(style);
  126. }
  127.  
  128. // Function to toggle fullscreen for the specific code block
  129. function toggleFullScreen(codeWrapper) {
  130. if (!document.fullscreenElement && codeWrapper.requestFullscreen) {
  131. codeWrapper.requestFullscreen().then(() => {
  132. codeWrapper.classList.add('fullscreen');
  133. codeWrapper.querySelector('code').classList.forEach(cls => {
  134. codeWrapper.classList.add(cls);
  135. });
  136. });
  137. } else if (document.fullscreenElement && document.exitFullscreen) {
  138. document.exitFullscreen().then(() => {
  139. codeWrapper.classList.remove('fullscreen');
  140. codeWrapper.querySelector('code').classList.forEach(cls => {
  141. codeWrapper.classList.remove(cls);
  142. });
  143. });
  144. }
  145. }
  146.  
  147. // Function to copy code to clipboard
  148. function copyToClipboard(codeWrapper) {
  149. const code = codeWrapper.querySelector('code').innerText;
  150. navigator.clipboard.writeText(code).then(() => {
  151. console.log('Code copied to clipboard!');
  152. Toast("Code copied to clipboard!", 100);
  153.  
  154. // codeWrapper.textContent="Copied";
  155. // setTimeout( ()=>copyBtn.textContent="Copy", 1*1000);
  156.  
  157. }).catch(err => {
  158. console.error('Error copying code to clipboard: ', err);
  159. });
  160. }
  161.  
  162. // Function to create fullscreen and copy buttons for each code block
  163. function addButtons() {
  164. document.querySelectorAll('pre code').forEach((code) => {
  165. let wrapper = code.closest('.code-wrapper');
  166. if (!wrapper) {
  167. wrapper = document.createElement('div');
  168. wrapper.classList.add('code-wrapper');
  169. code.classList.forEach(cls => {
  170. if (cls !== 'hljs') {
  171. wrapper.classList.add(cls);
  172. }
  173. });
  174. code.parentNode.insertBefore(wrapper, code);
  175. wrapper.appendChild(code);
  176. }
  177.  
  178. if (!wrapper.querySelector('.fullscreen-btn')) {
  179. const fullscreenBtn = document.createElement('button');
  180. fullscreenBtn.textContent = 'Fullscreen';
  181. fullscreenBtn.classList.add('fullscreen-btn', 'button');
  182. fullscreenBtn.addEventListener('click', () => toggleFullScreen(wrapper));
  183. wrapper.appendChild(fullscreenBtn);
  184. }
  185.  
  186. // Add copy button
  187. if (!wrapper.querySelector('.copy-btn')) {
  188. const copyBtn = document.createElement('button');
  189. copyBtn.textContent = 'Copy';
  190. copyBtn.classList.add('copy-btn', 'button');
  191. copyBtn.addEventListener('click', () => copyToClipboard(wrapper));
  192. wrapper.appendChild(copyBtn);
  193. }
  194. });
  195. }
  196.  
  197. // Wait for the DOM to be fully loaded
  198. window.addEventListener('load', function() {
  199. addStyles();
  200. setTimeout(addButtons, 0);
  201. });
  202. })();