// ==UserScript==
// @name GreasyFork Code: Syntax Highlight by PrismJS
// @namespace Violentmonkey Scripts
// @grant none
// @version 0.2.7
// @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==
(() => {
let byPass = true;
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`,
}
function selectAllWithinElement(element) {
// Clear any current selections
window.getSelection().removeAllRanges();
// Create a new range
let range = document.createRange();
// Check if the element exists
if (element) {
// Select all content within the element
range.selectNodeContents(element);
// Add the range to the selection
window.getSelection().addRange(range);
} else {
console.error('Element not found with ID:', element);
}
}
document.addEventListener('keydown', (e) => {
if (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)
const Promise = (async function () { })().constructor;
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_;
}
}
};
})();
const documentReady = new Promise(resolve => {
Promise.resolve().then(() => {
if (document.readyState !== 'loading') {
resolve();
} else {
window.addEventListener("DOMContentLoaded", resolve, false);
}
});
});
async function doAction() {
await new Promise(r => setTimeout(r, 1));
document.head.appendChild(document.createElement('style')).textContent = `
.code-container{
height:100vh;
}
.code-container .CodeMirror, .code-container textarea{
height:100%;
}
`;
if (window.requestIdleCallback) await new Promise(r => !!window.requestIdleCallback(r));
else {
await new Promise(r => !!window.requestAnimationFrame(r));
await new Promise(r => !!window.setTimeout(r, 170));
await new Promise(r => !!window.requestAnimationFrame(r));
}
byPass = false;
}
let mgg = 0;
async function mTz() {
if (mgg) return;
mgg = 1;
documentReady.then(doAction);
}
function getElementsByTagName(tag) {
if (byPass) {
if (tag === 'pre' || tag === 'code' || tag === 'xmp') {
if (location.pathname.endsWith('/code')) {
setTimeout(mTz, 100)
return [];
}
}
}
return this.getElementsByTagName331(tag);
}
async function onBodyHeadReadyAsync() {
if (document.body && document.head) {
} else {
const promiseBegin = new Promise(resolve => {
let mo = new MutationObserver(() => {
if (document.body && document.head) {
mo.disconnect();
mo.takeRecords();
mo = null;
resolve();
}
});
mo.observe(document, { subtree: true, childList: true });
});
await promiseBegin.then();
}
}
// 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;
}
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
}
/*
body {
margin: 0;
line-height: inherit
}
hr {
height: 0;
color: inherit;
border-top-width: 1px
}
abbr:where([title]) {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted
}
h1,h2,h3,h4,h5,h6 {
font-size: inherit;
font-weight: inherit
}
b,strong {
font-weight: bolder
}
*/
.code-container code, .code-container kbd, .code-container pre, .code-container samp {
font-family: ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;
font-size: 1em
}
/*
small {
font-size: 80%
}
sub,sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline
}
sub {
bottom: -.25em
}
sup {
top: -.5em
}
table {
text-indent: 0;
border-color: inherit;
border-collapse: collapse
}
button,input,optgroup,select,textarea {
font-family: inherit;
font-feature-settings: inherit;
font-variation-settings: inherit;
font-size: 100%;
font-weight: inherit;
line-height: inherit;
color: inherit;
margin: 0;
padding: 0
}
button,select {
text-transform: none
}
:-moz-focusring {
outline: auto
}
:-moz-ui-invalid {
box-shadow: none
}
progress {
vertical-align: baseline
}
::-webkit-inner-spin-button,::-webkit-outer-spin-button {
height: auto
}
[type=search] {
-webkit-appearance: textfield;
outline-offset: -2px
}
::-webkit-search-decoration {
-webkit-appearance: none
}
::-webkit-file-upload-button {
-webkit-appearance: button;
font: inherit
}
summary {
display: list-item
}
blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre {
margin: 0
}
fieldset {
margin: 0
}
fieldset,legend {
padding: 0
}
menu,ol,ul {
list-style: none;
margin: 0;
padding: 0
}
textarea {
resize: vertical
}
input::-moz-placeholder,textarea::-moz-placeholder {
opacity: 1;
color: #9ca3af
}
input::placeholder,textarea::placeholder {
opacity: 1;
color: #9ca3af
}
*/
#script-content > .code-container[class] {
width: 100%;
}
.code-container[class] {
border-radius: 0;
}
.code-container[class] {
border-radius: 0;
}
.code-container > pre:only-child{
padding:0;
}
code.syntax-highlighted[class] {
/*
font-family: ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,"Liberation Mono",monospace !important;
font-size: 9pt;
*/
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: #f4f4f4;
padding-right: 6px;
margin-right: 4px;
contain: paint style;
}
[dark] .hljs-add-marker-width .marker-fixed-width[class] {
background: #242424;
color: #b6b2b2;
}
.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 {
/* position: absolute !important;*/
/* visibility: collapse; */
display:none;
}
/*
html:not([dkkfv]) div.code-container > pre{
visibility: collapse;
}
html:not([dkkfv]) code:only-child {
visibility: collapse;
}
*/
.code-container,
.code-container pre:only-child,
.code-container pre:only-child code:only-child {
max-height: calc(100vh + 4px);
max-width: calc(100vw + 4px);
}
` : '';
const cssAdd = `
${global_css}
${cssForCodePage}
.code-container {
max-width: 100%;
display: inline-flex;
flex-direction: column;
overflow: auto;
border-radius: 8px;
max-height: 100%;
overflow: visible;
}
.code-container > pre:only-child {
max-width: 100%;
display: inline-flex;
flex-direction: column;
flex-grow: 1;
height: 0;
}
.code-container > pre:only-child > code:only-child {
max-width: 100%;
flex-grow: 1;
height: 0;
}
.code-container pre code {
padding: 0;
font-family: Consolas;
cursor: text;
overflow: auto;
box-sizing: border-box;
}
.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;
}
body .token.comment {
color: var(--token-color-comment);
}
body .token.atrule, body .token.attr-value, body .token.keyword {
color: #1415ec;
color: var(--token-color-keyword);
}
.language-stylus .token.atrule, .language-stylus .token.attr-value, .language-stylus .token.keyword {
color: #700d0d;
}
body .token.punctuation{
color: var(--token-color-punctuation);
}
body .token.variable-declaration,
body .token.variable {
color: #0d10cd;
}
body .token.selector{
color: #1373bb;
}
body .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
}
`;
HTMLElement.prototype.getElementsByTagName331 = HTMLElement.prototype.getElementsByTagName
Document.prototype.getElementsByTagName331 = Document.prototype.getElementsByTagName
HTMLElement.prototype.getElementsByTagName = getElementsByTagName
Document.prototype.getElementsByTagName = getElementsByTagName
const pScript = new PromiseExternal();
onBodyHeadReadyAsync().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();
});
/** @param {HTMLElement} pre */
async function prepareCodeAreaAsync(pre) {
for (const li of pre.querySelectorAll('li')) {
li.append(document.createTextNode('\n'));
}
const codeElement = document.createElement('code');
// codeElement.classList.add('language-javascript');
codeElement.innerHTML = pre.innerHTML;
// Clearing the original code container and appending the new one
// pre.classList = '';
pre.innerHTML = '';
// pre.appendChild(codeElement);
// if (pre.querySelector('code')) return;
const code = codeElement;
const codeContainer = pre.closest('.code-container');
if (codeContainer && codeContainer.querySelector('.code-container>pre:only-child')) {
// avoid selection to the outside by mouse dragging
codeContainer.setAttribute('contenteditable', '');
codeContainer.querySelector('.code-container>pre:only-child').setAttribute('contenteditable', 'false');
}
// let parentNode = code.parentNode;
// let nextNode = code.nextSibling;
// code.remove();
let parentNode = pre;
let nextNode = null;
await Promise.resolve().then();
// preset language
/*
const text = codeElement.textContent;
if(/(^|\n)\s*\/\/\s+==UserScript==\s*\n/.test(text)){
codeElement.classList.add('language-javascript');
}else if(/(^|\n)\s*\/\*\s+==UserStyle==\s*\n/.test(text)){
codeElement.classList.add('language-css');
}
*/
let className = '';
if (pre.classList.contains('lang-js')) {
className = 'language-javascript';
codeElement.classList.add();
} else if (pre.classList.contains('lang-css')) {
const text = codeElement.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';
}
}
}
if (!className) return;
codeElement.classList.add(className);
codeElement.classList.add('syntax-highlighted')
let htmlCode = '';
if (className === 'language-javascript') {
htmlCode = Prism.highlight(code.textContent, Prism.languages.javascript, 'javascript');
} else if (className === 'language-stylus') {
htmlCode = Prism.highlight(code.textContent, Prism.languages.stylus, 'stylus');
} else if (className === 'language-less') {
htmlCode = Prism.highlight(code.textContent, Prism.languages.less, 'less');
} else {
htmlCode = Prism.highlight(code.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');
}
let targetCode = code;
if (htmlCode) {
const template = document.createElement('template');
template.innerHTML = `<code>${htmlCode}</code>`;
const code2 = template.content.firstChild;
for (const className of code.classList) {
code2.classList.add(className);
}
targetCode = code2;
} else {
code.innerHTML = "";
targetCode = code;
}
targetCode.style.setProperty('--hljs-marker-width', mwStyle);
parentNode.insertBefore(targetCode, nextNode);
}
documentReady.then(async () => {
if (!location.pathname.endsWith('/code')) {
byPass = false;
return;
}
await pScript.then();
// Code highlighting
const promises = [...document.querySelectorAll('.code-container pre.lang-js, .code-container pre.lang-css')].map(prepareCodeAreaAsync)
Promise.all(promises).then(() => {
// setTimeout(() => {
document.documentElement.setAttribute('dkkfv', '');
// }, 1);
})
});
})();