NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name Textarea Keyboard Shortcuts
// @description Userscripts Comments Fix style shortcuts for the whole web
// @namespace sizzlemctwizzle
// @version 0.0.8
// @include http://*
// @include https://*
// @exclude http://userscripts.org/*
// ==/UserScript==
function $x(x, t, r) {
if (t && t.tagName)
var h = r, r = t, t = h;
var d = r ? r.ownerDocument || r : r = document, p;
switch (t) {
case XPathResult.NUMBER_TYPE:
p = 'numberValue';
break;
case XPathResult.STRING_TYPE:
p = 'stringValue';
break;
case XPathResult.BOOLEAN_TYPE:
p = 'booleanValue';
break;
case XPathResult.ANY_UNORDERED_NODE_TYPE:
case XPathResult.FIRST_ORDERED_NODE_TYPE:
p = 'singleNodeValue';
break;
default:
return d.evaluate(x, r, null, t || XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
}
return d.evaluate(x, r, null, t, null)[p];
}
// Optional shortcut functions I like
function $x1(x, r) { return $x(x, XPathResult.FIRST_ORDERED_NODE_TYPE , r) }
function $xb(x, r) { return $x(x, XPathResult.BOOLEAN_TYPE, r) }
// A robust and universal forEach
function forEach(lst, cb) {
if(!lst)
return;
if (lst.snapshotItem)
for (var i = 0, len = lst.snapshotLength; i < len; ++i)
cb(lst.snapshotItem(i), i, lst);
else if (lst.iterateNext) {
var item, next = lst.iterateNext;
while (item = next())
cb(item, lst);
} else if (typeof lst.length != 'undefined')
for (var i = 0, len = lst.length; i < len; ++i)
cb(lst[i], i, lst);
else if (typeof lst == "object")
for (var i in lst)
cb(lst[i], i, lst);
}
// Insert an element after another
function insertAfter(node, after) { after.parentNode.insertBefore(node, after.nextSibling);}
// A really cool element creation funtion by avg and JoeSimmons, and modified by me
function create() {
switch(arguments.length) {
case 1:
var A = document.createTextNode(arguments[0]);
break;
default:
var A = document.createElement(arguments[0]),
B = arguments[1];
for (var b in B) {
if (b.indexOf("on") == 0)
A.addEventListener(b.substring(2), B[b], false);
else if (",style,accesskey,id,name,src,href,which".indexOf("," +
b.toLowerCase()) != -1)
A.setAttribute(b, B[b]);
else
A[b] = B[b];
}
for(var i = 2, len = arguments.length; i < len; ++i)
A.appendChild(arguments[i]);
}
return A;
}
// Remove an element
function remove(element1) { element1.parentNode.removeChild(element1); }
// Get element by id
function $(element2) { return document.getElementById(element2); }
// Get elements by classname
function $c(element3, root) { return (root||document).getElementsByClassName(element3); }
// Format the quote and append the quote to the correct box
function quote_handle(e) {
var box = $x1('//textarea');
if (lastSelectedBox) box = lastSelectedBox;
else if (!box) return;
var select = window.getSelection();
if (!select || !select.focusNode) return;
e.preventDefault();
var tag = select.focusNode.parentNode.tagName.toLowerCase();
var opentag = '', closetag = '';
if (tag == "pre" || tag == 'code') {
opentag = '<' + tag + '>';
closetag = '</' + tag + '>';
}
var quoted = select.toString().replace(/^\s+|\s+$/g, '');
if (quoted == '') return;
quoted = '<blockquote>' + opentag + quoted + closetag + '</blockquote>';
box.focus();
if (box.value == '') {
box.value = quoted;
box.scrollTop = box.scrollHeight;
} else {
var x, y;
if ( (y=box.selectionEnd) - (x=box.selectionStart) == 0 ) { // insert quote at cursor
box.value = (box.value).substring(0, x) + quoted + '\n' + (box.value).substring(y, (box.value).length);
var len = ((box.value).substring(0, x) + quoted).length
box.setSelectionRange(len, len);
} else { // append quote
if (/\n$/.test(box.value))
box.value = box.value.replace(/\n+$/,'');
box.value += quoted;
box.scrollTop = box.scrollHeight;
}
}
}
function process(e) {
document.documentElement.removeEventListener('DOMNodeInserted', process, false);
if (e && e.target) {
if (e.target.tagName == "TEXTAREA") listen(e.target);
forEach(document.evaluate('.//textarea', e.target, null, 7, null), function(box) {
listen(box);
});
}
document.documentElement.addEventListener('DOMNodeInserted', process, false);
}
function shortcuts(e, box) {
var x=box.selectionStart,y=box.selectionEnd;
var before = (box.value).substring(0,x);
var selected=(box.value).substring(x,y);
var after = (box.value).substring(y, (box.value).length);
var tag, length;
// The activate key is ctrl on mac and alt on everything else
switch(e.keyCode) {
case 67: tag="<code>"+selected+"</code>";break;
case 80: tag="<pre>"+selected+"</pre>";break;
case 66: tag="<strong>"+selected+"</strong>";break;
case 73: tag="<em>"+selected+"</em>";break;
case 85: tag="<ins>"+selected+"</ins>";break;
case 81: tag="<blockquote>"+selected+"</blockquote>";break;
case 83: tag="<del>"+selected+"</del>";break;
case 65: tag="<a href=\"\">"+selected+"</a>";break;
case 88: tag="<img src=\""+selected+"\" />";break;
case 72: tag="<h4>"+selected+"</h4>";break;
case 76: if (y-x>0) tag='<a href="'+((h=prompt('What do you want to link "'+selected+'" to?'))?h:'')+'">'+selected+'</a>';break;
}
if (tag) {
var topScroll = box.scrollTop;
box.value = before+tag+after;
length = (y-x == 0) ? before.length + ((tag.length - 1) / 2) : y + tag.length;
box.setSelectionRange(length, length);
box.focus();
box.scrollTop = topScroll;
if (e.keyCode) e.preventDefault();
}
}
function listen(box) {
box.addEventListener("keydown", function(e) {
if((window.navigator.userAgent.match('Macintosh')) ? e.ctrlKey && !e.altKey : e.altKey && !e.ctrlKey) {
shortcuts(e, this);
}
} ,false);
box.addEventListener("focus", function(e) {
lastSelectedBox = e.target;
} ,false);
}
forEach(document.evaluate('//textarea', document, null, 7, null), function(box) {
listen(box);
});
var lastSelectedBox = null;
document.documentElement.addEventListener('DOMNodeInserted', process, false);
window.addEventListener("keydown", function(e) {
if(((window.navigator.userAgent.match('Macintosh')) ? e.ctrlKey && !e.altKey : e.altKey && !e.ctrlKey)
&& e.keyCode == 81) {
quote_handle(e);
}
} ,false);