Greasy Fork is available in English.

Quipqiup Show Key

Show the substitution alphabet used for a specific solution in Quipqiup

// ==UserScript==
// @name         Quipqiup Show Key
// @namespace    http://tampermonkey.net/
// @version      2023-12-27
// @description  Show the substitution alphabet used for a specific solution in Quipqiup
// @author       Corgo
// @match        https://quipqiup.com/
// @grant        none
// @license      @MIT
// ==/UserScript==


(function() {
    'use strict';

    document.addEventListener('click', function(event) {
        if (event.target.classList.contains('soltable_plaintext')) {
            const blah = showKey(event.target.innerText);

            const key = document.createElement('div');
            key.innerHTML = blah+'    '; // random unicode space or else it gets stripped by HTML :^)

            key.style.position = 'fixed'; // change div attributes to look nicer
            key.style.top = (event.clientY + 5) + 'px';
            key.style.left = (event.clientX + 5) + 'px';
            key.style.backgroundColor = '#ffffff';
            key.style.padding = '5px';

            key.style.border = 'solid 2px #666666'; // thanks @codewarrior0
            key.style['font-family'] = 'monospace';

            const closeButton = document.createElement('span'); // add button to close key
            closeButton.textContent = '[x]';
            closeButton.style.cursor = 'pointer';
            closeButton.style.position = 'absolute';
            closeButton.style.top = '5px';
            closeButton.style.right = '5px';

            closeButton.addEventListener('click', function() { // add functionality to close button
                key.remove();
            });

            key.appendChild(closeButton);
            document.body.appendChild(key);
        }
    });

    const og_on_solve = on_solve_button; // saving original quipqiup on_solve_button function

    on_solve_button = function(args) { // hooking into quipqiup's on_solve_button
        const ciphertext = document.getElementById("ciphertext").value.trim(); // grab ciphertext from text box
        localStorage.setItem('ciphertext', ciphertext); // saving ciphertext (as we can't trust the textbox to not change)
        og_on_solve(args); // calling original on_solve_button
    };

    function showKey(plaintext) {
        const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        const ciphertext = localStorage.getItem('ciphertext');
        const uniqct = String.prototype.concat.call(...new Set(ciphertext.toUpperCase().replace(/[^A-Z]/g, ''))); // get all unique characters in ciphertext
        const uniqpt = String.prototype.concat.call(...new Set(plaintext.toUpperCase().replace(/[^A-Z]/g, ''))); // get all unique characters in plaintext
        let key1 = Array(26).fill("_")
        let key2 = Array(26).fill("_")

        for (var i = 0; i < uniqpt.length; i++) { // create substitution key 1 ([substitutionkey] -> ABCD...)
            key1[alphabet.indexOf(uniqpt[i])] = uniqct[i];
        }
        for (var j = 0; j < uniqct.length; j++) { // create substitution key 2 (ABCD... -> [substitutionkey])
            key2[alphabet.indexOf(uniqct[j])] = uniqpt[j];
        }

        key1 = key1.join('');
        key2 = key2.join('');

        return alphabet + "   |   " + key2 + "<br>" + key1 + "   |   " + alphabet // return alphabet and key to compare (again thanks @codewarrior0)
    }
})();