GreasyFork Code: Syntax Highlight by CodeMirror

To syntax highlight GreasyFork Code by CodeMirror

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