FA Content Filter

Filters user-defined content while browsing Furaffinity.

当前为 2018-04-17 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name FA Content Filter
  3. // @namespace fa-filter
  4. // @description Filters user-defined content while browsing Furaffinity.
  5. // @include *://www.furaffinity.net/*
  6. // @require http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js
  7. // @version 1.5.6
  8. // @grant GM.getValue
  9. // @grant GM.setValue
  10. // @grant GM.deleteValue
  11. // @grant GM.openInTab
  12. // ==/UserScript==
  13.  
  14. // === WARNING ===
  15. // THE TAG FUNCTIONS ARE COMMENTED OUT IN ORDER TO PREVENT ACCIDENTAL DDoS DETECTION ON FURAFFINITY.
  16. this.$ = this.jQuery = jQuery.noConflict(true);
  17.  
  18. // Shitty workaround, but w/e
  19. async function main() {
  20. // === INITIALIZE USER ARRAY ===
  21. var userArray = JSON.parse(await GM.getValue('userList', '{}'));
  22. //var tagArray = JSON.parse(GM.getvalue('tagList', '{}'));
  23.  
  24. // === GENERAL TEMPORARY VARIABLES ===
  25. var filterEnabled = {['subs']:true, ['shouts']:true, ['coms']:true, ['notifications']:true};
  26.  
  27. // === FILTER ===
  28. var parseSettings = function() {
  29. if (!(userArray instanceof Array)) {
  30. $.each(userArray, function(username, data) {
  31. if (data['subs'] === 1) { hideSubmissions(username); }
  32. if (data['shouts'] === 1) { hideShouts(username); }
  33. if (data['coms'] === 1) { hideComments(username); }
  34. if (data['notifications'] === 1) { hideNotifications(username); }
  35. });
  36. }
  37. };
  38.  
  39. //var parseTagSettings = function() {
  40. // $('.t-image a[href^="/view"]').each(function() {
  41. // var url = $(this).attr('href');
  42. // console.log(url);
  43. // $.post(url, function(data) {
  44. // console.log($('#keywords', data).text());
  45. // });
  46. // });
  47. //}
  48.  
  49.  
  50. // === SAVE ===
  51. function writeSettings() {
  52. GM.setValue('userList', JSON.stringify(userArray));
  53. }
  54.  
  55. // === FUNCTIONS ===
  56. // Hide user submissions
  57. function hideSubmissions(username) {
  58. if ($('figure').length) {
  59. // Beta
  60. var submissionBeta = $('figure.u-' + escapeUsername(username));
  61. var submissionFavesBeta = $('figure[data-user="u-' + escapeUsername(username) + '"]');
  62. var submissionInboxBeta = $('a[href="/user/' + username + '"]').closest('figure');
  63.  
  64. stylizeHidden(submissionBeta);
  65. stylizeHidden(submissionFavesBeta);
  66. stylizeHidden(submissionInboxBeta);
  67.  
  68. submissionBeta.addClass('hidden-sub').hide();
  69. submissionFavesBeta.addClass('hidden-sub').hide();
  70. submissionInboxBeta.find('input').prop('checked', true);
  71. submissionInboxBeta.addClass('hidden-sub').hide();
  72.  
  73. if (!filterEnabled['subs']) {
  74. submissionBeta.show();
  75. submissionInboxBeta.show();
  76. }
  77. } else {
  78. // Classic
  79. // Browse/Submissions
  80. var submission1 = $('b[id^="sid_"] a[href="/user/' + username + '/"]').closest('b');
  81. stylizeHidden(submission1);
  82. // Mark Submissions as Checked
  83. submission1.children('small').children('input').prop('checked', true);
  84. submission1.addClass('hidden-sub').hide();
  85.  
  86. // Favorites/Front Page
  87. var submission2 = $('b[id^="sid_"] img[src$="#' + username + '"]').closest('b');
  88. stylizeHidden(submission2);
  89. submission2.addClass('hidden-sub').hide();
  90.  
  91. // Correspond to UI
  92. if (!filterEnabled['subs']) {
  93. submission1.show();
  94. submission2.show();
  95. }
  96. }
  97. }
  98.  
  99. function showSubmissions(username) {
  100. // Browse/Submissions
  101. var submission1 = $('b[id^="sid_"] a[href="/user/' + username + '/"]').closest('b');
  102. var submissionBeta = $('figure.u-' + escapeUsername(username));
  103. var submissionFavesBeta = $('figure[data-user="u-' + escapeUsername(username) + '"]');
  104. var submissionInboxBeta = $('a[href^="/user/' + username + '"]').closest('figure');
  105.  
  106. undoStylize(submission1);
  107. undoStylize(submissionBeta);
  108. undoStylize(submissionFavesBeta);
  109. undoStylize(submissionInboxBeta);
  110.  
  111. // Mark Submissions as Checked
  112. submission1.children('small').children('input').prop('checked', false);
  113. submission1.removeClass('hidden-sub').show();
  114. submissionBeta.removeClass('hidden-sub').show();
  115. submissionFavesBeta.removeClass('hidden-sub').show();
  116. submissionInboxBeta.removeClass('hidden-sub').show();
  117. submissionInboxBeta.find('input').prop('checked', false);
  118.  
  119. // Favorites/Front Page
  120. var submission2 = $('b[id^="sid_"] img[src$="#' + username + '"]').closest('b');
  121. undoStylize(submission2);
  122. submission2.removeClass('hidden-sub').show();
  123. }
  124.  
  125. // Hide user shouts
  126. function hideShouts(username) {
  127. // Classic
  128. var shout = $('table[id^="shout-"] td.alt1 img[alt="' + username + '"]').closest('table[id^="shout-"]');
  129. shout.addClass('hidden-shout').hide();
  130. stylizeHidden(shout.find('table'));
  131. shout.next('br').addClass('hidden-shout-br').hide();
  132.  
  133. // Beta
  134. var shoutBeta = $('.comment_container .shout-avatar img[alt="' + username +'"]').closest('.comment_container');
  135. shoutBeta.addClass('hidden-shout').hide();
  136. stylizeHidden(shoutBeta.find('.header'));
  137. stylizeHidden(shoutBeta.find('.body'));
  138.  
  139. // We want to only highlight and check
  140. var shoutManageBeta = $('table[id^="shout-"] .comments-flex-item-icon img[alt="' + username +'"]').closest('table[id^="shout-"]');
  141. shoutManageBeta.addClass('hidden-shout');
  142. stylizeHidden(shoutManageBeta.find('.comments-userline-flex'));
  143. stylizeHidden(shoutManageBeta.find('.comment_text'));
  144. shoutManageBeta.find('input[type="checkbox"]').prop('checked', true);
  145. }
  146.  
  147. // Hide user comments and threads
  148. function hideComments(username) {
  149. // Classic
  150. var comments = $('.container-comment td.icon img[alt="' + username + '"]').closest('.container-comment');
  151.  
  152. $(comments).each(function() {
  153. // Hide comment and get width
  154. if (!($(this).hasClass('hidden-comment'))) {
  155. var width = Number($(this).addClass('hidden-comment').hide().attr('width').slice(0,-1));
  156. var current = $(this).next('.container-comment');
  157.  
  158. // Iterate through comments until there's a width that is greater than or equal
  159. while (true) {
  160. if (current.length) {
  161. if (Number(current.attr('width').slice(0,-1)) < width) {
  162. current.addClass('hidden-comment').hide();
  163. current = current.next('.container-comment');
  164. } else {
  165. break;
  166. }
  167. } else {
  168. break;
  169. }
  170. }
  171. }
  172. });
  173.  
  174. // Beta
  175. var commentsBeta = $('.comment_container .avatar img[alt="' + username + '"]').closest('.comment_container');
  176. stylizeHidden(commentsBeta.find('.header'));
  177. stylizeHidden(commentsBeta.find('.body'));
  178.  
  179. $(commentsBeta).each(function() {
  180. // Get width, then hide comment
  181. if (!($(this).hasClass('hidden-comment'))) {
  182. var width = $(this).width();
  183. var current = $(this).next('.comment_container');
  184.  
  185. $(this).addClass('hidden-comment').hide();
  186.  
  187. // Iterate through the comments until there's a width that is greater than or equal
  188. while (true) {
  189. if (current.length) {
  190. if (current.width() < width) {
  191. current.addClass('hidden-comment').hide();
  192. current = current.next('.comment_container');
  193. } else {
  194. break;
  195. }
  196. } else {
  197. break;
  198. }
  199. }
  200. }
  201. });
  202. }
  203.  
  204. // Hide user notifications
  205. function hideNotifications(username) {
  206. var notification = $('.message-stream a[href="/user/' + username + '/"]').closest('li');
  207. notification.addClass('hidden-notification').hide();
  208. stylizeHidden(notification);
  209. notification.children('input').prop('checked', true);
  210.  
  211. // Classic only
  212. notification.children('table').children('tbody').children('tr').children('td').children('.checkbox').children('input').prop('checked', true);
  213. }
  214.  
  215. function stylizeHidden(item) {
  216. $(item).css('background-color', '#FFBBBB');
  217. $(item).css('color', '#FF0000');
  218. $('a:link', item).css('color', '#FF0000');
  219. $('a:visited', item).css('color', '#FF0000');
  220. }
  221.  
  222. function undoStylize(item) {
  223. $(item).css('background-color', '');
  224. $(item).css('color', '');
  225. $('a:link', item).css('color', '');
  226. $('a:visited', item).css('color', '');
  227. }
  228.  
  229. // === UI ===
  230. // == Filter Toggle ==
  231. // Submissions
  232. function filtersSubs() {
  233. // Remove all pre-existing UI for soft-refresh
  234. $('[id="faf-toggle-subs"]').remove();
  235. $('.faf-remove-user-external').parent().remove();
  236. $('.faf-add-user-external').parent().remove();
  237.  
  238. if ($('.hidden-sub').length > 0) {
  239. // Classic
  240. if (!$('li.lileft').length) {
  241. $display = '<input style="float:right;" id="faf-toggle-subs" class="button" type="button" value="Toggle Filtered Submissions (' + $('.hidden-sub').length + ')"></input>';
  242. $('form').first().append($display);
  243. // Beta
  244. } else {
  245. $display = '<li class="lileft"><a class="top-heading" id="faf-toggle-subs" href="#!"><div class="sprite-nuke menu-space-saver hideonmobile"></div>Toggle Filtered Submissions (' + $('.hidden-sub').length + ')</a></li>';
  246. $('.lileft').last().after($display);
  247. }
  248. } else {
  249. filterEnabled['subs'] = true;
  250. }
  251.  
  252. if ($('figure').length) {
  253. // Beta
  254. $('figure').each(function() {
  255. var username = $(this).attr('class').match('u-([^\\s]+)');
  256. if (!username) {
  257. username = $(this).attr('data-user').match('u-([^\\s]+)');
  258. }
  259. if (username) {
  260. username = username[1];
  261. if (username in userArray && userArray[username]['subs'] === 1) {
  262. $(this).find('figcaption').append('<p><a style="color: #FF5555!important;" class="faf-remove-user-external" id="faf-' + username + '" href="#!" title="Remove ' + username + ' from filter">[Unfilter]</a></p>');
  263. } else {
  264. $(this).find('figcaption').append('<p><a style="color: #FF5555!important;" class="faf-add-user-external" id="faf-' + username + '" href="#!" title="Add ' + username + ' to filter">[Filter]</a></p>');
  265. }
  266. }
  267. });
  268. } else {
  269. $('b[id^="sid_"]').each(function() {
  270. var username = $(this).find('small a').attr('href');
  271. username = username.match('/user/(.*)/');
  272. if (username) {
  273. if (username[1] in userArray && userArray[username[1]]['subs'] === 1) {
  274. $(this).find('small').append('<span>&nbsp;<a style="color: #FF5555!important;" class="faf-remove-user-external" id="faf-' + username[1] + '" href="#!" title="Remove ' + username[1] + ' from filter">[Unfilter]</a></span>');
  275. } else {
  276. $(this).find('small').append('<span>&nbsp;<a style="color: #FF5555!important;" class="faf-add-user-external" id="faf-' + username[1] + '" href="#!" title="Add ' + username[1] + ' to filter">[Filter]</a></span>');
  277. }
  278. }
  279. });
  280. }
  281. }
  282.  
  283. // Followed Submissions
  284. function filtersSubsFollow() {
  285. if ($('.hidden-sub').length > 0) {
  286. // Beta
  287. if ($('.button-nav-item').length) {
  288. $display = '<div class="button-nav-item"><button class="button mobile-button" id="faf-toggle-subs" type="button">Toggle Filtered Submissions (' + $('.hidden-sub').length + ')</button></div>';
  289. $('.actions').css('max-width', '700px');
  290. } else {
  291. $display = '<input id="faf-toggle-subs" class="button" type="button" value="Toggle Filtered Submissions (' + $('.hidden-sub').length + ')"></input>';
  292. }
  293. $('.actions').append($display);
  294. }
  295. }
  296.  
  297. // Shouts
  298. function filtersShouts() {
  299. if ($('.hidden-shout').length > 0) {
  300. $display = '<center><input id="faf-toggle-shouts" class="button" type="button" value="Toggle Filtered Shouts (' + $('.hidden-shout').length + ')"></input></center>';
  301. // Classic
  302. $('table[id^="shout-"]').first().prevAll('table.maintable:first').append($display);
  303. // Beta
  304. $($display).insertAfter('#shoutboxentry');
  305. }
  306. }
  307.  
  308. // Shouts (Controls, Beta Only)
  309. function filtersShoutsControl() {
  310. if ($('.hidden-shout').length > 0) {
  311. $display = '<button id="faf-toggle-shouts" class="button mobile-button" type="button" value="Toggle Filtered Shouts (' + $('.hidden-shout').length + ')">Toggle Filtered Shouts (' + $('.hidden-shout').length + ')</button>';
  312. $('.section-divider').last().append($display);
  313. $('.hidden-shout input').prop('checked', true);
  314. }
  315. }
  316.  
  317. // Comments
  318. function filtersComments() {
  319. if ($('.hidden-comment').length > 0) {
  320. $display = '<input style="float:right;" id="faf-toggle-comments" class="button" type="button" value="Toggle Filtered Comments (' + $('.hidden-comment').length + ')"></input>';
  321. if (!$('.flex-submission-container').length) {
  322. // Classic
  323. $('table.container-comment').first().parent().parent().prev().children().append($display);
  324. } else {
  325. // Beta
  326. $($display).insertAfter('.flex-submission-container');
  327. }
  328. }
  329. }
  330.  
  331. // Notifications
  332. function filtersNotifications() {
  333. if ($('.hidden-notification').length > 0) {
  334. $display = '<input id="faf-toggle-notifications" class="button" type="button" value="Toggle Filtered Notifications (' + $('.hidden-notification').length + ')"></input>';
  335. $('.global-controls').append($display);
  336. $('.global_controls').append($display);
  337.  
  338. // = Notification Count =
  339. // Classic
  340. if ($('fieldset[id^="messages-watches"] .hidden-notification').length > 0)
  341. $('fieldset[id^="messages-watches"] h3').append(' (' + $('fieldset[id^="messages-watches"] .hidden-notification').length + ' filtered)');
  342. if ($('fieldset[id^="messages-comments-submission"] .hidden-notification').length > 0)
  343. $('fieldset[id^="messages-comments-submission"] h3').append(' (' + $('fieldset[id^="messages-comments-submission"] .hidden-notification').length + ' filtered)');
  344. if ($('fieldset[id^="messages-shouts"] .hidden-notification').length > 0)
  345. $('fieldset[id^="messages-shouts"] h3').append(' (' + $('fieldset[id^="messages-shouts"] .hidden-notification').length + ' filtered)');
  346. if ($('fieldset[id^="messages-favorites"] .hidden-notification').length > 0)
  347. $('fieldset[id^="messages-favorites"] h3').append(' (' + $('fieldset[id^="messages-favorites"] .hidden-notification').length + ' filtered)');
  348.  
  349. // Beta
  350. if ($('div[id^="messages-watches"] .hidden-notification').length > 0)
  351. $('div[id^="messages-watches"] h2').append(' (' + $('div[id^="messages-watches"] .hidden-notification').length + ' filtered)');
  352. if ($('div[id^="messages-comments-submission"] .hidden-notification').length > 0)
  353. $('div[id^="messages-comments-submission"] h2').append(' (' + $('div[id^="messages-comments-submission"] .hidden-notification').length + ' filtered)');
  354. if ($('div[id^="messages-shouts"] .hidden-notification').length > 0)
  355. $('div[id^="messages-shouts"] h2').append(' (' + $('div[id^="messages-shouts"] .hidden-notification').length + ' filtered)');
  356. if ($('div[id^="messages-favorites"] .hidden-notification').length > 0)
  357. $('div[id^="messages-favorites"] h2').append(' (' + $('div[id^="messages-favorites"] .hidden-notification').length + ' filtered)');
  358. if ($('div[id^="messages-journals"] .hidden-notification').length > 0)
  359. $('div[id^="messages-journals"] h2').append(' (' + $('div[id^="messages-journals"] .hidden-notification').length + ' filtered)');
  360. }
  361. }
  362.  
  363. // == Buttons ==
  364. // Show/Hide Submissions
  365. $(document.body).on('click', '#faf-toggle-subs', function() {
  366. $('.hidden-sub').toggle();
  367. filterEnabled['subs'] = !filterEnabled['subs'];
  368. });
  369.  
  370. // Show/Hide Shouts
  371. $(document.body).on('click', '#faf-toggle-shouts', function() {
  372. $('.hidden-shout').toggle();
  373. $('.hidden-shout-br').toggle();
  374. filterEnabled['shouts'] = !filterEnabled['shouts'];
  375. });
  376.  
  377. // Show/Hide Comments
  378. $(document.body).on('click', '#faf-toggle-comments', function() {
  379. $('.hidden-comment').toggle();
  380. filterEnabled['coms'] = !filterEnabled['coms'];
  381. });
  382.  
  383. // Show/Hide Notifications
  384. $(document.body).on('click', '#faf-toggle-notifications', function() {
  385. $('.hidden-notification').toggle();
  386. filterEnabled['notifications'] = !filterEnabled['notifications'];
  387. });
  388.  
  389. // == External Filters ==
  390. // Add submission filter outside of settings
  391. $(document.body).on('click', '.faf-add-user-external', function() {
  392. var addUser = $(this).attr('id').match('faf-(.*)')[1];
  393.  
  394. // Add to array
  395. if (!(addUser in userArray)) {
  396. userArray[addUser] = {'subs':1, 'shouts':0, 'coms':0, 'notifications':0};
  397. } else {
  398. userArray[addUser]['subs'] = 1;
  399. }
  400.  
  401. // Hide, replace link, and save
  402. hideSubmissions(addUser);
  403. filtersSubs();
  404. writeSettings();
  405. });
  406.  
  407. // Remove submission filter outside of settings
  408. $(document.body).on('click', '.faf-remove-user-external', function() {
  409. var removeUser = $(this).attr('id').match('faf-(.*)')[1];
  410.  
  411. // Remove from array
  412. if (removeUser in userArray) {
  413. userArray[removeUser]['subs'] = 0;
  414. }
  415.  
  416. // Show, replace link, and save
  417. showSubmissions(removeUser);
  418. filtersSubs();
  419. writeSettings();
  420. });
  421.  
  422. // == User Settings ==
  423. function displaySettings() {
  424. // Navbar link
  425. $('<li class="noblock"><a target="_blank" href="/controls/site-settings#fa-filter">FA Filter</a></li>').insertAfter($('li.sfw-toggle'));
  426.  
  427. if (window.location.pathname.lastIndexOf('/controls/site-settings', 0) === 0) {
  428. // Brute forced, but there are no tables in the beta layout site-settings page. This is one of the major differences.
  429. if (!$('table').length) {
  430. // Beta HTML Code
  431. var settingsDisplay = '<section>' +
  432. '<div class="section-body">' +
  433. '<h2 id="fa-filter">FA Filter</h2>' +
  434. '<h4>Add a User</h4>' +
  435. '<div class="control-panel-option">' +
  436. '<div class="control-panel-item-1">' +
  437. '<p>Tired of seeing somebody\'s contributions on the site? Add them to your filter list!<br/><strong>Note:</strong> Enter in the username of the person you want to filter, which is the username that would appear after "furaffinity.net/user/".' +
  438. '</div>' +
  439. '<div class="control-panel-item-2">' +
  440. '<input class="textbox" type="text" id="faf-add-username" maxlength="50"></input>&nbsp;<input id="faf-add" class="button" type="button" value="Add" />' +
  441. '</div>' +
  442. '</div>' +
  443. '<h4>Validate Filters</h4>' +
  444. '<div class="control-panel-option">' +
  445. '<div class="control-panel-item-1">' +
  446. '<p>This double-checks to make sure that your filtered usernames are correct and, optionally, removes users that don\'t have any enabled filters.<br/><strong>Note:</strong> This automatically saves the list.</p>' +
  447. '</div>' +
  448. '<div class="control-panel-item-2">' +
  449. '<select name="faf-validate-options" id="select-faf-validate-options" class="styled">' +
  450. '<option value="v" selected="selected">Vaildate Filters Only</option>' +
  451. '<option value="vr">Validate and Remove Unused Filters</option>' +
  452. '</select><input id="faf-validate" class="button" type="button" value="Apply" /><br/>' +
  453. '<span class="faf-validate-status" style="font-weight: bold; color: #009900; display: none;">Validated! 0 user(s) have been modified or removed.</span>' +
  454. '</div>' +
  455. '</div>' +
  456. '<div class="maintable rounded">' +
  457. '<table class="sessions-list faf-list faf-list-beta" width="100%" cellspacing="0" cellpadding="0" border="0" style="padding:0 15px 10px 15px">' +
  458. '<tbody>' +
  459. '<tr>' +
  460. '<td class="p10t p5r p5b"><h3>Username</h3></td>' +
  461. '<td class="p10t p5r p5b" width="200px"><h3>Submissions</h3></td>' +
  462. '<td class="p10t p5r p5b" width="200px"><h3>Shouts</h3></td>' +
  463. '<td class="p10t p5r p5b" width="200px"><h3>Comments</h3></td>' +
  464. '<td class="p10t p5r p5b" width="200px"><h3>Notifications</h3></td>' +
  465. '</tr>' +
  466. '</tbody>' +
  467. '</table>' +
  468. '</div>' +
  469. '</div>' +
  470. '<div class="section-footer alignright">' +
  471. '<span class="faf-update-status" style="font-weight: bold; color: #006600; display: none;">Update successful!</span>&nbsp;&nbsp;<input class="button mobile-button" id="faf-update" type="button" value="Apply Filters (FA Filter)">' +
  472. '</div>' +
  473. '</section>';
  474. $(settingsDisplay).insertBefore($('section').last());
  475. } else {
  476. // Classic HTML Code
  477. var settingsDisplay = '<table id="fa-filter" cellpadding="0" cellspacing="1" border="0" class="section maintable"><tbody>' +
  478. '<tr><td height="22" class="cat links">&nbsp;<strong>FA Filter</strong></td></tr>' +
  479. '<tr><td class="alt1 addpad ucp-site-settings" align="center">' +
  480. '<table cellspacing="1" cellpadding="0" border="0"><tbody>' +
  481. '<tr>' +
  482. '<th><strong>Add a User</strong></th>' +
  483. '<td><input type="text" id="faf-add-username" maxlength="50"></input>&nbsp;<input id="faf-add" class="button" type="button" value="Add User"></td>' +
  484. '<td class="option-description">' +
  485. '<h3>Hide a user\'s contributions to the site.</h3>' +
  486. '<p>Tired of seeing somebody\'s contributions on the site? Add them to your filter list!<br>Note: Enter in the username of the person you want to filter, which is the username that would appear after "furaffinity.net/user/".</p>' +
  487. '</td>' +
  488. '</tr>' +
  489. '<tr>' +
  490. '<th><strong>Validate Filters</strong></th>' +
  491. '<td>' +
  492. '<select name="faf-validate-options" id="select-faf-validate-options" class="styled">' +
  493. '<option value="v" selected="selected">Vaildate Filters Only</option>' +
  494. '<option value="vr">Validate and Remove Unused Filters</option>' +
  495. '</select>&nbsp;<input id="faf-validate" class="button" type="button" value="Apply" /><br/>' +
  496. '<span class="faf-validate-status" style="font-weight: bold; color: #009900; display: none;">Validated! 0 user(s) have been modified or removed.</span>' +
  497. '</td>' +
  498. '<td class="option-description">' +
  499. '<h3>Clean up everything and revalidate filtered usernames.</h3>' +
  500. '<p>This double-checks to make sure that your filtered usernames are correct and, optionally, removes users that don\'t have any enabled filters.<br/><strong>Note:</strong> This automatically saves the list.</p>' +
  501. '</td>' +
  502. '</tr>' +
  503. '<tr>' +
  504. '<th class="noborder" style="vertical-align: text-top;"><strong style="position: relative; top: 25px;">Modify Filters</strong></th>' +
  505. '<td class="noborder">' +
  506. '<table cellspacing="0" cellpadding="0" border="0" class="faf-list faf-list-classic">' +
  507. '<tr><th><strong>Username</strong></th><th><strong>Submissions</strong></th><th><strong>Shouts</strong></th><th><strong>Comments</strong></th><th><strong>Notifications</strong></th></tr>' +
  508. '</table>' +
  509. '<br><br><input class="button" id="faf-update" type="button" value="Apply Filters (FA Filter)"> <span class="faf-update-status" style="font-weight: bold; color: #006600; display: none;">Update successful!</span>' +
  510. '</td>' +
  511. '<td class="option-description noborder">' +
  512. '<h3>Choose what items you don\'t want to see.</h3>' +
  513. '<p>If you still want to see some of the things that a user contributes, you can control that here.</p>' +
  514. '</td>' +
  515. '</tr>' +
  516. '</tbody></table>' +
  517. '</td></tr>' +
  518. '</tbody></table>';
  519. $('form').append(settingsDisplay);
  520. }
  521.  
  522. // Populate list
  523. $.each(userArray, function(username, data) {
  524. addFilterUser(username, data);
  525. });
  526. }
  527. }
  528.  
  529. // Display user in the filter table
  530. function addFilterUser(username, data) {
  531. // Classic
  532. if ($('table.faf-list-classic').length) {
  533.  
  534. var row = '<tr class="checked" id="filter-' + username + '"><td class="noborder"><a class="fa-filter-remove fonthighlight" id="faf-rm-' + username + '" href="#!">[x]</a> ' + username + '</td>';
  535. if (data['subs'] === 1) { row += '<td class="noborder"><input id="faf-check-subs-' + username + '" type="checkbox" checked="checked"></td>'; } else { row += '<td class="noborder"><input id="faf-check-subs-' + username + '" type="checkbox"></td>'; }
  536. if (data['shouts'] === 1) { row += '<td class="noborder"><input id="faf-check-shouts-' + username + '" type="checkbox" checked="checked"></td>'; } else { row += '<td class="noborder"><input id="faf-check-shouts-' + username + '" type="checkbox"></td>'; }
  537. if (data['coms'] === 1) { row += '<td class="noborder"><input id="faf-check-coms-' + username + '" type="checkbox" checked="checked"></td>'; } else { row += '<td class="noborder"><input id="faf-check-coms-' + username + '" type="checkbox"></td>'; }
  538. if (data['notifications'] === 1) { row += '<td class="noborder"><input id="faf-check-notifications-' + username + '" type="checkbox" checked="checked"></td>'; } else { row += '<td class="noborder"><input id="faf-check-notifications-' + username + '" type="checkbox"></td>'; }
  539.  
  540. row += '</tr>';
  541.  
  542. $('table.faf-list tr:last').after(row);
  543. // Beta
  544. } else {
  545. var rowBeta = '<tr id="filter-' + username + '"><td class="p5r" valign="middle" width="auto"><a class="fa-filter-remove" id="faf-rm-' + username + '" href="#!">[x]</a> ' + username + '</td>';
  546. if (data['subs'] === 1) { rowBeta += '<td class="p5r" valign="middle" width="auto"><input id="faf-check-subs-' + username + '" type="checkbox" checked="checked"></td>'; } else { rowBeta += '<td class="p5r" valign="middle" width="auto"><input id="faf-check-subs-' + username + '" type="checkbox"></td>'; }
  547. if (data['shouts'] === 1) { rowBeta += '<td class="p5r" valign="middle" width="auto"><input id="faf-check-shouts-' + username + '" type="checkbox" checked="checked"></td>'; } else { rowBeta += '<td class="p5r" valign="middle" width="auto"><input id="faf-check-shouts-' + username + '" type="checkbox"></td>'; }
  548. if (data['coms'] === 1) { rowBeta += '<td class="p5r" valign="middle" width="auto"><input id="faf-check-coms-' + username + '" type="checkbox" checked="checked"></td>'; } else { rowBeta += '<td class="p5r" valign="middle" width="auto"><input id="faf-check-coms-' + username + '" type="checkbox"></td>'; }
  549. if (data['notifications'] === 1) { rowBeta += '<td class="p5r" valign="middle" width="auto"><input id="faf-check-notifications-' + username + '" type="checkbox" checked="checked"></td>'; } else { rowBeta += '<td class="p5r" valign="middle" width="auto"><input id="faf-check-notifications-' + username + '" type="checkbox"></td>'; }
  550.  
  551. rowBeta += '</tr>';
  552.  
  553. $('table.faf-list tr:last').after(rowBeta);
  554. }
  555. }
  556.  
  557. // Add
  558. $(document.body).on('click', '#faf-add', function() {
  559. var username = $.trim($('#faf-add-username').val());
  560. $('#faf-add-username').val('');
  561. if (username !== '') {
  562. username = username.toLowerCase();
  563. username = username.replace(/[_]/g, '');
  564. if (!(username in userArray)) {
  565. userArray[username] = {'subs':1, 'shouts':1, 'coms':1, 'notifications':1};
  566. addFilterUser(username, userArray[username]);
  567. }
  568. }
  569. });
  570.  
  571. // Remove
  572. $(document.body).on('click', 'a.fa-filter-remove', function(event) {
  573. var username = event.target.id.substr(7);
  574. delete userArray[username];
  575.  
  576. userEsc = escapeUsername(username);
  577.  
  578. $('table.faf-list tr#filter-' + userEsc).remove();
  579. });
  580.  
  581. // Update
  582. $(document.body).on('click', '#faf-update', function() {
  583. $('.faf-list tr[id^="filter-"]').each(function() {
  584. var username = this.id.substr(7);
  585. var vals = {'subs':0, 'shouts':0, 'coms':0, 'notifications':0};
  586.  
  587. userEsc = escapeUsername(username);
  588.  
  589. // Check checkboxes
  590. if ($('#faf-check-subs-' + userEsc).is(':checked')) { vals['subs'] = 1; }
  591. if ($('#faf-check-shouts-' + userEsc).is(':checked')) { vals['shouts'] = 1; }
  592. if ($('#faf-check-coms-' + userEsc).is(':checked')) { vals['coms'] = 1; }
  593. if ($('#faf-check-notifications-' + userEsc).is(':checked')) { vals['notifications'] = 1; }
  594.  
  595. userArray[username] = vals;
  596. });
  597.  
  598. // Save
  599. writeSettings();
  600.  
  601. // Display message
  602. $('.faf-update-status').fadeIn('slow');
  603. setTimeout(function() {
  604. $('.faf-update-status').fadeOut('slow');
  605. }, 5000);
  606. });
  607.  
  608. // Validate
  609. $(document.body).on('click', '#faf-validate', function() {
  610. var modCount = 0;
  611. // Validate
  612. $.each(userArray, function(username, data) {
  613. var tempUsername = username;
  614. tempUsername = tempUsername.trim();
  615. if (tempUsername !== '') {
  616. tempUsername = tempUsername.toLowerCase();
  617. tempUsername = tempUsername.replace(/[_ ]/g, '');
  618. if (tempUsername !== username) {
  619. userArray[tempUsername] = data;
  620. delete userArray[username];
  621. $('tr[id="filter-' + username + '"]').remove();
  622. modCount++;
  623. }
  624. }
  625. });
  626.  
  627. // Remove empty
  628. if ($('#select-faf-validate-options').val() === 'vr') {
  629. $.each(userArray, function(username, data) {
  630. var isEmpty = true;
  631. $.each(data, function(entity, value) {
  632. if (value === 1) {
  633. isEmpty = false;
  634. }
  635. });
  636. if (isEmpty) {
  637. delete userArray[username];
  638. $('tr[id="filter-' + username + '"]').remove();
  639. modCount++;
  640. }
  641. });
  642. }
  643.  
  644. // Save
  645. writeSettings();
  646.  
  647. // Display message
  648. $('.faf-validate-status').text('Validated! ' + modCount + ' user(s) have been modified or removed.');
  649. $('.faf-validate-status').fadeIn('slow');
  650. setTimeout(function() {
  651. $('.faf-validate-status').fadeOut('slow');
  652. }, 5000);
  653. });
  654.  
  655. // === UTILITIES ===
  656. function escapeUsername(username) {
  657. // Replace periods/colons/tildes with escaped versions. Who the fuck allows periods AND tildes in usernames, seriously?
  658. userEsc = username.replace(/\./g, '\\.');
  659. userEsc = userEsc.replace(/:/g, '\\:');
  660. userEsc = userEsc.replace(/~/g, '\\~');
  661. return userEsc;
  662. }
  663.  
  664. function updateCSS() {
  665. var newCSS = '<style type="text/css">' +
  666. 'section.gallery figure { padding-bottom: 62px; }' +
  667. '</style>';
  668. $('head').append(newCSS);
  669. }
  670.  
  671. displaySettings();
  672. updateCSS();
  673.  
  674. setTimeout(parseSettings, 50);
  675. //setTimeout(parseTagSettings, 100);
  676.  
  677. // Submissions
  678. if (window.location.pathname.lastIndexOf('/browse', 0) === 0) setTimeout(filtersSubs, 100);
  679. else if (window.location.pathname.lastIndexOf('/favorites', 0) === 0) setTimeout(filtersSubs, 100);
  680. else if (window.location.pathname.lastIndexOf('/msg/submissions', 0) === 0) setTimeout(filtersSubsFollow, 100);
  681. // Shouts
  682. else if (window.location.pathname.lastIndexOf('/user', 0) === 0) setTimeout(filtersShouts, 100);
  683. else if (window.location.pathname.lastIndexOf('/controls/shouts', 0) === 0) setTimeout(filtersShoutsControl, 100);
  684. // Comments
  685. else if (window.location.pathname.lastIndexOf('/view', 0) === 0) setTimeout(filtersComments, 100);
  686. // Notifications
  687. else if (window.location.pathname.lastIndexOf('/msg/others', 0) === 0) setTimeout(filtersNotifications, 100);
  688. else setTimeout(filtersSubs, 100);
  689. }
  690.  
  691. main();