Guest User

MeFiQuote for New Theme

a guest
Feb 27th, 2015
226
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name Mefiquote
  3. // @namespace http://plutor.org/
  4. // @description Adds "quote" links to Metafilter comments.
  5. // @include http://metafilter.com/*
  6. // @include http://*.metafilter.com/*
  7. // ==/UserScript==
  8.  
  9. //
  10. // DONE 2011-02-23
  11. // * Use MeFi's own jquery object (properly this time)
  12. // * Use a content scope injector instead of unsafeWindow
  13. // * Handle new ajax comments - big thanks to pb
  14. //
  15. // TODO
  16. // * Indicate when "quote" will quote the selection
  17. // * Make it work with epiphany and opera
  18. // * Ability to link to the original post on preview
  19.  
  20. // Content Scope
  21. var script = document.createElement('script');
  22. script.appendChild(document.createTextNode('('+ everything.toString() +')();'));
  23. script.setAttribute("type", "application/javascript");
  24. (document.body || document.head || document.documentElement).appendChild(script);
  25.  
  26. /* ======================================================================== */
  27. function everything() {
  28. var BUTTONTEXT = '"';
  29. var QUOTEFORMAT = '<a href="%l">%n</a>: "<i>%q</i>"';
  30.  
  31. /* ======================================================================== */
  32.  
  33. function mq_quotethis(evt) {
  34. var commenttextarea = $("#comment");
  35. if (commenttextarea.length < 1) return;
  36.  
  37. var quotelink = $(this);
  38. var metadata = quotelink.parent();
  39. var comment = metadata.parent();
  40.  
  41.  
  42. // Get all of the data to fill in placeholders
  43. var quotebits = new Object;
  44. quotebits['%'] = '%';
  45.  
  46. if (mq_selection_within_comment(comment)) {
  47. quotebits.q = document.getSelection().toString();
  48. } else {
  49. quotebits.q = new String(comment.html());
  50. quotebits.q = quotebits.q.replace(/<br>/ig, '');
  51.  
  52. // Remove the trailing metadata
  53. if (quotebits.q.lastIndexOf('<span class="smallcopy">posted by') > -1)
  54. quotebits.q = quotebits.q.slice(0,
  55. quotebits.q.lastIndexOf('<span class="smallcopy">posted by'));
  56.  
  57. // Remove the player from music
  58. if (quotebits.q.lastIndexOf('<object ') > -1)
  59. quotebits.q = quotebits.q.slice(0,
  60. quotebits.q.lastIndexOf('<object '));
  61.  
  62. // Remove the more inside junk
  63. quotebits.q = quotebits.q.replace(/<\/?div[^>]*>/g, '');
  64. quotebits.q = quotebits.q.replace(/^[ \t\n]*/, '');
  65. quotebits.q = quotebits.q.replace(/[ \t\n]*$/, '');
  66. }
  67.  
  68. // Default to top of the thread, just in case
  69. quotebits.l = "" + location.protocol + "//" + location.host + location.pathname;
  70.  
  71. // The rest of the data
  72. metadata.children('a').each( function(i) {
  73. var url = $(this).attr('href');
  74. var path = url.replace(/(https:|http:)?\/\/([^\/]*\.)?metafilter.com/, '');
  75. if (url == path && path.match('^/'))
  76. url = "" + location.protocol + "//" + location.host + path;
  77.  
  78. if (path.match(/^\/user\/(\d+)/)) {
  79. quotebits.i = RegExp.$1;
  80. quotebits.n = $(this).html();
  81. quotebits.n = quotebits.n.replace(/<.*/, '');
  82. quotebits.p = url;
  83. } else if (path.match(/#\d+$/)) {
  84. quotebits.l = url;
  85. }
  86. } );
  87.  
  88. // Replace all of the placeholders
  89. var quoteregex = new RegExp('%(.)', 'g');
  90. var quotehtml = new String();
  91. var lastIndex = 0;
  92. while ( quoteregex.exec(QUOTEFORMAT) ) {
  93. var thisIndex = quoteregex.lastIndex;
  94. quotehtml = quotehtml.concat( QUOTEFORMAT.substr(lastIndex, thisIndex-lastIndex-2) );
  95. var val = quotebits[QUOTEFORMAT.substr(thisIndex-1, 1)];
  96. if (val != undefined) {
  97. quotehtml = quotehtml.concat( quotebits[QUOTEFORMAT.substr(thisIndex-1, 1)] );
  98. } else {
  99. quotehtml = quotehtml.concat( '%' + QUOTEFORMAT.substr(thisIndex-1, 1) );
  100. }
  101.  
  102. lastIndex = thisIndex;
  103. }
  104. quotehtml = quotehtml.concat( QUOTEFORMAT.substr(lastIndex) );
  105.  
  106. // GM_log( quotehtml );
  107. var commentval = commenttextarea.val() || "";
  108. if (commentval != "" && !commentval.match(/\n\n$/)) {
  109. commentval += "\n\n";
  110. }
  111. commentval += quotehtml + "\n\n";
  112.  
  113. commenttextarea.val(commentval);
  114. }
  115.  
  116. /* ======================================================================== */
  117.  
  118. function mq_load_preferences() {
  119. BUTTONTEXT = Cookie.get('mefiquote_buttontext') || BUTTONTEXT;
  120. QUOTEFORMAT = Cookie.get('mefiquote_quoteformat') || QUOTEFORMAT;
  121. }
  122.  
  123. function mq_save_preferences() {
  124. var buttontext_el = $('#mq_buttontext');
  125. var quoteformat_el = $('#mq_quoteformat');
  126.  
  127. Cookie.set('mefiquote_buttontext', (buttontext_el.val() || BUTTONTEXT),
  128. 24*365*10, '', 'metafilter.com', false);
  129. Cookie.set('mefiquote_quoteformat', (quoteformat_el.val() || QUOTEFORMAT),
  130. 24*365*10, '', 'metafilter.com', false);
  131.  
  132. return true; /* So it actually submits, too */
  133. }
  134.  
  135. /* ======================================================================== */
  136.  
  137. function mq_escape(str) {
  138. return str.replace(/"/g, '&quot;');
  139. }
  140.  
  141. /* ======================================================================== */
  142.  
  143. function mq_selection_within_comment(comment) {
  144. var selection = window.getSelection();
  145.  
  146. // an empty selection doesn't count as being within the comment, otherwise
  147. // the quote button tries to quote it and things behave counterintuitively
  148. if (selection == null || selection.isCollapsed) {
  149. return false;
  150. }
  151.  
  152. // check to see if the selection is inside this comment
  153. var rangeStart = selection.getRangeAt(0).startContainer;
  154. var rangeEnd = selection.getRangeAt(0).endContainer;
  155.  
  156. if (rangeStart != null && rangeEnd != null) {
  157. var start_found = false;
  158. var end_found = false;
  159.  
  160. // TODO - Why doesn't parents().index() do the right thing?
  161. $(rangeStart).parents().andSelf().each( function() {
  162. if (this == comment.get(0)) start_found = true;
  163. });
  164. $(rangeEnd).parents().andSelf().each( function() {
  165. if (this == comment.get(0)) end_found = true;
  166. });
  167.  
  168. return (start_found && end_found);
  169. }
  170. return false;
  171. }
  172.  
  173. /* ======================================================================== */
  174.  
  175. function mq_init_preferences() {
  176. var inputs = $('input');
  177. var submit_button = $('input[type=submit]').filter( function() {
  178. return $(this).val().match(/Save your Preferences/);
  179. } );
  180. if (inputs.length < 1 || submit_button.length < 1) return;
  181.  
  182. // Create the fieldset
  183. var mefiquote_fieldset = $('<fieldset>'
  184. + '<legend>MefiQuote preferences</legend>'
  185. + '<label for="mq_buttontext">Quote button text: </label>'
  186. + '<input type="text" id="mq_buttontext" name="mq_buttontext" value="'
  187. + mq_escape(BUTTONTEXT)
  188. + '" maxlength="200" size="30" onfocus="this.style.background=\'#ddd\';" onblur="this.style.background=\'#ccc\';" /><br />'
  189. + '<label for="mq_quoteformat">Quote format:<br />'
  190. + '<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>'
  191. + '<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\';">'
  192. + mq_escape(QUOTEFORMAT)
  193. + '</textarea>'
  194. + '</fieldset>')
  195. .insertBefore(submit_button);
  196.  
  197. // Add javascript to the form
  198. submit_button.parents('form').submit( mq_save_preferences );
  199. }
  200.  
  201. function mq_init_thread() {
  202. console.log("init-thread");
  203.  
  204. var commenttextarea = $("#comment");
  205. if (commenttextarea.length < 1) return;
  206.  
  207. var n = 0;
  208. $('span').each( function(i) {
  209. var curr = $(this);
  210. if (curr.hasClass('smallcopy') && curr.html().match(/^posted by/) &&
  211. curr.parents('#prevDiv2, form').length == 0 &&
  212. curr.find('.quotebutton').length == 0) {
  213. // Skip the first (post) quote link on preview
  214. if (location.pathname.match('^/contribute/post_comment_preview.mefi') && n++ == 0)
  215. return;
  216.  
  217. // Add the button
  218. var quotebutton = $('<a href="#comment">' + BUTTONTEXT + '</a>')
  219. .attr('target', '_self')
  220. .addClass('quotebutton');
  221.  
  222. curr.append(' [').append( quotebutton ).append(']');
  223. }
  224. } );
  225. }
  226.  
  227. function mq_init_newcomments() {
  228. $("#newcomments").bind('mefi-comments',
  229. function() {
  230. console.log("event!");
  231. mq_init_thread();
  232. } );
  233. console.log("init-newcomments");
  234. }
  235.  
  236. /**
  237. * Modified from cookie-js 0.4 by Maxime Haineault (max@centdessin.com)
  238. * <http://code.google.com/p/cookie-js/>
  239. */
  240. Cookie = {
  241. /** Get a cookie's value */
  242. get: function(key) {
  243. // Still not sure that "[a-zA-Z0-9.()=|%/_]+($|;)" match *all* allowed characters in cookies
  244. tmp = document.cookie.match((new RegExp(key +'=[a-zA-Z0-9.()=|%/_]+($|;)','g')));
  245. if(!tmp || !tmp[0]) return null;
  246. else return unescape(tmp[0].substring(key.length+1,tmp[0].length).replace(';','')) || null;
  247.  
  248. },
  249.  
  250. /** Set a cookie */
  251. set: function(key, value, ttl, path, domain, secure) {
  252. cookie = [key+'='+ escape(value),
  253. 'path='+ ((!path || path=='') ? '/' : path),
  254. 'domain='+ ((!domain || domain=='')? window.location.host : domain)];
  255.  
  256. if (ttl) cookie.push('expires=' + Cookie.hoursToExpireDate(ttl));
  257. if (secure) cookie.push('secure');
  258. return document.cookie = cookie.join('; ');
  259. },
  260.  
  261. /** Unset a cookie */
  262. unset: function(key, path, domain) {
  263. path = (!path || typeof path != 'string') ? '' : path;
  264. domain = (!domain || typeof domain != 'string') ? '' : domain;
  265. if (Cookie.get(key)) Cookie.set(key, '', 'Thu, 01-Jan-70 00:00:01 GMT', path, domain);
  266. },
  267.  
  268. /** Return GTM date string of "now" + time to live */
  269. hoursToExpireDate: function(ttl) {
  270. if (parseInt(ttl) == 'NaN' ) return '';
  271. else {
  272. now = new Date();
  273. now.setTime(now.getTime() + (parseInt(ttl) * 60 * 60 * 1000));
  274. return now.toGMTString();
  275. }
  276. }
  277. }
  278.  
  279. function mq_init() {
  280. mq_load_preferences();
  281.  
  282. var url = location.pathname;
  283.  
  284. if (url.match(/^\/(\d+)/) || url.match('^/contribute/post_comment_preview.mefi')) {
  285. mq_init_thread();
  286. mq_init_newcomments();
  287.  
  288. // Attach a listener to clicks -- just once
  289. $(".content").on("click", "a.quotebutton", mq_quotethis);
  290. } else if (url.match('^/contribute/customize.cfm')) {
  291. mq_init_preferences();
  292. }
  293. }
  294.  
  295. mq_init();
  296. }
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×