User:Ilmari Karonen/rot13.js

/* 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');

});