How to use safelist method in wpt

Best JavaScript code snippet using wpt

safelist.user.js

Source:safelist.user.js Github

copy

Full Screen

1// ==UserScript==2// @name Safelist3// @namespace https://github.com/BrokenEagle/JavaScripts4// @version 365// @source https://danbooru.donmai.us/users/237996// @description Alternate Danbooru blacklist handler7// @author BrokenEagle8// @match *://*.donmai.us/*9// @grant none10// @run-at document-body11// @downloadURL https://raw.githubusercontent.com/BrokenEagle/JavaScripts/stable/safelist.user.js12// @require https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js13// ==/UserScript==14(function() {15'use strict';16////////////////17//Constants18const list_callback_retrytime = 5000;19const list_callback_polling_interval = 50;20const timeout_polling_interval = 1000;21const max_danbooru_retries = 50;22const danbooru_recheck_interval = 100;23const debug_console = false;24const help_hints = {25 'enable_tag_hide':"Hide all occurrences of a tag in sidemenus and tables.",26 'enable_text_replace':"Replace all occurrences of a tag with <u><b>Replacement Text</b></u> in prose and titles.",27 'enable_write_mode':"Enable writes to your Danbooru blacklist with the <b><u>Push</u></b> button.",28 'enable_validate_mode':'Enable <a href="https://raw.githubusercontent.com/BrokenEagle/JavaScripts/stable/validateblacklist.user.js">ValidateBlacklist addon</a> if installed. Click <b><u>Validate</u></b> button to activate.',29 'enable_order_mode':'Enable <a href="https://raw.githubusercontent.com/BrokenEagle/JavaScripts/stable/orderblacklist.user.js">OrderBlacklist addon</a> if installed. Click <b><u>Order</u></b> button to activate.',30 'use_session_enable':"Have a different state of enabled on every page tab.",31 'use_session_level':"Have a different active list on every page tab."32};33const safelist_css = `34/*Safelist controls*/35#safelist-box {36 margin-bottom: 0.5em;37}38#safelist-box h1 {39 font-size: 1.16667em;40}41#safelist-box #safelist {42 margin-left: 1em;43}44#safelist-box #safelist .safelist-active,45#safelist-box #safelist .safelist-pending {46 font-style: italic;47}48#safelist-box #safelist .safelist-pending:after {49 content: "(Loading)";50 padding-left: 4px;51}52#safelist-box #safelist .safelist-allnone {53 font-weight: bold;54}55 /*Sidebar list*/56#c-posts #sidebar #safelist-box #safelist li,57#c-favorites #sidebar #safelist-box #safelist li, 58#c-wiki-pages #sidebar #safelist-box #safelist li {59 list-style-type: disc;60}61 /*Topbar list*/62#c-artist-commentaries #safelist-box h1,63#c-comments #safelist-box h1,64#c-users #safelist-box #safelist-box h1,65#c-favorite-groups #safelist-box h1,66#c-pools #safelist-box h1,67#c-post-appeals #safelist-box h1,68#c-post-flags #safelist-box h1,69#c-post-replacements #safelist-box h1,70#c-explore-posts #safelist-box h1 {71 display: inline;72}73#c-artist-commentaries #safelist-box #safelist,74#c-comments #safelist-box #safelist,75#c-users #safelist-box #safelist,76#c-favorite-groups #safelist-box #safelist,77#c-pools #safelist-box #safelist,78#c-post-appeals #safelist-box #safelist,79#c-post-flags #safelist-box #safelist,80#c-post-replacements #safelist-box #safelist,81#c-explore-posts #safelist-box #safelist {82 display: inline;83}84#c-artist-commentaries #safelist-box #safelist li,85#c-comments #safelist-box #safelist li,86#c-users #safelist-box #safelist li,87#c-favorite-groups #safelist-box #safelist li,88#c-pools #safelist-box #safelist li,89#c-post-appeals #safelist-box #safelist li,90#c-post-flags #safelist-box #safelist li,91#c-post-replacements #safelist-box #safelist li,92#c-explore-posts #safelist-box #safelist li {93 display: inline;94 position: relative;95}96#c-artist-commentaries #safelist-box #safelist li:after,97#c-comments #safelist-box #safelist li:after,98#c-users #safelist-box #safelist li:after,99#c-favorite-groups #safelist-box #safelist li:after,100#c-pools #safelist-box #safelist li:after,101#c-post-appeals #safelist-box #safelist li:after,102#c-post-flags #safelist-box #safelist li:after,103#c-post-replacements #safelist-box #safelist li:after,104#c-explore-posts #safelist-box #safelist li:after {105 content: "|";106 font-weight: normal;107}108#c-artist-commentaries #safelist-box #safelist li.safelist-pending:before,109#c-comments #safelist-box #safelist li.safelist-pending:before,110#c-users #safelist-box #safelist li.safelist-pending:before,111#c-favorite-groups #safelist-box #safelist li.safelist-pending:before,112#c-pools #safelist-box #safelist li.safelist-pending:before,113#c-post-appeals #safelist-box #safelist li.safelist-pending:before,114#c-post-flags #safelist-box #safelist li.safelist-pending:before,115#c-post-replacements #safelist-box #safelist li.safelist-pending:before,116#c-explore-posts #safelist-box #safelist li.safelist-pending:before {117 content: "(Loading)";118 top: 20px;119 left: -5px;120 position: absolute;121}122/*Safelist settings*/123 /*General settings*/124#c-posts #a-index #safelist-settings {125 display: block;126}127#c-posts #a-index #safelist-settings input.btn {128 margin-right: 1em;129 margin-top: 1em;130 min-width: 4em;131}132 /*Name row*/133#c-posts #a-index #safelist-settings .safelist-namerow {134 height: 2em;135}136#c-posts #a-index #safelist-settings .safelist-namerow h2 {137 display: inline-block;138 margin-right: 0.5em;139}140#c-posts #a-index #safelist-settings .safelist-namerow .text {141 margin: 0.5em;142 padding-left: 0.5em;143 line-height:150%;144}145#c-posts #a-index #safelist-settings > div {146 margin-bottom: 1em;147}148 /*Input groupings*/149#c-posts #a-index #safelist-settings .input {150 border: 2px solid grey;151 padding: 0.8em;152 border-radius: 10px;153}154#c-posts #a-index #safelist-settings .input label {155 display: block;156 font-weight: bold;157 line-height: 1.5em;158 font-size: 100%;159}160#c-posts #a-index #safelist-settings .input span {161 display: block;162 max-width: 90%;163}164 /*Textblock(s)*/165#c-posts #a-index #safelist-settings textarea {166 width: 90%;167 height: 10em;168}169#c-posts #a-index #safelist-settings .safelist-textblock li {170 list-style-type: disc;171}172#c-posts #a-index #safelist-settings .safelist-textblock ul {173 margin-left: 1.5em;174}175#c-posts #a-index #safelist-settings .safelist-textblock div {176 padding: 0 0.5em;177 border: 2px solid lightgrey;178 width: 90%;179 height: 10em;180 font-size: 0.8em;181 overflow: auto;182}183 /*Checkbox input*/184#c-posts #a-index #safelist-settings .safelist-checkbox input {185 margin-top: 1em;186}187#c-posts #a-index #safelist-settings .safelist-checkbox .hint {188 margin: 1em 0;189}190 /*Fit and placement settings*/191#c-posts #a-index #safelist-settings .safelist-textblock,192#c-posts #a-index #safelist-settings .safelist-checkbox,193#c-posts #a-index #safelist-settings .safelist-textinput,194#c-posts #a-index #safelist-settings .safelist-namerow {195 width: 50%;196 float: left;197 margin-top: 0.5em;198 position: relative;199}200#c-posts #a-index #safelist-settings .safelist-selection,201#c-posts #a-index #safelist-settings .safelist-halfcheckbox {202 width: 25%;203 float: left;204 margin-top: 0.5em;205 position: relative;206}207 /*Tooltip*/208#c-posts #a-index #safelist-settings .tooltip {209 visibility: hidden;210 background-color: black;211 color: #fff;212 text-align: center;213 border-radius: 6px;214 padding: 5px 0;215 border: 2px solid grey;216 /* Position the tooltip */217 position: absolute;218 z-index: 1;219 bottom: 100%;220 left: 4em;221 margin-left: -60px;222}223#c-posts #a-index #safelist-settings .validate-blacklist.tooltip {224 text-align: left;225}226#c-posts #a-index #safelist-settings label:hover ~ .tooltip,227#c-posts #a-index #safelist-settings .tooltip:hover {228 visibility: visible;229}230/*Other settings*/231div.safelist-error {232 font-size: 125%;233 margin: 1em;234 font-weight: bold;235 text-align: left;236 border: 2px solid lightgrey;237}238`;239const css_enabled = `240#page #blacklist-box {241 display: none !important;242}243#page .post-preview,244#page .post-preview.blacklisted,245#page .post-preview.blacklisted.blacklisted-active,246#page #image-container,247#page #image-container.blacklisted,248#page #image-container.blacklisted.blacklisted-active,249#page #has-parent-relationship-preview .blacklisted:not(.blacklisted-active),250#page #has-children-relationship-preview .blacklisted:not(.blacklisted-active) {251 display: none !important;252}253#page .post-preview.safelist-active,254#page .post-preview.blacklisted.safelist-active,255#page .post-preview.blacklisted.blacklisted-active.safelist-active,256#page #image-container.safelist-active,257#page #image-container.blacklisted.safelist-active,258#page #image-container.blacklisted.blacklisted-active.safelist-active {259 display: block !important;260}261#page #has-parent-relationship-preview .blacklisted:not(.blacklisted-active).safelist-active,262#page #has-children-relationship-preview .blacklisted:not(.blacklisted-active).safelist-active {263 display: inline-block !important;264}265`;266/////////////////////267//Global variables268//Main variable for storing permenant data269var safelist_config;270//Main variable for storing session data271var safelist_session;272//Translated tag list to Danbooru's format for processsing blacklist entries273var custom_entries;274//Stores the active and variable menus275var menu_items;276//Stores the precalculated list of hidden posts to reduce penalty for list calculation277var post_list_dict = {};278//Keeps track of CSS styles implemented to allow for swapping of styles279var cssstyle_dict = {};280//Used for quick comparison of raw settings281var json_settings;282////////////////283//Classes284//Main application class285class Safelist {286 constructor(level) {287 this.level = level;288 this.list = [''];289 this.css = '';290 this.hotkey = ['',''];291 this.name ="Level "+level.toUpperCase();292 this.enabled = true;293 }294 validateSafelistData() {295 validateData(this,'css','string',"");296 validateData(this,'name','string',"Level "+this.level.toUpperCase());297 validateData(this,'enabled','boolean',true);298 validateData(this,'background_process','boolean',false);299 if ($.isArray(this.list) && (this.list.length>=1)) {300 let templist = _(this.list).filter(tag=>{return (typeof(tag)==='string')&&(tag!=='');}).defaults(['']).value();301 if (debug_console && (_.xor(this.list,templist).length>0)) {debuglog("Invalid list item(s) found");}302 this.list = templist;303 } else {304 debuglog("Invalid key: list");305 this.list = [""];306 }307 if ($.isArray(this.hotkey) && (this.hotkey.length>=2)){308 if ((typeof this.hotkey[0]!=='string')||($.inArray(this.hotkey[0],['','alt','shift','ctrl'])<0)) {309 debuglog("Invalid hotkey: modifier");310 this.hotkey[0] = "";311 }312 if ((typeof this.hotkey[0]!=='string')||($.inArray(this.hotkey[1],_.concat('','abcdefghijklmnopqrstuvwxyz1234567890'.split('')))<0)) {313 debuglog("Invalid hotkey: keypress");314 this.hotkey[1] = "";315 }316 if (debug_console && this.hotkey.length>2) {debuglog("Invalid hotkey length");}317 this.hotkey = this.hotkey.slice(0,2);318 } else {319 debuglog("Invalid key: hotkey");320 this.hotkey = ["",""];321 }322 _(this).each((val,key)=>{323 if ($.inArray(key,['level','list','css','hotkey','name','enabled','background_process'])<0) {324 debuglog(`Deleting key: ${key}`);325 delete this[key];326 }327 });328 }329 //Getter/setter functions330 get isVariable() {331 return !isNaN(this.level);332 }333 get isPrunable() {334 return (this.isVariable && !this.enabled);335 }336 get isEmpty() {337 return (this.list.length==1) && (this.list[0]==='');338 }339 get tagstring() {340 return this.list.join('\n');341 }342 set tagstring(str) {343 this.list = _(str).split('\n').map($.trim).filter(tag=>{return tag!=='';}).defaults(['']).value();344 }345 //Copied code from Danbooru on adding !important to every entry346 renderedCSS() {347 return '\r\n' + this.css.348 split('\n').349 map(function(str) {350 return str.replace(351 /(\S)\s*(?:!important)?\s*(;|})/,352 "$1 !important$2");353 })354 .join('\n') + '\r\n';355 }356 357 /////////////////////////358 //Render HTML functions359 360 //Links in the side menu361 renderedSide() {362 if (!this.enabled) {return "";}363 const constantaddon = (this.isVariable?"":'class="safelist-allnone"');364 return `365 <li ${constantaddon}><a href="#" id="safe-level-${this.level}">${this.name}</a></li>`;366 }367 //Sections in the setting menu368 renderLevelSetting() {369 let optionitem = "";370 let listitem = `371 <div class="input" id="safelist-settings-level-${this.level}">`;372 listitem += this.renderNamerow();373 listitem += this.renderKeyselect();374 listitem += (this.isVariable?this.renderBackgroundOption():'');375 listitem += `376 <div class="clearfix"></div>`;377 listitem += (this.isVariable?this.renderTagBlock():this.renderLevelCheckbox());378 listitem += this.renderCSSBlock();379 listitem += `380 <div class="clearfix"></div>`;381 optionitem += this.renderLevelButtons();382 optionitem += this.renderFeedback();383 if ($.inArray(this.level,['a','n'])<0) {384 listitem += optionitem;385 }386 return listitem + `387 </div>`;388 }389 //List name, edit button and textbox390 renderNamerow() {391 let escapedname = sanitizeForHTML(this.name);392 let nameitem = `393 <div class="safelist-namerow">394 <h2 id="safelist-heading-level-${this.level}">${this.name}</h2>395 <input type="text" name="safelist-name-level-${this.level}" value="${escapedname}" size="40" autocomplete="off" class="text">`;396 nameitem += this.renderButton('edit');397 return nameitem + `398 </div>`;399 }400 //Hotkey dropdowns401 renderKeyselect() {402 let item = `403 <div class="safelist-selection">404 <label for="safelist_keyselect_level_${this.level}" style="width:5em">Hotkey</label>405 <select name="safelistKeymodifierLevel${this.level}" id="safelist_modifier_level_${this.level}">`;406 $.each(['','alt','shift','ctrl'], (i,key)=>{407 let selected = (this.hotkey[0]===key?'selected="selected"':'');408 let ucase = _.startCase(key);409 item += `\r\n <option ${selected} value="${key}">${ucase}</option>`;410 });411 item += `</select>412 <select name="safelistKeyselectLevel${this.level}" id="safelist_keyselect_level_${this.level}">`;413 $.each(_.concat('','abcdefghijklmnopqrstuvwxyz1234567890'.split('')), (i,key)=>{414 let selected = (this.hotkey[1]===key?'selected="selected"':'');415 let ucase = key.toUpperCase();416 item += `\r\n <option ${selected} value="${key}">${ucase}</option>`;417 });418 return item + `419 </select>420 <span class="tooltip">Changes list when Safelist is active. Keep in mind existing <a href="/static/keyboard_shortcuts">Danbooru hotkeys</a>.</span>421 </div>`;422 }423 //Background process options424 renderBackgroundOption() {425 const value = (this.background_process ? "checked" : "");426 return `427 <div class="safelist-halfcheckbox">428 <label for="safelist_background_process_level_${this.level}" style="width:12em">Background Process</label>429 <input type="checkbox" ${value} name="safelistBackgroundProcessLevel${this.level.toUpperCase()}" id="safelist_background_process_level_${this.level}">430 <span class="tooltip">Process this list in the background so that changing lists is more responsive.</span>431 </div>`;432 }433 //For constant levels all and none... takes place of taglist434 renderLevelCheckbox() {435 const value = (this.enabled ? "checked" : "");436 const label = (this.level=='a'?"Enable all":"Enable none");437 const hint = (this.level=='a'?"Shows everything.":"Shows nothing.");438 return `439 <div class="safelist-checkbox">440 <label for="safelist-enable-level-${this.level}" style="width:9em">${label} list</label>441 <input type="checkbox" ${value} name="safelistCheckboxLevel${this.level.toUpperCase()}" id="safelist-enable-level-${this.level}">442 <span class="tooltip">${hint}</span>443 </div>`;444 }445 //For custom levels446 renderTagBlock() {447 return `448 <div class="safelist-textblock">449 <label for="safelist_tags_level_${this.level}" style="width:9em">Blacklisted tags</label>450 <textarea name="safelistTagsLevel${this.level}" id="safelist_tags_level_${this.level}" cols="40" rows="5" autocomplete="off">${this.tagstring}</textarea>451 <span class="tooltip">Put any tag combinations you never want to see here. Each combination should go on a separate line. <a href="/wiki_pages/help:blacklists">View help.</a></span>452 </div>`;453 }454 //Custom style per level455 renderCSSBlock() {456 return `457 <div class="safelist-textblock">458 <label for="safelist_css_level_${this.level}" style="width:7em">Custom CSS</label>459 <textarea name="safelistCSSLevel${this.level}" id="safelist_css_level_${this.level}" cols="40" rows="5" autocomplete="off">${this.css}</textarea>460 <span class="tooltip">Style to apply to the whole site.</span>461 </div>`;462 }463 //Button renderer464 renderButton(type) {465 const value = _.startCase(type);466 return `467 <input type="submit" name="safelist-${type}-level-${this.level}" value="${value}" class="btn safelist-${type}">`;468 }469 //Renders all level buttons470 renderLevelButtons() {471 let optionitem = `472 <div class="safelist-setting-buttons">`;473 optionitem += this.renderButton('pull');474 optionitem += this.renderButton('push');475 optionitem += this.renderButton('validate');476 optionitem += this.renderButton('reset');477 optionitem += this.renderButton('apply');478 optionitem += this.renderButton('order');479 optionitem += this.renderButton('delete');480 return optionitem + `481 </div>`;482 }483 //For the addon modules484 renderFeedback() {485 return `486 <div class="safelist-output">487 <div class="safelist-textblock">488 <label for="safelist_feedback_level_${this.level}">Feedback</label>489 <textarea readonly name="safelistFeedbackLevel${this.level}" id="safelist_feedback_level_${this.level}" cols="40" rows="5"></textarea>490 </div>491 <div class="safelist-textblock">492 <label for="safelist_results_level_${this.level}" style="width:15em">Results</label>493 <div id="safelist_results_level_${this.level}"></div>494 <span class="validate-blacklist"></span>495 </div>496 <div class="clearfix"></div>497 </div>`;498 }499 500 ////////////////////501 //Click functions502 503 //Side menu click504 setSideLevelClick() {505 $("#safe-level-"+this.level).off().click(function(e) {506 //Click events need their own try/catch blocks507 try {508 console.time("LevelChange");509 $("#show-posts-link").click();510 //The only context we have on a click is "e", so get the level from it511 let match = /safe-level-(.*)/.exec(e.currentTarget.id);512 if(match) {513 let key = match[1];514 safelist_session.active_list = key;515 let value = safelist_config.levels[key];516 if (post_list_dict[key]===undefined){517 debuglog("List not ready!");518 //If no lists are being actively calculated...?519 if (Object.keys(calculateActiveList.background_work).length===0) {520 calculateActiveList.handle = setTimeout(calculateActiveList,1);521 }522 setActiveList(key,"pending");523 //Else calculateActiveList will automatically switch over524 } else {525 debuglog("Precalculated list change");526 showHidePosts(post_list_dict[key]);527 setActiveList(key,"active");528 }529 setCSSStyle(value.renderedCSS(),"safelist_user_css");530 setSessionData();531 if (safelist_config.enable_tag_hide) {532 value.scrubTags();533 }534 if (safelist_config.enable_text_replace) {535 value.scrubText();536 }537 }538 console.timeEnd("LevelChange");539 e.preventDefault();540 } catch (e) {541 errorlog(e);542 throw e;543 }544 });545 }546 //Activate hotkey for level if it exists547 setKeypress() {548 $(document).off("keydown.safelist.level"+this.level);549 if ((!$.isArray(this.hotkey)) || (this.hotkey.length < 2) || (this.hotkey[1] === '')) {return;}550 let combokey = (this.hotkey[0] === ''?this.hotkey[1]:this.hotkey.join('+'));551 debuglog(this.level,String(this.hotkey),combokey);552 $(document).on("keydown.safelist.level"+this.level, null,combokey, e=>{553 if (safelist_session.enable_safelist) {554 $("#safe-level-"+this.level).click();555 }556 });557 }558 //Set all level clicks for menu559 setMenuLevelClicks() {560 $(`[name="safelist-name-level-${this.level}"]`).hide();561 $(`[name="safelist-reset-level-${this.level}"]`).hide();562 $(`[name="safelist-apply-level-${this.level}"]`).hide();563 $(`#safelist-settings-level-${this.level} .safelist-output`).hide();564 this.setNameChangeClick();565 this.setPullButtonClick();566 this.setPushButtonClick();567 this.setValidateButtonClick();568 this.setOrderButtonClick();569 this.setResetButtonClick();570 this.setApplyButtonClick();571 this.setDeleteButtonClick();572 }573 //Set the name edit button574 setNameChangeClick() {575 $(`[name="safelist-edit-level-${this.level}"]`).off().click(function(e) {576 try {577 let match = /safelist-edit-level-(.*)/.exec(e.currentTarget.name);578 if (match) {579 let level = match[1];580 $("#safelist-heading-level-"+level).hide();581 $(`[name="safelist-edit-level-${level}"]`).hide();582 $(`[name="safelist-name-level-${level}"]`).show();583 }584 } catch (e) {585 errorlog(e);586 throw e;587 }588 });589 }590 //Set the pull blacklist button591 setPullButtonClick() {592 $(`[name="safelist-pull-level-${this.level}"]`).off().click(function(e) {593 try {594 let match = /safelist-pull-level-(.*)/.exec(e.target.name);595 if (match) {596 let level = match[1];597 $("#safelist_tags_level_"+level).val(598 Danbooru.meta("blacklisted-tags")599 .replace(/(rating:[qes])\w+/ig, "$1")600 .toLowerCase().split(/,/).join('\n'));601 }602 } catch (e) {603 errorlog(e);604 throw e;605 }606 });607 }608 //Set the push blacklist button609 setPushButtonClick() {610 $(`[name="safelist-push-level-${this.level}"]`).off().click(function(e) {611 try {612 let match = /safelist-push-level-(.*)/.exec(e.target.name);613 if (match) {614 let level = match[1];615 let keyinput = confirm("Update your blacklist on Danbooru?");616 if (keyinput) {617 let tagdata = $("#safelist_tags_level_"+level).val().replace(/\n/g,'\r\n');618 let senddata = {'user':{'blacklisted_tags': tagdata}};619 let user = Danbooru.meta("current-user-id");620 $.ajax({621 type: "PUT",622 url: "/users/" + user + ".json",623 data: senddata,624 success: function(data) {625 debuglog("Success",data);626 Danbooru.notice("Settings updated.");627 },628 error: function(data) {629 debuglog("Failure",data);630 Danbooru.notice("Error updating settings!");631 }632 });633 }634 }635 } catch (e) {636 errorlog(e);637 throw e;638 }639 });640 }641 //Set the validate blacklist button642 setValidateButtonClick() {643 $(`[name="safelist-validate-level-${this.level}"]`).off().click(function(e) {644 try {645 let match = /safelist-validate-level-(.*)/.exec(e.target.name);646 if (match) {647 let level = match[1];648 //Only process if ValidateBlacklist is installed649 if (typeof(ValidateBlacklist)=='function') {650 $(`[name="safelist-validate-level-${level}"]`).hide();651 $(`[name="safelist-reset-level-${level}"]`).show();652 $(`#safelist-settings-level-${level} .safelist-output`).show();653 $(`[name="safelist-order-level-${level}"]`)[0].setAttribute("disabled","true");654 //Get current tags in tag box655 var safelevel = safelist_config.levels[level];656 let taglist = $("#safelist_tags_level_"+level).val().split('\n');657 safelevel.$results = $("#safelist_results_level_"+level);658 safelevel.logger = new TextboxLogger("#safelist_feedback_level_"+level);659 safelevel.blacklist = new ValidateBlacklist(taglist,safelevel.logger);660 safelevel.instance = ValidateBlacklist;661 //Clear both output areas662 safelevel.logger.clear();663 safelevel.$results[0].innerHTML = "";664 //Start processing the lists665 safelevel.blacklist.processList();666 setTimeout(()=>{safelevel.addonCallback();},timeout_polling_interval);667 } else {668 Danbooru.notice("Validate Blacklist not installed!");669 $(`[name="safelist-validate-level-${level}"]`)[0].setAttribute("disabled","true");670 }671 }672 } catch (e) {673 errorlog(e);674 throw e;675 }676 });677 }678 setOrderButtonClick() {679 $(`[name="safelist-order-level-${this.level}"]`).off().click(function(e) {680 try {681 let match = /safelist-order-level-(.*)/.exec(e.target.name);682 if (match) {683 let level = match[1];684 //Only process if ValidateBlacklist is installed685 if (typeof(OrderBlacklist)=='function') {686 $(`[name="safelist-order-level-${level}"]`).hide();687 $(`[name="safelist-reset-level-${level}"]`).show();688 $(`#safelist-settings-level-${level} .safelist-output`).show();689 $(`[name="safelist-validate-level-${level}"]`)[0].setAttribute("disabled","true");690 //Get current tags in tag box691 var safelevel = safelist_config.levels[level];692 let taglist = $("#safelist_tags_level_"+level).val().split('\n');693 safelevel.$results = $("#safelist_results_level_"+level);694 safelevel.logger = new TextboxLogger("#safelist_feedback_level_"+level);695 safelevel.blacklist = new OrderBlacklist(taglist,safelevel.logger);696 safelevel.instance = OrderBlacklist;697 //Clear both output areas698 safelevel.logger.clear();699 safelevel.$results[0].innerHTML = "";700 //Start processing the lists701 safelevel.blacklist.processList();702 setTimeout(()=>{safelevel.addonCallback();},timeout_polling_interval);703 } else {704 Danbooru.notice("Order Blacklist not installed!");705 $(`[name="safelist-order-level-${level}"]`)[0].setAttribute("disabled","true");706 }707 }708 } catch (e) {709 errorlog(e);710 throw e;711 }712 });713 }714 //Set the reset button715 setResetButtonClick() {716 $(`[name="safelist-reset-level-${this.level}"]`).off().click(function(e) {717 try {718 let match = /safelist-reset-level-(.*)/.exec(e.target.name);719 if (match) {720 let level = match[1];721 //Was the validate global variable instantiated...?722 var safelevel = safelist_config.levels[level];723 if ('blacklist' in safelevel) {724 $(`[name="safelist-reset-level-${level}"]`).hide();725 $(`[name="safelist-validate-level-${level}"]`).show();726 safelevel.blacklist.allstop();727 } else {728 Danbooru.notice("Safelist addon not initiated!");729 $(`[name="safelist-reset-level-${level}"]`)[0].setAttribute("disabled","true");730 }731 }732 } catch (e) {733 errorlog(e);734 throw e;735 }736 });737 }738 //Set apply button739 setApplyButtonClick() {740 $(`[name="safelist-apply-level-${this.level}"]`).off().click(function(e) {741 try {742 let match = /safelist-apply-level-(.*)/.exec(e.target.name);743 if (match) {744 let level = match[1];745 var safelevel = safelist_config.levels[level];746 if ('blacklist' in safelevel) {747 $(`[name="safelist-apply-level-${level}"]`).hide();748 safelevel.resetButtons();749 $("#safelist_tags_level_"+level).val(safelevel.blacklist.reconstructed_list.join('\n'));750 safelevel.logger.log("Blacklist has been updated in text area!");751 safelevel.logger.log("Click 'Save' to update Safelist settings...");752 if (safelist_config.enable_write_mode) {753 safelevel.logger.log("...or click 'Push' to update Danbooru blacklist.");754 }755 } else {756 Danbooru.notice("Safelist addon not initiated!");757 $(`[name="safelist-apply-level-${level}"]`)[0].setAttribute("disabled","true");758 }759 }760 } catch (e) {761 errorlog(e);762 throw e;763 }764 });765 }766 //Set delete button767 setDeleteButtonClick() {768 $(`[name="safelist-delete-level-${this.level}"]`).off().click(function(e) {769 try {770 let match = /safelist-delete-level-(.*)/.exec(e.target.name);771 if (match) {772 let level = match[1];773 let value = safelist_config.levels[level];774 $("#safelist-settings-level-"+level).hide();775 value.enabled=false;776 }777 } catch (e) {778 errorlog(e);779 throw e;780 }781 });782 }783 784 /////////////////////785 //Helper functions786 787 //Callback for the validate button788 addonCallback() {789 try {790 if (this.blacklist.is_ready) {791 this.$results[0].innerHTML = this.blacklist.reconstructed_html;792 $(`[name="safelist-reset-level-${this.level}"]`).hide();793 if (!this.blacklist.unchanged) {794 $(`[name="safelist-apply-level-${this.level}"]`).show();795 //Load the legend...796 //Doing this here so that we don't have to check for the addon at program initialization797 let $tooltip = $(`#safelist_results_level_${this.level} + .validate-blacklist`);798 let $label = $(`[for=safelist_results_level_${this.level}]`);799 if ($tooltip.length && (this.instance.legend!==undefined)) {800 $tooltip[0].innerHTML = this.instance.legend;801 $tooltip.addClass("tooltip");802 $label[0].innerHTML = "Results (hover for legend)";803 }804 } else {805 this.resetButtons();806 }807 } else if ((!this.blacklist.stop)&&(!this.blacklist.error)) {808 debuglog("Reschedule callback");809 var me = this;810 setTimeout(()=>{me.addonCallback();},timeout_polling_interval);811 }812 } catch (e) {813 errorlog(e);814 throw e;815 }816 }817 resetButtons() {818 $(`[name="safelist-validate-level-${this.level}"]`).show();819 if (safelist_config.enable_validate_mode) {$(`[name="safelist-validate-level-${this.level}"]`)[0].removeAttribute("disabled");}820 $(`[name="safelist-order-level-${this.level}"]`).show();821 if (safelist_config.enable_order_mode) {$(`[name="safelist-order-level-${this.level}"]`)[0].removeAttribute("disabled");}822 }823 824 //Tag & text functions825 826 //The following are completely tag related and will be hidden827 scrubTags() {828 //Only start calculating once the active enabled list is done829 if (checkPriority()) {830 var me = this;831 setTimeout(()=>{me.scrubTags();},500);832 return;833 }834 showTags();835 if (this.isEmpty) {return;}836 console.time("ScrubTags");837 if ($("#c-posts").length) {838 hideTags(".search-tag",1,this.list);839 }840 if ($("#c-favorites").length) {841 hideTags(".search-tag",1,this.list);842 }843 if ($("#c-wiki-pages").length) {844 hideTags("#c-wiki-pages li a",0,this.list);845 hideTags("#c-wiki-pages .striped td:nth-of-type(1) a",2,this.list);846 }847 if ($("#c-wiki-page-versions").length) {848 hideTags("#c-wiki-page-versions li a",0,this.list);849 hideTags("#c-wiki-page-versions .striped td:nth-of-type(1) a",2,this.list);850 }851 if ($("#c-artists").length) {852 hideTags("#c-artists .striped td:nth-of-type(1) a",2,this.list);853 }854 if ($("#c-artist-versions").length) {855 hideTags("#c-artist-versions td:nth-of-type(1) a",2,this.list);856 }857 if ($("#c-tags").length) {858 hideTags("#c-tags .striped td:nth-of-type(2) a:nth-of-type(2)",2,this.list);859 }860 if ($("#c-meta-searches").length) {861 hideTags("#c-meta-searches .striped td:nth-of-type(1)",1,this.list);862 hideTags("#c-meta-searches .striped td:nth-of-type(2)",1,this.list);863 }864 if ($("#c-explore-posts #a-searches").length) {865 hideTags("#c-explore-posts #a-searches .striped td:nth-of-type(1) a",2,this.list);866 }867 if ($("#c-explore-posts #a-missed-searches").length) {868 hideTags("#c-explore-posts #a-missed-searches .striped td:nth-of-type(1) a",2,this.list);869 }870 console.timeEnd("ScrubTags");871 }872 //The following may only be partially tag-related and will be replaced with replacement text873 scrubText() {874 if (this.isEmpty) {return;}875 if ((!validateExpandableStatus.isdone)||checkPriority()) {876 var me = this;877 setTimeout(()=>{me.scrubText();},500);878 return;879 }880 console.time("ScrubText");881 if ($("#c-forum-topics #a-index").length) {882 hideText("#c-forum-topics #a-index .striped td:nth-of-type(1) a:not(.last-page)",this.list);883 }884 if ($("#c-forum-topics #a-show").length) {885 hideText("#c-forum-topics #a-show h1",this.list);886 }887 if ($("#c-dmails #a-index").length) {888 hideText("#c-dmails #a-index .striped td:nth-of-type(4) a",this.list);889 }890 if ($("#c-dmails #a-show").length) {891 hideText("#c-dmails #a-show h2",this.list);892 }893 if ($("#c-wiki-pages #a-show").length) {894 hideText("#wiki-page-title",this.list);895 }896 if ($("#c-artists #a-show").length) {897 hideText("#c-artists #a-show h1",this.list);898 }899 if ($("#c-upload-tags-report #a-show").length) {900 hideText("#c-upload-tags-report #a-show .striped td:not(:first-of-type)",this.list);901 }902 if ($("#c-post-versions #a-index").length) {903 hideText(".diff-list",this.list);904 }905 if ($("#c-notes #a-index").length) {906 hideText("#c-notes #a-index .striped td:nth-of-type(4)",this.list);907 }908 if ($("#c-note-versions #a-index").length) {909 hideText("#c-note-versions #a-index .striped td:nth-of-type(4)",this.list);910 }911 if ($("#c-posts #a-show").length) {912 hideText("#c-posts #a-show #artist-commentary h3",this.list);913 delayHideText("#notes article","#c-posts #a-show .note-box-inner-border",this.list);914 delayHideText("#notes article","#c-posts #a-show .note-body",this.list);915 }916 if ($("#c-pools #a-index").length) {917 hideText("#c-pools #a-index .striped td:nth-of-type(2) a:not(.last-page)",this.list);918 }919 if ($("#c-pools #a-show").length) {920 hideText("#c-pools #a-show h1 a",this.list);921 }922 if ($("#c-pools #a-gallery").length) {923 hideText("#c-pools #a-gallery .desc",this.list);924 }925 if ($("#c-pool-versions #a-index").length) {926 hideText("#c-pool-versions #a-index .striped td:nth-of-type(1)",this.list);927 }928 if ($("#c-bans #a-index").length) {929 hideText("#c-bans #a-index .striped td:nth-of-type(5)",this.list);930 }931 if ($("#c-user-feedbacks #a-index").length) {932 hideText("#c-user-feedbacks #a-index .striped td:nth-of-type(4)",this.list);933 }934 if ($("#c-burs #a-index").length) {935 hideText("#c-burs #a-index .striped td:nth-of-type(4)",this.list);936 }937 if ($("#c-artist-commentaries #a-index").length) {938 hideText("#c-artist-commentaries #a-index .striped h3",this.list);939 }940 if ($("#c-artist-commentary-versions #a-index").length) {941 //Replace this with h3 if https://github.com/r888888888/danbooru/issues/3187 gets fixed942 hideText("#c-artist-commentary-versions #a-index .striped td:nth-of-type(2)",this.list);943 hideText("#c-artist-commentary-versions #a-index .striped td:nth-of-type(3)",this.list);944 }945 if ($("#c-tag-aliases #a-index").length) {946 hideText("#c-tag-aliases #a-index .striped td:nth-of-type(1)",this.list);947 hideText("#c-tag-aliases #a-index .striped td:nth-of-type(2)",this.list);948 }949 if ($("#c-tag-implications #a-index").length) {950 hideText("#c-tag-implications #a-index .striped td:nth-of-type(1)",this.list);951 hideText("#c-tag-implications #a-index .striped td:nth-of-type(2)",this.list);952 }953 if ($("#c-post-appeals #a-index").length) {954 hideText("#c-post-appeals #a-index .striped td:nth-of-type(2)",this.list);955 }956 if ($("#c-post-flags #a-index").length) {957 hideText("#c-post-flags #a-index .striped td:nth-of-type(2)",this.list);958 }959 //There are a lot of these, so check every time960 if ($(".prose:not(.dtext-preview)").length) {961 hideText(".prose:not(.dtext-preview)",this.list);962 fixExpandables();963 }964 console.timeEnd("ScrubText",this.list);965 }966}967//////////////////968//Main functions969function initializeSafelist() {970 getActualTime("Initialize start:");971 console.time("Initialize");972 console.time("PreInit");973 loadProgramData();974 loadSessionData();975 validateExpandableStatus();976 console.timeEnd("PreInit");977 if ($("#blacklist-box").length&&!($("#c-wiki-page-versions").length)) {978 console.time("SideSetup");979 setCSSStyle(safelist_css,"safelist_css");980 menu_items = calculateRenderedMenus();981 $("#blacklist-box").after(renderSidemenu());982 setListClicks();983 post_list_dict.a = [];984 post_list_dict.n = safelistPosts();985 createEntryArray();986 console.timeEnd("SideSetup");987 if (safelist_session.enable_safelist) {988 $("#enable-safelist").click();989 } else {990 $("#disable-safelist").click();991 }992 if ('requestIdleCallback' in window) {993 calculateLists.handle = requestIdleCallback(calculateLists);994 } else {995 //Need to test out the following996 calculateLists.handle = setTimeout(calculateLists,list_callback_retrytime);997 }998 } else if ((safelist_session.enable_safelist) && (safelist_session.active_list !== undefined)) {999 //Activate any non-post functions if applicable1000 console.time("NonPost");1001 //Value could be undefined if the active list was pruned1002 let value = safelist_config.levels[safelist_session.active_list];1003 //For the check priority function1004 post_list_dict[safelist_session.active_list] = [];1005 value && setCSSStyle(value.renderedCSS(),"safelist_user_css");1006 if (safelist_config.enable_text_replace) {1007 value && value.scrubText();1008 }1009 if (safelist_config.enable_tag_hide) {1010 value && value.scrubTags();1011 }1012 console.timeEnd("NonPost");1013 }1014 //Render settings menu only from post index page1015 //Since it starts out hidden, we are doing it last1016 if($("#c-posts #a-index").length) {1017 console.time("MenuSetup");1018 $("#post-sections li:last-child").after(renderSettingMenuLink());1019 $("#excerpt").before(renderSettingMenu());1020 $("#safelist-settings").hide();1021 setSettingsClicks();1022 if (!safelist_config.enable_write_mode) {1023 $.each($(".safelist-push"), (i,entry)=>{entry.setAttribute("disabled",true);});1024 }1025 if (!safelist_config.enable_validate_mode) {1026 $.each($(".safelist-validate"), (i,entry)=>{entry.setAttribute("disabled",true);});1027 }1028 if (!safelist_config.enable_order_mode) {1029 $.each($(".safelist-order"), (i,entry)=>{entry.setAttribute("disabled",true);});1030 }1031 console.timeEnd("MenuSetup");1032 }1033 console.timeEnd("Initialize");1034}1035function reloadSafelist(configure,changed_menus) {1036 console.time("Reload");1037 //The side menu has changed, so rerender it1038 if (changed_menus.length) {1039 //Redraw the safelist sidemenu1040 $("#safelist-box")[0].outerHTML = renderSidemenu();1041 setListClicks();1042 setActiveList(safelist_session.active_list,'active');1043 //The following avoids using (enable/disable).click(), which can potentially cause unneeded work1044 if(safelist_session.enable_safelist) {1045 $("#enable-safelist").hide();1046 $("#disable-safelist").show();1047 }1048 else {1049 $("#safelist").hide();1050 $("#enable-safelist").show();1051 $("#disable-safelist").hide();1052 }1053 }1054 if ('levels' in configure) {1055 //A list has changed, so recreate the entry array1056 if (_.reduce(safelist_config.levels,(result,value)=>{return result || ('list' in value);},false)) {1057 debuglog("Updating custom entries...");1058 createEntryArray();1059 }1060 $.each(configure.levels,(level,val)=>{1061 let value = safelist_config.levels[level];1062 if ('list' in val) {1063 delete post_list_dict[level];1064 if (safelist_session.enable_safelist && (safelist_session.active_list == level)) {1065 //The list was active, so set it to pending1066 setActiveList(safelist_session.active_list,'pending');1067 signalActiveList(true);1068 }1069 }1070 if (('css' in val) && safelist_session.enable_safelist && (safelist_session.active_list == level)) {1071 setCSSStyle(value.renderedCSS(),"safelist_user_css");1072 }1073 if ('name' in val) {1074 $("#safelist-heading-level-"+level)[0].innerHTML = value.name;1075 if (changed_menus.length === 0) {$("#safe-level-"+level)[0].innerHTML = value.name;}1076 }1077 if ('hotkey' in val) {1078 value.setKeypress();1079 }1080 });1081 restartLists();1082 }1083 if ('name' in configure) {1084 $("#safelist-box h1")[0].innerHTML = safelist_config.name;1085 $("#show-safelist-settings-link")[0].innerHTML = safelist_config.name;1086 }1087 let value = safelist_config.levels[safelist_session.active_list];1088 if (('enable_text_replace' in configure) || (('replacement_text' in configure))) {1089 if (safelist_config.enable_text_replace) {1090 //Only hide text if the list is defined and enabled1091 value && value.enabled && value.scrubText();1092 } else {1093 showText();1094 }1095 }1096 if ('enable_tag_hide' in configure) {1097 if (safelist_config.enable_tag_hide) {1098 //Only hide tags if the list is defined and enabled1099 value && value.enabled && value.scrubTags();1100 } else {1101 showTags();1102 }1103 }1104 if ('enable_write_mode' in configure) {1105 if (safelist_config.enable_write_mode) {1106 $.each($(".safelist-push"), (i,entry)=>{entry.removeAttribute("disabled");});1107 } else {1108 $.each($(".safelist-push"), (i,entry)=>{entry.setAttribute("disabled",true);});1109 }1110 }1111 if ('enable_validate_mode' in configure) {1112 if (safelist_config.enable_validate_mode) {1113 $.each($(".safelist-validate"), (i,entry)=>{entry.removeAttribute("disabled");});1114 } else {1115 $.each($(".safelist-validate"), (i,entry)=>{entry.setAttribute("disabled",true);});1116 }1117 }1118 if ('enable_order_mode' in configure) {1119 if (safelist_config.enable_validate_mode) {1120 $.each($(".safelist-order"), (i,entry)=>{entry.removeAttribute("disabled");});1121 } else {1122 $.each($(".safelist-order"), (i,entry)=>{entry.setAttribute("disabled",true);});1123 }1124 }1125 if (('use_session_enable' in configure) || ('use_session_level' in configure)) {1126 setSessionData();1127 }1128 $("#safelist-rawsettings > textarea").val(json_settings);1129 console.timeEnd("Reload");1130}1131//Set Safelist config before calling this function1132function resetAllSettings() {1133 //Cancel any list calculations1134 signalActiveList();1135 restartLists();1136 menu_items = calculateRenderedMenus();1137 createEntryArray();1138 post_list_dict = {};1139 post_list_dict.a = [];1140 post_list_dict.n = safelistPosts();1141 //Side menu items1142 $("#safelist-box")[0].outerHTML = renderSidemenu();1143 setListClicks();1144 initialSessionData(true);1145 $("#disable-safelist").click();1146 showHidePosts(safelistPosts());1147 //Settings menu1148 $("#show-safelist-settings-link")[0].innerHTML = safelist_config.name;1149 $("#safelist-settings")[0].outerHTML = renderSettingMenu();1150 $("#safelist-settings").hide();1151 setSettingsClicks();1152 if (!safelist_config.enable_write_mode) {1153 $.each($(".safelist-push"), (i,entry)=>{entry.setAttribute("disabled",true);});1154 }1155 if (!safelist_config.enable_validate_mode) {1156 $.each($(".safelist-validate"), (i,entry)=>{entry.setAttribute("disabled",true);});1157 }1158 if (!safelist_config.enable_order_mode) {1159 $.each($(".safelist-order"), (i,entry)=>{entry.setAttribute("disabled",true);});1160 }1161}1162/////////////////////1163//Helper functions1164//Resets all program variables to Default values1165function initialProgramData() {1166 safelist_config = {};1167 safelist_config.name = "Safelist";1168 safelist_config.levels = {};1169 ['a','n','1'].map((level,i)=>{ safelist_config.levels[level]=new Safelist(level);});1170 safelist_config.next_index = 2;1171 safelist_config.enable_tag_hide = false;1172 safelist_config.enable_text_replace = false;1173 safelist_config.enable_validate_mode = false;1174 safelist_config.enable_order_mode = false;1175 safelist_config.enable_write_mode = false;1176 safelist_config.use_session_enable = false;1177 safelist_config.use_session_level = false;1178 safelist_config.replacement_text = '';1179}1180//Loads program data from storage1181function loadProgramData() {1182 safelist_config = window.localStorage.safelist_config;1183 if(safelist_config!==undefined){1184 try {1185 safelist_config = JSON.parse(safelist_config);1186 } catch (e) {1187 Danbooru.notice("Settings corrupted... reverting to initial configuration.");1188 initialProgramData();1189 setProgramData();1190 return;1191 }1192 $.each(safelist_config.levels, (level,val)=>{1193 safelist_config.levels[level] = Object.assign(new Safelist(''),val);1194 });1195 pruneCustomLists();1196 } else {1197 initialProgramData();1198 }1199 setProgramData();1200}1201//Stores program data1202function setProgramData() {1203 validateProgramData();1204 window.localStorage.safelist_config = json_settings = JSON.stringify(safelist_config);1205}1206//Validates program data1207function validateProgramData() {1208 debuglog("Checking configuration");1209 if (typeof(safelist_config)!=='object') {1210 debuglog("Invalid configuration variable");1211 safelist_config = {};1212 }1213 validateData(safelist_config,'name','string',"Safelist");1214 validateData(safelist_config,'replacement_text','string',"");1215 validateData(safelist_config,'enable_tag_hide','boolean',false);1216 validateData(safelist_config,'enable_text_replace','boolean',false);1217 validateData(safelist_config,'enable_write_mode','boolean',false);1218 validateData(safelist_config,'enable_validate_mode','boolean',false);1219 validateData(safelist_config,'enable_order_mode','boolean',false);1220 validateData(safelist_config,'use_session_enable','boolean',false);1221 validateData(safelist_config,'use_session_level','boolean',false);1222 if (validateData(safelist_config,'levels','object',{})) {1223 let maxlevel = 0;1224 $.each(safelist_config.levels, (key,value)=>{1225 debuglog("Checking safelist "+key);1226 if (!(value instanceof Safelist)) {1227 debuglog('Invalid Safelist');1228 safelist_config.levels[key] = new Safelist(key);1229 } else {1230 if (key!==value.level) {1231 debuglog('Invalid key: level');1232 value.level=key;1233 }1234 value.validateSafelistData();1235 }1236 maxlevel = (value.isVariable?Math.max(parseInt(key),maxlevel):maxlevel);1237 });1238 safelist_config.next_index = maxlevel + 1;1239 } else {1240 ['a','n','1'].map((level,i)=>{ safelist_config.levels[level]=new Safelist(level);});1241 safelist_config.next_index = 2;1242 }1243 _(safelist_config).each((val,key)=>{1244 if ($.inArray(key,['name','replacement_text','enable_tag_hide','enable_text_replace',1245 'enable_write_mode','enable_validate_mode','enable_order_mode',1246 'use_session_enable','use_session_level',1247 'levels','next_index','enable_safelist','active_list'])<0) {1248 debuglog(`Deleting key: ${key}`);1249 delete safelist_config[key];1250 }1251 });1252}1253function initialSessionData(enabled = false) {1254 safelist_session = {};1255 safelist_session.enable_safelist = enabled;1256 safelist_session.active_list = undefined;1257}1258//Loads session data from storage1259function loadSessionData() {1260 safelist_session = window.sessionStorage.safelist_session;1261 if(safelist_session!==undefined) {1262 try {1263 safelist_session = JSON.parse(safelist_session);1264 } catch (e) {1265 initialSessionData();1266 }1267 } else {1268 initialSessionData();1269 }1270 if (!safelist_config.use_session_enable) {1271 safelist_session.enable_safelist = (safelist_config.enable_safelist!==undefined?safelist_config.enable_safelist:false);1272 }1273 if (!safelist_config.use_session_level) {1274 safelist_session.active_list = safelist_config.active_list;1275 }1276 setSessionData();1277}1278//Stores session data1279function setSessionData() {1280 window.sessionStorage.safelist_session = JSON.stringify(safelist_session);1281 if ((!safelist_config.use_session_enable)||(!safelist_config.use_session_level)) {1282 //Don't use the working safelist config since that could be modifed1283 //Changes to long-term storage should only take place if the user clicks "Save"1284 let tempparse = JSON.parse(window.localStorage.safelist_config);1285 if (!safelist_config.use_session_enable) {1286 tempparse.enable_safelist = safelist_session.enable_safelist;1287 }1288 if (!safelist_config.use_session_level) {1289 tempparse.active_list = safelist_session.active_list;1290 }1291 window.localStorage.safelist_config = JSON.stringify(tempparse);1292 }1293}1294//Removing lists only at page load helps with the detection of new list adds1295//Plus it removes errors for something that could still using a deleted level's data1296function pruneCustomLists() {1297 $.each(safelist_config.levels, (level,val)=>{1298 if(val.isPrunable) {1299 delete safelist_config.levels[level];1300 }1301 });1302}1303//Set the style for the active list in the side menu1304function setActiveList(level,type) {1305 if (level===undefined) {return;}1306 $("#safelist li").removeClass("safelist-active safelist-pending");1307 $(`#safe-level-${level}`).parent().addClass(`safelist-${type}`);1308}1309//Create the same structure that Danbooru uses for each custom list1310function createEntryArray(){1311 custom_entries = {};1312 $.each(safelist_config.levels, (level,val)=>{1313 if(val.isVariable) {1314 var array = [];1315 $.each(val.list, (i,tags)=>{1316 var entry = Danbooru.Blacklist.parse_entry(tags);1317 array.push(entry);1318 });1319 custom_entries[level]=array;1320 }1321 });1322}1323//Sets the css style and retains a pointer to the DOM object for later edits1324function setCSSStyle(csstext,title) {1325 if (title in cssstyle_dict) {1326 cssstyle_dict[title].innerHTML = csstext;1327 } else {1328 cssstyle_dict[title] = document.createElement('style');1329 cssstyle_dict[title].type = 'text/css';1330 cssstyle_dict[title].innerHTML = csstext;1331 document.head.appendChild(cssstyle_dict[title]);1332 }1333}1334//A faster way to show and hide posts using precalcuated lists1335function showHidePosts(postlist) {1336 console.time("showHidePosts");1337 $.each(_.difference(safelistPosts(),postlist), (i,post)=>{1338 safelistUnhide(post);1339 });1340 $.each(postlist, (i,post)=>{1341 safelistHide(post);1342 });1343 console.timeEnd("showHidePosts");1344}1345//Copy of Danbooru's functions since we're using a different class to hide items1346function safelistHide(post) {1347 var $post = $(post);1348 $post.removeClass("safelist-active");1349 var $video = $post.find("video").get(0);1350 if ($video) {1351 $video.pause();1352 $video.currentTime = 0;1353 }1354}1355function safelistUnhide(post) {1356 var $post = $(post);1357 $post.addClass("safelist-active");1358 var $video = $post.find("video").get(0);1359 if ($video) {1360 $video.play();1361 }1362}1363//Get the current state of the menus for other functions to use1364function calculateRenderedMenus() {1365 var menu = {'rendered_menus':[],'variable_menus':[],'process_menus':[]};1366 $.each(safelist_config.levels, (level,val)=>{1367 if (val.enabled) {1368 if (val.isVariable) {1369 menu.variable_menus.push(parseInt(val.level));1370 if (val.background_process) {1371 menu.process_menus.push(parseInt(val.level));1372 }1373 }1374 menu.rendered_menus.push(val.level);1375 }1376 });1377 //Sort from lowest to highest, and then set to string1378 menu.variable_menus = menu.variable_menus.sort((a,b)=>{return a-b;}).map((level,i)=>String(level));1379 menu.process_menus = menu.process_menus.sort((a,b)=>{return a-b;}).map((level,i)=>String(level));1380 return menu;1381}1382function checkPriority() {1383 return ((safelist_session.enable_safelist) && (safelist_session.active_list!==undefined) && (!(safelist_session.active_list in post_list_dict)));1384}1385function safelistPosts() {1386 return $(".post-preview, #image-container, #c-comments .post");1387}1388///////////////////////////1389//Calculate list functions1390//Asynchronous function that calculates inactive lists in the background1391function calculateLists(deadline) {1392 try {1393 //Only start calculating once the active enabled list is done1394 if (checkPriority()) {1395 if ('requestIdleCallback' in window) {1396 calculateLists.handle = requestIdleCallback(calculateLists);1397 } else {1398 calculateLists.handle = setTimeout(calculateLists,list_callback_retrytime);1399 }1400 return;1401 }1402 if (calculateLists.$safelist_posts === undefined) {calculateLists.$safelist_posts = safelistPosts();}1403 if (!('requestIdleCallback' in window)) {deadline = performance.now();}1404 while (true) {1405 //Are we starting a new job?1406 if (!('update_list' in calculateLists.background_work)) {1407 //Get the next uncalculated list1408 //let update_list = _(menu_items.variable_menus).concat(['a','n','danbooru']).xor(Object.keys(post_list_dict)).shift();1409 let update_list = _(menu_items.process_menus).difference(Object.keys(post_list_dict)).shift();1410 //Main exit condition1411 if (update_list === undefined) {1412 debuglog("Lists done!");1413 return;1414 }1415 if (calculateLists.lists_processed===0) {getActualTime("Passive list start:");}1416 calculateLists.lists_processed++;1417 //Initialize FOR loop and other variables1418 calculateLists.background_work.update_list = update_list;1419 calculateLists.background_work.start_id = 0;1420 calculateLists.background_work.update_array = [];1421 calculateLists.background_work.start_time = performance.now();1422 } else if (calculateLists.background_work.update_list in post_list_dict) {1423 //User has changed list from inactive to active midst calculating1424 calculateLists.background_work = {};1425 continue;1426 }1427 let index = calculateLists.background_work.update_list;1428 //Restart the FOR loop where we left off1429 for (let i=calculateLists.background_work.start_id;i < calculateLists.$safelist_posts.length;i++) {1430 for (let j=0;j<custom_entries[index].length;j++){1431 if (Danbooru.Blacklist.post_match(calculateLists.$safelist_posts[i], custom_entries[index][j])) {1432 calculateLists.background_work.update_array.push(calculateLists.$safelist_posts[i]);1433 //Bail early on any entry match1434 break;1435 }1436 }1437 calculateLists.background_work.start_id++;1438 if ('requestIdleCallback' in window) {1439 if (deadline.timeRemaining() <= 0.0) {1440 //Release function back to idle pool1441 calculateLists.handle = requestIdleCallback(calculateLists);1442 return;1443 }1444 }1445 //Release the process every once in a while to avoid locking up the processor1446 //Using a 50% on/off duty cycle at a constant interval1447 else if ((performance.now() - deadline)>list_callback_polling_interval) {1448 calculateLists.handle = setTimeout(calculateLists,list_callback_polling_interval);1449 return;1450 }1451 }1452 //Add finished list to global variable1453 post_list_dict[index] = calculateLists.background_work.update_array;1454 console.log(`Completed list ${index}: `,performance.now()-calculateLists.background_work.start_time);1455 calculateLists.background_work = {};1456 }1457 } catch (e) {1458 errorlog(e);1459 throw e;1460 }1461}1462calculateLists.background_work = {};1463calculateLists.lists_processed = 0;1464function restartLists() {1465 if ('requestIdleCallback' in window) {1466 cancelIdleCallback(calculateLists.handle);1467 setTimeout(()=>{1468 calculateLists.background_work = {};1469 calculateLists.handle = requestIdleCallback(calculateLists);1470 },500);1471 } else {1472 clearTimeout(calculateLists.handle);1473 setTimeout(()=>{1474 calculateLists.background_work = {};1475 calculateLists.handle = setTimeout(calculateLists,list_callback_retrytime);1476 },500);1477 }1478}1479//Like caclulateLists, but for the active list, plus it has higher priority1480function calculateActiveList() {1481 try {1482 if (calculateActiveList.$safelist_posts === undefined) {calculateActiveList.$safelist_posts = safelistPosts();}1483 if (('level' in calculateActiveList.background_work)&&(safelist_session.active_list != calculateActiveList.background_work.level)) {1484 debuglog("Changing list...");1485 calculateActiveList.background_work = {};1486 }1487 if ((safelist_session.active_list in post_list_dict)||(!safelist_session.enable_safelist)) {1488 debuglog("Bailing on work...");1489 calculateActiveList.background_work = {};1490 setActiveList(safelist_session.active_list,'active');1491 return;1492 }1493 if (!('level' in calculateActiveList.background_work)) {1494 getActualTime("Active list start:");1495 calculateActiveList.background_work.level = safelist_session.active_list;1496 calculateActiveList.background_work.start_id = 0;1497 calculateActiveList.background_work.update_array = [];1498 calculateActiveList.background_work.start_time = performance.now();1499 }1500 let level = calculateActiveList.background_work.level;1501 let iteration_time = performance.now();1502 for (let i=calculateActiveList.background_work.start_id;i < calculateActiveList.$safelist_posts.length;i++) {1503 for (let j=0;j<custom_entries[level].length;j++){1504 if (Danbooru.Blacklist.post_match(calculateActiveList.$safelist_posts[i], custom_entries[level][j])) {1505 calculateActiveList.background_work.update_array.push(calculateActiveList.$safelist_posts[i]);1506 //Bail early on any entry match1507 break;1508 }1509 }1510 calculateActiveList.background_work.start_id++;1511 //Pass control back every once in a while to avoid locking up the browser1512 if ((performance.now() - iteration_time) > 50.0) {1513 calculateActiveList.handle = setTimeout(calculateActiveList,1);1514 return ;1515 }1516 }1517 post_list_dict[level] = calculateActiveList.background_work.update_array;1518 console.log("Completed active list:",performance.now()-calculateActiveList.background_work.start_time);1519 setActiveList(safelist_session.active_list,'active');1520 showHidePosts(post_list_dict[level]);1521 calculateActiveList.background_work = {};1522 } catch (e) {1523 errorlog(e);1524 throw e;1525 }1526}1527calculateActiveList.background_work = {};1528function signalActiveList(restart=false) {1529 clearTimeout(calculateActiveList.handle);1530 if (checkPriority()) {1531 setTimeout(()=>{1532 calculateActiveList.background_work = {};1533 if (restart) {calculateActiveList.handle = setTimeout(calculateActiveList,1);}1534 },500);1535 }1536}1537////////////////////1538//Render functions1539function renderSidemenu() {1540 let safelistBox = `1541<section id="safelist-box">1542 <h1>${safelist_config.name}</h1>1543 <ul id="safelist">`;1544 safelistBox += safelist_config.levels.a.renderedSide();1545 $.each(menu_items.variable_menus, (i,level)=>{safelistBox += safelist_config.levels[level].renderedSide();});1546 safelistBox += safelist_config.levels.n.renderedSide();1547 return safelistBox + `1548 </ul>1549 <a href="#" id="enable-safelist">Enable</a>1550 <a href="#" id="disable-safelist">Disable</a>1551</section>`;1552}1553function renderSettingMenuLink() {1554 return `1555<li><a href="#" id="show-safelist-settings-link">${safelist_config.name}</a></li>`;1556}1557function renderSettingMenu() {1558 let menustring = `1559<fieldset id="safelist-settings">1560 <div class="input" id="safelist-settings-optional">1561 <h2>Options</h2>`;1562 menustring += renderOptionTextinput('name');1563 menustring += renderOptionTextinput('replacement_text');1564 menustring += renderOptionCheckbox('enable_tag_hide');1565 menustring += renderOptionCheckbox('enable_text_replace');1566 menustring += renderOptionCheckbox('use_session_enable');1567 menustring += renderOptionCheckbox('use_session_level');1568 menustring += renderOptionCheckbox('enable_validate_mode');1569 menustring += renderOptionCheckbox('enable_order_mode');1570 menustring += renderOptionCheckbox('enable_write_mode');1571 menustring += `1572 <div class="clearfix"></div>1573 </div>`;1574 menustring += safelist_config.levels.a.renderLevelSetting();1575 menustring += safelist_config.levels.n.renderLevelSetting();1576 $.each(menu_items.variable_menus, (i,level)=>{menustring += safelist_config.levels[level].renderLevelSetting();});1577 return menustring + `1578 <hr>1579 <div id="safelist-controls">1580 <input type="submit" name="safelist-commit" value="Submit" class="btn">1581 <input type="submit" name="safelist-add" value="Add" class="btn">1582 <input type="submit" name="safelist-resetall" value="Reset All" class="btn">1583 <input type="submit" name="safelist-showhideraw" value="Show Raw" class="btn">1584 </div>1585 <div id="safelist-rawsettings">1586 <textarea style="width:100%;height:10em">${json_settings}</textarea>1587 <span class="hint">Used to transfer settings between domains/computers. <b>Settings here take priority!</b>.</span>1588 </div>1589</fieldset>1590`;1591}1592function renderOptionTextinput(setting) {1593 const name = "safelist-" + _.kebabCase(setting);1594 const title = _.startCase(setting);1595 const value = sanitizeForHTML(safelist_config[setting]);1596 return `<div class="safelist-textinput">1597 <label for="${name}">${title}</label>1598 <input type="text" name="${name}" value="${value}" size="40" autocomplete="off">1599 </div>`;1600}1601function renderOptionCheckbox(setting) {1602 const name = _.camelCase(setting);1603 const id = "safelist-" + _.kebabCase(setting);1604 const label = _.startCase(setting);1605 const value = (safelist_config[setting] ? "checked" : "");1606 const hint = help_hints[setting];1607 return `1608 <div class="safelist-checkbox">1609 <label for="${id}" style="width:13em">${label}</label>1610 <input type="checkbox" ${value} name="${name}" id="${id}">1611 <span class="tooltip">${hint}</span>1612 </div>`;1613}1614////////////////////1615// Click functions1616//List clicks1617function setListClicks() {1618 $.each(safelist_config.levels, (key,value)=>{1619 value.setSideLevelClick();1620 value.setKeypress(key);1621 });1622 enableSafelistClick();1623 disableSafelistClick();1624}1625function enableSafelistClick() {1626 $("#enable-safelist").off().click(function(e) {1627 try {1628 console.time("Enable");1629 setCSSStyle(css_enabled,"blacklist_css");1630 $("#safelist").show();1631 $("#enable-safelist").hide();1632 $("#disable-safelist").show();1633 if ($.inArray(safelist_session.active_list,menu_items.rendered_menus)>=0){1634 $("#safe-level-"+safelist_session.active_list).click();1635 }1636 safelist_session.enable_safelist = true;1637 setSessionData();1638 console.timeEnd("Enable");1639 e.preventDefault();1640 } catch (e) {1641 errorlog(e);1642 throw e;1643 }1644 });1645}1646function disableSafelistClick() {1647 $("#disable-safelist").off().click(function(e) {1648 try {1649 console.time("Disable");1650 setCSSStyle('',"blacklist_css");1651 //The following should not run at program initialization1652 if (safelist_session.enable_safelist) {1653 setCSSStyle('',"safelist_user_css");1654 if (safelist_config.enable_tag_hide) {1655 showTags();1656 }1657 if (safelist_config.enable_text_replace) {1658 showText();1659 }1660 $("#show-posts-link").click();1661 }1662 $("#safelist").hide();1663 $("#enable-safelist").show();1664 $("#disable-safelist").hide();1665 safelist_session.enable_safelist = false;1666 setSessionData();1667 console.timeEnd("Disable");1668 e.preventDefault();1669 } catch (e) {1670 errorlog(e);1671 throw e;1672 }1673 });1674}1675//Menu settings clicks1676function setSettingsClicks() {1677 setSaveButtonClick();1678 setAddButtonClick();1679 setResetAllButtonClick();1680 setRawClick();1681 setChangeMenuClick();1682 $.each(safelist_config.levels, (level,val)=>{1683 val.setMenuLevelClicks();1684 });1685}1686function setChangeMenuClick() {1687 $("#post-sections a").off("click").click(function(e) {1688 try {1689 const post_sections = ["posts","excerpt","safelist-settings"];1690 let match=/show-(.*)-link/.exec(e.currentTarget.id);1691 if(match){1692 if ((match[1] === "excerpt")&&($(e.currentTarget).parent().hasClass("active"))) {1693 return;1694 }1695 let activesection = match[1];1696 $.each(_.difference(post_sections,activesection), function(i, section) {1697 $("#"+section).hide();1698 });1699 $("#"+activesection).show();1700 }1701 $("#post-sections li").removeClass("active");1702 $(e.currentTarget).parent().addClass("active");1703 e.preventDefault();1704 } catch (e) {1705 errorlog(e);1706 throw e;1707 }1708 });1709}1710function setAddButtonClick() {1711 $("[name=safelist-add]").off().click(function(e) {1712 try {1713 let index = safelist_config.next_index.toString();1714 let addlist = safelist_config.levels[index] = new Safelist(index);1715 $("#safelist-settings>hr").before(addlist.renderLevelSetting());1716 if (!safelist_config.enable_write_mode) {$(`[name="safelist-push-level-${index}"]`)[0].setAttribute("disabled","true");}1717 if (!safelist_config.enable_validate_mode) {$(`[name="safelist-validate-level-${index}"]`)[0].setAttribute("disabled","true");}1718 if (!safelist_config.enable_order_mode) {$(`[name="safelist-order-level-${index}"]`)[0].setAttribute("disabled","true");}1719 addlist.setMenuLevelClicks();1720 safelist_config.next_index++;1721 } catch (e) {1722 errorlog(e);1723 throw e;1724 }1725 });1726}1727function setResetAllButtonClick() {1728 $("[name=safelist-resetall]").off().click(function(e) {1729 try {1730 let keyinput = confirm("Reset all Safelist settings?");1731 if (keyinput) {1732 console.time("ResetAll");1733 initialProgramData();1734 setProgramData();1735 resetAllSettings();1736 console.timeEnd("ResetAll");1737 }1738 } catch (e) {1739 errorlog(e);1740 throw e;1741 }1742 });1743}1744function setRawClick() {1745 $("#safelist-rawsettings").hide();1746 $("[name=safelist-showhideraw]").off().click(function(e) {1747 try {1748 var button = $(this);1749 $("#safelist-rawsettings").fadeToggle("fast");1750 if (button.val() === "Show Raw") {1751 button.val("Hide Raw");1752 } else {1753 button.val("Show Raw");1754 }1755 } catch (e) {1756 errorlog(e);1757 throw e;1758 }1759 });1760}1761function setSaveButtonClick() {1762 $("[name=safelist-commit]").off().click(function(e) {1763 try {1764 //Save presettings change for comparison later1765 let checkjson_settings = $("#safelist-rawsettings > textarea").val();1766 if (json_settings != checkjson_settings) {1767 debuglog("Raw change detected!");1768 try {1769 safelist_config = JSON.parse(checkjson_settings);1770 } catch (err) {1771 Danbooru.notice("Raw settings corrupted... reverting to original data!");1772 $("#safelist-rawsettings > textarea").val(json_settings);1773 return;1774 }1775 $.each(safelist_config.levels, (level,val)=>{1776 safelist_config.levels[level] = Object.assign(new Safelist(''),val);1777 });1778 setProgramData();1779 resetAllSettings();1780 return;1781 }1782 validateProgramData();1783 var preconfig = _.cloneDeep(safelist_config);1784 var premenu = calculateRenderedMenus();1785 safelist_config.levels.a.enabled = $("#safelist-enable-level-a")[0].checked;1786 safelist_config.levels.n.enabled = $("#safelist-enable-level-n")[0].checked;1787 safelist_config.enable_tag_hide = $("#safelist-enable-tag-hide")[0].checked;1788 safelist_config.enable_text_replace = $("#safelist-enable-text-replace")[0].checked;1789 safelist_config.enable_write_mode = $("#safelist-enable-write-mode")[0].checked;1790 safelist_config.enable_validate_mode = $("#safelist-enable-validate-mode")[0].checked;1791 safelist_config.enable_order_mode = $("#safelist-enable-validate-mode")[0].checked;1792 safelist_config.use_session_enable = $("#safelist-use-session-enable")[0].checked;1793 safelist_config.use_session_level = $("#safelist-use-session-level")[0].checked;1794 safelist_config.replacement_text = $("[name=safelist-replacement-text]").val().replace(/<.+?>/g,'');1795 safelist_config.name = $("[name=safelist-name]").val();1796 $.each(safelist_config.levels, (level,val)=>{1797 if($.inArray(level,premenu.variable_menus)>=0) {1798 val.tagstring = $("#safelist_tags_level_"+level).val();1799 val.background_process = $("#safelist_background_process_level_"+level)[0].checked;1800 }1801 val.css = $("#safelist_css_level_"+level).val();1802 val.name = $(`[name=safelist-name-level-${level}]`).val();1803 val.hotkey[0] = $("#safelist_modifier_level_"+level).val();1804 val.hotkey[1] = $("#safelist_keyselect_level_"+level).val();1805 });1806 $(".safelist-namerow .text").hide();1807 $(".safelist-namerow h2").show();1808 $(".safelist-namerow .btn").show();1809 setProgramData();1810 Danbooru.notice("Settings saved.");1811 let postmenu = calculateRenderedMenus();1812 let changed_menus = _.xor(postmenu.rendered_menus,menu_items.rendered_menus);1813 menu_items = postmenu;1814 recurseCompareSettings(preconfig,safelist_config);1815 debuglog(preconfig,changed_menus);1816 reloadSafelist(preconfig,changed_menus);1817 } catch (e) {1818 errorlog(e);1819 throw e;1820 }1821 });1822}1823//////////////////////////1824//Tag & Text functions1825function hideTags(domname,parentlevel,list) {1826 $.each($(domname), (i,domtag)=>{1827 let normalizedtag = domtag.innerText.replace(' ','_');1828 $.each(list, (i,censor_tag)=>{1829 if(normalizedtag==censor_tag){1830 let node = $(domtag);1831 for (let j=0;j<parentlevel;j++){1832 node = node.parent();1833 }1834 node.hide();1835 //bail early1836 return;1837 }1838 });1839 });1840}1841function showTags() {1842 console.time("ShowTags");1843 if ($("#c-posts").length) {1844 $(".search-tag").parent().show();1845 }1846 if ($("#c-favorites").length) {1847 $(".search-tag").parent().show();1848 }1849 if ($("#c-wiki-pages").length) {1850 $("#c-wiki-pages li a").show();1851 $("#c-wiki-pages .striped tr").show();1852 }1853 if ($("#c-wiki-page-versions").length) {1854 $("#c-wiki-page-versions li a").show();1855 $("#c-wiki-page-versions .striped tr").show();1856 }1857 if ($("#c-artists").length) {1858 $("#c-artists .striped tr").show();1859 }1860 if ($("#c-artist-versions").length) {1861 $("#c-artist-versions tr").show();1862 }1863 if ($("#c-tags").length) {1864 $("#c-tags .striped tr").show();1865 }1866 if ($("#c-meta-searches").length) {1867 $("#c-meta-searches .striped tr").show();1868 }1869 if ($("#c-explore-posts #a-searches").length) {1870 $("#c-explore-posts #a-searches .striped tr").show();1871 }1872 if ($("#c-explore-posts #a-missed-searches").length) {1873 $("#c-explore-posts #a-missed-searches .striped tr").show();1874 }1875 console.timeEnd("ShowTags");1876}1877//This function will clobber any existing events (only expandable buttons so far)1878//However, a recursive function that avoided the above was orders of magnitude slower1879function hideText(domname, list) {1880 debuglog(domname);1881 if(hideText[domname]===undefined) {1882 hideText[domname] = {};1883 hideText[domname].domlink = $(domname);1884 hideText[domname].domtext = _.map(hideText[domname].domlink,"innerHTML");1885 }1886 $.each(hideText[domname].domlink, (i,dom)=>{1887 let replace_text = hideText[domname].domtext[i];1888 $.each(list, (i,censor_tag)=>{1889 replace_text = replace_text.replace(tagRegExp(censor_tag),safelist_config.replacement_text);1890 });1891 if (dom.innerHTML != replace_text) {1892 dom.innerHTML = replace_text;1893 }1894 });1895}1896function delayHideText(sourcedom,destdom,list) {1897 try {1898 debuglog(sourcedom,$(sourcedom).length,destdom,$(destdom).length);1899 if ($(sourcedom).length != $(destdom).length) {1900 setTimeout(delayHideText,50,sourcedom,destdom,list);1901 return;1902 }1903 hideText(destdom,list);1904 } catch (e) {1905 errorlog(e);1906 throw e;1907 }1908}1909function showText() {1910 console.time("ShowText");1911 $.each(Object.keys(hideText), (i,key)=>{1912 $.each(hideText[key].domlink, (i,dom)=>{dom.innerHTML=hideText[key].domtext[i];});1913 });1914 fixExpandables();1915 console.timeEnd("ShowText");1916}1917///////////////////////////////////1918//Functions for expandable Dtext1919//Will fix any DText expandable broken by hideText1920function fixExpandables() {1921 if (!isExpandables()) {1922 return;1923 }1924 let $expandable_buttons = $(".expandable-button");1925 if ($expandable_buttons.length) {1926 $expandable_buttons.off();1927 Danbooru.Dtext.initialize_expandables();1928 }1929}1930//Check if Danbooru is done by checking the display status1931function validateExpandableStatus() {1932 try {1933 if (!isExpandables()) {1934 debuglog("There are no Dtext expandables!");1935 validateExpandableStatus.isdone = true;1936 return;1937 }1938 validateExpandableStatus.isdone = _.reduce($(".expandable-content"),(result,value)=>{return result && (value.style.display === "none"); },true);1939 if (validateExpandableStatus.isdone) {1940 debuglog("DText expandables are done!");1941 } else {1942 if (validateExpandableStatus.checked === 0) {1943 debuglog("Dtext expandables are not done!");1944 }1945 setTimeout(validateExpandableStatus,500);1946 validateExpandableStatus.checked++;1947 }1948 } catch (e) {1949 errorlog(e);1950 throw e;1951 }1952}1953validateExpandableStatus.isdone = false;1954validateExpandableStatus.checked = 0;1955//Logic function to reduce calls to DOM1956function isExpandables() {1957 if (isExpandables.firsttime) {1958 isExpandables.value = (($(".prose:not(.dtext-preview)").length!==0)&&($(".expandable-content").length!==0));1959 isExpandables.firsttime = false;1960 }1961 return isExpandables.value;1962}1963isExpandables.firsttime = true;1964//////////////////////1965//Utility functions1966//Compare two objects to detect changes to the first1967function recurseCompareSettings(object1,object2) {1968 $.each(object1, function(key,val) {1969 if (_.isEqual(object1[key],object2[key])) {1970 delete object1[key];1971 } else if (typeof object1[key]==="object") {1972 recurseCompareSettings(object1[key],object2[key]);1973 }1974 });1975}1976function validateData(object,key,type,defaultval) {1977 if (typeof(object[key])!==type) {1978 debuglog(`Invalid Key: ${key}`);1979 object[key] = defaultval;1980 return false;1981 }1982 return true;1983}1984function tagRegExp(str) {1985 return RegExp('\\b'+str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1").replace(/_/g,'[_ ]')+'\\b','gi');1986}1987function sanitizeForHTML(str) {1988 return str.replace(/&/g,'&amp;').replace(/>/g,'&gt;').replace(/</g,'&lt;').replace(/\n/g,'<br>').replace(/"/g,'&quot;');1989}1990function getActualTime(str) {1991 debuglog(str,performance.now()-getActualTime.starttime);1992}1993getActualTime.starttime = performance.now();1994function sleep(ms) {1995 return new Promise(resolve => setTimeout(resolve, ms));1996}1997function debuglog(args) {1998 if (debug_console) {1999 console.log.apply(this,arguments);2000 }2001}2002function errorlog(error) {2003 console.trace(error);2004 let errortext = sanitizeForHTML(error.stack);2005 $("footer").append(`<div class="safelist-error">Safelist error: ${errortext}</div>`);2006 alert("Safelist error ocurred... check page bottom for details!");2007}2008//////////////////////2009//Main entry points2010async function libraryWait() {2011 try {2012 console.log("Checking Danbooru");2013 while (typeof(window.Danbooru)==="undefined") {2014 if (libraryWait.checked > max_danbooru_retries) {return;}2015 console.log("Waiting on Danbooru...");2016 let temp = await sleep(50);2017 libraryWait.checked++;2018 }2019 console.log("Checking Danbooru.Blacklist");2020 while (typeof(window.Danbooru.Blacklist)==="undefined") {2021 if (libraryWait.checked > max_danbooru_retries) {return;}2022 console.log("Waiting on Danbooru Blacklist...");2023 let temp = await sleep(50);2024 libraryWait.checked++;2025 }2026 initializeSafelist();2027 } catch (e) {2028 errorlog(e);2029 throw e;2030 }2031}2032libraryWait.checked = 0;2033libraryWait();...

