Advertisement
Guest User

MeFiQuote for New Theme

a guest
Feb 27th, 2015
297
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.93 KB | None | 0 0
  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. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement