- // ==UserScript==
- // @name GreasyFork Code: Syntax Highlight by PrismJS
- // @namespace Violentmonkey Scripts
- // @grant none
- // @version 0.4.2
- // @author CY Fung
- // @description To syntax highlight GreasyFork Code by PrismJS
- // @run-at document-start
- // @inject-into page
- // @unwrap
- // @license MIT
- // @match https://greatest.deepsurf.us/*
- // @match https://sleazyfork.org/*
- //
- // ==/UserScript==
-
-
- (() => {
-
- const USE_SHADOW_MODE = true; // performance fix for long coding
-
- const cdn = 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0';
- const resoruces = {
- 'prism-core.js': `${cdn}/components/prism-core.js`,
- 'prism-clike.js': `${cdn}/components/prism-clike.min.js`,
- 'prism-javascript.js': `${cdn}/components/prism-javascript.min.js`,
- 'prism-css.js': `${cdn}/components/prism-css.min.js`,
- 'prism-stylus.js': `${cdn}/components/prism-stylus.min.js`,
- 'prism.css': `${cdn}/themes/prism.min.css`,
- 'prism-dark.css': `${cdn}/themes/prism-dark.min.css`,
- }
-
- const doActionCSS = () => `
-
- .code-container, .code-container-shadow{
- height:100vh;
- }
- .code-container .CodeMirror, .code-container textarea{
- height:100%;
- }
- `;
-
-
- const global_css = () =>`
-
- html {
- line-height: 1.5;
- -webkit-text-size-adjust: 100%;
- -moz-tab-size: 4;
- -o-tab-size: 4;
- tab-size: 4;
- font-family: ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;
- font-feature-settings: normal;
- font-variation-settings: normal
- }
-
- .code-container code, .code-container kbd, .code-container pre, .code-container samp,
- .code-container-pre, .code-container-pre code, .code-container-pre pre {
- font-family: ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;
- font-size: 1em
- }
-
- #script-content > .code-container[class] {
- width: 100%;
- }
-
- .code-container[class], .code-container-shadow[class] {
- border-radius: 0;
- }
-
- .code-container > pre:only-child, .code-container-pre{
- padding:0;
- }
-
- pre.code-container-pre[class]{
-
- padding: 0;
- border: 0;
- margin: 0;
- }
-
- code.syntax-highlighted[class] {
- font-family: monospace;
- font-size: 13px;
- font-variant-ligatures: contextual;
- line-height: 1.15rem;
- text-shadow: none !important;
- }
-
- .hljs-comment[class], .hljs-quote[class] {
- font-style: inherit;
- color: #259789;
- }
-
- .hljs-add-marker-width .marker-fixed-width[class] {
- user-select: none !important;
- width: calc(var(--hljs-marker-width, 0em) + 16px);
- background: var(--marker-color-background, #f4f4f4);
- padding-right: 6px;
- margin-right: 4px;
- contain: paint style;
- color: var(--marker-color-text, inherit);
- }
-
- .marker-fixed-width[marker-text]::before {
- content:attr(marker-text);
- }
-
- `;
-
-
- const cssForCodePage = () => /\/scripts\/\d+[^\s\/\\]*\/code(\/|$)/.test(location.href) ? `
-
- html:not([dkkfv]) div.code-container {
- display:none;
- }
-
- .code-container,
- .code-container pre:only-child,
- .code-container pre:only-child code:only-child,
- .code-container-pre {
- max-height: calc(100vh + 4px);
- max-width: calc(100vw + 4px);
- }
- ` : '';
-
-
- const cssAdd = () =>`
-
- ${global_css()}
-
- ${cssForCodePage()}
-
- .code-container, .code-container-shadow {
- max-width: 100%;
- display: inline-flex;
- flex-direction: column;
- overflow: auto;
- border-radius: 8px;
- max-height: 100%;
- overflow: visible;
- }
- .code-container > pre:only-child, .code-container-pre {
- max-width: 100%;
- display: inline-flex;
- flex-direction: column;
- flex-grow: 1;
- height: 0;
- }
- .code-container > pre:only-child > code:only-child, .code-container-pre > code:only-child{
- max-width: 100%;
- flex-grow: 1;
- height: 0;
- }
- .code-container pre code, .code-container-pre code {
- padding: 0;
- font-family: Consolas;
- cursor: text;
- overflow: auto;
- box-sizing: border-box;
- }
- .code-container pre code .marker, .code-container-pre code .marker {
- display: inline-block;
- color: #636d83;
- text-align: right;
- padding-right: 20px;
- user-select: none;
- cursor: auto;
- }
-
- .code-container[contenteditable]{
- outline: 0 !important;
- contain: strict;
- box-sizing: border-box;
- }
-
- .code-container[contenteditable]>pre[contenteditable="false"]{
- contain: strict;
- width: initial;
- box-sizing: border-box;
- }
-
-
-
-
- html {
-
- --token-color-keyword: #07a;
- --token-color-punctuation: #1415ec;
- --token-color-comment: #259789;
- --token-color-function: #da204f;
- }
-
- [dark] {
-
- --token-color-keyword: #898af2;
- --token-color-punctuation: #fadbdb;
- --token-color-comment:#59c6b9;
- --token-color-function: #e98aa2;
-
- --marker-color-background: #242424;
- --marker-color-text: #b6b2b2;
-
- }
-
-
- code .token.comment {
- color: var(--token-color-comment);
- }
-
- code .token.atrule, code .token.attr-value, code .token.keyword {
- color: #1415ec;
- color: var(--token-color-keyword);
- }
-
-
- .language-stylus .token.atrule, .language-stylus .token.attr-value, .language-stylus .token.keyword {
- color: #700d0d;
- }
-
-
- code .token.punctuation{
- color: var(--token-color-punctuation);
- }
-
-
- code .token.variable-declaration,
- code .token.variable {
- color: #0d10cd;
- }
-
- code .token.selector{
- color: #1373bb;
- }
-
-
- code .token.function {
- color:var(--token-color-function);
- }
-
-
-
- .language-stylus .token.variable-declaration,
- .language-stylus .token.variable {
- color: #0d10cd;
- }
-
- .language-stylus .token.selector{
- color: #1373bb;
- }
-
- .language-stylus .token.punctuation{
- color:#700d0d;
- }
-
-
- .language-stylus .token.function {
- color:#da204f
- }
-
-
- .token, span.marker {
- contain: content;
- }
-
- .prettyprint.prettyprint {
- background-color: transparent;
- }
-
- `;
-
-
- const Promise = (async function () { })().constructor;
-
- const delayPn = delay => new Promise((fn => setTimeout(fn, delay)));
-
- const PromiseExternal = ((resolve_, reject_) => {
- const h = (resolve, reject) => { resolve_ = resolve; reject_ = reject };
- return class PromiseExternal extends Promise {
- constructor(cb = h) {
- super(cb);
- if (cb === h) {
- /** @type {(value: any) => void} */
- this.resolve = resolve_;
- /** @type {(reason?: any) => void} */
- this.reject = reject_;
- }
- }
- };
- })();
-
- // -------- fix requestIdleCallback issue for long coding --------
-
- const pud = new PromiseExternal();
- if (typeof window.requestIdleCallback === 'function' && !window.requestIdleCallback842 && window.requestIdleCallback.length === 1) {
- window.requestIdleCallback842 = window.requestIdleCallback;
- window.requestIdleCallback = function (callback, ...args) {
- console.error(322)
- return (this || window).requestIdleCallback842(async function () {
- await pud.then();
- setTimeout(()=>{
- callback.apply(this, arguments);
- });
- }, ...args);
- }
- }
-
- // -------- fix requestIdleCallback issue for long coding --------
-
- const pScript = new PromiseExternal();
- const pElementQuery = new PromiseExternal();
-
- HTMLElement.prototype.getElementsByTagName331 = HTMLElement.prototype.getElementsByTagName;
- Document.prototype.getElementsByTagName331 = Document.prototype.getElementsByTagName;
-
- HTMLElement.prototype.getElementsByTagName = getElementsByTagName;
- Document.prototype.getElementsByTagName = getElementsByTagName;
-
- let byPass = true;
-
- const observablePromise = (proc, timeoutPromise) => {
- let promise = null;
- return {
- obtain() {
- if (!promise) {
- promise = new Promise(resolve => {
- let mo = null;
- const f = () => {
- let t = proc();
- if (t) {
- mo.disconnect();
- mo.takeRecords();
- mo = null;
- resolve(t);
- }
- }
- mo = new MutationObserver(f);
- mo.observe(document, { subtree: true, childList: true })
- f();
- timeoutPromise && timeoutPromise.then(() => {
- resolve(null)
- });
- });
- }
- return promise
- }
- }
- }
-
- const documentReady = new Promise(resolve => {
- Promise.resolve().then(() => {
- if (document.readyState !== 'loading') {
- resolve();
- } else {
- window.addEventListener("DOMContentLoaded", resolve, false);
- }
- });
- });
-
- documentReady.then(async () => {
- pud.resolve();
- });
-
- function getElementsByTagName(tag) {
- if (byPass) {
- if (tag === 'pre' || tag === 'code' || tag === 'xmp') {
- if (location.pathname.endsWith('/code')) {
- pElementQuery.resolve();
- return [];
- }
- }
- }
- return this.getElementsByTagName331(tag);
- }
-
- async function onBodyHeadReadyAsync() {
- await observablePromise(() => document.body && document.head).obtain();
- }
-
-
- // Load CSS
- function loadJS(href) {
-
- return new Promise(resolve => {
-
- const script = document.createElement('script');
- script.src = href;
- script.onload = () => {
- resolve(script);
- };
- document.head.appendChild(script);
-
- });
-
- }
-
- // Load CSS
- function loadCSS(href) {
- const link = document.createElement('link');
- link.rel = 'stylesheet';
- link.href = href;
- document.head.appendChild(link);
- return link;
- }
-
-
-
-
-
- function getLangClassName(pre, textContent){
-
-
-
- let className = '';
- let preLang = '';
-
- if (pre.classList.contains('lang-js')) {
- preLang = 'lang-js';
- } else if (pre.classList.contains('lang-css')) {
- preLang = 'lang-css';
- } else if (pre.classList.contains('uglyprint')){
- let m =/\/\/\s*={2,9}(\w+)={2,9}\s*[\r\n]/.exec(pre.textContent);
- if(m){
- m = m[1];
- if(m === 'UserScript') preLang = 'lang-js';
- if(m === 'UserStyle') preLang = 'lang-css';
- }
- }
-
- if (preLang === 'lang-js') {
- className = 'language-javascript';
- } else if (preLang === 'lang-css') {
-
- const text = textContent;
- let m = /\n@preprocessor\s+([-_a-zA-Z]{3,8})\s*\n/.exec(text);
- className = 'language-css'
- if (m) {
- const preprocessor = m[1];
- if (preprocessor === 'stylus') {
- className = 'language-stylus';
- } else if (preprocessor === 'uso') {
- className = 'language-stylus';
- } else if (preprocessor === 'less') {
- className = 'language-less';
- } else if (preprocessor === 'default') {
- className = 'language-stylus';
- } else {
- className = 'language-stylus';
- }
- }
-
- }
-
- return className;
-
-
- }
-
- /** @param {HTMLElement} pre */
- function prepareCodeAreaAsync(pre) {
-
- if (pre.isConnected === false) return;
- const preParentNode = pre.parentNode;
- const preNextNode = pre.nextSibling;
-
- const codeContainer = pre.closest('.code-container');
- const doContentEditable = codeContainer && codeContainer.querySelector('.code-container>pre:only-child');
-
- pre.remove();
-
- for (const li of pre.querySelectorAll('li')) {
- li.append(document.createTextNode('\n'));
- }
-
- const textContent = pre.textContent;
-
- const className = getLangClassName(pre, textContent);
-
- if (!className) return;
-
- if (doContentEditable) {
- // avoid selection to the outside by mouse dragging
- codeContainer.setAttribute('contenteditable', '');
- pre.setAttribute('contenteditable', 'false');
- }
-
- const code = document.createElement('code');
-
- code.classList.add(className);
- code.classList.add('syntax-highlighted')
-
- let htmlCode = '';
-
- if (className === 'language-javascript') {
- htmlCode = Prism.highlight(textContent, Prism.languages.javascript, 'javascript');
- } else if (className === 'language-stylus') {
- htmlCode = Prism.highlight(textContent, Prism.languages.stylus, 'stylus');
- } else if (className === 'language-less') {
- htmlCode = Prism.highlight(textContent, Prism.languages.less, 'less');
- } else {
- htmlCode = Prism.highlight(textContent, Prism.languages.css, 'css');
- }
-
- // Adding line numbers
- htmlCode = htmlCode || '';
- const htmlSplit = htmlCode ? htmlCode.split('\n') : [];
- const totalLines = htmlSplit.length;
-
- let mwStyle = '';
-
- if (totalLines >= 1) {
- code.classList.add('hljs-add-marker-width');
- const len = `${totalLines}`.length * 0.5;
- mwStyle = `${len}em`;
- htmlCode = htmlSplit.map((n, i) => `<span class="marker marker-fixed-width" marker-text="${i + 1}"></span>${n}`).join('\n') || '';
-
- } else {
-
- code.classList.remove('hljs-add-marker-width');
- }
-
- code.innerHTML = htmlCode;
- code.style.setProperty('--hljs-marker-width', mwStyle);
-
-
-
- if(pre.firstChild === pre.lastChild && pre.firstChild instanceof Node){
- pre.firstChild.replaceWith(code);
- }else{
- pre.innerHTML = '';
- pre.appendChild(code);
- }
- pre.classList.add('code-container-pre');
-
-
- if(USE_SHADOW_MODE){
-
- const shadowDiv = document.createElement("div");
- shadowDiv.classList.add('code-container-shadow')
-
- const shadow = shadowDiv.attachShadow({ mode: "open" });
-
- const styles = document.querySelectorAll('link, style');
- for(style of styles) {
- if(style.classList.contains("stylus")) continue;
- if(style.nodeName === 'LINK' && style.rel !== 'stylesheet') continue;
- shadow.appendChild(style.cloneNode(true))
- }
-
- shadow.appendChild(pre)
- preParentNode.insertBefore(shadowDiv, preNextNode);
- }else{
-
- preParentNode.insertBefore(pre, preNextNode);
- }
-
-
-
-
- }
-
- const documentBodyHeadReady = onBodyHeadReadyAsync();
-
- documentBodyHeadReady.then(async () => {
-
- if (!location.pathname.endsWith('/code')) {
- return;
- }
-
- document.head.appendChild(document.createElement('style')).textContent = `${cssAdd()}`;
-
- self.Prism = self.Prism || {};
- self.Prism.manual = true;
- await loadJS(resoruces['prism-core.js']);
- await loadJS(resoruces['prism-clike.js']);
- await loadJS(resoruces['prism-javascript.js']);
- await loadJS(resoruces['prism-css.js']);
- await loadJS(resoruces['prism-stylus.js']);
-
- if (document.documentElement.hasAttribute('dark')) {
-
- loadCSS(resoruces['prism-dark.css']);
- } else {
-
- loadCSS(resoruces['prism.css']);
- }
-
- pScript.resolve();
-
-
-
-
- });
-
- let keydownActive = false;
-
- documentReady.then(async () => {
-
- if (!location.pathname.endsWith('/code')) {
- byPass = false;
- return;
- }
- await pScript.then();
-
- await Promise.race([pElementQuery, delayPn(800)]);
-
- const targets = document.querySelectorAll('.code-container pre.lang-js, .code-container pre.lang-css, .code-container pre.uglyprint');
- // pre.uglyprint : too long code ; see https://greatest.deepsurf.us/zh-CN/scripts/24204-picviewer-ce/code
-
- if (targets.length === 0) return;
-
- await delayPn(40);
-
- document.head.appendChild(document.createElement('style')).textContent = doActionCSS();
-
- await delayPn(40);
-
- byPass = false;
-
- // Code highlighting
- const promises = [...targets].map(prepareCodeAreaAsync)
- await Promise.all(promises);
-
- await delayPn(40);
- document.documentElement.setAttribute('dkkfv', '');
- keydownActive = true;
-
- });
-
- function selectAllWithinElement(element) {
- window.getSelection().removeAllRanges();
- let range = document.createRange();
- if (element) {
- range.selectNodeContents(element);
- window.getSelection().addRange(range);
- } else {
- console.error('Element not found with ID:', element);
- }
- }
- document.addEventListener('keydown', (e) => {
- if (keydownActive && e && e.code === 'KeyA' && e.isTrusted && (e.metaKey || e.ctrlKey) && !e.shiftKey && !e.altKey) {
-
- const target = e.target;
- const container = target ? target.closest('div.code-container') : null;
- const code = container ? container.querySelector('code') : null;
-
- if (container && code) {
-
- e.preventDefault();
- e.stopPropagation();
- e.stopImmediatePropagation();
-
- setTimeout(() => {
- selectAllWithinElement(code);
- }, 1)
-
- }
-
- }
- }, true);
-
-
- })();