Refactor and fix type errors in WI and script modules (#4123) * remove unnecessary arg passage from WI helper funcs * remove some typescript red from script.js * hide in shame * Add JSDoc to helper functions * Fix fav_ch_checked not updating * Move PWA mode match to firstLoadInit * Fix more type errors and deprecations * Fix the rest of type errors in script.js --------- Co-authored-by: RossAscends <124905043+RossAscends@users.noreply.github.com>

b3c636fe91159a8be475512f35dff347a3f87ab0

Cohee <18619528+Cohee1207@users.noreply.github.com>

Signed
3 files changed, +188 -130Ignore whitespace
public/global.d.ts+5 -0
@@ -30,6 +30,11 @@ declare global {
3030 izoomify(options?: any): JQuery;
3131 }
3232
33+ // NPM package doesn't have the 'queue' property in the type definition
34+ interface JQueryTransitOptions {
35+ queue?: boolean;
36+ }
37+
3338 namespace Select2 {
3439 interface Options<Result = DataFormat | GroupedDataFormat, RemoteResult = any> {
3540 /**
public/script.js+94 -89
@@ -770,21 +770,6 @@ async function getSystemMessages() {
770770 };
771771}
772772
773-// Register configuration migrations
774-registerPromptManagerMigration();
775-
776-$(document).ajaxError(function myErrorHandler(_, xhr) {
777- // Cohee: CSRF doesn't error out in multiple tabs anymore, so this is unnecessary
778- /*
779- if (xhr.status == 403) {
780- toastr.warning(
781- 'doubleCsrf errors in console are NORMAL in this case. If you want to run ST in multiple tabs, start the server with --disableCsrf option.',
782- 'Looks like you\'ve opened SillyTavern in another browser tab',
783- { timeOut: 0, extendedTimeOut: 0, preventDuplicates: true },
784- );
785- } */
786-});
787-
788773async function getClientVersion() {
789774 try {
790775 const response = await fetch('/version');
@@ -865,7 +850,8 @@ export let create_save = {
865850 creator: '',
866851 personality: '',
867852 first_message: '',
868- avatar: '',
853+ /** @type {FileList|null} */
854+ avatar: null,
869855 scenario: '',
870856 mes_example: '',
871857 world: '',
@@ -982,6 +968,8 @@ async function firstLoadInit() {
982968 }
983969
984970 showLoader();
971+ registerPromptManagerMigration();
972+ initStandaloneMode();
985973 initLibraryShims();
986974 addShowdownPatch(showdown);
987975 reloadMarkdownProcessor();
@@ -1040,6 +1028,13 @@ async function fixViewport() {
10401028 document.body.style.position = '';
10411029}
10421030
1031+function initStandaloneMode() {
1032+ const isPwaMode = window.matchMedia('(display-mode: standalone)').matches;
1033+ if (isPwaMode) {
1034+ $('body').addClass('PWA');
1035+ }
1036+}
1037+
10431038function cancelStatusCheck(reason = 'Manually cancelled status check') {
10441039 abortStatusCheck?.abort(new AbortReason(reason));
10451040 abortStatusCheck = new AbortController();
@@ -1396,7 +1391,6 @@ export function resultCheckStatus() {
13961391 stopStatusLoading();
13971392}
13981393
1399-
14001394/**
14011395 * Switches the currently selected character to the one with the given ID. (character index, not the character key!)
14021396 *
@@ -3760,6 +3754,7 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy
37603754 if (responseLengthCustomized) {
37613755 TempResponseLength.save(api, responseLength);
37623756 }
3757+ /** @type {object|any[]} */
37633758 let generateData = {};
37643759
37653760 switch (api) {
@@ -7138,6 +7133,11 @@ export async function saveChat({ chatName, withMetadata, mesId, force = false }
71387133 }
71397134}
71407135
7136+/**
7137+ * Processes the avatar image from the input element, allowing the user to crop it if necessary.
7138+ * @param {HTMLInputElement} input - The input element containing the avatar file.
7139+ * @returns {Promise<void>}
7140+ */
71417141async function read_avatar_load(input) {
71427142 if (input.files && input.files[0]) {
71437143 if (selected_button == 'create') {
@@ -7169,7 +7169,7 @@ async function read_avatar_load(input) {
71697169 await createOrEditCharacter();
71707170 await delay(DEFAULT_SAVE_EDIT_TIMEOUT);
71717171
71727172 const formData = new FormData(/** @type {HTMLFormElement} */($('#form_create').get(0)));
71737173 await fetch(getThumbnailUrl('avatar', formData.get('avatar_url')), {
71747174 method: 'GET',
71757175 cache: 'no-cache',
@@ -7179,22 +7179,21 @@ async function read_avatar_load(input) {
71797179 },
71807180 });
71817181
71827182 const messages = $('.mes').each(async function toArray() {;
7183- const nameMatch = $(this).attr('ch_name') == formData.get('ch_name');
7183+ for (const el of messages) {
7184- if ($(this).attr('is_system') == 'true' && !nameMatch) {
7184+ const $el = $(el);
7185- return;
7185+ const nameMatch = $el.attr('ch_name') == formData.get('ch_name');
7186- }
7186+ if ($el.attr('is_system') == 'true' && !nameMatch) continue;
71877187 if ($(this)el.attr('is_user') == 'true') {continue;
7188- return;
7188+
7189- }
71907189 if (nameMatch) {
71917190 const previewSrc = $('#avatar_load_preview').attr('src');
71927191 const avatar = $(this)el.find('.avatar img');
71937192 avatar.attr('src', default_avatar);
71947193 await delay(1);
71957194 avatar.attr('src', previewSrc);
71967195 }
71977196 });
71987197
71997198 console.log('Avatar refreshed');
72007199 }
@@ -8044,7 +8043,7 @@ export async function getChatsFromFiles(data, isGroupChat) {
80448043 * response is an object with an `error` property set to `true`.
80458044 */
80468045export async function getPastCharacterChats(characterId = null) {
80478046 characterId = characterId ?? parseInt(this_chid);
80488047 if (!characters[characterId]) return [];
80498048
80508049 const response = await fetch('/api/characters/chats', {
@@ -8111,9 +8110,7 @@ export async function displayPastChats() {
81118110 // UX convenience: Focus the search field when the Manage Chat Files view opens.
81128111 setTimeout(function () {
81138112 const textSearchElement = $('#select_chat_search');
8114- textSearchElement.click();
8113+ textSearchElement.trigger('click').trigger('focus').trigger('select');
8115- textSearchElement.focus();
8116- textSearchElement.select(); // select content (if any) for easy erasing
81178114 }, 200);
81188115}
81198116
@@ -8380,11 +8377,10 @@ function select_rm_create({ switchMenu = true } = {}) {
83808377 switchMenu && setMenuType('create');
83818378
83828379 //console.log('select_rm_Create() -- selected button: '+selected_button);
83838380 if (selected_button == 'create' && create_save.avatar) {
8384- if (create_save.avatar != '') {
8381+ const addAvatarInput = /** @type {HTMLInputElement} */ ($('#add_avatar_button').get(0));
83858382 $('#add_avatar_button').get(0) addAvatarInput.files = create_save.avatar;
8386- read_avatar_load($('#add_avatar_button').get(0));
8383+ read_avatar_load(addAvatarInput);
8387- }
83888384 }
83898385
83908386 switchMenu && selectRightMenuWithAnimation('rm_ch_create_block');
@@ -8510,11 +8506,18 @@ export function updateChatMetadata(newValues, reset) {
85108506 chat_metadata = reset ? { ...newValues } : { ...chat_metadata, ...newValues };
85118507}
85128508
8509+
8510+/**
8511+ * Updates the state of the favorite button based on the provided state.
8512+ * @param {boolean} state Whether the favorite button should be on or off.
8513+ */
85138514function updateFavButtonState(state) {
8515+ // Update global state of the flag
8516+ // TODO: This is bad and needs to be refactored.
85148517 fav_ch_checked = state;
85158518 $('#fav_checkbox').valprop(fav_ch_checked'checked', state);
85168519 $('#favorite_button').toggleClass('fav_on', fav_ch_checkedstate);
85178520 $('#favorite_button').toggleClass('fav_off', !fav_ch_checkedstate);
85188521}
85198522
85208523export async function setScenarioOverride() {
@@ -8830,7 +8833,7 @@ function updateEditArrowClasses() {
88308833export function closeMessageEditor(what = 'all') {
88318834 if (what === 'message' || what === 'all') {
88328835 if (this_edit_mes_id) {
88338836 $(`#chat .mes[mesid="${this_edit_mes_id}"] .mes_edit_cancel`).clicktrigger('click');
88348837 }
88358838 }
88368839 if (what === 'reasoning' || what === 'all') {
@@ -8919,7 +8922,8 @@ function openCharacterWorldPopup() {
89198922 }
89208923
89218924 function onExtraWorldInfoChanged() {
89228925 const selectedWorldsselectorFieldValue = $('.character_extra_world_info_selector').val();
8926+ const selectedWorlds = Array.isArray(selectorFieldValue) ? selectorFieldValue : [];
89238927 let charLore = world_info.charLore ?? [];
89248928
89258929 // TODO: Maybe make this utility function not use the window context?
@@ -8964,7 +8968,7 @@ function openCharacterWorldPopup() {
89648968 // Apped to base dropdown
89658969 world_names.forEach((item, i) => {
89668970 const option = document.createElement('option');
89678971 option.value = String(i);
89688972 option.innerText = item;
89698973 option.selected = item === worldId;
89708974 select.append(option);
@@ -8976,7 +8980,7 @@ function openCharacterWorldPopup() {
89768980 }
89778981 world_names.forEach((item, i) => {
89788982 const option = document.createElement('option');
89798983 option.value = String(i);
89808984 option.innerText = item;
89818985
89828986 const existingCharLore = world_info.charLore?.find((e) => e.name === getCharaFilename());
@@ -9082,7 +9086,7 @@ function addAlternateGreeting(template, greeting, index, getArray, popup) {
90829086 */
90839087async function createOrEditCharacter(e) {
90849088 $('#rm_info_avatar').html('');
90859089 const formData = new FormData(/** @type {HTMLFormElement} */($('#form_create').get(0)));
90869090 formData.set('fav', String(fav_ch_checked));
90879091 const isNewChat = e instanceof CustomEvent && e.type === 'newChat';
90889092
@@ -9164,7 +9168,7 @@ async function createOrEditCharacter(e) {
91649168
91659169 $('#character_popup-button-h3').text('Create character');
91669170
91679171 create_save.avatar = ''null;
91689172
91699173 $('#add_avatar_button').replaceWith(
91709174 $('#add_avatar_button').val('').clone(true),
@@ -10172,9 +10176,6 @@ async function doGetChatName() {
1017210176 return getCurrentChatDetails().sessionName;
1017310177}
1017410178
10175-const isPwaMode = window.navigator.standalone;
10176-if (isPwaMode) { $('body').addClass('PWA'); }
10177-
1017810179function doCharListDisplaySwitch() {
1017910180 power_user.charListGrid = !power_user.charListGrid;
1018010181 document.body.classList.toggle('charListGrid', power_user.charListGrid);
@@ -10759,23 +10760,23 @@ jQuery(async function () {
1075910760
1076010761 //menu buttons setup
1076110762
1076210763 $('#rm_button_settings').clickon('click', function () {
1076310764 selected_button = 'settings';
1076410765 selectRightMenuWithAnimation('rm_api_block');
1076510766 });
1076610767 $('#rm_button_characters').clickon('click', function () {
1076710768 selected_button = 'characters';
1076810769 select_rm_characters();
1076910770 });
1077010771 $('#rm_button_back').clickon('click', function () {
1077110772 selected_button = 'characters';
1077210773 select_rm_characters();
1077310774 });
1077410775 $('#rm_button_create').clickon('click', function () {
1077510776 selected_button = 'create';
1077610777 select_rm_create();
1077710778 });
1077810779 $('#rm_button_selected_ch').clickon('click', function () {
1077910780 if (selected_group) {
1078010781 select_group_chats(selected_group);
1078110782 } else {
@@ -10870,7 +10871,7 @@ jQuery(async function () {
1087010871 callPopup('<h3>' + t`Delete the Chat File?` + '</h3>', 'del_chat');
1087110872 });
1087210873
1087310874 $('#advanced_div').clickon('click', function () {
1087410875 if (!is_advanced_char_open) {
1087510876 is_advanced_char_open = true;
1087610877 $('#character_popup').css({ 'display': 'flex', 'opacity': 0.0 }).addClass('open');
@@ -10885,7 +10886,7 @@ jQuery(async function () {
1088510886 }
1088610887 });
1088710888
1088810889 $('#character_cross').clickon('click', function () {
1088910890 is_advanced_char_open = false;
1089010891 $('#character_popup').transition({
1089110892 opacity: 0,
@@ -10895,12 +10896,12 @@ jQuery(async function () {
1089510896 setTimeout(function () { $('#character_popup').css('display', 'none'); }, animation_duration);
1089610897 });
1089710898
1089810899 $('#character_popup_ok').clickon('click', function () {
1089910900 is_advanced_char_open = false;
1090010901 $('#character_popup').css('display', 'none');
1090110902 });
1090210903
1090310904 $('#dialogue_popup_ok').clickon('click', async function (e_e, customData) {
1090410905 const fromSlashCommand = customData?.fromSlashCommand || false;
1090510906 dialogueCloseStop = false;
1090610907 $('#shadow_popup').transition({
@@ -10930,7 +10931,7 @@ jQuery(async function () {
1093010931 hideLoader();
1093110932 } else { // Open the history view again after 2 seconds (delay to avoid edge cases for deleting last chat).
1093210933 setTimeout(function () {
1093310934 $('#option_select_chat').clicktrigger('click');
1093410935 $('#options').hide(); // hide option popup menu
1093510936 hideLoader();
1093610937 }, 2000);
@@ -10941,18 +10942,16 @@ jQuery(async function () {
1094110942 if (popup_type == 'input') {
1094210943 dialogueResolve($('#dialogue_popup_input').val());
1094310944 $('#dialogue_popup_input').val('');
10944-
1094510945 }
1094610946 else {
1094710947 dialogueResolve(true);
10948-
1094910948 }
1095010949
1095110950 dialogueResolve = null;
1095210951 }
1095310952 });
1095410953
1095510954 $('#dialogue_popup_cancel').clickon('click', function (e) {
1095610955 dialogueCloseStop = false;
1095710956 $('#shadow_popup').transition({
1095810957 opacity: 0,
@@ -10965,21 +10964,20 @@ jQuery(async function () {
1096510964 $('#dialogue_popup').removeClass('large_dialogue_popup');
1096610965 }, animation_duration);
1096710966
10968- //$("#shadow_popup").css("opacity:", 0.0);
1096910967 popup_type = '';
1097010968
1097110969 if (dialogueResolve) {
1097210970 dialogueResolve(false);
1097310971 dialogueResolve = null;
1097410972 }
10975-
1097610973 });
1097710974
1097810975 $('#add_avatar_button').changeon('change', function () {
10979- read_avatar_load(this);
10976+ const inputElement = /** @type {HTMLInputElement} */ (this);
10977+ read_avatar_load(inputElement);
1098010978 });
1098110979
1098210980 $('#form_create').on('submit', (e) => createOrEditCharacter(e.originalEvent));
1098310981
1098410982 $('#delete_button').on('click', async function () {
1098510983 if (this_chid === undefined || !characters[this_chid]) {
@@ -10990,7 +10988,7 @@ jQuery(async function () {
1099010988 let deleteChats = false;
1099110989
1099210990 const confirm = await Popup.show.confirm(t`Delete the character?`, await renderTemplateAsync('deleteConfirm'), {
1099310991 onClose: () => { deleteChats = !!$('#del_char_checkbox').prop('checked'); },
1099410992 });
1099510993 if (!confirm) {
1099610994 return;
@@ -11111,7 +11109,7 @@ jQuery(async function () {
1111111109
1111211110 ///////////////////////////////////////////////////////////////////////////////////
1111311111
1111411112 $('#api_button').clickon('click', function (e) {
1111511113 if ($('#api_url_text').val() != '') {
1111611114 let value = formatKoboldUrl(String($('#api_url_text').val()).trim());
1111711115
@@ -11252,7 +11250,7 @@ jQuery(async function () {
1125211250 if ((selected_group || this_chid !== undefined) && !is_send_press) {
1125311251 let deleteCurrentChat = false;
1125411252 const result = await Popup.show.confirm(t`Start new chat?`, await renderTemplateAsync('newChatConfirm'), {
1125511253 onClose: () => { deleteCurrentChat = !!$('#del_chat_checkbox').prop('checked'); },
1125611254 });
1125711255 if (!result) {
1125811256 return;
@@ -11356,7 +11354,7 @@ jQuery(async function () {
1135611354 //////////////////////////////////////////////////////////////////////////////////////////////
1135711355
1135811356 //functionality for the cancel delete messages button, reverts to normal display of input form
1135911357 $('#dialogue_del_mes_cancel').clickon('click', function () {
1136011358 $('#dialogue_del_mes').css('display', 'none');
1136111359 $('#send_form').css('display', css_send_form_display);
1136211360 $('.del_checkbox').each(function () {
@@ -11496,7 +11494,7 @@ jQuery(async function () {
1149611494
1149711495 //////////////////////////////////////////////////////////////
1149811496
1149911497 $('#select_chat_cross').clickon('click', function () {
1150011498 $('#shadow_select_chat_popup').transition({
1150111499 opacity: 0,
1150211500 duration: animation_duration,
@@ -11590,8 +11588,10 @@ jQuery(async function () {
1159011588 edit_textarea.height(0);
1159111589 edit_textarea.height(edit_textarea[0].scrollHeight);
1159211590 }
1159311591 edit_textarea.focustrigger('focus');
11594- edit_textarea[0].setSelectionRange( //this sets the cursor at the end of the text
11592+ const textAreaElement = /** @type {HTMLTextAreaElement} */ (edit_textarea[0]);
11593+ // Sets the cursor at the end of the text
11594+ textAreaElement.setSelectionRange(
1159511595 String(edit_textarea.val()).length,
1159611596 String(edit_textarea.val()).length,
1159711597 );
@@ -11843,8 +11843,8 @@ jQuery(async function () {
1184311843 //Select chat
1184411844
1184511845 //**************************CHARACTER IMPORT EXPORT*************************//
1184611846 $('#character_import_button').clickon('click', function () {
1184711847 $('#character_import_file').clicktrigger('click');
1184811848 });
1184911849
1185011850 $('#character_import_file').on('change', async function (e) {
@@ -11912,12 +11912,16 @@ jQuery(async function () {
1191211912 }
1191311913 });
1191411914 //**************************CHAT IMPORT EXPORT*************************//
1191511915 $('#chat_import_button').clickon('click', function () {
1191611916 $('#chat_import_file').clicktrigger('click');
1191711917 });
1191811918
1191911919 $('#chat_import_file').on('change', async function (e) {
11920- const file = e.target.files[0];
11920+ const targetElement = /** @type {HTMLInputElement} */ (e.target);
11921+ if (!(targetElement instanceof HTMLInputElement)) {
11922+ return;
11923+ }
11924+ const file = targetElement.files[0];
1192111925
1192211926 if (!file) {
1192311927 return;
@@ -11939,7 +11943,7 @@ jQuery(async function () {
1193911943 const format = ext[1].toLowerCase();
1194011944 $('#chat_import_file_type').val(format);
1194111945
1194211946 const formData = new FormData(/** @type {HTMLFormElement} */($('#form_import_chat').get(0)));
1194311947 formData.append('user_name', name1);
1194411948 $('#select_chat_div').html('');
1194511949
@@ -11950,12 +11954,12 @@ jQuery(async function () {
1195011954 }
1195111955 });
1195211956
1195311957 $('#rm_button_group_chats').clickon('click', function () {
1195411958 selected_button = 'group_chats';
1195511959 select_group_chats();
1195611960 });
1195711961
1195811962 $('#rm_button_back_from_group').clickon('click', function () {
1195911963 selected_button = 'characters';
1196011964 select_rm_characters();
1196111965 });
@@ -12025,7 +12029,7 @@ jQuery(async function () {
1202512029 }
1202612030 });
1202712031
1202812032 $(document).on('click', '.inline-drawer-toggle', async function (e) {
1202912033 if ($(e.target).hasClass('text_pole')) {
1203012034 return;
1203112035 }
@@ -12043,10 +12047,10 @@ jQuery(async function () {
1204312047
1204412048 // Set the height of "autoSetHeight" textareas within the inline-drawer to their scroll height
1204512049 if (!CSS.supports('field-sizing', 'content')) {
1204612050 const textareas = drawerContent.find('textarea.autoSetHeight').each(async function () {;
12047- await resetScrollHeight($(this));
12051+ for (const textarea of textareas) {
12048- return;
12052+ await resetScrollHeight($(textarea));
1204912053 });
1205012054 }
1205112055 });
1205212056
@@ -12161,7 +12165,7 @@ jQuery(async function () {
1216112165 return;
1216212166 }
1216312167 if (isEditVisible && power_user.auto_save_msg_edits === true) {
1216412168 $(`#chat .mes[mesid="${this_edit_mes_id}"] .mes_edit_done`).clicktrigger('click');
1216512169 closeMessageEditor('reasoning');
1216612170 $('#send_textarea').focus();
1216712171 return;
@@ -12176,7 +12180,8 @@ jQuery(async function () {
1217612180 });
1217712181
1217812182 $('#char-management-dropdown').on('change', async (e) => {
12179- let target = $(e.target.selectedOptions).attr('id');
12183+ const targetElement = /** @type {HTMLSelectElement} */ (e.target);
12184+ const target = $(targetElement.selectedOptions).attr('id');
1218012185 switch (target) {
1218112186 case 'set_character_world':
1218212187 openCharacterWorldPopup();
public/scripts/world-info.js+89 -41
@@ -2529,7 +2529,16 @@ export function parseRegexFromString(input) {
25292529 }
25302530}
25312531
2532-//MARK: getWorldEntry
2532+/**
2533+ * Enables the input helper for keys in a World Info entry.
2534+ * @param {object} params - Parameters for enabling the keys input helper.
2535+ * @param {JQuery<HTMLElement>} params.template - The template element containing the input.
2536+ * @param {object} params.entry - The entry object containing the keys.
2537+ * @param {string} params.entryPropName - The property name of the entry that holds the keys.
2538+ * @param {string} params.originalDataValueName - The name of the original data value to be set.
2539+ * @param {string} params.name - The name of the world info entry.
2540+ * @param {object} params.data - The data object containing entries.
2541+ */
25332542function enableKeysInputHelper({ template, entry, entryPropName, originalDataValueName, name, data }) {
25342543 const isFancyInput = !isMobile() && !power_user.wi_key_input_plaintext;
25352544 const input = isFancyInput ? template.find(`select[name="${entryPropName}"]`) : template.find(`textarea[name="${entryPropName}"]`);
@@ -2625,6 +2634,12 @@ function enableKeysInputHelper({ template, entry, entryPropName, originalDataVal
26252634
26262635/**
26272636 * Helper to handle match checkboxes for WI entries.
2637+ * @param {object} params - Parameters for handling match checkboxes.
2638+ * @param {JQuery<HTMLElement>} params.template - The template element containing the checkbox.
2639+ * @param {object} params.entry - The entry object containing the checkbox state.
2640+ * @param {string} params.fieldName - The name of the checkbox field.
2641+ * @param {object} params.data - The data object containing entries.
2642+ * @param {string} params.name - The name of the world info to save changes to.
26282643 */
26292644function handleMatchCheckboxHelper({ template, entry, fieldName, data, name }) {
26302645 const key = originalWIDataKeyMap[fieldName];
@@ -2642,6 +2657,10 @@ function handleMatchCheckboxHelper({ template, entry, fieldName, data, name }) {
26422657
26432658/**
26442659 * Helper to update position/order display.
2660+ * @param {object} params - Parameters for updating position/order display.
2661+ * @param {JQuery<HTMLElement>} params.template - The template element containing the display.
2662+ * @param {object} params.data - The data object containing entries.
2663+ * @param {string} params.uid - The unique identifier of the entry to update.
26452664 */
26462665function updatePosOrdDisplayHelper({ template, data, uid }) {
26472666 let entry = data.entries[uid];
@@ -2658,8 +2677,9 @@ function updatePosOrdDisplayHelper({ template, data, uid }) {
26582677
26592678/**
26602679 * Helper to initialize character filter select2.
2680+ * @param {JQuery<HTMLElement>} characterFilter - The select element for character filter.
26612681 */
26622682function initCharacterFilterSelect2Helper(characterFilter, t) {
26632683 if (!isMobile()) {
26642684 $(characterFilter).select2({
26652685 width: '100%',
@@ -2672,8 +2692,11 @@ function initCharacterFilterSelect2Helper(characterFilter, t) {
26722692
26732693/**
26742694 * Helper to fill character and tag options for character filter.
2695+ * @param {object} params - Parameters for filling options.
2696+ * @param {JQuery<HTMLElement>} params.characterFilter - The select element to fill with options.
2697+ * @param {object} params.entry - The entry object containing character filter data.
26752698 */
26762699function fillCharacterAndTagOptionsHelper({ characterFilter, entry, getContext }) {
26772700 const characters = getContext().characters;
26782701 characters.forEach((character) => {
26792702 const option = document.createElement('option');
@@ -2696,8 +2719,13 @@ function fillCharacterAndTagOptionsHelper({ characterFilter, entry, getContext }
26962719
26972720/**
26982721 * Helper to handle character filter changes.
2722+ * @param {object} params - Parameters for handling character filter changes.
2723+ * @param {JQuery<HTMLElement>} params.characterFilter - The select element for character filter.
2724+ * @param {object} params.data - The data object containing entries.
2725+ * @param {object} params.entry - The entry object to update.
2726+ * @param {string} params.name - The name of the world info to save changes to.
26992727 */
27002728function handleCharacterFilterChangeHelper({ characterFilter, data, entry, name, world_names, getContext, setWIOriginalDataValue, saveWorldInfo, t }) {
27012729 characterFilter.on('mousedown change', async function (e) {
27022730 if (world_names.length === 0) {
27032731 e.preventDefault();
@@ -2728,8 +2756,13 @@ function handleCharacterFilterChangeHelper({ characterFilter, data, entry, name,
27282756
27292757/**
27302758 * Helper to handle probability input.
2759+ * @param {object} params - Parameters for handling probability input.
2760+ * @param {JQuery<HTMLElement>} params.probabilityInput - The input element for probability.
2761+ * @param {object} params.data - The data object containing entries.
2762+ * @param {object} params.entry - The entry object to update.
2763+ * @param {string} params.name - The name of the world info to save changes to.
27312764 */
27322765function handleProbabilityInputHelper({ probabilityInput, data, entry, name, setWIOriginalDataValue, saveWorldInfo }) {
27332766 probabilityInput.data('uid', entry.uid);
27342767 probabilityInput.on('input', async function (_, { noSave = false } = {}) {
27352768 const uid = $(this).data('uid');
@@ -2750,8 +2783,14 @@ function handleProbabilityInputHelper({ probabilityInput, data, entry, name, set
27502783
27512784/**
27522785 * Helper to handle probability toggle.
2786+ * @param {object} params - Parameters for handling probability toggle.
2787+ * @param {JQuery<HTMLElement>} params.probabilityToggle - The toggle element for probability.
2788+ * @param {object} params.data - The data object containing entries.
2789+ * @param {object} params.entry - The entry object to update.
2790+ * @param {string} params.name - The name of the world info to save changes to.
2791+ * @param {JQuery<HTMLElement>} params.probabilityInput - The input element for probability.
27532792 */
27542793function handleProbabilityToggleHelper({ probabilityToggle, data, entry, name, probabilityInput, setWIOriginalDataValue, saveWorldInfo }) {
27552794 probabilityToggle.data('uid', entry.uid);
27562795 probabilityToggle.on('input', async function (_, { noSave = false } = {}) {
27572796 const uid = $(this).data('uid');
@@ -2774,8 +2813,14 @@ function handleProbabilityToggleHelper({ probabilityToggle, data, entry, name, p
27742813
27752814/**
27762815 * Helper to handle select2 dropdowns for boolean selects.
2816+ * @param {object} params - Parameters for handling boolean selects.
2817+ * @param {JQuery<HTMLElement>} params.selectElem - The select element for boolean values.
2818+ * @param {object} params.entry - The entry object containing the boolean value.
2819+ * @param {string} params.entryKey - The key in the entry object for the boolean value.
2820+ * @param {object} params.data - The data object containing entries.
2821+ * @param {string} params.name - The name of the world info to save changes to.
27772822 */
27782823function handleBooleanSelectHelper({ selectElem, entry, entryKey, data, name, setWIOriginalDataValue, saveWorldInfo }) {
27792824 selectElem.data('uid', entry.uid);
27802825 selectElem.on('input', async function (_, { noSave = false } = {}) {
27812826 const uid = $(this).data('uid');
@@ -2789,8 +2834,17 @@ function handleBooleanSelectHelper({ selectElem, entry, entryKey, data, name, se
27892834
27902835/**
27912836 * Helper to handle input fields for numbers.
2837+ * @param {object} params - Parameters for handling number inputs.
2838+ * @param {JQuery<HTMLElement>} params.inputElem - The input element for the number.
2839+ * @param {object} params.entry - The entry object containing the number value.
2840+ * @param {string} params.entryKey - The key in the entry object for the number value.
2841+ * @param {object} params.data - The data object containing entries.
2842+ * @param {string} params.name - The name of the world info to save changes to.
2843+ * @param {number} params.min - The minimum value for the number input.
2844+ * @param {number} params.max - The maximum value for the number input.
2845+ * @param {boolean} [params.clamp=false] - Whether to clamp the value within the min and max range.
27922846 */
27932847function handleNumberInputHelper({ inputElem, entry, entryKey, data, name, setWIOriginalDataValue, saveWorldInfo, min, max, clamp = false }) {
27942848 inputElem.data('uid', entry.uid);
27952849 inputElem.on('input', async function (_, { noSave = false } = {}) {
27962850 const uid = $(this).data('uid');
@@ -2813,8 +2867,13 @@ function handleNumberInputHelper({ inputElem, entry, entryKey, data, name, setWI
28132867
28142868/**
28152869 * Helper to handle tri-state selector for constant/normal/vectorized.
2870+ * @param {object} params - Parameters for handling the entry state selector.
2871+ * @param {JQuery<HTMLElement>} params.entryStateSelector - The select element for entry state.
2872+ * @param {object} params.entry - The entry object containing the state.
2873+ * @param {object} params.data - The data object containing entries.
2874+ * @param {string} params.name - The name of the world info to save changes to.
28162875 */
28172876function handleEntryStateSelectorHelper({ entryStateSelector, entry, data, name, setWIOriginalDataValue, saveWorldInfo }) {
28182877 entryStateSelector.data('uid', entry.uid);
28192878 entryStateSelector.on('click', function (event) {
28202879 event.stopPropagation();
@@ -2850,8 +2909,14 @@ function handleEntryStateSelectorHelper({ entryStateSelector, entry, data, name,
28502909
28512910/**
28522911 * Helper to handle kill switch toggle.
2912+ * @param {object} params - Parameters for handling the kill switch toggle.
2913+ * @param {JQuery<HTMLElement>} params.entryKillSwitch - The toggle element for the kill switch.
2914+ * @param {object} params.entry - The entry object containing the state.
2915+ * @param {object} params.data - The data object containing entries.
2916+ * @param {string} params.name - The name of the world info to save changes to.
2917+ * @param {JQuery<HTMLElement>} params.template - The template element for the entry.
28532918 */
28542919function handleEntryKillSwitchHelper({ entryKillSwitch, entry, data, name, setWIOriginalDataValue, saveWorldInfo, template }) {
28552920 entryKillSwitch.data('uid', entry.uid);
28562921 entryKillSwitch.on('click', async function () {
28572922 const uid = entry.uid;
@@ -2912,13 +2977,12 @@ export async function getWorldEntry(name, data, entry) {
29122977 orderInput.css('width', 'calc(3em + 15px)');
29132978
29142979 // Probability
29152980 handleProbabilityInputHelper({ probabilityInput: headerTemplate.find('input[name="probability"]'), data, entry, name, setWIOriginalDataValue, saveWorldInfo });
29162981
29172982 // Depth
29182983 handleNumberInputHelper({
29192984 inputElem: headerTemplate.find('input[name="depth"]'),
29202985 entry, entryKey: 'depth', data, name, setWIOriginalDataValuemin: 0, saveWorldInfomax: MAX_SCAN_DEPTH, clamp: false,
2921- min: 0, max: MAX_SCAN_DEPTH, clamp: false,
29222986 });
29232987 headerTemplate.find('input[name="depth"]').css('width', 'calc(3em + 15px)');
29242988
@@ -2954,13 +3018,13 @@ export async function getWorldEntry(name, data, entry) {
29543018 // Tri-state selector
29553019 handleEntryStateSelectorHelper({
29563020 entryStateSelector: headerTemplate.find('select[name="entryStateSelector"]'),
29573021 entry, data, name, setWIOriginalDataValue, saveWorldInfo,
29583022 });
29593023
29603024 // Kill switch
29613025 handleEntryKillSwitchHelper({
29623026 entryKillSwitch: headerTemplate.find('div[name="entryKillSwitch"]'),
29633027 entry, data, name, setWIOriginalDataValue, saveWorldInfo, template: headerTemplate,
29643028 });
29653029
29663030 // Duplicate/delete/move buttons
@@ -3087,7 +3151,6 @@ export async function getWorldEntry(name, data, entry) {
30873151 probabilityToggle: editTemplate.find('input[name="useProbability"]'),
30883152 data, entry, name,
30893153 probabilityInput: headerTemplate.find('input[name="probability"]'),
3090- setWIOriginalDataValue, saveWorldInfo,
30913154 });
30923155
30933156 // Comment toggle
@@ -3168,11 +3231,9 @@ export async function getWorldEntry(name, data, entry) {
31683231
31693232 const characterFilter = editTemplate.find('select[name="characterFilter"]');
31703233 characterFilter.data('uid', entry.uid);
31713234 initCharacterFilterSelect2Helper(characterFilter, t);
31723235 fillCharacterAndTagOptionsHelper({ characterFilter, entry, getContext });
3173- handleCharacterFilterChangeHelper({
3236+ handleCharacterFilterChangeHelper({ characterFilter, data, entry, name });
3174- characterFilter, data, entry, name, world_names, getContext, setWIOriginalDataValue, saveWorldInfo, t,
3175- });
31763237
31773238 // Content
31783239 const counter = editTemplate.find('.world_entry_form_token_counter');
@@ -3246,25 +3307,21 @@ export async function getWorldEntry(name, data, entry) {
32463307 // Group weight
32473308 handleNumberInputHelper({
32483309 inputElem: editTemplate.find('input[name="groupWeight"]'),
32493310 entry, entryKey: 'groupWeight', data, name, setWIOriginalDataValuemin: 1, saveWorldInfomax: 10000, clamp: true,
3250- min: 1, max: 10000, clamp: true,
32513311 });
32523312
32533313 // Sticky, cooldown, delay
32543314 handleNumberInputHelper({
32553315 inputElem: editTemplate.find('input[name="sticky"]'),
32563316 entry, entryKey: 'sticky', data, name, setWIOriginalDataValuemin: 1, saveWorldInfomax: 10000, clamp: false,
3257- min: 1, max: 10000, clamp: false,
32583317 });
32593318 handleNumberInputHelper({
32603319 inputElem: editTemplate.find('input[name="cooldown"]'),
32613320 entry, entryKey: 'cooldown', data, name, setWIOriginalDataValuemin: 1, saveWorldInfomax: 10000, clamp: false,
3262- min: 1, max: 10000, clamp: false,
32633321 });
32643322 handleNumberInputHelper({
32653323 inputElem: editTemplate.find('input[name="delay"]'),
32663324 entry, entryKey: 'delay', data, name, setWIOriginalDataValuemin: 1, saveWorldInfomax: 10000, clamp: false,
3267- min: 1, max: 10000, clamp: false,
32683325 });
32693326
32703327 // Exclude/prevent recursion
@@ -3300,18 +3357,9 @@ export async function getWorldEntry(name, data, entry) {
33003357 delayUntilRecursionLevelInput.val(['number', 'string'].includes(typeof entry.delayUntilRecursion) ? entry.delayUntilRecursion : '').trigger('input', { noSave: true });
33013358
33023359 // Boolean selects
3303- handleBooleanSelectHelper({
3360+ handleBooleanSelectHelper({ selectElem: editTemplate.find('select[name="caseSensitive"]'), entry, entryKey: 'caseSensitive', data, name });
33043361 handleBooleanSelectHelper({ selectElem: editTemplate.find('select[name="caseSensitivematchWholeWords"]'), entry, entryKey: 'matchWholeWords', data, name });
3305- entry, entryKey: 'caseSensitive', data, name, setWIOriginalDataValue, saveWorldInfo,
3362+ handleBooleanSelectHelper({ selectElem: editTemplate.find('select[name="useGroupScoring"]'), entry, entryKey: 'useGroupScoring', data, name });
3306- });
3307- handleBooleanSelectHelper({
3308- selectElem: editTemplate.find('select[name="matchWholeWords"]'),
3309- entry, entryKey: 'matchWholeWords', data, name, setWIOriginalDataValue, saveWorldInfo,
3310- });
3311- handleBooleanSelectHelper({
3312- selectElem: editTemplate.find('select[name="useGroupScoring"]'),
3313- entry, entryKey: 'useGroupScoring', data, name, setWIOriginalDataValue, saveWorldInfo,
3314- });
33153363
33163364 // Match checkboxes
33173365 handleMatchCheckboxHelper({ template: editTemplate, entry, fieldName: 'matchPersonaDescription', data, name });