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