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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";
79 //unassociated functions
80 var Generics = /** @class */ (function () {
83 Generics.storageAvailable = function (storage_type) {
85 var storage = window[storage_type];
86 storage.setItem('x', 'x');
87 storage.removeItem('x');
95 Generics.detectBrowser = function () {
96 if ((navigator.userAgent.indexOf('Opera') || navigator.userAgent.indexOf('OPR')) != -1) {
100 else if (navigator.userAgent.indexOf('Chrome') != -1) {
101 console.log('Chrome');
104 else if (navigator.userAgent.indexOf('Safari') != -1) {
105 console.log('Safari');
108 else if (navigator.userAgent.indexOf('Firefox') != -1) {
109 console.log('FireFox');
112 else if (navigator.userAgent.indexOf('MSIE') != -1) {
117 console.log('Other');
121 //gets json keys by regex test
122 Generics.getJSONPropertiesByKeyName = function (JSON_obj, regex_string) {
123 var regex = new RegExp("^" + regex_string + "$");
124 var rtnArray = Array();
125 for (var key in JSON_obj)
130 //send alert to 4chanx
131 Generics.alert4ChanX = function (message, type, time) {
132 var detail = { type: type, content: message, lifetime: time };
133 var event = new CustomEvent('CreateNotification', { bubbles: true, detail: detail });
134 document.dispatchEvent(event);
136 Generics.getJSON = function (url, callback, extra) {
138 for (var _i = 3; _i < arguments.length; _i++) {
139 all_extra[_i - 3] = arguments[_i];
141 var xhr = new XMLHttpRequest();
142 xhr.open('GET', url, true);
143 xhr.responseType = 'json';
144 xhr.onload = function () {
145 var status = xhr.status;
147 callback.apply(void 0, [null, xhr.response, extra].concat(all_extra));
157 var FeatureInterface = /** @class */ (function () {
158 function FeatureInterface() {
160 return FeatureInterface;
162 var TopBar = /** @class */ (function () {
164 this.shortcuts_container = document.getElementById("shortcuts");
165 this.shortcuts_menu = document.getElementById("shortcut-menu");
166 this.fse_icon_container = document.createElement("SPAN");
167 this.fse_icon_node = document.createElement("A");
168 this.fse_style_node = document.createElement("STYLE");
169 this.fa_fse_style = ".fa_jpy::before{content:'\f157'}";
170 this.fse_style_node.innerHTML = this.fa_fse_style;
171 this.fse_icon_container.setAttribute("class", "shortcut brackets-wrap");
172 this.fse_icon_node.setAttribute("class", "fa fa-jpy");
173 this.fse_icon_node.setAttribute("href", "javascript:void(0);");
174 this.fse_icon_node.setAttribute("title", "4F-FSE Settings");
175 this.fse_icon_node.textContent = "4F-FSE Settings";
176 this.settings_window = new SettingsWindow();
178 TopBar.prototype.build = function () {
180 document.head.appendChild(this.fse_style_node);
181 this.fse_icon_container.appendChild(this.fse_icon_node);
182 this.shortcuts_container.insertBefore(this.fse_icon_container, this.shortcuts_menu);
183 //https://stackoverflow.com/questions/44606399/typescript-how-to-access-the-class-instance-from-event-handler-method
184 this.fse_icon_node.addEventListener("click", function (evt) { return _this.open4FSettings(_this.settings_window); });
186 TopBar.prototype.open4FSettings = function (settings_window) {
187 settings_window.displayWindow();
189 TopBar.prototype.getSettingsArr = function () {
190 return this.settings_window.getSettingsArr();
194 var ImageHider = /** @class */ (function (_super) {
195 __extends(ImageHider, _super);
196 function ImageHider() {
197 var _this = _super.call(this) || this;
198 _this.blank_png = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAACXBIWXMAALiMAAC4jAHM9rsvAAAAG3RFWHRTb2Z0d2FyZQBDZWxzeXMgU3R1ZGlvIFRvb2zBp+F8AAAAo0lEQVR42u3RAQ0AAAjDMO5f9LFBSCdhTdvRnQIEiIAAERAgAgJEQIC4AERAgAgIEAEBIiBABERAgAgIEAEBIiBABERAgAgIEAEBIiBABERAgAgIEAEBIiBABERAgAgIEAEBIiBABERAgAgIEAEBIiBABERAgAgIEAEBIiBABERAgAgIEAEBIiBABERAgAgIEAEBIiBABAQIECACAkRAgAjI9xbzUCtI4axs4wAAAABJRU5ErkJggg==";
199 _this.retrieveStates();
204 //retrieve from memory the hidden images
205 //Images are stored in memory as f<ID_NUMBER>IMG and recalled using the storage_key
206 //Function makes a check to see if the hiding time limit for the thread has expired or not.
207 //Note: Must have the DOM itterate through before retrieval
208 ImageHider.prototype.retrieveStates = function () {
210 var storage_position = 0;
211 var JSON_storage = {}; /*;any bypasses dot notation issues on objects*/
213 var local_store_size = window.localStorage.length;
214 while (storage_position < local_store_size) {
215 storage_key = window.localStorage.key(storage_position);
216 JSON_storage[storage_key] = window.localStorage.getItem(storage_key);
219 this.threads_to_hide = Generics.getJSONPropertiesByKeyName(JSON_storage, '[0-9]+IMG');
220 //aquire each time to check for changes
221 this.hide_expiration_time = parseInt(JSON_storage.Expiration_Time);
222 if (this.hide_expiration_time === null)
223 this.hide_expiration_time = Constants.DEFAULT_HIDE_EXPIRATION_TIME;
224 var md5_filters = JSON_storage.MD5_List_FSE;
225 if (md5_filters !== undefined && md5_filters !== null) {
226 this.md5_filters_arr = md5_filters.split('\n');
227 //remove trailing and starting slash
228 this.md5_filters_arr.forEach(function (md5, index) {
230 _this.md5_filters_arr[index] = md5.substring(1, md5.length - 1);
234 ImageHider.prototype.storeStates = function () {
236 for (var _i = 0; _i < arguments.length; _i++) {
237 item_pairs[_i] = arguments[_i];
239 window.localStorage.setItem(item_pairs[0], item_pairs[1]);
241 ImageHider.prototype.init = function () { };
242 //hide image onclick listener.
243 //Method 404's a given image. This 404'ing allows image dissabling to be toggled on and off.
244 //Post number associated with the image is stored in local storage.
245 ImageHider.prototype.hideOnClick = function (event) {
247 var is_hidden = event.target.src.substring(21, 29) == ",iVBORw0";
249 if ((event.ctrlKey && event.shiftKey) && !is_hidden) {
250 event.preventDefault();
251 event.stopPropagation();
252 hide_group_id = event.target.getAttribute('hide-grouping');
253 this.storeStates(hide_group_id, "" + Date.now());
254 [].slice.call(document.querySelectorAll('img[hide-grouping="' + hide_group_id + '"]')).forEach(function (image_node) {
255 image_node.setAttribute('hidden-src', image_node.src);
256 image_node.src = _this.blank_png;
259 else if (event.ctrlKey && event.shiftKey) {
260 event.preventDefault();
261 event.stopPropagation();
262 hide_group_id = event.target.getAttribute('hide-grouping');
263 window.localStorage.removeItem(hide_group_id);
264 event.target.src = event.target.getAttribute('hidden-src');
265 [].slice.call(document.querySelectorAll('img[hide-grouping="' + hide_group_id + '"]')).forEach(function (image_node) {
266 image_node.src = image_node.getAttribute('hidden-src');
269 this.retrieveStates();
272 ImageHider.prototype.decideAction = function (node) {
273 //tagname is always upper in HTML, in xml it's displayed as written.
274 if (node.tagName === 'IMG') {
275 if (node.id === "ihover") {
276 this.hideHoverImageNode(node);
279 if (!/\d+IMG/.test(node.getAttribute('hide-grouping')) && (node.getAttribute('data-md5') !== null)) {
280 this.hideImageNode(node);
285 ImageHider.prototype.activate = function () {
286 // new MutationObserver((mutations) => {
287 // this.retrieveStates();
289 // }).observe(document.getElementById('hoverUI'), {childList: true});
290 console.log("4F-FSE: ImageHider Active");
292 ImageHider.prototype.hideImageNode = function (image_node) {
294 var sister_node = image_node.parentNode.parentNode.parentNode.getElementsByClassName('catalog-thumb')[0]; // the catalog sister to index
295 if (sister_node === undefined)
296 sister_node = document.createElement('IMG');
297 image_node.setAttribute('hide-grouping', image_node.parentNode.parentNode.id.substring(1) + 'IMG');
298 sister_node.setAttribute('hide-grouping', image_node.parentNode.parentNode.id.substring(1) + 'IMG');
299 image_node.addEventListener('click', function (evt) { return _this.hideOnClick(evt); });
300 sister_node.addEventListener('click', function (evt) { return _this.hideOnClick(evt); });
301 var threadstore_len = this.threads_to_hide.length;
302 var node_group_id = image_node.getAttribute('hide-grouping');
303 for (var thread = 0; thread < threadstore_len; thread++) {
304 if (node_group_id == this.threads_to_hide[thread]) {
305 image_node.setAttribute('hidden-src', image_node.src);
306 image_node.src = this.blank_png;
307 sister_node.setAttribute('hidden-src', sister_node.src);
308 sister_node.src = this.blank_png;
312 //index node holds the MD5
313 var node_md5 = image_node.getAttribute('data-md5');
314 if (this.md5_filters_arr !== undefined) {
315 var md5_filters_arr_len = this.md5_filters_arr.length;
316 for (var md5 = 0; md5 < md5_filters_arr_len; md5++) {
317 if (node_md5 == this.md5_filters_arr[md5]) {
318 this.threads_to_hide.push();
319 image_node.setAttribute('hidden-src', image_node.src);
320 image_node.src = this.blank_png;
321 sister_node.setAttribute('hidden-src', sister_node.src);
322 sister_node.src = this.blank_png;
328 ImageHider.prototype.hideHoverImageNode = function (image_node) {
330 // if(image_node.tagName == 'DIV') {
331 // is_embeded_post = true;
332 // image_node = image_node.getElementsByClassName('postContainer')[0];
333 // if(image_node === undefined) return;
335 var unprocessed_id = image_node.getAttribute('data-full-i-d');
336 // if (unprocessed_id === null) return;
337 var proccessed_id = unprocessed_id.substring(unprocessed_id.indexOf('.') + 1);
338 var image_node_id = proccessed_id + 'IMG';
339 // if(is_embeded_post) image_node = image_node.getElementsByTagName('IMG')[0];
340 if (image_node === undefined)
342 for (var thread = 0, threadstore_len = this.threads_to_hide.length; thread < threadstore_len; thread++) {
343 if (image_node_id == this.threads_to_hide[thread]) {
344 image_node.removeAttribute('src');
348 //thread node holds the MD5
350 // if(is_embeded_post) node_md5 = image_node.getAttribute('data-md5');
351 /*else */ node_md5 = document.getElementById('f' + proccessed_id).getElementsByTagName('IMG')[0].getAttribute('data-md5');
352 if (this.md5_filters_arr !== undefined) {
353 for (var md5 = 0, md5_filters_arr_len = this.md5_filters_arr.length; md5 < md5_filters_arr_len; md5++) {
354 if (node_md5 == this.md5_filters_arr[md5]) {
355 image_node.removeAttribute('src');
362 }(FeatureInterface));
363 var TextReplacer = /** @class */ (function (_super) {
364 __extends(TextReplacer, _super);
365 function TextReplacer() {
366 var _this = _super.call(this) || this;
367 _this.text_filters = []; //object
368 _this.filtered_threads = [];
369 _this.retrieveStates();
374 TextReplacer.prototype.init = function () {
375 this.filtered_threads = [];
378 TextReplacer.prototype.activate = function () { console.log("4F-FSE: TextReplacer Active"); };
379 TextReplacer.prototype.decideAction = function (node) {
380 if (node.tagName == "BLOCKQUOTE") {
381 if (node.className == "postMessage") {
382 var blockquote_id = node.id;
383 var already_filtered = false;
384 this.filtered_threads.forEach(function (thread_id) {
385 if (thread_id == blockquote_id) {
386 already_filtered = true;
393 if (!already_filtered && this.text_filters.length !== 0) {
394 var itterator = document.createNodeIterator(node, NodeFilter.SHOW_TEXT);
396 while ((localNode = itterator.nextNode())) {
397 for (var filter = 0; filter < this.number_of_filters; filter++) {
398 if (this.text_filters[filter].Active === "true") {
399 var last_slash_index = this.text_filters[filter].Regex.lastIndexOf("/");
400 var filter_text = this.text_filters[filter].Regex.substring(1, last_slash_index);
401 var flag = this.text_filters[filter].Regex.substring(last_slash_index + 1);
402 var regex = new RegExp(filter_text, flag);
403 var node_text = localNode.textContent;
404 if (regex.test(node_text)) {
405 localNode.textContent = node_text.replace(regex, this.text_filters[filter].Replacement);
406 this.filtered_threads.push(blockquote_id);
414 TextReplacer.prototype.retrieveStates = function () {
416 var storage_index = 0;
417 var JSON_storage = {};
419 while (storage_index < window.localStorage.length) {
420 storage_key = window.localStorage.key(storage_index);
421 JSON_storage[storage_key] = window.localStorage.getItem(storage_key);
424 this.number_of_filters = JSON_storage["filter_quantity"];
425 var filters = Generics.getJSONPropertiesByKeyName(JSON_storage, "[0-9]+FLT");
427 filters.forEach(function (filter) {
428 _this.text_filters.push(TextReplacer.formatFilterSettings(JSON_storage[filter]));
431 //Splits the saved settings into components
432 TextReplacer.formatFilterSettings = function (input) {
433 var processed_input = (input.split('=')).map(function (x) { return decodeURIComponent(x); });
434 return { Active: processed_input[0], Regex: processed_input[1], Replacement: processed_input[2] };
436 TextReplacer.prototype.storeStates = function () { };
438 }(FeatureInterface));
439 var DanbooruImageAdder = /** @class */ (function (_super) {
440 __extends(DanbooruImageAdder, _super);
441 function DanbooruImageAdder() {
442 var _this = _super.call(this) || this;
443 _this.timeout_functions = [];
445 _this.post_number = 0;
446 _this.page_number = 0;
447 _this.json_post_numbers_used = [];
448 _this.previous_images = [];
449 _this.json_numbers_used = [];
450 _this.subdomain_regex = new RegExp("(raikou|hijiribe)\d*\.");
451 _this.maximum_attempts = 20;
457 DanbooruImageAdder.prototype.init = function () {
459 this.time = this.time_max;
460 this.number_of_attempts = this.maximum_attempts;
461 document.addEventListener("QRDialogCreation", function (evt) {
462 _this.enhance4ChanX_HTML();
463 _this.enhanced4ChanXListeners();
466 DanbooruImageAdder.prototype.enhance4ChanX_HTML = function () {
467 var qr_window = document.getElementById("qr");
468 /*Should I auto open things for the user?*/
469 // var imagedump_opener:any = document.getElementById("dump-button");
470 // if(imagedump_opener !== null){imagedump_opener.click();}
472 //image setting html elements.
473 var qr_image_adder_table = document.createElement("TABLE");
474 qr_image_adder_table.setAttribute("id", "qrImages");
475 qr_image_adder_table.setAttribute("style", "text-align:center");
476 qr_window.appendChild(qr_image_adder_table);
477 var options_row = document.createElement("TR");
478 options_row.setAttribute("ID", "or");
479 options_row.setAttribute("style", "margin:5px;");
480 qr_image_adder_table.appendChild(options_row);
481 var checkbox_safe = document.createElement("INPUT");
482 checkbox_safe.setAttribute("id", "safe");
483 checkbox_safe.setAttribute("type", "checkbox");
484 var checkbox_safe_text = document.createTextNode("Safe");
485 var checkbox_questionable = document.createElement("INPUT");
486 checkbox_questionable.setAttribute("id", "questionable");
487 checkbox_questionable.setAttribute("type", "checkbox");
488 var checkbox_questionable_text = document.createTextNode("Questionable");
489 var checkbox_explicit = document.createElement("INPUT");
490 checkbox_explicit.setAttribute("id", "explicit");
491 checkbox_explicit.setAttribute("type", "checkbox");
492 var checkbox_explicit_text = document.createTextNode("Explicit");
493 options_row.appendChild(checkbox_safe_text);
494 options_row.appendChild(checkbox_safe);
495 options_row.appendChild(checkbox_questionable_text);
496 options_row.appendChild(checkbox_questionable);
497 options_row.appendChild(checkbox_explicit_text);
498 options_row.appendChild(checkbox_explicit);
499 var image_tagging_row = document.createElement("TR");
500 this.help_icon_container = document.createElement("A");
501 this.help_icon_container.href = "javascript:void(0)";
502 this.help_icon_container.title = "Click to View Help!";
503 var help_icon = document.createElement("IMG");
504 help_icon.setAttribute("class", "help_icon");
505 help_icon.src = Constants.HELP_ICON_SOURCE;
506 this.help_icon_container.appendChild(help_icon);
507 image_tagging_row.appendChild(this.help_icon_container);
508 var tooltip_div = document.createElement("DIV");
509 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>";
510 (tooltip_div).setAttribute("class", "tooltip-4F");
511 (tooltip_div).setAttribute("id", "tooltipIA");
512 qr_window.appendChild(tooltip_div);
513 var second_row_nodes = [
514 document.createTextNode("Tags: "),
515 document.createElement("INPUT"),
516 document.createElement("INPUT"),
517 document.createElement("A"),
518 document.createElement("INPUT"),
520 second_row_nodes.forEach(function (node) {
521 image_tagging_row.appendChild(node);
523 qr_image_adder_table.appendChild(image_tagging_row);
524 var auto_complete_row = document.createElement("TR");
525 auto_complete_row.setAttribute("ID", "auto-complete-row");
526 auto_complete_row.setAttribute("style", "margin:5px;");
527 qr_image_adder_table.appendChild(auto_complete_row);
528 second_row_nodes[1].setAttribute("ID", "tag_input");
529 var option_text_size = 18;
530 second_row_nodes[1].setAttribute("style", "width:44.9%;" + "font-size:" + option_text_size + "px");
531 second_row_nodes[3].setAttribute("ID", "timer");
532 second_row_nodes[3].setAttribute("style", "width:20%;margin:0 5px");
533 second_row_nodes[4].setAttribute("ID", "urlContainer");
534 second_row_nodes[4].setAttribute("style", "width:75%;margin:5px -25px");
535 second_row_nodes[4].setAttribute("disabled", "");
536 second_row_nodes[2].setAttribute("ID", "imageButton");
537 second_row_nodes[2].setAttribute("type", "button");
538 second_row_nodes[2].setAttribute("value", "Set Image");
539 //textarea expansion;
540 qr_window.getElementsByTagName("TEXTAREA")[0].style.width = "110%";
541 qr_window.appendChild(document.createElement("hr"));
543 DanbooruImageAdder.prototype.enhanced4ChanXListeners = function () {
545 this.highQualityImages();
546 document.getElementById("qr-filerm").addEventListener("click", function (evt) { return _this.clearImage(); });
547 var qr_reference = document.getElementById("qr");
548 var tooltip_div = document.getElementById("tooltipIA");
549 this.help_icon_container.addEventListener("click", function (evt) {
550 if (_this.tool_tip_visible)
551 tooltip_div.setAttribute("style", "z-index:9;padding:5px;border:1px solid black;background-color:white;word-wrap:break-word;display:none;position:absolute;");
553 tooltip_div.setAttribute("style", "z-index:9;padding:5px;border:1px solid black;background-color:white;word-wrap:break-word;display:block;position:absolute;"
554 + "left:" + (evt.clientX - qr_reference.getBoundingClientRect().x) +
555 "px;top:" + (evt.clientY - qr_reference.getBoundingClientRect().y) + "px;");
556 _this.tool_tip_visible = !_this.tool_tip_visible;
558 var tag_input = document.getElementById("tag_input");
559 tag_input.addEventListener("input", function (evt) {
560 _this.setTagInterface(tag_input, document.getElementById("auto-complete-row"));
562 document.getElementById("imageButton").addEventListener("click", function (evt) { return _this.activate(); });
564 DanbooruImageAdder.prototype.highQualityImages = function () {
566 var imagedump_file_list = document.getElementById("dump-list");
567 //used for setting and unsetting high resolution thumbs for dump list.
568 var dumplist_image = "";
569 var previous_dumplist_image = "";
570 var observer = new MutationObserver(function (mutate) {
571 dumplist_image = imagedump_file_list.firstChild.style.backgroundImage;
572 if (dumplist_image !== previous_dumplist_image && _this.img_URL !== "") {
573 imagedump_file_list.firstChild.style.backgroundImage = "url(" + _this.img_URL + ")";
574 previous_dumplist_image = imagedump_file_list.firstChild.style.backgroundImage;
576 else if (_this.img_URL == "") { }
578 observer.observe(imagedump_file_list, { attributes: true, subtree: true, childList: true, characterData: true });
580 DanbooruImageAdder.prototype.activate = function () {
582 //on setimage click clear flags, timers and start another search
583 this.json_post_numbers_used = Array();
584 //reset a failed_to_find_required_tags boolean
585 this.primed_for_fail = false;
586 for (var i = 0; i < this.timeout_functions.length; i++) {
587 clearInterval(this.timeout_functions[i]);
589 this.tag_incorrect_state = false;
590 this.timeout = false;
591 //freeze interface to prevent mid opperation changes
592 document.getElementById("tag_input").setAttribute("disabled", "1");
593 document.getElementById("imageButton").setAttribute("disabled", "1");
594 this.time = this.time_max;
595 this.timeout_functions.push(setInterval(function () { return _this.counterFunction(); }, 1000));
599 //remove the high quallity image from the dump list
600 DanbooruImageAdder.prototype.clearImage = function () {
601 var imagedump_file_list = document.getElementById("dump-list");
602 imagedump_file_list.firstChild.style.backgroundImage = "url()"; //trigger mutation event
603 this.img_URL = ""; //get mutation to set to dead
605 DanbooruImageAdder.prototype.setTagInterface = function (tag_input_node, auto_complete_row) {
606 var tags = tag_input_node.value;
607 if (this.old_tags_before_change !== tags) {
608 this.previous_images = [];
609 var tag_carat_position = tag_input_node.selectionStart - 1;
610 var closest_tag = (function () {
611 var current_chararcter = tags.charAt(tag_carat_position);
613 var right_most = tag_carat_position;
614 while (current_chararcter != " " && current_chararcter != "" && current_chararcter !== undefined) {
616 current_chararcter = tags.charAt(tag_carat_position + i);
617 if (current_chararcter != " " && current_chararcter != "")
618 right_most = tag_carat_position + i;
621 current_chararcter = tags.charAt(tag_carat_position);
623 var leftMost = tag_carat_position;
624 while (current_chararcter != " " && current_chararcter != "" && current_chararcter !== undefined) {
626 current_chararcter = tags.charAt(tag_carat_position - i);
627 if (current_chararcter != " " && current_chararcter != "")
628 leftMost = tag_carat_position - i;
630 return tags.substring(leftMost, right_most);
632 var xhr = new GM_xmlhttpRequest(({
634 url: "https://danbooru.donmai.us/tags.json?search[name_matches]=" + closest_tag + "*&search[order]=count",
635 responseType: "json",
636 onload: function (data) {
637 data = data.response;
638 var tagArray = tags.split(" ");
639 while (auto_complete_row.hasChildNodes()) {
640 auto_complete_row.removeChild(auto_complete_row.lastChild);
642 var qr_width = document.getElementById("qr").offsetWidth;
643 var tag_table = document.createElement("TABLE");
644 tag_table.setAttribute("style", "border:1px solid black;margin-top:5px");
645 var tag_row = document.createElement("TR");
646 for (var i = 0; i < 5; i++) {
647 var a = document.createElement("A");
648 var tagText = data["" + i];
649 if (tagText == "" || tagText === undefined)
651 tagText = tagText["name"];
652 var a_txt = document.createTextNode(data[i]["name"]);
653 var tag_data = document.createElement("TD");
654 tag_data.setAttribute("style", "padding:5px;font-size:15px;font-weight:bold;border:1px solid black;");
655 a.appendChild(a_txt);
656 tag_data.appendChild(a);
657 tag_row.appendChild(tag_data);
658 tag_table.appendChild(tag_row);
659 auto_complete_row.appendChild(tag_table);
660 if (tag_table.offsetWidth > qr_width - 10) {
661 tag_row.removeChild(tag_data);
662 tag_table = document.createElement("TABLE");
663 tag_row = document.createElement("TR");
664 tag_row.appendChild(tag_data);
665 tag_table.appendChild(tag_row);
666 tag_table.setAttribute("style", "border:1px solid black;");
667 auto_complete_row.appendChild(tag_table);
669 a.addEventListener("click", function (evt) {
670 tagArray[tagArray.indexOf(closest_tag)] = this.textContent;
671 document.getElementById("tag_input").value = tagArray.join(" ");
677 this.old_tags_before_change = tag_input_node.value;
679 //a series of calls on other functions that leads to the image being searched for
680 DanbooruImageAdder.prototype.setImage = function (this_) {
682 var tags = document.getElementById("tag_input").value.trim();
683 if (tags.indexOf(":") > -1) {
684 Generics.alert4ChanX("Character ':' not used for file characteristic searches", "warning");
686 var tags_arr = tags.split(" ");
687 var xhr_image_load = new GM_xmlhttpRequest(({
689 //returns a list of all tags and their properties
690 url: "https://danbooru.donmai.us/tags.json?search[name]=" + tags_arr.join() + "&search[order]=count",
691 responseType: "json",
692 onload: function (data) {
693 this_.json_tag = this_.verifyTags(data, tags_arr);
694 if (this_.failed_to_find_required_tags_state)
697 var end_URL = this_.ratingURL(this_.json_tag);
698 var URL = this_.setPostAndPage(end_URL);
699 this_.send_URL = URL;
700 //final check, sends final request after function or calls this function again
701 Generics.getJSON(URL, function (err, data, tags, _this_) { return this_.checkPageFromDanbooru(err, data, tags, _this_); }, tags_arr, this_);
705 //make 4chanX alerts on issues, and account for error cases.
706 DanbooruImageAdder.prototype.verifyTags = function (data, tags) {
707 data = data.response;
708 //if data is blank, use a no-tag approach
709 if (tags.length == 1 && tags[0] == "")
712 this.json_tag = data;
713 this.failed_to_find_required_tags_state = false;
714 //if data has a null or undefined case, return an error
715 if (data.length == 0) {
716 Generics.alert4ChanX("All tags incorrect", "error", 10);
717 this.failed_to_find_required_tags_state = true;
718 document.getElementById("timer").textContent = "";
719 document.getElementById("tag_input").removeAttribute("disabled");
720 document.getElementById("imageButton").removeAttribute("disabled");
721 return this.json_tag;
723 else if (data.length != tags.length && !this.tag_incorrect_state) {
724 this.tag_incorrect_state = true;
725 if (document.getElementById("tag_input").value.trim() == "")
726 Generics.alert4ChanX("No Tags", "info", 2);
728 Generics.alert4ChanX("One Tag Incorrect", "warning");
730 //tag size. Smallest tag is placed at bottom of JSON
731 this.smallest_tag_size = parseInt(data[data.length - 1]["post_count"]);
732 return this.json_tag;
734 //evaluate the rating restrictions to account for danbooru's tagging limitations
735 DanbooruImageAdder.prototype.ratingURL = function (tags) {
737 //evaluate the 3! possible permutations
738 if (document.getElementById("safe").checked) {
739 if (document.getElementById("questionable").checked) {
740 if (document.getElementById("explicit").checked) {
742 URL = "&utf8=%E2%9C%93&tags=" + tags[tags.length - 2]["name"] + "+" + tags[tags.length - 1]["name"];
744 URL = "&utf8=%E2%9C%93&tags=" + tags[tags.length - 1]["name"];
747 URL = "&utf8=%E2%9C%93&tags=" + "-rating%3Aexplicit" + "+" + tags[tags.length - 1]["name"];
750 else if (document.getElementById("explicit").checked) {
751 URL = "&utf8=%E2%9C%93&tags=" + "-rating%3Aquestionable" + "+" + tags[tags.length - 1]["name"];
754 URL = "&utf8=%E2%9C%93&tags=" + "rating%3Asafe" + "+" + tags[tags.length - 1]["name"];
757 else if (document.getElementById("questionable").checked) {
758 if (document.getElementById("explicit").checked) {
759 URL = "&utf8=%E2%9C%93&tags=" + "-rating%3Asafe" + "+" + tags[tags.length - 1]["name"];
762 URL = "&utf8=%E2%9C%93&tags=" + "rating%3Aquestionable" + "+" + tags[tags.length - 1]["name"];
765 else if (document.getElementById("explicit").checked) {
766 URL = "&utf8=%E2%9C%93&tags=" + "rating%3Aexplicit" + "+" + tags[tags.length - 1]["name"];
770 URL = "&utf8=%E2%9C%93&tags=" + tags[tags.length - 2]["name"] + "+" + tags[tags.length - 1]["name"];
772 URL = "&utf8=%E2%9C%93&tags=" + tags[tags.length - 1]["name"];
776 //set where to search
777 DanbooruImageAdder.prototype.setPostAndPage = function (end_URL) {
780 this.post_number = 0;
782 if (this.top_page != this.top_page_max)
783 this.smallest_tag_size = this.top_page * 20;
784 if (this.smallest_tag_size == 0)
785 this.smallest_tag_size = 100;
787 var escape_cond = true;
788 this.page_number = ((Math.floor(Math.random() * 10000)) % Math.ceil(this.smallest_tag_size / 20)) % 1000; //1000 is max page search limit
789 this.json_post_numbers_used.forEach(function (page) {
791 _this.primed_for_fail = true; // no more pages to search and looped once
795 else if (page == _this.page_number) {
800 } while (!escape_cond);
801 this.json_numbers_used.push(this.page_number);
802 var URL = "https://danbooru.donmai.us/posts.json?page=" + this.page_number + end_URL;
805 //check if valid url location
806 DanbooruImageAdder.prototype.checkPageFromDanbooru = function (err, data, tags, this_arr) {
808 console.log('Something went wrong: ' + err);
809 Generics.alert4ChanX("Danbooru Server Did Not Perform request -- Error: " + err, "error");
810 document.getElementById("timer").textContent = "";
811 document.getElementById("tag_input").removeAttribute("disabled");
812 document.getElementById("imageButton").removeAttribute("disabled");
816 var duplicate = false;
817 //check for repeating images found
818 this_arr.previous_images.forEach(function (item) {
819 if (item[0] == this_arr.post_number && item[1] == this_arr.post_number) {
822 this_arr.post_number++;
824 } while (duplicate == false && this_arr.previous_images.length > this_arr.post_number);
825 if (this_arr.primed_for_fail) {
826 Generics.alert4ChanX("No Results: All found for tags \"" + document.getElementById("tag_input").value + "\"", "error");
827 this_arr.reset_search_timer_fields();
830 else if ((data.length < this_arr.post_number + 1) && this_arr.number_of_attempts > 0) {
831 if (this_arr.top_page > this_arr.page_number) {
832 this_arr.top_page = this_arr.page_number + this_arr.post_number / 20;
834 this_arr.number_of_attempts--;
835 document.getElementById("timer").textContent = this_arr.number_of_attempts + "|" + this_arr.time;
836 this_arr.setImage(this_arr);
838 else if (this_arr.number_of_attempts > 0) {
839 //ALL PARAMETERS WILL BE RESET INSIDE JSON
840 document.getElementById("timer").textContent = this_arr.number_of_attempts + "|" + this_arr.time;
841 Generics.getJSON(this_arr.send_URL, function (err, data, tags, _this_arr) { return this_arr.setImageFromDanbooru(err, data, tags, _this_arr); }, tags, this_arr);
844 Generics.alert4ChanX("Not found", "error");
845 this_arr.reset_search_timer_fields();
850 DanbooruImageAdder.prototype.reset_search_timer_fields = function () {
851 this.top_page = this.top_page_max;
852 this.number_of_attempts = this.maximum_attempts;
853 document.getElementById("timer").textContent = "";
854 document.getElementById("tag_input").removeAttribute("disabled");
855 document.getElementById("imageButton").removeAttribute("disabled");
857 //finally draw from the JSON page to generate and place the post into the 4chanX dumplist
858 DanbooruImageAdder.prototype.setImageFromDanbooru = function (err, data, tags, this_arr) {
860 console.log('Something went wrong: ' + err);
861 Generics.alert4ChanX("Danbooru Server Did Not Perform request -- Error: " + err, "error");
862 document.getElementById("timer").textContent = "";
863 document.getElementById("tag_input").removeAttribute("disabled");
864 document.getElementById("imageButton").removeAttribute("disabled");
867 this_arr.json_page = data;
868 var image_found = false;
869 for (this_arr.post_number = this_arr.post_number; this_arr.post_number < 20; this_arr.post_number++) {
870 if (this_arr.timeout) {
871 //Case1: Took too long to scan the page.
872 //Result: Kills search
873 Generics.alert4ChanX("timeout after " + this_arr.time + " seconds", "error");
874 for (var i = 0; i < this_arr.timeout_functions.length; i++) {
875 clearInterval(this_arr.timeout_functions[i]);
877 this_arr.reset_search_timer_fields();
880 else if (this_arr.json_page["" + this_arr.post_number] == undefined) {
881 //Case2: reaches an undefined page.
882 //Result: Switches to a new page
883 this_arr.top_page = this_arr.page_number;
884 this_arr.number_of_attempts--;
885 this_arr.setImage(this_arr);
888 //set the page to search
889 var end_URL = this_arr.json_page["" + this_arr.post_number].file_url;
890 var URL = "https://danbooru.donmai.us" + end_URL;
891 if (this_arr.subdomain_regex.test(end_URL))
893 //place url in visible box
894 this_arr.urlContainterFunction(URL);
898 :{id: 3038118, created_at: "2018-03-02T15:27:56.469-05:00", uploader_id: 49091, score: 6,…}
902 created_at:"2018-03-02T15:27:56.469-05:00"
905 fav_string:"fav:553974 fav:467363 fav:455311 fav:490034 fav:505064 fav:482030 fav:351935 fav:66907 fav:467355 fav:519151"
908 file_url:"/data/__miyuki_kantai_collection_drawn_by_kumadano__7a12a196cc1aa9f794bca81a2a14bb81.jpg"
909 has_active_children:false
912 has_visible_children:false
921 is_rating_locked:false
922 is_status_locked:false
923 large_file_url:"/data/__miyuki_kantai_collection_drawn_by_kumadano__7a12a196cc1aa9f794bca81a2a14bb81.jpg"
924 last_comment_bumped_at:null
925 last_commented_at:null
927 md5:"7a12a196cc1aa9f794bca81a2a14bb81"
931 preview_file_url:"/data/preview/7a12a196cc1aa9f794bca81a2a14bb81.jpg"
934 source:"https://twitter.com/kumadano/status/969629578137251840"
937 tag_count_character:1
938 tag_count_copyright:1
941 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"
942 tag_string_artist:"kumadano"
943 tag_string_character:"miyuki_(kantai_collection)"
944 tag_string_copyright:"kantai_collection"
945 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"
946 tag_string_meta:"commentary_request"
948 updated_at:"2018-03-03T09:09:32.357-05:00"
953 var failed_to_find_required_tags = false;
954 if (end_URL === undefined ||
955 end_URL.indexOf(".mp4") > -1 || end_URL.indexOf(".webm") > -1 || end_URL.indexOf(".swf") > -1 || end_URL.indexOf(".zip") > -1) {
959 tags.forEach(function (tag) {
960 //if tag contains an order then whatever
961 if (tag.indexOf("order:") > -1) { }
962 else if (tag.indexOf("rating:") > -1) {
963 if (tag.charAt(7) !== this_arr.json_page["" + this_arr.post_number]["rating"]) {
964 failed_to_find_required_tags = true;
967 else if (this_arr.json_page["" + this_arr.post_number]["tag_string"].indexOf(tag) == -1) {
968 failed_to_find_required_tags = true;
972 if (failed_to_find_required_tags) {
976 if (this_arr.json_page["" + this_arr.post_number].file_size >= 4000000) {
977 var end_URL = this_arr.json_page["" + this_arr.post_number].large_file_url;
978 var URL = "https://danbooru.donmai.us" + end_URL;
979 if (this_arr.subdomain_regex.test(end_URL))
982 document.getElementById("timer").textContent = "...";
983 this_arr.img_URL = URL;
984 var xhr = new GM_xmlhttpRequest(({
987 responseType: "arraybuffer",
988 onload: function (response) {
989 //is it a non existent image?
990 if (response.response.byteLength <= 387) {
991 Generics.alert4ChanX("Image Does Not Exist on Danbooru(404 error)\nDanbooru seems to be updating image servers???", "error");
994 if (end_URL.indexOf(".jpg") > -1)
995 blob = new Blob([response.response], { type: "image/jpeg" });
996 else if (end_URL.indexOf(".png") > -1)
997 blob = new Blob([response.response], { type: "image/png" });
998 else if (end_URL.indexOf(".gif") > -1)
999 blob = new Blob([response.response], { type: "image/gif" });
1000 var counter = document.getElementById("timer");
1001 while (counter.hasChildNodes())
1002 counter.removeChild(counter.lastChild);
1003 this_arr.reset_search_timer_fields();
1004 this_arr.time = this_arr.time_max;
1005 var name = end_URL.replace(/(data|cached)/g, "");
1006 name = name.replace(/\//g, "");
1007 //SEND RESULTING RESPONSE TO 4CHANX FILES === QRSetFile
1008 var detail = { file: blob, name: name };
1009 if (typeof cloneInto === 'function') {
1010 detail = cloneInto(detail, document.defaultView);
1012 document.dispatchEvent(new CustomEvent('QRSetFile', { bubbles: true, detail: detail }));
1017 //SET PAGE&POST AS FOUND
1018 this_arr.previous_images.push([this_arr.page_number, this_arr.post_number]);
1019 this_arr.post_number = 9001;
1023 this_arr.top_page = this_arr.page_number;
1024 this_arr.number_of_attempts--;
1025 this_arr.setImage(this_arr);
1029 DanbooruImageAdder.prototype.urlContainterFunction = function (url) {
1030 var url_box = document.getElementById("urlContainer");
1031 url_box.value = url;
1033 DanbooruImageAdder.prototype.counterFunction = function () {
1034 if (!this.timeout) {
1036 if (this.time < 0) {
1037 this.timeout = true;
1038 this.time = this.time_max;
1042 DanbooruImageAdder.prototype.decideAction = function (node) { };
1043 DanbooruImageAdder.prototype.retrieveStates = function () { };
1044 DanbooruImageAdder.prototype.storeStates = function () {
1046 for (var _i = 0; _i < arguments.length; _i++) {
1047 items[_i] = arguments[_i];
1050 return DanbooruImageAdder;
1051 }(FeatureInterface));
1052 var ThreadRebuilder = /** @class */ (function (_super) {
1053 __extends(ThreadRebuilder, _super);
1054 function ThreadRebuilder() {
1055 var _this = _super.call(this) || this;
1057 _this.thread_data = [['Comment'], ['Image URLs'], ['Image Names'], ['Post No.']];
1058 _this.semaphore = 1;
1059 _this.semaphore_posts = 1;
1060 _this.use_offsite_archive = false;
1061 _this.window_displayed = false;
1062 _this.in_sequence = false;
1063 _this.tool_top_visible = false;
1064 _this.thread_data_length = 0;
1065 _this.posts_created = 0;
1066 _this.checked = false;
1070 ThreadRebuilder.prototype.init = function () {
1071 var board_uproces = window.location.pathname;
1072 this.board = board_uproces.substring(1, board_uproces.length - 1);
1075 ThreadRebuilder.prototype.retrieveStates = function () {
1076 this.use_offsite_archive = localStorage.getItem("ArchiveType") == "0" ? true : false;
1078 ThreadRebuilder.prototype.storeStates = function () {
1080 for (var _i = 0; _i < arguments.length; _i++) {
1081 items[_i] = arguments[_i];
1084 ThreadRebuilder.prototype.activate = function () {
1086 document.addEventListener("QRDialogCreation", function (e) { return _this.enhance4ChanX(); });
1087 document.addEventListener('QRPostSuccessful', function (e) {
1088 if (_this.in_sequence) {
1089 document.getElementById("dump-list").childNodes[1].click();
1090 _this.setPropperLinking(document.getElementById("qr").getElementsByTagName("TEXTAREA")[0].value);
1094 ThreadRebuilder.prototype.decideAction = function (node) { };
1095 ThreadRebuilder.prototype.enhance4ChanX = function () {
1097 var qr_window = document.getElementById("qr");
1098 if (document.getElementById("qrRebuilder") !== null)
1099 qr_window.removeChild(document.getElementById("qrRebuilder"));
1100 var thread_rebuilder_table = document.createElement("TABLE");
1101 thread_rebuilder_table.setAttribute("id", "qrRebuilder");
1102 thread_rebuilder_table.setAttribute("style", "text-align:center");
1103 qr_window.appendChild(thread_rebuilder_table);
1104 var thread_row = document.createElement("TR");
1105 var option_text_size = 18;
1106 var help_icon_container = document.createElement("A");
1107 help_icon_container.href = "javascript:void(0)";
1108 help_icon_container.title = "Click to View Help!";
1109 var help_icon = document.createElement("IMG");
1110 help_icon.setAttribute("style", "height:" + option_text_size * 1.25 + "px;margin:-4px 10px");
1111 help_icon.src = Constants.HELP_ICON_SOURCE;
1112 help_icon_container.appendChild(help_icon);
1113 thread_row.appendChild(help_icon_container);
1114 var tooltip_div = document.createElement("DIV");
1115 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>";
1116 tooltip_div.setAttribute("style", "z-index:9;padding:5px;border:1px solid black;background-color:white;word-wrap:break-word;display:none;position:absolute;");
1117 help_icon_container.addEventListener("click", function (evt) {
1118 if (_this.tool_top_visible)
1119 tooltip_div.setAttribute("style", "z-index:9;padding:5px;border:1px solid black;background-color:white;word-wrap:break-word;display:none;position:absolute;");
1121 tooltip_div.setAttribute("style", "z-index:9;padding:5px;border:1px solid black;background-color:white;word-wrap:break-word;display:block;position:absolute;"
1122 + "left:" + (evt.clientX - qr_window.getBoundingClientRect().x) +
1123 "px;top:" + (evt.clientY - qr_window.getBoundingClientRect().y) + "px;");
1124 _this.tool_top_visible = !_this.tool_top_visible;
1126 qr_window.appendChild(tooltip_div);
1127 var second_row_nodes = [
1128 document.createTextNode("Thread: "),
1129 document.createElement("INPUT"),
1130 document.createElement("INPUT"),
1132 second_row_nodes.forEach(function (node) {
1133 thread_row.appendChild(node);
1135 thread_rebuilder_table.appendChild(thread_row);
1136 second_row_nodes[1].setAttribute("ID", "threadInput");
1137 second_row_nodes[1].setAttribute("style", "width:35.0%");
1138 second_row_nodes[2].setAttribute("ID", "threadButton");
1139 second_row_nodes[2].setAttribute("type", "button");
1140 second_row_nodes[2].setAttribute("value", "Set Rebuild Queue");
1141 second_row_nodes[2].addEventListener("click", function () {
1142 _this.in_sequence = true;
1144 _this.getThread(second_row_nodes[1].value);
1145 _this.postID = setInterval(function () { return _this.postRoutine(); }, 1000);
1146 if (_this.timeListen === undefined)
1147 _this.timeListen = setInterval(function () { return _this.timeListenerFunction(); }, 1000);
1149 qr_window.appendChild(document.createElement("hr"));
1152 ThreadRebuilder.prototype.postRoutine = function () {
1154 if (this.semaphore == 0) {
1156 this.thread_data_length = this.thread_data[0].length;
1157 this.fillID = setInterval(function () { return _this.fillRoutine(); }, 10);
1162 ThreadRebuilder.prototype.stopRoutine = function () {
1163 clearInterval(this.postID);
1166 ThreadRebuilder.prototype.fillRoutine = function () {
1167 if (this.posts_created >= this.thread_data_length) {
1168 this.semaphore_posts = 0;
1169 this.stopFillRoutine();
1171 else if (this.semaphore_posts == 1) {
1172 this.semaphore_posts--;
1173 this.createPost(this.thread_data[0][this.posts_created], this.thread_data[1][this.posts_created], this.thread_data[2][this.posts_created]);
1174 this.posts_created++;
1178 ThreadRebuilder.prototype.stopFillRoutine = function () {
1179 clearInterval(this.fillID);
1181 ThreadRebuilder.prototype.setPropperLinking = function (text) {
1183 var search_regex = RegExp(">>\\d+", "g");
1186 var link_arr = Array();
1187 while ((result = search_regex.exec(text)) != null) {
1188 var end_index = search_regex.lastIndex;
1189 var post_no = result.toString().replace(/>/g, "");
1190 link_arr.push([post_no, end_index]);
1192 //hunt down the text of what it linked to
1193 //Get the links inside of the origonal message to show text contents
1194 var responding_text = Array();
1195 if (this.use_offsite_archive)
1196 var URL = "https://www.archived.moe/_/api/chan/thread/?board=" + this.board + "&num=" + document.getElementById("threadInput").value;
1198 var URL = "https://a.4cdn.org/" + this.board + "/thread/" + document.getElementById("threadInput").value + ".json";
1199 var xhr = new GM_xmlhttpRequest(({
1202 responseType: "json",
1203 onload: function (data) {
1204 if (_this.use_offsite_archive)
1205 data = data.response["" + document.getElementById("threadInput").value]["posts"];
1207 data = data.response["posts"];
1208 if (data == undefined) {
1209 alert("Invalid Thread ID: " + document.getElementById("threadInput").value + ". ");
1212 link_arr.forEach(function (link_item) {
1213 for (var data_entry = 0; data_entry < data.length; data_entry++) {
1214 if (parseInt(link_item[0]) == parseInt(data[data_entry]["no"])) {
1215 if (_this.use_offsite_archive && data[data_entry]["comment_processed"] !== undefined)
1216 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"]]);
1217 else if (data[data_entry]["com"] !== undefined)
1218 responding_text.push([[post_no, end_index], data[data_entry]["com"].replace(/(>>|#p)\d+/g, ""), data[data_entry]["md5"]]);
1220 responding_text.push([[post_no, end_index], undefined, data[data_entry]["md5"]]);
1225 var current_url = window.location.href;
1226 var hash_index = current_url.lastIndexOf("#") != -1 ? current_url.lastIndexOf("#") : window.location.href.length;
1227 var current_thread = window.location.href.substring(current_url.lastIndexOf("/") + 1, hash_index);
1228 var current_url = "https://a.4cdn.org/" + _this.board + "/thread/" + current_thread + ".json";
1229 //open current thread to hunt down the text found in links
1230 var xhr = new GM_xmlhttpRequest(({
1233 responseType: "json",
1234 onload: function (data) {
1235 data = data.response["posts"];
1236 if (data == undefined) {
1237 alert("Invalid Thread ID: " + document.getElementById("threadInput").value + ". ");
1240 responding_text.forEach(function (response_item) {
1241 for (var data_entry = 0; data_entry < data.length; data_entry++) {
1242 if (data[data_entry]["com"] !== undefined && (response_item[1] == data[data_entry]["com"].replace(/(>>|#p)\d+/g, "") || response_item[1] == null)
1243 && (response_item[2] == data[data_entry]["md5"] || response_item[2] == null)) {
1244 var start_index = response_item[0][0].legth - response_item[0][1];
1245 text = text.substring(0, start_index) + ">>" + data[data_entry]["no"] + text.substring(response_item[0][1]);
1248 else if (response_item[2] !== undefined && response_item[2] == data[data_entry]["md5"]) {
1249 var start_index = response_item[0][0].legth - response_item[0][1];
1250 text = text.substring(0, start_index) + ">>" + data[data_entry]["no"] + text.substring(response_item[0][1]);
1255 document.getElementById("qr").getElementsByTagName("TEXTAREA")[0].value = text;
1256 document.getElementById("add-post").click();
1257 _this.semaphore_posts++;
1266 //2) GET ARCHIVED THREAD
1267 ThreadRebuilder.prototype.getThread = function (threadNo) {
1269 this.thread_data = [[], [], [], []];
1270 if (this.use_offsite_archive)
1271 var URL = "https://www.archived.moe/_/api/chan/thread/?board=" + this.board + "&num=" + document.getElementById("threadInput").value;
1273 var URL = "https://a.4cdn.org/" + this.board + "/thread/" + document.getElementById("threadInput").value + ".json";
1274 var xhr = new GM_xmlhttpRequest(({
1277 responseType: "json",
1278 onload: function (data) {
1279 var starting_post = -1;
1280 if (_this.use_offsite_archive) {
1282 data = data.response["" + document.getElementById("threadInput").value];
1286 data = data.response;
1288 if (data == undefined) {
1289 alert("Invalid Thread ID: " + threadNo + ".\n4chan Archive ");
1292 if (_this.use_offsite_archive)
1293 data["posts"] = data.values(data["posts"]);
1294 var len = data["posts"].length;
1295 for (var post_number = starting_post; post_number < len; post_number++) {
1296 var comment = undefined;
1297 if (_this.use_offsite_archive)
1298 comment = data["posts"][post_number]["comment"];
1300 comment = data["posts"][post_number]["com"];
1301 if (comment !== undefined && comment !== null)
1302 _this.thread_data[0].push(comment);
1304 _this.thread_data[0].push("");
1305 var filename = undefined;
1306 if (_this.use_offsite_archive) {
1307 if (data["posts"][post_number]["media"] !== null)
1308 filename = "" + data["posts"][post_number]["media"]["media_filename"];
1311 filename = "" + data["posts"][post_number]["tim"] + data["posts"][post_number]["ext"];
1312 if (filename !== undefined && filename !== null && filename.indexOf("undefined") == -1)
1313 if (_this.use_offsite_archive)
1314 if (data["posts"][post_number]["media"] !== null)
1315 _this.thread_data[1].push(data["posts"][post_number]["media"]["remote_media_link"]);
1317 _this.thread_data[1].push("");
1319 _this.thread_data[1].push("https://i.4cdn.org/" + _this.board + "/" + filename);
1321 _this.thread_data[1].push("");
1322 if (_this.use_offsite_archive) {
1323 if (data["posts"][post_number]["media"] !== null)
1324 _this.thread_data[2].push(data["posts"][post_number]["media"]["media_id"]);
1327 _this.thread_data[2].push(data["posts"][post_number]["filename"]);
1328 if (_this.use_offsite_archive)
1329 _this.thread_data[3].push(data["posts"][post_number]["num"]);
1331 _this.thread_data[3].push(data["posts"][post_number]["no"]);
1339 //3) RIP POSTS AND IMAGES
1340 ThreadRebuilder.prototype.createPost = function (text, imageURL, imageName) {
1342 if (imageURL != "") {
1343 var response_type = "arraybuffer";
1344 if (this.use_offsite_archive)
1345 response_type = "text";
1346 var xhr = new GM_xmlhttpRequest(({
1349 responseType: response_type,
1350 onload: function (response) {
1351 if (_this.use_offsite_archive) {
1352 var parser = new DOMParser();
1353 var content_attribute = parser.parseFromString(response.response, "text/html").getElementsByTagName("META")[0].getAttribute("content");
1354 var redirect_url = content_attribute.substring(content_attribute.indexOf("http"));
1355 var xhr = new GM_xmlhttpRequest(({ method: "GET", url: redirect_url, responseType: "arraybuffer",
1356 onload: function (response) {
1357 _this.inputImage(response, text, imageURL, imageName);
1362 _this.inputImage(response, text, imageURL, imageName);
1368 text = this.createPostComment(text);
1369 this.setPropperLinking(text);
1372 ThreadRebuilder.prototype.inputImage = function (response, text, imageURL, imageName) {
1375 if (imageURL.indexOf(".jpg") > -1) {
1376 blob = new Blob([response.response], { type: "image/jpeg" });
1379 else if (imageURL.indexOf(".png") > -1) {
1380 blob = new Blob([response.response], { type: "image/png" });
1383 else if (imageURL.indexOf(".gif") > -1) {
1384 blob = new Blob([response.response], { type: "image/gif" });
1387 else if (imageURL.indexOf(".webm") > -1) {
1388 blob = new Blob([response.response], { type: "video/webm" });
1391 var name = imageName + ext;
1392 //SEND RESULTING RESPONSE TO 4CHANX FILES === QRSetFile
1393 var detail = { file: blob, name: name };
1394 detail = cloneInto(detail, document.defaultView);
1395 document.dispatchEvent(new CustomEvent('QRSetFile', { bubbles: true, detail: detail }));
1396 if (text !== "" && text !== undefined) {
1397 text = this.createPostComment(text);
1398 this.setPropperLinking(text);
1401 document.getElementById("add-post").click();
1402 this.semaphore_posts++;
1405 //4) CREATE POST QUEUE
1406 ThreadRebuilder.prototype.createPostComment = function (text) {
1407 var dummy = document.createElement("DIV");
1408 dummy.innerHTML = text;
1409 var inside_node = dummy.firstChild;
1410 var return_text = "";
1412 if (inside_node.tagName == "BR")
1413 return_text += "\n";
1415 return_text += inside_node.textContent;
1416 } while ((inside_node = inside_node.nextSibling));
1420 ThreadRebuilder.prototype.timeListenerFunction = function () {
1421 var time = parseInt(document.getElementById("qr-filename-container").nextSibling.value.replace(/[a-zA-Z]+/g, ""));
1423 this.checked = false;
1425 else if (time > 5) {
1426 this.checked = true;
1429 ThreadRebuilder.prototype.killAll = function () {
1430 this.thread_data_length = 0;
1431 this.posts_created = 0;
1433 this.postID = undefined;
1435 this.semaphore_posts = 1;
1436 this.stopFillRoutine();
1437 this.fillID = undefined;
1438 this.thread_data = [['Comment'], ['Image URLs'], ['Image Names'], ['Post No.']];
1440 var qr_dumplist = document.getElementById("dump-list").childNodes;
1441 var qr_dumplist_len = qr_dumplist.length;
1442 var current_preview = 0;
1443 while (qr_dumplist_len - current_preview > 1) {
1444 qr_dumplist[0].firstChild.click();
1448 return ThreadRebuilder;
1449 }(FeatureInterface));
1450 var CharacterInserter = /** @class */ (function (_super) {
1451 __extends(CharacterInserter, _super);
1452 function CharacterInserter(use_kita, use_yen) {
1453 var _this = _super.call(this) || this;
1454 _this.kita_character = "キタ━━━(゚∀゚)━━━!!";
1455 _this.kita_hash_color = "#444444";
1456 _this.yen_character = "¥";
1457 _this.yen_hash_color = "#9370DB";
1458 _this.use_yen = use_yen;
1459 _this.use_kita = use_kita;
1460 _this.retrieveStates();
1465 CharacterInserter.prototype.init = function () {
1467 this.hotkeyListeners();
1469 CharacterInserter.prototype.activate = function () {
1470 console.log("4F-FSE: CharacterInserter Active - " + (this.use_kita ? "Character Coloring+" : "") + (this.use_yen ? " Line Coloring" : ""));
1472 CharacterInserter.prototype.decideAction = function (node) {
1473 if (node.tagName == "BLOCKQUOTE")
1474 this.colorCharacters(node);
1476 CharacterInserter.prototype.retrieveStates = function () {
1477 if (localStorage.getItem("Yen_Character") === undefined || localStorage.getItem("Yen_Character") === null)
1478 this.yen_character = "¥";
1480 this.yen_character = localStorage.getItem("Yen_Character");
1481 if (localStorage.getItem("Yen_Color") === undefined || localStorage.getItem("Yen_Color") === null)
1482 this.yen_hash_color = "#9370DB";
1484 this.yen_hash_color = localStorage.getItem("Yen_Color");
1485 if (localStorage.getItem("Kita_Character") === undefined || localStorage.getItem("Kita_Character") === null)
1486 this.kita_character = "キタ━━━(゚∀゚)━━━!!";
1488 this.kita_character = localStorage.getItem("Kita_Character");
1489 if (localStorage.getItem("Kita_Color") === undefined || localStorage.getItem("Kita_Color") === null)
1490 this.kita_hash_color = "#444444";
1492 this.kita_hash_color = localStorage.getItem("Kita_Color");
1494 CharacterInserter.prototype.storeStates = function () {
1496 for (var _i = 0; _i < arguments.length; _i++) {
1497 items[_i] = arguments[_i];
1501 CharacterInserter.prototype.addStyle = function () {
1502 var style = document.createElement("STYLE");
1503 style.innerHTML = ".the_m_word{color:" + this.yen_hash_color + "} \n.the_k_word{color:" + this.kita_hash_color + "}";
1504 document.head.appendChild(style);
1506 //hotkeys for kita and yen
1507 CharacterInserter.prototype.hotkeyListeners = function () {
1509 var listener_obj = {};
1510 window.addEventListener("keydown", function (e) {
1511 listener_obj[e.keyCode] = true;
1512 var node = document.activeElement;
1513 if (listener_obj[17] && listener_obj[75]) {
1515 _this.insertAtPos(node, _this.kita_character);
1517 if (listener_obj[17] && listener_obj[220]) {
1519 _this.insertAtPos(node, _this.yen_character);
1521 }, { passive: false, capture: false, once: false });
1522 window.addEventListener("keyup", function (e) {
1523 listener_obj[e.keyCode] = false;
1524 }, { passive: false, capture: false, once: false });
1526 CharacterInserter.prototype.insertAtPos = function (node, buzzwords) {
1527 var sel_start = node.selectionStart;
1528 var sel_end = node.selectionEnd;
1529 var node_text = node.value;
1530 node.value = node_text.substr(0, sel_start) + buzzwords + node_text.substr(sel_end);
1531 node.selectionStart = sel_start + buzzwords.length;
1532 node.selectionEnd = sel_end + buzzwords.length;
1535 CharacterInserter.prototype.colorCharacters = function (root) {
1536 if (root.nodeType !== Node.ELEMENT_NODE) {
1539 if (root.textContent.indexOf(this.yen_character) <= -1 && root.textContent.indexOf(this.kita_character) <= -1) {
1542 var txtItterator = document.createNodeIterator(root, NodeFilter.SHOW_TEXT);
1544 while ((text_node = txtItterator.nextNode())) {
1545 //disregard text inside of A tag links and already colored text
1546 if (text_node.parentNode.tagName == "A" || /the_[a-z]_word/g.test(text_node.parentNode.className))
1548 this.setColor(text_node, txtItterator);
1551 //give color to text inside of nodes.
1552 // first scan for yen symbols and then check the front of the text for not nested kita.
1553 CharacterInserter.prototype.setColor = function (text_node, txtItterator) {
1554 var start_text_node = text_node;
1556 var yen_node = this.use_kita ? this.searchYen(text_node) : false;
1557 if (yen_node != false) {
1558 //jump to internal node
1559 text_node = txtItterator.nextNode();
1560 //scan for nested kita
1562 result = this.use_kita ? this.searchKita(text_node) : false;
1563 if (result != false) {
1564 //jump foreward to point after kita inserted
1565 text_node = txtItterator.nextNode();
1566 text_node = txtItterator.nextNode();
1568 } while (result != false);
1570 //scan for outside kita from start
1572 result = this.use_kita ? this.searchKita(start_text_node) : false;
1573 start_text_node = result.nextSibling;
1574 } while (result != false && start_text_node !== undefined);
1576 //find the location of a yen, split the text from above that position, create a span element and place split into this span.
1577 //Then take the initial text node and insert into it from after the text node.
1578 CharacterInserter.prototype.searchYen = function (text_node) {
1579 var yenIndex = text_node.textContent.indexOf(this.yen_character);
1580 if (yenIndex > -1) {
1581 var splitNode = text_node.splitText(yenIndex);
1582 var span = document.createElement('span');
1583 span.className = "the_m_word";
1584 span.appendChild(splitNode);
1585 text_node.parentNode.insertBefore(span, text_node.nextSibling);
1590 //find the location of a kita, isolate it by splitting from the point where the kita ends and the point where it begins.
1591 //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,
1592 //then refer back to the parent and place it after the leftmost string.
1593 CharacterInserter.prototype.searchKita = function (text_node) {
1594 var kIndex = text_node.textContent.indexOf(this.kita_character);
1596 var far_split_note = text_node.splitText(kIndex + this.kita_character.length);
1597 var splitNode = text_node.splitText(kIndex);
1598 var span = document.createElement('span');
1599 span.className = "the_k_word";
1600 span.appendChild(splitNode);
1601 text_node.parentNode.insertBefore(span, text_node.nextSibling);
1606 return CharacterInserter;
1607 }(FeatureInterface));
1608 var PasswordViewer = /** @class */ (function (_super) {
1609 __extends(PasswordViewer, _super);
1610 function PasswordViewer() {
1611 var _this = _super.call(this) || this;
1612 _this.post_id = "postPassword";
1613 _this.del_id = "delPassword";
1614 _this.label_post = document.createElement('LABEL');
1615 _this.label_del = document.createElement('LABEL');
1620 PasswordViewer.prototype.init = function () {
1621 this.node_post = document.getElementById(this.post_id);
1622 this.node_del = document.getElementById(this.del_id);
1623 this.node_post_parent = this.node_post.parentNode;
1624 this.node_del_parent = this.node_del.parentNode;
1625 this.label_post.textContent = 'Post: ';
1626 this.label_del.textContent = 'Delete: ';
1628 //activate displays passwords
1629 PasswordViewer.prototype.activate = function () {
1630 console.log("4F-FSE: PasswordViewer Active");
1631 this.node_post_parent.insertBefore(this.label_post, this.node_post);
1632 this.node_del_parent.insertBefore(this.label_del, this.node_del);
1633 this.node_post.removeAttribute('type');
1634 this.node_del.removeAttribute('type');
1635 document.getElementsByClassName('deleteform')[0].style.display = 'inline';
1636 this.node_del.style.display = 'inline';
1637 this.label_del.style.display = 'inline';
1638 this.label_del.style.paddingLeft = '10px';
1640 PasswordViewer.prototype.decideAction = function (node) { };
1641 PasswordViewer.prototype.retrieveStates = function () { };
1643 PasswordViewer.prototype.storeStates = function () { };
1645 return PasswordViewer;
1646 }(FeatureInterface));
1647 var SettingsWindow = /** @class */ (function (_super) {
1648 __extends(SettingsWindow, _super);
1649 function SettingsWindow() {
1650 var _this = _super.call(this) || this;
1651 _this.background_div = document.createElement('DIV');
1652 _this.settings_div = document.createElement('DIV');
1653 _this.close_div = document.createElement('DIV');
1654 _this.contents_div = document.createElement('DIV');
1655 _this.ul_selection_start = document.createElement('UL');
1656 _this.close_link = document.createElement('A');
1657 _this.title_para = document.createElement('P');
1658 _this.title_text = document.createTextNode('4F-FSE Settings');
1659 _this.end_para = document.createElement('P');
1660 _this.end_text = document.createTextNode('Refresh to view changes');
1661 _this.settings_style = document.createElement('STYLE');
1662 //to change order change, this AND...*
1663 _this.list_items = [
1664 { Text: " | View 『Image Hiding』 Settings", ListenerFunc: function (a_id) {
1665 _this.clearContainer();
1666 _this.contents_div.innerHTML =
1667 "\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";
1668 document.getElementById("Expiration_Time").value = "" + (_this.setting_items.image_hiding_settings.Expiration_Time / Constants.MILLISECONDS_TO_THE_HOUR);
1669 document.getElementById("MD5_List_FSE").value = _this.setting_items.image_hiding_settings.MD5_List_FSE;
1670 var set_button = document.createElement('INPUT');
1671 document.getElementById("disposable_container").appendChild(set_button);
1672 set_button.setAttribute('VALUE', "Set Image Settings");
1673 set_button.addEventListener("click", function (evt) {
1674 _this.storeStates();
1675 _this.clearContainer();
1676 _this.rebuildContainer();
1678 set_button.setAttribute('TYPE', 'button');
1681 { Text: " | View 『Word Replacement』 Settings", ListenerFunc: function (a_id) {
1682 _this.clearContainer();
1683 var disposable_container = document.createElement("DIV");
1684 disposable_container.setAttribute("ID", "disposable_container");
1685 _this.contents_div.appendChild(disposable_container);
1686 _this.filterWindow(disposable_container);
1687 _this.filterSetTable();
1690 { Text: " | View 『Danbooru Image Adder』 Settings", ListenerFunc: function (a_id) {
1691 _this.clearContainer();
1692 var disposable_container = document.createElement("DIV");
1693 disposable_container.setAttribute("id", "disposable_container");
1694 _this.contents_div.appendChild(disposable_container);
1695 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>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=\"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";
1696 _this.setImageAdderFields();
1697 _this.setImageAdderEventListeners();
1700 { Text: " | View 『Thread Rebuilder』 Settings", ListenerFunc: function (a_id) {
1701 _this.clearContainer();
1702 var disposable_container = document.createElement("DIV");
1703 disposable_container.setAttribute("id", "disposable_container");
1704 _this.contents_div.appendChild(disposable_container);
1705 disposable_container.innerHTML =
1706 "\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";
1707 (document.getElementById("setArchive")).addEventListener("click", function () {
1708 _this.storeStates();
1709 _this.clearContainer();
1710 _this.rebuildContainer();
1712 if (_this.setting_items.thread_rebuild_settings.Archive_Type === "0")
1713 document.getElementById("OffsiteArchive").checked = true;
1714 else if (_this.setting_items.thread_rebuild_settings.Archive_Type === "1")
1715 document.getElementById("OnsiteArchive").checked = true;
1718 { Text: " | View 『¥ Text』 Settings [Customizable]", ListenerFunc: function (a_id) {
1719 _this.clearContainer();
1720 var disposable_container = document.createElement("DIV");
1721 disposable_container.setAttribute("id", "disposable_container");
1722 _this.contents_div.appendChild(disposable_container);
1723 disposable_container.innerHTML =
1724 "\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";
1725 document.getElementById("SelectColorYen").addEventListener("input", function (evt) {
1726 document.getElementById("HexColorYen_text").value =
1727 (document.getElementById("SelectColorYen").value);
1729 document.getElementById("setQuote").addEventListener("click", function (e) {
1730 _this.storeStates();
1731 _this.clearContainer();
1732 _this.rebuildContainer();
1734 if (_this.setting_items.character_inserter_settings.Yen_Character !== undefined)
1735 document.getElementById("quoteCharacter").value = _this.setting_items.character_inserter_settings.Yen_Character;
1736 if (_this.setting_items.character_inserter_settings.Yen_Color !== undefined)
1737 document.getElementById("HexColorYen_text").value = _this.setting_items.character_inserter_settings.Yen_Color;
1738 document.getElementById("SelectColorYen").value = _this.setting_items.character_inserter_settings.Yen_Color;
1741 { Text: " | View 『Kita』 Settings [Customizable]", ListenerFunc: function (a_id) {
1742 _this.clearContainer();
1743 var disposable_container = document.createElement("DIV");
1744 disposable_container.setAttribute("id", "disposable_container");
1745 _this.contents_div.appendChild(disposable_container);
1746 disposable_container.innerHTML =
1747 "\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";
1748 document.getElementById("SelectColorKita").addEventListener("input", function (evt) {
1749 document.getElementById("HexColorKita_text").value =
1750 (document.getElementById("SelectColorKita").value);
1752 document.getElementById("setCharacter").addEventListener("click", function (e) {
1753 _this.storeStates();
1754 _this.clearContainer();
1755 _this.rebuildContainer();
1757 if (_this.setting_items.character_inserter_settings.Kita_Character !== undefined)
1758 document.getElementById("selectiveCharacters").value = _this.setting_items.character_inserter_settings.Kita_Character;
1759 if (_this.setting_items.character_inserter_settings.Kita_Color !== undefined)
1760 document.getElementById("HexColorKita_text").value = _this.setting_items.character_inserter_settings.Kita_Color;
1761 document.getElementById("SelectColorKita").value = _this.setting_items.character_inserter_settings.Kita_Color;
1764 { Text: " | Set 『Visible Password』", ListenerFunc: function (input_id) {
1765 var input = document.getElementById(input_id);
1766 var is_check = !input.checked;
1767 document.getElementById(input_id).checked = is_check;
1768 _this.storeStates();
1771 _this.setting_items = {};
1772 _this.retrieveStates();
1777 SettingsWindow.prototype.setImageAdderFields = function () {
1778 document.getElementById("width_DIA").value = this.setting_items.image_adder_settings.Width;
1779 document.getElementById("height_DIA").value = this.setting_items.image_adder_settings.Height;
1780 document.getElementById("qr_width_DIA").value = this.setting_items.image_adder_settings.QR_Width;
1781 if (document.getElementById("width_DIA").value == "489")
1782 document.getElementById("v_large_DIA").checked = true;
1783 else if (document.getElementById("width_DIA").value == "400")
1784 document.getElementById("large_DIA").checked = true;
1785 else if (document.getElementById("width_DIA").value == "300")
1786 document.getElementById("medium_DIA").checked = true;
1787 else if (document.getElementById("width_DIA").value == "200")
1788 document.getElementById("small_DIA").checked = true;
1790 SettingsWindow.prototype.setImageAdderEventListeners = function () {
1792 document.getElementById("v_large_DIA").addEventListener("click", function () {
1793 document.getElementById("width_DIA").value = "489";
1794 document.getElementById("height_DIA").value = "489";
1796 document.getElementById("large_DIA").addEventListener("click", function () {
1797 document.getElementById("width_DIA").value = "400";
1798 document.getElementById("height_DIA").value = "400";
1800 document.getElementById("medium_DIA").addEventListener("click", function () {
1801 document.getElementById("width_DIA").value = "300";
1802 document.getElementById("height_DIA").value = "300";
1804 document.getElementById("small_DIA").addEventListener("click", function () {
1805 document.getElementById("width_DIA").value = "200";
1806 document.getElementById("height_DIA").value = "200";
1808 document.getElementById("SetImageAdderProperties").addEventListener("click", function (evt) {
1809 _this.storeStates();
1810 _this.clearContainer();
1811 _this.rebuildContainer();
1815 SettingsWindow.prototype.retrieveStates = function () {
1816 //values used to fill out data fields
1817 this.setting_items.image_hiding_settings = { Expiration_Time: localStorage.getItem("Expiration_Time"), MD5_List_FSE: localStorage.getItem("MD5_List_FSE"), Active: localStorage.getItem("ImageHidingActive") };
1818 this.retrieveWordReplaceStates();
1819 this.retrieveImageAdderStates();
1820 this.retrieveRebuildStates();
1821 this.retrieveCharacterInsertingStates();
1822 this.setting_items.password_settings = (localStorage.getItem("PasswordActive"));
1824 SettingsWindow.prototype.retrieveActiveToggles = function () {
1825 if (localStorage.getItem("4F-FSE") === null) {
1826 document.getElementById("check-settings0").checked = true;
1827 document.getElementById("check-settings1").checked = false;
1828 document.getElementById("check-settings2").checked = false;
1829 document.getElementById("check-settings3").checked = false;
1830 document.getElementById("check-settings4").checked = true;
1831 document.getElementById("check-settings5").checked = true;
1832 document.getElementById("check-settings6").checked = true;
1833 localStorage.setItem("4F-FSE", "Success");
1834 this.displayWindow();
1837 document.getElementById("check-settings0").checked = localStorage.getItem("ImageHidingActive") === 'true';
1838 document.getElementById("check-settings1").checked = localStorage.getItem("TextReplaceActive") === 'true';
1839 document.getElementById("check-settings2").checked = localStorage.getItem("ImageAdderActive") === 'true';
1840 document.getElementById("check-settings3").checked = localStorage.getItem("ThreadRebuilderActive") === 'true';
1841 document.getElementById("check-settings4").checked = localStorage.getItem("YenActive") === 'true';
1842 document.getElementById("check-settings5").checked = localStorage.getItem("KitaActive") === 'true';
1843 document.getElementById("check-settings6").checked = localStorage.getItem("PasswordActive") === 'true';
1845 SettingsWindow.prototype.retrieveWordReplaceStates = function () {
1846 //acquire text filter representation
1847 var storage_index = 0;
1848 var JSON_storage = {};
1850 var text_filters = [];
1851 var local_store_len = window.localStorage.length;
1852 while (storage_index < local_store_len) {
1853 storage_key = window.localStorage.key(storage_index);
1854 JSON_storage[storage_key] = window.localStorage.getItem(storage_key);
1857 var filters = Generics.getJSONPropertiesByKeyName(JSON_storage, "[0-9]+FLT");
1859 filters.forEach(function (filter) {
1860 text_filters.push(TextReplacer.formatFilterSettings(JSON_storage[filter]));
1862 this.setting_items.word_replace_settings = { Number_of_filters: localStorage.getItem("filter_quantity"), Text_Filter_List: text_filters, Active: localStorage.getItem("TextReplaceActive") };
1864 SettingsWindow.prototype.retrieveImageAdderStates = function () {
1865 this.setting_items.image_adder_settings = { Width: localStorage.getItem("width_DIA"),
1866 Height: localStorage.getItem("height_DIA"),
1867 QR_Width: localStorage.getItem("qr_width_DIA"),
1868 Active: localStorage.getItem("ImageAdderActive") };
1869 if (this.setting_items.image_adder_settings.Height === null)
1870 this.setting_items.image_adder_settings.Height = 400;
1871 if (this.setting_items.image_adder_settings.Width === null)
1872 this.setting_items.image_adder_settings.Width = 400;
1873 if (this.setting_items.image_adder_settings.QR_Width === null)
1874 this.setting_items.image_adder_settings.QR_Width = 480;
1875 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;}";
1876 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;}";
1878 SettingsWindow.prototype.retrieveRebuildStates = function () {
1879 if (localStorage.getItem("ArchiveType_FSE") !== "1" && localStorage.getItem("ArchiveType_FSE") !== "0")
1880 localStorage.setItem("ArchiveType_FSE", "1");
1881 this.setting_items.thread_rebuild_settings = { Archive_Type: localStorage.getItem("ArchiveType_FSE"), Active: localStorage.getItem("ThreadRebuilderActive") };
1883 SettingsWindow.prototype.retrieveCharacterInsertingStates = function () {
1884 if (localStorage.getItem("Yen_Character") === undefined || localStorage.getItem("Yen_Character") === null)
1885 localStorage.setItem("Yen_Character", "¥");
1886 if (localStorage.getItem("Yen_Color") === undefined || localStorage.getItem("Yen_Color") === null)
1887 localStorage.setItem("Yen_Color", "#9370DB");
1888 if (localStorage.getItem("Kita_Character") === undefined || localStorage.getItem("Kita_Character") === null)
1889 localStorage.setItem("Kita_Character", "キタ━━━(゚∀゚)━━━!!");
1890 if (localStorage.getItem("Kita_Color") === undefined || localStorage.getItem("Kita_Color") === null)
1891 localStorage.setItem("Kita_Color", "#444444");
1892 this.setting_items.character_inserter_settings = { Yen_Active: localStorage.getItem("YenActive") == 'true', Yen_Character: localStorage.getItem("Yen_Character"), Yen_Color: localStorage.getItem("Yen_Color"),
1893 Kita_Active: localStorage.getItem("KitaActive") == 'true', Kita_Character: localStorage.getItem("Kita_Character"), Kita_Color: localStorage.getItem("Kita_Color") };
1895 SettingsWindow.prototype.storeStates = function () {
1897 this.storeImageFilterStates();
1898 //Text replace settings
1899 this.storeTextFilterStates();
1900 //Image Adder settings
1901 this.storeImageAdderStates();
1902 //Thread rebuild settings
1903 this.storeRebuildStates();
1904 //character inserter
1905 this.storeCharacterInserterStates();
1906 //Password replace settings
1907 this.storePasswordStates();
1908 this.retrieveStates();
1910 SettingsWindow.prototype.storeActiveToggles = function () {
1912 localStorage.setItem("ImageHidingActive", (document.getElementById("check-settings0").checked.toString()));
1913 localStorage.setItem("TextReplaceActive", (document.getElementById("check-settings1").checked.toString()));
1914 localStorage.setItem("ImageAdderActive", (document.getElementById("check-settings2").checked.toString()));
1915 localStorage.setItem("ThreadRebuilderActive", (document.getElementById("check-settings3").checked.toString()));
1916 localStorage.setItem("YenActive", (document.getElementById("check-settings4").checked.toString()));
1917 localStorage.setItem("KitaActive", (document.getElementById("check-settings5").checked.toString()));
1918 localStorage.setItem("PasswordActive", (document.getElementById("check-settings6").checked.toString()));
1920 SettingsWindow.prototype.storeImageFilterStates = function () {
1921 if (document.getElementById("Expiration_Time") !== null) {
1922 var time = document.getElementById("Expiration_Time");
1923 var millisecond_time = parseInt(time.value) * Constants.MILLISECONDS_TO_THE_HOUR;
1924 if (millisecond_time == 0 || millisecond_time === null || millisecond_time === undefined)
1925 millisecond_time = Constants.DEFAULT_HIDE_EXPIRATION_TIME;
1926 localStorage.setItem("Expiration_Time", millisecond_time.toString());
1927 var md5_filters = document.getElementById("MD5_List_FSE").value;
1928 localStorage.setItem("MD5_List_FSE", md5_filters);
1929 Generics.alert4ChanX("Image Settings Saved", "success", 3);
1932 SettingsWindow.prototype.storeTextFilterStates = function () {
1933 if (document.getElementById("FilterRow0") !== null) {
1934 var f_row_moving = document.getElementById("FilterRow0");
1935 var number_of_filters = 0;
1936 var number_of_filters_actual = 0;
1937 while (f_row_moving.nextSibling !== null) {
1938 if (document.getElementById("Pattern" + number_of_filters).value !== "")
1939 number_of_filters_actual++;
1940 number_of_filters++;
1941 f_row_moving = f_row_moving.nextSibling;
1943 window.localStorage.setItem("filter_quantity", number_of_filters_actual.toString());
1944 for (var pattern_input = 0; pattern_input < number_of_filters; pattern_input++) {
1945 var pattern_to_store = document.getElementById("Pattern" + pattern_input).value;
1946 var replacement_to_store = document.getElementById("Replacement" + pattern_input).value;
1949 if (pattern_to_store === "") {
1950 localStorage.removeItem(pattern_input + "FLT");
1953 else if (new RegExp("^\/.*\/\\D+$").test(pattern_to_store)) { }
1954 else if (new RegExp("^\/.*\/$").test(pattern_to_store)) {
1955 pattern_to_store = pattern_to_store + setting;
1957 else if (!new RegExp("^/.*\/\\D$").test(pattern_to_store)) {
1958 pattern_to_store = "/" + pattern_to_store + "/" + setting;
1960 //test for breakages, try to cause error
1961 var error_test = new RegExp(pattern_to_store.substring(0, pattern_to_store.lastIndexOf("/") + 1), pattern_to_store.substring(pattern_to_store.lastIndexOf("/") + 1));
1964 Generics.alert4ChanX("Unrecoverable Regex error on pattern " + pattern_input + " for " + pattern_to_store, "error", undefined);
1967 pattern_to_store = encodeURIComponent(pattern_to_store);
1968 var save_string = document.getElementById("Active" + pattern_input).checked + '=' + pattern_to_store + '=' + replacement_to_store;
1969 window.localStorage.setItem(pattern_input + "FLT", save_string);
1971 Generics.alert4ChanX("Wordfilters Updated!", "success", 3);
1974 SettingsWindow.prototype.storeImageAdderStates = function () {
1975 if (document.getElementById("SetImageAdderProperties") !== null) {
1976 var width = document.getElementById("width_DIA").value;
1977 localStorage.setItem("width_DIA", width);
1978 var height = document.getElementById("height_DIA").value;
1979 localStorage.setItem("height_DIA", height);
1980 var qr_width = document.getElementById("qr_width_DIA").value;
1981 localStorage.setItem("qr_width_DIA", qr_width);
1984 SettingsWindow.prototype.storeRebuildStates = function () {
1985 if (document.getElementById("setArchive") !== null) {
1986 localStorage.setItem("ArchiveType_FSE", document.getElementById("OffsiteArchive").checked === true ? "0" : "1");
1989 SettingsWindow.prototype.storeCharacterInserterStates = function () {
1990 if (document.getElementById("setCharacter") !== null) {
1991 localStorage.setItem("Kita_Character", document.getElementById("selectiveCharacters").value);
1992 localStorage.setItem("Kita_Color", document.getElementById("HexColorKita_text").value);
1994 else if (document.getElementById("setQuote") !== null) {
1995 localStorage.setItem("Yen_Character", document.getElementById("quoteCharacter").value);
1996 localStorage.setItem("Yen_Color", document.getElementById("HexColorYen_text").value);
1999 SettingsWindow.prototype.storePasswordStates = function () {
2000 //password view settings
2001 if (document.getElementById("check-settings6") !== null)
2002 localStorage.setItem("PasswordActive", "" + document.getElementById("check-settings6").checked);
2004 SettingsWindow.prototype.clearContainer = function () {
2005 var disposable = document.getElementById("disposable_container");
2006 if (disposable !== null)
2007 this.contents_div.removeChild(disposable);
2009 this.contents_div.removeChild(this.ul_selection_start);
2011 SettingsWindow.prototype.rebuildContainer = function () {
2012 this.contents_div.appendChild(this.ul_selection_start);
2014 SettingsWindow.prototype.init = function () {
2016 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}";
2017 this.background_div.setAttribute('class', 'SettingsBackground');
2018 this.background_div.setAttribute('id', 'SettingsBackground');
2019 this.background_div.setAttribute('style', 'display:none');
2020 this.settings_div.setAttribute('class', 'settingsMain');
2021 this.settings_div.setAttribute('id', 'settingsWindow');
2022 this.settings_div.setAttribute('style', 'display:none;width:500px');
2023 this.close_link.setAttribute('href', 'javascript:void(0)');
2024 this.close_div.setAttribute('class', 'closeIcon');
2025 this.close_div.addEventListener('click', function (evt) { return _this.hideWindow(); });
2026 this.title_para.setAttribute('class', 'titleStyle');
2027 this.contents_div.setAttribute('class', 'contentStyle');
2028 this.end_para.setAttribute('class', 'footerStyle');
2029 this.ul_selection_start.setAttribute("ID", "selection_list");
2030 this.generateList(this.contents_div);
2032 SettingsWindow.prototype.generateList = function (head_node) {
2034 this.list_items.forEach(function (list_item, index) {
2035 var li = document.createElement('LI');
2036 li.setAttribute('class', 'settingsItem');
2037 if (list_item.Text.indexOf('View') > -1) {
2038 var input = document.createElement('INPUT');
2039 var input_id = 'check-settings' + index;
2040 input.setAttribute('TYPE', 'checkbox');
2041 input.setAttribute('ID', 'check-settings' + index);
2042 li.appendChild(input);
2043 input.addEventListener('click', function (evt) { return _this.storeActiveToggles(); });
2044 var a = document.createElement('A');
2045 a.setAttribute('href', 'javascript:void(0)');
2046 a.textContent = list_item.Text;
2047 var a_id = 'tab-settings' + index;
2048 a.setAttribute('ID', 'tab-settings' + index);
2049 var setup_func = function (_a_id) {
2050 a.addEventListener('click', function (evt) { return list_item.ListenerFunc(_a_id); });
2052 _this.ul_selection_start.appendChild(li);
2057 var input = document.createElement('INPUT');
2058 var input_id = 'check-settings' + index;
2059 input.setAttribute('TYPE', 'checkbox');
2060 input.setAttribute('ID', 'check-settings' + index);
2061 input.addEventListener('click', function (evt) { return _this.storeActiveToggles(); });
2062 li.appendChild(input);
2063 var label = document.createElement('LABEL');
2064 label.textContent = list_item.Text;
2065 li.appendChild(label);
2066 _this.ul_selection_start.appendChild(li);
2067 input.checked = _this.setting_items.password_settings == 'true';
2068 var setup_func = function (input_id) {
2069 label.addEventListener('click', function (evt) { return list_item.ListenerFunc(input_id); });
2071 setup_func(input_id);
2075 SettingsWindow.prototype.activate = function () {
2077 document.body.appendChild(this.settings_style);
2078 this.background_div.addEventListener('click', function (evt) { return _this.hideWindow(); });
2079 document.body.appendChild(this.background_div);
2080 this.settings_div.appendChild(this.close_link);
2081 this.close_link.appendChild(this.close_div);
2082 this.title_para.appendChild(this.title_text);
2083 this.settings_div.appendChild(this.title_para);
2084 this.settings_div.appendChild(this.contents_div);
2085 this.contents_div.appendChild(this.ul_selection_start);
2086 this.end_para.appendChild(this.end_text);
2087 this.settings_div.appendChild(this.end_para);
2088 document.body.appendChild(this.settings_div);
2089 this.retrieveActiveToggles();
2091 SettingsWindow.prototype.decideAction = function (node) { };
2092 SettingsWindow.prototype.getSettingsArr = function () {
2093 return this.setting_items;
2095 SettingsWindow.prototype.displayWindow = function () {
2096 this.background_div.style.display = 'block';
2097 this.settings_div.style.display = 'block';
2098 this.rebuildContainer();
2100 SettingsWindow.prototype.hideWindow = function () {
2101 this.background_div.style.display = 'none';
2102 this.settings_div.style.display = 'none';
2103 this.clearContainer();
2105 SettingsWindow.prototype.filterWindow = function (disposable_container) {
2107 var filter_table = document.createElement("table");
2108 filter_table.setAttribute("style", "text-align:center;");
2109 filter_table.setAttribute("id", "filter_table");
2110 disposable_container.appendChild(filter_table);
2111 var table_head_active = document.createElement("th");
2112 var head_text_active = document.createTextNode("Active");
2113 table_head_active.appendChild(head_text_active);
2114 filter_table.appendChild(table_head_active);
2115 var table_head_pattern = document.createElement("th");
2116 var headTextPattern = document.createTextNode("Pattern");
2117 table_head_pattern.appendChild(headTextPattern);
2118 filter_table.appendChild(table_head_pattern);
2119 var table_head_replacement = document.createElement("th");
2120 var head_text_replacement = document.createTextNode("Replacement");
2121 table_head_replacement.appendChild(head_text_replacement);
2122 filter_table.appendChild(table_head_replacement);
2123 //Create the pattern table
2124 //loop to create rows
2125 var number_of_filters = parseInt(this.setting_items.word_replace_settings.number_of_filters);
2126 if (number_of_filters === 0 || isNaN(number_of_filters))
2127 number_of_filters = 6;
2128 for (var i = 0; i < number_of_filters; i++) {
2129 var table_row_contents = document.createElement("tr");
2130 table_row_contents.setAttribute("id", "FilterRow" + i);
2131 var table_data_active = document.createElement("td");
2132 var table_checkbox_active = document.createElement("input");
2133 table_checkbox_active.setAttribute("type", "checkbox");
2134 table_checkbox_active.setAttribute("id", "Active" + i);
2135 table_data_active.appendChild(table_checkbox_active);
2136 table_row_contents.appendChild(table_data_active);
2137 var table_data_pattern = document.createElement("td");
2138 var table_input_pattern = document.createElement("input");
2139 table_input_pattern.setAttribute("class", "inputs");
2140 table_input_pattern.setAttribute("id", "Pattern" + i);
2141 table_data_pattern.appendChild(table_input_pattern);
2142 table_row_contents.appendChild(table_data_pattern);
2143 var table_data_replacement = document.createElement("td");
2144 var table_input_replacement = document.createElement("input");
2145 table_input_replacement.setAttribute("class", "inputs");
2146 table_input_replacement.setAttribute("id", "Replacement" + i);
2147 table_data_replacement.appendChild(table_input_replacement);
2148 table_row_contents.appendChild(table_data_replacement);
2149 filter_table.appendChild(table_row_contents);
2151 var table_last_contents = document.createElement("tr");
2152 var table_add_collumn = document.createElement("td");
2153 var table_add_row_button = document.createElement("input");
2154 var table_subtract_row_button = document.createElement("input");
2155 table_subtract_row_button.setAttribute("type", "button");
2156 table_subtract_row_button.setAttribute("value", "-");
2157 table_subtract_row_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2158 table_add_collumn.appendChild(table_subtract_row_button);
2159 table_subtract_row_button.addEventListener("click", function (evt) { return _this.filterRemoveRow(); });
2160 table_add_row_button.setAttribute("type", "button");
2161 table_add_row_button.setAttribute("value", "+");
2162 table_add_row_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2163 table_add_collumn.appendChild(table_add_row_button);
2164 table_add_row_button.addEventListener("click", function (evt) { return _this.filterAddRow(); });
2165 table_last_contents.appendChild(table_add_collumn);
2166 var table_set_collumn = document.createElement("td");
2167 var table_confirm_button = document.createElement("input");
2168 table_confirm_button.setAttribute("type", "button");
2169 table_confirm_button.setAttribute("id", "table_confirm_button");
2170 table_confirm_button.setAttribute("value", "Set Replacements");
2171 table_confirm_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2173 table_confirm_button.addEventListener("click", function (evt) {
2174 _this.storeStates();
2175 _this.clearContainer();
2176 _this.rebuildContainer();
2178 table_set_collumn.appendChild(table_confirm_button);
2179 table_last_contents.appendChild(table_set_collumn);
2180 var table_close_collumn = document.createElement("td");
2181 var table_close_button = document.createElement("input");
2182 table_close_button.setAttribute("type", "button");
2183 table_close_button.setAttribute("value", "Close Without Saving");
2184 table_close_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2185 table_close_button.addEventListener("click", function (evt) {
2186 _this.clearContainer();
2187 _this.rebuildContainer();
2189 table_close_collumn.appendChild(table_close_button);
2190 table_last_contents.appendChild(table_close_collumn);
2191 filter_table.appendChild(table_last_contents);
2193 SettingsWindow.prototype.filterAddRow = function () {
2195 var number_of_filters = parseInt(this.setting_items.word_replace_settings.number_of_filters);
2196 var filter_table = document.getElementById("filter_table");
2197 filter_table.deleteRow(number_of_filters + 1);
2198 var table_row_contents = document.createElement("tr");
2199 table_row_contents.setAttribute("id", "FilterRow" + (number_of_filters));
2200 var table_data_active = document.createElement("td");
2201 var table_checkbox_active = document.createElement("input");
2202 table_checkbox_active.setAttribute("type", "checkbox");
2203 table_checkbox_active.setAttribute("id", "Active" + (number_of_filters));
2204 table_data_active.appendChild(table_checkbox_active);
2205 table_row_contents.appendChild(table_data_active);
2206 var table_data_pattern = document.createElement("td");
2207 var table_input_pattern = document.createElement("input");
2208 table_input_pattern.setAttribute("class", "inputs");
2209 table_input_pattern.setAttribute("id", "Pattern" + (number_of_filters));
2210 table_data_pattern.appendChild(table_input_pattern);
2211 table_row_contents.appendChild(table_data_pattern);
2212 var table_data_replacement = document.createElement("td");
2213 var table_input_replacement = document.createElement("input");
2214 table_input_replacement.setAttribute("class", "inputs");
2215 table_input_replacement.setAttribute("id", "Replacement" + (number_of_filters));
2216 table_data_replacement.appendChild(table_input_replacement);
2217 table_row_contents.appendChild(table_data_replacement);
2218 filter_table.appendChild(table_row_contents);
2219 var table_last_contents = document.createElement("tr");
2220 var table_add_collumn = document.createElement("td");
2221 var table_add_row_button = document.createElement("input");
2222 var table_subtract_row_button = document.createElement("input");
2223 table_subtract_row_button.setAttribute("type", "button");
2224 table_subtract_row_button.setAttribute("value", "-");
2225 table_subtract_row_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2226 table_add_collumn.appendChild(table_subtract_row_button);
2227 table_subtract_row_button.addEventListener("click", function (evt) { return _this.filterRemoveRow(); });
2228 table_add_row_button.setAttribute("type", "button");
2229 table_add_row_button.setAttribute("value", "+");
2230 table_add_row_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2231 table_add_collumn.appendChild(table_add_row_button);
2232 table_add_row_button.addEventListener("click", function (evt) { return _this.filterAddRow(); });
2233 table_last_contents.appendChild(table_add_collumn);
2234 var table_set_collumn = document.createElement("td");
2235 var table_confirm_button = document.createElement("input");
2236 table_confirm_button.setAttribute("type", "button");
2237 table_confirm_button.setAttribute("id", "table_confirm_button");
2238 table_confirm_button.setAttribute("value", "Set Replacements");
2239 table_confirm_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2241 table_confirm_button.addEventListener("click", function (evt) {
2242 _this.storeStates();
2243 _this.clearContainer();
2244 _this.rebuildContainer();
2246 table_set_collumn.appendChild(table_confirm_button);
2247 table_last_contents.appendChild(table_set_collumn);
2248 var table_close_collumn = document.createElement("td");
2249 var table_close_button = document.createElement("input");
2250 table_close_button.setAttribute("type", "button");
2251 table_close_button.setAttribute("value", "Close Without Saving");
2252 table_close_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2253 table_close_button.addEventListener("click", function (evt) {
2254 _this.clearContainer();
2255 _this.rebuildContainer();
2257 table_close_collumn.appendChild(table_close_button);
2258 table_last_contents.appendChild(table_close_collumn);
2259 filter_table.appendChild(table_last_contents);
2261 SettingsWindow.prototype.filterRemoveRow = function () {
2262 var number_of_filters = parseInt(this.setting_items.word_replace_settings.number_of_filters);
2263 var filter_table = document.getElementById("filter_table");
2264 if (number_of_filters != 0) {
2265 filter_table.deleteRow(number_of_filters);
2266 number_of_filters--;
2269 SettingsWindow.prototype.filterSetTable = function () {
2270 var filter_length = this.setting_items.word_replace_settings.Text_Filter_List.length;
2271 for (var filter_count = 0; filter_count < filter_length; filter_count++) {
2272 if (this.setting_items.word_replace_settings.Text_Filter_List[filter_count].Active === null ||
2273 this.setting_items.word_replace_settings.Text_Filter_List[filter_count].Regex === null ||
2274 this.setting_items.word_replace_settings.Text_Filter_List[filter_count].Replacement === null)
2276 if (this.setting_items.word_replace_settings.Text_Filter_List[filter_count].Active === "true") {
2277 document.getElementById("Active" + filter_count).checked = true;
2280 document.getElementById("Active" + filter_count).checked = false;
2282 document.getElementById("Pattern" + filter_count).value =
2283 this.setting_items.word_replace_settings.Text_Filter_List[filter_count].Regex;
2284 document.getElementById("Replacement" + filter_count).value =
2285 this.setting_items.word_replace_settings.Text_Filter_List[filter_count].Replacement;
2288 return SettingsWindow;
2289 }(FeatureInterface));
2290 var Main = /** @class */ (function (_super) {
2291 __extends(Main, _super);
2293 var _this = _super.call(this) || this;
2294 _this.features = {}; /*;any bypasses dot notation issues on objects*/
2295 _this.settings = {};
2296 if (!Generics.storageAvailable('localStorage')) {
2297 alert("4F-FSE: local storage error");
2302 _this.retrieveStates();
2304 _this.decideAction(document.getElementById('delform'));
2305 _this.observeEvents();
2308 Main.prototype.retrieveStates = function () {
2309 var top_bar = new TopBar();
2311 this.settings = top_bar.getSettingsArr();
2313 Main.prototype.init = function () {
2314 if (this.settings.image_hiding_settings.Active) {
2315 this.features.image_hider = new ImageHider();
2317 if (this.settings.word_replace_settings.Active) {
2318 this.features.text_replacer = new TextReplacer();
2320 if (this.settings.image_adder_settings.Active) {
2321 this.features.danbooru_image_adder = new DanbooruImageAdder();
2323 if (this.settings.thread_rebuild_settings.Active) {
2324 this.features.thread_rebuilder = new ThreadRebuilder();
2326 if (this.settings.character_inserter_settings.Yen_Active || this.settings.character_inserter_settings.Kita_Active) {
2327 this.features.character_inserter = new CharacterInserter(this.settings.character_inserter_settings.Yen_Active, this.settings.character_inserter_settings.Kita_Active);
2329 if (this.settings.password_settings == 'true') {
2330 this.features.password_viewer = new PasswordViewer();
2332 for (var feature_key in this.features)
2333 this.features[feature_key].retrieveStates();
2335 Main.prototype.activate = function () { console.log("4F-FSE Starting"); };
2336 Main.prototype.storeStates = function () { };
2337 Main.prototype.observeEvents = function () {
2339 var document_changes = new MutationObserver(function (mutations) {
2340 mutations.forEach(function (mutation) {
2341 [].forEach.call(mutation.addedNodes, function (node) { return _this.decideAction(node); });
2343 }).observe(document.body, { childList: true, subtree: true });
2345 Main.prototype.decideAction = function (node) {
2346 if (node === undefined || node.tagName === undefined)
2349 var itterator = document.createNodeIterator(start, NodeFilter.SHOW_ELEMENT);
2351 while ((node = itterator.nextNode())) {
2352 if (node.tagName !== "BLOCKQUOTE" && node.tagName !== "IMG")
2354 for (var feature_key in this.features) {
2355 this.features[feature_key].decideAction(node);
2360 }(FeatureInterface));
2361 document.addEventListener('4chanXInitFinished', function () { new Main(); });