您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds a 'decode' button to code elements. Can be clicked repeatedly.
// ==UserScript== // @name snahp.it - Add Decode Button // @namespace forum.snahp.it // @version 0.5.4 // @description Adds a 'decode' button to code elements. Can be clicked repeatedly. // @author Genome // @license MIT // @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://fora.snahp.eu/favicon.ico // @run-at document-idle // @grant none // ==/UserScript== /*jshint esversion: 6 */ (function() { 'use strict'; const isChromium = navigator.userAgent.toLowerCase().includes('chrome'); const isFirefox = navigator.userAgent.toLowerCase().includes('firefox'); let base64Rx = /([a-z0-9+\/]{20,}[=]*)/i; let undoBuffer = []; // 0.5.0: Add undo buffer to let you roll back your decodes in reverse order. // Encodes or decodes any (likely) base64 strings line by line surgically. function base64CodeByLine(targetText, decode = true) { let textLines = targetText.split("\n"); let completeLines = []; for(let textLine of textLines) { let hasText = textLine.trim().length > 0; if(!hasText) { completeLines.push(textLine); continue; } if(decode && 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"); } const oldLinkRx = /links\.snahp\.it/gi; // Encodes or Decodes the innerText of a passed in DOM element. function base64CodeContents(el, decode = true) { debugger; if(el && el.innerText.trim() !== "") { undoBuffer.push({ "element": el, "previousText": el.innerText }); el.innerText = base64CodeByLine(el.innerText, decode); // 0.5.1: Re-fix links going to links.snahp.it to the new domain. if(oldLinkRx.test(el.innerText)) { el.innerText = el.innerText.replaceAll(oldLinkRx, "lnk.snahp.eu"); } } } function undoLast() { if(undoBuffer.length > 0) { let lastOp = undoBuffer.pop(); lastOp.element.innerText = lastOp.previousText; } } // 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) { // Add <br/> tag inside to hidebox to buffer the contents from selecting anything after. // v0.5.4: Only for Chromium based browsers, ignore Firefox (no selection issue) if(!isFirefox && isChromium) { let newBr = document.createElement('br'); newBr.style.content = "\"\""; // Style fix 0.5.3 Workaround for allowing <br/> to still split text, but not show. boxElem.appendChild(newBr); } // Create a decode and copy button and make their click actions refer to this specific box. let decode = createButton("Decode", ["pointer", "noselect"], bareBoxButtonStyle, () => base64CodeContents(boxElem)); // 0.5.0 Add ability to right click to re-encode just in case it's needed. decode.addEventListener("contextmenu", (ev) => { ev.preventDefault(); // Don't pop up the right click menu but ONLY on this button. ev.stopPropagation(); undoLast(); }); 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;", () => base64CodeContents(codeboxElement) ); // 0.5.0 Add ability to right click to re-encode just in case it's needed. newButton.addEventListener("contextmenu", (ev) => { ev.preventDefault(); // Don't pop up the right click menu but ONLY on this button. ev.stopPropagation(); undoLast(); }); copyButtonEl.parentNode.appendChild(newButton); } } addCodeboxButtons(); addBareBoxButtons(); })();