Full Screen

Full Screen

index.ts

Source:index.ts Github

copy

Full Screen

1import type { IconifyJSON } from '@iconify/types'2// import { useConfig, useDebugger } from '@nbhr/utils'3import type { UnoGenerator } from '@unocss/core'4import { createGenerator } from '@unocss/core'5import UnocssIcons from '@unocss/preset-icons'6import fg from 'fast-glob'7import { readFileSync } from 'fs'8import { parse, preprocess } from 'svelte/compiler'9import type {10 PreprocessorGroup,11 Processed,12} from 'svelte/types/compiler/preprocess'13import { Processor } from 'windicss/lib'14// import type { FullConfig } from 'windicss/types/interfaces'15import { CSSParser } from 'windicss/utils/parser'16import { StyleSheet } from 'windicss/utils/style'17import { globalStyleSheet, Magician, SetObject } from './utils'18import { loadConfig } from 'unconfig'19import { FullConfig } from 'windicss/types/interfaces'20// const DEV = false21// let windiConfig: FullConfig22// let configMTime: number23// let OPTIONS: BaseConfig24let entryFileName = ''25interface generatorObject {26 data: SetObject27 updatedAt: number28 writtenAt?: number29}30const raw = new Map<string, generatorObject>([31 [32 '__GLOBAL',33 {34 data: {35 inlineClasses: new Set(),36 inlineDirectives: new Set(),37 inlineExpressions: new Set(),38 inlineIcons: new Set(),39 inlineAttributify: new Map(),40 },41 updatedAt: Date.now(),42 },43 ],44])45async function generateCSS(46 key: string,47 attributes: Record<string, string | boolean>48) {49 const t = raw.get(key)50 // MARK: WINDI DEFAULT51 // const FILESHEET = CSS_STYLESHEETS.get(filename || '') || undefined52 // if (FILESHEET && attributes['windi:global']) {53 // INLINE_STYLE = globalStyleSheet(FILESHEET['code']).build()54 // } else if (FILESHEET) {55 // INLINE_STYLE = FILESHEET['code'].build()56 // }57 const defaultStyleSheet = generatorWindi.interpret(58 Array.from(59 new Set([60 ...(t?.data.inlineClasses || new Set()),61 ...(t?.data.inlineDirectives || new Set()),62 ...(t?.data.inlineExpressions || new Set()),63 ])64 ).join(' ')65 ).styleSheet66 let defaultStyles = ''67 if (attributes['windi:global'] || attributes['windi-inline-global']) {68 defaultStyles = globalStyleSheet(defaultStyleSheet).build()69 } else {70 defaultStyles = defaultStyleSheet.build()71 }72 // MARK: ATTRIBUTIFY73 const nObj: Record<string, string[]> = {}74 t?.data.inlineAttributify.forEach((v: Set<string>, k: string) => {75 nObj[k] = Array.from(v)76 })77 const attributifyStyleSheet = generatorWindi.attributify(nObj).styleSheet78 let attributifyStyles = ''79 if (attributes['windi:global'] || attributes['windi-inline-global']) {80 attributifyStyles = globalStyleSheet(attributifyStyleSheet).build()81 } else {82 attributifyStyles = attributifyStyleSheet.build()83 }84 // MARK: ICONS (experimental)85 let iconStyles = ''86 if (generatorUno && configuration.experimental?.icons != undefined) {87 iconStyles = await generatorUno88 .generate(t?.data.inlineIcons || '')89 .then(resolve => resolve.css)90 }91 return { defaultStyles, attributifyStyles, iconStyles }92}93function agent(): PreprocessorGroup {94 let result: SetObject95 return {96 async markup({ content, filename }): Promise<Processed> {97 if (!filename) return { code: content }98 // console.log(filename, 'markup agent')99 let worker = new Magician(content, filename, configuration)100 worker = worker.prepare()101 worker = worker.setInject()102 worker = worker.extract()103 result = worker.getSets()104 raw.set(filename, {105 data: result,106 updatedAt: Date.now(),107 })108 return {109 code: worker.getContent(),110 }111 },112 }113}114function main(): PreprocessorGroup {115 if (configuration.experimental?.scan !== undefined) {116 const files = fg.sync(['src/**/*.svelte'], {})117 for (const file of files) {118 const content = readFileSync(file).toString()119 const filename = file120 const ast = parse(content, { filename })121 const hasGlobalInline = ast.css.attributes.some(122 el => el.name == 'windi-inline-global'123 )124 console.log(filename, hasGlobalInline)125 let worker = new Magician(content, filename, configuration)126 worker = worker.prepare()127 worker = worker.extract()128 const result = worker.getSets()129 if (hasGlobalInline) {130 const global = raw.get('__GLOBAL')!.data131 raw.set('__GLOBAL', {132 data: {133 inlineClasses: new Set([134 ...global.inlineClasses,135 ...result.inlineClasses,136 ]),137 inlineDirectives: new Set([138 ...global.inlineDirectives,139 ...result.inlineDirectives,140 ]),141 inlineExpressions: new Set([142 ...global.inlineExpressions,143 ...result.inlineExpressions,144 ]),145 inlineIcons: new Set([146 ...global.inlineIcons,147 ...result.inlineIcons,148 ]),149 inlineAttributify: new Map([150 ...global.inlineAttributify,151 ...result.inlineAttributify,152 ]),153 },154 updatedAt: Date.now(),155 })156 raw.set(filename, {157 data: {158 inlineClasses: new Set(),159 inlineDirectives: new Set(),160 inlineExpressions: new Set(),161 inlineIcons: new Set(),162 inlineAttributify: new Map(),163 },164 updatedAt: Date.now(),165 })166 } else {167 raw.set(filename, {168 data: result,169 updatedAt: Date.now(),170 })171 }172 }173 }174 return {175 async style({ content, attributes, filename }): Promise<Processed> {176 if (!filename) return { code: content }177 // console.log(filename, 'style main')178 // // MARK: PREFLIGHTS179 // if (OPTIONS.preflights === true && attributes['windi:preflights:global']) {180 // const PREFLIGHTS = PROCESSOR.preflight()181 // PREFLIGHTS_STYLE = globalStyleSheet(PREFLIGHTS).build()182 // } else if (OPTIONS.preflights === true && attributes['windi:preflights']) {183 // const PREFLIGHTS = PROCESSOR.preflight()184 // PREFLIGHTS_STYLE = PREFLIGHTS.build()185 // }186 let preflightStyleSheet = new StyleSheet()187 if (188 attributes['windi:preflights:global'] ||189 attributes['windi-preflights-global']190 ) {191 preflightStyleSheet = globalStyleSheet(generatorWindi.preflight())192 }193 const preflightStyles = preflightStyleSheet.build()194 // // MARK: SAFELIST195 // if (OPTIONS.safeList && attributes['windi:safelist:global']) {196 // const SAFELIST = PROCESSOR.interpret(OPTIONS.safeList).styleSheet197 // SAFELIST_STYLE = globalStyleSheet(SAFELIST).build()198 // if (OPTIONS.experimental && OPTIONS.experimental.icons != undefined) {199 // let UNO_SAFELIST_STYLE = ''200 // const { css } = await UNO.generate(OPTIONS.safeList)201 // const UNO_SAFELIST_STYLESHEET = new CSSParser(css).parse()202 // UNO_SAFELIST_STYLE = globalStyleSheet(UNO_SAFELIST_STYLESHEET).build()203 // SAFELIST_STYLE += UNO_SAFELIST_STYLE204 // }205 // } else if (OPTIONS.safeList && attributes['windi:safelist']) {206 // const SAFELIST = PROCESSOR.interpret(OPTIONS.safeList).styleSheet207 // SAFELIST_STYLE = SAFELIST.build()208 // if (OPTIONS.experimental && OPTIONS.experimental.icons != undefined) {209 // let UNO_SAFELIST_STYLE = ''210 // const { css } = await UNO.generate(OPTIONS.safeList)211 // UNO_SAFELIST_STYLE = css212 // SAFELIST_STYLE += UNO_SAFELIST_STYLE213 // }214 // }215 let safelistStyleSheet = new StyleSheet()216 let safelistIconsStyleSheet = new StyleSheet()217 if (218 attributes['windi:safelist:global'] ||219 attributes['windi-safelist-global']220 ) {221 safelistStyleSheet = globalStyleSheet(222 generatorWindi.interpret(configuration.safeList || '').styleSheet223 )224 if (generatorUno && configuration.experimental?.icons != undefined) {225 const { css } = await generatorUno.generate(226 configuration.safeList || ''227 )228 safelistIconsStyleSheet = globalStyleSheet(new CSSParser(css).parse())229 }230 }231 let safelistStyles = safelistStyleSheet.build()232 safelistStyles += safelistIconsStyleSheet.build()233 let defaultStyles, attributifyStyles, iconStyles234 if (entryFileName.length > 0) {235 const result = await generateCSS(filename, attributes)236 defaultStyles = result.defaultStyles237 attributifyStyles = result.attributifyStyles238 iconStyles = result.iconStyles239 } else {240 entryFileName = filename241 const resultGlobal = await generateCSS('__GLOBAL', {242 'windi-inline-global': true,243 })244 defaultStyles = resultGlobal.defaultStyles245 attributifyStyles = resultGlobal.attributifyStyles246 iconStyles = resultGlobal.iconStyles247 const result = await generateCSS(filename, attributes)248 defaultStyles += result.defaultStyles249 attributifyStyles += result.attributifyStyles250 iconStyles += result.iconStyles251 }252 // MARK: CUSTOM CSS + WINDI @apply253 // let CSS: StyleSheet254 // CSS_SOURCE = content255 // if (CSS_SOURCE && attributes['global']) {256 // CSS = new CSSParser(CSS_SOURCE, PROCESSOR).parse()257 // CSS_STYLE = globalStyleSheet(CSS).build()258 // } else if (CSS_SOURCE) {259 // const tmpCSS = CSS_SOURCE260 // const rules = [...(tmpCSS.matchAll(/(?<selector>[^}]*){(?<css>[^}]*)}/gim) || [])]261 // rules.forEach(rule => {262 // if (rule.groups && rule.groups.selector.includes(':global')) {263 // const globalCSS = new CSSParser(rule[0], PROCESSOR).parse()264 // const buildGlobalCSS = globalStyleSheet(globalCSS).build()265 // if (buildGlobalCSS.length > 0) CSS_STYLE += buildGlobalCSS + '\n'266 // } else {267 // CSS = new CSSParser(rule[0], PROCESSOR).parse()268 // const buildLocalCSS = CSS.build()269 // if (buildLocalCSS.length > 0) CSS_STYLE += buildLocalCSS + '\n'270 // }271 // })272 // }273 const cssStyleSheet =274 new CSSParser(content, generatorWindi).parse() || new StyleSheet()275 let cssStyles = ''276 if (attributes['global']) {277 cssStyles = globalStyleSheet(cssStyleSheet).build()278 } else {279 cssStyles = cssStyleSheet.build()280 }281 // // MARK: COMBINE282 // let newStyleCode = '\n'283 // if (PREFLIGHTS_STYLE.length > 0) newStyleCode += PREFLIGHTS_STYLE + '\n'284 // if (SAFELIST_STYLE.length > 0) newStyleCode += SAFELIST_STYLE + '\n'285 // if (CSS_STYLE.length > 0) newStyleCode += CSS_STYLE + '\n'286 // if (INLINE_STYLE.length > 0) newStyleCode += INLINE_STYLE + '\n'287 // if (UNO_STYLE.length > 0) newStyleCode += UNO_STYLE + '\n'288 let newCode = ''289 if (preflightStyles.length > 0) newCode += '\n' + preflightStyles290 if (safelistStyles.length > 0) newCode += '\n' + safelistStyles291 if (defaultStyles.length > 0) newCode += '\n' + defaultStyles292 if (attributifyStyles.length > 0) newCode += '\n' + attributifyStyles293 if (iconStyles.length > 0) newCode += '\n' + iconStyles294 if (cssStyles.length > 0) newCode += '\n' + cssStyles295 newCode += '\n'296 return {297 code: newCode,298 }299 },300 }301}302export interface BaseConfig {303 silent?: boolean304 mode?: 'development' | 'production'305 configPath?: string306 disableFormat?: boolean307 devTools?: {308 enabled: boolean309 completions?: boolean310 }311 //312 safeList?: string313 preflights?: boolean314 // bundle?: string;315 // debug?: boolean;316 // compile?: boolean;317 // prefix?: string;318 // verbosity?: number;319 experimental?: {320 icons?: {321 prefix?: string322 collections?: Record<string, IconifyJSON>323 extraProperties?: Record<string, string>324 }325 scan?: boolean326 }327}328export type DefaultConfig = BaseConfig329export type UserConfig = BaseConfig330const defaultConfig: DefaultConfig = {331 silent: false,332 // mode333 // configPath334 disableFormat: false,335 devTools: {336 enabled: false,337 },338 safeList: undefined,339 preflights: true,340 // bundle: undefined,341 // compile: false,342 // prefix: 'windi-',343 // verbosity: 1,344 // debug: false,345}346let configuration: BaseConfig347let generatorWindi: Processor348let generatorUno: UnoGenerator349let windiConfiguration: FullConfig350// if (windiConfig != undefined) {351// if (OPTIONS.configPath) {352// // get modified time of config file353// const mTime = statSync(OPTIONS.configPath).mtimeMs354// if (mTime > configMTime) {355// const tmpConfigPath = `./${Date.now()}windi.config.js`356// copyFileSync(OPTIONS.configPath, tmpConfigPath)357// loadConfig(tmpConfigPath)358// .catch(e => {359// useDebugger.createLog('Unknown Error while loading the config')360// console.error(e)361// })362// .finally(() => {363// rmSync(tmpConfigPath)364// resolve({365// code: _preprocess(content, filename),366// })367// })368// } else {369// resolve({370// code: _preprocess(content, filename),371// })372// }373// }374// } else {375// if (OPTIONS.configPath) {376// loadConfig(OPTIONS.configPath)377// .catch(e => {378// useDebugger.createLog('Unknown Error while loading the config')379// console.error(e)380// })381// .finally(() => {382// resolve({383// code: _preprocess(content, filename),384// })385// })386// } else {387// PROCESSOR.loadConfig()388// resolve({389// code: _preprocess(content, filename),390// })391// }392// }393// function loadConfig(path: string): Promise<void> {394// useDebugger.createLog('Trying to load windi configuration from ' + path)395// return useConfig.load<FullConfig>(path).then(config => {396// // write current unix timestamp to configMTime397// configMTime = Date.now()398// if (config.preflight === false) OPTIONS.preflights = false399// if (config.safelist && typeof config.safelist == 'string') {400// OPTIONS.safeList = config.safelist401// } else if (config.safelist) {402// const tmpSafelist = config.safelist as (string | string[])[]403// OPTIONS.safeList = [...new Set(tmpSafelist.flat(Infinity))].join(' ')404// }405// console.log(config)406// console.log(JSON.stringify(config.theme))407// PROCESSOR.loadConfig(config)408// useDebugger.createLog('Configuration loaded successfully')409// windiConfig = config410// })411// }412export function windi(userConfig: UserConfig = {}): PreprocessorGroup {413 configuration = { ...defaultConfig, ...userConfig }414 generatorWindi = new Processor()415 const steps: PreprocessorGroup[] = []416 if (configuration.experimental?.icons != undefined) {417 generatorUno = createGenerator(418 {419 presets: [420 UnocssIcons({421 ...configuration.experimental.icons,422 }),423 ],424 },425 {}426 )427 }428 if (configuration.experimental?.scan == undefined) {429 steps.push(agent())430 }431 steps.push(main())432 return {433 async markup({ content, filename }): Promise<Processed> {434 if (!windiConfiguration) {435 const { config } = await loadConfig<FullConfig>({436 merge: false,437 sources: [438 {439 files: 'windi.config',440 // default extensions441 extensions: ['ts', 'mts', 'cts', 'js', 'mjs', 'cjs', 'json', ''],442 },443 ],444 })445 windiConfiguration = config446 if (typeof config?.safelist == 'string') {447 configuration.safeList = config.safelist448 } else if (config?.safelist) {449 configuration.safeList = [450 ...new Set(config.safelist.flat(Infinity)),451 ].join(' ')452 }453 generatorWindi.loadConfig(config)454 }455 let currentContent = content456 for (const step of steps) {457 const code = (await preprocess(currentContent, step, { filename })).code458 currentContent = code459 }460 return {461 code: currentContent,462 }463 },464 }465}...

