1 var __extends
= (this && this.__extends
) || (function () {
2 var extendStatics
= Object
.setPrototypeOf
||
3 ({ __proto__
: [] } instanceof Array
&& function (d
, b
) { d
.__proto__
= b
; }) ||
4 function (d
, b
) { for (var p
in b
) if (b
.hasOwnProperty(p
)) d
[p
] = b
[p
]; };
5 return function (d
, b
) {
7 function __() { this.constructor = d
; }
8 d
.prototype = b
=== null ? Object
.create(b
) : (__
.prototype = b
.prototype, new __());
12 // @name 4Free-FSE [4chan X Enhancement]
13 // @author ECHibiki - /qa/
14 // @description 4Free - Free Stuff Enhancments. 7 additional features on top of 4chanX
16 // @namespace http://verniy.xyz/
17 // @match *://boards.4chan.org/*
18 // @updateURL https://raw.githubusercontent.com/ECHibiki/4Free-FSE/master/builds/4-Free.user.js
19 // @downloadURL https://raw.githubusercontent.com/ECHibiki/4Free-FSE/master/builds/4-Free.user.js
20 // @grant GM_xmlhttpRequest
21 // @run-at document-start
22 // @icon data:image/jpeg;base64,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
26 https://github.com/ccd0/4chan-x/wiki/4chan-X-API
27 https://github.com/ECHibiki/4chan-UserScripts/blob/master/MD5%20Filters%20by%20QAJPYOtGo.txt
31 4chanX-Free Stuff Enhancements is a userscript that operates with 4chanX to give it additional features. These enhancements were written by me from early 2017 up to 2018 as a way to teach myself how to work with JavaScript while giving something back to the community I took part in.
32 Some of these features are simple, like the password viewer, others are more complex using multiple concurent AJAX calls such as the thread rebuilder or the image adder. <br/>
33 Below is a description of the features this package has to offer.
35 ### Danbooru Image Adder
36 #### Adds images to your posts
37 Adds an image to your post taken from the danbooru's image collection.<br/>
38 Supply it with tags via an autocomplete, set the rating(s/q/e) and it will give an image for you to post with.
42 Converts the colors of special symbols from plain black into other prettier colors(yen == purple, kita == dark grey).<br/>
43 #### Hotkeys for Convinience
44 <strong>Press ctrl+\ for ¥</strong>
45 Highlights the whole line in purple much like how greentext works<br/>
46 <strong>Press ctrl+k for キタ━━━(゚∀゚)━━━!!</strong>
47 Highlights just the word in dark gray<br/>
49 ### 4chan-Ignoring-Enhancements
51 Gives the ability to hide images with ___ctrl+shift+click___. Stores in browser memory for new sessions.<br/>
52 Also includes over 20,000 MD5 filters of things like frogs, goldface, guro done by from QAJPYOtGo<br/>
53 https://github.com/ECHibiki/4chan-UserScripts/blob/master/MD5%20Filters%20by%20QAJPYOtGo.txt
55 Also includes the ability to do word replacements with a regex replacement system.<br>
58 #### Rebuild dead threads from scratch
59 Rebuild a thread from 4chan's archive.<br/>
60 Simple system that could use some additions(using 4chan's offsite archives for example)
63 #### Shows your 4chan post/delete password
64 * Displays your 4chan password in an inputbox.
65 * Top left is the post password, Bottom right is the delete password.
66 * Edit the input boxes to change them.
68 __Note:__ some 4chan boards don't allow custom post passwords. May require cookie manipulation, but this has not yet been tested...
71 var Constants
= /** @class */ (function () {
72 function Constants() {
74 Constants
.DEFAULT_HIDE_EXPIRATION_TIME
= 172800000;
75 Constants
.MILLISECONDS_TO_THE_HOUR
= 3600000;
76 Constants
.HELP_ICON_SOURCE
= "data:image/jpeg;base64,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";
77 Constants
.BLANK_PNG
= "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAACXBIWXMAALiMAAC4jAHM9rsvAAAAG3RFWHRTb2Z0d2FyZQBDZWxzeXMgU3R1ZGlvIFRvb2zBp+F8AAAAo0lEQVR42u3RAQ0AAAjDMO5f9LFBSCdhTdvRnQIEiIAAERAgAgJEQIC4AERAgAgIEAEBIiBABERAgAgIEAEBIiBABERAgAgIEAEBIiBABERAgAgIEAEBIiBABERAgAgIEAEBIiBABERAgAgIEAEBIiBABERAgAgIEAEBIiBABERAgAgIEAEBIiBABERAgAgIEAEBIiBABAQIECACAkRAgAjI9xbzUCtI4axs4wAAAABJRU5ErkJggg==";
80 //unassociated functions
81 var Generics
= /** @class */ (function () {
84 Generics
.storageAvailable = function (storage_type
) {
86 var storage
= window
[storage_type
];
87 storage
.setItem('x', 'x');
88 storage
.removeItem('x');
96 Generics
.detectBrowser = function () {
97 if ((navigator
.userAgent
.indexOf('Opera') || navigator
.userAgent
.indexOf('OPR')) != -1) {
101 else if (navigator
.userAgent
.indexOf('Chrome') != -1) {
102 console
.log('Chrome');
105 else if (navigator
.userAgent
.indexOf('Safari') != -1) {
106 console
.log('Safari');
109 else if (navigator
.userAgent
.indexOf('Firefox') != -1) {
110 console
.log('FireFox');
113 else if (navigator
.userAgent
.indexOf('MSIE') != -1) {
118 console
.log('Other');
122 //gets json keys by regex test
123 Generics
.getJSONPropertiesByKeyName = function (JSON_obj
, regex_string
) {
124 var regex
= new RegExp("^" + regex_string
+ "$");
125 var rtnArray
= Array();
126 for (var key
in JSON_obj
)
131 //send alert to 4chanx
132 Generics
.alert4ChanX = function (message
, type
, time
) {
133 var detail
= { type
: type
, content
: message
, lifetime
: time
};
134 var event
= new CustomEvent('CreateNotification', { bubbles
: true, detail
: detail
});
135 document
.dispatchEvent(event
);
137 Generics
.getJSON = function (url
, callback
, extra
) {
139 for (var _i
= 3; _i
< arguments
.length
; _i
++) {
140 all_extra
[_i
- 3] = arguments
[_i
];
142 var xhr
= new XMLHttpRequest();
143 xhr
.open('GET', url
, true);
144 xhr
.responseType
= 'json';
145 xhr
.onload = function () {
146 var status
= xhr
.status
;
148 callback
.apply(void 0, [null, xhr
.response
, extra
].concat(all_extra
));
158 var FeatureInterface
= /** @class */ (function () {
159 function FeatureInterface() {
161 return FeatureInterface
;
163 var TopBar
= /** @class */ (function () {
165 this.shortcuts_container
= document
.getElementById("shortcuts");
166 this.shortcuts_menu
= document
.getElementById("shortcut-menu");
167 this.fse_icon_container
= document
.createElement("SPAN");
168 this.fse_icon_node
= document
.createElement("A");
169 this.fse_style_node
= document
.createElement("STYLE");
170 this.fa_fse_style
= ".fa_jpy::before{content:'\f157'}";
171 this.fse_style_node
.innerHTML
= this.fa_fse_style
;
172 this.fse_icon_container
.setAttribute("class", "shortcut brackets-wrap");
173 this.fse_icon_node
.setAttribute("class", "fa fa-jpy");
174 this.fse_icon_node
.setAttribute("href", "javascript:void(0);");
175 this.fse_icon_node
.setAttribute("title", "4F-FSE Settings");
176 this.fse_icon_node
.textContent
= "4F-FSE Settings";
177 this.settings_window
= new SettingsWindow();
179 TopBar
.prototype.build = function () {
181 document
.head
.appendChild(this.fse_style_node
);
182 this.fse_icon_container
.appendChild(this.fse_icon_node
);
183 this.shortcuts_container
.insertBefore(this.fse_icon_container
, this.shortcuts_menu
);
184 //https://stackoverflow.com/questions/44606399/typescript-how-to-access-the-class-instance-from-event-handler-method
185 this.fse_icon_node
.addEventListener("click", function (evt
) { return _this
.open4FSettings(_this
.settings_window
); });
187 TopBar
.prototype.open4FSettings = function (settings_window
) {
188 settings_window
.displayWindow();
190 TopBar
.prototype.getSettingsArr = function () {
191 return this.settings_window
.getSettingsArr();
195 var ImageHider
= /** @class */ (function (_super
) {
196 __extends(ImageHider
, _super
);
197 function ImageHider() {
198 var _this
= _super
.call(this) || this;
199 _this
.listener_obj
= {};
200 _this
.retrieveStates();
205 //retrieve from memory the hidden images
206 //Images are stored in memory as f<ID_NUMBER>IMG and recalled using the storage_key
207 //Function makes a check to see if the hiding time limit for the thread has expired or not.
208 //Note: Must have the DOM itterate through before retrieval
209 ImageHider
.prototype.retrieveStates = function () {
211 var storage_position
= 0;
212 var JSON_storage
= {}; /*;any bypasses dot notation issues on objects*/
214 var local_store_size
= window
.localStorage
.length
;
215 while (storage_position
< local_store_size
) {
216 storage_key
= window
.localStorage
.key(storage_position
);
217 JSON_storage
[storage_key
] = window
.localStorage
.getItem(storage_key
);
220 this.threads_to_hide
= Generics
.getJSONPropertiesByKeyName(JSON_storage
, '[0-9]+IMG');
221 //aquire each time to check for changes
222 this.hide_expiration_time
= parseInt(JSON_storage
.Expiration_Time
);
223 if (this.hide_expiration_time
=== null)
224 this.hide_expiration_time
= Constants
.DEFAULT_HIDE_EXPIRATION_TIME
;
225 var md5_filters
= JSON_storage
.MD5_List_FSE
;
226 if (md5_filters
!== undefined && md5_filters
!== null) {
227 this.md5_filters_arr
= md5_filters
.split('\n');
228 //remove trailing and starting slash
229 this.md5_filters_arr
.forEach(function (md5
, index
) {
231 _this
.md5_filters_arr
[index
] = md5
.substring(1, md5
.length
- 1);
235 ImageHider
.prototype.storeStates = function () {
237 for (var _i
= 0; _i
< arguments
.length
; _i
++) {
238 item_pairs
[_i
] = arguments
[_i
];
240 window
.localStorage
.setItem(item_pairs
[0], item_pairs
[1]);
242 ImageHider
.prototype.init = function () {
243 this.hotkeyListeners();
245 //hide image onclick listener.
246 //Method 404's a given image. This 404'ing allows image dissabling to be toggled on and off.
247 //Post number associated with the image is stored in local storage.
248 ImageHider
.prototype.hideOnClick = function (event
) {
249 var is_hidden
= event
.target
.src
.substring(21, 29) == ",iVBORw0";
251 if (((this.listener_obj
[17] || this.listener_obj
[91]) && this.listener_obj
[16]) && !is_hidden
) {
252 event
.preventDefault();
253 event
.stopPropagation();
254 hide_group_id
= event
.target
.getAttribute('hide-grouping');
255 this.storeStates(hide_group_id
, "" + Date
.now());
256 [].slice
.call(document
.querySelectorAll('img[hide-grouping="' + hide_group_id
+ '"]')).forEach(function (image_node
) {
257 image_node
.setAttribute('hidden-src', image_node
.src
);
258 image_node
.src
= Constants
.BLANK_PNG
;
261 else if ((this.listener_obj
[17] || this.listener_obj
[91]) && this.listener_obj
[16]) {
262 event
.preventDefault();
263 event
.stopPropagation();
264 hide_group_id
= event
.target
.getAttribute('hide-grouping');
265 window
.localStorage
.removeItem(hide_group_id
);
266 event
.target
.src
= event
.target
.getAttribute('hidden-src');
267 [].slice
.call(document
.querySelectorAll('img[hide-grouping="' + hide_group_id
+ '"]')).forEach(function (image_node
) {
268 image_node
.src
= image_node
.getAttribute('hidden-src');
271 this.retrieveStates();
274 //hotkeys for ctrl[17] and shift[16]
275 ImageHider
.prototype.hotkeyListeners = function () {
277 window
.addEventListener("keydown", function (e
) {
278 _this
.listener_obj
[e
.keyCode
] = true;
279 }, { passive
: false, capture
: false, once
: false });
280 window
.addEventListener("keyup", function (e
) {
281 _this
.listener_obj
[e
.keyCode
] = false;
282 }, { passive
: false, capture
: false, once
: false });
284 ImageHider
.prototype.decideAction = function (node
) {
285 //tagname is always upper in HTML, in xml it's displayed as written.
286 if (node
.tagName
=== 'IMG' || node
.tagName
=== 'VIDEO') {
287 if (node
.id
=== "ihover") {
288 this.hideHoverImageNode(node
);
291 if (node
.getAttribute('data-md5') !== null) {
292 this.hideImageNode(node
);
297 ImageHider
.prototype.activate = function () {
298 console
.log("4F-FSE: ImageHider Active");
300 ImageHider
.prototype.hideImageNode = function (image_node
) {
302 var sister_node
= image_node
.parentNode
.parentNode
.parentNode
.getElementsByClassName('catalog-thumb')[0]; // the catalog sister to index
303 var sister_node_non_exist
= false;
304 if (sister_node
=== undefined) {
305 sister_node_non_exist
= true;
307 var image_node_already_run
= false;
308 if (/\d+IMG/.test(image_node
.getAttribute('hide-grouping'))) {
309 image_node_already_run
= true;
310 if (!sister_node_non_exist
) {
311 if (/\d+IMG/.test(sister_node
.getAttribute('hide-grouping'))) {
316 if (!image_node_already_run
)
317 image_node
.setAttribute('hide-grouping', image_node
.parentNode
.parentNode
.id
.substring(1) + 'IMG');
318 if (!sister_node_non_exist
)
319 sister_node
.setAttribute('hide-grouping', image_node
.parentNode
.parentNode
.id
.substring(1) + 'IMG');
320 if (!image_node_already_run
)
321 image_node
.addEventListener('click', function (evt
) { return _this
.hideOnClick(evt
); });
322 if (!sister_node_non_exist
)
323 sister_node
.addEventListener('click', function (evt
) { return _this
.hideOnClick(evt
); });
324 var threadstore_len
= this.threads_to_hide
.length
;
325 var node_group_id
= image_node
.getAttribute('hide-grouping');
326 for (var thread
= 0; thread
< threadstore_len
; thread
++) {
327 if (node_group_id
== this.threads_to_hide
[thread
]) {
328 if (!image_node_already_run
) {
329 image_node
.setAttribute('hidden-src', image_node
.src
);
330 image_node
.src
= Constants
.BLANK_PNG
;
332 if (!sister_node_non_exist
) {
333 sister_node
.setAttribute('hidden-src', sister_node
.src
);
334 sister_node
.src
= Constants
.BLANK_PNG
;
339 //index node holds the MD5
340 var node_md5
= image_node
.getAttribute('data-md5');
341 if (this.md5_filters_arr
!== undefined) {
342 var md5_filters_arr_len
= this.md5_filters_arr
.length
;
343 for (var md5
= 0; md5
< md5_filters_arr_len
; md5
++) {
344 if (node_md5
== this.md5_filters_arr
[md5
]) {
345 this.threads_to_hide
.push();
346 if (!image_node_already_run
) {
347 image_node
.setAttribute('hidden-src', image_node
.src
);
348 image_node
.src
= Constants
.BLANK_PNG
;
350 if (!sister_node_non_exist
) {
351 sister_node
.setAttribute('hidden-src', sister_node
.src
);
352 sister_node
.src
= Constants
.BLANK_PNG
;
359 ImageHider
.prototype.hideHoverImageNode = function (image_node
) {
360 var unprocessed_id
= image_node
.getAttribute('data-full-i-d');
361 var proccessed_id
= unprocessed_id
.substring(unprocessed_id
.indexOf('.') + 1);
362 var image_node_id
= proccessed_id
+ 'IMG';
363 if (image_node
=== undefined)
365 for (var thread
= 0, threadstore_len
= this.threads_to_hide
.length
; thread
< threadstore_len
; thread
++) {
366 if (image_node_id
== this.threads_to_hide
[thread
]) {
367 image_node
.removeAttribute('src');
371 //thread node holds the MD5
373 // if(is_embeded_post) node_md5 = image_node.getAttribute('data-md5');
374 /*else */ node_md5
= document
.getElementById('f' + proccessed_id
).getElementsByTagName('IMG')[0].getAttribute('data-md5');
375 if (this.md5_filters_arr
!== undefined) {
376 for (var md5
= 0, md5_filters_arr_len
= this.md5_filters_arr
.length
; md5
< md5_filters_arr_len
; md5
++) {
377 if (node_md5
== this.md5_filters_arr
[md5
]) {
378 image_node
.removeAttribute('src');
385 }(FeatureInterface
));
386 var TextReplacer
= /** @class */ (function (_super
) {
387 __extends(TextReplacer
, _super
);
388 function TextReplacer() {
389 var _this
= _super
.call(this) || this;
390 _this
.text_filters
= []; //object
391 _this
.filtered_threads
= [];
392 _this
.retrieveStates();
397 TextReplacer
.prototype.init = function () {
398 this.filtered_threads
= [];
401 TextReplacer
.prototype.activate = function () { console
.log("4F-FSE: TextReplacer Active"); };
402 TextReplacer
.prototype.decideAction = function (node
) {
403 if (node
.tagName
== "BLOCKQUOTE") {
404 if (node
.className
== "postMessage") {
405 var blockquote_id
= node
.id
;
406 var already_filtered
= false;
407 this.filtered_threads
.forEach(function (thread_id
) {
408 if (thread_id
== blockquote_id
) {
409 already_filtered
= true;
416 if (!already_filtered
&& this.text_filters
.length
!== 0) {
417 var itterator
= document
.createNodeIterator(node
, NodeFilter
.SHOW_TEXT
);
419 while ((localNode
= itterator
.nextNode())) {
420 for (var filter
= 0; filter
< this.number_of_filters
; filter
++) {
421 if (this.text_filters
[filter
].Active
=== "true") {
422 var last_slash_index
= this.text_filters
[filter
].Regex
.lastIndexOf("/");
423 var filter_text
= this.text_filters
[filter
].Regex
.substring(1, last_slash_index
);
424 var flag
= this.text_filters
[filter
].Regex
.substring(last_slash_index
+ 1);
425 var regex
= new RegExp(filter_text
, flag
);
426 var node_text
= localNode
.textContent
;
427 if (regex
.test(node_text
)) {
428 localNode
.textContent
= node_text
.replace(regex
, this.text_filters
[filter
].Replacement
);
429 this.filtered_threads
.push(blockquote_id
);
437 TextReplacer
.prototype.retrieveStates = function () {
439 var storage_index
= 0;
440 var JSON_storage
= {};
442 while (storage_index
< window
.localStorage
.length
) {
443 storage_key
= window
.localStorage
.key(storage_index
);
444 JSON_storage
[storage_key
] = window
.localStorage
.getItem(storage_key
);
447 this.number_of_filters
= JSON_storage
["filter_quantity"];
448 var filters
= Generics
.getJSONPropertiesByKeyName(JSON_storage
, "[0-9]+FLT");
450 filters
.forEach(function (filter
) {
451 _this
.text_filters
.push(TextReplacer
.formatFilterSettings(JSON_storage
[filter
]));
454 //Splits the saved settings into components
455 TextReplacer
.formatFilterSettings = function (input
) {
456 var processed_input
= (input
.split('=')).map(function (x
) { return decodeURIComponent(x
); });
457 return { Active
: processed_input
[0], Regex
: processed_input
[1], Replacement
: processed_input
[2] };
459 TextReplacer
.prototype.storeStates = function () { };
461 }(FeatureInterface
));
462 var DanbooruImageAdder
= /** @class */ (function (_super
) {
463 __extends(DanbooruImageAdder
, _super
);
464 function DanbooruImageAdder() {
465 var _this
= _super
.call(this) || this;
466 _this
.timeout_functions
= [];
468 _this
.post_number
= 0;
469 _this
.page_number
= 0;
470 _this
.json_page_numbers_used
= [];
471 _this
.previous_images
= [];
472 _this
.json_numbers_used
= [];
473 _this
.previous_page
= 9001;
474 _this
.subdomain_regex
= new RegExp("http(|s)://");
475 _this
.maximum_attempts
= 20;
481 DanbooruImageAdder
.prototype.init = function () {
483 this.time
= this.time_max
;
484 this.number_of_attempts
= this.maximum_attempts
;
485 document
.addEventListener("QRDialogCreation", function (evt
) {
486 _this
.enhance4ChanX_HTML();
487 _this
.enhanced4ChanXListeners();
490 DanbooruImageAdder
.prototype.enhance4ChanX_HTML = function () {
491 var qr_window
= document
.getElementById("qr");
492 /*Should I auto open things for the user?*/
493 // var imagedump_opener:any = document.getElementById("dump-button");
494 // if(imagedump_opener !== null){imagedump_opener.click();}
496 //image setting html elements.
497 var qr_image_adder_table
= document
.createElement("TABLE");
498 qr_image_adder_table
.setAttribute("id", "qrImages");
499 qr_image_adder_table
.setAttribute("style", "text-align:center");
500 qr_window
.appendChild(qr_image_adder_table
);
501 var options_row
= document
.createElement("TR");
502 options_row
.setAttribute("ID", "or");
503 options_row
.setAttribute("style", "margin:5px;");
504 qr_image_adder_table
.appendChild(options_row
);
505 var checkbox_safe
= document
.createElement("INPUT");
506 checkbox_safe
.setAttribute("id", "safe");
507 checkbox_safe
.setAttribute("type", "checkbox");
508 checkbox_safe
.checked
= true;
509 var checkbox_safe_text
= document
.createTextNode("Safe");
510 var checkbox_questionable
= document
.createElement("INPUT");
511 checkbox_questionable
.setAttribute("id", "questionable");
512 checkbox_questionable
.setAttribute("type", "checkbox");
513 var checkbox_questionable_text
= document
.createTextNode("Questionable");
514 var checkbox_explicit
= document
.createElement("INPUT");
515 checkbox_explicit
.setAttribute("id", "explicit");
516 checkbox_explicit
.setAttribute("type", "checkbox");
517 var checkbox_explicit_text
= document
.createTextNode("Explicit");
518 options_row
.appendChild(checkbox_safe_text
);
519 options_row
.appendChild(checkbox_safe
);
520 options_row
.appendChild(checkbox_questionable_text
);
521 options_row
.appendChild(checkbox_questionable
);
522 options_row
.appendChild(checkbox_explicit_text
);
523 options_row
.appendChild(checkbox_explicit
);
524 var image_tagging_row
= document
.createElement("TR");
525 this.help_icon_container
= document
.createElement("A");
526 this.help_icon_container
.href
= "javascript:void(0)";
527 this.help_icon_container
.title
= "Click to View Help!";
528 var help_icon
= document
.createElement("IMG");
529 help_icon
.setAttribute("class", "help_icon");
530 help_icon
.src
= Constants
.HELP_ICON_SOURCE
;
531 this.help_icon_container
.appendChild(help_icon
);
532 image_tagging_row
.appendChild(this.help_icon_container
);
533 var tooltip_div
= document
.createElement("DIV");
534 tooltip_div
.innerHTML
= "Insert Tags to search from danbooru in the text box to the side.<br/>The URL for the image will be bellow. Some browsers such as chrome allow you to select this text<br/>Do Not Use \"order:\" tags<br/>Do Not Use \"rating:\" tags<br/>For more speed uncheck all boxes!<hr/>Submit bugs to <a href='https://github.com/ECHibiki/4chan-UserScripts'>my Github</a>";
535 (tooltip_div
).setAttribute("class", "tooltip-4F");
536 (tooltip_div
).setAttribute("id", "tooltipIA");
537 qr_window
.appendChild(tooltip_div
);
538 var second_row_nodes
= [
539 document
.createTextNode("Tags: "),
540 document
.createElement("INPUT"),
541 document
.createElement("INPUT"),
542 document
.createElement("A"),
543 document
.createElement("INPUT"),
545 second_row_nodes
.forEach(function (node
) {
546 image_tagging_row
.appendChild(node
);
548 qr_image_adder_table
.appendChild(image_tagging_row
);
549 var auto_complete_row
= document
.createElement("TR");
550 auto_complete_row
.setAttribute("ID", "auto-complete-row");
551 auto_complete_row
.setAttribute("style", "margin:5px;");
552 qr_image_adder_table
.appendChild(auto_complete_row
);
553 second_row_nodes
[1].setAttribute("ID", "tag_input");
554 var option_text_size
= 18;
555 second_row_nodes
[1].setAttribute("style", "width:44.9%;" + "font-size:" + option_text_size
+ "px");
556 second_row_nodes
[3].setAttribute("ID", "timer");
557 second_row_nodes
[3].setAttribute("style", "width:20%;margin:0 5px");
558 second_row_nodes
[4].setAttribute("ID", "urlContainer");
559 second_row_nodes
[4].setAttribute("style", "width:75%;margin:5px -25px");
560 second_row_nodes
[4].setAttribute("disabled", "");
561 second_row_nodes
[2].setAttribute("ID", "imageButton");
562 second_row_nodes
[2].setAttribute("type", "button");
563 second_row_nodes
[2].setAttribute("value", "Set Image");
564 //textarea expansion;
565 qr_window
.getElementsByTagName("TEXTAREA")[0].style
.width
= "110%";
566 qr_window
.appendChild(document
.createElement("hr"));
568 DanbooruImageAdder
.prototype.enhanced4ChanXListeners = function () {
570 this.highQualityImages();
571 document
.getElementById("qr-filerm").addEventListener("click", function (evt
) { return _this
.clearImage(); });
572 var qr_reference
= document
.getElementById("qr");
573 var tooltip_div
= document
.getElementById("tooltipIA");
574 this.help_icon_container
.addEventListener("click", function (evt
) {
575 if (_this
.tool_tip_visible
)
576 tooltip_div
.setAttribute("style", "z-index:9;padding:5px;border:1px solid black;background-color:white;word-wrap:break-word;display:none;position:absolute;");
578 tooltip_div
.setAttribute("style", "z-index:9;padding:5px;border:1px solid black;background-color:white;word-wrap:break-word;display:block;position:absolute;"
579 + "left:" + (evt
.clientX
- qr_reference
.getBoundingClientRect().x
) +
580 "px;top:" + (evt
.clientY
- qr_reference
.getBoundingClientRect().y
) + "px;");
581 _this
.tool_tip_visible
= !_this
.tool_tip_visible
;
583 var tag_input
= document
.getElementById("tag_input");
584 tag_input
.addEventListener("input", function (evt
) {
585 _this
.setTagInterface(tag_input
, document
.getElementById("auto-complete-row"));
587 document
.getElementById("imageButton").addEventListener("click", function (evt
) { return _this
.activate(); });
589 DanbooruImageAdder
.prototype.highQualityImages = function () {
591 var imagedump_file_list
= document
.getElementById("dump-list");
592 //used for setting and unsetting high resolution thumbs for dump list.
593 var dumplist_image
= "";
594 var previous_dumplist_image
= "";
595 var observer
= new MutationObserver(function (mutate
) {
596 dumplist_image
= imagedump_file_list
.firstChild
.style
.backgroundImage
;
597 if (dumplist_image
!== previous_dumplist_image
&& _this
.img_URL
!== "") {
598 imagedump_file_list
.firstChild
.style
.backgroundImage
= "url(" + _this
.img_URL
+ ")";
599 previous_dumplist_image
= imagedump_file_list
.firstChild
.style
.backgroundImage
;
601 else if (_this
.img_URL
== "") { }
603 observer
.observe(imagedump_file_list
, { attributes
: true, subtree
: true, childList
: true, characterData
: true });
605 DanbooruImageAdder
.prototype.activate = function () {
607 //on setimage click clear flags, timers and start another search
608 this.json_page_numbers_used
= Array();
609 this.previous_page
= 9001;
610 //reset a failed_to_find_required_tags boolean
611 this.primed_for_fail
= false;
612 for (var i
= 0; i
< this.timeout_functions
.length
; i
++) {
613 clearInterval(this.timeout_functions
[i
]);
615 this.tag_incorrect_state
= false;
616 this.timeout
= false;
617 //freeze interface to prevent mid opperation changes
618 document
.getElementById("tag_input").setAttribute("disabled", "1");
619 document
.getElementById("imageButton").setAttribute("disabled", "1");
620 this.time
= this.time_max
;
621 this.timeout_functions
.push(setInterval(function () { return _this
.counterFunction(); }, 1000));
625 //remove the high quallity image from the dump list
626 DanbooruImageAdder
.prototype.clearImage = function () {
627 var imagedump_file_list
= document
.getElementById("dump-list");
628 imagedump_file_list
.firstChild
.style
.backgroundImage
= "url()"; //trigger mutation event
629 this.img_URL
= ""; //get mutation to set to dead
631 DanbooruImageAdder
.prototype.setTagInterface = function (tag_input_node
, auto_complete_row
) {
632 var tags
= tag_input_node
.value
;
633 if (this.old_tags_before_change
!== tags
) {
634 this.previous_images
= [];
635 var tag_carat_position
= tag_input_node
.selectionStart
- 1;
636 var closest_tag
= (function () {
637 var current_chararcter
= tags
.charAt(tag_carat_position
);
639 var right_most
= tag_carat_position
;
640 while (current_chararcter
!= " " && current_chararcter
!= "" && current_chararcter
!== undefined) {
642 current_chararcter
= tags
.charAt(tag_carat_position
+ i
);
643 if (current_chararcter
!= " " && current_chararcter
!= "")
644 right_most
= tag_carat_position
+ i
;
647 current_chararcter
= tags
.charAt(tag_carat_position
);
649 var leftMost
= tag_carat_position
;
650 while (current_chararcter
!= " " && current_chararcter
!= "" && current_chararcter
!== undefined) {
652 current_chararcter
= tags
.charAt(tag_carat_position
- i
);
653 if (current_chararcter
!= " " && current_chararcter
!= "")
654 leftMost
= tag_carat_position
- i
;
656 return tags
.substring(leftMost
, right_most
);
658 var xhr
= new GM_xmlhttpRequest(({
660 url
: "https://danbooru.donmai.us/tags.json?search[name_matches]=" + closest_tag
+ "*&search[order]=count",
661 responseType
: "json",
662 onload: function (data
) {
663 data
= data
.response
;
664 var tagArray
= tags
.split(" ");
665 while (auto_complete_row
.hasChildNodes()) {
666 auto_complete_row
.removeChild(auto_complete_row
.lastChild
);
668 var qr_width
= document
.getElementById("qr").offsetWidth
;
669 var tag_table
= document
.createElement("TABLE");
670 tag_table
.setAttribute("style", "border:1px solid black;margin-top:5px");
671 var tag_row
= document
.createElement("TR");
672 for (var i
= 0; i
< 5; i
++) {
673 var a
= document
.createElement("A");
674 var tagText
= data
["" + i
];
675 if (tagText
== "" || tagText
=== undefined)
677 tagText
= tagText
["name"];
678 var a_txt
= document
.createTextNode(data
[i
]["name"]);
679 var tag_data
= document
.createElement("TD");
680 tag_data
.setAttribute("style", "padding:5px;font-size:15px;font-weight:bold;border:1px solid black;");
681 a
.appendChild(a_txt
);
682 tag_data
.appendChild(a
);
683 tag_row
.appendChild(tag_data
);
684 tag_table
.appendChild(tag_row
);
685 auto_complete_row
.appendChild(tag_table
);
686 if (tag_table
.offsetWidth
> qr_width
- 10) {
687 tag_row
.removeChild(tag_data
);
688 tag_table
= document
.createElement("TABLE");
689 tag_row
= document
.createElement("TR");
690 tag_row
.appendChild(tag_data
);
691 tag_table
.appendChild(tag_row
);
692 tag_table
.setAttribute("style", "border:1px solid black;");
693 auto_complete_row
.appendChild(tag_table
);
695 a
.addEventListener("click", function (evt
) {
696 tagArray
[tagArray
.indexOf(closest_tag
)] = this.textContent
;
697 document
.getElementById("tag_input").value
= tagArray
.join(" ");
703 this.old_tags_before_change
= tag_input_node
.value
;
705 //a series of calls on other functions that leads to the image being searched for
706 DanbooruImageAdder
.prototype.setImage = function (this_
) {
708 var tags
= document
.getElementById("tag_input").value
.trim();
709 if (tags
.indexOf(":") > -1) {
710 Generics
.alert4ChanX("Character ':' not used for functional purpose", "warning");
712 var tags_arr
= tags
.split(" ");
713 var xhr_image_load
= new GM_xmlhttpRequest(({
715 //returns a list of all tags and their properties
716 url
: "https://danbooru.donmai.us/tags.json?search[name]=" + tags_arr
.join() + "&search[order]=count",
717 responseType
: "json",
718 onload: function (data
) {
719 this_
.json_tag
= this_
.verifyTags(data
, tags_arr
);
720 if (this_
.failed_to_find_required_tags_state
)
723 var end_URL
= this_
.ratingURL(this_
.json_tag
);
724 var URL
= this_
.setPostAndPage(end_URL
);
725 this_
.send_URL
= URL
;
726 //final check, sends final request after function or calls this function again
727 Generics
.getJSON(URL
, function (err
, data
, tags
, _this_
) { return this_
.checkPageFromDanbooru(err
, data
, tags
, _this_
); }, tags_arr
, this_
);
731 //make 4chanX alerts on issues, and account for error cases.
732 DanbooruImageAdder
.prototype.verifyTags = function (data
, tags
) {
733 data
= data
.response
;
734 this.json_tag
= data
;
735 this.failed_to_find_required_tags_state
= false;
736 //if data has a null or undefined case, return an error
737 if (data
.length
== 0) {
738 Generics
.alert4ChanX("All tags incorrect", "error", 10);
739 this.failed_to_find_required_tags_state
= true;
740 document
.getElementById("timer").textContent
= "";
741 document
.getElementById("tag_input").removeAttribute("disabled");
742 document
.getElementById("imageButton").removeAttribute("disabled");
743 return this.json_tag
;
745 else if (data
.length
!= tags
.length
&& !this.tag_incorrect_state
) {
746 this.tag_incorrect_state
= true;
747 if (document
.getElementById("tag_input").value
.trim() == "")
748 Generics
.alert4ChanX("No Tags", "info", 2);
750 Generics
.alert4ChanX("One Tag Incorrect", "warning");
752 //tag size. Smallest tag is placed at bottom of JSON
753 this.smallest_tag_size
= parseInt(data
[data
.length
- 1]["post_count"]);
754 return this.json_tag
;
756 //evaluate the rating restrictions to account for danbooru's tagging limitations
757 DanbooruImageAdder
.prototype.ratingURL = function (tags
) {
759 //evaluate the 3! possible permutations
760 if (document
.getElementById("safe").checked
) {
761 if (document
.getElementById("questionable").checked
) {
762 if (document
.getElementById("explicit").checked
) {
764 URL
= "&utf8=%E2%9C%93&tags=" + tags
[tags
.length
- 2]["name"] + "+" + tags
[tags
.length
- 1]["name"];
766 URL
= "&utf8=%E2%9C%93&tags=" + tags
[tags
.length
- 1]["name"];
769 URL
= "&utf8=%E2%9C%93&tags=" + "-rating%3Aexplicit" + "+" + tags
[tags
.length
- 1]["name"];
772 else if (document
.getElementById("explicit").checked
) {
773 URL
= "&utf8=%E2%9C%93&tags=" + "-rating%3Aquestionable" + "+" + tags
[tags
.length
- 1]["name"];
776 URL
= "&utf8=%E2%9C%93&tags=" + "rating%3Asafe" + "+" + tags
[tags
.length
- 1]["name"];
779 else if (document
.getElementById("questionable").checked
) {
780 if (document
.getElementById("explicit").checked
) {
781 URL
= "&utf8=%E2%9C%93&tags=" + "-rating%3Asafe" + "+" + tags
[tags
.length
- 1]["name"];
784 URL
= "&utf8=%E2%9C%93&tags=" + "rating%3Aquestionable" + "+" + tags
[tags
.length
- 1]["name"];
787 else if (document
.getElementById("explicit").checked
) {
788 URL
= "&utf8=%E2%9C%93&tags=" + "rating%3Aexplicit" + "+" + tags
[tags
.length
- 1]["name"];
792 URL
= "&utf8=%E2%9C%93&tags=" + tags
[tags
.length
- 2]["name"] + "+" + tags
[tags
.length
- 1]["name"];
794 URL
= "&utf8=%E2%9C%93&tags=" + tags
[tags
.length
- 1]["name"];
798 //set where to search
799 DanbooruImageAdder
.prototype.setPostAndPage = function (end_URL
) {
800 this.post_number
= 0;
802 if (this.top_page
!= this.top_page_max
)
803 this.smallest_tag_size
= this.top_page
* 20;
804 if (this.smallest_tag_size
== 0)
805 this.smallest_tag_size
= 100;
806 var escape_cond
= true;
807 this.page_number
= ((Math
.floor(Math
.random() * 10000)) % Math
.ceil(this.smallest_tag_size
/ 20)) % 1000; //1000 is max page search limit
808 if (this.page_number
== 0 && this.previous_page
== 0) {
809 this.primed_for_fail
= true;
811 this.json_numbers_used
.push(this.page_number
);
812 this.previous_page
= this.page_number
;
813 var URL
= "https://danbooru.donmai.us/posts.json?page=" + this.page_number
+ end_URL
;
816 //check if valid url location
817 DanbooruImageAdder
.prototype.checkPageFromDanbooru = function (err
, data
, tags
, this_arr
) {
819 console
.log('Something went wrong: ' + err
);
820 Generics
.alert4ChanX("Danbooru Server Did Not Perform request -- Error: " + err
, "error");
821 document
.getElementById("timer").textContent
= "";
822 document
.getElementById("tag_input").removeAttribute("disabled");
823 document
.getElementById("imageButton").removeAttribute("disabled");
827 var duplicate
= false;
828 //check for repeating images found
829 this_arr
.previous_images
.forEach(function (item
) {
830 if (item
[0] == this_arr
.page_number
&& item
[1] == this_arr
.post_number
) {
832 this_arr
.post_number
++;
836 this_arr
.number_of_attempts
--;
837 if (this_arr
.primed_for_fail
) {
838 Generics
.alert4ChanX("No Results: All found for tags \"" + document
.getElementById("tag_input").value
+ "\"", "error");
839 this_arr
.reset_search_timer_fields();
842 //Out of items on current json page so go to next page
843 else if ((data
.length
< this_arr
.post_number
+ 1) && this_arr
.number_of_attempts
> 0) {
844 if (this_arr
.top_page
> this_arr
.page_number
) {
845 this_arr
.top_page
= this_arr
.page_number
+ this_arr
.post_number
/ 20;
848 this_arr
.post_number
= 0;
849 document
.getElementById("timer").textContent
= this_arr
.number_of_attempts
+ "|" + this_arr
.time
;
850 this_arr
.setImage(this_arr
);
852 else if (this_arr
.number_of_attempts
> 0) {
853 //ALL PARAMETERS WILL BE RESET INSIDE JSON
854 document
.getElementById("timer").textContent
= this_arr
.number_of_attempts
+ "|" + this_arr
.time
;
855 Generics
.getJSON(this_arr
.send_URL
, function (err
, data
, tags
, _this_arr
) { return this_arr
.setImageFromDanbooru(err
, data
, tags
, _this_arr
); }, tags
, this_arr
);
858 Generics
.alert4ChanX("Not found", "error");
859 this_arr
.reset_search_timer_fields();
864 DanbooruImageAdder
.prototype.reset_search_timer_fields = function () {
865 this.top_page
= this.top_page_max
;
866 this.number_of_attempts
= this.maximum_attempts
;
867 document
.getElementById("timer").textContent
= "";
868 document
.getElementById("tag_input").removeAttribute("disabled");
869 document
.getElementById("imageButton").removeAttribute("disabled");
871 //finally draw from the JSON page to generate and place the post into the 4chanX dumplist
872 DanbooruImageAdder
.prototype.setImageFromDanbooru = function (err
, data
, tags
, this_arr
) {
874 console
.log('Something went wrong: ' + err
);
875 Generics
.alert4ChanX("Danbooru Server Did Not Perform request -- Error: " + err
, "error");
876 document
.getElementById("timer").textContent
= "";
877 document
.getElementById("tag_input").removeAttribute("disabled");
878 document
.getElementById("imageButton").removeAttribute("disabled");
881 this_arr
.json_page
= data
;
882 var image_found
= false;
883 for (this_arr
.post_number
= this_arr
.post_number
; this_arr
.post_number
< 20; this_arr
.post_number
++) {
884 if (this_arr
.timeout
) {
885 //Case1: Took too long to scan the page.
886 //Result: Kills search
887 Generics
.alert4ChanX("timeout after " + this_arr
.time
+ " seconds", "error");
888 for (var i
= 0; i
< this_arr
.timeout_functions
.length
; i
++) {
889 clearInterval(this_arr
.timeout_functions
[i
]);
891 this_arr
.reset_search_timer_fields();
894 else if (this_arr
.json_page
["" + this_arr
.post_number
] == undefined) {
895 //Case2: reaches an undefined page.
896 //Result: Switches to a new page
897 this_arr
.top_page
= this_arr
.page_number
;
898 this_arr
.setImage(this_arr
);
901 //set the page to search
902 var end_URL
= this_arr
.json_page
["" + this_arr
.post_number
].file_url
;
903 var URL
= "https://danbooru.donmai.us" + end_URL
;
904 if (this_arr
.subdomain_regex
.test(end_URL
))
906 //place url in visible box
907 this_arr
.urlContainterFunction(URL
);
911 :{id: 3038118, created_at: "2018-03-02T15:27:56.469-05:00", uploader_id: 49091, score: 6,…}
915 created_at:"2018-03-02T15:27:56.469-05:00"
918 fav_string:"fav:553974 fav:467363 fav:455311 fav:490034 fav:505064 fav:482030 fav:351935 fav:66907 fav:467355 fav:519151"
921 file_url:"/data/__miyuki_kantai_collection_drawn_by_kumadano__7a12a196cc1aa9f794bca81a2a14bb81.jpg"
922 has_active_children:false
925 has_visible_children:false
934 is_rating_locked:false
935 is_status_locked:false
936 large_file_url:"/data/__miyuki_kantai_collection_drawn_by_kumadano__7a12a196cc1aa9f794bca81a2a14bb81.jpg"
937 last_comment_bumped_at:null
938 last_commented_at:null
940 md5:"7a12a196cc1aa9f794bca81a2a14bb81"
944 preview_file_url:"/data/preview/7a12a196cc1aa9f794bca81a2a14bb81.jpg"
947 source:"https://twitter.com/kumadano/status/969629578137251840"
950 tag_count_character:1
951 tag_count_copyright:1
954 tag_string:"1girl black_legwear blue_sailor_collar blue_skirt brown_eyes brown_hair commentary_request full_body grin kantai_collection kumadano miyuki_(kantai_collection) pleated_skirt ribbon sailor_collar school_uniform serafuku short_hair short_sleeves simple_background skirt smile socks solo standing wavy_hair white_background wrists_extended"
955 tag_string_artist:"kumadano"
956 tag_string_character:"miyuki_(kantai_collection)"
957 tag_string_copyright:"kantai_collection"
958 tag_string_general:"1girl black_legwear blue_sailor_collar blue_skirt brown_eyes brown_hair full_body grin pleated_skirt ribbon sailor_collar school_uniform serafuku short_hair short_sleeves simple_background skirt smile socks solo standing wavy_hair white_background wrists_extended"
959 tag_string_meta:"commentary_request"
961 updated_at:"2018-03-03T09:09:32.357-05:00"
966 var failed_to_find_required_tags
= false;
967 if (end_URL
=== undefined ||
968 end_URL
.indexOf(".mp4") > -1 || end_URL
.indexOf(".webm") > -1 || end_URL
.indexOf(".swf") > -1 || end_URL
.indexOf(".zip") > -1) {
972 tags
.forEach(function (tag
) {
973 //if tag contains an order then whatever
974 if (tag
.indexOf("order:") > -1) { }
975 //if it contains a raiting, check the rating character at the seventh index
976 else if (tag
.indexOf("rating:") > -1) {
977 if (tag
.charAt(7) !== this_arr
.json_page
["" + this_arr
.post_number
]["rating"]) {
978 failed_to_find_required_tags
= true;
981 //otherwise check if the tagstring contains the tags
982 else if (this_arr
.json_page
["" + this_arr
.post_number
]["tag_string"].indexOf(tag
) == -1) {
983 failed_to_find_required_tags
= true;
987 if (failed_to_find_required_tags
) {
991 if (this_arr
.json_page
["" + this_arr
.post_number
].file_size
>= 4000000) {
992 var end_URL
= this_arr
.json_page
["" + this_arr
.post_number
].large_file_url
;
993 var URL
= "https://danbooru.donmai.us" + end_URL
;
994 if (this_arr
.subdomain_regex
.test(end_URL
))
997 document
.getElementById("timer").textContent
= "...";
998 this_arr
.img_URL
= URL
;
999 var xhr
= new GM_xmlhttpRequest(({
1002 responseType
: "arraybuffer",
1003 onload: function (response
) {
1004 //is it a non existent image?
1005 if (response
.response
.byteLength
<= 387) {
1006 Generics
.alert4ChanX("Image Does Not Exist on Danbooru(404 error)\nDanbooru seems to be updating image servers???", "error");
1009 if (end_URL
.indexOf(".jpg") > -1)
1010 blob
= new Blob([response
.response
], { type
: "image/jpeg" });
1011 else if (end_URL
.indexOf(".png") > -1)
1012 blob
= new Blob([response
.response
], { type
: "image/png" });
1013 else if (end_URL
.indexOf(".gif") > -1)
1014 blob
= new Blob([response
.response
], { type
: "image/gif" });
1015 var counter
= document
.getElementById("timer");
1016 while (counter
.hasChildNodes())
1017 counter
.removeChild(counter
.lastChild
);
1018 this_arr
.reset_search_timer_fields();
1019 this_arr
.time
= this_arr
.time_max
;
1020 var name
= end_URL
.replace(/(data|cached)/g, "");
1021 name
= name
.replace(/\//g, "");
1022 //SEND RESULTING RESPONSE TO 4CHANX FILES === QRSetFile
1023 var detail
= { file
: blob
, name
: name
};
1024 if (typeof cloneInto
=== 'function') {
1025 detail
= cloneInto(detail
, document
.defaultView
);
1027 document
.dispatchEvent(new CustomEvent('QRSetFile', { bubbles
: true, detail
: detail
}));
1032 //SET PAGE&POST AS FOUND
1033 this_arr
.previous_images
.push([this_arr
.page_number
, this_arr
.post_number
]);
1034 this_arr
.post_number
= 9001;
1038 // this_arr.top_page = this_arr.page_number;
1039 this_arr
.setImage(this_arr
);
1043 DanbooruImageAdder
.prototype.urlContainterFunction = function (url
) {
1044 var url_box
= document
.getElementById("urlContainer");
1045 url_box
.value
= url
;
1047 DanbooruImageAdder
.prototype.counterFunction = function () {
1048 if (!this.timeout
) {
1050 if (this.time
< 0) {
1051 this.timeout
= true;
1052 this.time
= this.time_max
;
1056 DanbooruImageAdder
.prototype.decideAction = function (node
) { };
1057 DanbooruImageAdder
.prototype.retrieveStates = function () { };
1058 DanbooruImageAdder
.prototype.storeStates = function () {
1060 for (var _i
= 0; _i
< arguments
.length
; _i
++) {
1061 items
[_i
] = arguments
[_i
];
1064 return DanbooruImageAdder
;
1065 }(FeatureInterface
));
1066 var ThreadRebuilder
= /** @class */ (function (_super
) {
1067 __extends(ThreadRebuilder
, _super
);
1068 function ThreadRebuilder() {
1069 var _this
= _super
.call(this) || this;
1071 _this
.thread_data
= [['Comment'], ['Image URLs'], ['Image Names'], ['Post No.']];
1072 _this
.semaphore
= 1;
1073 _this
.semaphore_posts
= 1;
1074 _this
.use_offsite_archive
= false;
1075 _this
.window_displayed
= false;
1076 _this
.in_sequence
= false;
1077 _this
.tool_top_visible
= false;
1078 _this
.thread_data_length
= 0;
1079 _this
.posts_created
= 0;
1080 _this
.checked
= false;
1084 ThreadRebuilder
.prototype.init = function () {
1085 var pathname
= window
.location
.pathname
.substring(1);
1086 this.board
= pathname
.substring(0, pathname
.indexOf("/"));
1089 ThreadRebuilder
.prototype.retrieveStates = function () {
1090 this.use_offsite_archive
= localStorage
.getItem("ArchiveType") == "0" ? true : false;
1092 ThreadRebuilder
.prototype.storeStates = function () {
1094 for (var _i
= 0; _i
< arguments
.length
; _i
++) {
1095 items
[_i
] = arguments
[_i
];
1098 ThreadRebuilder
.prototype.activate = function () {
1100 document
.addEventListener("QRDialogCreation", function (e
) { return _this
.enhance4ChanX(); });
1101 document
.addEventListener('QRPostSuccessful', function (e
) {
1102 if (_this
.in_sequence
) {
1103 document
.getElementById("dump-list").childNodes
[1].click();
1104 _this
.setPropperLinking(document
.getElementById("qr").getElementsByTagName("TEXTAREA")[0].value
);
1108 ThreadRebuilder
.prototype.decideAction = function (node
) { };
1109 ThreadRebuilder
.prototype.enhance4ChanX = function () {
1111 var qr_window
= document
.getElementById("qr");
1112 if (document
.getElementById("qrRebuilder") !== null)
1113 qr_window
.removeChild(document
.getElementById("qrRebuilder"));
1114 var thread_rebuilder_table
= document
.createElement("TABLE");
1115 thread_rebuilder_table
.setAttribute("id", "qrRebuilder");
1116 thread_rebuilder_table
.setAttribute("style", "text-align:center");
1117 qr_window
.appendChild(thread_rebuilder_table
);
1118 var thread_row
= document
.createElement("TR");
1119 var option_text_size
= 18;
1120 var help_icon_container
= document
.createElement("A");
1121 help_icon_container
.href
= "javascript:void(0)";
1122 help_icon_container
.title
= "Click to View Help!";
1123 var help_icon
= document
.createElement("IMG");
1124 help_icon
.setAttribute("style", "height:" + option_text_size
* 1.25 + "px;margin:-4px 10px");
1125 help_icon
.src
= Constants
.HELP_ICON_SOURCE
;
1126 help_icon_container
.appendChild(help_icon
);
1127 thread_row
.appendChild(help_icon_container
);
1128 var tooltip_div
= document
.createElement("DIV");
1129 tooltip_div
.innerHTML
= "Insert the thread number of the post to rebuild<br/>Must be in either the 4chan archives or archived.moe<hr/>Submit bugs to <a href='https://github.com/ECHibiki/4chan-UserScripts'>my Github</a>";
1130 tooltip_div
.setAttribute("style", "z-index:9;padding:5px;border:1px solid black;background-color:white;word-wrap:break-word;display:none;position:absolute;");
1131 help_icon_container
.addEventListener("click", function (evt
) {
1132 if (_this
.tool_top_visible
)
1133 tooltip_div
.setAttribute("style", "z-index:9;padding:5px;border:1px solid black;background-color:white;word-wrap:break-word;display:none;position:absolute;");
1135 tooltip_div
.setAttribute("style", "z-index:9;padding:5px;border:1px solid black;background-color:white;word-wrap:break-word;display:block;position:absolute;"
1136 + "left:" + (evt
.clientX
- qr_window
.getBoundingClientRect().x
) +
1137 "px;top:" + (evt
.clientY
- qr_window
.getBoundingClientRect().y
) + "px;");
1138 _this
.tool_top_visible
= !_this
.tool_top_visible
;
1140 qr_window
.appendChild(tooltip_div
);
1141 var second_row_nodes
= [
1142 document
.createTextNode("Thread: "),
1143 document
.createElement("INPUT"),
1144 document
.createElement("INPUT"),
1146 second_row_nodes
.forEach(function (node
) {
1147 thread_row
.appendChild(node
);
1149 thread_rebuilder_table
.appendChild(thread_row
);
1150 second_row_nodes
[1].setAttribute("ID", "threadInput");
1151 second_row_nodes
[1].setAttribute("style", "width:35.0%");
1152 second_row_nodes
[2].setAttribute("ID", "threadButton");
1153 second_row_nodes
[2].setAttribute("type", "button");
1154 second_row_nodes
[2].setAttribute("value", "Set Rebuild Queue");
1155 second_row_nodes
[2].addEventListener("click", function () {
1156 _this
.in_sequence
= true;
1158 _this
.getThread(second_row_nodes
[1].value
);
1159 _this
.postID
= setInterval(function () { return _this
.postRoutine(); }, 1000);
1160 if (_this
.timeListen
=== undefined)
1161 _this
.timeListen
= setInterval(function () { return _this
.timeListenerFunction(); }, 1000);
1163 qr_window
.appendChild(document
.createElement("hr"));
1166 ThreadRebuilder
.prototype.postRoutine = function () {
1168 if (this.semaphore
== 0) {
1170 this.thread_data_length
= this.thread_data
[0].length
;
1171 this.fillID
= setInterval(function () { return _this
.fillRoutine(); }, 10);
1176 ThreadRebuilder
.prototype.stopRoutine = function () {
1177 clearInterval(this.postID
);
1180 ThreadRebuilder
.prototype.fillRoutine = function () {
1181 if (this.posts_created
>= this.thread_data_length
) {
1182 this.semaphore_posts
= 0;
1183 this.stopFillRoutine();
1185 else if (this.semaphore_posts
== 1) {
1186 this.semaphore_posts
--;
1187 this.createPost(this.thread_data
[0][this.posts_created
], this.thread_data
[1][this.posts_created
], this.thread_data
[2][this.posts_created
]);
1188 this.posts_created
++;
1192 ThreadRebuilder
.prototype.stopFillRoutine = function () {
1193 clearInterval(this.fillID
);
1195 ThreadRebuilder
.prototype.setPropperLinking = function (text
) {
1197 var search_regex
= RegExp(">>\\d+", "g");
1200 var link_arr
= Array();
1201 while ((result
= search_regex
.exec(text
)) != null) {
1202 var end_index
= search_regex
.lastIndex
;
1203 var post_no
= result
.toString().replace(/>/g
, "");
1204 link_arr
.push([post_no
, end_index
]);
1206 //hunt down the text of what it linked to
1207 //Get the links inside of the origonal message to show text contents
1208 var responding_text
= Array();
1209 if (this.use_offsite_archive
)
1210 var URL
= "https://www.archived.moe/_/api/chan/thread/?board=" + this.board
+ "&num=" + document
.getElementById("threadInput").value
;
1212 var URL
= "https://a.4cdn.org/" + this.board
+ "/thread/" + document
.getElementById("threadInput").value
+ ".json";
1213 var xhr
= new GM_xmlhttpRequest(({
1216 responseType
: "json",
1217 onload: function (data
) {
1218 if (_this
.use_offsite_archive
)
1219 data
= data
.response
["" + document
.getElementById("threadInput").value
]["posts"];
1221 data
= data
.response
["posts"];
1222 if (data
== undefined) {
1223 alert("Invalid Thread ID: " + document
.getElementById("threadInput").value
+ ". ");
1226 link_arr
.forEach(function (link_item
) {
1227 for (var data_entry
= 0; data_entry
< data
.length
; data_entry
++) {
1228 if (parseInt(link_item
[0]) == parseInt(data
[data_entry
]["no"])) {
1229 if (_this
.use_offsite_archive
&& data
[data_entry
]["comment_processed"] !== undefined)
1230 responding_text
.push([[post_no
, end_index
], data
[data_entry
]["comment_processed"].replace(/(>>|https:\/\/www\.archived\.moe\/.*\/thread\/.*\/#)\d+/g, ""), link_item
["media"]["safe_media_hash"]]);
1231 else if (data
[data_entry
]["com"] !== undefined)
1232 responding_text
.push([[post_no
, end_index
], data
[data_entry
]["com"].replace(/(>>|#p)\d+/g, ""), data
[data_entry
]["md5"]]);
1234 responding_text
.push([[post_no
, end_index
], undefined, data
[data_entry
]["md5"]]);
1239 var current_url
= window
.location
.href
;
1240 var hash_index
= current_url
.lastIndexOf("#") != -1 ? current_url
.lastIndexOf("#") : window
.location
.href
.length
;
1241 var current_thread
= window
.location
.href
.substring(current_url
.lastIndexOf("/") + 1, hash_index
);
1242 var current_url
= "https://a.4cdn.org/" + _this
.board
+ "/thread/" + current_thread
+ ".json";
1243 //open current thread to hunt down the text found in links
1244 var xhr
= new GM_xmlhttpRequest(({
1247 responseType
: "json",
1248 onload: function (data
) {
1249 data
= data
.response
["posts"];
1250 if (data
== undefined) {
1251 alert("Invalid Thread ID: " + document
.getElementById("threadInput").value
+ ". ");
1254 responding_text
.forEach(function (response_item
) {
1255 for (var data_entry
= 0; data_entry
< data
.length
; data_entry
++) {
1256 if (data
[data_entry
]["com"] !== undefined && (response_item
[1] == data
[data_entry
]["com"].replace(/(>>|#p)\d+/g, "") || response_item
[1] == null)
1257 && (response_item
[2] == data
[data_entry
]["md5"] || response_item
[2] == null)) {
1258 var start_index
= response_item
[0][0].legth
- response_item
[0][1];
1259 text
= text
.substring(0, start_index
) + ">>" + data
[data_entry
]["no"] + text
.substring(response_item
[0][1]);
1262 else if (response_item
[2] !== undefined && response_item
[2] == data
[data_entry
]["md5"]) {
1263 var start_index
= response_item
[0][0].legth
- response_item
[0][1];
1264 text
= text
.substring(0, start_index
) + ">>" + data
[data_entry
]["no"] + text
.substring(response_item
[0][1]);
1269 document
.getElementById("qr").getElementsByTagName("TEXTAREA")[0].value
= text
;
1270 document
.getElementById("add-post").click();
1271 _this
.semaphore_posts
++;
1280 //2) GET ARCHIVED THREAD
1281 ThreadRebuilder
.prototype.getThread = function (threadNo
) {
1283 this.thread_data
= [[], [], [], []];
1284 if (this.use_offsite_archive
)
1285 var URL
= "https://www.archived.moe/_/api/chan/thread/?board=" + this.board
+ "&num=" + document
.getElementById("threadInput").value
;
1287 var URL
= "https://a.4cdn.org/" + this.board
+ "/thread/" + document
.getElementById("threadInput").value
+ ".json";
1288 var xhr
= new GM_xmlhttpRequest(({
1291 responseType
: "json",
1292 onload: function (data
) {
1293 var starting_post
= -1;
1294 if (_this
.use_offsite_archive
) {
1296 data
= data
.response
["" + document
.getElementById("threadInput").value
];
1300 data
= data
.response
;
1302 if (data
== undefined) {
1303 alert("Invalid Thread ID: " + threadNo
+ ".\n4chan Archive ");
1306 if (_this
.use_offsite_archive
)
1307 data
["posts"] = data
.values(data
["posts"]);
1308 var len
= data
["posts"].length
;
1309 for (var post_number
= starting_post
; post_number
< len
; post_number
++) {
1310 var comment
= undefined;
1311 if (_this
.use_offsite_archive
)
1312 comment
= data
["posts"][post_number
]["comment"];
1314 comment
= data
["posts"][post_number
]["com"];
1315 if (comment
!== undefined && comment
!== null)
1316 _this
.thread_data
[0].push(comment
);
1318 _this
.thread_data
[0].push("");
1319 var filename
= undefined;
1320 if (_this
.use_offsite_archive
) {
1321 if (data
["posts"][post_number
]["media"] !== null)
1322 filename
= "" + data
["posts"][post_number
]["media"]["media_filename"];
1325 filename
= "" + data
["posts"][post_number
]["tim"] + data
["posts"][post_number
]["ext"];
1326 if (filename
!== undefined && filename
!== null && filename
.indexOf("undefined") == -1)
1327 if (_this
.use_offsite_archive
)
1328 if (data
["posts"][post_number
]["media"] !== null)
1329 _this
.thread_data
[1].push(data
["posts"][post_number
]["media"]["remote_media_link"]);
1331 _this
.thread_data
[1].push("");
1333 _this
.thread_data
[1].push("https://i.4cdn.org/" + _this
.board
+ "/" + filename
);
1335 _this
.thread_data
[1].push("");
1336 if (_this
.use_offsite_archive
) {
1337 if (data
["posts"][post_number
]["media"] !== null)
1338 _this
.thread_data
[2].push(data
["posts"][post_number
]["media"]["media_id"]);
1341 _this
.thread_data
[2].push(data
["posts"][post_number
]["filename"]);
1342 if (_this
.use_offsite_archive
)
1343 _this
.thread_data
[3].push(data
["posts"][post_number
]["num"]);
1345 _this
.thread_data
[3].push(data
["posts"][post_number
]["no"]);
1353 //3) RIP POSTS AND IMAGES
1354 ThreadRebuilder
.prototype.createPost = function (text
, imageURL
, imageName
) {
1356 if (imageURL
!= "") {
1357 var response_type
= "arraybuffer";
1358 if (this.use_offsite_archive
)
1359 response_type
= "text";
1360 var xhr
= new GM_xmlhttpRequest(({
1363 responseType
: response_type
,
1364 onload: function (response
) {
1365 if (_this
.use_offsite_archive
) {
1366 var parser
= new DOMParser();
1367 var content_attribute
= parser
.parseFromString(response
.response
, "text/html").getElementsByTagName("META")[0].getAttribute("content");
1368 var redirect_url
= content_attribute
.substring(content_attribute
.indexOf("http"));
1369 var xhr
= new GM_xmlhttpRequest(({ method
: "GET", url
: redirect_url
, responseType
: "arraybuffer",
1370 onload: function (response
) {
1371 _this
.inputImage(response
, text
, imageURL
, imageName
);
1376 _this
.inputImage(response
, text
, imageURL
, imageName
);
1382 text
= this.createPostComment(text
);
1383 this.setPropperLinking(text
);
1386 ThreadRebuilder
.prototype.inputImage = function (response
, text
, imageURL
, imageName
) {
1389 if (imageURL
.indexOf(".jpg") > -1) {
1390 blob
= new Blob([response
.response
], { type
: "image/jpeg" });
1393 else if (imageURL
.indexOf(".png") > -1) {
1394 blob
= new Blob([response
.response
], { type
: "image/png" });
1397 else if (imageURL
.indexOf(".gif") > -1) {
1398 blob
= new Blob([response
.response
], { type
: "image/gif" });
1401 else if (imageURL
.indexOf(".webm") > -1) {
1402 blob
= new Blob([response
.response
], { type
: "video/webm" });
1405 var name
= imageName
+ ext
;
1406 //SEND RESULTING RESPONSE TO 4CHANX FILES === QRSetFile
1407 var detail
= { file
: blob
, name
: name
};
1408 detail
= cloneInto(detail
, document
.defaultView
);
1409 document
.dispatchEvent(new CustomEvent('QRSetFile', { bubbles
: true, detail
: detail
}));
1410 if (text
!== "" && text
!== undefined) {
1411 text
= this.createPostComment(text
);
1412 this.setPropperLinking(text
);
1415 document
.getElementById("add-post").click();
1416 this.semaphore_posts
++;
1419 //4) CREATE POST QUEUE
1420 ThreadRebuilder
.prototype.createPostComment = function (text
) {
1421 var dummy
= document
.createElement("DIV");
1422 dummy
.innerHTML
= text
;
1423 var inside_node
= dummy
.firstChild
;
1424 var return_text
= "";
1426 if (inside_node
.tagName
== "BR")
1427 return_text
+= "\n";
1429 return_text
+= inside_node
.textContent
;
1430 } while ((inside_node
= inside_node
.nextSibling
));
1434 ThreadRebuilder
.prototype.timeListenerFunction = function () {
1435 var time
= parseInt(document
.getElementById("qr-filename-container").nextSibling
.value
.replace(/[a-zA-Z]+/g, ""));
1437 this.checked
= false;
1439 else if (time
> 5) {
1440 this.checked
= true;
1443 ThreadRebuilder
.prototype.killAll = function () {
1444 this.thread_data_length
= 0;
1445 this.posts_created
= 0;
1447 this.postID
= undefined;
1449 this.semaphore_posts
= 1;
1450 this.stopFillRoutine();
1451 this.fillID
= undefined;
1452 this.thread_data
= [['Comment'], ['Image URLs'], ['Image Names'], ['Post No.']];
1454 var qr_dumplist
= document
.getElementById("dump-list").childNodes
;
1455 var qr_dumplist_len
= qr_dumplist
.length
;
1456 var current_preview
= 0;
1457 while (qr_dumplist_len
- current_preview
> 1) {
1458 qr_dumplist
[0].firstChild
.click();
1462 return ThreadRebuilder
;
1463 }(FeatureInterface
));
1464 var CharacterInserter
= /** @class */ (function (_super
) {
1465 __extends(CharacterInserter
, _super
);
1466 function CharacterInserter(use_kita
, use_yen
) {
1467 var _this
= _super
.call(this) || this;
1468 _this
.kita_character
= "キタ━━━(゚∀゚)━━━!!";
1469 _this
.kita_hash_color
= "#444444";
1470 _this
.yen_character
= "¥";
1471 _this
.yen_hash_color
= "#9370DB";
1472 _this
.use_yen
= use_yen
;
1473 _this
.use_kita
= use_kita
;
1474 _this
.retrieveStates();
1479 CharacterInserter
.prototype.init = function () {
1481 this.hotkeyListeners();
1483 CharacterInserter
.prototype.activate = function () {
1484 console
.log("4F-FSE: CharacterInserter Active - " + (this.use_kita
? "Character Coloring+" : "") + (this.use_yen
? " Line Coloring" : ""));
1486 CharacterInserter
.prototype.decideAction = function (node
) {
1487 if (node
.tagName
== "BLOCKQUOTE")
1488 this.colorCharacters(node
);
1490 CharacterInserter
.prototype.retrieveStates = function () {
1491 if (localStorage
.getItem("Yen_Character") === undefined || localStorage
.getItem("Yen_Character") === null)
1492 this.yen_character
= "¥";
1494 this.yen_character
= localStorage
.getItem("Yen_Character");
1495 if (localStorage
.getItem("Yen_Color") === undefined || localStorage
.getItem("Yen_Color") === null)
1496 this.yen_hash_color
= "#9370DB";
1498 this.yen_hash_color
= localStorage
.getItem("Yen_Color");
1499 if (localStorage
.getItem("Kita_Character") === undefined || localStorage
.getItem("Kita_Character") === null)
1500 this.kita_character
= "キタ━━━(゚∀゚)━━━!!";
1502 this.kita_character
= localStorage
.getItem("Kita_Character");
1503 if (localStorage
.getItem("Kita_Color") === undefined || localStorage
.getItem("Kita_Color") === null)
1504 this.kita_hash_color
= "#444444";
1506 this.kita_hash_color
= localStorage
.getItem("Kita_Color");
1508 CharacterInserter
.prototype.storeStates = function () {
1510 for (var _i
= 0; _i
< arguments
.length
; _i
++) {
1511 items
[_i
] = arguments
[_i
];
1515 CharacterInserter
.prototype.addStyle = function () {
1516 var style
= document
.createElement("STYLE");
1517 style
.innerHTML
= ".the_m_word{color:" + this.yen_hash_color
+ "} \n.the_k_word{color:" + this.kita_hash_color
+ "}";
1518 document
.head
.appendChild(style
);
1520 //hotkeys for kita and yen
1521 CharacterInserter
.prototype.hotkeyListeners = function () {
1523 var listener_obj
= {};
1524 window
.addEventListener("keydown", function (e
) {
1525 listener_obj
[e
.keyCode
] = true;
1526 var node
= document
.activeElement
;
1527 if ((listener_obj
[17] || listener_obj
[91]) && listener_obj
[75]) {
1529 _this
.insertAtPos(node
, _this
.kita_character
);
1531 if ((listener_obj
[17] || listener_obj
[91]) && listener_obj
[220]) {
1533 _this
.insertAtPos(node
, _this
.yen_character
);
1535 }, { passive
: false, capture
: false, once
: false });
1536 window
.addEventListener("keyup", function (e
) {
1537 listener_obj
[e
.keyCode
] = false;
1538 }, { passive
: false, capture
: false, once
: false });
1540 CharacterInserter
.prototype.insertAtPos = function (node
, buzzwords
) {
1541 var sel_start
= node
.selectionStart
;
1542 var sel_end
= node
.selectionEnd
;
1543 var node_text
= node
.value
;
1544 node
.value
= node_text
.substr(0, sel_start
) + buzzwords
+ node_text
.substr(sel_end
);
1545 node
.selectionStart
= sel_start
+ buzzwords
.length
;
1546 node
.selectionEnd
= sel_end
+ buzzwords
.length
;
1549 CharacterInserter
.prototype.colorCharacters = function (root
) {
1550 if (root
.nodeType
!== Node
.ELEMENT_NODE
) {
1553 if (root
.textContent
.indexOf(this.yen_character
) <= -1 && root
.textContent
.indexOf(this.kita_character
) <= -1) {
1556 var wbr
= root
.getElementsByTagName('WBR');
1557 var wbr_len
= wbr
.length
;
1558 var wbr_indices
= Array();
1559 function previousIndex(len
) {
1561 return wbr_indices
[len
- 1];
1565 for (var wbr_item
= 0; wbr_item
< wbr_len
; wbr_item
++) {
1566 wbr_indices
.push(wbr
[wbr_item
].previousSibling
.length
+ previousIndex(wbr_item
));
1568 while (wbr
.length
) {
1569 root
.removeChild(wbr
[wbr
.length
- 1]);
1572 var txtItterator
= document
.createNodeIterator(root
, NodeFilter
.SHOW_TEXT
);
1574 while ((text_node
= txtItterator
.nextNode())) {
1575 //disregard text inside of A tag links and already colored text
1576 if (text_node
.parentNode
.tagName
== "A" || /the_[a-z]_word/g.test(text_node
.parentNode
.className
))
1578 this.setColor(text_node
, txtItterator
);
1580 //restart and add back the wbr
1581 var txtItterator
= document
.createNodeIterator(root
, NodeFilter
.SHOW_TEXT
);
1583 while ((text_node
= txtItterator
.nextNode())) {
1584 //disregard text inside of A tag links and already colored text
1585 if (text_node
.parentNode
.tagName
== "A")
1587 wbr_indices
= this.addWBR(text_node
, txtItterator
, wbr_indices
);
1591 CharacterInserter
.prototype.addWBR = function (text_node
, txtItterator
, wbr_indices
) {
1592 wbr_indices
[0] = wbr_indices
[0] - text_node
.length
;
1593 if (wbr_indices
[0] <= 0) {
1594 var split_node
= text_node
.splitText(text_node
.length
+ wbr_indices
[0]);
1595 var wbr
= document
.createElement("WBR");
1596 split_node
.parentNode
.insertBefore(wbr
, text_node
.nextSibling
);
1597 wbr_indices
.shift();
1601 //give color to text inside of nodes.
1602 // first scan for yen symbols and then check the front of the text for not nested kita.
1603 CharacterInserter
.prototype.setColor = function (text_node
, txtItterator
) {
1604 var start_text_node
= text_node
;
1606 var yen_node
= this.use_kita
? this.searchYen(text_node
) : false;
1607 if (yen_node
!= false) {
1608 //jump to internal node
1609 text_node
= txtItterator
.nextNode();
1610 //scan for nested kita
1612 result
= this.use_kita
? this.searchKita(text_node
) : false;
1613 if (result
!= false) {
1614 //jump foreward to point after kita inserted
1615 text_node
= txtItterator
.nextNode();
1616 text_node
= txtItterator
.nextNode();
1618 } while (result
!= false);
1620 //scan for outside kita from start
1622 result
= this.use_kita
? this.searchKita(start_text_node
) : false;
1623 start_text_node
= result
.nextSibling
;
1624 } while (result
!= false && start_text_node
!== undefined);
1626 //find the location of a yen, split the text from above that position, create a span element and place split into this span.
1627 //Then take the initial text node and insert into it from after the text node.
1628 CharacterInserter
.prototype.searchYen = function (text_node
) {
1629 var yenIndex
= text_node
.textContent
.indexOf(this.yen_character
);
1630 if (yenIndex
> -1) {
1631 var splitNode
= text_node
.splitText(yenIndex
);
1632 var span
= document
.createElement('span');
1633 span
.className
= "the_m_word";
1634 span
.appendChild(splitNode
);
1635 text_node
.parentNode
.insertBefore(span
, text_node
.nextSibling
);
1640 //find the location of a kita, isolate it by splitting from the point where the kita ends and the point where it begins.
1641 //Now that there are 3 text nodes, take the middle one from the start position index split, add the text which goes to the point of the rightmost split,
1642 //then refer back to the parent and place it after the leftmost string.
1643 CharacterInserter
.prototype.searchKita = function (text_node
) {
1644 var kIndex
= text_node
.textContent
.indexOf(this.kita_character
);
1646 var far_split_note
= text_node
.splitText(kIndex
+ this.kita_character
.length
);
1647 var splitNode
= text_node
.splitText(kIndex
);
1648 var span
= document
.createElement('span');
1649 span
.className
= "the_k_word";
1650 span
.appendChild(splitNode
);
1651 text_node
.parentNode
.insertBefore(span
, text_node
.nextSibling
);
1656 return CharacterInserter
;
1657 }(FeatureInterface
));
1658 var PasswordViewer
= /** @class */ (function (_super
) {
1659 __extends(PasswordViewer
, _super
);
1660 function PasswordViewer() {
1661 var _this
= _super
.call(this) || this;
1662 _this
.post_id
= "postPassword";
1663 _this
.del_id
= "delPassword";
1664 _this
.label_post
= document
.createElement('LABEL');
1665 _this
.label_del
= document
.createElement('LABEL');
1670 PasswordViewer
.prototype.init = function () {
1671 this.node_post
= document
.getElementById(this.post_id
);
1672 this.node_del
= document
.getElementById(this.del_id
);
1673 this.node_post_parent
= this.node_post
.parentNode
;
1674 this.node_del_parent
= this.node_del
.parentNode
;
1675 this.label_post
.textContent
= 'Post: ';
1676 this.label_del
.textContent
= 'Delete: ';
1678 //activate displays passwords
1679 PasswordViewer
.prototype.activate = function () {
1680 console
.log("4F-FSE: PasswordViewer Active");
1681 this.node_post_parent
.insertBefore(this.label_post
, this.node_post
);
1682 this.node_del_parent
.insertBefore(this.label_del
, this.node_del
);
1683 this.node_post
.removeAttribute('type');
1684 this.node_del
.removeAttribute('type');
1685 document
.getElementsByClassName('deleteform')[0].style
.display
= 'inline';
1686 this.node_del
.style
.display
= 'inline';
1687 this.label_del
.style
.display
= 'inline';
1688 this.label_del
.style
.paddingLeft
= '10px';
1690 PasswordViewer
.prototype.decideAction = function (node
) { };
1691 PasswordViewer
.prototype.retrieveStates = function () { };
1693 PasswordViewer
.prototype.storeStates = function () { };
1695 return PasswordViewer
;
1696 }(FeatureInterface
));
1697 var SettingsWindow
= /** @class */ (function (_super
) {
1698 __extends(SettingsWindow
, _super
);
1699 function SettingsWindow() {
1700 var _this
= _super
.call(this) || this;
1701 _this
.background_div
= document
.createElement('DIV');
1702 _this
.settings_div
= document
.createElement('DIV');
1703 _this
.close_div
= document
.createElement('DIV');
1704 _this
.contents_div
= document
.createElement('DIV');
1705 _this
.ul_selection_start
= document
.createElement('UL');
1706 _this
.close_link
= document
.createElement('A');
1707 _this
.title_para
= document
.createElement('P');
1708 _this
.title_text
= document
.createTextNode('4F-FSE Settings');
1709 _this
.end_para
= document
.createElement('P');
1710 _this
.end_text
= document
.createTextNode('Refresh to view changes');
1711 _this
.settings_style
= document
.createElement('STYLE');
1712 //to change order change, this AND...*
1713 _this
.list_items
= [
1714 { Text
: " | View 『Image Hiding』 Settings", ListenerFunc: function (a_id
) {
1715 _this
.clearContainer();
1716 _this
.contents_div
.innerHTML
=
1717 "\n\t\t\t\t<div id=\"disposable_container\">\n\t\t\t\t\t\t\t\t <label>Non-MD5 Expiration Time(hours): </label>\n\t\t\t\t\t\t\t\t <input id=\"Expiration_Time\">\n\t\t\t\t\t\t\t\t <hr>\n\t\t\t\t\t\t\t\t <label>MD5 Filters:</label>\n\t\t\t\t\t\t\t\t <br>\n\t\t\t\t\t\t\t\t <textarea style=\"width:98%;height:217px\" placeholder=\"Enter MD5 like on 4chanX... \n\t\t\t\t\t\t\t\t/abc123/\n\t\t\t\t\t\t\t\t/def890/\" id=\"MD5_List_FSE\"></textarea>\n\t\t\t\t\t\t\t\t<hr>\n\t\t\t\t</div>\n\t\t\t\t";
1718 document
.getElementById("Expiration_Time").value
= "" + (_this
.setting_items
.image_hiding_settings
.Expiration_Time
/ Constants
.MILLISECONDS_TO_THE_HOUR
);
1719 document
.getElementById("MD5_List_FSE").value
= _this
.setting_items
.image_hiding_settings
.MD5_List_FSE
;
1720 var set_button
= document
.createElement('INPUT');
1721 document
.getElementById("disposable_container").appendChild(set_button
);
1722 set_button
.setAttribute('VALUE', "Set Image Settings");
1723 set_button
.addEventListener("click", function (evt
) {
1724 _this
.storeStates();
1725 _this
.clearContainer();
1726 _this
.rebuildContainer();
1728 set_button
.setAttribute('TYPE', 'button');
1731 { Text
: " | View 『Word Replacement』 Settings", ListenerFunc: function (a_id
) {
1732 _this
.clearContainer();
1733 var disposable_container
= document
.createElement("DIV");
1734 disposable_container
.setAttribute("ID", "disposable_container");
1735 _this
.contents_div
.appendChild(disposable_container
);
1736 _this
.filterWindow(disposable_container
);
1737 _this
.filterSetTable();
1740 { Text
: " | View 『Danbooru Image Adder』 Settings", ListenerFunc: function (a_id
) {
1741 _this
.clearContainer();
1742 var disposable_container
= document
.createElement("DIV");
1743 disposable_container
.setAttribute("id", "disposable_container");
1744 _this
.contents_div
.appendChild(disposable_container
);
1745 disposable_container
.innerHTML
= "\n\t\t\t<table style=\"text-align:center;margin-left:5px\">\n\t\t\t\t<tr>\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<label>Very Large: </label>\n\t\t\t\t\t</td>\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<input id=\"v_large_DIA\" name=\"preivew-size\" style=\"display:inline\" type=\"radio\">\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<label>Large: </label>\n\t\t\t\t\t</td>\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<input id=\"large_DIA\" name=\"preivew-size\" style=\"display:inline\" type=\"radio\">\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<label>Medium: </label>\n\t\t\t\t\t</td>\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<input id=\"medium_DIA\" name=\"preivew-size\" style=\"display:inline\" type=\"radio\">\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<label>Small: </label>\n\t\t\t\t\t</td>\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<input id=\"small_DIA\" name=\"preivew-size\" style=\"display:inline\" type=\"radio\">\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<label>Width: </label>\n\t\t\t\t\t</td>\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<input id=\"width_DIA\" name=\"preivew-size\" style=\"width:20%\" type=\"text\">\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<label>Height: </label>\n\t\t\t\t\t</td>\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<input id=\"height_DIA\" name=\"preivew-size\" style=\"width:20%\" type=\"text\">\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t</table>\t\n\t\t\n\t\t\t<hr>\n\t\t\t\n\t\t\t<label>Quick Reply Min Width: </label>\n\t\t\t<input id=\"qr_width_DIA\" name=\"preivew-size\" style=\"width:20%\" type=\"text\">\n\t\t\n\t\t\t<hr>\n\t\t\n\t\t\t<input id=\"SetImageAdderProperties\" value=\"Set Preview Size\" type=\"button\">\n\t\t\t";
1746 _this
.setImageAdderFields();
1747 _this
.setImageAdderEventListeners();
1750 { Text
: " | View 『Thread Rebuilder』 Settings", ListenerFunc: function (a_id
) {
1751 _this
.clearContainer();
1752 var disposable_container
= document
.createElement("DIV");
1753 disposable_container
.setAttribute("id", "disposable_container");
1754 _this
.contents_div
.appendChild(disposable_container
);
1755 disposable_container
.innerHTML
=
1756 "\n\t\t\t\t<label>Use 4chan Archives: </label>\n\t\t\t\t<input name=\"ArchiveSettings\" id=\"OnsiteArchive\" type=\"radio\">\n\t\t\t\t<br>\n\t\t\t\t<label>Use Offsite Archives: </label>\n\t\t\t\t<input name=\"ArchiveSettings\" id=\"OffsiteArchive\" type=\"radio\">\n\t\t\t\t<br>\n\t\t\t\t<input id=\"setArchive\" value=\"Set Archive\" type=\"button\">\n\t\t\t";
1757 (document
.getElementById("setArchive")).addEventListener("click", function () {
1758 _this
.storeStates();
1759 _this
.clearContainer();
1760 _this
.rebuildContainer();
1762 if (_this
.setting_items
.thread_rebuild_settings
.Archive_Type
=== "0")
1763 document
.getElementById("OffsiteArchive").checked
= true;
1764 else if (_this
.setting_items
.thread_rebuild_settings
.Archive_Type
=== "1")
1765 document
.getElementById("OnsiteArchive").checked
= true;
1768 { Text
: " | View 『¥ Text』 Settings [Customizable]", ListenerFunc: function (a_id
) {
1769 _this
.clearContainer();
1770 var disposable_container
= document
.createElement("DIV");
1771 disposable_container
.setAttribute("id", "disposable_container");
1772 _this
.contents_div
.appendChild(disposable_container
);
1773 disposable_container
.innerHTML
=
1774 "\n\t\t\t\t<label>\u00A5Quote Character: </label>\n\t\t\t\t<input name=\"quoteCharacter\" id=\"quoteCharacter\" type=\"text\" value=\"\u00A5\">\n\t\t\t\t<br>\n\t\t\t\t<label>RGB Hex Color: </label>\n\t\t\t\t<input name=\"HexColorYen\" id=\"HexColorYen_text\" type=\"text\">\n\t\t\t\t<input name=\"HexColorYen\" id=\"SelectColorYen\" type=\"color\">\n\t\t\t\t<br>\n\t\t\t\t<input id=\"setQuote\" value=\"Set Quote Settings\" type=\"button\">\n\t\t\t";
1775 document
.getElementById("SelectColorYen").addEventListener("input", function (evt
) {
1776 document
.getElementById("HexColorYen_text").value
=
1777 (document
.getElementById("SelectColorYen").value
);
1779 document
.getElementById("setQuote").addEventListener("click", function (e
) {
1780 _this
.storeStates();
1781 _this
.clearContainer();
1782 _this
.rebuildContainer();
1784 if (_this
.setting_items
.character_inserter_settings
.Yen_Character
!== undefined)
1785 document
.getElementById("quoteCharacter").value
= _this
.setting_items
.character_inserter_settings
.Yen_Character
;
1786 if (_this
.setting_items
.character_inserter_settings
.Yen_Color
!== undefined)
1787 document
.getElementById("HexColorYen_text").value
= _this
.setting_items
.character_inserter_settings
.Yen_Color
;
1788 document
.getElementById("SelectColorYen").value
= _this
.setting_items
.character_inserter_settings
.Yen_Color
;
1791 { Text
: " | View 『Kita』 Settings [Customizable]", ListenerFunc: function (a_id
) {
1792 _this
.clearContainer();
1793 var disposable_container
= document
.createElement("DIV");
1794 disposable_container
.setAttribute("id", "disposable_container");
1795 _this
.contents_div
.appendChild(disposable_container
);
1796 disposable_container
.innerHTML
=
1797 "\t\t\t\t\t\t\t\t\n\t\t\t\t<script src=\"http://jscolor.js\"></script>\n\t\t\t\t<label>Kita Characters: </label>\n\t\t\t\t<input name=\"selectiveCharacter\" id=\"selectiveCharacters\" type=\"text\" value=\"\uFF77\uFF80\u2501\u2501\u2501(\uFF9F\u2200\uFF9F)\u2501\u2501\u2501!!\">\n\t\t\t\t<br>\n\t\t\t\t<label>RGB Hex Color: </label>\n\t\t\t\t<input name=\"HexColorKita\" id=\"HexColorKita_text\" type=\"text\">\n\t\t\t\t<input name=\"HexColorKita\" id=\"SelectColorKita\" type=\"color\">\n\t\t\t\t<br>\n\t\t\t\t<input id=\"setCharacter\" value=\"Set Character Settings\" type=\"button\">\n\t\t\t";
1798 document
.getElementById("SelectColorKita").addEventListener("input", function (evt
) {
1799 document
.getElementById("HexColorKita_text").value
=
1800 (document
.getElementById("SelectColorKita").value
);
1802 document
.getElementById("setCharacter").addEventListener("click", function (e
) {
1803 _this
.storeStates();
1804 _this
.clearContainer();
1805 _this
.rebuildContainer();
1807 if (_this
.setting_items
.character_inserter_settings
.Kita_Character
!== undefined)
1808 document
.getElementById("selectiveCharacters").value
= _this
.setting_items
.character_inserter_settings
.Kita_Character
;
1809 if (_this
.setting_items
.character_inserter_settings
.Kita_Color
!== undefined)
1810 document
.getElementById("HexColorKita_text").value
= _this
.setting_items
.character_inserter_settings
.Kita_Color
;
1811 document
.getElementById("SelectColorKita").value
= _this
.setting_items
.character_inserter_settings
.Kita_Color
;
1814 { Text
: " | Set 『Visible Password』", ListenerFunc: function (input_id
) {
1815 _this
.storeStates();
1818 _this
.setting_items
= {};
1819 _this
.retrieveStates();
1824 SettingsWindow
.prototype.setImageAdderFields = function () {
1825 document
.getElementById("width_DIA").value
= this.setting_items
.image_adder_settings
.Width
;
1826 document
.getElementById("height_DIA").value
= this.setting_items
.image_adder_settings
.Height
;
1827 document
.getElementById("qr_width_DIA").value
= this.setting_items
.image_adder_settings
.QR_Width
;
1828 if (document
.getElementById("width_DIA").value
== "489")
1829 document
.getElementById("v_large_DIA").checked
= true;
1830 else if (document
.getElementById("width_DIA").value
== "400")
1831 document
.getElementById("large_DIA").checked
= true;
1832 else if (document
.getElementById("width_DIA").value
== "300")
1833 document
.getElementById("medium_DIA").checked
= true;
1834 else if (document
.getElementById("width_DIA").value
== "200")
1835 document
.getElementById("small_DIA").checked
= true;
1837 SettingsWindow
.prototype.setImageAdderEventListeners = function () {
1839 document
.getElementById("v_large_DIA").addEventListener("click", function () {
1840 document
.getElementById("width_DIA").value
= "489";
1841 document
.getElementById("height_DIA").value
= "489";
1843 document
.getElementById("large_DIA").addEventListener("click", function () {
1844 document
.getElementById("width_DIA").value
= "400";
1845 document
.getElementById("height_DIA").value
= "400";
1847 document
.getElementById("medium_DIA").addEventListener("click", function () {
1848 document
.getElementById("width_DIA").value
= "300";
1849 document
.getElementById("height_DIA").value
= "300";
1851 document
.getElementById("small_DIA").addEventListener("click", function () {
1852 document
.getElementById("width_DIA").value
= "200";
1853 document
.getElementById("height_DIA").value
= "200";
1855 document
.getElementById("SetImageAdderProperties").addEventListener("click", function (evt
) {
1856 _this
.storeStates();
1857 _this
.clearContainer();
1858 _this
.rebuildContainer();
1862 SettingsWindow
.prototype.retrieveStates = function () {
1863 //values used to fill out data fields
1864 this.setting_items
.image_hiding_settings
= { Expiration_Time
: localStorage
.getItem("Expiration_Time"), MD5_List_FSE
: localStorage
.getItem("MD5_List_FSE"), Active
: localStorage
.getItem("ImageHidingActive") };
1865 this.retrieveWordReplaceStates();
1866 this.retrieveImageAdderStates();
1867 this.retrieveRebuildStates();
1868 this.retrieveCharacterInsertingStates();
1869 this.setting_items
.password_settings
= (localStorage
.getItem("PasswordActive"));
1871 SettingsWindow
.prototype.retrieveActiveToggles = function () {
1872 if (localStorage
.getItem("4F-FSE") === null) {
1873 document
.getElementById("check-settings0").checked
= true;
1874 document
.getElementById("check-settings1").checked
= false;
1875 document
.getElementById("check-settings2").checked
= false;
1876 document
.getElementById("check-settings3").checked
= false;
1877 document
.getElementById("check-settings4").checked
= true;
1878 document
.getElementById("check-settings5").checked
= true;
1879 document
.getElementById("check-settings6").checked
= true;
1880 localStorage
.setItem("4F-FSE", "Success");
1881 this.displayWindow();
1884 document
.getElementById("check-settings0").checked
= localStorage
.getItem("ImageHidingActive") === 'true';
1885 document
.getElementById("check-settings1").checked
= localStorage
.getItem("TextReplaceActive") === 'true';
1886 document
.getElementById("check-settings2").checked
= localStorage
.getItem("ImageAdderActive") === 'true';
1887 document
.getElementById("check-settings3").checked
= localStorage
.getItem("ThreadRebuilderActive") === 'true';
1888 document
.getElementById("check-settings4").checked
= localStorage
.getItem("YenActive") === 'true';
1889 document
.getElementById("check-settings5").checked
= localStorage
.getItem("KitaActive") === 'true';
1890 document
.getElementById("check-settings6").checked
= localStorage
.getItem("PasswordActive") === 'true';
1892 SettingsWindow
.prototype.retrieveWordReplaceStates = function () {
1893 //acquire text filter representation
1894 var storage_index
= 0;
1895 var JSON_storage
= {};
1897 var text_filters
= [];
1898 var local_store_len
= window
.localStorage
.length
;
1899 while (storage_index
< local_store_len
) {
1900 storage_key
= window
.localStorage
.key(storage_index
);
1901 JSON_storage
[storage_key
] = window
.localStorage
.getItem(storage_key
);
1904 var filters
= Generics
.getJSONPropertiesByKeyName(JSON_storage
, "[0-9]+FLT");
1906 filters
.forEach(function (filter
) {
1907 text_filters
.push(TextReplacer
.formatFilterSettings(JSON_storage
[filter
]));
1909 this.setting_items
.word_replace_settings
= { Number_of_Filters
: localStorage
.getItem("filter_quantity"), Text_Filter_List
: text_filters
, Active
: localStorage
.getItem("TextReplaceActive") };
1911 SettingsWindow
.prototype.retrieveImageAdderStates = function () {
1912 this.setting_items
.image_adder_settings
= { Width
: localStorage
.getItem("width_DIA"),
1913 Height
: localStorage
.getItem("height_DIA"),
1914 QR_Width
: localStorage
.getItem("qr_width_DIA"),
1915 Active
: localStorage
.getItem("ImageAdderActive") };
1916 if (this.setting_items
.image_adder_settings
.Height
=== null)
1917 this.setting_items
.image_adder_settings
.Height
= 400;
1918 if (this.setting_items
.image_adder_settings
.Width
=== null)
1919 this.setting_items
.image_adder_settings
.Width
= 400;
1920 if (this.setting_items
.image_adder_settings
.QR_Width
=== null)
1921 this.setting_items
.image_adder_settings
.QR_Width
= 480;
1922 document
.getElementById("fourchanx-css").textContent
+= ".qr-preview { height:" + this.setting_items
.image_adder_settings
.Height
+ "px; width: " + this.setting_items
.image_adder_settings
.Width
+ "px; left:8%;background-size: cover;}";
1923 document
.getElementById("fourchanx-css").textContent
+= "#dump-list { min-height: " + (this.setting_items
.image_adder_settings
.Width
- 20) + "px; width: " + (this.setting_items
.image_adder_settings
.QR_Width
) + "px;}";
1925 SettingsWindow
.prototype.retrieveRebuildStates = function () {
1926 if (localStorage
.getItem("ArchiveType_FSE") !== "1" && localStorage
.getItem("ArchiveType_FSE") !== "0")
1927 localStorage
.setItem("ArchiveType_FSE", "1");
1928 this.setting_items
.thread_rebuild_settings
= { Archive_Type
: localStorage
.getItem("ArchiveType_FSE"), Active
: localStorage
.getItem("ThreadRebuilderActive") };
1930 SettingsWindow
.prototype.retrieveCharacterInsertingStates = function () {
1931 if (localStorage
.getItem("Yen_Character") === undefined || localStorage
.getItem("Yen_Character") === null)
1932 localStorage
.setItem("Yen_Character", "¥");
1933 if (localStorage
.getItem("Yen_Color") === undefined || localStorage
.getItem("Yen_Color") === null)
1934 localStorage
.setItem("Yen_Color", "#9370DB");
1935 if (localStorage
.getItem("Kita_Character") === undefined || localStorage
.getItem("Kita_Character") === null)
1936 localStorage
.setItem("Kita_Character", "キタ━━━(゚∀゚)━━━!!");
1937 if (localStorage
.getItem("Kita_Color") === undefined || localStorage
.getItem("Kita_Color") === null)
1938 localStorage
.setItem("Kita_Color", "#444444");
1939 this.setting_items
.character_inserter_settings
= { Yen_Active
: localStorage
.getItem("YenActive"), Yen_Character
: localStorage
.getItem("Yen_Character"), Yen_Color
: localStorage
.getItem("Yen_Color"),
1940 Kita_Active
: localStorage
.getItem("KitaActive"), Kita_Character
: localStorage
.getItem("Kita_Character"), Kita_Color
: localStorage
.getItem("Kita_Color") };
1942 SettingsWindow
.prototype.storeStates = function () {
1944 this.storeImageFilterStates();
1945 //Text replace settings
1946 this.storeTextFilterStates();
1947 //Image Adder settings
1948 this.storeImageAdderStates();
1949 //Thread rebuild settings
1950 this.storeRebuildStates();
1951 //character inserter
1952 this.storeCharacterInserterStates();
1953 //Password replace settings
1954 this.storePasswordStates();
1955 this.retrieveStates();
1957 SettingsWindow
.prototype.storeActiveToggles = function () {
1958 localStorage
.setItem("ImageHidingActive", (document
.getElementById("check-settings0").checked
.toString()));
1959 localStorage
.setItem("TextReplaceActive", (document
.getElementById("check-settings1").checked
.toString()));
1960 localStorage
.setItem("ImageAdderActive", (document
.getElementById("check-settings2").checked
.toString()));
1961 localStorage
.setItem("ThreadRebuilderActive", (document
.getElementById("check-settings3").checked
.toString()));
1962 localStorage
.setItem("YenActive", (document
.getElementById("check-settings4").checked
.toString()));
1963 localStorage
.setItem("KitaActive", (document
.getElementById("check-settings5").checked
.toString()));
1964 localStorage
.setItem("PasswordActive", (document
.getElementById("check-settings6").checked
.toString()));
1966 SettingsWindow
.prototype.storeImageFilterStates = function () {
1967 if (document
.getElementById("Expiration_Time") !== null) {
1968 var time
= document
.getElementById("Expiration_Time");
1969 var millisecond_time
= parseInt(time
.value
) * Constants
.MILLISECONDS_TO_THE_HOUR
;
1970 if (millisecond_time
== 0 || millisecond_time
=== null || millisecond_time
=== undefined)
1971 millisecond_time
= Constants
.DEFAULT_HIDE_EXPIRATION_TIME
;
1972 localStorage
.setItem("Expiration_Time", millisecond_time
.toString());
1973 var md5_filters
= document
.getElementById("MD5_List_FSE").value
;
1974 localStorage
.setItem("MD5_List_FSE", md5_filters
);
1975 Generics
.alert4ChanX("Image Settings Saved", "success", 3);
1978 SettingsWindow
.prototype.storeTextFilterStates = function () {
1979 if (document
.getElementById("FilterRow0") !== null) {
1980 var f_row_moving
= document
.getElementById("FilterRow0");
1981 var Number_of_Filters
= 0;
1982 var Number_of_Filters_actual
= 0;
1983 while (f_row_moving
.nextSibling
!== null) {
1984 if (document
.getElementById("Pattern" + Number_of_Filters
).value
!== "")
1985 Number_of_Filters_actual
++;
1986 Number_of_Filters
++;
1987 f_row_moving
= f_row_moving
.nextSibling
;
1989 window
.localStorage
.setItem("filter_quantity", Number_of_Filters_actual
.toString());
1990 for (var pattern_input
= 0; pattern_input
< Number_of_Filters
; pattern_input
++) {
1991 var pattern_to_store
= document
.getElementById("Pattern" + pattern_input
).value
;
1992 var replacement_to_store
= document
.getElementById("Replacement" + pattern_input
).value
;
1995 if (pattern_to_store
=== "") {
1996 localStorage
.removeItem(pattern_input
+ "FLT");
1999 else if (new RegExp("^\/.*\/\\D+$").test(pattern_to_store
)) { }
2000 else if (new RegExp("^\/.*\/$").test(pattern_to_store
)) {
2001 pattern_to_store
= pattern_to_store
+ setting
;
2003 else if (!new RegExp("^/.*\/\\D$").test(pattern_to_store
)) {
2004 pattern_to_store
= "/" + pattern_to_store
+ "/" + setting
;
2006 //test for breakages, try to cause error
2007 var error_test
= new RegExp(pattern_to_store
.substring(0, pattern_to_store
.lastIndexOf("/") + 1), pattern_to_store
.substring(pattern_to_store
.lastIndexOf("/") + 1));
2010 Generics
.alert4ChanX("Unrecoverable Regex error on pattern " + pattern_input
+ " for " + pattern_to_store
, "error", undefined);
2013 pattern_to_store
= encodeURIComponent(pattern_to_store
);
2014 var save_string
= document
.getElementById("Active" + pattern_input
).checked
+ '=' + pattern_to_store
+ '=' + replacement_to_store
;
2015 window
.localStorage
.setItem(pattern_input
+ "FLT", save_string
);
2017 Generics
.alert4ChanX("Wordfilters Updated!", "success", 3);
2020 SettingsWindow
.prototype.storeImageAdderStates = function () {
2021 if (document
.getElementById("SetImageAdderProperties") !== null) {
2022 var width
= document
.getElementById("width_DIA").value
;
2023 localStorage
.setItem("width_DIA", width
);
2024 var height
= document
.getElementById("height_DIA").value
;
2025 localStorage
.setItem("height_DIA", height
);
2026 var qr_width
= document
.getElementById("qr_width_DIA").value
;
2027 localStorage
.setItem("qr_width_DIA", qr_width
);
2030 SettingsWindow
.prototype.storeRebuildStates = function () {
2031 if (document
.getElementById("setArchive") !== null) {
2032 localStorage
.setItem("ArchiveType_FSE", document
.getElementById("OffsiteArchive").checked
=== true ? "0" : "1");
2035 SettingsWindow
.prototype.storeCharacterInserterStates = function () {
2036 if (document
.getElementById("setCharacter") !== null) {
2037 localStorage
.setItem("Kita_Character", document
.getElementById("selectiveCharacters").value
);
2038 localStorage
.setItem("Kita_Color", document
.getElementById("HexColorKita_text").value
);
2040 else if (document
.getElementById("setQuote") !== null) {
2041 localStorage
.setItem("Yen_Character", document
.getElementById("quoteCharacter").value
);
2042 localStorage
.setItem("Yen_Color", document
.getElementById("HexColorYen_text").value
);
2045 SettingsWindow
.prototype.storePasswordStates = function () {
2046 //password view settings
2047 if (document
.getElementById("check-settings6") !== null)
2048 localStorage
.setItem("PasswordActive", "" + document
.getElementById("check-settings6").checked
);
2050 SettingsWindow
.prototype.clearContainer = function () {
2051 var disposable
= document
.getElementById("disposable_container");
2052 if (disposable
!== null)
2053 this.contents_div
.removeChild(disposable
);
2055 this.contents_div
.removeChild(this.ul_selection_start
);
2057 SettingsWindow
.prototype.rebuildContainer = function () {
2058 this.contents_div
.appendChild(this.ul_selection_start
);
2060 SettingsWindow
.prototype.init = function () {
2062 this.settings_style
.innerHTML
= ".inputs{\n\t\t\t\t\t\t\t\t\t\t\tbackground-color:rgb(200,200,200);margin:5px 7px;width:100px;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t.SettingsBackground{\n\t\t\t\t\t\t\t\t\t\t\tposition:fixed;width:100%;height:100%;background-color:rgba(200,200,200,0.3);top:0;left:0; z-index:9\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t.settingsItem{\n\t\t\t\t\t\t\t\t\t\t\tfont-size:18px;list-style:katakana-iroha outside;padding:2px;color:#2e2345;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t.settingsItem input{\n\t\t\t\t\t\t\t\t\t\t\ttransform: scale(1.2);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t.settingsMain{\n\t\t\t\t\t\t\t\t\t\t\tborder:solid 1px black;position:fixed;background-color:rgb(200,200,200);left:40%;top:20%;margin-bottom:0; z-index:10\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t.closeIcon{\n\t\t\t\t\t\t\t\t\t\t\tborder:solid 1px black;position:absolute;width:25px;height:25px;background-color:rgba(255,100,90,0.9); right:3px;top:3px; z-index:10\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t.titleStyle{\n\t\t\t\t\t\t\t\t\t\t\tfont-size: 20px;padding: 12px 0px 9px 22px\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t.tooltip-4F{\n\t\t\t\t\t\t\t\t\t\t\tz-index:9;padding:5px;border:1px solid black;background-color:white;word-wrap:break-word;display:none;position:absolute;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t.help_icon{\n\t\t\t\t\t\t\t\t\t\t\theight:22.5px;margin:-4px 10px\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t.footerStyle{\n\t\t\t\t\t\t\t\t\t\t\tpadding-left: 12px;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t.contentStyle{\n\t\t\t\t\t\t\t\t\t\t\tbackground-color:white;margin:0 0;padding:5px 25px;\n\t\t\t\t\t\t\t\t\t\t}";
2063 this.background_div
.setAttribute('class', 'SettingsBackground');
2064 this.background_div
.setAttribute('id', 'SettingsBackground');
2065 this.background_div
.setAttribute('style', 'display:none');
2066 this.settings_div
.setAttribute('class', 'settingsMain');
2067 this.settings_div
.setAttribute('id', 'settingsWindow');
2068 this.settings_div
.setAttribute('style', 'display:none;width:500px');
2069 this.close_link
.setAttribute('href', 'javascript:void(0)');
2070 this.close_div
.setAttribute('class', 'closeIcon');
2071 this.close_div
.addEventListener('click', function (evt
) { return _this
.hideWindow(); });
2072 this.title_para
.setAttribute('class', 'titleStyle');
2073 this.contents_div
.setAttribute('class', 'contentStyle');
2074 this.end_para
.setAttribute('class', 'footerStyle');
2075 this.ul_selection_start
.setAttribute("ID", "selection_list");
2076 this.generateList(this.contents_div
);
2078 SettingsWindow
.prototype.generateList = function (head_node
) {
2080 this.list_items
.forEach(function (list_item
, index
) {
2081 var li
= document
.createElement('LI');
2082 li
.setAttribute('class', 'settingsItem');
2083 if (list_item
.Text
.indexOf('View') > -1) {
2084 var input
= document
.createElement('INPUT');
2085 var input_id
= 'check-settings' + index
;
2086 input
.setAttribute('TYPE', 'checkbox');
2087 input
.setAttribute('ID', 'check-settings' + index
);
2088 li
.appendChild(input
);
2089 input
.addEventListener('click', function (evt
) { return _this
.storeActiveToggles(); });
2090 var a
= document
.createElement('A');
2091 a
.setAttribute('href', 'javascript:void(0)');
2092 a
.textContent
= list_item
.Text
;
2093 var a_id
= 'tab-settings' + index
;
2094 a
.setAttribute('ID', 'tab-settings' + index
);
2095 var setup_func = function (_a_id
) {
2096 a
.addEventListener('click', function (evt
) { return list_item
.ListenerFunc(_a_id
); });
2098 _this
.ul_selection_start
.appendChild(li
);
2103 var input
= document
.createElement('INPUT');
2104 var input_id
= 'check-settings' + index
;
2105 input
.setAttribute('TYPE', 'checkbox');
2106 input
.setAttribute('ID', 'check-settings' + index
);
2107 input
.addEventListener('click', function (evt
) { return _this
.storeActiveToggles(); });
2108 var label
= document
.createElement('LABEL');
2109 label
.appendChild(input
);
2110 var label_text
= document
.createTextNode(list_item
.Text
);
2111 label
.appendChild(label_text
);
2112 li
.appendChild(label
);
2113 _this
.ul_selection_start
.appendChild(li
);
2114 input
.checked
= _this
.setting_items
.password_settings
== 'true';
2115 var setup_func = function (input_id
) {
2116 label
.addEventListener('click', function (evt
) { return list_item
.ListenerFunc(input_id
); });
2118 setup_func(input_id
);
2122 SettingsWindow
.prototype.activate = function () {
2124 document
.body
.appendChild(this.settings_style
);
2125 this.background_div
.addEventListener('click', function (evt
) { return _this
.hideWindow(); });
2126 document
.body
.appendChild(this.background_div
);
2127 this.settings_div
.appendChild(this.close_link
);
2128 this.close_link
.appendChild(this.close_div
);
2129 this.title_para
.appendChild(this.title_text
);
2130 this.settings_div
.appendChild(this.title_para
);
2131 this.settings_div
.appendChild(this.contents_div
);
2132 this.contents_div
.appendChild(this.ul_selection_start
);
2133 this.end_para
.appendChild(this.end_text
);
2134 this.settings_div
.appendChild(this.end_para
);
2135 document
.body
.appendChild(this.settings_div
);
2136 this.retrieveActiveToggles();
2138 SettingsWindow
.prototype.decideAction = function (node
) { };
2139 SettingsWindow
.prototype.getSettingsArr = function () {
2140 return this.setting_items
;
2142 SettingsWindow
.prototype.displayWindow = function () {
2143 this.background_div
.style
.display
= 'block';
2144 this.settings_div
.style
.display
= 'block';
2145 this.rebuildContainer();
2147 SettingsWindow
.prototype.hideWindow = function () {
2148 this.background_div
.style
.display
= 'none';
2149 this.settings_div
.style
.display
= 'none';
2150 this.clearContainer();
2152 SettingsWindow
.prototype.filterWindow = function (disposable_container
) {
2154 var filter_table
= document
.createElement("table");
2155 filter_table
.setAttribute("style", "text-align:center;");
2156 filter_table
.setAttribute("id", "filter_table");
2157 disposable_container
.appendChild(filter_table
);
2158 var top_row
= document
.createElement("TR");
2159 filter_table
.appendChild(top_row
);
2160 var table_head_active
= document
.createElement("th");
2161 top_row
.appendChild(table_head_active
);
2162 var head_text_active
= document
.createTextNode("Active");
2163 table_head_active
.appendChild(head_text_active
);
2164 var table_head_pattern
= document
.createElement("th");
2165 top_row
.appendChild(table_head_pattern
);
2166 var headTextPattern
= document
.createTextNode("Pattern");
2167 table_head_pattern
.appendChild(headTextPattern
);
2168 var table_head_replacement
= document
.createElement("th");
2169 top_row
.appendChild(table_head_replacement
);
2170 var head_text_replacement
= document
.createTextNode("Replacement");
2171 table_head_replacement
.appendChild(head_text_replacement
);
2172 //Create the pattern table
2173 //loop to create rows
2174 var Number_of_Filters
= parseInt(this.setting_items
.word_replace_settings
.Number_of_Filters
);
2175 console
.log(Number_of_Filters
);
2176 if (Number_of_Filters
=== 0 || isNaN(Number_of_Filters
))
2177 Number_of_Filters
= 6;
2178 for (var i
= 0; i
< Number_of_Filters
; i
++) {
2179 var table_row_contents
= document
.createElement("tr");
2180 table_row_contents
.setAttribute("id", "FilterRow" + i
);
2181 var table_data_active
= document
.createElement("td");
2182 var table_checkbox_active
= document
.createElement("input");
2183 table_checkbox_active
.setAttribute("type", "checkbox");
2184 table_checkbox_active
.setAttribute("id", "Active" + i
);
2185 table_data_active
.appendChild(table_checkbox_active
);
2186 table_row_contents
.appendChild(table_data_active
);
2187 var table_data_pattern
= document
.createElement("td");
2188 var table_input_pattern
= document
.createElement("input");
2189 table_input_pattern
.setAttribute("class", "inputs");
2190 table_input_pattern
.setAttribute("id", "Pattern" + i
);
2191 table_data_pattern
.appendChild(table_input_pattern
);
2192 table_row_contents
.appendChild(table_data_pattern
);
2193 var table_data_replacement
= document
.createElement("td");
2194 var table_input_replacement
= document
.createElement("input");
2195 table_input_replacement
.setAttribute("class", "inputs");
2196 table_input_replacement
.setAttribute("id", "Replacement" + i
);
2197 table_data_replacement
.appendChild(table_input_replacement
);
2198 table_row_contents
.appendChild(table_data_replacement
);
2199 filter_table
.appendChild(table_row_contents
);
2201 var table_last_contents
= document
.createElement("tr");
2202 var table_add_collumn
= document
.createElement("td");
2203 var table_add_row_button
= document
.createElement("input");
2204 var table_subtract_row_button
= document
.createElement("input");
2205 table_subtract_row_button
.setAttribute("type", "button");
2206 table_subtract_row_button
.setAttribute("value", "-");
2207 table_subtract_row_button
.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2208 table_add_collumn
.appendChild(table_subtract_row_button
);
2209 table_subtract_row_button
.addEventListener("click", function (evt
) { return _this
.filterRemoveRow(); });
2210 table_add_row_button
.setAttribute("type", "button");
2211 table_add_row_button
.setAttribute("value", "+");
2212 table_add_row_button
.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2213 table_add_collumn
.appendChild(table_add_row_button
);
2214 table_add_row_button
.addEventListener("click", function (evt
) { return _this
.filterAddRow(); });
2215 table_last_contents
.appendChild(table_add_collumn
);
2216 var table_set_collumn
= document
.createElement("td");
2217 var table_confirm_button
= document
.createElement("input");
2218 table_confirm_button
.setAttribute("type", "button");
2219 table_confirm_button
.setAttribute("id", "table_confirm_button");
2220 table_confirm_button
.setAttribute("value", "Set Replacements");
2221 table_confirm_button
.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2223 table_confirm_button
.addEventListener("click", function (evt
) {
2224 _this
.storeStates();
2225 _this
.clearContainer();
2226 _this
.rebuildContainer();
2228 table_set_collumn
.appendChild(table_confirm_button
);
2229 table_last_contents
.appendChild(table_set_collumn
);
2230 var table_close_collumn
= document
.createElement("td");
2231 var table_close_button
= document
.createElement("input");
2232 table_close_button
.setAttribute("type", "button");
2233 table_close_button
.setAttribute("value", "Close Without Saving");
2234 table_close_button
.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2235 table_close_button
.addEventListener("click", function (evt
) {
2236 _this
.clearContainer();
2237 _this
.rebuildContainer();
2239 table_close_collumn
.appendChild(table_close_button
);
2240 table_last_contents
.appendChild(table_close_collumn
);
2241 filter_table
.appendChild(table_last_contents
);
2243 SettingsWindow
.prototype.filterAddRow = function () {
2245 var filter_table
= document
.getElementById("filter_table");
2246 var Number_of_Filters
= 0;
2247 var filter_children
= document
.getElementById("filter_table").firstChild
;
2248 while (filter_children
.nextSibling
) {
2249 filter_children
= filter_children
.nextSibling
;
2250 Number_of_Filters
++;
2252 var table_row_contents
= document
.createElement("tr");
2253 table_row_contents
.setAttribute("id", "FilterRow" + (Number_of_Filters
- 1));
2254 filter_table
.removeChild(filter_children
);
2255 var table_data_active
= document
.createElement("td");
2256 var table_checkbox_active
= document
.createElement("input");
2257 table_checkbox_active
.setAttribute("type", "checkbox");
2258 table_checkbox_active
.setAttribute("id", "Active" + (Number_of_Filters
- 1));
2259 table_data_active
.appendChild(table_checkbox_active
);
2260 table_row_contents
.appendChild(table_data_active
);
2261 var table_data_pattern
= document
.createElement("td");
2262 var table_input_pattern
= document
.createElement("input");
2263 table_input_pattern
.setAttribute("class", "inputs");
2264 table_input_pattern
.setAttribute("id", "Pattern" + (Number_of_Filters
- 1));
2265 table_data_pattern
.appendChild(table_input_pattern
);
2266 table_row_contents
.appendChild(table_data_pattern
);
2267 var table_data_replacement
= document
.createElement("td");
2268 var table_input_replacement
= document
.createElement("input");
2269 table_input_replacement
.setAttribute("class", "inputs");
2270 table_input_replacement
.setAttribute("id", "Replacement" + (Number_of_Filters
- 1));
2271 table_data_replacement
.appendChild(table_input_replacement
);
2272 table_row_contents
.appendChild(table_data_replacement
);
2273 filter_table
.appendChild(table_row_contents
);
2274 var table_last_contents
= document
.createElement("tr");
2275 var table_add_collumn
= document
.createElement("td");
2276 var table_add_row_button
= document
.createElement("input");
2277 var table_subtract_row_button
= document
.createElement("input");
2278 table_subtract_row_button
.setAttribute("type", "button");
2279 table_subtract_row_button
.setAttribute("value", "-");
2280 table_subtract_row_button
.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2281 table_add_collumn
.appendChild(table_subtract_row_button
);
2282 table_subtract_row_button
.addEventListener("click", function (evt
) { return _this
.filterRemoveRow(); });
2283 table_add_row_button
.setAttribute("type", "button");
2284 table_add_row_button
.setAttribute("value", "+");
2285 table_add_row_button
.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2286 table_add_collumn
.appendChild(table_add_row_button
);
2287 table_add_row_button
.addEventListener("click", function (evt
) { return _this
.filterAddRow(); });
2288 table_last_contents
.appendChild(table_add_collumn
);
2289 var table_set_collumn
= document
.createElement("td");
2290 var table_confirm_button
= document
.createElement("input");
2291 table_confirm_button
.setAttribute("type", "button");
2292 table_confirm_button
.setAttribute("id", "table_confirm_button");
2293 table_confirm_button
.setAttribute("value", "Set Replacements");
2294 table_confirm_button
.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2296 table_confirm_button
.addEventListener("click", function (evt
) {
2297 _this
.storeStates();
2298 _this
.clearContainer();
2299 _this
.rebuildContainer();
2301 table_set_collumn
.appendChild(table_confirm_button
);
2302 table_last_contents
.appendChild(table_set_collumn
);
2303 var table_close_collumn
= document
.createElement("td");
2304 var table_close_button
= document
.createElement("input");
2305 table_close_button
.setAttribute("type", "button");
2306 table_close_button
.setAttribute("value", "Close Without Saving");
2307 table_close_button
.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2308 table_close_button
.addEventListener("click", function (evt
) {
2309 _this
.clearContainer();
2310 _this
.rebuildContainer();
2312 table_close_collumn
.appendChild(table_close_button
);
2313 table_last_contents
.appendChild(table_close_collumn
);
2314 filter_table
.appendChild(table_last_contents
);
2316 SettingsWindow
.prototype.filterRemoveRow = function () {
2317 var filter_table
= document
.getElementById("filter_table");
2318 var Number_of_Filters
= 0;
2319 var filter_children
= document
.getElementById("filter_table").firstChild
;
2320 while (filter_children
.nextSibling
) {
2321 filter_children
= filter_children
.nextSibling
;
2322 Number_of_Filters
++;
2324 if (Number_of_Filters
!= 2) {
2325 filter_table
.deleteRow(--Number_of_Filters
);
2328 SettingsWindow
.prototype.filterSetTable = function () {
2329 var filter_length
= this.setting_items
.word_replace_settings
.Number_of_Filters
;
2330 for (var filter_count
= 0; filter_count
< filter_length
; filter_count
++) {
2331 if (this.setting_items
.word_replace_settings
.Text_Filter_List
[filter_count
].Active
=== null ||
2332 this.setting_items
.word_replace_settings
.Text_Filter_List
[filter_count
].Regex
=== null ||
2333 this.setting_items
.word_replace_settings
.Text_Filter_List
[filter_count
].Replacement
=== null)
2335 if (this.setting_items
.word_replace_settings
.Text_Filter_List
[filter_count
].Active
=== "true") {
2336 document
.getElementById("Active" + filter_count
).checked
= true;
2339 document
.getElementById("Active" + filter_count
).checked
= false;
2341 document
.getElementById("Pattern" + filter_count
).value
=
2342 this.setting_items
.word_replace_settings
.Text_Filter_List
[filter_count
].Regex
;
2343 document
.getElementById("Replacement" + filter_count
).value
=
2344 this.setting_items
.word_replace_settings
.Text_Filter_List
[filter_count
].Replacement
;
2347 return SettingsWindow
;
2348 }(FeatureInterface
));
2349 var Main
= /** @class */ (function (_super
) {
2350 __extends(Main
, _super
);
2352 var _this
= _super
.call(this) || this;
2353 _this
.features
= {}; /*;any bypasses dot notation issues on objects*/
2354 _this
.settings
= {};
2355 if (!Generics
.storageAvailable('localStorage')) {
2356 alert("4F-FSE: local storage error");
2361 _this
.retrieveStates();
2363 _this
.decideAction(document
.getElementById('delform'));
2364 _this
.observeEvents();
2367 Main
.prototype.retrieveStates = function () {
2368 var top_bar
= new TopBar();
2370 this.settings
= top_bar
.getSettingsArr();
2372 Main
.prototype.init = function () {
2373 if (this.settings
.image_hiding_settings
.Active
=== "true") {
2374 this.features
.image_hider
= new ImageHider();
2376 if (this.settings
.word_replace_settings
.Active
=== "true") {
2377 this.features
.text_replacer
= new TextReplacer();
2379 if (this.settings
.image_adder_settings
.Active
=== "true") {
2380 this.features
.danbooru_image_adder
= new DanbooruImageAdder();
2382 if (this.settings
.thread_rebuild_settings
.Active
=== "true") {
2383 this.features
.thread_rebuilder
= new ThreadRebuilder();
2385 if (this.settings
.character_inserter_settings
.Yen_Active
=== "true" || this.settings
.character_inserter_settings
.Kita_Active
=== "true") {
2386 this.features
.character_inserter
= new CharacterInserter(this.settings
.character_inserter_settings
.Yen_Active
=== "true", this.settings
.character_inserter_settings
.Kita_Active
=== "true");
2388 if (this.settings
.password_settings
== 'true') {
2389 this.features
.password_viewer
= new PasswordViewer();
2391 for (var feature_key
in this.features
)
2392 this.features
[feature_key
].retrieveStates();
2394 Main
.prototype.activate = function () { console
.log("4F-FSE Starting"); };
2395 Main
.prototype.storeStates = function () { };
2396 Main
.prototype.observeEvents = function () {
2398 var document_changes
= new MutationObserver(function (mutations
) {
2399 mutations
.forEach(function (mutation
) {
2400 [].forEach
.call(mutation
.addedNodes
, function (node
) { return _this
.decideAction(node
); });
2402 }).observe(document
.body
, { childList
: true, subtree
: true });
2404 Main
.prototype.decideAction = function (node
) {
2405 if (node
== undefined || node
.tagName
== undefined)
2408 var itterator
= document
.createNodeIterator(start
, NodeFilter
.SHOW_ELEMENT
);
2410 while ((node
= itterator
.nextNode())) {
2411 if (node
.tagName
!== "BLOCKQUOTE" && node
.tagName
!== "IMG" && node
.tagName
!== "VIDEO")
2413 for (var feature_key
in this.features
) {
2414 this.features
[feature_key
].decideAction(node
);
2419 }(FeatureInterface
));
2420 document
.addEventListener('4chanXInitFinished', function () { new Main(); });