Adds a 'decode' button to code elements. Can be clicked repeatedly.
As of
// ==UserScript==
// @name snahp - Add Decode Button
// @namespace forum.snahp.it
// @version 0.4.2
// @description Adds a 'decode' button to code elements. Can be clicked repeatedly.
// @author Genome
// @homepage https://fora.snahp.eu/viewtopic.php?p=1161800
// @match https://fora.snahp.eu/viewtopic.php*
// @match https://forum.snahp.it/viewtopic.php*
// @icon https://www.google.com/s2/favicons?domain=fora.snahp.eu
// @run-at document-idle
// @grant none
// ==/UserScript==
/*jshint esversion: 6 */
(function() {
'use strict';
let base64Rx = /([a-z0-9+\/]{20,}[=]*)/i;
// Decodes any (likely) base64 strings line by line surgically.
function base64DecodeByLine(targetText) {
let textLines = targetText.split("\n");
let completeLines = [];
for(let textLine of textLines) {
if(base64Rx.test(textLine)) {
let findResult = base64Rx.exec(textLine);
let b64Text = findResult[1];
let targetIx = findResult.index;
let completeLine = textLine.substring(0, targetIx) + atob(b64Text) + textLine.substring(targetIx + b64Text.length);
completeLines.push(completeLine);
} else {
completeLines.push(textLine);
}
}
return completeLines.join("\n");
}
// Decodes the innerText of a passed in DOM element.
function base64DecodeContents(el) {
if(el && el.innerText.trim() !== "") {
el.innerText = base64DecodeByLine(el.innerText);
}
}
// Copies the innerText of a given html element.
function copyContents(el) {
navigator.clipboard.writeText(el.innerText.trim());
}
// Finds hideboxes with no internal <codebox> element (aka they are bare text).
function findBareUnhideBoxes() {
let finalElems = []
for (const el of document.querySelectorAll("dl.hidebox.unhide")) {
if(el.querySelector('div.codebox') == null) {
finalElems.push(el);
}
}
return finalElems;
}
// Create an <a> element and quickly assign some properties (text, any classes, hardcoded style, and a 'click' action)
function createButton(buttonText, classList, hardStyle, onClickCallback) {
let newButton = document.createElement('a');
newButton.innerText = buttonText;
if(classList) classList.forEach(cl => newButton.classList.add(cl))
if(hardStyle) newButton.style = hardStyle;
if(onClickCallback) newButton.addEventListener("click", onClickCallback);
return newButton;
}
const bareBoxButtonStyle = "margin: 0 8px 0 8px; font-weight: bold;";
const bareBoxWrapperStyle = "float: right; text-align: right; border: 1px inset white;";
// Adds a controls div with buttons to hideboxes WITH NO Codebox inside. Aka BareBox. (so they are bare text)
function addBareBoxButtons() {
// Find 'dl.hidebox.unhide' boxes with no internal codebox.
let boxElems = findBareUnhideBoxes();
for (let boxElem of boxElems) {
// Create a decode and copy button and make their click actions refer to this specific box.
let decode = createButton("Decode", ["pointer", "noselect"], bareBoxButtonStyle, () => base64DecodeContents(boxElem));
let copy = createButton("Copy", ["pointer", "noselect"], bareBoxButtonStyle, () => copyContents(boxElem));
// Create a wrapper div to hold both and position it next to the BareBox.
let newControlsWrapper = document.createElement('div');
newControlsWrapper.append(decode, copy);
newControlsWrapper.style = bareBoxWrapperStyle;
boxElem.insertAdjacentElement("afterend", newControlsWrapper);
}
}
// Creates 'Decode' button for Codebox elements.
function addCodeboxButtons() {
// Find all the 'copy' buttons attached to code-boxes on the page.
let codeboxCopyButtons = document.querySelectorAll(".codebox p a:last-child");
// For each of the code boxes.
for(let copyButtonEl of codeboxCopyButtons) {
// Find the related codebox (it's a cousin element).
let codeboxElement = copyButtonEl.parentNode.parentNode.querySelector('pre code');
// Create a new button and bind click event to decode.
let newButton = createButton(
"Decode", ["pointer", "noselect"], "float: right; margin-right: 8px; margin-left: 8px;",
() => base64DecodeContents(codeboxElement)
);
copyButtonEl.parentNode.appendChild(newButton);
}
}
addCodeboxButtons();
addBareBoxButtons();
})();