4chan-Ignoring-Enhancements

4chan Pain Kill Extension

اعتبارا من 16-03-2018. شاهد أحدث إصدار.

  1. // ==UserScript==
  2. // @name 4chan-Ignoring-Enhancements
  3. // @namespace http://tampermonkey.net/
  4. // @version 3.7
  5. // @description 4chan Pain Kill Extension
  6. // @author ECHibiki-/qa/
  7. // @match http://boards.4chan.org/*
  8. // @match https://boards.4chan.org/*
  9. // @include https://boards.4chan.org/*
  10. // @include http://boards.4chan.org/*
  11. // @run-at document-start
  12. // ==/UserScript==
  13.  
  14. /*
  15. This userscript enables 4chan users to hide images in the catalog and threads.
  16. Gives the ability to hide images with ctrl+shift+click. Stores in browser memory for new sessions.
  17. Also includes the ability to do word replacements with a regex replacement system.
  18. */
  19.  
  20. var local_store_threads = [];
  21. var browser;
  22. var finished = false;
  23. var window_displayed = false;
  24. var default_expire_time = 172800000;
  25.  
  26. var expire_time;
  27. var md5_filters;
  28. var md5_filters_arr = [];
  29.  
  30. var number_of_filters = 0;
  31. var initial_filters = [];
  32. var filtered_threads = [];
  33. var kill = [];
  34. var finished = false;
  35. var observer;
  36.  
  37. var blank_png = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAACXBIWXMAALiMAAC4jAHM9rsvAAAAG3RFWHRTb2Z0d2FyZQBDZWxzeXMgU3R1ZGlvIFRvb2zBp+F8AAAAo0lEQVR42u3RAQ0AAAjDMO5f9LFBSCdhTdvRnQIEiIAAERAgAgJEQIC4AERAgAgIEAEBIiBABERAgAgIEAEBIiBABERAgAgIEAEBIiBABERAgAgIEAEBIiBABERAgAgIEAEBIiBABERAgAgIEAEBIiBABERAgAgIEAEBIiBABERAgAgIEAEBIiBABERAgAgIEAEBIiBABAQIECACAkRAgAjI9xbzUCtI4axs4wAAAABJRU5ErkJggg==";
  38.  
  39. //The following is image hiding functions.
  40. //The next are filter functions
  41. //The last are setup functions
  42.  
  43. /**
  44. 0000000000000000000000000000000000000000000000000000000000000000000000000000000////0000000000000000000000000000000000000000000000000000000000000000000000000000000//
  45. //0000000000000000000000000000000000000000000000000000000000000000000000000000000////0000000000000000000000000000000000000000000000000000000000000000000000000000000//
  46. //0000000000000000000000000000000000000000000000000000000000000000000000000000000////0000000000000000000000000000000000000000000000000000000000000000000000000000000//
  47. //0000000000000000000000000000000000000000000000000000000000000000000000000000000////0000000000000000000000000000000000000000000000000000000000000000000000000000000//
  48. //0000000000000000000000000000000000000000000000000000000000000000000000000000000////0000000000000000000000000000000000000000000000000000000000000000000000000000000//
  49. //0000000000000000000000000000000000000000000000000000000000000000000000000000000////0000000000000000000000000000000000000000000000000000000000000000000000000000000//
  50. //0000000000000000000000000000000000000000000000000000000000000000000000000000000////0000000000000000000000000000000000000000000000000000000000000000000000000000000//
  51. //0000000000000000000000000000000000000000000000000000000000000000000000000000000////0000000000000000000000000000000000000000000000000000000000000000000000000000000//
  52. **/
  53.  
  54.  
  55. //is storage possible
  56. function storageAvailable(type) {
  57. try {
  58. var storage = window[type],
  59. x = '__storage_test__';
  60. storage.setItem(x, x);
  61. storage.removeItem(x);
  62. return true;
  63. }
  64. catch(e) {
  65. //From https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API
  66. return e instanceof DOMException && (
  67. // everything except Firefox
  68. e.code === 22 ||
  69. // Firefox
  70. e.code === 1014 ||
  71. // test name field too, because code might not be present
  72. // everything except Firefox
  73. e.name === 'QuotaExceededError' ||
  74. // Firefox
  75. e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
  76. // acknowledge QuotaExceededError only if there's something already stored
  77. storage.length !== 0;
  78. }
  79. }
  80.  
  81. //What Browser
  82. function detectBrowser() {
  83. if((navigator.userAgent.indexOf("Opera") || navigator.userAgent.indexOf('OPR')) != -1 )
  84. {
  85. console.log("Opera");
  86. return 0;
  87. }
  88. else if(navigator.userAgent.indexOf("Chrome") != -1 )
  89. {
  90. console.log("Chrome");
  91. return 1;
  92. }
  93. else if(navigator.userAgent.indexOf("Safari") != -1)
  94. {
  95. console.log("Safari");
  96. return 2;
  97. }
  98. else if(navigator.userAgent.indexOf("Firefox") != -1 )
  99. {
  100. console.log("FireFox");
  101. return 3;
  102. }
  103. else if((navigator.userAgent.indexOf("MSIE") != -1 ) || (!!document.documentMode == true )) //IF IE > 10
  104. {
  105. console.log("IE");
  106. return 4;
  107. }
  108. else
  109. {
  110. console.log("Other");
  111. return -1;
  112. }
  113. }
  114.  
  115. //hide image onclick listener.
  116. //Method 404's a given image. This 404'ing allows image dissabling to be toggled on and off.
  117. //Post number associated with the image is stored in local storage.
  118. function hideImage(event){
  119. var hide_index = this.src.indexOf("base64");
  120. if((event.ctrlKey && event.shiftKey) && hide_index == -1){
  121. event.preventDefault();
  122. event.stopPropagation();
  123. if (storageAvailable('localStorage')) {
  124. localStorage.setItem(this.getAttribute("hide-grouping"), Date.now());
  125. }
  126. else {
  127. console.log("No Storage");
  128. }
  129. //some browsers require a querry on the image URL to 404 it.
  130. var nodes = document.querySelectorAll('img[hide-grouping="'+this.getAttribute("hide-grouping")+'"]');
  131. nodes.forEach(function(node){
  132. if(node.getAttribute("hide-grouping") == event.target.getAttribute("hide-grouping")){
  133. node.setAttribute("hidden-src", node.src);
  134. node.src = blank_png;//this.src + ".HIDDEN" + "?" + Date.now();
  135. }
  136. });
  137. return false;
  138. }
  139. else if(event.ctrlKey && event.shiftKey){
  140. event.preventDefault();
  141. event.stopPropagation();
  142. if (storageAvailable('localStorage')) {
  143. localStorage.removeItem(this.getAttribute("hide-grouping"));
  144. }
  145. else {
  146. console.log("No Storage");
  147. }
  148. var nodes = document.querySelectorAll('img[hide-grouping="'+this.getAttribute("hide-grouping")+'"]');
  149. nodes.forEach(function(node){
  150. if(node.getAttribute("hide-grouping") == event.target.getAttribute("hide-grouping")){
  151. node.src = node.getAttribute("hidden-src");
  152. }
  153. });
  154. return false;
  155. }
  156. return true;
  157. }
  158.  
  159. //functions to find properties by regex
  160. function getPropertyByRegex(obj,propName) {
  161. var re = new RegExp("^" + propName + "(\\[\\d*\\])?$"),
  162. key;
  163. var rtnArray = [];
  164. for (key in obj)
  165. if (re.test(key))
  166. rtnArray.push(key);
  167. return rtnArray;
  168. }
  169.  
  170. //retrieve from memory the hidden images
  171. //Images are stored in memory as f<ID_NUMBER>IMG and recalled using the storage_key
  172. //Function makes a check to see if the hiding time limit for the thread has expired or not.
  173. //Note: Must have the DOM itterate through before retrieval
  174. function retrieveStates(){
  175. var storage_position = 0,
  176. oJson = {},
  177. storage_key;
  178. while(storage_position < window.localStorage.length) {
  179. storage_key = window.localStorage.key(storage_position);
  180. oJson[storage_key] = window.localStorage.getItem(storage_key);
  181. storage_position++;
  182. }
  183. local_store_threads = getPropertyByRegex(oJson,"[0-9]+IMG");
  184. expire_time = localStorage.getItem("Expiration_Time");
  185. md5_filters = localStorage.getItem("MD5_List_FSE");
  186. if(md5_filters !== null)
  187. md5_filters_arr = md5_filters.split("\n");
  188. md5_filters_arr.forEach(function(md5, index){
  189. md5 = md5.trim();
  190. md5_filters_arr[index] = md5.substring(1, md5.length - 1);
  191. });
  192. }
  193.  
  194.  
  195. //settings for time expiration on image hiding
  196. function hideWindow(){
  197. var style = document.createElement('style');
  198. style.innerHTML = ".inputs{background-color:rgb(200,200,200);margin:5px 7px;width:100px;}";
  199. document.body.appendChild(style);
  200.  
  201. var background_div = document.createElement("div");
  202. background_div.setAttribute("style", "border:solid 1px black;position:fixed;width:100%;height:100%;background-color:rgba(200,200,200,0.3);top:0;left:0;display:none; z-index:9");
  203. background_div.setAttribute("id", "hiBackground");
  204. document.body.appendChild(background_div);
  205. background_div.addEventListener("click", hideToggle);
  206.  
  207. var window_div = document.createElement("div");
  208. window_div.setAttribute("style", "border:solid 1px black;position:fixed;width:400px;background-color:rgb(200,200,200);left:40%;top:20%;margin-bottom:0; display:none; z-index:10");
  209. window_div.setAttribute("id", "hiWindow");
  210.  
  211. var close_div = document.createElement("div");
  212. close_div.setAttribute("style", "border:solid 1px black;position:absolute;width:25px;height:25px;background-color:rgba(255,100,90,0.9); right:3px;top:3px; z-index:10");
  213. close_div.addEventListener("click", hideToggle);
  214. window_div.appendChild(close_div);
  215.  
  216. var title_para = document.createElement("p");
  217. title_para.setAttribute("style", "margin-left:5px;margin-top:5px");
  218. var title_text = document.createTextNode("Filter Settings");
  219. title_para.appendChild(title_text);
  220. window_div.appendChild(title_para);
  221.  
  222. var container_div = document.createElement("div");
  223. container_div.setAttribute("style","background-color:white;margin:0 0;padding:5px;");
  224. window_div.appendChild(container_div);
  225.  
  226. var expiration_label = document.createElement("label");
  227. var expiration_text = document.createTextNode("Non-MD5 Expiration Time(hours): ");
  228. expiration_label.appendChild(expiration_text);
  229. container_div.appendChild(expiration_label);
  230. var expiration_input = document.createElement("input");
  231. expiration_input.setAttribute("id", "Expiration_Time");
  232.  
  233. expiration_input.value = expire_time / 3600000;
  234.  
  235. container_div.appendChild(expiration_input);
  236. container_div.appendChild(expiration_input);
  237. container_div.appendChild(document.createElement("hr"));
  238.  
  239. var md5_label = document.createElement("label");
  240. var md5_text = document.createTextNode("MD5 Filters:");
  241. var md5_textarea = document.createElement("TextArea");
  242. md5_textarea.setAttribute("style", "width:98%;height:217px");
  243.  
  244. if(md5_filters !== null)
  245. md5_textarea.value = md5_filters;
  246.  
  247. md5_textarea.setAttribute("placeholder", "Enter MD5 like on 4chanX... \n/abc123/\n/def890/");
  248. md5_textarea.setAttribute("ID", "MD5_List_FSE");
  249. container_div.appendChild(md5_label);
  250. md5_label.appendChild(md5_text);
  251. container_div.appendChild(document.createElement("br"));
  252. container_div.appendChild(md5_textarea);
  253.  
  254. container_div.appendChild(document.createElement("hr"));
  255.  
  256. var set_button = document.createElement("input");
  257. set_button.setAttribute("type", "button");
  258. set_button.setAttribute("id", "setTime");
  259. set_button.setAttribute("value", "Set");
  260. set_button.addEventListener("click", function(){
  261. if (storageAvailable('localStorage')) {
  262. var time = document.getElementById("Expiration_Time");
  263. var millisecond_time = time.value * 3600000;
  264. if (millisecond_time == 0 || millisecond_time === null || millisecond_time === undefined) millisecond_time = default_expire_time;
  265. expire_time = millisecond_time;
  266. localStorage.setItem("Expiration_Time", millisecond_time);
  267.  
  268. md5_filters = document.getElementById("MD5_List_FSE").value;
  269. localStorage.setItem("MD5_List_FSE", md5_filters);
  270.  
  271. hideToggle();
  272. }
  273. });
  274. container_div.appendChild(set_button);
  275.  
  276. document.body.appendChild(window_div);
  277.  
  278. }
  279.  
  280. function hideToggle(){
  281. if(window_displayed){
  282. document.getElementById("hiWindow").style.display = "none";
  283. document.getElementById("hiBackground").style.display = "none";
  284. window_displayed = false;
  285. }
  286. else{
  287. document.getElementById("hiWindow").style.display = "inline-block";
  288. document.getElementById("hiBackground").style.display = "inline-block";
  289. window_displayed = true;
  290. }
  291. }
  292.  
  293. function hideButton(){
  294. var hide_button = document.createElement("input");
  295. hide_button.setAttribute("Value", "Hide Image Settings");
  296. hide_button.setAttribute("type", "button");
  297. hide_button.setAttribute("style", "position:absolute;top:45px");
  298. hideWindow();
  299. if(document.body === null){
  300. setTimeout(hideButton, 30);
  301. }
  302. else{
  303. document.body.appendChild(hide_button);
  304. hide_button.addEventListener("click", hideToggle);
  305. }
  306. }
  307.  
  308.  
  309. /**111111111111111111111111111111111111111111111111111111111111////111111111111111111111111111111111111111111111111111111111111//
  310. //111111111111111111111111111111111111111111111111111111111111////111111111111111111111111111111111111111111111111111111111111//
  311. //111111111111111111111111111111111111111111111111111111111111////111111111111111111111111111111111111111111111111111111111111//
  312. //111111111111111111111111111111111111111111111111111111111111////111111111111111111111111111111111111111111111111111111111111//
  313. //111111111111111111111111111111111111111111111111111111111111////111111111111111111111111111111111111111111111111111111111111//
  314. //111111111111111111111111111111111111111111111111111111111111////111111111111111111111111111111111111111111111111111111111111//
  315. //111111111111111111111111111111111111111111111111111111111111////111111111111111111111111111111111111111111111111111111111111//
  316. //111111111111111111111111111111111111111111111111111111111111////111111111111111111111111111111111111111111111111111111111111//
  317. */
  318.  
  319. //store filter settings
  320. function loadSettings(){
  321. var filter_setting = 0,
  322. oJson = {},
  323. storage_key;
  324. while( filter_setting < window.localStorage.length) {
  325. filter_setting++;
  326. storage_key = window.localStorage.key(filter_setting);
  327. oJson[storage_key] = window.localStorage.getItem(storage_key);
  328. }
  329. number_of_filters = oJson["q"];
  330. filters = getPropertyByRegex(oJson,"filter[0-9]*");
  331. filters.forEach(function(filter){
  332. initial_filters.push(formatSettings(oJson[filter]));
  333. });
  334. }
  335.  
  336. function saveSettings(){
  337.  
  338. kill = []; //Determins if a certain pattern should be used or not due to regex errors from the user
  339.  
  340. if(storageAvailable('localStorage')){
  341. window.localStorage.setItem("q", number_of_filters);
  342. for (var pattern_input = 0 ; pattern_input < number_of_filters; pattern_input++){
  343. var pattern_to_store = document.getElementById("Pattern"+pattern_input).value;
  344. var replacement_to_store = document.getElementById("Replacement"+pattern_input).value;
  345. var setting = "g";
  346. if(pattern_to_store === "" || replacement_to_store === "") continue;
  347. if (pattern_to_store.charAt(0) == "/" && pattern_to_store.charAt(pattern_to_store.length - 1) == "/"){
  348. pattern_to_store = pattern_to_store + setting;
  349. }
  350. else if(pattern_to_store.charAt(0) !== "/" && pattern_to_store.substr(pattern_to_store.length - 2).match(/\/[a-zA-Z$]/) == null){
  351. pattern_to_store = "/" + pattern_to_store + "/" + setting;
  352. }
  353. document.getElementById("Pattern"+pattern_input).value = pattern_to_store;
  354. var save_string = '"' + document.getElementById("Active"+pattern_input).checked + '"-"' + pattern_to_store + '"-"' + replacement_to_store + '"';
  355. window.localStorage.setItem("filter" + pattern_input, save_string);
  356. }
  357. }
  358. alert("Replacements Saved");
  359. }
  360.  
  361. //Splits the saved settings into components
  362. function formatSettings(input){
  363. var rtn = input.split('"-"');
  364. var i = 0;
  365. rtn.forEach(function(filter){
  366. rtn[i] = filter.replace("\"", "");
  367. i++;
  368. });
  369. return rtn;
  370. }
  371.  
  372. function filterWindow(){
  373. var style = document.createElement('style');
  374. style.innerHTML = ".inputs{background-color:rgb(200,200,200);margin:5px 7px;width:100px;}";
  375. document.body.appendChild(style);
  376.  
  377. var background_div = document.createElement("div");
  378. background_div.setAttribute("style", "border:solid 1px black;position:fixed;width:100%;height:100%;background-color:rgba(200,200,200,0.3);top:0;left:0;display:none; z-index:9");
  379. background_div.setAttribute("id", "FilterBackground");
  380. document.body.appendChild(background_div);
  381. background_div.addEventListener("click", filterToggle);
  382.  
  383. var window_div = document.createElement("div");
  384. window_div.setAttribute("style", "border:solid 1px black;position:fixed;width:400px;background-color:rgb(200,200,200);left:40%;top:20%;margin-bottom:0; display:none; z-index:10");
  385. window_div.setAttribute("id", "FilterWindow");
  386.  
  387. var close_div = document.createElement("div");
  388. close_div.setAttribute("style", "border:solid 1px black;position:absolute;width:25px;height:25px;background-color:rgba(255,100,90,0.9); right:3px;top:3px; z-index:10");
  389. close_div.addEventListener("click", filterToggle);
  390. window_div.appendChild(close_div);
  391.  
  392. var title_para = document.createElement("p");
  393. title_para.setAttribute("style", "margin-left:5px;margin-top:5px");
  394. var title_text = document.createTextNode("Filter Settings");
  395. title_para.appendChild(title_text);
  396. window_div.appendChild(title_para);
  397.  
  398. var container_div = document.createElement("div");
  399. container_div.setAttribute("style","background-color:white;margin:0 0;padding:5px;");
  400. window_div.appendChild(container_div);
  401.  
  402. var filter_table = document.createElement("table");
  403. filter_table.setAttribute("style", "text-align:center;");
  404. filter_table.setAttribute("id", "filter_table");
  405. container_div.appendChild(filter_table);
  406.  
  407. var table_row = document.createElement("tr");
  408. filter_table.appendChild(table_row);
  409. var table_head_active = document.createElement("th");
  410. var head_text_active = document.createTextNode("Active");
  411. table_head_active.appendChild(head_text_active);
  412. filter_table.appendChild(table_head_active);
  413. var table_head_pattern = document.createElement("th");
  414. var headTextPattern = document.createTextNode("Pattern");
  415. table_head_pattern.appendChild(headTextPattern);
  416. filter_table.appendChild(table_head_pattern);
  417. var table_head_replacement = document.createElement("th");
  418. var head_text_replacement = document.createTextNode("Replacement");
  419. table_head_replacement.appendChild(head_text_replacement);
  420. filter_table.appendChild(table_head_replacement);
  421.  
  422.  
  423. //Create the pattern table
  424. //loop to create rows
  425. if (number_of_filters === 0 || isNaN(number_of_filters)) number_of_filters = 6;
  426. for (var i = 0; i < number_of_filters ; i++){
  427. var table_row_contents = document.createElement("tr");
  428. table_row_contents.setAttribute("id", "FilterRow" + i);
  429.  
  430. var table_data_active = document.createElement("td");
  431. var table_checkbox_active = document.createElement("input");
  432. table_checkbox_active.setAttribute("type", "checkbox");
  433. table_checkbox_active.setAttribute("id", "Active" + i);
  434. table_data_active.appendChild(table_checkbox_active);
  435. table_row_contents.appendChild(table_data_active);
  436.  
  437. var table_data_pattern = document.createElement("td");
  438. var table_input_pattern = document.createElement("input");
  439. table_input_pattern.setAttribute("class", "inputs");
  440. table_input_pattern.setAttribute("id", "Pattern" + i);
  441. table_data_pattern.appendChild(table_input_pattern);
  442. table_row_contents.appendChild(table_data_pattern);
  443.  
  444. var table_data_replacement = document.createElement("td");
  445. var table_input_replacement = document.createElement("input");
  446. table_input_replacement.setAttribute("class", "inputs");
  447. table_input_replacement.setAttribute("id", "Replacement" + i);
  448. table_data_replacement.appendChild(table_input_replacement);
  449. table_row_contents.appendChild(table_data_replacement);
  450.  
  451. filter_table.appendChild(table_row_contents);
  452. }
  453.  
  454. var table_last_contents = document.createElement("tr");
  455.  
  456. var table_add_collumn = document.createElement("td");
  457. var table_add_row_button = document.createElement("input");
  458. var table_subtract_row_button = document.createElement("input");
  459. table_subtract_row_button.setAttribute("type", "button");
  460. table_subtract_row_button.setAttribute("value", "-");
  461. table_subtract_row_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
  462. table_add_collumn.appendChild(table_subtract_row_button);
  463. table_subtract_row_button.addEventListener("click", removeRow);
  464. table_add_row_button.setAttribute("type", "button");
  465. table_add_row_button.setAttribute("value", "+");
  466. table_add_row_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
  467. table_add_collumn.appendChild(table_add_row_button);
  468. table_add_row_button.addEventListener("click", addRow);
  469.  
  470. table_last_contents.appendChild(table_add_collumn);
  471.  
  472. var table_set_collumn = document.createElement("td");
  473. var table_confirm_button = document.createElement("input");
  474. table_confirm_button.setAttribute("type", "button");
  475. table_confirm_button.setAttribute("id", "table_confirm_button");
  476. table_confirm_button.setAttribute("value", "Set Replacements");
  477. table_confirm_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
  478. table_confirm_button.addEventListener("click", saveSettings);
  479. table_confirm_button.addEventListener("click", modifyDOM);
  480. table_confirm_button.addEventListener("click", filterToggle);
  481. table_set_collumn.appendChild(table_confirm_button);
  482. table_last_contents.appendChild(table_set_collumn);
  483.  
  484.  
  485. var table_close_collumn = document.createElement("td");
  486. var table_close_button = document.createElement("input");
  487. table_close_button.setAttribute("type", "button");
  488. table_close_button.setAttribute("value", "Close Menu");
  489. table_close_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
  490. table_close_button.addEventListener("click", filterToggle);
  491. table_close_collumn.appendChild(table_close_button);
  492. table_last_contents.appendChild(table_close_collumn);
  493.  
  494. filter_table.appendChild(table_last_contents);
  495.  
  496. document.body.appendChild(window_div);
  497.  
  498. }
  499.  
  500. function filterToggle(){
  501. if(window_displayed){
  502. document.getElementById("FilterWindow").style.display = "none";
  503. document.getElementById("FilterBackground").style.display = "none";
  504. window_displayed = false;
  505. }
  506. else{
  507. document.getElementById("FilterWindow").style.display = "inline-block";
  508. document.getElementById("FilterBackground").style.display = "inline-block";
  509. window_displayed = true;
  510. }
  511. }
  512.  
  513. function filterButton(){
  514. var filter_button = document.createElement("input");
  515. filter_button.setAttribute("Value", "Word Filter Settings");
  516. filter_button.setAttribute("type", "button");
  517. filter_button.setAttribute("style", "position:absolute;top:75px");
  518. filter_button.addEventListener("click", filterWindow);
  519. document.body.appendChild(filter_button);
  520. filter_button.addEventListener("click", filterToggle);
  521. }
  522.  
  523. function addRow(){
  524. var filter_table = document.getElementById("filter_table");
  525. filter_table.deleteRow(parseInt(number_of_filters) + 1);
  526. number_of_filters++;
  527.  
  528. var table_row_contents = document.createElement("tr");
  529. table_row_contents.setAttribute("id", "FilterRow" + (number_of_filters - 1));
  530.  
  531. var table_data_active = document.createElement("td");
  532. var table_checkbox_active = document.createElement("input");
  533. table_checkbox_active.setAttribute("type", "checkbox");
  534. table_checkbox_active.setAttribute("id", "Active" + (number_of_filters - 1));
  535. table_data_active.appendChild(table_checkbox_active);
  536. table_row_contents.appendChild(table_data_active);
  537.  
  538. var table_data_pattern = document.createElement("td");
  539. var table_input_pattern = document.createElement("input");
  540. table_input_pattern.setAttribute("class", "inputs");
  541. table_input_pattern.setAttribute("id", "Pattern" + (number_of_filters - 1));
  542. table_data_pattern.appendChild(table_input_pattern);
  543. table_row_contents.appendChild(table_data_pattern);
  544.  
  545. var table_data_replacement = document.createElement("td");
  546. var table_input_replacement = document.createElement("input");
  547. table_input_replacement.setAttribute("class", "inputs");
  548. table_input_replacement.setAttribute("id", "Replacement" + (number_of_filters - 1));
  549. table_data_replacement.appendChild(table_input_replacement);
  550. table_row_contents.appendChild(table_data_replacement);
  551.  
  552. filter_table.appendChild(table_row_contents);
  553.  
  554. var table_last_contents = document.createElement("tr");
  555.  
  556. var table_add_collumn = document.createElement("td");
  557. var table_add_row_button = document.createElement("input");
  558. var table_subtract_row_button = document.createElement("input");
  559. table_subtract_row_button.setAttribute("type", "button");
  560. table_subtract_row_button.setAttribute("value", "-");
  561. table_subtract_row_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
  562. table_add_collumn.appendChild(table_subtract_row_button);
  563. table_subtract_row_button.addEventListener("click", removeRow);
  564. table_add_row_button.setAttribute("type", "button");
  565. table_add_row_button.setAttribute("value", "+");
  566. table_add_row_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
  567. table_add_collumn.appendChild(table_add_row_button);
  568. table_add_row_button.addEventListener("click", addRow);
  569.  
  570. table_last_contents.appendChild(table_add_collumn);
  571.  
  572. var table_set_collumn = document.createElement("td");
  573. var table_confirm_button = document.createElement("input");
  574. table_confirm_button.setAttribute("type", "button");
  575. table_confirm_button.setAttribute("id", "table_confirm_button");
  576. table_confirm_button.setAttribute("value", "Set Replacements");
  577. table_confirm_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
  578. table_confirm_button.addEventListener("click", saveSettings);
  579. table_confirm_button.addEventListener("click", modifyDOM);
  580. table_confirm_button.addEventListener("click", filterToggle);
  581. table_set_collumn.appendChild(table_confirm_button);
  582. table_last_contents.appendChild(table_set_collumn);
  583.  
  584. var table_close_collumn = document.createElement("td");
  585. var table_close_button = document.createElement("input");
  586. table_close_button.setAttribute("type", "button");
  587. table_close_button.setAttribute("value", "Close Menu");
  588. table_close_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
  589. table_close_button.addEventListener("click", filterToggle);
  590. table_close_collumn.appendChild(table_close_button);
  591. table_last_contents.appendChild(table_close_collumn);
  592.  
  593. filter_table.appendChild(table_last_contents);
  594. }
  595.  
  596. function removeRow(){
  597. var filter_table = document.getElementById("filter_table");
  598. if(number_of_filters != 0){
  599. filter_table.deleteRow(number_of_filters);
  600. number_of_filters--;
  601. }
  602. }
  603.  
  604. function setTable(){
  605. var filter_count = 0;
  606. initial_filters.forEach(function(filter){
  607. if(filter[2] === null || filter[1] === null || filter[0] === null || filter_count == number_of_filters) return;
  608. if(filter[0] == "true"){
  609. document.getElementById("Active"+filter_count).checked = true;
  610. }
  611. else if(filter[0] == "false"){
  612. document.getElementById("Active"+filter_count).checked = false;
  613. }
  614. document.getElementById("Pattern"+filter_count).value = filter[1];
  615. document.getElementById("Replacement"+filter_count).value = filter[2];
  616. filter_count++;
  617. });
  618. }
  619.  
  620.  
  621. //222222222222222222222222222222222222222222222222222222222222////2222222222222222222222222222222222222222222222222222222222221111111111111111111111111111//
  622. //222222222222222222222222222222222222222222222222222222222222////2222222222222222222222222222222222222222222222222222222222221111111111111111111111111111//
  623. //222222222222222222222222222222222222222222222222222222222222////2222222222222222222222222222222222222222222222222222222222221111111111111111111111111111//
  624. //222222222222222222222222222222222222222222222222222222222222////2222222222222222222222222222222222222222222222222222222222221111111111111111111111111111//
  625. //222222222222222222222222222222222222222222222222222222222222////2222222222222222222222222222222222222222222222222222222222221111111111111111111111111111//
  626. //222222222222222222222222222222222222222222222222222222222222////2222222222222222222222222222222222222222222222222222222222221111111111111111111111111111//
  627. //222222222222222222222222222222222222222222222222222222222222////2222222222222222222222222222222222222222222222222222222222221111111111111111111111111111//
  628. //222222222222222222222222222222222222222222222222222222222222////2222222222222222222222222222222222222222222222222222222222221111111111111111111111111111//
  629. //222222222222222222222222222222222222222222222222222222222222////2222222222222222222222222222222222222222222222222222222222221111111111111111111111111111//
  630. //222222222222222222222222222222222222222222222222222222222222////2222222222222222222222222222222222222222222222222222222222221111111111111111111111111111//
  631.  
  632. //Functions to set the DOM listener and observers
  633.  
  634. var hidden_count = 0;
  635. function modifyDOM(){
  636. var start = document.getElementById("delform");
  637. var itterator = document.createTreeWalker(start, NodeFilter.SHOW_ELEMENTS, NodeFilter.SHOW_ELEMENTS);
  638. var node = "";
  639.  
  640. while((node = itterator.nextNode())){
  641. decisionProcess(node, itterator);
  642. }
  643. if(!page_setup)
  644. console.log("HIDDEN THREADS: " + hidden_count);
  645. }
  646.  
  647. function decisionProcess(node, itterator){
  648. var cname = node.className;
  649. var tag = node.tagName;
  650. if(tag === "IMG" || tag === "img"){
  651. if(!/\d+IMG/.test(node.getAttribute("hide-grouping")) && (node.getAttribute("data-md5") !== null)){
  652. filterImage(node);
  653. }
  654. }
  655. else if(cname == "postMessage"){
  656. var blockquote_id = node.id;
  657. var already_filtered = false;
  658. filtered_threads.forEach(function(thread_id){
  659. if(thread_id == blockquote_id) {
  660. already_filtered = true;
  661. return;
  662. }
  663. });
  664. if(!already_filtered){
  665. if(itterator == undefined) itterator = document.createTreeWalker(node, NodeFilter.SHOW_ELEMENTS, NodeFilter.SHOW_ELEMENTS);
  666. var localNode;
  667. while((localNode = itterator.nextNode())){
  668. var className = localNode.className;
  669. if(className == undefined || className == "quotelink"){
  670. for(var i = 0 ; i < number_of_filters; i++){
  671. if(kill[i] == true) continue;
  672. filter = document.getElementById("Pattern"+i);
  673. replacement = document.getElementById("Replacement"+i);
  674. active = document.getElementById("Active"+i);
  675. if(active.checked){
  676. var lastChar = filter.value.length - 1;
  677. var filterText = filter.value;
  678. if(filterText === "") break;
  679. var setting = filterText.substr(lastChar);
  680. filterText = filterText.substr(1, lastChar-2);
  681. try{
  682. var regex = new RegExp(filterText, setting);
  683. var node_text = localNode.textContent;
  684. if(regex.test(node_text)){
  685. localNode.textContent = node_text.replace(regex, replacement.value);
  686. filtered_threads.push(blockquote_id);
  687. }
  688. }
  689. catch(e){
  690. alert(i + "'s regex was invalid");
  691. kill[i] = true;
  692. }
  693. }
  694. }
  695. }
  696. else break;
  697. }
  698. }
  699. }
  700. }
  701.  
  702. function filterImage(node){
  703. var sister_node = node.parentNode.parentNode.parentNode.getElementsByClassName("catalog-thumb")[0]; // the catalog sister to index
  704. if(sister_node === undefined) sister_node = document.createElement("IMG");
  705.  
  706. node.setAttribute("hide-grouping", node.parentNode.parentNode.id.substring(1) + "IMG");
  707. sister_node.setAttribute("hide-grouping", node.parentNode.parentNode.id.substring(1) + "IMG");
  708.  
  709. node.addEventListener("click", hideImage, {passive:false, capture:false, once:false});
  710. sister_node.addEventListener("click", hideImage, {passive:false, capture:false, once:false});
  711.  
  712. var threadstore_len = local_store_threads.length;
  713. var node_group_id = node.getAttribute("hide-grouping");
  714.  
  715. for(var thread = 0 ; thread < threadstore_len; thread++){
  716. if(node_group_id == local_store_threads[thread]){
  717. node.setAttribute("hidden-src", node.src);
  718. node.src = blank_png;//this.src + ".HIDDEN" + "?" + Date.now();
  719.  
  720. sister_node.setAttribute("hidden-src", sister_node.src);
  721. sister_node.src = blank_png;//this.src + ".HIDDEN" + "?" + Date.now();
  722.  
  723. hidden_count++;
  724. return;
  725. }
  726. }
  727. //index node holds the MD5
  728. var node_md5 = node.getAttribute("data-md5");
  729. var md5_filters_arr_len = md5_filters_arr.length;
  730. for(var md5 = 0 ; md5 < md5_filters_arr_len; md5++){
  731. if(node_md5 == md5_filters_arr[md5]){
  732. node.setAttribute("hidden-src", node.src);
  733. node.src = blank_png;//this.src + ".HIDDEN" + "?" + Date.now();
  734.  
  735. sister_node.setAttribute("hidden-src", sister_node.src);
  736. sister_node.src = blank_png;//this.src + ".HIDDEN" + "?" + Date.now();
  737.  
  738. hidden_count++;
  739. return;
  740. }
  741. }
  742. }
  743.  
  744. function hoverUIObserver(mutations){
  745. mutations.forEach(function(mutation){
  746. mutation.addedNodes.forEach(function(image_node){
  747. var is_embeded_post;
  748. if(image_node.tagName == "DIV") {
  749. is_embeded_post = true;
  750. image_node = image_node.getElementsByClassName("postContainer")[0];
  751. if(image_node === undefined) return;
  752. }
  753.  
  754. var unprocessed_id = image_node.getAttribute("data-full-i-d");
  755. if (unprocessed_id === null) return;
  756. var proccessed_id = unprocessed_id.substring(unprocessed_id.indexOf(".") + 1);
  757. var image_node_id = proccessed_id + "IMG";
  758. if(is_embeded_post) image_node = image_node.getElementsByTagName("IMG")[0];
  759. if(image_node === undefined) return;
  760.  
  761. var threadstore_len = local_store_threads.length;
  762. for(var thread = 0 ; thread < threadstore_len; thread++){
  763. if(image_node_id == local_store_threads[thread]){
  764. image_node.removeAttribute("src");
  765. return;
  766. }
  767. }
  768. //thread node holds the MD5
  769. var node_md5;
  770. if(is_embeded_post) node_md5 = image_node.getAttribute("data-md5");
  771. else node_md5 = document.getElementById("f" + proccessed_id).getElementsByTagName("IMG")[0].getAttribute("data-md5");
  772. var md5_filters_arr_len = md5_filters_arr.length;
  773. for(var md5 = 0 ; md5 < md5_filters_arr_len; md5++){
  774. if(node_md5 == md5_filters_arr[md5]){
  775. image_node.removeAttribute("src");
  776. return;
  777. }
  778. }
  779. });
  780. });
  781. }
  782.  
  783. //initial onload setup
  784. function hideSetup(){
  785. retrieveStates();
  786. hideButton();
  787. }
  788.  
  789. function filterSetup(){
  790. loadSettings();
  791. filterButton();
  792. filterWindow();
  793. setTable();
  794. }
  795.  
  796. function pkxSetup(){
  797. expire_time = localStorage.getItem("Expiration_Time");
  798. md5_filters = localStorage.getItem("MD5_List_FSE");
  799.  
  800. hideSetup();
  801. filterSetup();
  802. // initial_setup_observer.disconnect();
  803. modifyDOM();
  804. document.addEventListener('PostsInserted',function(e){
  805. retrieveStates();
  806. modifyDOM();
  807. });
  808. new MutationObserver(function(mutations){
  809. retrieveStates();
  810. hoverUIObserver(mutations);
  811. }).observe(document.getElementById("hoverUI"), {childList: true});
  812. }
  813.  
  814. //4chanX exists
  815. var page_setup = false;
  816. document.addEventListener('4chanXInitFinished', function(e) {
  817. browser = detectBrowser();
  818. pkxSetup();
  819. console.log("Script loaded: 4chanPKX");
  820. page_setup = true;
  821. }, false);