User:Ilmari Karonen/rot13.js

From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
/* This script can be used to encode/decode text with [[ROT13]].  Just select the text you want to transform and click the "rot13" button (or press ''alt-R'').
 *
 * Known bugs
 * - Should encode/decode the entire page (or just the content section) if nothing is selected.
 * - Does not work on textbox content.
 * - Only works in Mozilla (and maybe Safari?); an IE port should be possible, but would take a lot of work.
 */

var rot13map;
function rot13(a)
{
    if (!rot13map) {
        rot13map = new Array();
        var s = "abcdefghijklmnopqrstuvwxyz";
        for (var i = 0; i < s.length; i++)
            rot13map[s.charAt(i)] = s.charAt((i+13)%26);
        s = s.toUpperCase();
        for (var i = 0; i < s.length; i++)
            rot13map[s.charAt(i)] = s.charAt((i+13)%26);
    }
    var s = "";
    for (var i = 0; i < a.length; i++) {
        var b = rot13map[a.charAt(i)];
        s += (b ? b : a.charAt(i));
    }
    //alert("rot13('"+a+"') = '"+s+"'");
    return s;
}

function getTextNodesInRange (range) {
    var retVal = new Array();
    retVal.startOffset = retVal.endOffset = -1; 
    var nodes = retVal.nodes = new Array();

    var currNode = range.startContainer;
    var lastNode = range.endContainer;

    if (currNode.nodeType == 3)
        retVal.startOffset = range.startOffset;
    else if (currNode.firstChild)
        currNode = currNode.childNodes[range.startOffset];

    if (lastNode.nodeType == 3)
        retVal.endOffset = range.endOffset;
    else if (lastNode.firstChild)
        lastNode = (range.endOffset > 0 ? lastNode.childNodes[range.endOffset] : lastNode.prevSibling);

    search:
    while (currNode) {
        while (currNode.firstChild)
            if ((currNode = currNode.firstChild) == lastNode) break;
        if (currNode.nodeType == 3)
            nodes.push(currNode);
        if (currNode == lastNode)
            break;
        while (!currNode.nextSibling)
            if ((currNode = currNode.parentNode) == lastNode) break search;
        currNode = currNode.nextSibling;
    }
    if (retVal.startOffset < 0)
        retVal.startOffset = 0;
    if (retVal.endOffset < 0)
        retVal.endOffset = (nodes.length ? nodes[nodes.length-1].length : 0);
    return retVal;
}

function rot13Selection () {
    if (!window.getSelection && !document.getSelection) {
        alert("Browser does not support getSelection().");
        return;
    }
    var selection = (window.getSelection ? window.getSelection() : document.getSelection());
    if (!selection || selection.isCollapsed) return;

    if (!selection.getRangeAt) {
        alert("Browser does not support selection.getRangeAt().");
        return;
    }
    var texts = new Array();
    for (var i = 0; i < selection.rangeCount; i++) {
        var textNodes = getTextNodesInRange(selection.getRangeAt(i));
        //alert("processing "+textNodes.nodes.length+" nodes");
        texts.push(textNodes);
        var j = 0;
        if (textNodes.nodes.length < 1)
            continue;
        else if (textNodes.nodes.length < 2)
            textNodes.nodes[j].nodeValue = (textNodes.nodes[j].nodeValue.substring(0, textNodes.startOffset) +
                                            rot13(textNodes.nodes[j].nodeValue.substring(textNodes.startOffset, textNodes.endOffset)) +
                                            textNodes.nodes[j].nodeValue.substring(textNodes.endOffset));
        else {
            textNodes.nodes[j].nodeValue = (textNodes.nodes[j].nodeValue.substring(0, textNodes.startOffset) +
                                            rot13(textNodes.nodes[j].nodeValue.substring(textNodes.startOffset)));
            for (j = 1; j < textNodes.nodes.length-1; j++)
                textNodes.nodes[j].nodeValue = rot13(textNodes.nodes[j].nodeValue);
            textNodes.nodes[j].nodeValue = (rot13(textNodes.nodes[j].nodeValue.substring(0, textNodes.endOffset)) +
                                            textNodes.nodes[j].nodeValue.substring(textNodes.endOffset));
        }
    }
    selection = window.getSelection();
    selection.removeAllRanges();
    for (var i = 0; i < texts.length; i++) {
         if (texts[i].nodes.length < 1) continue;
         var range = document.createRange();
         range.setStart(texts[i].nodes[0], texts[i].startOffset);
         range.setEnd(texts[i].nodes[texts[i].nodes.length-1], texts[i].endOffset);
         selection.addRange(range);
    }
}

addOnloadHook(function () {
    mw.util.addPortletLink('p-cactions', 'javascript:rot13Selection()', 'rot13', 'ca-rot13', 'Encrypt/decrypt selection with ROT-13', 'R');
});