GreasyFork Code: Syntax Highlight by CodeMirror

To syntax highlight GreasyFork Code by CodeMirror

As of 2023-11-18. See the latest version.

  1. // ==UserScript==
  2. // @name GreasyFork Code: Syntax Highlight by CodeMirror
  3. // @namespace Violentmonkey Scripts
  4. // @match https://greatest.deepsurf.us/*
  5. // @grant none
  6. // @version 0.2.5
  7. // @author CY Fung
  8. // @description To syntax highlight GreasyFork Code by CodeMirror
  9. // @run-at document-start
  10. // @inject-into page
  11. // @unwrap
  12. // @license MIT
  13. // ==/UserScript==
  14.  
  15. (() => {
  16. let byPass = true;
  17.  
  18. let documentReady = new Promise(resolve => {
  19. Promise.resolve().then(() => {
  20. if (document.readyState !== 'loading') {
  21. resolve();
  22. } else {
  23. window.addEventListener("DOMContentLoaded", resolve, false);
  24. }
  25. });
  26. });
  27.  
  28. // Function to load CodeMirror library
  29. function loadCodeMirror(arr) {
  30.  
  31.  
  32. const promises = arr.map((href) => {
  33. return new Promise(resolve => {
  34.  
  35. const script = document.createElement('script');
  36. script.src = href;
  37. script.onload = () => {
  38. resolve(script);
  39. };
  40. document.head.appendChild(script);
  41.  
  42. });
  43.  
  44.  
  45. });
  46.  
  47. return Promise.all(promises);
  48. }
  49.  
  50. // Function to load CodeMirror CSS
  51. function loadCodeMirrorCSS(href) {
  52. const link = document.createElement('link');
  53. link.rel = 'stylesheet';
  54. link.href = href;
  55. document.head.appendChild(link);
  56. }
  57.  
  58. async function runBlock(codeBlock) {
  59.  
  60. let textarea = document.createElement('textarea');
  61. textarea.value = `${codeBlock.textContent}`;
  62. textarea.readOnly = true;
  63. textarea.id = 'editor651';
  64.  
  65.  
  66. // textarea.classList.add('code-container')
  67.  
  68. textarea.style.width = '100%';
  69. textarea.style.height = '100vh';
  70.  
  71.  
  72. codeBlock.replaceWith(textarea);
  73. codeBlock.remove();
  74.  
  75.  
  76. let editor651 = CodeMirror.fromTextArea(document.querySelector('#editor651'), {
  77.  
  78. mode: "javascript",
  79.  
  80. readOnly: true,
  81. styleActiveLine: true,
  82. lineNumbers: true,
  83. extraKeys: { "Alt-F": "findPersistent" }
  84. });
  85. editor651.save();
  86.  
  87.  
  88. }
  89.  
  90. // Main function to apply CodeMirror syntax highlighting to pre elements
  91. async function applyCodeMirrorSyntaxHighlighting() {
  92.  
  93. if (window.requestIdleCallback) await new Promise(r => !!window.requestIdleCallback(r));
  94. else {
  95. await new Promise(r => !!window.requestAnimationFrame(r));
  96. await new Promise(r => !!window.setTimeout(r, 170));
  97. await new Promise(r => !!window.requestAnimationFrame(r));
  98. }
  99.  
  100. const codeBlocks = document.querySelectorAll('pre.prettyprint.linenums.lang-js');
  101.  
  102.  
  103. // Check if CodeMirror is loaded
  104. if (typeof CodeMirror !== 'undefined') {
  105.  
  106. for (const codeBlock of codeBlocks) {
  107.  
  108. await new Promise((resolve) => {
  109.  
  110. let io = new IntersectionObserver(() => {
  111.  
  112. io.disconnect();
  113. io.takeRecords();
  114. io = null;
  115. resolve();
  116.  
  117.  
  118. })
  119.  
  120. io.observe(codeBlock);
  121.  
  122. });
  123.  
  124. await runBlock(codeBlock);
  125.  
  126.  
  127. }
  128.  
  129.  
  130.  
  131. } else {
  132. console.error('CodeMirror library is not loaded. Syntax highlighting cannot be applied.');
  133. }
  134. }
  135.  
  136. async function doAction() {
  137.  
  138. await new Promise(r => setTimeout(r, 1));
  139.  
  140. document.head.appendChild(document.createElement('style')).textContent = `
  141.  
  142. .code-container{
  143. height:100vh;
  144. }
  145. .code-container .CodeMirror, .code-container textarea{
  146. height:100%;
  147. }
  148. /*
  149. body {
  150. display: flex;
  151. flex-direction: column;
  152. height: 100vh;
  153. }
  154. body > div:last-child {
  155. height:0;
  156. flex-grow:1;
  157. display: flex;
  158. flex-direction:column;
  159. }
  160. body > div:last-child > #script-info:last-child {
  161. height:0;
  162. flex-grow:1;
  163. display: flex;
  164. flex-direction:column;
  165. }
  166. body > div:last-child > #script-info:last-child > #script-content:last-child {
  167. height:0;
  168. flex-grow:1;
  169. display: flex;
  170. flex-direction:column;
  171. gap:2px;
  172. }
  173. body > div:last-child > #script-info:last-child > #script-content:last-child > * {
  174. margin:0;
  175. }
  176. body > div:last-child > #script-info:last-child > #script-content:last-child > .code-container:last-child {
  177. height:0;
  178. flex-grow:1;
  179. display: flex;
  180. flex-direction:column;
  181. }
  182. body > div:last-child > #script-info:last-child > #script-content:last-child > .code-container:last-child > textarea:last-child {
  183. height:0;
  184. flex-grow:1;
  185. display: flex;
  186. flex-direction:column;
  187. }
  188. body > div:last-child > #script-info:last-child > #script-content:last-child > .code-container:last-child > .CodeMirror:last-child {
  189. height:0;
  190. flex-grow:1;
  191. display: flex;
  192. flex-direction:column;
  193. }
  194. */
  195. `;
  196.  
  197. await loadCodeMirror(['https://cdn.jsdelivr.net/npm/codemirror@5.65.15/lib/codemirror.min.js']);
  198.  
  199. await loadCodeMirror([
  200. 'https://cdn.jsdelivr.net/npm/codemirror@5.65.15/mode/javascript/javascript.min.js',
  201. 'https://cdn.jsdelivr.net/npm/codemirror@5.65.15/addon/selection/active-line.min.js',
  202.  
  203.  
  204. 'https://cdn.jsdelivr.net/npm/codemirror@5.65.15/addon/search/search.js',
  205. 'https://cdn.jsdelivr.net/npm/codemirror@5.65.15/addon/search/searchcursor.js',
  206. 'https://cdn.jsdelivr.net/npm/codemirror@5.65.15/addon/search/jump-to-line.js',
  207. 'https://cdn.jsdelivr.net/npm/codemirror@5.65.15/addon/dialog/dialog.js'
  208.  
  209. ]);
  210.  
  211. loadCodeMirrorCSS('https://cdn.jsdelivr.net/npm/codemirror@5.65.15/lib/codemirror.min.css');
  212. loadCodeMirrorCSS('https://cdn.jsdelivr.net/npm/codemirror@5.65.15/addon/dialog/dialog.css');
  213.  
  214. await Promise.all([new Promise(r => setTimeout(r, 60)), new Promise(r => window.requestAnimationFrame(r))]);
  215.  
  216.  
  217. byPass = false;
  218.  
  219. applyCodeMirrorSyntaxHighlighting();
  220.  
  221.  
  222.  
  223.  
  224.  
  225.  
  226. }
  227.  
  228.  
  229. let mgg = 0;
  230. async function mTz() {
  231. if (mgg) return;
  232. mgg = 1;
  233. documentReady.then(doAction);
  234. }
  235.  
  236.  
  237.  
  238. function getElementsByTagName(tag) {
  239.  
  240. if (byPass) {
  241. if (tag === 'pre' || tag === 'code' || tag === 'xmp') {
  242. if (location.pathname.endsWith('/code')) {
  243.  
  244. setTimeout(mTz, 10)
  245. return [];
  246. }
  247. }
  248. }
  249. return this.getElementsByTagName331(tag);
  250. }
  251.  
  252.  
  253.  
  254. HTMLElement.prototype.getElementsByTagName331 = HTMLElement.prototype.getElementsByTagName
  255. Document.prototype.getElementsByTagName331 = Document.prototype.getElementsByTagName
  256.  
  257. HTMLElement.prototype.getElementsByTagName = getElementsByTagName
  258. Document.prototype.getElementsByTagName = getElementsByTagName
  259.  
  260. /*
  261. let mz= function(evt){
  262.  
  263. if(evt && evt.type ==='readystatechange') return;
  264. return EventTarget.prototype.addEventListener.apply(this,arguments)
  265.  
  266. };
  267. window.addEventListener = mz
  268. document.addEventListener = mz;
  269. */
  270.  
  271.  
  272. documentReady.then(async () => {
  273.  
  274. if (location.pathname.endsWith('/code')) return;
  275.  
  276. byPass = false;
  277.  
  278. });
  279.  
  280. })();