GreasyFork Code: Monaco Editor

12/17/2023, 2:31:22 PM

目前为 2023-12-17 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name GreasyFork Code: Monaco Editor
  3. // @namespace Violentmonkey Scripts
  4. // @match https://greasyfork.org/*
  5. // @grant none
  6. // @version 0.1.4
  7. // @author CY Fung
  8. // @description 12/17/2023, 2:31:22 PM
  9. // @run-at document-start
  10. // @unwrap
  11. // @license MIT
  12. // ==/UserScript==
  13.  
  14. // localStorage.darkMode = 'true'
  15. // localStorage.autoMonacoEditor = 'true'
  16.  
  17. (() => {
  18.  
  19. const vsPath = "https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.45.0/min/vs";
  20.  
  21. const cssText01 = `
  22. .monaco-editor-container{
  23. margin: 0;
  24. padding: 0;
  25. box-sizing: border-box;
  26. display: none;
  27. }
  28. [monaco-editor-status="1"] .monaco-editor-container{
  29. display: block;
  30. }
  31. [monaco-editor-status="1"] .monaco-controlled-textarea{
  32. display: none;
  33. }
  34. [monaco-editor-status="2"] .monaco-editor-container{
  35. display: none;
  36. }
  37. [monaco-editor-status="2"] .monaco-controlled-textarea{
  38. display: block;
  39. }
  40. `;
  41.  
  42. const elmSet = {};
  43.  
  44. HTMLInputElement.prototype.addEventListener177 = HTMLInputElement.prototype.addEventListener;
  45. HTMLInputElement.prototype.addEventListener = function () {
  46. if (arguments.length === 2 && arguments[0] === 'change' && (arguments[1] || 0).name === 'handleChange') {
  47. // if(this === ) return;
  48. // console.log(this)
  49. if (this.id === 'enable-source-editor-code') return;
  50. // return;
  51. }
  52. return this.addEventListener177.apply(this, arguments);
  53.  
  54. }
  55.  
  56.  
  57. function loadResource(type, url) {
  58. if (type === 'css') {
  59. return new Promise(resolve => {
  60. var link = document.createElement('link');
  61. var onload = function () {
  62. link.removeEventListener('load', onload, false);
  63. resolve();
  64. }
  65. link.addEventListener('load', onload, false);
  66. link.rel = 'stylesheet';
  67. link.href = url;
  68. document.head.appendChild(link);
  69. });
  70. } else if (type === 'js') {
  71. return new Promise(resolve => {
  72. var script = document.createElement('script');
  73. var onload = function () {
  74. script.removeEventListener('load', onload, false);
  75. resolve();
  76. }
  77. script.addEventListener('load', onload, false);
  78. script.src = url;
  79. document.head.appendChild(script);
  80. })
  81. }
  82. }
  83.  
  84. function onChange817(e) {
  85.  
  86.  
  87.  
  88. // console.log(123213)
  89.  
  90. const target = (e || 0).target || null;
  91.  
  92. if (!target) return;
  93.  
  94. let monacoStatus = target.getAttribute('monaco-status')
  95. if (monacoStatus) {
  96.  
  97. e.stopImmediatePropagation();
  98. e.stopPropagation();
  99. e.preventDefault();
  100.  
  101. const textAreaParent = elmSet.textAreaParent;
  102. const textArea = elmSet.textArea;
  103. const editor = elmSet.editor;
  104.  
  105. // console.log(monacoStatus)
  106. if (monacoStatus === '1') {
  107. // elmSet.container.replaceWith(elmSet.textArea);
  108.  
  109.  
  110.  
  111. textAreaParent.setAttribute('monaco-editor-status', '2')
  112. target.setAttribute('monaco-status', monacoStatus = '2')
  113. return;
  114.  
  115. } else if (monacoStatus === '2') {
  116.  
  117. // elmSet.textArea.replaceWith(elmSet.container);
  118.  
  119. const currentCode = editor.getValue();
  120. const currentText = textArea.value;
  121. if (currentCode !== currentText) {
  122. editor.setValue(currentText);
  123. }
  124.  
  125. textAreaParent.setAttribute('monaco-editor-status', '1')
  126. target.setAttribute('monaco-status', monacoStatus = '1')
  127. return;
  128. } else {
  129. return;
  130. }
  131.  
  132. }
  133.  
  134. const codeId = target.getAttribute('data-related-editor') || '';
  135. if (!codeId) return;
  136.  
  137. const textArea = document.getElementById(codeId);
  138.  
  139. if (!textArea) return;
  140.  
  141. const codeLang = target.getAttribute('data-editor-language'); // 'javascript', 'css'
  142.  
  143. if (!codeLang) return;
  144.  
  145.  
  146. target.setAttribute('monaco-status', '1');
  147.  
  148.  
  149. e.stopImmediatePropagation();
  150. e.stopPropagation();
  151. e.preventDefault();
  152.  
  153.  
  154. // Setting up Monaco Editor requirements
  155. let require = {
  156. paths: {
  157. vs: vsPath,
  158. },
  159. };
  160.  
  161. window.require = (window.require || {});
  162. window.require.paths = (window.require.paths || {});
  163. Object.assign(window.require.paths, require.paths);
  164.  
  165.  
  166. const addCssText = (id, text) => {
  167. if (document.getElementById(id)) return;
  168. const style = document.createElement('style');
  169. style.id = id;
  170. style.textContent = text;
  171. document.head.appendChild(style);
  172.  
  173. }
  174.  
  175.  
  176. (async function () {
  177.  
  178. // Dynamically load CSS and JS
  179. await loadResource('css', `${vsPath}/editor/editor.main.css`);
  180. await loadResource('js', `${vsPath}/loader.js`);
  181. await loadResource('js', `${vsPath}/editor/editor.main.nls.js`);
  182. await loadResource('js', `${vsPath}/editor/editor.main.js`);
  183.  
  184. addCssText('rmbnctzOOksi', cssText01);
  185.  
  186. monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
  187. allowNonTsExtensions: true,
  188. checkJs: true,
  189. });
  190.  
  191. const container = document.createElement('div');
  192. container.className = 'monaco-editor-container';
  193. container.style.height = textArea.getBoundingClientRect().height + 'px';
  194. // textArea.replaceWith(container);
  195. textArea.classList.add('monaco-controlled-textarea');
  196. const textAreaParent = elmSet.textAreaParent = textArea.parentNode;
  197. textAreaParent.setAttribute('monaco-editor-status', '1');
  198. textAreaParent.insertBefore(container, textArea.nextSibling);
  199.  
  200. elmSet.textArea = textArea;
  201. elmSet.container = container;
  202.  
  203. const monacoLangs = {
  204. 'javascript': 'javascript',
  205. 'css': 'css',
  206. };
  207.  
  208. const monacoLang = monacoLangs[codeLang];
  209.  
  210.  
  211. const editor = monaco.editor.create(container, {
  212. value: textArea.value,
  213. language: monacoLang,
  214. automaticLayout: true,
  215. foldingStrategy: 'indentation',
  216. lineNumbers: 'on',
  217. readOnly: false,
  218. minimap: {
  219. enabled: false,
  220. },
  221. cursorStyle: 'line',
  222. });
  223.  
  224. elmSet.editor = editor;
  225.  
  226. if (document.documentElement.hasAttribute('dark')) monaco.editor.setTheme("vs-dark");
  227.  
  228. editor.onDidChangeModelContent(e => {
  229. elmSet.textArea.value = editor.getValue()
  230. });
  231.  
  232.  
  233. // console.log(monaco, monaco.onDidChangeModelContent)
  234.  
  235. // window.editor.getModel().onDidChangeContent((event) => {
  236. // render();
  237. // });
  238.  
  239. // editor.setTheme
  240.  
  241. // onDidChangeContent is attached to a model, and will only apply to that model
  242. // onDidChangeModelContent
  243.  
  244.  
  245.  
  246. })();
  247.  
  248.  
  249. }
  250.  
  251. function onReady() {
  252. window.removeEventListener("DOMContentLoaded", onReady, false);
  253.  
  254. const jsResources = [
  255. `${vsPath}/loader.js`,
  256. `${vsPath}/editor/editor.main.nls.js`,
  257. `${vsPath}/editor/editor.main.js`,
  258. ];
  259.  
  260.  
  261. const template = document.createElement('template');
  262.  
  263. for (const url of jsResources) {
  264. const link = document.createElement('link');
  265. link.setAttribute('rel', 'prefetch');
  266. link.setAttribute('as', 'script');
  267. link.setAttribute('href', url);
  268. template.content.appendChild(link)
  269. document.head.appendChild(template.content);
  270. }
  271.  
  272. if (localStorage.darkMode === 'true') document.documentElement.setAttribute('dark', '')
  273.  
  274. const checkerbox = document.querySelector('input#enable-source-editor-code[name="enable-source-editor-code"]');
  275.  
  276. if(checkerbox){
  277. checkerbox.addEventListener('change', onChange817, { once: false, capture: true, passive: false });
  278. if(localStorage.autoMonacoEditor === 'true' && requestIdleCallback){
  279. requestIdleCallback(()=>{
  280. if(checkerbox.checked === false && checkerbox.isConnected) checkerbox.click();
  281. });
  282.  
  283. }
  284. }
  285.  
  286.  
  287. }
  288.  
  289.  
  290. Promise.resolve().then(() => {
  291.  
  292. if (document.readyState !== 'loading') {
  293. onReady();
  294. } else {
  295. window.addEventListener("DOMContentLoaded", onReady, false);
  296. }
  297.  
  298. });
  299.  
  300. })();