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.listener_obj = {};
200 _this.retrieveStates();
205 //retrieve from memory the hidden images
206 //Images are stored in memory as f<ID_NUMBER>IMG and recalled using the storage_key
207 //Function makes a check to see if the hiding time limit for the thread has expired or not.
208 //Note: Must have the DOM itterate through before retrieval
209 ImageHider.prototype.retrieveStates = function () {
211 var storage_position = 0;
212 var JSON_storage = {}; /*;any bypasses dot notation issues on objects*/
214 var local_store_size = window.localStorage.length;
215 while (storage_position < local_store_size) {
216 storage_key = window.localStorage.key(storage_position);
217 JSON_storage[storage_key] = window.localStorage.getItem(storage_key);
220 this.threads_to_hide = Generics.getJSONPropertiesByKeyName(JSON_storage, '[0-9]+IMG');
221 //aquire each time to check for changes
222 this.hide_expiration_time = parseInt(JSON_storage.Expiration_Time);
223 if (this.hide_expiration_time === null)
224 this.hide_expiration_time = Constants.DEFAULT_HIDE_EXPIRATION_TIME;
225 var md5_filters = JSON_storage.MD5_List_FSE;
226 if (md5_filters !== undefined && md5_filters !== null) {
227 this.md5_filters_arr = md5_filters.split('\n');
228 //remove trailing and starting slash
229 this.md5_filters_arr.forEach(function (md5, index) {
231 _this.md5_filters_arr[index] = md5.substring(1, md5.length - 1);
235 ImageHider.prototype.storeStates = function () {
237 for (var _i = 0; _i < arguments.length; _i++) {
238 item_pairs[_i] = arguments[_i];
240 window.localStorage.setItem(item_pairs[0], item_pairs[1]);
242 ImageHider.prototype.init = function () {
243 this.hotkeyListeners();
245 //hide image onclick listener.
246 //Method 404's a given image. This 404'ing allows image dissabling to be toggled on and off.
247 //Post number associated with the image is stored in local storage.
248 ImageHider.prototype.hideOnClick = function (event) {
250 var is_hidden = event.target.src.substring(21, 29) == ",iVBORw0";
252 if ((this.listener_obj[17] && this.listener_obj[16]) && !is_hidden) {
253 event.preventDefault();
254 event.stopPropagation();
255 hide_group_id = event.target.getAttribute('hide-grouping');
256 this.storeStates(hide_group_id, "" + Date.now());
257 [].slice.call(document.querySelectorAll('img[hide-grouping="' + hide_group_id + '"]')).forEach(function (image_node) {
258 image_node.setAttribute('hidden-src', image_node.src);
259 image_node.src = _this.blank_png;
262 else if (this.listener_obj[17] && this.listener_obj[16]) {
263 event.preventDefault();
264 event.stopPropagation();
265 hide_group_id = event.target.getAttribute('hide-grouping');
266 window.localStorage.removeItem(hide_group_id);
267 event.target.src = event.target.getAttribute('hidden-src');
268 [].slice.call(document.querySelectorAll('img[hide-grouping="' + hide_group_id + '"]')).forEach(function (image_node) {
269 image_node.src = image_node.getAttribute('hidden-src');
272 this.retrieveStates();
275 //hotkeys for ctrl[17] and shift[16]
276 ImageHider.prototype.hotkeyListeners = function () {
278 window.addEventListener("keydown", function (e) {
279 _this.listener_obj[e.keyCode] = true;
280 }, { passive: false, capture: false, once: false });
281 window.addEventListener("keyup", function (e) {
282 _this.listener_obj[e.keyCode] = false;
283 }, { passive: false, capture: false, once: false });
285 ImageHider.prototype.decideAction = function (node) {
286 //tagname is always upper in HTML, in xml it's displayed as written.
287 if (node.tagName === 'IMG' || node.tagName === 'VIDEO') {
288 if (node.id === "ihover") {
289 this.hideHoverImageNode(node);
292 if (node.getAttribute('data-md5') !== null) {
293 this.hideImageNode(node);
298 ImageHider.prototype.activate = function () {
299 console.log("4F-FSE: ImageHider Active");
301 ImageHider.prototype.hideImageNode = function (image_node) {
303 var sister_node = image_node.parentNode.parentNode.parentNode.getElementsByClassName('catalog-thumb')[0]; // the catalog sister to index
304 var sister_node_non_exist = false;
305 if (sister_node === undefined) {
306 sister_node_non_exist = true;
308 var image_node_already_run = false;
309 if (/\d+IMG/.test(image_node.getAttribute('hide-grouping'))) {
310 image_node_already_run = true;
311 if (!sister_node_non_exist) {
312 if (/\d+IMG/.test(sister_node.getAttribute('hide-grouping'))) {
317 if (!image_node_already_run)
318 image_node.setAttribute('hide-grouping', image_node.parentNode.parentNode.id.substring(1) + 'IMG');
319 if (!sister_node_non_exist)
320 sister_node.setAttribute('hide-grouping', image_node.parentNode.parentNode.id.substring(1) + 'IMG');
321 if (!image_node_already_run)
322 image_node.addEventListener('click', function (evt) { return _this.hideOnClick(evt); });
323 if (!sister_node_non_exist)
324 sister_node.addEventListener('click', function (evt) { return _this.hideOnClick(evt); });
325 var threadstore_len = this.threads_to_hide.length;
326 var node_group_id = image_node.getAttribute('hide-grouping');
327 for (var thread = 0; thread < threadstore_len; thread++) {
328 if (node_group_id == this.threads_to_hide[thread]) {
329 if (!image_node_already_run) {
330 image_node.setAttribute('hidden-src', image_node.src);
331 image_node.src = this.blank_png;
333 if (!sister_node_non_exist) {
334 sister_node.setAttribute('hidden-src', sister_node.src);
335 sister_node.src = this.blank_png;
340 //index node holds the MD5
341 var node_md5 = image_node.getAttribute('data-md5');
342 if (this.md5_filters_arr !== undefined) {
343 var md5_filters_arr_len = this.md5_filters_arr.length;
344 for (var md5 = 0; md5 < md5_filters_arr_len; md5++) {
345 if (node_md5 == this.md5_filters_arr[md5]) {
346 this.threads_to_hide.push();
347 if (!image_node_already_run) {
348 image_node.setAttribute('hidden-src', image_node.src);
349 image_node.src = this.blank_png;
351 if (!sister_node_non_exist) {
352 sister_node.setAttribute('hidden-src', sister_node.src);
353 sister_node.src = this.blank_png;
360 ImageHider.prototype.hideHoverImageNode = function (image_node) {
361 var unprocessed_id = image_node.getAttribute('data-full-i-d');
362 var proccessed_id = unprocessed_id.substring(unprocessed_id.indexOf('.') + 1);
363 var image_node_id = proccessed_id + 'IMG';
364 if (image_node === undefined)
366 for (var thread = 0, threadstore_len = this.threads_to_hide.length; thread < threadstore_len; thread++) {
367 if (image_node_id == this.threads_to_hide[thread]) {
368 image_node.removeAttribute('src');
372 //thread node holds the MD5
374 // if(is_embeded_post) node_md5 = image_node.getAttribute('data-md5');
375 /*else */ node_md5 = document.getElementById('f' + proccessed_id).getElementsByTagName('IMG')[0].getAttribute('data-md5');
376 if (this.md5_filters_arr !== undefined) {
377 for (var md5 = 0, md5_filters_arr_len = this.md5_filters_arr.length; md5 < md5_filters_arr_len; md5++) {
378 if (node_md5 == this.md5_filters_arr[md5]) {
379 image_node.removeAttribute('src');
386 }(FeatureInterface));
387 var TextReplacer = /** @class */ (function (_super) {
388 __extends(TextReplacer, _super);
389 function TextReplacer() {
390 var _this = _super.call(this) || this;
391 _this.text_filters = []; //object
392 _this.filtered_threads = [];
393 _this.retrieveStates();
398 TextReplacer.prototype.init = function () {
399 this.filtered_threads = [];
402 TextReplacer.prototype.activate = function () { console.log("4F-FSE: TextReplacer Active"); };
403 TextReplacer.prototype.decideAction = function (node) {
404 if (node.tagName == "BLOCKQUOTE") {
405 if (node.className == "postMessage") {
406 var blockquote_id = node.id;
407 var already_filtered = false;
408 this.filtered_threads.forEach(function (thread_id) {
409 if (thread_id == blockquote_id) {
410 already_filtered = true;
417 if (!already_filtered && this.text_filters.length !== 0) {
418 var itterator = document.createNodeIterator(node, NodeFilter.SHOW_TEXT);
420 while ((localNode = itterator.nextNode())) {
421 for (var filter = 0; filter < this.number_of_filters; filter++) {
422 if (this.text_filters[filter].Active === "true") {
423 var last_slash_index = this.text_filters[filter].Regex.lastIndexOf("/");
424 var filter_text = this.text_filters[filter].Regex.substring(1, last_slash_index);
425 var flag = this.text_filters[filter].Regex.substring(last_slash_index + 1);
426 var regex = new RegExp(filter_text, flag);
427 var node_text = localNode.textContent;
428 if (regex.test(node_text)) {
429 localNode.textContent = node_text.replace(regex, this.text_filters[filter].Replacement);
430 this.filtered_threads.push(blockquote_id);
438 TextReplacer.prototype.retrieveStates = function () {
440 var storage_index = 0;
441 var JSON_storage = {};
443 while (storage_index < window.localStorage.length) {
444 storage_key = window.localStorage.key(storage_index);
445 JSON_storage[storage_key] = window.localStorage.getItem(storage_key);
448 this.number_of_filters = JSON_storage["filter_quantity"];
449 var filters = Generics.getJSONPropertiesByKeyName(JSON_storage, "[0-9]+FLT");
451 filters.forEach(function (filter) {
452 _this.text_filters.push(TextReplacer.formatFilterSettings(JSON_storage[filter]));
455 //Splits the saved settings into components
456 TextReplacer.formatFilterSettings = function (input) {
457 var processed_input = (input.split('=')).map(function (x) { return decodeURIComponent(x); });
458 return { Active: processed_input[0], Regex: processed_input[1], Replacement: processed_input[2] };
460 TextReplacer.prototype.storeStates = function () { };
462 }(FeatureInterface));
463 var DanbooruImageAdder = /** @class */ (function (_super) {
464 __extends(DanbooruImageAdder, _super);
465 function DanbooruImageAdder() {
466 var _this = _super.call(this) || this;
467 _this.timeout_functions = [];
469 _this.post_number = 0;
470 _this.page_number = 0;
471 _this.json_page_numbers_used = [];
472 _this.previous_images = [];
473 _this.json_numbers_used = [];
474 _this.previous_page = 9001;
475 _this.subdomain_regex = new RegExp("http(|s)://");
476 _this.maximum_attempts = 20;
482 DanbooruImageAdder.prototype.init = function () {
484 this.time = this.time_max;
485 this.number_of_attempts = this.maximum_attempts;
486 document.addEventListener("QRDialogCreation", function (evt) {
487 _this.enhance4ChanX_HTML();
488 _this.enhanced4ChanXListeners();
491 DanbooruImageAdder.prototype.enhance4ChanX_HTML = function () {
492 var qr_window = document.getElementById("qr");
493 /*Should I auto open things for the user?*/
494 // var imagedump_opener:any = document.getElementById("dump-button");
495 // if(imagedump_opener !== null){imagedump_opener.click();}
497 //image setting html elements.
498 var qr_image_adder_table = document.createElement("TABLE");
499 qr_image_adder_table.setAttribute("id", "qrImages");
500 qr_image_adder_table.setAttribute("style", "text-align:center");
501 qr_window.appendChild(qr_image_adder_table);
502 var options_row = document.createElement("TR");
503 options_row.setAttribute("ID", "or");
504 options_row.setAttribute("style", "margin:5px;");
505 qr_image_adder_table.appendChild(options_row);
506 var checkbox_safe = document.createElement("INPUT");
507 checkbox_safe.setAttribute("id", "safe");
508 checkbox_safe.setAttribute("type", "checkbox");
509 checkbox_safe.checked = true;
510 var checkbox_safe_text = document.createTextNode("Safe");
511 var checkbox_questionable = document.createElement("INPUT");
512 checkbox_questionable.setAttribute("id", "questionable");
513 checkbox_questionable.setAttribute("type", "checkbox");
514 var checkbox_questionable_text = document.createTextNode("Questionable");
515 var checkbox_explicit = document.createElement("INPUT");
516 checkbox_explicit.setAttribute("id", "explicit");
517 checkbox_explicit.setAttribute("type", "checkbox");
518 var checkbox_explicit_text = document.createTextNode("Explicit");
519 options_row.appendChild(checkbox_safe_text);
520 options_row.appendChild(checkbox_safe);
521 options_row.appendChild(checkbox_questionable_text);
522 options_row.appendChild(checkbox_questionable);
523 options_row.appendChild(checkbox_explicit_text);
524 options_row.appendChild(checkbox_explicit);
525 var image_tagging_row = document.createElement("TR");
526 this.help_icon_container = document.createElement("A");
527 this.help_icon_container.href = "javascript:void(0)";
528 this.help_icon_container.title = "Click to View Help!";
529 var help_icon = document.createElement("IMG");
530 help_icon.setAttribute("class", "help_icon");
531 help_icon.src = Constants.HELP_ICON_SOURCE;
532 this.help_icon_container.appendChild(help_icon);
533 image_tagging_row.appendChild(this.help_icon_container);
534 var tooltip_div = document.createElement("DIV");
535 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>";
536 (tooltip_div).setAttribute("class", "tooltip-4F");
537 (tooltip_div).setAttribute("id", "tooltipIA");
538 qr_window.appendChild(tooltip_div);
539 var second_row_nodes = [
540 document.createTextNode("Tags: "),
541 document.createElement("INPUT"),
542 document.createElement("INPUT"),
543 document.createElement("A"),
544 document.createElement("INPUT"),
546 second_row_nodes.forEach(function (node) {
547 image_tagging_row.appendChild(node);
549 qr_image_adder_table.appendChild(image_tagging_row);
550 var auto_complete_row = document.createElement("TR");
551 auto_complete_row.setAttribute("ID", "auto-complete-row");
552 auto_complete_row.setAttribute("style", "margin:5px;");
553 qr_image_adder_table.appendChild(auto_complete_row);
554 second_row_nodes[1].setAttribute("ID", "tag_input");
555 var option_text_size = 18;
556 second_row_nodes[1].setAttribute("style", "width:44.9%;" + "font-size:" + option_text_size + "px");
557 second_row_nodes[3].setAttribute("ID", "timer");
558 second_row_nodes[3].setAttribute("style", "width:20%;margin:0 5px");
559 second_row_nodes[4].setAttribute("ID", "urlContainer");
560 second_row_nodes[4].setAttribute("style", "width:75%;margin:5px -25px");
561 second_row_nodes[4].setAttribute("disabled", "");
562 second_row_nodes[2].setAttribute("ID", "imageButton");
563 second_row_nodes[2].setAttribute("type", "button");
564 second_row_nodes[2].setAttribute("value", "Set Image");
565 //textarea expansion;
566 qr_window.getElementsByTagName("TEXTAREA")[0].style.width = "110%";
567 qr_window.appendChild(document.createElement("hr"));
569 DanbooruImageAdder.prototype.enhanced4ChanXListeners = function () {
571 this.highQualityImages();
572 document.getElementById("qr-filerm").addEventListener("click", function (evt) { return _this.clearImage(); });
573 var qr_reference = document.getElementById("qr");
574 var tooltip_div = document.getElementById("tooltipIA");
575 this.help_icon_container.addEventListener("click", function (evt) {
576 if (_this.tool_tip_visible)
577 tooltip_div.setAttribute("style", "z-index:9;padding:5px;border:1px solid black;background-color:white;word-wrap:break-word;display:none;position:absolute;");
579 tooltip_div.setAttribute("style", "z-index:9;padding:5px;border:1px solid black;background-color:white;word-wrap:break-word;display:block;position:absolute;"
580 + "left:" + (evt.clientX - qr_reference.getBoundingClientRect().x) +
581 "px;top:" + (evt.clientY - qr_reference.getBoundingClientRect().y) + "px;");
582 _this.tool_tip_visible = !_this.tool_tip_visible;
584 var tag_input = document.getElementById("tag_input");
585 tag_input.addEventListener("input", function (evt) {
586 _this.setTagInterface(tag_input, document.getElementById("auto-complete-row"));
588 document.getElementById("imageButton").addEventListener("click", function (evt) { return _this.activate(); });
590 DanbooruImageAdder.prototype.highQualityImages = function () {
592 var imagedump_file_list = document.getElementById("dump-list");
593 //used for setting and unsetting high resolution thumbs for dump list.
594 var dumplist_image = "";
595 var previous_dumplist_image = "";
596 var observer = new MutationObserver(function (mutate) {
597 dumplist_image = imagedump_file_list.firstChild.style.backgroundImage;
598 if (dumplist_image !== previous_dumplist_image && _this.img_URL !== "") {
599 imagedump_file_list.firstChild.style.backgroundImage = "url(" + _this.img_URL + ")";
600 previous_dumplist_image = imagedump_file_list.firstChild.style.backgroundImage;
602 else if (_this.img_URL == "") { }
604 observer.observe(imagedump_file_list, { attributes: true, subtree: true, childList: true, characterData: true });
606 DanbooruImageAdder.prototype.activate = function () {
608 //on setimage click clear flags, timers and start another search
609 this.json_page_numbers_used = Array();
610 this.previous_page = 9001;
611 //reset a failed_to_find_required_tags boolean
612 this.primed_for_fail = false;
613 for (var i = 0; i < this.timeout_functions.length; i++) {
614 clearInterval(this.timeout_functions[i]);
616 this.tag_incorrect_state = false;
617 this.timeout = false;
618 //freeze interface to prevent mid opperation changes
619 document.getElementById("tag_input").setAttribute("disabled", "1");
620 document.getElementById("imageButton").setAttribute("disabled", "1");
621 this.time = this.time_max;
622 this.timeout_functions.push(setInterval(function () { return _this.counterFunction(); }, 1000));
626 //remove the high quallity image from the dump list
627 DanbooruImageAdder.prototype.clearImage = function () {
628 var imagedump_file_list = document.getElementById("dump-list");
629 imagedump_file_list.firstChild.style.backgroundImage = "url()"; //trigger mutation event
630 this.img_URL = ""; //get mutation to set to dead
632 DanbooruImageAdder.prototype.setTagInterface = function (tag_input_node, auto_complete_row) {
633 var tags = tag_input_node.value;
634 if (this.old_tags_before_change !== tags) {
635 this.previous_images = [];
636 var tag_carat_position = tag_input_node.selectionStart - 1;
637 var closest_tag = (function () {
638 var current_chararcter = tags.charAt(tag_carat_position);
640 var right_most = tag_carat_position;
641 while (current_chararcter != " " && current_chararcter != "" && current_chararcter !== undefined) {
643 current_chararcter = tags.charAt(tag_carat_position + i);
644 if (current_chararcter != " " && current_chararcter != "")
645 right_most = tag_carat_position + i;
648 current_chararcter = tags.charAt(tag_carat_position);
650 var leftMost = tag_carat_position;
651 while (current_chararcter != " " && current_chararcter != "" && current_chararcter !== undefined) {
653 current_chararcter = tags.charAt(tag_carat_position - i);
654 if (current_chararcter != " " && current_chararcter != "")
655 leftMost = tag_carat_position - i;
657 return tags.substring(leftMost, right_most);
659 var xhr = new GM_xmlhttpRequest(({
661 url: "https://danbooru.donmai.us/tags.json?search[name_matches]=" + closest_tag + "*&search[order]=count",
662 responseType: "json",
663 onload: function (data) {
664 data = data.response;
665 var tagArray = tags.split(" ");
666 while (auto_complete_row.hasChildNodes()) {
667 auto_complete_row.removeChild(auto_complete_row.lastChild);
669 var qr_width = document.getElementById("qr").offsetWidth;
670 var tag_table = document.createElement("TABLE");
671 tag_table.setAttribute("style", "border:1px solid black;margin-top:5px");
672 var tag_row = document.createElement("TR");
673 for (var i = 0; i < 5; i++) {
674 var a = document.createElement("A");
675 var tagText = data["" + i];
676 if (tagText == "" || tagText === undefined)
678 tagText = tagText["name"];
679 var a_txt = document.createTextNode(data[i]["name"]);
680 var tag_data = document.createElement("TD");
681 tag_data.setAttribute("style", "padding:5px;font-size:15px;font-weight:bold;border:1px solid black;");
682 a.appendChild(a_txt);
683 tag_data.appendChild(a);
684 tag_row.appendChild(tag_data);
685 tag_table.appendChild(tag_row);
686 auto_complete_row.appendChild(tag_table);
687 if (tag_table.offsetWidth > qr_width - 10) {
688 tag_row.removeChild(tag_data);
689 tag_table = document.createElement("TABLE");
690 tag_row = document.createElement("TR");
691 tag_row.appendChild(tag_data);
692 tag_table.appendChild(tag_row);
693 tag_table.setAttribute("style", "border:1px solid black;");
694 auto_complete_row.appendChild(tag_table);
696 a.addEventListener("click", function (evt) {
697 tagArray[tagArray.indexOf(closest_tag)] = this.textContent;
698 document.getElementById("tag_input").value = tagArray.join(" ");
704 this.old_tags_before_change = tag_input_node.value;
706 //a series of calls on other functions that leads to the image being searched for
707 DanbooruImageAdder.prototype.setImage = function (this_) {
709 var tags = document.getElementById("tag_input").value.trim();
710 if (tags.indexOf(":") > -1) {
711 Generics.alert4ChanX("Character ':' not used for functional purpose", "warning");
713 var tags_arr = tags.split(" ");
714 var xhr_image_load = new GM_xmlhttpRequest(({
716 //returns a list of all tags and their properties
717 url: "https://danbooru.donmai.us/tags.json?search[name]=" + tags_arr.join() + "&search[order]=count",
718 responseType: "json",
719 onload: function (data) {
720 this_.json_tag = this_.verifyTags(data, tags_arr);
721 if (this_.failed_to_find_required_tags_state)
724 var end_URL = this_.ratingURL(this_.json_tag);
725 var URL = this_.setPostAndPage(end_URL);
726 this_.send_URL = URL;
727 //final check, sends final request after function or calls this function again
728 Generics.getJSON(URL, function (err, data, tags, _this_) { return this_.checkPageFromDanbooru(err, data, tags, _this_); }, tags_arr, this_);
732 //make 4chanX alerts on issues, and account for error cases.
733 DanbooruImageAdder.prototype.verifyTags = function (data, tags) {
734 data = data.response;
735 this.json_tag = data;
736 this.failed_to_find_required_tags_state = false;
737 //if data has a null or undefined case, return an error
738 if (data.length == 0) {
739 Generics.alert4ChanX("All tags incorrect", "error", 10);
740 this.failed_to_find_required_tags_state = true;
741 document.getElementById("timer").textContent = "";
742 document.getElementById("tag_input").removeAttribute("disabled");
743 document.getElementById("imageButton").removeAttribute("disabled");
744 return this.json_tag;
746 else if (data.length != tags.length && !this.tag_incorrect_state) {
747 this.tag_incorrect_state = true;
748 if (document.getElementById("tag_input").value.trim() == "")
749 Generics.alert4ChanX("No Tags", "info", 2);
751 Generics.alert4ChanX("One Tag Incorrect", "warning");
753 //tag size. Smallest tag is placed at bottom of JSON
754 this.smallest_tag_size = parseInt(data[data.length - 1]["post_count"]);
755 return this.json_tag;
757 //evaluate the rating restrictions to account for danbooru's tagging limitations
758 DanbooruImageAdder.prototype.ratingURL = function (tags) {
760 //evaluate the 3! possible permutations
761 if (document.getElementById("safe").checked) {
762 if (document.getElementById("questionable").checked) {
763 if (document.getElementById("explicit").checked) {
765 URL = "&utf8=%E2%9C%93&tags=" + tags[tags.length - 2]["name"] + "+" + tags[tags.length - 1]["name"];
767 URL = "&utf8=%E2%9C%93&tags=" + tags[tags.length - 1]["name"];
770 URL = "&utf8=%E2%9C%93&tags=" + "-rating%3Aexplicit" + "+" + tags[tags.length - 1]["name"];
773 else if (document.getElementById("explicit").checked) {
774 URL = "&utf8=%E2%9C%93&tags=" + "-rating%3Aquestionable" + "+" + tags[tags.length - 1]["name"];
777 URL = "&utf8=%E2%9C%93&tags=" + "rating%3Asafe" + "+" + tags[tags.length - 1]["name"];
780 else if (document.getElementById("questionable").checked) {
781 if (document.getElementById("explicit").checked) {
782 URL = "&utf8=%E2%9C%93&tags=" + "-rating%3Asafe" + "+" + tags[tags.length - 1]["name"];
785 URL = "&utf8=%E2%9C%93&tags=" + "rating%3Aquestionable" + "+" + tags[tags.length - 1]["name"];
788 else if (document.getElementById("explicit").checked) {
789 URL = "&utf8=%E2%9C%93&tags=" + "rating%3Aexplicit" + "+" + tags[tags.length - 1]["name"];
793 URL = "&utf8=%E2%9C%93&tags=" + tags[tags.length - 2]["name"] + "+" + tags[tags.length - 1]["name"];
795 URL = "&utf8=%E2%9C%93&tags=" + tags[tags.length - 1]["name"];
799 //set where to search
800 DanbooruImageAdder.prototype.setPostAndPage = function (end_URL) {
801 this.post_number = 0;
803 if (this.top_page != this.top_page_max)
804 this.smallest_tag_size = this.top_page * 20;
805 if (this.smallest_tag_size == 0)
806 this.smallest_tag_size = 100;
807 var escape_cond = true;
808 this.page_number = ((Math.floor(Math.random() * 10000)) % Math.ceil(this.smallest_tag_size / 20)) % 1000; //1000 is max page search limit
809 if (this.page_number == 0 && this.previous_page == 0) {
810 this.primed_for_fail = true;
812 this.json_numbers_used.push(this.page_number);
813 this.previous_page = this.page_number;
814 var URL = "https://danbooru.donmai.us/posts.json?page=" + this.page_number + end_URL;
817 //check if valid url location
818 DanbooruImageAdder.prototype.checkPageFromDanbooru = function (err, data, tags, this_arr) {
820 console.log('Something went wrong: ' + err);
821 Generics.alert4ChanX("Danbooru Server Did Not Perform request -- Error: " + err, "error");
822 document.getElementById("timer").textContent = "";
823 document.getElementById("tag_input").removeAttribute("disabled");
824 document.getElementById("imageButton").removeAttribute("disabled");
828 var duplicate = false;
829 //check for repeating images found
830 this_arr.previous_images.forEach(function (item) {
831 if (item[0] == this_arr.page_number && item[1] == this_arr.post_number) {
833 this_arr.post_number++;
837 if (this_arr.primed_for_fail) {
838 Generics.alert4ChanX("No Results: All found for tags \"" + document.getElementById("tag_input").value + "\"", "error");
839 this_arr.reset_search_timer_fields();
842 else if ((data.length < this_arr.post_number + 1) && this_arr.number_of_attempts > 0) {
843 if (this_arr.top_page > this_arr.page_number) {
844 this_arr.top_page = this_arr.page_number + this_arr.post_number / 20;
846 this_arr.number_of_attempts--;
848 this_arr.post_number = 0;
849 document.getElementById("timer").textContent = this_arr.number_of_attempts + "|" + this_arr.time;
850 this_arr.setImage(this_arr);
852 else if (this_arr.number_of_attempts > 0) {
853 //ALL PARAMETERS WILL BE RESET INSIDE JSON
854 document.getElementById("timer").textContent = this_arr.number_of_attempts + "|" + this_arr.time;
855 Generics.getJSON(this_arr.send_URL, function (err, data, tags, _this_arr) { return this_arr.setImageFromDanbooru(err, data, tags, _this_arr); }, tags, this_arr);
858 Generics.alert4ChanX("Not found", "error");
859 this_arr.reset_search_timer_fields();
864 DanbooruImageAdder.prototype.reset_search_timer_fields = function () {
865 this.top_page = this.top_page_max;
866 this.number_of_attempts = this.maximum_attempts;
867 document.getElementById("timer").textContent = "";
868 document.getElementById("tag_input").removeAttribute("disabled");
869 document.getElementById("imageButton").removeAttribute("disabled");
871 //finally draw from the JSON page to generate and place the post into the 4chanX dumplist
872 DanbooruImageAdder.prototype.setImageFromDanbooru = function (err, data, tags, this_arr) {
874 console.log('Something went wrong: ' + err);
875 Generics.alert4ChanX("Danbooru Server Did Not Perform request -- Error: " + err, "error");
876 document.getElementById("timer").textContent = "";
877 document.getElementById("tag_input").removeAttribute("disabled");
878 document.getElementById("imageButton").removeAttribute("disabled");
881 this_arr.json_page = data;
882 var image_found = false;
883 for (this_arr.post_number = this_arr.post_number; this_arr.post_number < 20; this_arr.post_number++) {
884 if (this_arr.timeout) {
885 //Case1: Took too long to scan the page.
886 //Result: Kills search
887 Generics.alert4ChanX("timeout after " + this_arr.time + " seconds", "error");
888 for (var i = 0; i < this_arr.timeout_functions.length; i++) {
889 clearInterval(this_arr.timeout_functions[i]);
891 this_arr.reset_search_timer_fields();
894 else if (this_arr.json_page["" + this_arr.post_number] == undefined) {
895 //Case2: reaches an undefined page.
896 //Result: Switches to a new page
897 this_arr.top_page = this_arr.page_number;
898 //this_arr.number_of_attempts--;
899 this_arr.setImage(this_arr);
902 //set the page to search
903 var end_URL = this_arr.json_page["" + this_arr.post_number].file_url;
904 var URL = "https://danbooru.donmai.us" + end_URL;
905 if (this_arr.subdomain_regex.test(end_URL))
907 //place url in visible box
908 this_arr.urlContainterFunction(URL);
912 :{id: 3038118, created_at: "2018-03-02T15:27:56.469-05:00", uploader_id: 49091, score: 6,…}
916 created_at:"2018-03-02T15:27:56.469-05:00"
919 fav_string:"fav:553974 fav:467363 fav:455311 fav:490034 fav:505064 fav:482030 fav:351935 fav:66907 fav:467355 fav:519151"
922 file_url:"/data/__miyuki_kantai_collection_drawn_by_kumadano__7a12a196cc1aa9f794bca81a2a14bb81.jpg"
923 has_active_children:false
926 has_visible_children:false
935 is_rating_locked:false
936 is_status_locked:false
937 large_file_url:"/data/__miyuki_kantai_collection_drawn_by_kumadano__7a12a196cc1aa9f794bca81a2a14bb81.jpg"
938 last_comment_bumped_at:null
939 last_commented_at:null
941 md5:"7a12a196cc1aa9f794bca81a2a14bb81"
945 preview_file_url:"/data/preview/7a12a196cc1aa9f794bca81a2a14bb81.jpg"
948 source:"https://twitter.com/kumadano/status/969629578137251840"
951 tag_count_character:1
952 tag_count_copyright:1
955 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"
956 tag_string_artist:"kumadano"
957 tag_string_character:"miyuki_(kantai_collection)"
958 tag_string_copyright:"kantai_collection"
959 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"
960 tag_string_meta:"commentary_request"
962 updated_at:"2018-03-03T09:09:32.357-05:00"
967 var failed_to_find_required_tags = false;
968 if (end_URL === undefined ||
969 end_URL.indexOf(".mp4") > -1 || end_URL.indexOf(".webm") > -1 || end_URL.indexOf(".swf") > -1 || end_URL.indexOf(".zip") > -1) {
973 tags.forEach(function (tag) {
974 //if tag contains an order then whatever
975 if (tag.indexOf("order:") > -1) { }
976 else if (tag.indexOf("rating:") > -1) {
977 if (tag.charAt(7) !== this_arr.json_page["" + this_arr.post_number]["rating"]) {
978 failed_to_find_required_tags = true;
981 else if (this_arr.json_page["" + this_arr.post_number]["tag_string"].indexOf(tag) == -1) {
982 failed_to_find_required_tags = true;
986 if (failed_to_find_required_tags) {
990 if (this_arr.json_page["" + this_arr.post_number].file_size >= 4000000) {
991 var end_URL = this_arr.json_page["" + this_arr.post_number].large_file_url;
992 var URL = "https://danbooru.donmai.us" + end_URL;
993 if (this_arr.subdomain_regex.test(end_URL))
996 document.getElementById("timer").textContent = "...";
997 this_arr.img_URL = URL;
998 var xhr = new GM_xmlhttpRequest(({
1001 responseType: "arraybuffer",
1002 onload: function (response) {
1003 //is it a non existent image?
1004 if (response.response.byteLength <= 387) {
1005 Generics.alert4ChanX("Image Does Not Exist on Danbooru(404 error)\nDanbooru seems to be updating image servers???", "error");
1008 if (end_URL.indexOf(".jpg") > -1)
1009 blob = new Blob([response.response], { type: "image/jpeg" });
1010 else if (end_URL.indexOf(".png") > -1)
1011 blob = new Blob([response.response], { type: "image/png" });
1012 else if (end_URL.indexOf(".gif") > -1)
1013 blob = new Blob([response.response], { type: "image/gif" });
1014 var counter = document.getElementById("timer");
1015 while (counter.hasChildNodes())
1016 counter.removeChild(counter.lastChild);
1017 this_arr.reset_search_timer_fields();
1018 this_arr.time = this_arr.time_max;
1019 var name = end_URL.replace(/(data|cached)/g, "");
1020 name = name.replace(/\//g, "");
1021 //SEND RESULTING RESPONSE TO 4CHANX FILES === QRSetFile
1022 var detail = { file: blob, name: name };
1023 if (typeof cloneInto === 'function') {
1024 detail = cloneInto(detail, document.defaultView);
1026 document.dispatchEvent(new CustomEvent('QRSetFile', { bubbles: true, detail: detail }));
1031 //SET PAGE&POST AS FOUND
1032 this_arr.previous_images.push([this_arr.page_number, this_arr.post_number]);
1033 this_arr.post_number = 9001;
1037 // this_arr.top_page = this_arr.page_number;
1038 // //this_arr.number_of_attempts--;
1039 this_arr.setImage(this_arr);
1043 DanbooruImageAdder.prototype.urlContainterFunction = function (url) {
1044 var url_box = document.getElementById("urlContainer");
1045 url_box.value = url;
1047 DanbooruImageAdder.prototype.counterFunction = function () {
1048 if (!this.timeout) {
1050 if (this.time < 0) {
1051 this.timeout = true;
1052 this.time = this.time_max;
1056 DanbooruImageAdder.prototype.decideAction = function (node) { };
1057 DanbooruImageAdder.prototype.retrieveStates = function () { };
1058 DanbooruImageAdder.prototype.storeStates = function () {
1060 for (var _i = 0; _i < arguments.length; _i++) {
1061 items[_i] = arguments[_i];
1064 return DanbooruImageAdder;
1065 }(FeatureInterface));
1066 var ThreadRebuilder = /** @class */ (function (_super) {
1067 __extends(ThreadRebuilder, _super);
1068 function ThreadRebuilder() {
1069 var _this = _super.call(this) || this;
1071 _this.thread_data = [['Comment'], ['Image URLs'], ['Image Names'], ['Post No.']];
1072 _this.semaphore = 1;
1073 _this.semaphore_posts = 1;
1074 _this.use_offsite_archive = false;
1075 _this.window_displayed = false;
1076 _this.in_sequence = false;
1077 _this.tool_top_visible = false;
1078 _this.thread_data_length = 0;
1079 _this.posts_created = 0;
1080 _this.checked = false;
1084 ThreadRebuilder.prototype.init = function () {
1085 var board_uproces = window.location.pathname;
1086 this.board = board_uproces.substring(1, board_uproces.length - 1);
1089 ThreadRebuilder.prototype.retrieveStates = function () {
1090 this.use_offsite_archive = localStorage.getItem("ArchiveType") == "0" ? true : false;
1092 ThreadRebuilder.prototype.storeStates = function () {
1094 for (var _i = 0; _i < arguments.length; _i++) {
1095 items[_i] = arguments[_i];
1098 ThreadRebuilder.prototype.activate = function () {
1100 document.addEventListener("QRDialogCreation", function (e) { return _this.enhance4ChanX(); });
1101 document.addEventListener('QRPostSuccessful', function (e) {
1102 if (_this.in_sequence) {
1103 document.getElementById("dump-list").childNodes[1].click();
1104 _this.setPropperLinking(document.getElementById("qr").getElementsByTagName("TEXTAREA")[0].value);
1108 ThreadRebuilder.prototype.decideAction = function (node) { };
1109 ThreadRebuilder.prototype.enhance4ChanX = function () {
1111 var qr_window = document.getElementById("qr");
1112 if (document.getElementById("qrRebuilder") !== null)
1113 qr_window.removeChild(document.getElementById("qrRebuilder"));
1114 var thread_rebuilder_table = document.createElement("TABLE");
1115 thread_rebuilder_table.setAttribute("id", "qrRebuilder");
1116 thread_rebuilder_table.setAttribute("style", "text-align:center");
1117 qr_window.appendChild(thread_rebuilder_table);
1118 var thread_row = document.createElement("TR");
1119 var option_text_size = 18;
1120 var help_icon_container = document.createElement("A");
1121 help_icon_container.href = "javascript:void(0)";
1122 help_icon_container.title = "Click to View Help!";
1123 var help_icon = document.createElement("IMG");
1124 help_icon.setAttribute("style", "height:" + option_text_size * 1.25 + "px;margin:-4px 10px");
1125 help_icon.src = Constants.HELP_ICON_SOURCE;
1126 help_icon_container.appendChild(help_icon);
1127 thread_row.appendChild(help_icon_container);
1128 var tooltip_div = document.createElement("DIV");
1129 tooltip_div.innerHTML = "Insert the thread number of the post to rebuild<br/>Must be in either the 4chan archives or archived.moe<hr/>Submit bugs to <a href='https://github.com/ECHibiki/4chan-UserScripts'>my Github</a>";
1130 tooltip_div.setAttribute("style", "z-index:9;padding:5px;border:1px solid black;background-color:white;word-wrap:break-word;display:none;position:absolute;");
1131 help_icon_container.addEventListener("click", function (evt) {
1132 if (_this.tool_top_visible)
1133 tooltip_div.setAttribute("style", "z-index:9;padding:5px;border:1px solid black;background-color:white;word-wrap:break-word;display:none;position:absolute;");
1135 tooltip_div.setAttribute("style", "z-index:9;padding:5px;border:1px solid black;background-color:white;word-wrap:break-word;display:block;position:absolute;"
1136 + "left:" + (evt.clientX - qr_window.getBoundingClientRect().x) +
1137 "px;top:" + (evt.clientY - qr_window.getBoundingClientRect().y) + "px;");
1138 _this.tool_top_visible = !_this.tool_top_visible;
1140 qr_window.appendChild(tooltip_div);
1141 var second_row_nodes = [
1142 document.createTextNode("Thread: "),
1143 document.createElement("INPUT"),
1144 document.createElement("INPUT"),
1146 second_row_nodes.forEach(function (node) {
1147 thread_row.appendChild(node);
1149 thread_rebuilder_table.appendChild(thread_row);
1150 second_row_nodes[1].setAttribute("ID", "threadInput");
1151 second_row_nodes[1].setAttribute("style", "width:35.0%");
1152 second_row_nodes[2].setAttribute("ID", "threadButton");
1153 second_row_nodes[2].setAttribute("type", "button");
1154 second_row_nodes[2].setAttribute("value", "Set Rebuild Queue");
1155 second_row_nodes[2].addEventListener("click", function () {
1156 _this.in_sequence = true;
1158 _this.getThread(second_row_nodes[1].value);
1159 _this.postID = setInterval(function () { return _this.postRoutine(); }, 1000);
1160 if (_this.timeListen === undefined)
1161 _this.timeListen = setInterval(function () { return _this.timeListenerFunction(); }, 1000);
1163 qr_window.appendChild(document.createElement("hr"));
1166 ThreadRebuilder.prototype.postRoutine = function () {
1168 if (this.semaphore == 0) {
1170 this.thread_data_length = this.thread_data[0].length;
1171 this.fillID = setInterval(function () { return _this.fillRoutine(); }, 10);
1176 ThreadRebuilder.prototype.stopRoutine = function () {
1177 clearInterval(this.postID);
1180 ThreadRebuilder.prototype.fillRoutine = function () {
1181 if (this.posts_created >= this.thread_data_length) {
1182 this.semaphore_posts = 0;
1183 this.stopFillRoutine();
1185 else if (this.semaphore_posts == 1) {
1186 this.semaphore_posts--;
1187 this.createPost(this.thread_data[0][this.posts_created], this.thread_data[1][this.posts_created], this.thread_data[2][this.posts_created]);
1188 this.posts_created++;
1192 ThreadRebuilder.prototype.stopFillRoutine = function () {
1193 clearInterval(this.fillID);
1195 ThreadRebuilder.prototype.setPropperLinking = function (text) {
1197 var search_regex = RegExp(">>\\d+", "g");
1200 var link_arr = Array();
1201 while ((result = search_regex.exec(text)) != null) {
1202 var end_index = search_regex.lastIndex;
1203 var post_no = result.toString().replace(/>/g, "");
1204 link_arr.push([post_no, end_index]);
1206 //hunt down the text of what it linked to
1207 //Get the links inside of the origonal message to show text contents
1208 var responding_text = Array();
1209 if (this.use_offsite_archive)
1210 var URL = "https://www.archived.moe/_/api/chan/thread/?board=" + this.board + "&num=" + document.getElementById("threadInput").value;
1212 var URL = "https://a.4cdn.org/" + this.board + "/thread/" + document.getElementById("threadInput").value + ".json";
1213 var xhr = new GM_xmlhttpRequest(({
1216 responseType: "json",
1217 onload: function (data) {
1218 if (_this.use_offsite_archive)
1219 data = data.response["" + document.getElementById("threadInput").value]["posts"];
1221 data = data.response["posts"];
1222 if (data == undefined) {
1223 alert("Invalid Thread ID: " + document.getElementById("threadInput").value + ". ");
1226 link_arr.forEach(function (link_item) {
1227 for (var data_entry = 0; data_entry < data.length; data_entry++) {
1228 if (parseInt(link_item[0]) == parseInt(data[data_entry]["no"])) {
1229 if (_this.use_offsite_archive && data[data_entry]["comment_processed"] !== undefined)
1230 responding_text.push([[post_no, end_index], data[data_entry]["comment_processed"].replace(/(>>|https:\/\/www\.archived\.moe\/.*\/thread\/.*\/#)\d+/g, ""), link_item["media"]["safe_media_hash"]]);
1231 else if (data[data_entry]["com"] !== undefined)
1232 responding_text.push([[post_no, end_index], data[data_entry]["com"].replace(/(>>|#p)\d+/g, ""), data[data_entry]["md5"]]);
1234 responding_text.push([[post_no, end_index], undefined, data[data_entry]["md5"]]);
1239 var current_url = window.location.href;
1240 var hash_index = current_url.lastIndexOf("#") != -1 ? current_url.lastIndexOf("#") : window.location.href.length;
1241 var current_thread = window.location.href.substring(current_url.lastIndexOf("/") + 1, hash_index);
1242 var current_url = "https://a.4cdn.org/" + _this.board + "/thread/" + current_thread + ".json";
1243 //open current thread to hunt down the text found in links
1244 var xhr = new GM_xmlhttpRequest(({
1247 responseType: "json",
1248 onload: function (data) {
1249 data = data.response["posts"];
1250 if (data == undefined) {
1251 alert("Invalid Thread ID: " + document.getElementById("threadInput").value + ". ");
1254 responding_text.forEach(function (response_item) {
1255 for (var data_entry = 0; data_entry < data.length; data_entry++) {
1256 if (data[data_entry]["com"] !== undefined && (response_item[1] == data[data_entry]["com"].replace(/(>>|#p)\d+/g, "") || response_item[1] == null)
1257 && (response_item[2] == data[data_entry]["md5"] || response_item[2] == null)) {
1258 var start_index = response_item[0][0].legth - response_item[0][1];
1259 text = text.substring(0, start_index) + ">>" + data[data_entry]["no"] + text.substring(response_item[0][1]);
1262 else if (response_item[2] !== undefined && response_item[2] == data[data_entry]["md5"]) {
1263 var start_index = response_item[0][0].legth - response_item[0][1];
1264 text = text.substring(0, start_index) + ">>" + data[data_entry]["no"] + text.substring(response_item[0][1]);
1269 document.getElementById("qr").getElementsByTagName("TEXTAREA")[0].value = text;
1270 document.getElementById("add-post").click();
1271 _this.semaphore_posts++;
1280 //2) GET ARCHIVED THREAD
1281 ThreadRebuilder.prototype.getThread = function (threadNo) {
1283 this.thread_data = [[], [], [], []];
1284 if (this.use_offsite_archive)
1285 var URL = "https://www.archived.moe/_/api/chan/thread/?board=" + this.board + "&num=" + document.getElementById("threadInput").value;
1287 var URL = "https://a.4cdn.org/" + this.board + "/thread/" + document.getElementById("threadInput").value + ".json";
1288 var xhr = new GM_xmlhttpRequest(({
1291 responseType: "json",
1292 onload: function (data) {
1293 var starting_post = -1;
1294 if (_this.use_offsite_archive) {
1296 data = data.response["" + document.getElementById("threadInput").value];
1300 data = data.response;
1302 if (data == undefined) {
1303 alert("Invalid Thread ID: " + threadNo + ".\n4chan Archive ");
1306 if (_this.use_offsite_archive)
1307 data["posts"] = data.values(data["posts"]);
1308 var len = data["posts"].length;
1309 for (var post_number = starting_post; post_number < len; post_number++) {
1310 var comment = undefined;
1311 if (_this.use_offsite_archive)
1312 comment = data["posts"][post_number]["comment"];
1314 comment = data["posts"][post_number]["com"];
1315 if (comment !== undefined && comment !== null)
1316 _this.thread_data[0].push(comment);
1318 _this.thread_data[0].push("");
1319 var filename = undefined;
1320 if (_this.use_offsite_archive) {
1321 if (data["posts"][post_number]["media"] !== null)
1322 filename = "" + data["posts"][post_number]["media"]["media_filename"];
1325 filename = "" + data["posts"][post_number]["tim"] + data["posts"][post_number]["ext"];
1326 if (filename !== undefined && filename !== null && filename.indexOf("undefined") == -1)
1327 if (_this.use_offsite_archive)
1328 if (data["posts"][post_number]["media"] !== null)
1329 _this.thread_data[1].push(data["posts"][post_number]["media"]["remote_media_link"]);
1331 _this.thread_data[1].push("");
1333 _this.thread_data[1].push("https://i.4cdn.org/" + _this.board + "/" + filename);
1335 _this.thread_data[1].push("");
1336 if (_this.use_offsite_archive) {
1337 if (data["posts"][post_number]["media"] !== null)
1338 _this.thread_data[2].push(data["posts"][post_number]["media"]["media_id"]);
1341 _this.thread_data[2].push(data["posts"][post_number]["filename"]);
1342 if (_this.use_offsite_archive)
1343 _this.thread_data[3].push(data["posts"][post_number]["num"]);
1345 _this.thread_data[3].push(data["posts"][post_number]["no"]);
1353 //3) RIP POSTS AND IMAGES
1354 ThreadRebuilder.prototype.createPost = function (text, imageURL, imageName) {
1356 if (imageURL != "") {
1357 var response_type = "arraybuffer";
1358 if (this.use_offsite_archive)
1359 response_type = "text";
1360 var xhr = new GM_xmlhttpRequest(({
1363 responseType: response_type,
1364 onload: function (response) {
1365 if (_this.use_offsite_archive) {
1366 var parser = new DOMParser();
1367 var content_attribute = parser.parseFromString(response.response, "text/html").getElementsByTagName("META")[0].getAttribute("content");
1368 var redirect_url = content_attribute.substring(content_attribute.indexOf("http"));
1369 var xhr = new GM_xmlhttpRequest(({ method: "GET", url: redirect_url, responseType: "arraybuffer",
1370 onload: function (response) {
1371 _this.inputImage(response, text, imageURL, imageName);
1376 _this.inputImage(response, text, imageURL, imageName);
1382 text = this.createPostComment(text);
1383 this.setPropperLinking(text);
1386 ThreadRebuilder.prototype.inputImage = function (response, text, imageURL, imageName) {
1389 if (imageURL.indexOf(".jpg") > -1) {
1390 blob = new Blob([response.response], { type: "image/jpeg" });
1393 else if (imageURL.indexOf(".png") > -1) {
1394 blob = new Blob([response.response], { type: "image/png" });
1397 else if (imageURL.indexOf(".gif") > -1) {
1398 blob = new Blob([response.response], { type: "image/gif" });
1401 else if (imageURL.indexOf(".webm") > -1) {
1402 blob = new Blob([response.response], { type: "video/webm" });
1405 var name = imageName + ext;
1406 //SEND RESULTING RESPONSE TO 4CHANX FILES === QRSetFile
1407 var detail = { file: blob, name: name };
1408 detail = cloneInto(detail, document.defaultView);
1409 document.dispatchEvent(new CustomEvent('QRSetFile', { bubbles: true, detail: detail }));
1410 if (text !== "" && text !== undefined) {
1411 text = this.createPostComment(text);
1412 this.setPropperLinking(text);
1415 document.getElementById("add-post").click();
1416 this.semaphore_posts++;
1419 //4) CREATE POST QUEUE
1420 ThreadRebuilder.prototype.createPostComment = function (text) {
1421 var dummy = document.createElement("DIV");
1422 dummy.innerHTML = text;
1423 var inside_node = dummy.firstChild;
1424 var return_text = "";
1426 if (inside_node.tagName == "BR")
1427 return_text += "\n";
1429 return_text += inside_node.textContent;
1430 } while ((inside_node = inside_node.nextSibling));
1434 ThreadRebuilder.prototype.timeListenerFunction = function () {
1435 var time = parseInt(document.getElementById("qr-filename-container").nextSibling.value.replace(/[a-zA-Z]+/g, ""));
1437 this.checked = false;
1439 else if (time > 5) {
1440 this.checked = true;
1443 ThreadRebuilder.prototype.killAll = function () {
1444 this.thread_data_length = 0;
1445 this.posts_created = 0;
1447 this.postID = undefined;
1449 this.semaphore_posts = 1;
1450 this.stopFillRoutine();
1451 this.fillID = undefined;
1452 this.thread_data = [['Comment'], ['Image URLs'], ['Image Names'], ['Post No.']];
1454 var qr_dumplist = document.getElementById("dump-list").childNodes;
1455 var qr_dumplist_len = qr_dumplist.length;
1456 var current_preview = 0;
1457 while (qr_dumplist_len - current_preview > 1) {
1458 qr_dumplist[0].firstChild.click();
1462 return ThreadRebuilder;
1463 }(FeatureInterface));
1464 var CharacterInserter = /** @class */ (function (_super) {
1465 __extends(CharacterInserter, _super);
1466 function CharacterInserter(use_kita, use_yen) {
1467 var _this = _super.call(this) || this;
1468 _this.kita_character = "キタ━━━(゚∀゚)━━━!!";
1469 _this.kita_hash_color = "#444444";
1470 _this.yen_character = "¥";
1471 _this.yen_hash_color = "#9370DB";
1472 _this.use_yen = use_yen;
1473 _this.use_kita = use_kita;
1474 _this.retrieveStates();
1479 CharacterInserter.prototype.init = function () {
1481 this.hotkeyListeners();
1483 CharacterInserter.prototype.activate = function () {
1484 console.log("4F-FSE: CharacterInserter Active - " + (this.use_kita ? "Character Coloring+" : "") + (this.use_yen ? " Line Coloring" : ""));
1486 CharacterInserter.prototype.decideAction = function (node) {
1487 if (node.tagName == "BLOCKQUOTE")
1488 this.colorCharacters(node);
1490 CharacterInserter.prototype.retrieveStates = function () {
1491 if (localStorage.getItem("Yen_Character") === undefined || localStorage.getItem("Yen_Character") === null)
1492 this.yen_character = "¥";
1494 this.yen_character = localStorage.getItem("Yen_Character");
1495 if (localStorage.getItem("Yen_Color") === undefined || localStorage.getItem("Yen_Color") === null)
1496 this.yen_hash_color = "#9370DB";
1498 this.yen_hash_color = localStorage.getItem("Yen_Color");
1499 if (localStorage.getItem("Kita_Character") === undefined || localStorage.getItem("Kita_Character") === null)
1500 this.kita_character = "キタ━━━(゚∀゚)━━━!!";
1502 this.kita_character = localStorage.getItem("Kita_Character");
1503 if (localStorage.getItem("Kita_Color") === undefined || localStorage.getItem("Kita_Color") === null)
1504 this.kita_hash_color = "#444444";
1506 this.kita_hash_color = localStorage.getItem("Kita_Color");
1508 CharacterInserter.prototype.storeStates = function () {
1510 for (var _i = 0; _i < arguments.length; _i++) {
1511 items[_i] = arguments[_i];
1515 CharacterInserter.prototype.addStyle = function () {
1516 var style = document.createElement("STYLE");
1517 style.innerHTML = ".the_m_word{color:" + this.yen_hash_color + "} \n.the_k_word{color:" + this.kita_hash_color + "}";
1518 document.head.appendChild(style);
1520 //hotkeys for kita and yen
1521 CharacterInserter.prototype.hotkeyListeners = function () {
1523 var listener_obj = {};
1524 window.addEventListener("keydown", function (e) {
1525 listener_obj[e.keyCode] = true;
1526 var node = document.activeElement;
1527 if (listener_obj[17] && listener_obj[75]) {
1529 _this.insertAtPos(node, _this.kita_character);
1531 if (listener_obj[17] && listener_obj[220]) {
1533 _this.insertAtPos(node, _this.yen_character);
1535 }, { passive: false, capture: false, once: false });
1536 window.addEventListener("keyup", function (e) {
1537 listener_obj[e.keyCode] = false;
1538 }, { passive: false, capture: false, once: false });
1540 CharacterInserter.prototype.insertAtPos = function (node, buzzwords) {
1541 var sel_start = node.selectionStart;
1542 var sel_end = node.selectionEnd;
1543 var node_text = node.value;
1544 node.value = node_text.substr(0, sel_start) + buzzwords + node_text.substr(sel_end);
1545 node.selectionStart = sel_start + buzzwords.length;
1546 node.selectionEnd = sel_end + buzzwords.length;
1549 CharacterInserter.prototype.colorCharacters = function (root) {
1550 if (root.nodeType !== Node.ELEMENT_NODE) {
1553 if (root.textContent.indexOf(this.yen_character) <= -1 && root.textContent.indexOf(this.kita_character) <= -1) {
1556 var txtItterator = document.createNodeIterator(root, NodeFilter.SHOW_TEXT);
1558 while ((text_node = txtItterator.nextNode())) {
1559 //disregard text inside of A tag links and already colored text
1560 if (text_node.parentNode.tagName == "A" || /the_[a-z]_word/g.test(text_node.parentNode.className))
1562 this.setColor(text_node, txtItterator);
1565 //give color to text inside of nodes.
1566 // first scan for yen symbols and then check the front of the text for not nested kita.
1567 CharacterInserter.prototype.setColor = function (text_node, txtItterator) {
1568 var start_text_node = text_node;
1570 var yen_node = this.use_kita ? this.searchYen(text_node) : false;
1571 if (yen_node != false) {
1572 //jump to internal node
1573 text_node = txtItterator.nextNode();
1574 //scan for nested kita
1576 result = this.use_kita ? this.searchKita(text_node) : false;
1577 if (result != false) {
1578 //jump foreward to point after kita inserted
1579 text_node = txtItterator.nextNode();
1580 text_node = txtItterator.nextNode();
1582 } while (result != false);
1584 //scan for outside kita from start
1586 result = this.use_kita ? this.searchKita(start_text_node) : false;
1587 start_text_node = result.nextSibling;
1588 } while (result != false && start_text_node !== undefined);
1590 //find the location of a yen, split the text from above that position, create a span element and place split into this span.
1591 //Then take the initial text node and insert into it from after the text node.
1592 CharacterInserter.prototype.searchYen = function (text_node) {
1593 var yenIndex = text_node.textContent.indexOf(this.yen_character);
1594 if (yenIndex > -1) {
1595 var splitNode = text_node.splitText(yenIndex);
1596 var span = document.createElement('span');
1597 span.className = "the_m_word";
1598 span.appendChild(splitNode);
1599 text_node.parentNode.insertBefore(span, text_node.nextSibling);
1604 //find the location of a kita, isolate it by splitting from the point where the kita ends and the point where it begins.
1605 //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,
1606 //then refer back to the parent and place it after the leftmost string.
1607 CharacterInserter.prototype.searchKita = function (text_node) {
1608 var kIndex = text_node.textContent.indexOf(this.kita_character);
1610 var far_split_note = text_node.splitText(kIndex + this.kita_character.length);
1611 var splitNode = text_node.splitText(kIndex);
1612 var span = document.createElement('span');
1613 span.className = "the_k_word";
1614 span.appendChild(splitNode);
1615 text_node.parentNode.insertBefore(span, text_node.nextSibling);
1620 return CharacterInserter;
1621 }(FeatureInterface));
1622 var PasswordViewer = /** @class */ (function (_super) {
1623 __extends(PasswordViewer, _super);
1624 function PasswordViewer() {
1625 var _this = _super.call(this) || this;
1626 _this.post_id = "postPassword";
1627 _this.del_id = "delPassword";
1628 _this.label_post = document.createElement('LABEL');
1629 _this.label_del = document.createElement('LABEL');
1634 PasswordViewer.prototype.init = function () {
1635 this.node_post = document.getElementById(this.post_id);
1636 this.node_del = document.getElementById(this.del_id);
1637 this.node_post_parent = this.node_post.parentNode;
1638 this.node_del_parent = this.node_del.parentNode;
1639 this.label_post.textContent = 'Post: ';
1640 this.label_del.textContent = 'Delete: ';
1642 //activate displays passwords
1643 PasswordViewer.prototype.activate = function () {
1644 console.log("4F-FSE: PasswordViewer Active");
1645 this.node_post_parent.insertBefore(this.label_post, this.node_post);
1646 this.node_del_parent.insertBefore(this.label_del, this.node_del);
1647 this.node_post.removeAttribute('type');
1648 this.node_del.removeAttribute('type');
1649 document.getElementsByClassName('deleteform')[0].style.display = 'inline';
1650 this.node_del.style.display = 'inline';
1651 this.label_del.style.display = 'inline';
1652 this.label_del.style.paddingLeft = '10px';
1654 PasswordViewer.prototype.decideAction = function (node) { };
1655 PasswordViewer.prototype.retrieveStates = function () { };
1657 PasswordViewer.prototype.storeStates = function () { };
1659 return PasswordViewer;
1660 }(FeatureInterface));
1661 var SettingsWindow = /** @class */ (function (_super) {
1662 __extends(SettingsWindow, _super);
1663 function SettingsWindow() {
1664 var _this = _super.call(this) || this;
1665 _this.background_div = document.createElement('DIV');
1666 _this.settings_div = document.createElement('DIV');
1667 _this.close_div = document.createElement('DIV');
1668 _this.contents_div = document.createElement('DIV');
1669 _this.ul_selection_start = document.createElement('UL');
1670 _this.close_link = document.createElement('A');
1671 _this.title_para = document.createElement('P');
1672 _this.title_text = document.createTextNode('4F-FSE Settings');
1673 _this.end_para = document.createElement('P');
1674 _this.end_text = document.createTextNode('Refresh to view changes');
1675 _this.settings_style = document.createElement('STYLE');
1676 //to change order change, this AND...*
1677 _this.list_items = [
1678 { Text: " | View 『Image Hiding』 Settings", ListenerFunc: function (a_id) {
1679 _this.clearContainer();
1680 _this.contents_div.innerHTML =
1681 "\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";
1682 document.getElementById("Expiration_Time").value = "" + (_this.setting_items.image_hiding_settings.Expiration_Time / Constants.MILLISECONDS_TO_THE_HOUR);
1683 document.getElementById("MD5_List_FSE").value = _this.setting_items.image_hiding_settings.MD5_List_FSE;
1684 var set_button = document.createElement('INPUT');
1685 document.getElementById("disposable_container").appendChild(set_button);
1686 set_button.setAttribute('VALUE', "Set Image Settings");
1687 set_button.addEventListener("click", function (evt) {
1688 _this.storeStates();
1689 _this.clearContainer();
1690 _this.rebuildContainer();
1692 set_button.setAttribute('TYPE', 'button');
1695 { Text: " | View 『Word Replacement』 Settings", ListenerFunc: function (a_id) {
1696 _this.clearContainer();
1697 var disposable_container = document.createElement("DIV");
1698 disposable_container.setAttribute("ID", "disposable_container");
1699 _this.contents_div.appendChild(disposable_container);
1700 _this.filterWindow(disposable_container);
1701 _this.filterSetTable();
1704 { Text: " | View 『Danbooru Image Adder』 Settings", ListenerFunc: function (a_id) {
1705 _this.clearContainer();
1706 var disposable_container = document.createElement("DIV");
1707 disposable_container.setAttribute("id", "disposable_container");
1708 _this.contents_div.appendChild(disposable_container);
1709 disposable_container.innerHTML = "\n\t\t\t<table style=\"text-align:center;margin-left:5px\">\n\t\t\t\t<tr>\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<label>Very Large: </label>\n\t\t\t\t\t</td>\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<input id=\"v_large_DIA\" name=\"preivew-size\" style=\"display:inline\" type=\"radio\">\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<label>Large: </label>\n\t\t\t\t\t</td>\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<input id=\"large_DIA\" name=\"preivew-size\" style=\"display:inline\" type=\"radio\">\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<label>Medium: </label>\n\t\t\t\t\t</td>\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<input id=\"medium_DIA\" name=\"preivew-size\" style=\"display:inline\" type=\"radio\">\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<label>Small: </label>\n\t\t\t\t\t</td>\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<input id=\"small_DIA\" name=\"preivew-size\" style=\"display:inline\" type=\"radio\">\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<label>Width: </label>\n\t\t\t\t\t</td>\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<input id=\"width_DIA\" name=\"preivew-size\" style=\"width:20%\" type=\"text\">\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<label>Height: </label>\n\t\t\t\t\t</td>\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<input id=\"height_DIA\" name=\"preivew-size\" style=\"width:20%\" type=\"text\">\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t</table>\t\n\t\t\n\t\t\t<hr>\n\t\t\t\n\t\t\t<label>Quick Reply Min Width: </label>\n\t\t\t<input id=\"qr_width_DIA\" name=\"preivew-size\" style=\"width:20%\" type=\"text\">\n\t\t\n\t\t\t<hr>\n\t\t\n\t\t\t<input id=\"SetImageAdderProperties\" value=\"Set Preview Size\" type=\"button\">\n\t\t\t";
1710 _this.setImageAdderFields();
1711 _this.setImageAdderEventListeners();
1714 { Text: " | View 『Thread Rebuilder』 Settings", ListenerFunc: function (a_id) {
1715 _this.clearContainer();
1716 var disposable_container = document.createElement("DIV");
1717 disposable_container.setAttribute("id", "disposable_container");
1718 _this.contents_div.appendChild(disposable_container);
1719 disposable_container.innerHTML =
1720 "\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";
1721 (document.getElementById("setArchive")).addEventListener("click", function () {
1722 _this.storeStates();
1723 _this.clearContainer();
1724 _this.rebuildContainer();
1726 if (_this.setting_items.thread_rebuild_settings.Archive_Type === "0")
1727 document.getElementById("OffsiteArchive").checked = true;
1728 else if (_this.setting_items.thread_rebuild_settings.Archive_Type === "1")
1729 document.getElementById("OnsiteArchive").checked = true;
1732 { Text: " | View 『¥ Text』 Settings [Customizable]", ListenerFunc: function (a_id) {
1733 _this.clearContainer();
1734 var disposable_container = document.createElement("DIV");
1735 disposable_container.setAttribute("id", "disposable_container");
1736 _this.contents_div.appendChild(disposable_container);
1737 disposable_container.innerHTML =
1738 "\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";
1739 document.getElementById("SelectColorYen").addEventListener("input", function (evt) {
1740 document.getElementById("HexColorYen_text").value =
1741 (document.getElementById("SelectColorYen").value);
1743 document.getElementById("setQuote").addEventListener("click", function (e) {
1744 _this.storeStates();
1745 _this.clearContainer();
1746 _this.rebuildContainer();
1748 if (_this.setting_items.character_inserter_settings.Yen_Character !== undefined)
1749 document.getElementById("quoteCharacter").value = _this.setting_items.character_inserter_settings.Yen_Character;
1750 if (_this.setting_items.character_inserter_settings.Yen_Color !== undefined)
1751 document.getElementById("HexColorYen_text").value = _this.setting_items.character_inserter_settings.Yen_Color;
1752 document.getElementById("SelectColorYen").value = _this.setting_items.character_inserter_settings.Yen_Color;
1755 { Text: " | View 『Kita』 Settings [Customizable]", ListenerFunc: function (a_id) {
1756 _this.clearContainer();
1757 var disposable_container = document.createElement("DIV");
1758 disposable_container.setAttribute("id", "disposable_container");
1759 _this.contents_div.appendChild(disposable_container);
1760 disposable_container.innerHTML =
1761 "\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";
1762 document.getElementById("SelectColorKita").addEventListener("input", function (evt) {
1763 document.getElementById("HexColorKita_text").value =
1764 (document.getElementById("SelectColorKita").value);
1766 document.getElementById("setCharacter").addEventListener("click", function (e) {
1767 _this.storeStates();
1768 _this.clearContainer();
1769 _this.rebuildContainer();
1771 if (_this.setting_items.character_inserter_settings.Kita_Character !== undefined)
1772 document.getElementById("selectiveCharacters").value = _this.setting_items.character_inserter_settings.Kita_Character;
1773 if (_this.setting_items.character_inserter_settings.Kita_Color !== undefined)
1774 document.getElementById("HexColorKita_text").value = _this.setting_items.character_inserter_settings.Kita_Color;
1775 document.getElementById("SelectColorKita").value = _this.setting_items.character_inserter_settings.Kita_Color;
1778 { Text: " | Set 『Visible Password』", ListenerFunc: function (input_id) {
1779 var input = document.getElementById(input_id);
1780 var is_check = !input.checked;
1781 document.getElementById(input_id).checked = is_check;
1782 _this.storeStates();
1785 _this.setting_items = {};
1786 _this.retrieveStates();
1791 SettingsWindow.prototype.setImageAdderFields = function () {
1792 document.getElementById("width_DIA").value = this.setting_items.image_adder_settings.Width;
1793 document.getElementById("height_DIA").value = this.setting_items.image_adder_settings.Height;
1794 document.getElementById("qr_width_DIA").value = this.setting_items.image_adder_settings.QR_Width;
1795 if (document.getElementById("width_DIA").value == "489")
1796 document.getElementById("v_large_DIA").checked = true;
1797 else if (document.getElementById("width_DIA").value == "400")
1798 document.getElementById("large_DIA").checked = true;
1799 else if (document.getElementById("width_DIA").value == "300")
1800 document.getElementById("medium_DIA").checked = true;
1801 else if (document.getElementById("width_DIA").value == "200")
1802 document.getElementById("small_DIA").checked = true;
1804 SettingsWindow.prototype.setImageAdderEventListeners = function () {
1806 document.getElementById("v_large_DIA").addEventListener("click", function () {
1807 document.getElementById("width_DIA").value = "489";
1808 document.getElementById("height_DIA").value = "489";
1810 document.getElementById("large_DIA").addEventListener("click", function () {
1811 document.getElementById("width_DIA").value = "400";
1812 document.getElementById("height_DIA").value = "400";
1814 document.getElementById("medium_DIA").addEventListener("click", function () {
1815 document.getElementById("width_DIA").value = "300";
1816 document.getElementById("height_DIA").value = "300";
1818 document.getElementById("small_DIA").addEventListener("click", function () {
1819 document.getElementById("width_DIA").value = "200";
1820 document.getElementById("height_DIA").value = "200";
1822 document.getElementById("SetImageAdderProperties").addEventListener("click", function (evt) {
1823 _this.storeStates();
1824 _this.clearContainer();
1825 _this.rebuildContainer();
1829 SettingsWindow.prototype.retrieveStates = function () {
1830 //values used to fill out data fields
1831 this.setting_items.image_hiding_settings = { Expiration_Time: localStorage.getItem("Expiration_Time"), MD5_List_FSE: localStorage.getItem("MD5_List_FSE"), Active: localStorage.getItem("ImageHidingActive") };
1832 this.retrieveWordReplaceStates();
1833 this.retrieveImageAdderStates();
1834 this.retrieveRebuildStates();
1835 this.retrieveCharacterInsertingStates();
1836 this.setting_items.password_settings = (localStorage.getItem("PasswordActive"));
1838 SettingsWindow.prototype.retrieveActiveToggles = function () {
1839 if (localStorage.getItem("4F-FSE") === null) {
1840 document.getElementById("check-settings0").checked = true;
1841 document.getElementById("check-settings1").checked = false;
1842 document.getElementById("check-settings2").checked = false;
1843 document.getElementById("check-settings3").checked = false;
1844 document.getElementById("check-settings4").checked = true;
1845 document.getElementById("check-settings5").checked = true;
1846 document.getElementById("check-settings6").checked = true;
1847 localStorage.setItem("4F-FSE", "Success");
1848 this.displayWindow();
1851 document.getElementById("check-settings0").checked = localStorage.getItem("ImageHidingActive") === 'true';
1852 document.getElementById("check-settings1").checked = localStorage.getItem("TextReplaceActive") === 'true';
1853 document.getElementById("check-settings2").checked = localStorage.getItem("ImageAdderActive") === 'true';
1854 document.getElementById("check-settings3").checked = localStorage.getItem("ThreadRebuilderActive") === 'true';
1855 document.getElementById("check-settings4").checked = localStorage.getItem("YenActive") === 'true';
1856 document.getElementById("check-settings5").checked = localStorage.getItem("KitaActive") === 'true';
1857 document.getElementById("check-settings6").checked = localStorage.getItem("PasswordActive") === 'true';
1859 SettingsWindow.prototype.retrieveWordReplaceStates = function () {
1860 //acquire text filter representation
1861 var storage_index = 0;
1862 var JSON_storage = {};
1864 var text_filters = [];
1865 var local_store_len = window.localStorage.length;
1866 while (storage_index < local_store_len) {
1867 storage_key = window.localStorage.key(storage_index);
1868 JSON_storage[storage_key] = window.localStorage.getItem(storage_key);
1871 var filters = Generics.getJSONPropertiesByKeyName(JSON_storage, "[0-9]+FLT");
1873 filters.forEach(function (filter) {
1874 text_filters.push(TextReplacer.formatFilterSettings(JSON_storage[filter]));
1876 this.setting_items.word_replace_settings = { Number_of_Filters: localStorage.getItem("filter_quantity"), Text_Filter_List: text_filters, Active: localStorage.getItem("TextReplaceActive") };
1878 SettingsWindow.prototype.retrieveImageAdderStates = function () {
1879 this.setting_items.image_adder_settings = { Width: localStorage.getItem("width_DIA"),
1880 Height: localStorage.getItem("height_DIA"),
1881 QR_Width: localStorage.getItem("qr_width_DIA"),
1882 Active: localStorage.getItem("ImageAdderActive") };
1883 if (this.setting_items.image_adder_settings.Height === null)
1884 this.setting_items.image_adder_settings.Height = 400;
1885 if (this.setting_items.image_adder_settings.Width === null)
1886 this.setting_items.image_adder_settings.Width = 400;
1887 if (this.setting_items.image_adder_settings.QR_Width === null)
1888 this.setting_items.image_adder_settings.QR_Width = 480;
1889 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;}";
1890 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;}";
1892 SettingsWindow.prototype.retrieveRebuildStates = function () {
1893 if (localStorage.getItem("ArchiveType_FSE") !== "1" && localStorage.getItem("ArchiveType_FSE") !== "0")
1894 localStorage.setItem("ArchiveType_FSE", "1");
1895 this.setting_items.thread_rebuild_settings = { Archive_Type: localStorage.getItem("ArchiveType_FSE"), Active: localStorage.getItem("ThreadRebuilderActive") };
1897 SettingsWindow.prototype.retrieveCharacterInsertingStates = function () {
1898 if (localStorage.getItem("Yen_Character") === undefined || localStorage.getItem("Yen_Character") === null)
1899 localStorage.setItem("Yen_Character", "¥");
1900 if (localStorage.getItem("Yen_Color") === undefined || localStorage.getItem("Yen_Color") === null)
1901 localStorage.setItem("Yen_Color", "#9370DB");
1902 if (localStorage.getItem("Kita_Character") === undefined || localStorage.getItem("Kita_Character") === null)
1903 localStorage.setItem("Kita_Character", "キタ━━━(゚∀゚)━━━!!");
1904 if (localStorage.getItem("Kita_Color") === undefined || localStorage.getItem("Kita_Color") === null)
1905 localStorage.setItem("Kita_Color", "#444444");
1906 this.setting_items.character_inserter_settings = { Yen_Active: localStorage.getItem("YenActive"), Yen_Character: localStorage.getItem("Yen_Character"), Yen_Color: localStorage.getItem("Yen_Color"),
1907 Kita_Active: localStorage.getItem("KitaActive"), Kita_Character: localStorage.getItem("Kita_Character"), Kita_Color: localStorage.getItem("Kita_Color") };
1909 SettingsWindow.prototype.storeStates = function () {
1911 this.storeImageFilterStates();
1912 //Text replace settings
1913 this.storeTextFilterStates();
1914 //Image Adder settings
1915 this.storeImageAdderStates();
1916 //Thread rebuild settings
1917 this.storeRebuildStates();
1918 //character inserter
1919 this.storeCharacterInserterStates();
1920 //Password replace settings
1921 this.storePasswordStates();
1922 this.retrieveStates();
1924 SettingsWindow.prototype.storeActiveToggles = function () {
1925 localStorage.setItem("ImageHidingActive", (document.getElementById("check-settings0").checked.toString()));
1926 localStorage.setItem("TextReplaceActive", (document.getElementById("check-settings1").checked.toString()));
1927 localStorage.setItem("ImageAdderActive", (document.getElementById("check-settings2").checked.toString()));
1928 localStorage.setItem("ThreadRebuilderActive", (document.getElementById("check-settings3").checked.toString()));
1929 localStorage.setItem("YenActive", (document.getElementById("check-settings4").checked.toString()));
1930 localStorage.setItem("KitaActive", (document.getElementById("check-settings5").checked.toString()));
1931 localStorage.setItem("PasswordActive", (document.getElementById("check-settings6").checked.toString()));
1933 SettingsWindow.prototype.storeImageFilterStates = function () {
1934 if (document.getElementById("Expiration_Time") !== null) {
1935 var time = document.getElementById("Expiration_Time");
1936 var millisecond_time = parseInt(time.value) * Constants.MILLISECONDS_TO_THE_HOUR;
1937 if (millisecond_time == 0 || millisecond_time === null || millisecond_time === undefined)
1938 millisecond_time = Constants.DEFAULT_HIDE_EXPIRATION_TIME;
1939 localStorage.setItem("Expiration_Time", millisecond_time.toString());
1940 var md5_filters = document.getElementById("MD5_List_FSE").value;
1941 localStorage.setItem("MD5_List_FSE", md5_filters);
1942 Generics.alert4ChanX("Image Settings Saved", "success", 3);
1945 SettingsWindow.prototype.storeTextFilterStates = function () {
1946 if (document.getElementById("FilterRow0") !== null) {
1947 var f_row_moving = document.getElementById("FilterRow0");
1948 var Number_of_Filters = 0;
1949 var Number_of_Filters_actual = 0;
1950 while (f_row_moving.nextSibling !== null) {
1951 if (document.getElementById("Pattern" + Number_of_Filters).value !== "")
1952 Number_of_Filters_actual++;
1953 Number_of_Filters++;
1954 f_row_moving = f_row_moving.nextSibling;
1956 window.localStorage.setItem("filter_quantity", Number_of_Filters_actual.toString());
1957 for (var pattern_input = 0; pattern_input < Number_of_Filters; pattern_input++) {
1958 var pattern_to_store = document.getElementById("Pattern" + pattern_input).value;
1959 var replacement_to_store = document.getElementById("Replacement" + pattern_input).value;
1962 if (pattern_to_store === "") {
1963 localStorage.removeItem(pattern_input + "FLT");
1966 else if (new RegExp("^\/.*\/\\D+$").test(pattern_to_store)) { }
1967 else if (new RegExp("^\/.*\/$").test(pattern_to_store)) {
1968 pattern_to_store = pattern_to_store + setting;
1970 else if (!new RegExp("^/.*\/\\D$").test(pattern_to_store)) {
1971 pattern_to_store = "/" + pattern_to_store + "/" + setting;
1973 //test for breakages, try to cause error
1974 var error_test = new RegExp(pattern_to_store.substring(0, pattern_to_store.lastIndexOf("/") + 1), pattern_to_store.substring(pattern_to_store.lastIndexOf("/") + 1));
1977 Generics.alert4ChanX("Unrecoverable Regex error on pattern " + pattern_input + " for " + pattern_to_store, "error", undefined);
1980 pattern_to_store = encodeURIComponent(pattern_to_store);
1981 var save_string = document.getElementById("Active" + pattern_input).checked + '=' + pattern_to_store + '=' + replacement_to_store;
1982 window.localStorage.setItem(pattern_input + "FLT", save_string);
1984 Generics.alert4ChanX("Wordfilters Updated!", "success", 3);
1987 SettingsWindow.prototype.storeImageAdderStates = function () {
1988 if (document.getElementById("SetImageAdderProperties") !== null) {
1989 var width = document.getElementById("width_DIA").value;
1990 localStorage.setItem("width_DIA", width);
1991 var height = document.getElementById("height_DIA").value;
1992 localStorage.setItem("height_DIA", height);
1993 var qr_width = document.getElementById("qr_width_DIA").value;
1994 localStorage.setItem("qr_width_DIA", qr_width);
1997 SettingsWindow.prototype.storeRebuildStates = function () {
1998 if (document.getElementById("setArchive") !== null) {
1999 localStorage.setItem("ArchiveType_FSE", document.getElementById("OffsiteArchive").checked === true ? "0" : "1");
2002 SettingsWindow.prototype.storeCharacterInserterStates = function () {
2003 if (document.getElementById("setCharacter") !== null) {
2004 localStorage.setItem("Kita_Character", document.getElementById("selectiveCharacters").value);
2005 localStorage.setItem("Kita_Color", document.getElementById("HexColorKita_text").value);
2007 else if (document.getElementById("setQuote") !== null) {
2008 localStorage.setItem("Yen_Character", document.getElementById("quoteCharacter").value);
2009 localStorage.setItem("Yen_Color", document.getElementById("HexColorYen_text").value);
2012 SettingsWindow.prototype.storePasswordStates = function () {
2013 //password view settings
2014 if (document.getElementById("check-settings6") !== null)
2015 localStorage.setItem("PasswordActive", "" + document.getElementById("check-settings6").checked);
2017 SettingsWindow.prototype.clearContainer = function () {
2018 var disposable = document.getElementById("disposable_container");
2019 if (disposable !== null)
2020 this.contents_div.removeChild(disposable);
2022 this.contents_div.removeChild(this.ul_selection_start);
2024 SettingsWindow.prototype.rebuildContainer = function () {
2025 this.contents_div.appendChild(this.ul_selection_start);
2027 SettingsWindow.prototype.init = function () {
2029 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}";
2030 this.background_div.setAttribute('class', 'SettingsBackground');
2031 this.background_div.setAttribute('id', 'SettingsBackground');
2032 this.background_div.setAttribute('style', 'display:none');
2033 this.settings_div.setAttribute('class', 'settingsMain');
2034 this.settings_div.setAttribute('id', 'settingsWindow');
2035 this.settings_div.setAttribute('style', 'display:none;width:500px');
2036 this.close_link.setAttribute('href', 'javascript:void(0)');
2037 this.close_div.setAttribute('class', 'closeIcon');
2038 this.close_div.addEventListener('click', function (evt) { return _this.hideWindow(); });
2039 this.title_para.setAttribute('class', 'titleStyle');
2040 this.contents_div.setAttribute('class', 'contentStyle');
2041 this.end_para.setAttribute('class', 'footerStyle');
2042 this.ul_selection_start.setAttribute("ID", "selection_list");
2043 this.generateList(this.contents_div);
2045 SettingsWindow.prototype.generateList = function (head_node) {
2047 this.list_items.forEach(function (list_item, index) {
2048 var li = document.createElement('LI');
2049 li.setAttribute('class', 'settingsItem');
2050 if (list_item.Text.indexOf('View') > -1) {
2051 var input = document.createElement('INPUT');
2052 var input_id = 'check-settings' + index;
2053 input.setAttribute('TYPE', 'checkbox');
2054 input.setAttribute('ID', 'check-settings' + index);
2055 li.appendChild(input);
2056 input.addEventListener('click', function (evt) { return _this.storeActiveToggles(); });
2057 var a = document.createElement('A');
2058 a.setAttribute('href', 'javascript:void(0)');
2059 a.textContent = list_item.Text;
2060 var a_id = 'tab-settings' + index;
2061 a.setAttribute('ID', 'tab-settings' + index);
2062 var setup_func = function (_a_id) {
2063 a.addEventListener('click', function (evt) { return list_item.ListenerFunc(_a_id); });
2065 _this.ul_selection_start.appendChild(li);
2070 var input = document.createElement('INPUT');
2071 var input_id = 'check-settings' + index;
2072 input.setAttribute('TYPE', 'checkbox');
2073 input.setAttribute('ID', 'check-settings' + index);
2074 input.addEventListener('click', function (evt) { return _this.storeActiveToggles(); });
2075 li.appendChild(input);
2076 var label = document.createElement('LABEL');
2077 label.textContent = list_item.Text;
2078 li.appendChild(label);
2079 _this.ul_selection_start.appendChild(li);
2080 input.checked = _this.setting_items.password_settings == 'true';
2081 var setup_func = function (input_id) {
2082 label.addEventListener('click', function (evt) { return list_item.ListenerFunc(input_id); });
2084 setup_func(input_id);
2088 SettingsWindow.prototype.activate = function () {
2090 document.body.appendChild(this.settings_style);
2091 this.background_div.addEventListener('click', function (evt) { return _this.hideWindow(); });
2092 document.body.appendChild(this.background_div);
2093 this.settings_div.appendChild(this.close_link);
2094 this.close_link.appendChild(this.close_div);
2095 this.title_para.appendChild(this.title_text);
2096 this.settings_div.appendChild(this.title_para);
2097 this.settings_div.appendChild(this.contents_div);
2098 this.contents_div.appendChild(this.ul_selection_start);
2099 this.end_para.appendChild(this.end_text);
2100 this.settings_div.appendChild(this.end_para);
2101 document.body.appendChild(this.settings_div);
2102 this.retrieveActiveToggles();
2104 SettingsWindow.prototype.decideAction = function (node) { };
2105 SettingsWindow.prototype.getSettingsArr = function () {
2106 return this.setting_items;
2108 SettingsWindow.prototype.displayWindow = function () {
2109 this.background_div.style.display = 'block';
2110 this.settings_div.style.display = 'block';
2111 this.rebuildContainer();
2113 SettingsWindow.prototype.hideWindow = function () {
2114 this.background_div.style.display = 'none';
2115 this.settings_div.style.display = 'none';
2116 this.clearContainer();
2118 SettingsWindow.prototype.filterWindow = function (disposable_container) {
2120 var filter_table = document.createElement("table");
2121 filter_table.setAttribute("style", "text-align:center;");
2122 filter_table.setAttribute("id", "filter_table");
2123 disposable_container.appendChild(filter_table);
2124 var top_row = document.createElement("TR");
2125 filter_table.appendChild(top_row);
2126 var table_head_active = document.createElement("th");
2127 top_row.appendChild(table_head_active);
2128 var head_text_active = document.createTextNode("Active");
2129 table_head_active.appendChild(head_text_active);
2130 var table_head_pattern = document.createElement("th");
2131 top_row.appendChild(table_head_pattern);
2132 var headTextPattern = document.createTextNode("Pattern");
2133 table_head_pattern.appendChild(headTextPattern);
2134 var table_head_replacement = document.createElement("th");
2135 top_row.appendChild(table_head_replacement);
2136 var head_text_replacement = document.createTextNode("Replacement");
2137 table_head_replacement.appendChild(head_text_replacement);
2138 //Create the pattern table
2139 //loop to create rows
2140 var Number_of_Filters = parseInt(this.setting_items.word_replace_settings.Number_of_Filters);
2141 console.log(Number_of_Filters);
2142 if (Number_of_Filters === 0 || isNaN(Number_of_Filters))
2143 Number_of_Filters = 6;
2144 for (var i = 0; i < Number_of_Filters; i++) {
2145 var table_row_contents = document.createElement("tr");
2146 table_row_contents.setAttribute("id", "FilterRow" + i);
2147 var table_data_active = document.createElement("td");
2148 var table_checkbox_active = document.createElement("input");
2149 table_checkbox_active.setAttribute("type", "checkbox");
2150 table_checkbox_active.setAttribute("id", "Active" + i);
2151 table_data_active.appendChild(table_checkbox_active);
2152 table_row_contents.appendChild(table_data_active);
2153 var table_data_pattern = document.createElement("td");
2154 var table_input_pattern = document.createElement("input");
2155 table_input_pattern.setAttribute("class", "inputs");
2156 table_input_pattern.setAttribute("id", "Pattern" + i);
2157 table_data_pattern.appendChild(table_input_pattern);
2158 table_row_contents.appendChild(table_data_pattern);
2159 var table_data_replacement = document.createElement("td");
2160 var table_input_replacement = document.createElement("input");
2161 table_input_replacement.setAttribute("class", "inputs");
2162 table_input_replacement.setAttribute("id", "Replacement" + i);
2163 table_data_replacement.appendChild(table_input_replacement);
2164 table_row_contents.appendChild(table_data_replacement);
2165 filter_table.appendChild(table_row_contents);
2167 var table_last_contents = document.createElement("tr");
2168 var table_add_collumn = document.createElement("td");
2169 var table_add_row_button = document.createElement("input");
2170 var table_subtract_row_button = document.createElement("input");
2171 table_subtract_row_button.setAttribute("type", "button");
2172 table_subtract_row_button.setAttribute("value", "-");
2173 table_subtract_row_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2174 table_add_collumn.appendChild(table_subtract_row_button);
2175 table_subtract_row_button.addEventListener("click", function (evt) { return _this.filterRemoveRow(); });
2176 table_add_row_button.setAttribute("type", "button");
2177 table_add_row_button.setAttribute("value", "+");
2178 table_add_row_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2179 table_add_collumn.appendChild(table_add_row_button);
2180 table_add_row_button.addEventListener("click", function (evt) { return _this.filterAddRow(); });
2181 table_last_contents.appendChild(table_add_collumn);
2182 var table_set_collumn = document.createElement("td");
2183 var table_confirm_button = document.createElement("input");
2184 table_confirm_button.setAttribute("type", "button");
2185 table_confirm_button.setAttribute("id", "table_confirm_button");
2186 table_confirm_button.setAttribute("value", "Set Replacements");
2187 table_confirm_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2189 table_confirm_button.addEventListener("click", function (evt) {
2190 _this.storeStates();
2191 _this.clearContainer();
2192 _this.rebuildContainer();
2194 table_set_collumn.appendChild(table_confirm_button);
2195 table_last_contents.appendChild(table_set_collumn);
2196 var table_close_collumn = document.createElement("td");
2197 var table_close_button = document.createElement("input");
2198 table_close_button.setAttribute("type", "button");
2199 table_close_button.setAttribute("value", "Close Without Saving");
2200 table_close_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2201 table_close_button.addEventListener("click", function (evt) {
2202 _this.clearContainer();
2203 _this.rebuildContainer();
2205 table_close_collumn.appendChild(table_close_button);
2206 table_last_contents.appendChild(table_close_collumn);
2207 filter_table.appendChild(table_last_contents);
2209 SettingsWindow.prototype.filterAddRow = function () {
2211 var filter_table = document.getElementById("filter_table");
2212 var Number_of_Filters = 0;
2213 var filter_children = document.getElementById("filter_table").firstChild;
2214 while (filter_children.nextSibling) {
2215 filter_children = filter_children.nextSibling;
2216 Number_of_Filters++;
2218 var table_row_contents = document.createElement("tr");
2219 table_row_contents.setAttribute("id", "FilterRow" + (Number_of_Filters - 1));
2220 filter_table.removeChild(filter_children);
2221 var table_data_active = document.createElement("td");
2222 var table_checkbox_active = document.createElement("input");
2223 table_checkbox_active.setAttribute("type", "checkbox");
2224 table_checkbox_active.setAttribute("id", "Active" + (Number_of_Filters - 1));
2225 table_data_active.appendChild(table_checkbox_active);
2226 table_row_contents.appendChild(table_data_active);
2227 var table_data_pattern = document.createElement("td");
2228 var table_input_pattern = document.createElement("input");
2229 table_input_pattern.setAttribute("class", "inputs");
2230 table_input_pattern.setAttribute("id", "Pattern" + (Number_of_Filters - 1));
2231 table_data_pattern.appendChild(table_input_pattern);
2232 table_row_contents.appendChild(table_data_pattern);
2233 var table_data_replacement = document.createElement("td");
2234 var table_input_replacement = document.createElement("input");
2235 table_input_replacement.setAttribute("class", "inputs");
2236 table_input_replacement.setAttribute("id", "Replacement" + (Number_of_Filters - 1));
2237 table_data_replacement.appendChild(table_input_replacement);
2238 table_row_contents.appendChild(table_data_replacement);
2239 filter_table.appendChild(table_row_contents);
2240 var table_last_contents = document.createElement("tr");
2241 var table_add_collumn = document.createElement("td");
2242 var table_add_row_button = document.createElement("input");
2243 var table_subtract_row_button = document.createElement("input");
2244 table_subtract_row_button.setAttribute("type", "button");
2245 table_subtract_row_button.setAttribute("value", "-");
2246 table_subtract_row_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2247 table_add_collumn.appendChild(table_subtract_row_button);
2248 table_subtract_row_button.addEventListener("click", function (evt) { return _this.filterRemoveRow(); });
2249 table_add_row_button.setAttribute("type", "button");
2250 table_add_row_button.setAttribute("value", "+");
2251 table_add_row_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2252 table_add_collumn.appendChild(table_add_row_button);
2253 table_add_row_button.addEventListener("click", function (evt) { return _this.filterAddRow(); });
2254 table_last_contents.appendChild(table_add_collumn);
2255 var table_set_collumn = document.createElement("td");
2256 var table_confirm_button = document.createElement("input");
2257 table_confirm_button.setAttribute("type", "button");
2258 table_confirm_button.setAttribute("id", "table_confirm_button");
2259 table_confirm_button.setAttribute("value", "Set Replacements");
2260 table_confirm_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2262 table_confirm_button.addEventListener("click", function (evt) {
2263 _this.storeStates();
2264 _this.clearContainer();
2265 _this.rebuildContainer();
2267 table_set_collumn.appendChild(table_confirm_button);
2268 table_last_contents.appendChild(table_set_collumn);
2269 var table_close_collumn = document.createElement("td");
2270 var table_close_button = document.createElement("input");
2271 table_close_button.setAttribute("type", "button");
2272 table_close_button.setAttribute("value", "Close Without Saving");
2273 table_close_button.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2274 table_close_button.addEventListener("click", function (evt) {
2275 _this.clearContainer();
2276 _this.rebuildContainer();
2278 table_close_collumn.appendChild(table_close_button);
2279 table_last_contents.appendChild(table_close_collumn);
2280 filter_table.appendChild(table_last_contents);
2282 SettingsWindow.prototype.filterRemoveRow = function () {
2283 var filter_table = document.getElementById("filter_table");
2284 var Number_of_Filters = 0;
2285 var filter_children = document.getElementById("filter_table").firstChild;
2286 while (filter_children.nextSibling) {
2287 filter_children = filter_children.nextSibling;
2288 Number_of_Filters++;
2290 if (Number_of_Filters != 2) {
2291 filter_table.deleteRow(--Number_of_Filters);
2294 SettingsWindow.prototype.filterSetTable = function () {
2295 var filter_length = this.setting_items.word_replace_settings.Number_of_Filters;
2296 for (var filter_count = 0; filter_count < filter_length; filter_count++) {
2297 if (this.setting_items.word_replace_settings.Text_Filter_List[filter_count].Active === null ||
2298 this.setting_items.word_replace_settings.Text_Filter_List[filter_count].Regex === null ||
2299 this.setting_items.word_replace_settings.Text_Filter_List[filter_count].Replacement === null)
2301 if (this.setting_items.word_replace_settings.Text_Filter_List[filter_count].Active === "true") {
2302 document.getElementById("Active" + filter_count).checked = true;
2305 document.getElementById("Active" + filter_count).checked = false;
2307 document.getElementById("Pattern" + filter_count).value =
2308 this.setting_items.word_replace_settings.Text_Filter_List[filter_count].Regex;
2309 document.getElementById("Replacement" + filter_count).value =
2310 this.setting_items.word_replace_settings.Text_Filter_List[filter_count].Replacement;
2313 return SettingsWindow;
2314 }(FeatureInterface));
2315 var Main = /** @class */ (function (_super) {
2316 __extends(Main, _super);
2318 var _this = _super.call(this) || this;
2319 _this.features = {}; /*;any bypasses dot notation issues on objects*/
2320 _this.settings = {};
2321 if (!Generics.storageAvailable('localStorage')) {
2322 alert("4F-FSE: local storage error");
2327 _this.retrieveStates();
2329 _this.decideAction(document.getElementById('delform'));
2330 _this.observeEvents();
2333 Main.prototype.retrieveStates = function () {
2334 var top_bar = new TopBar();
2336 this.settings = top_bar.getSettingsArr();
2338 Main.prototype.init = function () {
2339 if (this.settings.image_hiding_settings.Active === "true") {
2340 this.features.image_hider = new ImageHider();
2342 if (this.settings.word_replace_settings.Active === "true") {
2343 this.features.text_replacer = new TextReplacer();
2345 if (this.settings.image_adder_settings.Active === "true") {
2346 this.features.danbooru_image_adder = new DanbooruImageAdder();
2348 if (this.settings.thread_rebuild_settings.Active === "true") {
2349 this.features.thread_rebuilder = new ThreadRebuilder();
2351 if (this.settings.character_inserter_settings.Yen_Active === "true" || this.settings.character_inserter_settings.Kita_Active === "true") {
2352 this.features.character_inserter = new CharacterInserter(this.settings.character_inserter_settings.Yen_Active === "true", this.settings.character_inserter_settings.Kita_Active === "true");
2354 if (this.settings.password_settings == 'true') {
2355 this.features.password_viewer = new PasswordViewer();
2357 for (var feature_key in this.features)
2358 this.features[feature_key].retrieveStates();
2360 Main.prototype.activate = function () { console.log("4F-FSE Starting"); };
2361 Main.prototype.storeStates = function () { };
2362 Main.prototype.observeEvents = function () {
2364 var document_changes = new MutationObserver(function (mutations) {
2365 mutations.forEach(function (mutation) {
2366 [].forEach.call(mutation.addedNodes, function (node) { return _this.decideAction(node); });
2368 }).observe(document.body, { childList: true, subtree: true });
2370 Main.prototype.decideAction = function (node) {
2371 if (node === undefined || node.tagName === undefined)
2374 var itterator = document.createNodeIterator(start, NodeFilter.SHOW_ELEMENT);
2376 while ((node = itterator.nextNode())) {
2377 if (node.tagName !== "BLOCKQUOTE" && node.tagName !== "IMG" && node.tagName !== "VIDEO")
2379 for (var feature_key in this.features) {
2380 this.features[feature_key].decideAction(node);
2385 }(FeatureInterface));
2386 document.addEventListener('4chanXInitFinished', function () { new Main(); });