Created
February 12, 2016 22:17
-
-
Save shirlston/9cd3a758a379ca66de85 to your computer and use it in GitHub Desktop.
Mefiquote for modern theme
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Mefiquote (updated for redesign) | |
// @namespace http://plutor.org/ | |
// @description Adds "quote" links to Metafilter comments. Updated for the 2014 redesign. | |
// @include http://metafilter.com/* | |
// @include http://*.metafilter.com/* | |
// @include https://metafilter.com/* | |
// @include https://*.metafilter.com/* | |
// @version 0.0.1.20141102043946 | |
// ==/UserScript== | |
// | |
// DONE 2011-02-23 | |
// * Use MeFi's own jquery object (properly this time) | |
// * Use a content scope injector instead of unsafeWindow | |
// * Handle new ajax comments - big thanks to pb | |
// | |
// TODO | |
// * Indicate when "quote" will quote the selection | |
// * Make it work with epiphany and opera | |
// * Ability to link to the original post on preview | |
// Content Scope | |
var script = document.createElement('script'); | |
script.appendChild(document.createTextNode('('+ everything.toString() +')();')); | |
script.setAttribute("type", "application/javascript"); | |
(document.body || document.head || document.documentElement).appendChild(script); | |
/* ======================================================================== */ | |
function everything() { | |
var BUTTONTEXT = 'quote'; | |
var QUOTEFORMAT = '<a href="%l">%n</a>: "<i>%q</i>"'; | |
/* ======================================================================== */ | |
function mq_quotethis(evt) { | |
var commenttextarea = $("#comment"); | |
if (commenttextarea.length < 1) return; | |
var quotelink = $(this); | |
var metadata = quotelink.parent(); | |
var comment = metadata.parent(); | |
// Get all of the data to fill in placeholders | |
var quotebits = new Object; | |
quotebits['%'] = '%'; | |
if (mq_selection_within_comment(comment)) { | |
quotebits.q = document.getSelection().toString(); | |
} else { | |
quotebits.q = new String(comment.html()); | |
quotebits.q = quotebits.q.replace(/<br>/ig, ''); | |
// Remove the trailing metadata | |
if (quotebits.q.lastIndexOf('<span class="smallcopy">posted by') > -1) | |
quotebits.q = quotebits.q.slice(0, | |
quotebits.q.lastIndexOf('<span class="smallcopy">posted by')); | |
// Remove the player from music | |
if (quotebits.q.lastIndexOf('<object ') > -1) | |
quotebits.q = quotebits.q.slice(0, | |
quotebits.q.lastIndexOf('<object ')); | |
// Remove the more inside junk | |
quotebits.q = quotebits.q.replace(/<\/?div[^>]*>/g, ''); | |
quotebits.q = quotebits.q.replace(/^[ \t\n]*/, ''); | |
quotebits.q = quotebits.q.replace(/[ \t\n]*$/, ''); | |
} | |
// Default to top of the thread, just in case | |
quotebits.l = "" + location.protocol + "//" + location.host + location.pathname; | |
// The rest of the data | |
metadata.children('a').each( function(i) { | |
var url = $(this).attr('href'); | |
var path = url.replace(/https?:\/\/([^\/]*\.)?metafilter.com/, ''); | |
if (url == path && path.match('^/')) | |
url = "" + location.protocol + "//" + location.host + path; | |
if (path.match(/^\/user\/(\d+)/)) { | |
quotebits.i = RegExp.$1; | |
quotebits.n = $(this).html(); | |
quotebits.n = quotebits.n.replace(/<.*/, ''); | |
quotebits.p = url; | |
} else if (path.match(/#\d+$/)) { | |
quotebits.l = url; | |
} | |
} ); | |
// Replace all of the placeholders | |
var quoteregex = new RegExp('%(.)', 'g'); | |
var quotehtml = new String(); | |
var lastIndex = 0; | |
while ( quoteregex.exec(QUOTEFORMAT) ) { | |
var thisIndex = quoteregex.lastIndex; | |
quotehtml = quotehtml.concat( QUOTEFORMAT.substr(lastIndex, thisIndex-lastIndex-2) ); | |
var val = quotebits[QUOTEFORMAT.substr(thisIndex-1, 1)]; | |
if (val != undefined) { | |
quotehtml = quotehtml.concat( quotebits[QUOTEFORMAT.substr(thisIndex-1, 1)] ); | |
} else { | |
quotehtml = quotehtml.concat( '%' + QUOTEFORMAT.substr(thisIndex-1, 1) ); | |
} | |
lastIndex = thisIndex; | |
} | |
quotehtml = quotehtml.concat( QUOTEFORMAT.substr(lastIndex) ); | |
// GM_log( quotehtml ); | |
var commentval = commenttextarea.val() || ""; | |
if (commentval != "" && !commentval.match(/\n\n$/)) { | |
commentval += "\n\n"; | |
} | |
commentval += quotehtml + "\n\n"; | |
commenttextarea.val(commentval); | |
} | |
/* ======================================================================== */ | |
function mq_load_preferences() { | |
BUTTONTEXT = Cookie.get('mefiquote_buttontext') || BUTTONTEXT; | |
QUOTEFORMAT = Cookie.get('mefiquote_quoteformat') || QUOTEFORMAT; | |
} | |
function mq_save_preferences() { | |
var buttontext_el = $('#mq_buttontext'); | |
var quoteformat_el = $('#mq_quoteformat'); | |
Cookie.set('mefiquote_buttontext', (buttontext_el.val() || BUTTONTEXT), | |
24*365*10, '', 'metafilter.com', false); | |
Cookie.set('mefiquote_quoteformat', (quoteformat_el.val() || QUOTEFORMAT), | |
24*365*10, '', 'metafilter.com', false); | |
return true; /* So it actually submits, too */ | |
} | |
/* ======================================================================== */ | |
function mq_escape(str) { | |
return str.replace(/"/g, '"'); | |
} | |
/* ======================================================================== */ | |
function mq_selection_within_comment(comment) { | |
var selection = window.getSelection(); | |
// an empty selection doesn't count as being within the comment, otherwise | |
// the quote button tries to quote it and things behave counterintuitively | |
if (selection == null || selection.isCollapsed) { | |
return false; | |
} | |
// check to see if the selection is inside this comment | |
var rangeStart = selection.getRangeAt(0).startContainer; | |
var rangeEnd = selection.getRangeAt(0).endContainer; | |
if (rangeStart != null && rangeEnd != null) { | |
var start_found = false; | |
var end_found = false; | |
// TODO - Why doesn't parents().index() do the right thing? | |
$(rangeStart).parents().andSelf().each( function() { | |
if (this == comment.get(0)) start_found = true; | |
}); | |
$(rangeEnd).parents().andSelf().each( function() { | |
if (this == comment.get(0)) end_found = true; | |
}); | |
return (start_found && end_found); | |
} | |
return false; | |
} | |
/* ======================================================================== */ | |
function mq_init_preferences() { | |
var inputs = $('input'); | |
var submit_button = $('input[type=submit]').filter( function() { | |
return $(this).val().match(/Save your Preferences/); | |
} ); | |
if (inputs.length < 1 || submit_button.length < 1) return; | |
// Create the fieldset | |
var mefiquote_fieldset = $('<fieldset>' | |
+ '<legend>MefiQuote preferences</legend>' | |
+ '<label for="mq_buttontext">Quote button text: </label>' | |
+ '<input type="text" id="mq_buttontext" name="mq_buttontext" value="' | |
+ mq_escape(BUTTONTEXT) | |
+ '" maxlength="200" size="30" onfocus="this.style.background=\'#ddd\';" onblur="this.style.background=\'#ccc\';" /><br />' | |
+ '<label for="mq_quoteformat">Quote format:<br />' | |
+ '<span class="smallcopy" style="text-align: left">%i - commenter\'s user id<br />%l - url of comment<br />%n - commenter\'s name<br />%p - url of commenter\'s profile<br />%q - comment text<br />%% - an actual percent ("%")</span></label>' | |
+ '<textarea name="mq_quoteformat" id="mq_quoteformat" cols="60" rows="8" wrap="VIRTUAL" style="width:400px;height:200px;" onfocus="this.style.background=\'#ddd\';" onblur="this.style.background=\'#ccc\';">' | |
+ mq_escape(QUOTEFORMAT) | |
+ '</textarea>' | |
+ '</fieldset>') | |
.insertBefore(submit_button); | |
// Add javascript to the form | |
submit_button.parents('form').submit( mq_save_preferences ); | |
} | |
function mq_init_thread() { | |
console.log("init-thread"); | |
var commenttextarea = $("#comment"); | |
if (commenttextarea.length < 1) return; | |
var n = 0; | |
$('span').each( function(i) { | |
var curr = $(this); | |
if (curr.hasClass('smallcopy') && curr.html().match(/^posted by/) && | |
curr.parents('#prevDiv2, form').length == 0 && | |
curr.find('.quotebutton').length == 0) { | |
// Skip the first (post) quote link on preview | |
if (location.pathname.match('^/contribute/post_comment_preview.mefi') && n++ == 0) | |
return; | |
// Add the button | |
var quotebutton = $('<a href="#comment">' + BUTTONTEXT + '</a>') | |
.attr('target', '_self') | |
.addClass('quotebutton'); | |
curr.append(' [').append( quotebutton ).append(']'); | |
} | |
} ); | |
} | |
function mq_init_newcomments() { | |
$("#newcomments").bind('mefi-comments', | |
function() { | |
console.log("event!"); | |
mq_init_thread(); | |
} ); | |
console.log("init-newcomments"); | |
} | |
/** | |
* Modified from cookie-js 0.4 by Maxime Haineault (max@centdessin.com) | |
* <http://code.google.com/p/cookie-js/> | |
*/ | |
Cookie = { | |
/** Get a cookie's value */ | |
get: function(key) { | |
// Still not sure that "[a-zA-Z0-9.()=|%/_]+($|;)" match *all* allowed characters in cookies | |
tmp = document.cookie.match((new RegExp(key +'=[a-zA-Z0-9.()=|%/_]+($|;)','g'))); | |
if(!tmp || !tmp[0]) return null; | |
else return unescape(tmp[0].substring(key.length+1,tmp[0].length).replace(';','')) || null; | |
}, | |
/** Set a cookie */ | |
set: function(key, value, ttl, path, domain, secure) { | |
cookie = [key+'='+ escape(value), | |
'path='+ ((!path || path=='') ? '/' : path), | |
'domain='+ ((!domain || domain=='')? window.location.host : domain)]; | |
if (ttl) cookie.push('expires=' + Cookie.hoursToExpireDate(ttl)); | |
if (secure) cookie.push('secure'); | |
return document.cookie = cookie.join('; '); | |
}, | |
/** Unset a cookie */ | |
unset: function(key, path, domain) { | |
path = (!path || typeof path != 'string') ? '' : path; | |
domain = (!domain || typeof domain != 'string') ? '' : domain; | |
if (Cookie.get(key)) Cookie.set(key, '', 'Thu, 01-Jan-70 00:00:01 GMT', path, domain); | |
}, | |
/** Return GTM date string of "now" + time to live */ | |
hoursToExpireDate: function(ttl) { | |
if (parseInt(ttl) == 'NaN' ) return ''; | |
else { | |
now = new Date(); | |
now.setTime(now.getTime() + (parseInt(ttl) * 60 * 60 * 1000)); | |
return now.toGMTString(); | |
} | |
} | |
} | |
function mq_init() { | |
mq_load_preferences(); | |
var url = location.pathname; | |
if (url.match(/^\/(\d+)/) || url.match('^/contribute/post_comment_preview.mefi')) { | |
mq_init_thread(); | |
mq_init_newcomments(); | |
// Attach a listener to clicks -- just once | |
$(".content").on("click", "a.quotebutton", mq_quotethis); | |
} else if (url.match('^/contribute/customize.cfm')) { | |
mq_init_preferences(); | |
} | |
} | |
mq_init(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment