There are 13 previous versions of this script.
// ==UserScript==
// @name Userscripts.org Selection Quoting
// @namespace sizzlemctwizzle
// @version 1.0.9
// @description Just select the text and click "Quote"
// @require http://sizzlemctwizzle.com/updater.php?id=48059
// @include http://userscripts.org/topics/*
// ==/UserScript==
// Smart XPath Function
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 1:
p = 'numberValue';
break;
case 2:
p = 'stringValue';
break;
case 3:
p = 'booleanValue';
break;
case 8: case 9:
p = 'singleNodeValue';
break;
default:
return d.evaluate(x, r, null, t || 6, null);
}
return d.evaluate(x, r, null, t, null)[p];
}
// Optional shortcut functions I like
function $x1(x, r) { return $x(x, 9, r) }
function $xb(x, r) { return $x(x, 3, r) }
// A robust and universal forEach
function forEach(lst, cb) {
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;
while (item = lst.iterateNext())
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
for (var i in lst)
cb(lst[i], i, lst);
}
// Get element by id
function $(element) { return document.getElementById(element); }
// Get elements by classname
function $c(element, root, result) {
if (result && result.tagName)
var temp = root, root = result, result = temp;
var root = root || document;
element = (root.getElementsByClassName) ? root.getElementsByClassName(element) : $x(".//*[contains(concat(' ', @class, ' '), ' " + element + " ')]", root);
if (!result && result!=0)
return element;
else
return (element.length) ? element[result] : element.snapshotItem(result);
}
// Insert an element after another
function insertAfter(node, after) { after.parentNode.insertBefore(node, after.nextSibling);}
// Element creation function by Avg and JoeSimmons
function create(A, B, C) {
if (!B)
A = document.createTextNode(A);
else {
A = document.createElement(A);
for (var b in B) {
if (b.indexOf("on") == 0)
A.addEventListener(b.substring(2), B[b], false);
else if (b == "style")
A.setAttribute(b, B[b]);
else
A[b] = B[b];
}
if (C)
for(var i = 0, len = C.length; i<len; i++)
A.appendChild(C[i]);
}
return A;
}
// Format the quote and append the quote to the correct box
function quote_handle(e) {
e.preventDefault();
var post_hentry = $x1('./ancestor::tr[contains(@class, "post hentry")]', e.target),
post_id = post_hentry.id.split('row-')[1],
user = $c('fn', post_hentry, 0).getElementsByTagName('a')[0],
userName = user.getAttribute('text'),
userUrl = '/users/'+user.getAttribute('user_id'),
body = $("post-body-"+post_id);
if ((select=window.getSelection())&&(select.focusNode)&&(isPost(select, body.id))) {
quoted = selectHTML(select, body);
} else {
quoted = body.innerHTML;
}
if ($("reply").getAttribute('style').match("display: none;")&&($("edit").offsetHeight>0)&&$("edit_post_body")) {
box = $("edit_post_body");
} else if ($("reply").offsetHeight>0) {
box = $("post_body");
} else {
box = $("post_body");
$("reply").style.display = "block";
$("post_body").value = '';
}
box.focus();
quoted = '<blockquote><strong><a href="'+userUrl+'">'+userName+'</a></strong> <a href="'+
location.pathname+location.search+'#posts-'+post_id+'">wrote</a>:\n'+
quoted.replace(/^(<p>\s*<\/p>)/g,'').replace(/^(\s*<br>\s*)*\s*/,'').replace(/^\s*/,'').replace(/<pre>((?:.|\s)*?)<\/pre>/gmi,function(str,p1){return'<pre>'+p1.replace(/\n/g,'<br>')+'</pre>'}).replace(/\n/g, '').replace(/<!--((?:.|\n)*)-->/, '').replace(/<br>/g, '\n').replace(/<p>/g, '').replace(/<\/p>/g, "\n").replace(/^\s+|\s+$/g, '').replace(/ {2,}/g,' ') +
'</blockquote>\n';
if(box.value=='') {
box.value = quoted;
box.scrollTop = box.scrollHeight;
} else {
if ((y=box.selectionEnd)-(x=box.selectionStart)==0) {
box.value = (box.value).substring(0,x)+quoted+'\n'+(box.value).substring(y,(box.value).length);
length=((box.value).substring(0,x)+quoted).length
box.setSelectionRange(length, length);
} else {
if(/\n$/.test(box.value)) box.value = box.value.replace(/\n+$/,'');
box.value += quoted;
box.scrollTop = box.scrollHeight;
}
}
}
// Get the innerHTML of the selection
// Wrap the selection in its parent's tag
// If the parent is a blockquote then append the correct attribution
function selectHTML(sel, body) {
var html = "";
for (var i=0;i<sel.rangeCount;i++){
var d = create('span', {});
var r = sel.getRangeAt(i);
var parent_element = r.commonAncestorContainer;
if(parent_element.parentNode.tagName!="TD"&&parent_element.parentNode.tagName!="TR") tag=parent_element.parentNode.tagName.toLowerCase();
else if (parent_element.tagName&&parent_element.tagName!="TD") tag=parent_element.tagName.toLowerCase();
else tag = '';
var prev_html = parent_element.innerHTML;
try {
r.surroundContents(d);
} catch(e) {
GM_log("Selection quoting failed due to a bug in Firefox 3.5.x");
return body.innerHTML;
}
if(quote_frag=getParentQuote(parent_element,body.id)) {
if((link1=quote_frag.getElementsByTagName('a')[0])&&(/http:\/\/userscripts\.org\/users\/[^\/]+/.test(link1.href))) {
author_name = link1.textContent;
author_link = link1.pathname;
if((link2=quote_frag.getElementsByTagName('a')[1])&&(/http:\/\/userscripts\.org\/topics\/\d+.*#posts-\d+/.test(link2.href))) {
quote_link = link2.pathname;
} else {
quote_link = '';
}
quoted = '<blockquote><strong><a href="'+author_link+'">'+author_name+'</a></strong> '+((quote_link=='')?'wrote:':'<a href="'+quote_link+'">wrote</a>:')+'<br>';
if (tag=="ul"||tag=="li") quoted+='<ul><li>'+d.innerHTML+'</li></ul>';
else if(tag!=''&&tag!='blockquote') quoted+='<'+tag+'>'+d.innerHTML+'</'+tag+'>';
else quoted+=d.innerHTML;
quoted += '</blockquote>';
}
} else {
quoted='';
}
if (quoted!='') html +=quoted;
else if(tag=="ul"||tag=="li") html += '<ul><li>'+d.innerHTML+'</li></ul>';
else if(tag!=''&&tag!=='a') html += '<'+tag+'>'+d.innerHTML+'</'+tag+'>';
else html +=d.innerHTML;
parent_element.innerHTML = prev_html;
}
return html;
}
// Determine if the selected portion is in a post
function isPost(sel, id) {
if(sel.getRangeAt(0).commonAncestorContainer.tagName=="TBODY") return false;
node = sel.focusNode;
while (node.parentNode!=null) {
if(node.id&&node.id==id) return true;
node = node.parentNode;
}
return false;
}
// Determine if the selection portion is in a blockquote
// and return that node
function getParentQuote(node,id) {
while (node.parentNode&&node.id!=id) {
node = node.parentNode;
if (node.tagName=="BLOCKQUOTE") return node;
}
return false;
}
if($xb("//a[@class='utility']/child::text()[.='Reply to topic']"))
forEach($x('//td[@class="author vcard"]//span[@class="role"]'),
function(role){
insertAfter(create('a', {href: '#',
className: 'utility',
textContent: 'Quote',
style: 'display: block; clear: both; padding-top: 3px;',
onclick: function(e) { quote_handle(e); }}), role);
});
