Advertisement
NIghtBaker

UserJS - Post Counter, Nope Button, Highlight Qs & Yous

Aug 26th, 2018
145
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.03 KB | None | 0 0
  1. // Nope Button
  2. var imageBlacklist = [] ;
  3. function loadImageBlacklist() { JSON.parse(localStorage.imageBlacklist || "[]").forEach(addToImageBlaclist); }
  4. function saveImageBlacklist() { localStorage.imageBlacklist = JSON.stringify(imageBlacklist); }
  5. function addToImageBlaclist(md5) { if (md5 && -1 === imageBlacklist.indexOf(md5)) imageBlacklist.push(md5); }
  6. function blacklistPostImages(post) { $(post).find('img.post-image').each(function (i, el) { var md5 = el.getAttribute('data-md5'); addToImageBlaclist(md5); el.remove(); }); }
  7. function removeBlacklistedImages() { var removed = 0; $('img.post-image').each(function (i, el) { if (-1 !== imageBlacklist.indexOf(el.getAttribute('data-md5'))) { el.remove(); removed += 1; } }); return removed; }
  8. function onNopeClicked(event) { event.preventDefault(); event.stopPropagation(); loadImageBlacklist(); var post = $(event.target).closest('.post'); blacklistPostImages(post); removeBlacklistedImages(); saveImageBlacklist(); }
  9. function addNopeButtons() { $('.post').each(function(i, post) { if ($(post).find('.nope').length === 0) { $(post).prepend("<input type='button' class='nope' onClick='onNopeClicked(event)' value='Nope'></input>"); } }) }
  10. setInterval(function () { loadImageBlacklist(); removeBlacklistedImages(); addNopeButtons(); }, 500);
  11.  
  12. /* Display a replies counter overlay in the top right corner */
  13. $(function(){
  14. $('head').append('<style>#thread_stats_posts_ovl { '+
  15. 'position:fixed;top:35px;right:35px;'+
  16. 'font:38px sans-serif;opacity:0.5;color:#f60;}</style>');
  17. $('body').append('<div id="thread_stats_posts_ovl"/>');
  18. function copyStats() { $('#thread_stats_posts_ovl').
  19. text($('#thread_stats_posts').text());}
  20. $(document).on('new_post',copyStats); copyStats();});
  21.  
  22. // User Settings
  23. var anonsw = {
  24. qflair: '', // Examples: REAL, &rarr;
  25. qcolor: '#ffc',
  26. youcolor: '#fcc',
  27. scrollcolor: 'rgba(153, 153, 153, 0.6)',
  28. scrollbackcolor: '#333',
  29. scrolltime: 400, // ms
  30. updateDelay: 200, // ms
  31. sidenavWidth: 20, // px
  32.  
  33. floodEnabled: true,
  34. floodThreshold: 14, // min # posts before beginning fade
  35. floodVanish: 15, // max # posts before completed fade/hide
  36. floodBehavior: 'hide', // hide, hide
  37. fadenametripregex: /^(Anon(ymous)?-.*|.*-!!mG7VJxZNCI)$/i,
  38. fadenametripfloodvalue: -1, // Effective post count for fading, or -1 for auto of floodThreshold+post count
  39. strikeThroughNameFags: true,
  40.  
  41. rateHistoryLen: 50, // Data points on chart
  42. rateAvgLen: 10 // Number of data points to average for instantaneous rate
  43. };
  44.  
  45. (function( anonsw_main, $, undefined ) {
  46. // House keeping variables
  47. var qposts = [];
  48. var allqposts = [];
  49. var currq = -1;
  50. var youposts = [];
  51. var curryou = -1;
  52. var qnavposts = [];
  53. var younavposts = [];
  54. var ctx;
  55. var borderSz;
  56. var scrollWd;
  57. var minheight;
  58. var ratehistory = [];
  59.  
  60. // Case insensitive contains selector for finding yous. SO #8746882
  61. $.expr[":"].icontains = jQuery.expr.createPseudo(function (arg) {
  62. return function (elem) {
  63. return jQuery(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
  64. };
  65. });
  66.  
  67. // Get non-child text. SO #3442394
  68. function immediateText(el) {
  69. return el.contents().not(el.children()).text();
  70. }
  71.  
  72. // Highlight (you) posts/references
  73. function highlightYous() {
  74. $(youposts).each(function() {
  75. $(this).css('background-color', anonsw.youcolor);
  76. });
  77. return $.Deferred().resolve();
  78. }
  79.  
  80. // Remove invalid (you)'s
  81. function removeInvalidYous() {
  82. $('div.body:icontains("(You)")').each(function() {
  83. $(this).find(':not(small)').contents().filter(function() { return this.nodeType == 3 }).each(function() {
  84. this.textContent = this.textContent.replace(/\(+ *You *\)+/ig, "you");
  85. });
  86. });
  87. return $.Deferred().resolve();
  88. }
  89.  
  90. // Highlight Q posts
  91. function highlightQ() {
  92. $(allqposts).each(function(idx,val) {
  93. if($(val).css('background-color') !== anonsw.qcolor) {
  94. if(anonsw.qflair !== "") {
  95. $(val).find('p.intro > label > span.trip').first().prepend(anonsw.qflair + " ");
  96. }
  97. $(val).css('background-color', anonsw.qcolor);
  98. }
  99. });
  100. return $.Deferred().resolve();
  101. }
  102.  
  103. // Set which posts are Q posts
  104. function setQPosts() {
  105. qposts = $.map($('div.post:not(.post-hover) > p.intro > label > span.trip:contains("!!mG7VJxZNCI")'), function(el) {
  106. return $(el).closest('div.post');
  107. });
  108. allqposts = $.map($('div.post:not(.post-hover) > p.intro > label > span.trip:contains("!!mG7VJxZNCI")'), function(el) {
  109. return $(el).closest('div.post');
  110. });
  111. return $.Deferred().resolve();
  112. }
  113.  
  114. // Set which posts are (you) posts
  115. function setYouPosts() {
  116. youposts = $.map($('div.post:not(.post-hover) > p.intro > label span.name > span.own_post, div.post:not(.post-hover) > div.body > p.body-line > small:icontains("(You)")'), function(el) {
  117. return $(el).closest('div.post');
  118. });
  119. return $.Deferred().resolve();
  120. }
  121.  
  122. // Inserts side navigation (bird's eye)
  123. function sidenav() {
  124. $('body').append('<canvas id="sidenav"></canvas>');
  125. var nav = $('#sidenav');
  126. $(nav).css('position', 'fixed');
  127. $(nav).css('top', $('div.boardlist').height());
  128. $(nav).css('right', 0);
  129. $(nav).css('width', anonsw.sidenavWidth);
  130. $(nav).css('height', $(window).height() - $('div.boardlist').height());
  131. $(nav).css('background-color', anonsw.scrollbackcolor);
  132. $('body').css('margin-right', anonsw.sidenavWidth);
  133. ctx = $('#sidenav').get(0).getContext('2d');
  134. //ctx.canvas.height = $(document).height() - $('div.boardlist').height();
  135. ctx.canvas.height = 2048;
  136. ctx.canvas.width = anonsw.sidenavWidth;
  137. borderSz = 1;
  138. scrollWd = ctx.canvas.width / 2;
  139. }
  140.  
  141. // Set flood posts
  142. function setFloodPosts() {
  143. if(anonsw.floodEnabled) {
  144. var stats = {};
  145. var firstId = null;
  146. //console.log("==[ Name Fags ]=================================================");
  147. var posts = $('div.post:not(.post-hover)').not('.you');
  148. $(posts).each(function () {
  149. var id = $(this).find('p > span.poster_id').first().text();
  150. if(firstId != null) {
  151. if (!(id in stats)) {
  152. stats[id] = {count: 0, namefag: false, floodcount: 0};
  153. }
  154. stats[id].count++;
  155. if(!stats[id].namefag) {
  156. var name = immediateText($(this).find('p > label span.name').first());
  157. var trip = $(this).find('p > label > span.trip').first().text();
  158. stats[id].namefag = !anonsw.fadenametripregex.test(name+'-'+trip);
  159. //if(stats[id].namefag) {
  160. // console.log(id + '=' + stats[id].namefag + ', ' + name + ', ' + trip);
  161. //}
  162. }
  163. if(stats[id].namefag) {
  164. if(anonsw.fadenametripfloodvalue < 0) {
  165. stats[id].floodcount = anonsw.floodThreshold + stats[id].count;
  166. } else {
  167. stats[id].floodcount = anonsw.fadenametripfloodvalue;
  168. }
  169. } else {
  170. stats[id].floodcount = stats[id].count;
  171. }
  172. }
  173. if (firstId == null) {
  174. firstId = id;
  175. }
  176. });
  177. $.each(stats, function (key, value) {
  178. if (key !== firstId) {
  179. var ids = $('span.poster_id:contains("' + key + '")');
  180. if (value.floodcount > anonsw.floodThreshold || value.namefag) {
  181. if(anonsw.strikeThroughNameFags && value.namefag) {
  182. $(ids).each(function() {
  183. $(this).closest('div.post').hide();
  184. });
  185. }
  186. if (anonsw.floodBehavior === 'fade') {
  187. var intensity = value.floodcount;
  188. if (intensity > anonsw.floodVanish) {
  189. intensity = anonsw.floodVanish;
  190. }
  191. intensity = ((anonsw.floodVanish - anonsw.floodThreshold) - (intensity - anonsw.floodThreshold)) / (anonsw.floodVanish - anonsw.floodThreshold);
  192. if (intensity < 0.1) {
  193. intensity = 0.1;
  194. }
  195. $(ids).each(function () {
  196. $(this).closest('div.post').css('opacity', intensity);
  197. $(this).closest('div.post').hover(function () {
  198. $(this).animate({opacity: 1.0}, anonsw.updateDelay);
  199. }, function () {
  200. $(this).animate({opacity: intensity}, anonsw.updateDelay);
  201. });
  202. });
  203. } else if (anonsw.floodBehavior === 'hide') {
  204. if (value.count >= anonsw.floodVanish) {
  205. $(ids).each(function () {
  206. $(this).closest('div.post').hide();
  207. });
  208. }
  209. }
  210. } else {
  211. $(ids).each(function () {
  212. $(this).closest('div.post').css('opacity', 1.0);
  213. });
  214. }
  215. }
  216. });
  217. }
  218. return $.Deferred().resolve();
  219. }
  220.  
  221. // Update navigation
  222. function updateNav() {
  223. updateNavGraphics();
  224. }
  225.  
  226.  
  227. // Update navigation graphics
  228. function updateNavGraphics() {
  229. var sidenav = $('#sidenav');
  230. if(sidenav.length) {
  231. $(sidenav).css('height', $(window).height() - $('div.boardlist').height());
  232. minheight = ctx.canvas.height / ($(window).height() - $('div.boardlist').height()); // 1px
  233. ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  234.  
  235. // Draw nav q posts
  236. qnavposts = [];
  237. ctx.fillStyle = anonsw.qcolor;
  238. for (i = 0; i < qposts.length; i++) {
  239. // TODO: check if we have already added post, don't draw it again
  240. var el = $(qposts).get(i);
  241. var height = $(el).height() / $(document).height() * ctx.canvas.height;
  242. if(height < minheight) height = minheight;
  243. qnavposts[i] = {
  244. x : borderSz,
  245. y : $(el).offset().top / $(document).height() * ctx.canvas.height,
  246. width : ctx.canvas.width - borderSz*2,
  247. height : height
  248. };
  249. ctx.fillRect(qnavposts[i].x, qnavposts[i].y, qnavposts[i].width, qnavposts[i].height);
  250. }
  251.  
  252. // Draw nav you posts
  253. younavposts = [];
  254. ctx.fillStyle = anonsw.youcolor;
  255. for (i = 0; i < youposts.length; i++) {
  256. // TODO: check if we have already added post, don't add it again
  257. var el = $(youposts).get(i);
  258. var height = $(el).height() / $(document).height() * ctx.canvas.height;
  259. if(height < minheight) height = minheight;
  260. younavposts[i] = {
  261. x : borderSz,
  262. y : $(el).offset().top / $(document).height() * ctx.canvas.height,
  263. width : ctx.canvas.width - borderSz*2,
  264. height : height
  265. };
  266. ctx.fillRect(younavposts[i].x, younavposts[i].y, younavposts[i].width, younavposts[i].height);
  267. }
  268.  
  269. // Update nav window
  270. ctx.fillStyle = anonsw.scrollcolor;
  271. ctx.fillRect(
  272. scrollWd / 2,
  273. $(window).scrollTop() / $(document).height() * ctx.canvas.height,
  274. scrollWd,
  275. $(window).height() / $(document).height() * ctx.canvas.height
  276. );
  277.  
  278. // Add red marker at bottom of >750 posts
  279. if($('#thread_stats_posts').text() > 750) {
  280. var barHeight = (4 * 2048) / ($(window).height() - $('div.boardlist').height());
  281. ctx.fillStyle = '#f66';
  282. ctx.fillRect(
  283. 0,
  284. ctx.canvas.height - barHeight,
  285. ctx.canvas.width,
  286. barHeight
  287. );
  288. }
  289. }
  290. }
  291.  
  292. // Toggle post flooding
  293. anonsw_main.toggleFlood = function() {
  294. if(anonsw.floodEnabled) {
  295. anonsw.floodEnabled = false;
  296. $('.toggleFloodState').text('On');
  297. if(anonsw.floodBehavior === 'fade') {
  298. $('span.poster_id').each(function () {
  299. $(this).closest('div.post').css('opacity', 1);
  300. $(this).closest('div.post').off('mouseenter mouseleave');
  301. });
  302. } else if(anonsw.floodBehavior === 'hide') {
  303. $(this).closest('div.post').show();
  304. }
  305. } else {
  306. anonsw.floodEnabled = true;
  307. $('.toggleFloodState').text('Off');
  308. runq()
  309. }
  310. };
  311.  
  312. // Helper to run snippets in the right order
  313. function runq() {
  314. setQPosts()
  315. .done(highlightQ)
  316. .done(removeInvalidYous)
  317. .done(setYouPosts)
  318. .done(highlightYous)
  319. .done(setFloodPosts)
  320. .done(updateNav);
  321. }
  322.  
  323. anonsw_main.Q = function() {
  324. sidenav();
  325. runq();
  326.  
  327. // Select the node that will be observed for mutations
  328. var targetNode = $('div.thread')[0];
  329.  
  330. // Options for the observer (which mutations to observe)
  331. var config = { childList: true };
  332.  
  333. // Callback function to execute when mutations are observed
  334. var callback = function(mutationsList) {
  335. for(var mutation in mutationsList) {
  336. if (mutationsList[mutation].type == 'childList') {
  337. runq();
  338. break;
  339. }
  340. }
  341. };
  342.  
  343. // Create an observer instance linked to the callback function
  344. var observer = new MutationObserver(callback);
  345.  
  346. // Start observing the target node for configured mutations
  347. observer.observe(targetNode, config);
  348. };
  349. }( window.anonsw_main = window.anonsw_main || {}, jQuery ));
  350.  
  351. // Attach snippets to ready/change events
  352. $(document).ready(anonsw_main.Q);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement