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
[91]) && 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
[91]) && 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
[91]) && listener_obj
[75]) {
1529 _this
.insertAtPos(node
, _this
.kita_character
);
1531 if ((listener_obj
[17] || listener_obj
[91]) && listener_obj
[220]) {
1533 _this
.insertAtPos(node
, _this
.yen_character
);
1535 }, { passive
: false, capture
: false, once
: false });
1536 window
.addEventListener("keyup", function (e
) {
1537 listener_obj
[e
.keyCode
] = false;
1538 }, { passive
: false, capture
: false, once
: false });
1540 CharacterInserter
.prototype.insertAtPos = function (node
, buzzwords
) {
1541 var sel_start
= node
.selectionStart
;
1542 var sel_end
= node
.selectionEnd
;
1543 var node_text
= node
.value
;
1544 node
.value
= node_text
.substr(0, sel_start
) + buzzwords
+ node_text
.substr(sel_end
);
1545 node
.selectionStart
= sel_start
+ buzzwords
.length
;
1546 node
.selectionEnd
= sel_end
+ buzzwords
.length
;
1549 CharacterInserter
.prototype.colorCharacters = function (root
) {
1550 if (root
.nodeType
!== Node
.ELEMENT_NODE
) {
1553 if (root
.textContent
.indexOf(this.yen_character
) <= -1 && root
.textContent
.indexOf(this.kita_character
) <= -1) {
1556 var 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 _this
.storeStates();
1782 _this
.setting_items
= {};
1783 _this
.retrieveStates();
1788 SettingsWindow
.prototype.setImageAdderFields = function () {
1789 document
.getElementById("width_DIA").value
= this.setting_items
.image_adder_settings
.Width
;
1790 document
.getElementById("height_DIA").value
= this.setting_items
.image_adder_settings
.Height
;
1791 document
.getElementById("qr_width_DIA").value
= this.setting_items
.image_adder_settings
.QR_Width
;
1792 if (document
.getElementById("width_DIA").value
== "489")
1793 document
.getElementById("v_large_DIA").checked
= true;
1794 else if (document
.getElementById("width_DIA").value
== "400")
1795 document
.getElementById("large_DIA").checked
= true;
1796 else if (document
.getElementById("width_DIA").value
== "300")
1797 document
.getElementById("medium_DIA").checked
= true;
1798 else if (document
.getElementById("width_DIA").value
== "200")
1799 document
.getElementById("small_DIA").checked
= true;
1801 SettingsWindow
.prototype.setImageAdderEventListeners = function () {
1803 document
.getElementById("v_large_DIA").addEventListener("click", function () {
1804 document
.getElementById("width_DIA").value
= "489";
1805 document
.getElementById("height_DIA").value
= "489";
1807 document
.getElementById("large_DIA").addEventListener("click", function () {
1808 document
.getElementById("width_DIA").value
= "400";
1809 document
.getElementById("height_DIA").value
= "400";
1811 document
.getElementById("medium_DIA").addEventListener("click", function () {
1812 document
.getElementById("width_DIA").value
= "300";
1813 document
.getElementById("height_DIA").value
= "300";
1815 document
.getElementById("small_DIA").addEventListener("click", function () {
1816 document
.getElementById("width_DIA").value
= "200";
1817 document
.getElementById("height_DIA").value
= "200";
1819 document
.getElementById("SetImageAdderProperties").addEventListener("click", function (evt
) {
1820 _this
.storeStates();
1821 _this
.clearContainer();
1822 _this
.rebuildContainer();
1826 SettingsWindow
.prototype.retrieveStates = function () {
1827 //values used to fill out data fields
1828 this.setting_items
.image_hiding_settings
= { Expiration_Time
: localStorage
.getItem("Expiration_Time"), MD5_List_FSE
: localStorage
.getItem("MD5_List_FSE"), Active
: localStorage
.getItem("ImageHidingActive") };
1829 this.retrieveWordReplaceStates();
1830 this.retrieveImageAdderStates();
1831 this.retrieveRebuildStates();
1832 this.retrieveCharacterInsertingStates();
1833 this.setting_items
.password_settings
= (localStorage
.getItem("PasswordActive"));
1835 SettingsWindow
.prototype.retrieveActiveToggles = function () {
1836 if (localStorage
.getItem("4F-FSE") === null) {
1837 document
.getElementById("check-settings0").checked
= true;
1838 document
.getElementById("check-settings1").checked
= false;
1839 document
.getElementById("check-settings2").checked
= false;
1840 document
.getElementById("check-settings3").checked
= false;
1841 document
.getElementById("check-settings4").checked
= true;
1842 document
.getElementById("check-settings5").checked
= true;
1843 document
.getElementById("check-settings6").checked
= true;
1844 localStorage
.setItem("4F-FSE", "Success");
1845 this.displayWindow();
1848 document
.getElementById("check-settings0").checked
= localStorage
.getItem("ImageHidingActive") === 'true';
1849 document
.getElementById("check-settings1").checked
= localStorage
.getItem("TextReplaceActive") === 'true';
1850 document
.getElementById("check-settings2").checked
= localStorage
.getItem("ImageAdderActive") === 'true';
1851 document
.getElementById("check-settings3").checked
= localStorage
.getItem("ThreadRebuilderActive") === 'true';
1852 document
.getElementById("check-settings4").checked
= localStorage
.getItem("YenActive") === 'true';
1853 document
.getElementById("check-settings5").checked
= localStorage
.getItem("KitaActive") === 'true';
1854 document
.getElementById("check-settings6").checked
= localStorage
.getItem("PasswordActive") === 'true';
1856 SettingsWindow
.prototype.retrieveWordReplaceStates = function () {
1857 //acquire text filter representation
1858 var storage_index
= 0;
1859 var JSON_storage
= {};
1861 var text_filters
= [];
1862 var local_store_len
= window
.localStorage
.length
;
1863 while (storage_index
< local_store_len
) {
1864 storage_key
= window
.localStorage
.key(storage_index
);
1865 JSON_storage
[storage_key
] = window
.localStorage
.getItem(storage_key
);
1868 var filters
= Generics
.getJSONPropertiesByKeyName(JSON_storage
, "[0-9]+FLT");
1870 filters
.forEach(function (filter
) {
1871 text_filters
.push(TextReplacer
.formatFilterSettings(JSON_storage
[filter
]));
1873 this.setting_items
.word_replace_settings
= { Number_of_Filters
: localStorage
.getItem("filter_quantity"), Text_Filter_List
: text_filters
, Active
: localStorage
.getItem("TextReplaceActive") };
1875 SettingsWindow
.prototype.retrieveImageAdderStates = function () {
1876 this.setting_items
.image_adder_settings
= { Width
: localStorage
.getItem("width_DIA"),
1877 Height
: localStorage
.getItem("height_DIA"),
1878 QR_Width
: localStorage
.getItem("qr_width_DIA"),
1879 Active
: localStorage
.getItem("ImageAdderActive") };
1880 if (this.setting_items
.image_adder_settings
.Height
=== null)
1881 this.setting_items
.image_adder_settings
.Height
= 400;
1882 if (this.setting_items
.image_adder_settings
.Width
=== null)
1883 this.setting_items
.image_adder_settings
.Width
= 400;
1884 if (this.setting_items
.image_adder_settings
.QR_Width
=== null)
1885 this.setting_items
.image_adder_settings
.QR_Width
= 480;
1886 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;}";
1887 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;}";
1889 SettingsWindow
.prototype.retrieveRebuildStates = function () {
1890 if (localStorage
.getItem("ArchiveType_FSE") !== "1" && localStorage
.getItem("ArchiveType_FSE") !== "0")
1891 localStorage
.setItem("ArchiveType_FSE", "1");
1892 this.setting_items
.thread_rebuild_settings
= { Archive_Type
: localStorage
.getItem("ArchiveType_FSE"), Active
: localStorage
.getItem("ThreadRebuilderActive") };
1894 SettingsWindow
.prototype.retrieveCharacterInsertingStates = function () {
1895 if (localStorage
.getItem("Yen_Character") === undefined || localStorage
.getItem("Yen_Character") === null)
1896 localStorage
.setItem("Yen_Character", "¥");
1897 if (localStorage
.getItem("Yen_Color") === undefined || localStorage
.getItem("Yen_Color") === null)
1898 localStorage
.setItem("Yen_Color", "#9370DB");
1899 if (localStorage
.getItem("Kita_Character") === undefined || localStorage
.getItem("Kita_Character") === null)
1900 localStorage
.setItem("Kita_Character", "キタ━━━(゚∀゚)━━━!!");
1901 if (localStorage
.getItem("Kita_Color") === undefined || localStorage
.getItem("Kita_Color") === null)
1902 localStorage
.setItem("Kita_Color", "#444444");
1903 this.setting_items
.character_inserter_settings
= { Yen_Active
: localStorage
.getItem("YenActive"), Yen_Character
: localStorage
.getItem("Yen_Character"), Yen_Color
: localStorage
.getItem("Yen_Color"),
1904 Kita_Active
: localStorage
.getItem("KitaActive"), Kita_Character
: localStorage
.getItem("Kita_Character"), Kita_Color
: localStorage
.getItem("Kita_Color") };
1906 SettingsWindow
.prototype.storeStates = function () {
1908 this.storeImageFilterStates();
1909 //Text replace settings
1910 this.storeTextFilterStates();
1911 //Image Adder settings
1912 this.storeImageAdderStates();
1913 //Thread rebuild settings
1914 this.storeRebuildStates();
1915 //character inserter
1916 this.storeCharacterInserterStates();
1917 //Password replace settings
1918 this.storePasswordStates();
1919 this.retrieveStates();
1921 SettingsWindow
.prototype.storeActiveToggles = function () {
1922 localStorage
.setItem("ImageHidingActive", (document
.getElementById("check-settings0").checked
.toString()));
1923 localStorage
.setItem("TextReplaceActive", (document
.getElementById("check-settings1").checked
.toString()));
1924 localStorage
.setItem("ImageAdderActive", (document
.getElementById("check-settings2").checked
.toString()));
1925 localStorage
.setItem("ThreadRebuilderActive", (document
.getElementById("check-settings3").checked
.toString()));
1926 localStorage
.setItem("YenActive", (document
.getElementById("check-settings4").checked
.toString()));
1927 localStorage
.setItem("KitaActive", (document
.getElementById("check-settings5").checked
.toString()));
1928 localStorage
.setItem("PasswordActive", (document
.getElementById("check-settings6").checked
.toString()));
1930 SettingsWindow
.prototype.storeImageFilterStates = function () {
1931 if (document
.getElementById("Expiration_Time") !== null) {
1932 var time
= document
.getElementById("Expiration_Time");
1933 var millisecond_time
= parseInt(time
.value
) * Constants
.MILLISECONDS_TO_THE_HOUR
;
1934 if (millisecond_time
== 0 || millisecond_time
=== null || millisecond_time
=== undefined)
1935 millisecond_time
= Constants
.DEFAULT_HIDE_EXPIRATION_TIME
;
1936 localStorage
.setItem("Expiration_Time", millisecond_time
.toString());
1937 var md5_filters
= document
.getElementById("MD5_List_FSE").value
;
1938 localStorage
.setItem("MD5_List_FSE", md5_filters
);
1939 Generics
.alert4ChanX("Image Settings Saved", "success", 3);
1942 SettingsWindow
.prototype.storeTextFilterStates = function () {
1943 if (document
.getElementById("FilterRow0") !== null) {
1944 var f_row_moving
= document
.getElementById("FilterRow0");
1945 var Number_of_Filters
= 0;
1946 var Number_of_Filters_actual
= 0;
1947 while (f_row_moving
.nextSibling
!== null) {
1948 if (document
.getElementById("Pattern" + Number_of_Filters
).value
!== "")
1949 Number_of_Filters_actual
++;
1950 Number_of_Filters
++;
1951 f_row_moving
= f_row_moving
.nextSibling
;
1953 window
.localStorage
.setItem("filter_quantity", Number_of_Filters_actual
.toString());
1954 for (var pattern_input
= 0; pattern_input
< Number_of_Filters
; pattern_input
++) {
1955 var pattern_to_store
= document
.getElementById("Pattern" + pattern_input
).value
;
1956 var replacement_to_store
= document
.getElementById("Replacement" + pattern_input
).value
;
1959 if (pattern_to_store
=== "") {
1960 localStorage
.removeItem(pattern_input
+ "FLT");
1963 else if (new RegExp("^\/.*\/\\D+$").test(pattern_to_store
)) { }
1964 else if (new RegExp("^\/.*\/$").test(pattern_to_store
)) {
1965 pattern_to_store
= pattern_to_store
+ setting
;
1967 else if (!new RegExp("^/.*\/\\D$").test(pattern_to_store
)) {
1968 pattern_to_store
= "/" + pattern_to_store
+ "/" + setting
;
1970 //test for breakages, try to cause error
1971 var error_test
= new RegExp(pattern_to_store
.substring(0, pattern_to_store
.lastIndexOf("/") + 1), pattern_to_store
.substring(pattern_to_store
.lastIndexOf("/") + 1));
1974 Generics
.alert4ChanX("Unrecoverable Regex error on pattern " + pattern_input
+ " for " + pattern_to_store
, "error", undefined);
1977 pattern_to_store
= encodeURIComponent(pattern_to_store
);
1978 var save_string
= document
.getElementById("Active" + pattern_input
).checked
+ '=' + pattern_to_store
+ '=' + replacement_to_store
;
1979 window
.localStorage
.setItem(pattern_input
+ "FLT", save_string
);
1981 Generics
.alert4ChanX("Wordfilters Updated!", "success", 3);
1984 SettingsWindow
.prototype.storeImageAdderStates = function () {
1985 if (document
.getElementById("SetImageAdderProperties") !== null) {
1986 var width
= document
.getElementById("width_DIA").value
;
1987 localStorage
.setItem("width_DIA", width
);
1988 var height
= document
.getElementById("height_DIA").value
;
1989 localStorage
.setItem("height_DIA", height
);
1990 var qr_width
= document
.getElementById("qr_width_DIA").value
;
1991 localStorage
.setItem("qr_width_DIA", qr_width
);
1994 SettingsWindow
.prototype.storeRebuildStates = function () {
1995 if (document
.getElementById("setArchive") !== null) {
1996 localStorage
.setItem("ArchiveType_FSE", document
.getElementById("OffsiteArchive").checked
=== true ? "0" : "1");
1999 SettingsWindow
.prototype.storeCharacterInserterStates = function () {
2000 if (document
.getElementById("setCharacter") !== null) {
2001 localStorage
.setItem("Kita_Character", document
.getElementById("selectiveCharacters").value
);
2002 localStorage
.setItem("Kita_Color", document
.getElementById("HexColorKita_text").value
);
2004 else if (document
.getElementById("setQuote") !== null) {
2005 localStorage
.setItem("Yen_Character", document
.getElementById("quoteCharacter").value
);
2006 localStorage
.setItem("Yen_Color", document
.getElementById("HexColorYen_text").value
);
2009 SettingsWindow
.prototype.storePasswordStates = function () {
2010 //password view settings
2011 if (document
.getElementById("check-settings6") !== null)
2012 localStorage
.setItem("PasswordActive", "" + document
.getElementById("check-settings6").checked
);
2014 SettingsWindow
.prototype.clearContainer = function () {
2015 var disposable
= document
.getElementById("disposable_container");
2016 if (disposable
!== null)
2017 this.contents_div
.removeChild(disposable
);
2019 this.contents_div
.removeChild(this.ul_selection_start
);
2021 SettingsWindow
.prototype.rebuildContainer = function () {
2022 this.contents_div
.appendChild(this.ul_selection_start
);
2024 SettingsWindow
.prototype.init = function () {
2026 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}";
2027 this.background_div
.setAttribute('class', 'SettingsBackground');
2028 this.background_div
.setAttribute('id', 'SettingsBackground');
2029 this.background_div
.setAttribute('style', 'display:none');
2030 this.settings_div
.setAttribute('class', 'settingsMain');
2031 this.settings_div
.setAttribute('id', 'settingsWindow');
2032 this.settings_div
.setAttribute('style', 'display:none;width:500px');
2033 this.close_link
.setAttribute('href', 'javascript:void(0)');
2034 this.close_div
.setAttribute('class', 'closeIcon');
2035 this.close_div
.addEventListener('click', function (evt
) { return _this
.hideWindow(); });
2036 this.title_para
.setAttribute('class', 'titleStyle');
2037 this.contents_div
.setAttribute('class', 'contentStyle');
2038 this.end_para
.setAttribute('class', 'footerStyle');
2039 this.ul_selection_start
.setAttribute("ID", "selection_list");
2040 this.generateList(this.contents_div
);
2042 SettingsWindow
.prototype.generateList = function (head_node
) {
2044 this.list_items
.forEach(function (list_item
, index
) {
2045 var li
= document
.createElement('LI');
2046 li
.setAttribute('class', 'settingsItem');
2047 if (list_item
.Text
.indexOf('View') > -1) {
2048 var input
= document
.createElement('INPUT');
2049 var input_id
= 'check-settings' + index
;
2050 input
.setAttribute('TYPE', 'checkbox');
2051 input
.setAttribute('ID', 'check-settings' + index
);
2052 li
.appendChild(input
);
2053 input
.addEventListener('click', function (evt
) { return _this
.storeActiveToggles(); });
2054 var a
= document
.createElement('A');
2055 a
.setAttribute('href', 'javascript:void(0)');
2056 a
.textContent
= list_item
.Text
;
2057 var a_id
= 'tab-settings' + index
;
2058 a
.setAttribute('ID', 'tab-settings' + index
);
2059 var setup_func = function (_a_id
) {
2060 a
.addEventListener('click', function (evt
) { return list_item
.ListenerFunc(_a_id
); });
2062 _this
.ul_selection_start
.appendChild(li
);
2067 var input
= document
.createElement('INPUT');
2068 var input_id
= 'check-settings' + index
;
2069 input
.setAttribute('TYPE', 'checkbox');
2070 input
.setAttribute('ID', 'check-settings' + index
);
2071 input
.addEventListener('click', function (evt
) { return _this
.storeActiveToggles(); });
2072 var label
= document
.createElement('LABEL');
2073 label
.appendChild(input
);
2074 var label_text
= document
.createTextNode(list_item
.Text
);
2075 label
.appendChild(label_text
);
2076 li
.appendChild(label
);
2077 _this
.ul_selection_start
.appendChild(li
);
2078 input
.checked
= _this
.setting_items
.password_settings
== 'true';
2079 var setup_func = function (input_id
) {
2080 label
.addEventListener('click', function (evt
) { return list_item
.ListenerFunc(input_id
); });
2082 setup_func(input_id
);
2086 SettingsWindow
.prototype.activate = function () {
2088 document
.body
.appendChild(this.settings_style
);
2089 this.background_div
.addEventListener('click', function (evt
) { return _this
.hideWindow(); });
2090 document
.body
.appendChild(this.background_div
);
2091 this.settings_div
.appendChild(this.close_link
);
2092 this.close_link
.appendChild(this.close_div
);
2093 this.title_para
.appendChild(this.title_text
);
2094 this.settings_div
.appendChild(this.title_para
);
2095 this.settings_div
.appendChild(this.contents_div
);
2096 this.contents_div
.appendChild(this.ul_selection_start
);
2097 this.end_para
.appendChild(this.end_text
);
2098 this.settings_div
.appendChild(this.end_para
);
2099 document
.body
.appendChild(this.settings_div
);
2100 this.retrieveActiveToggles();
2102 SettingsWindow
.prototype.decideAction = function (node
) { };
2103 SettingsWindow
.prototype.getSettingsArr = function () {
2104 return this.setting_items
;
2106 SettingsWindow
.prototype.displayWindow = function () {
2107 this.background_div
.style
.display
= 'block';
2108 this.settings_div
.style
.display
= 'block';
2109 this.rebuildContainer();
2111 SettingsWindow
.prototype.hideWindow = function () {
2112 this.background_div
.style
.display
= 'none';
2113 this.settings_div
.style
.display
= 'none';
2114 this.clearContainer();
2116 SettingsWindow
.prototype.filterWindow = function (disposable_container
) {
2118 var filter_table
= document
.createElement("table");
2119 filter_table
.setAttribute("style", "text-align:center;");
2120 filter_table
.setAttribute("id", "filter_table");
2121 disposable_container
.appendChild(filter_table
);
2122 var top_row
= document
.createElement("TR");
2123 filter_table
.appendChild(top_row
);
2124 var table_head_active
= document
.createElement("th");
2125 top_row
.appendChild(table_head_active
);
2126 var head_text_active
= document
.createTextNode("Active");
2127 table_head_active
.appendChild(head_text_active
);
2128 var table_head_pattern
= document
.createElement("th");
2129 top_row
.appendChild(table_head_pattern
);
2130 var headTextPattern
= document
.createTextNode("Pattern");
2131 table_head_pattern
.appendChild(headTextPattern
);
2132 var table_head_replacement
= document
.createElement("th");
2133 top_row
.appendChild(table_head_replacement
);
2134 var head_text_replacement
= document
.createTextNode("Replacement");
2135 table_head_replacement
.appendChild(head_text_replacement
);
2136 //Create the pattern table
2137 //loop to create rows
2138 var Number_of_Filters
= parseInt(this.setting_items
.word_replace_settings
.Number_of_Filters
);
2139 console
.log(Number_of_Filters
);
2140 if (Number_of_Filters
=== 0 || isNaN(Number_of_Filters
))
2141 Number_of_Filters
= 6;
2142 for (var i
= 0; i
< Number_of_Filters
; i
++) {
2143 var table_row_contents
= document
.createElement("tr");
2144 table_row_contents
.setAttribute("id", "FilterRow" + i
);
2145 var table_data_active
= document
.createElement("td");
2146 var table_checkbox_active
= document
.createElement("input");
2147 table_checkbox_active
.setAttribute("type", "checkbox");
2148 table_checkbox_active
.setAttribute("id", "Active" + i
);
2149 table_data_active
.appendChild(table_checkbox_active
);
2150 table_row_contents
.appendChild(table_data_active
);
2151 var table_data_pattern
= document
.createElement("td");
2152 var table_input_pattern
= document
.createElement("input");
2153 table_input_pattern
.setAttribute("class", "inputs");
2154 table_input_pattern
.setAttribute("id", "Pattern" + i
);
2155 table_data_pattern
.appendChild(table_input_pattern
);
2156 table_row_contents
.appendChild(table_data_pattern
);
2157 var table_data_replacement
= document
.createElement("td");
2158 var table_input_replacement
= document
.createElement("input");
2159 table_input_replacement
.setAttribute("class", "inputs");
2160 table_input_replacement
.setAttribute("id", "Replacement" + i
);
2161 table_data_replacement
.appendChild(table_input_replacement
);
2162 table_row_contents
.appendChild(table_data_replacement
);
2163 filter_table
.appendChild(table_row_contents
);
2165 var table_last_contents
= document
.createElement("tr");
2166 var table_add_collumn
= document
.createElement("td");
2167 var table_add_row_button
= document
.createElement("input");
2168 var table_subtract_row_button
= document
.createElement("input");
2169 table_subtract_row_button
.setAttribute("type", "button");
2170 table_subtract_row_button
.setAttribute("value", "-");
2171 table_subtract_row_button
.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2172 table_add_collumn
.appendChild(table_subtract_row_button
);
2173 table_subtract_row_button
.addEventListener("click", function (evt
) { return _this
.filterRemoveRow(); });
2174 table_add_row_button
.setAttribute("type", "button");
2175 table_add_row_button
.setAttribute("value", "+");
2176 table_add_row_button
.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2177 table_add_collumn
.appendChild(table_add_row_button
);
2178 table_add_row_button
.addEventListener("click", function (evt
) { return _this
.filterAddRow(); });
2179 table_last_contents
.appendChild(table_add_collumn
);
2180 var table_set_collumn
= document
.createElement("td");
2181 var table_confirm_button
= document
.createElement("input");
2182 table_confirm_button
.setAttribute("type", "button");
2183 table_confirm_button
.setAttribute("id", "table_confirm_button");
2184 table_confirm_button
.setAttribute("value", "Set Replacements");
2185 table_confirm_button
.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2187 table_confirm_button
.addEventListener("click", function (evt
) {
2188 _this
.storeStates();
2189 _this
.clearContainer();
2190 _this
.rebuildContainer();
2192 table_set_collumn
.appendChild(table_confirm_button
);
2193 table_last_contents
.appendChild(table_set_collumn
);
2194 var table_close_collumn
= document
.createElement("td");
2195 var table_close_button
= document
.createElement("input");
2196 table_close_button
.setAttribute("type", "button");
2197 table_close_button
.setAttribute("value", "Close Without Saving");
2198 table_close_button
.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2199 table_close_button
.addEventListener("click", function (evt
) {
2200 _this
.clearContainer();
2201 _this
.rebuildContainer();
2203 table_close_collumn
.appendChild(table_close_button
);
2204 table_last_contents
.appendChild(table_close_collumn
);
2205 filter_table
.appendChild(table_last_contents
);
2207 SettingsWindow
.prototype.filterAddRow = function () {
2209 var filter_table
= document
.getElementById("filter_table");
2210 var Number_of_Filters
= 0;
2211 var filter_children
= document
.getElementById("filter_table").firstChild
;
2212 while (filter_children
.nextSibling
) {
2213 filter_children
= filter_children
.nextSibling
;
2214 Number_of_Filters
++;
2216 var table_row_contents
= document
.createElement("tr");
2217 table_row_contents
.setAttribute("id", "FilterRow" + (Number_of_Filters
- 1));
2218 filter_table
.removeChild(filter_children
);
2219 var table_data_active
= document
.createElement("td");
2220 var table_checkbox_active
= document
.createElement("input");
2221 table_checkbox_active
.setAttribute("type", "checkbox");
2222 table_checkbox_active
.setAttribute("id", "Active" + (Number_of_Filters
- 1));
2223 table_data_active
.appendChild(table_checkbox_active
);
2224 table_row_contents
.appendChild(table_data_active
);
2225 var table_data_pattern
= document
.createElement("td");
2226 var table_input_pattern
= document
.createElement("input");
2227 table_input_pattern
.setAttribute("class", "inputs");
2228 table_input_pattern
.setAttribute("id", "Pattern" + (Number_of_Filters
- 1));
2229 table_data_pattern
.appendChild(table_input_pattern
);
2230 table_row_contents
.appendChild(table_data_pattern
);
2231 var table_data_replacement
= document
.createElement("td");
2232 var table_input_replacement
= document
.createElement("input");
2233 table_input_replacement
.setAttribute("class", "inputs");
2234 table_input_replacement
.setAttribute("id", "Replacement" + (Number_of_Filters
- 1));
2235 table_data_replacement
.appendChild(table_input_replacement
);
2236 table_row_contents
.appendChild(table_data_replacement
);
2237 filter_table
.appendChild(table_row_contents
);
2238 var table_last_contents
= document
.createElement("tr");
2239 var table_add_collumn
= document
.createElement("td");
2240 var table_add_row_button
= document
.createElement("input");
2241 var table_subtract_row_button
= document
.createElement("input");
2242 table_subtract_row_button
.setAttribute("type", "button");
2243 table_subtract_row_button
.setAttribute("value", "-");
2244 table_subtract_row_button
.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2245 table_add_collumn
.appendChild(table_subtract_row_button
);
2246 table_subtract_row_button
.addEventListener("click", function (evt
) { return _this
.filterRemoveRow(); });
2247 table_add_row_button
.setAttribute("type", "button");
2248 table_add_row_button
.setAttribute("value", "+");
2249 table_add_row_button
.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2250 table_add_collumn
.appendChild(table_add_row_button
);
2251 table_add_row_button
.addEventListener("click", function (evt
) { return _this
.filterAddRow(); });
2252 table_last_contents
.appendChild(table_add_collumn
);
2253 var table_set_collumn
= document
.createElement("td");
2254 var table_confirm_button
= document
.createElement("input");
2255 table_confirm_button
.setAttribute("type", "button");
2256 table_confirm_button
.setAttribute("id", "table_confirm_button");
2257 table_confirm_button
.setAttribute("value", "Set Replacements");
2258 table_confirm_button
.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2260 table_confirm_button
.addEventListener("click", function (evt
) {
2261 _this
.storeStates();
2262 _this
.clearContainer();
2263 _this
.rebuildContainer();
2265 table_set_collumn
.appendChild(table_confirm_button
);
2266 table_last_contents
.appendChild(table_set_collumn
);
2267 var table_close_collumn
= document
.createElement("td");
2268 var table_close_button
= document
.createElement("input");
2269 table_close_button
.setAttribute("type", "button");
2270 table_close_button
.setAttribute("value", "Close Without Saving");
2271 table_close_button
.setAttribute("style", "padding: 7px 0; margin:5px 0;");
2272 table_close_button
.addEventListener("click", function (evt
) {
2273 _this
.clearContainer();
2274 _this
.rebuildContainer();
2276 table_close_collumn
.appendChild(table_close_button
);
2277 table_last_contents
.appendChild(table_close_collumn
);
2278 filter_table
.appendChild(table_last_contents
);
2280 SettingsWindow
.prototype.filterRemoveRow = function () {
2281 var filter_table
= document
.getElementById("filter_table");
2282 var Number_of_Filters
= 0;
2283 var filter_children
= document
.getElementById("filter_table").firstChild
;
2284 while (filter_children
.nextSibling
) {
2285 filter_children
= filter_children
.nextSibling
;
2286 Number_of_Filters
++;
2288 if (Number_of_Filters
!= 2) {
2289 filter_table
.deleteRow(--Number_of_Filters
);
2292 SettingsWindow
.prototype.filterSetTable = function () {
2293 var filter_length
= this.setting_items
.word_replace_settings
.Number_of_Filters
;
2294 for (var filter_count
= 0; filter_count
< filter_length
; filter_count
++) {
2295 if (this.setting_items
.word_replace_settings
.Text_Filter_List
[filter_count
].Active
=== null ||
2296 this.setting_items
.word_replace_settings
.Text_Filter_List
[filter_count
].Regex
=== null ||
2297 this.setting_items
.word_replace_settings
.Text_Filter_List
[filter_count
].Replacement
=== null)
2299 if (this.setting_items
.word_replace_settings
.Text_Filter_List
[filter_count
].Active
=== "true") {
2300 document
.getElementById("Active" + filter_count
).checked
= true;
2303 document
.getElementById("Active" + filter_count
).checked
= false;
2305 document
.getElementById("Pattern" + filter_count
).value
=
2306 this.setting_items
.word_replace_settings
.Text_Filter_List
[filter_count
].Regex
;
2307 document
.getElementById("Replacement" + filter_count
).value
=
2308 this.setting_items
.word_replace_settings
.Text_Filter_List
[filter_count
].Replacement
;
2311 return SettingsWindow
;
2312 }(FeatureInterface
));
2313 var Main
= /** @class */ (function (_super
) {
2314 __extends(Main
, _super
);
2316 var _this
= _super
.call(this) || this;
2317 _this
.features
= {}; /*;any bypasses dot notation issues on objects*/
2318 _this
.settings
= {};
2319 if (!Generics
.storageAvailable('localStorage')) {
2320 alert("4F-FSE: local storage error");
2325 _this
.retrieveStates();
2327 _this
.decideAction(document
.getElementById('delform'));
2328 _this
.observeEvents();
2331 Main
.prototype.retrieveStates = function () {
2332 var top_bar
= new TopBar();
2334 this.settings
= top_bar
.getSettingsArr();
2336 Main
.prototype.init = function () {
2337 if (this.settings
.image_hiding_settings
.Active
=== "true") {
2338 this.features
.image_hider
= new ImageHider();
2340 if (this.settings
.word_replace_settings
.Active
=== "true") {
2341 this.features
.text_replacer
= new TextReplacer();
2343 if (this.settings
.image_adder_settings
.Active
=== "true") {
2344 this.features
.danbooru_image_adder
= new DanbooruImageAdder();
2346 if (this.settings
.thread_rebuild_settings
.Active
=== "true") {
2347 this.features
.thread_rebuilder
= new ThreadRebuilder();
2349 if (this.settings
.character_inserter_settings
.Yen_Active
=== "true" || this.settings
.character_inserter_settings
.Kita_Active
=== "true") {
2350 this.features
.character_inserter
= new CharacterInserter(this.settings
.character_inserter_settings
.Yen_Active
=== "true", this.settings
.character_inserter_settings
.Kita_Active
=== "true");
2352 if (this.settings
.password_settings
== 'true') {
2353 this.features
.password_viewer
= new PasswordViewer();
2355 for (var feature_key
in this.features
)
2356 this.features
[feature_key
].retrieveStates();
2358 Main
.prototype.activate = function () { console
.log("4F-FSE Starting"); };
2359 Main
.prototype.storeStates = function () { };
2360 Main
.prototype.observeEvents = function () {
2362 var document_changes
= new MutationObserver(function (mutations
) {
2363 mutations
.forEach(function (mutation
) {
2364 [].forEach
.call(mutation
.addedNodes
, function (node
) { return _this
.decideAction(node
); });
2366 }).observe(document
.body
, { childList
: true, subtree
: true });
2368 Main
.prototype.decideAction = function (node
) {
2369 if (node
=== undefined || node
.tagName
=== undefined)
2372 var itterator
= document
.createNodeIterator(start
, NodeFilter
.SHOW_ELEMENT
);
2374 while ((node
= itterator
.nextNode())) {
2375 if (node
.tagName
!== "BLOCKQUOTE" && node
.tagName
!== "IMG" && node
.tagName
!== "VIDEO")
2377 for (var feature_key
in this.features
) {
2378 this.features
[feature_key
].decideAction(node
);
2383 }(FeatureInterface
));
2384 document
.addEventListener('4chanXInitFinished', function () { new Main(); });