Full Screen

Full Screen

head.js

Source:head.js Github

copy

Full Screen

1let vm = new Vue({2 el:'#indexTop',3 data:{4 topImgUrl:'images/topImg.png',5 }6})7let tradeDataList = {8 '煤矿':'safeList.html',9 '化工':'safeList.html',10 '建筑':'safeList.html',11 '机械':'safeList.html',12 '电力':'safeList.html',13 '冶金':'safeList.html',14 '消防':'safeList.html',15 '特种':'safeList.html',16 '视频':'list_videos.html',17}18let knowledgeDataList={19 '安全新闻':'list_01_safeNews.html',20 '安全法规':'safeList.html',21 '安全管理':'safeList.html',22 '安全技术':'safeList.html',23 '事故案例':'safeList.html',24 '操作规程':'safeList.html',25 '安全标准':'safeList.html',26 '安全教育':'safeList.html',27 '安全文化':'safeList.html',28 '应急预案':'safeList.html',29 '安全评价':'safeList.html',30 '工伤保险':'safeList.html',31 '职业卫生':'safeList.html',32 '环保|健康':'safeList.html',33 '管理体系':'safeList.html',34 '文档|论文':'safeList.html',35 '工 程 师':'safeList.html',36 '安全文艺':'safeList.html',37 '培训课件':'safeList.html',38 '管理资料':'safeList.html',39 '安全常识':'safeList.html',40}41let navMenuList = new Vue({42 el:'#navMenuList',43 data:{44 knowledge:'知识',45 knowledgeDataList:knowledgeDataList,46 trade:'行业',47 tradeDataList:tradeDataList,48 }...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1var wptools = require('wptools');2wptools.page('Barack Obama').get(function(err, resp) {3 console.log(resp);4});5var wptools = require('wptools');6wptools.page('Barack Obama').get(function(err, resp) {7 console.log(resp);8});9var wptools = require('wptools');10wptools.page('Barack Obama').get(function(err, resp) {11 console.log(resp);12});13var wptools = require('wptools');14wptools.page('Barack Obama').get(function(err, resp) {15 console.log(resp);16});17var wptools = require('wptools');18wptools.page('Barack Obama').get(function(err, resp) {19 console.log(resp);20});21var wptools = require('wptools');22wptools.page('Barack Obama').get(function(err, resp) {23 console.log(resp);24});25var wptools = require('wptools');26wptools.page('Barack Obama').get(function(err, resp) {27 console.log(resp);28});29var wptools = require('wptools');30wptools.page('Barack Obama').get(function(err, resp) {31 console.log(resp);32});33var wptools = require('wptools');34wptools.page('Barack Obama').get(function(err, resp) {35 console.log(resp);36});37var wptools = require('wptools');38wptools.page('Barack Obama').get(function(err, resp) {39 console.log(resp);40});

Full Screen

Using AI Code Generation

copy

Full Screen

1const wptools = require('wptools');2const fs = require('fs');3const { exec } = require("child_process");4const { promisify } = require('util');5const execPromise = promisify(exec);6const readline = require('readline').createInterface({7});8let safelist = JSON.parse(fs.readFileSync('safelist.json', 'utf8'));9let safelistLength = safelist.length;10let safelistIndex = 0;11let blacklist = JSON.parse(fs.readFileSync('blacklist.json', 'utf8'));12let blacklistLength = blacklist.length;13let blacklistIndex = 0;14let done = JSON.parse(fs.readFileSync('done.json', 'utf8'));15let doneLength = done.length;16let doneIndex = 0;17let done2 = JSON.parse(fs.readFileSync('done2.json', 'utf8'));18let done2Length = done2.length;19let done2Index = 0;20let done3 = JSON.parse(fs.readFileSync('done3.json', 'utf8'));21let done3Length = done3.length;22let done3Index = 0;23let done4 = JSON.parse(fs.readFileSync('done4.json', 'utf8'));24let done4Length = done4.length;25let done4Index = 0;26let done5 = JSON.parse(fs.readFileSync('done5.json', 'utf8'));27let done5Length = done5.length;28let done5Index = 0;29let done6 = JSON.parse(fs.readFileSync('done6.json', 'utf8'));30let done6Length = done6.length;31let done6Index = 0;32let done7 = JSON.parse(fs.readFileSync('done7.json', 'utf8'));33let done7Length = done7.length;34let done7Index = 0;35let done8 = JSON.parse(fs.readFileSync('done8.json', 'utf8'));36let done8Length = done8.length;37let done8Index = 0;38let done9 = JSON.parse(fs.readFileSync('done9.json', 'utf8'));39let done9Length = done9.length;

Full Screen

Using AI Code Generation

copy

Full Screen

1var WptApi = require('wpt-api');2var wpt = new WptApi('your api key');3wpt.safelist(function(err, data) {4 if (err) {5 console.log(err);6 }7 else {8 console.log(data);9 }10});

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run wpt automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful