docs and Ignoring-Enhancement edits in proggress
[4Free-FSE.git] / 4chan-Ignoring-Enhancements.user.js
blobe930fa2991fa61e83c0316bf30d53bb6bd829844
1 // ==UserScript==
2 // @name         4chan-Ignoring-Enhancements
3 // @namespace    http://tampermonkey.net/
4 // @version      1.6
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-body
12 // @updateURL    https://github.com/ECHibiki/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;
27 var expire_time;
29 var number_of_filters = 0;
30 var initial_filters = [];
31 var kill = [];
32 var finished = false;
33 var observer;
35 //The following is image hiding functions.
36 //The next are filter functions
37 //The last are setup functions
39 /**
40 0000000000000000000000000000000000000000000000000000000000000000000000000000000////0000000000000000000000000000000000000000000000000000000000000000000000000000000//
41 //0000000000000000000000000000000000000000000000000000000000000000000000000000000////0000000000000000000000000000000000000000000000000000000000000000000000000000000//
42 //0000000000000000000000000000000000000000000000000000000000000000000000000000000////0000000000000000000000000000000000000000000000000000000000000000000000000000000//
43 //0000000000000000000000000000000000000000000000000000000000000000000000000000000////0000000000000000000000000000000000000000000000000000000000000000000000000000000//
44 //0000000000000000000000000000000000000000000000000000000000000000000000000000000////0000000000000000000000000000000000000000000000000000000000000000000000000000000//
45 //0000000000000000000000000000000000000000000000000000000000000000000000000000000////0000000000000000000000000000000000000000000000000000000000000000000000000000000//
46 //0000000000000000000000000000000000000000000000000000000000000000000000000000000////0000000000000000000000000000000000000000000000000000000000000000000000000000000//
47 //0000000000000000000000000000000000000000000000000000000000000000000000000000000////0000000000000000000000000000000000000000000000000000000000000000000000000000000//
48 **/
51 //is storage possible
52 function storageAvailable(type) {
53     try {
54         var storage = window[type],
55             x = '__storage_test__';
56         storage.setItem(x, x);
57         storage.removeItem(x);
58         return true;
59     }
60     catch(e) {
61                 //From https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API
62         return e instanceof DOMException && (
63             // everything except Firefox
64             e.code === 22 ||
65             // Firefox
66             e.code === 1014 ||
67             // test name field too, because code might not be present
68             // everything except Firefox
69             e.name === 'QuotaExceededError' ||
70             // Firefox
71             e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
72             // acknowledge QuotaExceededError only if there's something already stored
73             storage.length !== 0;
74     }
77 //What Browser
78 function detectBrowser() { 
79     if((navigator.userAgent.indexOf("Opera") || navigator.userAgent.indexOf('OPR')) != -1 ) 
80     {
81         //console.log("Opera");
82         return 0;
83     }
84     else if(navigator.userAgent.indexOf("Chrome") != -1 )
85     {
86         //console.log("Chrome");
87         return 1;
88     }
89     else if(navigator.userAgent.indexOf("Safari") != -1)
90     {
91         //console.log("Safari");
92         return 2;
93     }
94     else if(navigator.userAgent.indexOf("Firefox") != -1 ) 
95     {
96         //console.log("FireFox");
97         return 3;
98     }
99     else if((navigator.userAgent.indexOf("MSIE") != -1 ) || (!!document.documentMode == true )) //IF IE > 10
100     {
101         //console.log("IE");
102         return 4;
103     }  
104     else 
105     {
106         //console.log("Other");
107         return -1;
108     }
111 //hide image onclick listener.
112 //Method 404's a given image. This 404'ing allows image dissabling to be toggled on and off.
113 //Post number associated with the image is stored in local storage.
114 function hideImage(event){
115     var hide_index = this.src.indexOf(".HIDDEN");
116     if((event.ctrlKey && event.shiftKey) && hide_index == -1){
117         event.preventDefault();
118         event.stopPropagation();
119         if (storageAvailable('localStorage')) {
120             if(this.id.charAt(0) == "p") this.id =  "f" + this.id.substr(1);
121             localStorage.setItem(this.id, Date.now());
122         }
123         else {
124             //console.log("No Storage");
125         }
126                 //some browsers require a querry on the image URL to 404 it.
127         this.src = this.src + ".HIDDEN" +  "?" + Date.now();
128         return false;
129     }
130     else if(event.ctrlKey && event.shiftKey){
131         event.preventDefault();
132         event.stopPropagation();
133         if (storageAvailable('localStorage')) {
134             if(this.id.charAt(0) == "p") this.id =  "f" + this.id.substr(1);
135             localStorage.removeItem(this.id);
136         }
137         else {
138             //console.log("No Storage");
139         }
140         this.src = this.src.substring(0, hide_index);
141         return false;
142     }
143     return true;
146 //functions to find properties by regex
147 function getPropertyByRegex(obj,propName) {
148     var re = new RegExp("^" + propName + "(\\[\\d*\\])?$"),
149         key;
150     var rtnArray = [];
151     for (key in obj)
152         if (re.test(key))
153             rtnArray.push(key);
154     return rtnArray;
157 //retrieve from memory the hidden images
158 //Images are stored in memory as f<ID_NUMBER>IMG and recalled using the storage_key
159 //Function makes a check to see if the hiding time limit for the thread has expired or not.
160 var hidden_count = 0;
161 function retrieveStates(){
162     var storage_position = 0,
163         oJson = {},
164         storage_key;
165     while(storage_position < window.localStorage.length) {
166         storage_position++;
167         storage_key = window.localStorage.key(storage_position);
168         oJson[storage_key] = window.localStorage.getItem(storage_key);
169     }
170     local_store_threads = getPropertyByRegex(oJson,"f[0-9]*IMG");
171         expire_time =  localStorage.getItem("ExpirationTime");
172         
173     local_store_threads.forEach(function callback(thread){
174                 //console.log(Date.now() - oJson[thread] + " > " + expire_time);
175         if(Date.now() - oJson[thread] > expire_time)
176             localStorage.removeItem(thread);
177                 
178                 //set hidden threads
179                 var image_node;
180         image_node = document.getElementById(""+thread);
181                 if(image_node !== null && image_node.src.indexOf(".HIDDEN") == -1){
182             image_node.src = image_node.src + ".HIDDEN" +  "?" + Date.now(); 
183             hidden_count++;
184         }
185                 
186                 image_node = document.getElementById("p"+thread.substring(1));
187                 if(image_node !== null && image_node.src.indexOf(".HIDDEN") == -1){
188             image_node.src = image_node.src + ".HIDDEN" +  "?" + Date.now(); 
189             hidden_count++;
190         }
191                 
192                 image_node = document.getElementById("thread-"+thread.substring(1));
193                 if(image_node !== null && image_node.src.indexOf(".HIDDEN") == -1){
194             image_node.src = image_node.src + ".HIDDEN" +  "?" + Date.now(); 
195             hidden_count++;
196         }
197                 image_node = document.getElementById("thumb-"+thread.substring(1));
198                 if(image_node !== null && image_node.src.indexOf(".HIDDEN") == -1){
199             image_node.src = image_node.src + ".HIDDEN" +  "?" + Date.now(); 
200             hidden_count++;
201         }
202                 
205     });
206         // half the ammount because it hides both index and catalog
207     console.log("HIDDEN THREADS: " + hidden_count / 2);
211 //settings for time expiration on image hiding
212 function hideWindow(){
213     var style = document.createElement('style');
214     style.innerHTML = ".inputs{background-color:rgb(200,200,200);margin:5px 7px;width:100px;}";
215     document.body.appendChild(style);
217     var background_div = document.createElement("div");
218     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");
219     background_div.setAttribute("id", "hiBackground");
220     document.body.appendChild(background_div);
221     background_div.addEventListener("click", hideToggle);
223     var window_div = document.createElement("div");
224     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");
225     window_div.setAttribute("id", "hiWindow");
227     var close_div = document.createElement("div");
228     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");
229     close_div.addEventListener("click", hideToggle);
230     window_div.appendChild(close_div);
232     var title_para = document.createElement("p");
233     title_para.setAttribute("style", "margin-left:5px;margin-top:5px");
234     var title_text = document.createTextNode("Filter Settings");
235     title_para.appendChild(title_text);
236     window_div.appendChild(title_para);
238     var container_div = document.createElement("div");
239     container_div.setAttribute("style","background-color:white;margin:0 0;padding:5px;");
240     window_div.appendChild(container_div);
242     var expiration_label = document.createElement("label");
243     var expiration_text = document.createTextNode("Expiration Time(hours): ");
244     expiration_label.appendChild(expiration_text);
245     container_div.appendChild(expiration_label);
246     var expiration_input = document.createElement("input");
247     expiration_input.setAttribute("id", "expirationTime");
248     container_div.appendChild(expiration_input);
249     container_div.appendChild(expiration_input);
250     container_div.appendChild(document.createElement("br"));
251     var set_button = document.createElement("input");
252     set_button.setAttribute("type", "button");
253     set_button.setAttribute("id", "setTime");
254     set_button.setAttribute("value", "Set Time");
255     set_button.addEventListener("click", function(){
256         if (storageAvailable('localStorage')) {
257             var time = document.getElementById("expirationTime");
258             var millisecond_time = time.value * 3600000;
259             if (millisecond_time == 0 || millisecond_time === null || millisecond_time === undefined) millisecond_time = default_expire_time; 
260             expire_time = millisecond_time;
261             localStorage.setItem("ExpirationTime", millisecond_time);
262             hideToggle();
263         }
264     });
265     expiration_input.setAttribute("value", localStorage.getItem("ExpirationTime") / 3600000);
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;
277     }
278     else{
279         document.getElementById("hiWindow").style.display = "inline-block";
280         document.getElementById("hiBackground").style.display = "inline-block";
281         window_displayed = true;
282     }     
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);
293     }
294     else{
295         document.body.appendChild(hide_button);
296         hide_button.addEventListener("click", hideToggle);
297     }
298     expire_time =  localStorage.getItem("ExpirationTime");
302 /**111111111111111111111111111111111111111111111111111111111111////111111111111111111111111111111111111111111111111111111111111//
303 //111111111111111111111111111111111111111111111111111111111111////111111111111111111111111111111111111111111111111111111111111//
304 //111111111111111111111111111111111111111111111111111111111111////111111111111111111111111111111111111111111111111111111111111//
305 //111111111111111111111111111111111111111111111111111111111111////111111111111111111111111111111111111111111111111111111111111//
306 //111111111111111111111111111111111111111111111111111111111111////111111111111111111111111111111111111111111111111111111111111//
307 //111111111111111111111111111111111111111111111111111111111111////111111111111111111111111111111111111111111111111111111111111//
308 //111111111111111111111111111111111111111111111111111111111111////111111111111111111111111111111111111111111111111111111111111//
309 //111111111111111111111111111111111111111111111111111111111111////111111111111111111111111111111111111111111111111111111111111//
312 //store filter settings
313 function loadSettings(){
314     var filter_setting = 0,
315         oJson = {},
316         storage_key;
317     while( filter_setting < window.localStorage.length) {
318         filter_setting++;
319         storage_key = window.localStorage.key(filter_setting);
320         oJson[storage_key] = window.localStorage.getItem(storage_key);
321     }
322     number_of_filters = oJson["q"];
323     //console.log(number_of_filters);
324     filters = getPropertyByRegex(oJson,"filter[0-9]*");
325     filters.forEach(function(filter){
326         initial_filters.push(formatSettings(oJson[filter]));
327     });
330 function saveSettings(){
331         
332     kill = []; //Determins if a certain pattern should be used or not due to regex errors from the user
333         
334     if(storageAvailable('localStorage')){
335         window.localStorage.setItem("q", number_of_filters);
336         for (var pattern_input = 0 ; pattern_input < number_of_filters; pattern_input++){
337             var pattern_to_store = document.getElementById("Pattern"+pattern_input).value;
338             var replacement_to_store = document.getElementById("Replacement"+pattern_input).value;
339             var setting = "g";
340             if(pattern_to_store === "" || replacement_to_store === "") continue; 
341             if (pattern_to_store.charAt(0) == "/" && pattern_to_store.charAt(pattern_to_store.length - 1) == "/"){
342                 pattern_to_store = pattern_to_store + setting;
343             }
344             else if(pattern_to_store.charAt(0) !== "/" && pattern_to_store.substr(pattern_to_store.length - 2).match(/\/[a-zA-Z$]/) == null){
345                 pattern_to_store = "/" + pattern_to_store + "/" + setting;
346             }
347             document.getElementById("Pattern"+pattern_input).value = pattern_to_store;
348             var save_string = '"' + document.getElementById("Active"+pattern_input).checked + '"-"' + pattern_to_store + '"-"' + replacement_to_store + '"';
349             window.localStorage.setItem("filter" + pattern_input, save_string);
350         }
351     }
352     alert("Replacements Saved");
355 //Splits the saved settings into components
356 function formatSettings(input){
357     var rtn =  input.split('"-"');
358     var i = 0;
359     rtn.forEach(function(filter){
360         rtn[i] = filter.replace("\"", "");
361         i++;
362     });
363     return rtn;
367 function filterWindow(){
368     var style = document.createElement('style');
369     style.innerHTML = ".inputs{background-color:rgb(200,200,200);margin:5px 7px;width:100px;}";
370     document.body.appendChild(style);
372     var background_div = document.createElement("div");
373     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");
374     background_div.setAttribute("id", "FilterBackground");
375     document.body.appendChild(background_div);
376     background_div.addEventListener("click",  filterToggle);
378     var window_div = document.createElement("div");
379     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");
380     window_div.setAttribute("id", "FilterWindow");
382     var close_div = document.createElement("div");
383     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");
384     close_div.addEventListener("click",  filterToggle);
385     window_div.appendChild(close_div);
387     var title_para = document.createElement("p");
388     title_para.setAttribute("style", "margin-left:5px;margin-top:5px");
389     var title_text = document.createTextNode("Filter Settings");
390     title_para.appendChild(title_text);
391     window_div.appendChild(title_para);
393     var container_div = document.createElement("div");
394     container_div.setAttribute("style","background-color:white;margin:0 0;padding:5px;");
395     window_div.appendChild(container_div);
397     var filter_table = document.createElement("table");
398     filter_table.setAttribute("style", "text-align:center;");
399     filter_table.setAttribute("id", "filter_table");
400     container_div.appendChild(filter_table);
402     var table_row = document.createElement("tr");
403     filter_table.appendChild(table_row);
404     var table_head_active =  document.createElement("th");
405     var head_text_active = document.createTextNode("Active");
406     table_head_active.appendChild(head_text_active);
407     filter_table.appendChild(table_head_active);
408     var table_head_pattern =  document.createElement("th");
409     var headTextPattern = document.createTextNode("Pattern");
410     table_head_pattern.appendChild(headTextPattern);
411     filter_table.appendChild(table_head_pattern);
412     var table_head_replacement =  document.createElement("th");
413     var head_text_replacement = document.createTextNode("Replacement");
414     table_head_replacement.appendChild(head_text_replacement);
415     filter_table.appendChild(table_head_replacement);
417         
418         //Create the pattern table
419     //loop to create rows
420     if (number_of_filters === 0 || isNaN(number_of_filters)) number_of_filters = 6;
421     for (var i = 0; i <  number_of_filters ; i++){
422         var table_row_contents = document.createElement("tr");
423         table_row_contents.setAttribute("id", "FilterRow" + i);
425         var table_data_active =  document.createElement("td");
426         var table_checkbox_active = document.createElement("input");
427         table_checkbox_active.setAttribute("type", "checkbox");
428         table_checkbox_active.setAttribute("id", "Active" + i);
429         table_data_active.appendChild(table_checkbox_active);
430         table_row_contents.appendChild(table_data_active);
432         var table_data_pattern =  document.createElement("td");
433         var table_input_pattern = document.createElement("input");
434         table_input_pattern.setAttribute("class", "inputs");
435         table_input_pattern.setAttribute("id", "Pattern" + i);
436         table_data_pattern.appendChild(table_input_pattern);
437         table_row_contents.appendChild(table_data_pattern);
439         var table_data_replacement =  document.createElement("td");
440         var table_input_replacement =  document.createElement("input");
441         table_input_replacement.setAttribute("class", "inputs");
442         table_input_replacement.setAttribute("id", "Replacement" + i);
443         table_data_replacement.appendChild(table_input_replacement);
444         table_row_contents.appendChild(table_data_replacement);
446         filter_table.appendChild(table_row_contents);
447     }
449     var table_last_contents = document.createElement("tr");
451     var table_add_collumn =  document.createElement("td");
452     var table_add_row_button = document.createElement("input");
453     var table_subtract_row_button = document.createElement("input");
454     table_subtract_row_button.setAttribute("type", "button");
455     table_subtract_row_button.setAttribute("value", "-");
456     table_subtract_row_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
457     table_add_collumn.appendChild(table_subtract_row_button);
458     table_subtract_row_button.addEventListener("click", removeRow);
459     table_add_row_button.setAttribute("type", "button");
460     table_add_row_button.setAttribute("value", "+");
461     table_add_row_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
462     table_add_collumn.appendChild(table_add_row_button);
463     table_add_row_button.addEventListener("click", addRow);
465     table_last_contents.appendChild(table_add_collumn);
467     var table_set_collumn =  document.createElement("td");
468     var table_confirm_button = document.createElement("input");
469     table_confirm_button.setAttribute("type", "button");
470     table_confirm_button.setAttribute("id", "table_confirm_button");
471     table_confirm_button.setAttribute("value", "Set Replacements");
472     table_confirm_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
473     table_confirm_button.addEventListener("click", saveSettings);
474     table_confirm_button.addEventListener("click", modifyDOM);
475     table_confirm_button.addEventListener("click", filterToggle);
476     table_set_collumn.appendChild(table_confirm_button);
477     table_last_contents.appendChild(table_set_collumn);
480     var table_close_collumn = document.createElement("td");
481     var table_close_button = document.createElement("input");
482     table_close_button.setAttribute("type", "button");
483     table_close_button.setAttribute("value", "Close Menu");
484     table_close_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
485     table_close_button.addEventListener("click",  filterToggle);
486     table_close_collumn.appendChild(table_close_button);
487     table_last_contents.appendChild(table_close_collumn);
489     filter_table.appendChild(table_last_contents);
491     document.body.appendChild(window_div);
495 function filterToggle(){
496     if(window_displayed){
497         document.getElementById("FilterWindow").style.display = "none";
498         document.getElementById("FilterBackground").style.display = "none";
499         window_displayed = false;
500     }
501     else{
502         document.getElementById("FilterWindow").style.display = "inline-block";
503         document.getElementById("FilterBackground").style.display = "inline-block";
504         window_displayed = true;
505     }
508 function filterButton(){
509     var filter_button = document.createElement("input");
510     filter_button.setAttribute("Value", "Word Filter Settings");
511     filter_button.setAttribute("type", "button");
512     filter_button.setAttribute("style", "position:absolute;top:75px");
513     filter_button.addEventListener("click", filterWindow);
514     document.body.appendChild(filter_button);
515     filter_button.addEventListener("click", filterToggle);
518 function addRow(){
519     var filter_table = document.getElementById("filter_table");
520     filter_table.deleteRow(parseInt(number_of_filters) + 1);
521     number_of_filters++;
522     
523     var table_row_contents = document.createElement("tr");
524     table_row_contents.setAttribute("id", "FilterRow" +  (number_of_filters - 1));
526     var table_data_active =  document.createElement("td");
527     var table_checkbox_active = document.createElement("input");
528     table_checkbox_active.setAttribute("type", "checkbox");
529     table_checkbox_active.setAttribute("id", "Active" + (number_of_filters - 1));
530     table_data_active.appendChild(table_checkbox_active);
531     table_row_contents.appendChild(table_data_active);
533     var table_data_pattern =  document.createElement("td");
534     var table_input_pattern = document.createElement("input");
535     table_input_pattern.setAttribute("class", "inputs");
536     table_input_pattern.setAttribute("id", "Pattern" + (number_of_filters - 1));
537     table_data_pattern.appendChild(table_input_pattern);
538     table_row_contents.appendChild(table_data_pattern);
540     var table_data_replacement =  document.createElement("td");
541     var table_input_replacement =  document.createElement("input");
542     table_input_replacement.setAttribute("class", "inputs");
543     table_input_replacement.setAttribute("id", "Replacement" + (number_of_filters - 1));
544     table_data_replacement.appendChild(table_input_replacement);
545     table_row_contents.appendChild(table_data_replacement);
547     filter_table.appendChild(table_row_contents);
549     var table_last_contents = document.createElement("tr");
551     var table_add_collumn =  document.createElement("td");
552     var table_add_row_button = document.createElement("input");
553     var table_subtract_row_button = document.createElement("input");
554     table_subtract_row_button.setAttribute("type", "button");
555     table_subtract_row_button.setAttribute("value", "-");
556     table_subtract_row_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
557     table_add_collumn.appendChild(table_subtract_row_button);
558     table_subtract_row_button.addEventListener("click", removeRow);
559     table_add_row_button.setAttribute("type", "button");
560     table_add_row_button.setAttribute("value", "+");
561     table_add_row_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
562     table_add_collumn.appendChild(table_add_row_button);
563     table_add_row_button.addEventListener("click", addRow);
564     
565     table_last_contents.appendChild(table_add_collumn);
567     var table_set_collumn =  document.createElement("td");
568     var table_confirm_button = document.createElement("input");
569     table_confirm_button.setAttribute("type", "button");
570     table_confirm_button.setAttribute("id", "table_confirm_button");
571     table_confirm_button.setAttribute("value", "Set Replacements");
572     table_confirm_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
573     table_confirm_button.addEventListener("click", saveSettings);
574     table_confirm_button.addEventListener("click", modifyDOM);
575     table_confirm_button.addEventListener("click", filterToggle);
576     table_set_collumn.appendChild(table_confirm_button);
577     table_last_contents.appendChild(table_set_collumn);
579     var table_close_collumn = document.createElement("td");
580     var table_close_button = document.createElement("input");
581     table_close_button.setAttribute("type", "button");
582     table_close_button.setAttribute("value", "Close Menu");
583     table_close_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
584     table_close_button.addEventListener("click", filterToggle);
585     table_close_collumn.appendChild(table_close_button);
586     table_last_contents.appendChild(table_close_collumn);
588     filter_table.appendChild(table_last_contents);  
591 function removeRow(){
592     var filter_table = document.getElementById("filter_table");
593     if(number_of_filters != 0){
594         filter_table.deleteRow(number_of_filters);
595         number_of_filters--;
596     }
599 function setTable(){
600     var filter_count = 0;
601     initial_filters.forEach(function(filter){
602         if(filter[2] === null || filter[1] === null || filter[0] === null || filter_count == number_of_filters) return;
603         if(filter[0] == "true"){
604             document.getElementById("Active"+filter_count).checked = true;
605         }
606         else if(filter[0] == "false"){
607             document.getElementById("Active"+filter_count).checked = false;
608         }
609         document.getElementById("Pattern"+filter_count).value = filter[1];
610         document.getElementById("Replacement"+filter_count).value = filter[2];
611         filter_count++;
612     });
616 //222222222222222222222222222222222222222222222222222222222222////2222222222222222222222222222222222222222222222222222222222221111111111111111111111111111//
617 //222222222222222222222222222222222222222222222222222222222222////2222222222222222222222222222222222222222222222222222222222221111111111111111111111111111//
618 //222222222222222222222222222222222222222222222222222222222222////2222222222222222222222222222222222222222222222222222222222221111111111111111111111111111//
619 //222222222222222222222222222222222222222222222222222222222222////2222222222222222222222222222222222222222222222222222222222221111111111111111111111111111//
620 //222222222222222222222222222222222222222222222222222222222222////2222222222222222222222222222222222222222222222222222222222221111111111111111111111111111//
621 //222222222222222222222222222222222222222222222222222222222222////2222222222222222222222222222222222222222222222222222222222221111111111111111111111111111//
622 //222222222222222222222222222222222222222222222222222222222222////2222222222222222222222222222222222222222222222222222222222221111111111111111111111111111//
623 //222222222222222222222222222222222222222222222222222222222222////2222222222222222222222222222222222222222222222222222222222221111111111111111111111111111//
624 //222222222222222222222222222222222222222222222222222222222222////2222222222222222222222222222222222222222222222222222222222221111111111111111111111111111//
625 //222222222222222222222222222222222222222222222222222222222222////2222222222222222222222222222222222222222222222222222222222221111111111111111111111111111//
627 //Functions to set the DOM listener and observers
629 //detect page changes
630 function observeDynamicMutation(node){
631     if(node === undefined)
632         node = document;
633         //on mutation event call functions
634     observer = new MutationObserver(function callBack(mutations){
635                 modifyDOM();
636     });
637     var config = {subtree: true, childList:true};//Subtree checks children of node, while subtree repeats actions on the child and sets observers on them
638     observer.observe(node, config);
641 function modifyDOM(){
642         var start = document.getElementById("delform");
643     var itterator = document.createTreeWalker(start, NodeFilter.SHOW_ELEMENTS, NodeFilter.SHOW_ELEMENTS);
644     var node = "";
646     while((node = itterator.nextNode())){
647         var cname = node.className;
648         var tag = node.tagName;
649         if(tag  === "IMG" || tag  === "img"){
650             if(!/(f|p)\d+IMG/.test(node.id) && (node.getAttribute("data-md5") !== null || node.className.indexOf("thumb") != -1)){
651                 node.id = node.parentNode.parentNode.id + "IMG";
652                 node.addEventListener("click", hideImage, {passive:false, capture:false, once:false});
653             }
654         }
655         else if(cname == "postMessage"){
656             while((localNode = itterator.nextNode())){
657                 var className = localNode.className;
658                 if(className == undefined || className == "quotelink"){
659                     for(var i = 0 ; i < number_of_filters; i++){
660                         if(kill[i] == true) continue;
661                         filter = document.getElementById("Pattern"+i);
662                         replacement = document.getElementById("Replacement"+i);
663                         active = document.getElementById("Active"+i);
664                         if(active.checked){
665                             var lastChar = filter.value.length - 1;
666                             var filterText = filter.value;
667                             if(filterText === "") break;
668                             var setting = filterText.substr(lastChar);
669                             filterText = filterText.substr(1, lastChar-2);
670                             filterText = "(^|[\\s!$%^&*()_+|~\\-=`{}\\[\\]:\";'<>?,\\.\\/])" + filterText + "([\\s!$%^&*()_+|~\\-=`{}\\[\\]:\";'<>?,\\.\\/]|$)";
671                             try{
672                                 var regex = new RegExp(filterText, setting);
673                                 localNode.textContent = localNode.textContent.replace(regex, " " + replacement.value + " ");
674                             }
675                             catch(e){
676                                 alert(i + "'s regex was invalid");
677                                 kill[i] = true;
678                             }
679                         }
680                     }
681                 }
682                 else break;
683             }
684         }
685     }
689 if (window.top != window.self)  //-- Don't run on frames or iframes
690     return;
692 //initial onload setup
693 function hideSetup(){
694         retrieveStates();
695     hideButton();
698 function filterSetup(){
699     loadSettings();
700     filterButton();
701     filterWindow();
702     setTable();
705 function pkxSetup(){
706     hideSetup();
707     filterSetup();
708         modifyDOM();
709     observeDynamicMutation();
712 //4chanX exists
713 //currently has issues due to a bug in 4chanX's API
714 var page_setup = false;
715 document.addEventListener('4chanXInitFinished', function(e) {
716         setTimeout(function(){// bypass 4chanX bug
717                 browser = detectBrowser();
718                 pkxSetup();
719                 console.log("Script loaded: 4chanPKX");
720                 page_setup = true;
721         }, 1000);
722 }, false);
724 setTimeout(function(){
725         if(!page_setup){
726                 browser = detectBrowser();
727                 pkxSetup();
728                 console.log("Script loaded: 4chanPKX");
729                 page_setup = true;
730         }
731 }, 3000);