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