WI: Split entry header and editor

9a82b688baf495ef42af5afbf4f2675dda5327f2

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

3 files changed, +365 -327Showing whitespace changes
public/css/world-info.css+4 -0
@@ -201,6 +201,10 @@
201 transition: opacity 500ms;201 transition: opacity 500ms;
202}202}
203203
204.world_entry_edit {
205 display: contents;
206}
207
204.disabledWIEntry {208.disabledWIEntry {
205 opacity: 0.4;209 opacity: 0.4;
206 filter: grayscale(1);210 filter: grayscale(1);
public/index.html+76 -73
@@ -6193,79 +6193,7 @@
6193 </div>6193 </div>
6194 </div>6194 </div>
6195 <div id="entry_edit_template" class="template_element">6195 <div id="entry_edit_template" class="template_element">
6196 <div class="world_entry">6196 <div class="world_entry_edit">
6197 <form class="world_entry_form wi-card-entry">
6198 <div class="inline-drawer wide100p">
6199 <div class="inline-drawer-header gap5px padding0">
6200 <span class="drag-handle">&#9776;</span>
6201 <div class="gap5px world_entry_thin_controls wide100p alignitemscenter">
6202 <div class="inline-drawer-toggle fa-fw fa-solid fa-circle-chevron-down inline-drawer-icon down"></div>
6203 <div class="fa-solid fa-toggle-on killSwitch" name="entryKillSwitch" data-i18n="[title]Toggle entry's active state." title="Toggle entry's active state."></div>
6204 <div class="flex-container alignitemscenter wide100p">
6205 <div class="WIEntryTitleAndStatus flex-container flex1 alignitemscenter">
6206 <div class="flex-container flex1">
6207 <textarea class="text_pole" rows="1" name="comment" data-i18n="[placeholder]Entry Title/Memo" placeholder="Entry Title/Memo"></textarea>
6208 </div>
6209 <!-- <span class="world_entry_form_position_value"></span> -->
6210 <select data-i18n="[title]WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized" title="WI Entry Status:&#13;🔵 Constant&#13;🟢 Normal&#13;🔗 Vectorized" name="entryStateSelector" class="text_pole widthNatural margin0">
6211 <option value="constant" title="Constant" data-i18n="[title]WI_Entry_Status_Constant">🔵</option>
6212 <option value="normal" title="Normal" data-i18n="[title]WI_Entry_Status_Normal">🟢</option>
6213 <option value="vectorized" title="Vectorized" data-i18n="[title]WI_Entry_Status_Vectorized">🔗</option>
6214 </select>
6215 </div>
6216 <div class="WIEnteryHeaderControls flex-container">
6217 <div name="PositionBlock" class="world_entry_form_control world_entry_form_radios wi-enter-footer-text">
6218 <label for="position" class="WIEntryHeaderTitleMobile" data-i18n="Position:">Position:</label>
6219 <select name="position" class="text_pole widthNatural margin0" data-i18n="[title]T_Position" title="↑Char: Before Character Definitions&#13;↓Char: After Character Definitions&#13;↑EM: Before Example Messages&#13;↓EM: After Example Messages&#13;↑AN: Before Author's Note&#13;↓AN: After Author's Note&#13;@D ⚙️: at Depth (System)&#13;@D 👤: at Depth (User)&#13;@D 🤖: at Depth (Assistant)">
6220 <option value="0" data-role="" data-i18n="Before Char Defs">
6221 ↑Char
6222 </option>
6223 <option value="1" data-role="" data-i18n="After Char Defs">
6224 ↓Char
6225 </option>
6226 <option value="5" data-role="" data-i18n="Before EM">
6227 ↑EM
6228 </option>
6229 <option value="6" data-role="" data-i18n="After EM">
6230 ↓EM
6231 </option>
6232 <option value="2" data-role="" data-i18n="Before AN">
6233 ↑AN
6234 </option>
6235 <option value="3" data-role="" data-i18n="After AN">
6236 ↓AN
6237 </option>
6238 <option value="4" data-role="0" data-i18n="at Depth System">
6239 @D ⚙️
6240 </option>
6241 <option value="4" data-role="1" data-i18n="at Depth User">
6242 @D 👤
6243 </option>
6244 <option value="4" data-role="2" data-i18n="at Depth AI">
6245 @D 🤖
6246 </option>
6247 </select>
6248 </div>
6249 <div class="world_entry_form_control wi-enter-footer-text flex-container flexNoGap">
6250 <label for="depth" class="WIEntryHeaderTitleMobile" data-i18n="Depth:">Depth:</label>
6251 <input title="Depth" class="text_pole wideMax100px margin0" type="number" name="depth" data-i18n="[title]Depth" placeholder="" min="0" max="9999" />
6252 </div>
6253 <div class="world_entry_form_control wi-enter-footer-text flex-container flexNoGap">
6254 <label for="order" class="WIEntryHeaderTitleMobile" data-i18n="Order:">Order:</label>
6255 <input title="Order" data-i18n="[title]Order" class="text_pole wideMax100px margin0" type="number" name="order" placeholder="" min="0" max="9999" />
6256 </div>
6257 <div class="world_entry_form_control wi-enter-footer-text flex-container flexNoGap probabilityContainer">
6258 <label for="order" class="WIEntryHeaderTitleMobile" data-i18n="Trigger %:">Trigger %:</label>
6259 <input title="Probability" data-i18n="[title]Probability" class="text_pole wideMax100px margin0" type="number" name="probability" placeholder="" min="0" max="100" />
6260 </div>
6261 </div>
6262 </div>
6263 </div>
6264 <i class="menu_button move_entry_button fa-solid fa-right-left" title="Move Entry to Another Lorebook" data-i18n="[title]Move Entry to Another Lorebook"></i>
6265 <i class="menu_button duplicate_entry_button fa-solid fa-paste" title="Duplicate world info entry" data-i18n="[title]Duplicate world info entry" type="submit" value=""></i>
6266 <i class="menu_button delete_entry_button fa-solid fa-trash-can" title="Delete world info entry" data-i18n="[title]Delete world info entry" type="submit" value=""></i>
6267 </div>
6268 <div class="inline-drawer-content flex-container paddingBottom5px wide100p">
6269 <div class="flex-container wide100p alignitemscenter">6197 <div class="flex-container wide100p alignitemscenter">
6270 <div name="keywordsAndLogicBlock" class="flex-container wide100p alignitemscenter">6198 <div name="keywordsAndLogicBlock" class="flex-container wide100p alignitemscenter">
6271 <div class="world_entry_form_control keyprimary flex1">6199 <div class="world_entry_form_control keyprimary flex1">
@@ -6557,6 +6485,81 @@
6557 </div>6485 </div>
6558 </div>6486 </div>
6559 </div>6487 </div>
6488 <div class="world_entry">
6489 <form class="world_entry_form wi-card-entry">
6490 <div class="inline-drawer wide100p">
6491 <div class="inline-drawer-header gap5px padding0">
6492 <span class="drag-handle">&#9776;</span>
6493 <div class="gap5px world_entry_thin_controls wide100p alignitemscenter">
6494 <div class="inline-drawer-toggle fa-fw fa-solid fa-circle-chevron-down inline-drawer-icon down"></div>
6495 <div class="fa-solid fa-toggle-on killSwitch" name="entryKillSwitch" data-i18n="[title]Toggle entry's active state." title="Toggle entry's active state."></div>
6496 <div class="flex-container alignitemscenter wide100p">
6497 <div class="WIEntryTitleAndStatus flex-container flex1 alignitemscenter">
6498 <div class="flex-container flex1">
6499 <textarea class="text_pole" rows="1" name="comment" data-i18n="[placeholder]Entry Title/Memo" placeholder="Entry Title/Memo"></textarea>
6500 </div>
6501 <!-- <span class="world_entry_form_position_value"></span> -->
6502 <select data-i18n="[title]WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized" title="WI Entry Status:&#13;🔵 Constant&#13;🟢 Normal&#13;🔗 Vectorized" name="entryStateSelector" class="text_pole widthNatural margin0">
6503 <option value="constant" title="Constant" data-i18n="[title]WI_Entry_Status_Constant">🔵</option>
6504 <option value="normal" title="Normal" data-i18n="[title]WI_Entry_Status_Normal">🟢</option>
6505 <option value="vectorized" title="Vectorized" data-i18n="[title]WI_Entry_Status_Vectorized">🔗</option>
6506 </select>
6507 </div>
6508 <div class="WIEnteryHeaderControls flex-container">
6509 <div name="PositionBlock" class="world_entry_form_control world_entry_form_radios wi-enter-footer-text">
6510 <label for="position" class="WIEntryHeaderTitleMobile" data-i18n="Position:">Position:</label>
6511 <select name="position" class="text_pole widthNatural margin0" data-i18n="[title]T_Position" title="↑Char: Before Character Definitions&#13;↓Char: After Character Definitions&#13;↑EM: Before Example Messages&#13;↓EM: After Example Messages&#13;↑AN: Before Author's Note&#13;↓AN: After Author's Note&#13;@D ⚙️: at Depth (System)&#13;@D 👤: at Depth (User)&#13;@D 🤖: at Depth (Assistant)">
6512 <option value="0" data-role="" data-i18n="Before Char Defs">
6513 ↑Char
6514 </option>
6515 <option value="1" data-role="" data-i18n="After Char Defs">
6516 ↓Char
6517 </option>
6518 <option value="5" data-role="" data-i18n="Before EM">
6519 ↑EM
6520 </option>
6521 <option value="6" data-role="" data-i18n="After EM">
6522 ↓EM
6523 </option>
6524 <option value="2" data-role="" data-i18n="Before AN">
6525 ↑AN
6526 </option>
6527 <option value="3" data-role="" data-i18n="After AN">
6528 ↓AN
6529 </option>
6530 <option value="4" data-role="0" data-i18n="at Depth System">
6531 @D ⚙️
6532 </option>
6533 <option value="4" data-role="1" data-i18n="at Depth User">
6534 @D 👤
6535 </option>
6536 <option value="4" data-role="2" data-i18n="at Depth AI">
6537 @D 🤖
6538 </option>
6539 </select>
6540 </div>
6541 <div class="world_entry_form_control wi-enter-footer-text flex-container flexNoGap">
6542 <label for="depth" class="WIEntryHeaderTitleMobile" data-i18n="Depth:">Depth:</label>
6543 <input title="Depth" class="text_pole wideMax100px margin0" type="number" name="depth" data-i18n="[title]Depth" placeholder="" min="0" max="9999" />
6544 </div>
6545 <div class="world_entry_form_control wi-enter-footer-text flex-container flexNoGap">
6546 <label for="order" class="WIEntryHeaderTitleMobile" data-i18n="Order:">Order:</label>
6547 <input title="Order" data-i18n="[title]Order" class="text_pole wideMax100px margin0" type="number" name="order" placeholder="" min="0" max="9999" />
6548 </div>
6549 <div class="world_entry_form_control wi-enter-footer-text flex-container flexNoGap probabilityContainer">
6550 <label for="order" class="WIEntryHeaderTitleMobile" data-i18n="Trigger %:">Trigger %:</label>
6551 <input title="Probability" data-i18n="[title]Probability" class="text_pole wideMax100px margin0" type="number" name="probability" placeholder="" min="0" max="100" />
6552 </div>
6553 </div>
6554 </div>
6555 </div>
6556 <i class="menu_button move_entry_button fa-solid fa-right-left" title="Move Entry to Another Lorebook" data-i18n="[title]Move Entry to Another Lorebook"></i>
6557 <i class="menu_button duplicate_entry_button fa-solid fa-paste" title="Duplicate world info entry" data-i18n="[title]Duplicate world info entry" type="submit" value=""></i>
6558 <i class="menu_button delete_entry_button fa-solid fa-trash-can" title="Delete world info entry" data-i18n="[title]Delete world info entry" type="submit" value=""></i>
6559 </div>
6560 <div class="inline-drawer-content inline-drawer-outlet flex-container paddingBottom5px wide100p ">
6561 <!-- Outlet for world_entry_edit -->
6562 </div>
6560 </div>6563 </div>
6561 </form>6564 </form>
6562 </div>6565 </div>
public/scripts/world-info.js+285 -254
@@ -58,7 +58,8 @@ export const scan_state = {
58 MIN_ACTIVATIONS: 3,58 MIN_ACTIVATIONS: 3,
59};59};
6060
61const WI_ENTRY_EDIT_TEMPLATE = $('#entry_edit_template .world_entry');61const WI_ENTRY_HEADER_TEMPLATE = $('#entry_edit_template .world_entry');
62const WI_ENTRY_EDIT_TEMPLATE = $('#entry_edit_template .world_entry_edit');
6263
63export let world_info = {};64export let world_info = {};
64export let selected_world_info = [];65export let selected_world_info = [];
@@ -1939,9 +1940,8 @@ function updateWorldEntryKeyOptionsCache(keyOptions, { remove = false, reset = f
1939 worldEntryKeyOptionsCache.sort((a, b) => b.count - a.count || a.text.localeCompare(b.text));1940 worldEntryKeyOptionsCache.sort((a, b) => b.count - a.count || a.text.localeCompare(b.text));
1940}1941}
19411942
1942function clearEntryList() {1943function clearEntryList($list) {
1943 console.time('clearEntryList');1944 console.time('clearEntryList');
1944 const $list = $('#world_popup_entries_list');
19451945
1946 if (!$list.children().length) {1946 if (!$list.children().length) {
1947 console.debug('List already empty, skipping cleanup.');1947 console.debug('List already empty, skipping cleanup.');
@@ -2007,7 +2007,7 @@ async function displayWorldEntries(name, data, navigation = navigation_option.no
20072007
2008 worldEntriesList.css({ 'opacity': 0, 'transition': 'opacity 250ms ease-in-out' });2008 worldEntriesList.css({ 'opacity': 0, 'transition': 'opacity 250ms ease-in-out' });
2009 await delay(250);2009 await delay(250);
2010 clearEntryList();2010 clearEntryList(worldEntriesList);
2011 worldEntriesList.show();2011 worldEntriesList.show();
20122012
2013 if (!data || !('entries' in data)) {2013 if (!data || !('entries' in data)) {
@@ -2104,7 +2104,7 @@ async function displayWorldEntries(name, data, navigation = navigation_option.no
2104 try {2104 try {
2105 // Prevent saveWorldInfo from firing timeouts while rendering the list2105 // Prevent saveWorldInfo from firing timeouts while rendering the list
2106 isSaveWorldInfoDisabled = true;2106 isSaveWorldInfoDisabled = true;
2107 clearEntryList();2107 clearEntryList(worldEntriesList);
21082108
2109 const keywordHeaders = await renderTemplateAsync('worldInfoKeywordHeaders');2109 const keywordHeaders = await renderTemplateAsync('worldInfoKeywordHeaders');
2110 const blocks = [];2110 const blocks = [];
@@ -2885,82 +2885,14 @@ function handleEntryKillSwitchHelper({ entryKillSwitch, entry, data, name, setWI
2885export async function getWorldEntry(name, data, entry) {2885export async function getWorldEntry(name, data, entry) {
2886 if (!data.entries[entry.uid]) return;2886 if (!data.entries[entry.uid]) return;
28872887
2888 const template = WI_ENTRY_EDIT_TEMPLATE.clone();2888 const headerTemplate = WI_ENTRY_HEADER_TEMPLATE.clone();
2889 template.data('uid', entry.uid);2889 headerTemplate.data('uid', entry.uid);
2890 template.attr('uid', entry.uid);2890 headerTemplate.attr('uid', entry.uid);
28912891
2892 if (typeof power_user.wi_key_input_plaintext === 'undefined') power_user.wi_key_input_plaintext = true;2892 if (typeof power_user.wi_key_input_plaintext === 'undefined') power_user.wi_key_input_plaintext = true;
28932893
2894 // Key inputs
2895 const keyInput = enableKeysInputHelper({ template, entry, entryPropName: 'key', originalDataValueName: 'keys', name, data });
2896 const keySecondaryInput = enableKeysInputHelper({ template, entry, entryPropName: 'keysecondary', originalDataValueName: 'secondary_keys', name, data });
2897
2898 // Key input switch
2899 template.find('.switch_input_type_icon').on('click', function () {
2900 power_user.wi_key_input_plaintext = !power_user.wi_key_input_plaintext;
2901 saveSettingsDebounced();
2902 const uid = ($(this).parents('.world_entry')).data('uid');
2903 updateEditor(uid, false);
2904 $(`.world_entry[uid="${uid}"] .inline-drawer-icon`).trigger('click');
2905 }).each((_, icon) => {
2906 $(icon).attr('title', $(icon).data(power_user.wi_key_input_plaintext ? 'tooltip-on' : 'tooltip-off'));
2907 $(icon).text($(icon).data(power_user.wi_key_input_plaintext ? 'icon-on' : 'icon-off'));
2908 });
2909
2910 // Logic AND/NOT
2911 const selectiveLogicDropdown = template.find('select[name="entryLogicType"]');
2912 selectiveLogicDropdown.data('uid', entry.uid);
2913 selectiveLogicDropdown.on('click', e => e.stopPropagation());
2914 selectiveLogicDropdown.on('input', async function () {
2915 const uid = $(this).data('uid');
2916 const value = Number($(this).val());
2917 data.entries[uid].selectiveLogic = !isNaN(value) ? value : world_info_logic.AND_ANY;
2918 setWIOriginalDataValue(data, uid, 'selectiveLogic', data.entries[uid].selectiveLogic);
2919 await saveWorldInfo(name, data);
2920 });
2921 template.find(`select[name="entryLogicType"] option[value=${entry.selectiveLogic}]`).prop('selected', true).trigger('input');
2922
2923 // Character filter
2924 const characterFilterLabel = template.find('label[for="characterFilter"] > small');
2925 characterFilterLabel.text(entry.characterFilter?.isExclude ? 'Exclude Character(s)' : 'Filter to Character(s)');
2926 const characterExclusionInput = template.find('input[name="character_exclusion"]');
2927 characterExclusionInput.data('uid', entry.uid);
2928 characterExclusionInput.on('input', async function () {
2929 const uid = $(this).data('uid');
2930 const value = $(this).prop('checked');
2931 characterFilterLabel.text(value ? 'Exclude Character(s)' : 'Filter to Character(s)');
2932 if (data.entries[uid].characterFilter) {
2933 if (!value && data.entries[uid].characterFilter.names.length === 0 && data.entries[uid].characterFilter.tags.length === 0) {
2934 delete data.entries[uid].characterFilter;
2935 } else {
2936 data.entries[uid].characterFilter.isExclude = value;
2937 }
2938 } else if (value) {
2939 Object.assign(data.entries[uid], { characterFilter: { isExclude: true, names: [], tags: [] } });
2940 }
2941 if (data.entries[uid]?.characterFilter?.names?.length > 0) {
2942 for (const name of [...data.entries[uid].characterFilter.names]) {
2943 if (!getContext().characters.find(x => x.avatar.replace(/\.[^/.]+$/, '') === name)) {
2944 data.entries[uid].characterFilter.names = data.entries[uid].characterFilter.names.filter(x => x !== name);
2945 }
2946 }
2947 }
2948 setWIOriginalDataValue(data, uid, 'character_filter', data.entries[uid].characterFilter);
2949 await saveWorldInfo(name, data);
2950 });
2951 characterExclusionInput.prop('checked', entry.characterFilter?.isExclude ?? false).trigger('input');
2952
2953 const characterFilter = template.find('select[name="characterFilter"]');
2954 characterFilter.data('uid', entry.uid);
2955 initCharacterFilterSelect2Helper(characterFilter, t);
2956 fillCharacterAndTagOptionsHelper({ characterFilter, entry, getContext });
2957 handleCharacterFilterChangeHelper({
2958 characterFilter, data, entry, name, world_names, getContext, setWIOriginalDataValue, saveWorldInfo, t,
2959 });
2960
2961 // Comment2894 // Comment
2962 const commentInput = template.find('textarea[name="comment"]');2895 const commentInput = headerTemplate.find('textarea[name="comment"]');
2963 const commentToggle = template.find('input[name="addMemo"]');
2964 commentInput.data('uid', entry.uid);2896 commentInput.data('uid', entry.uid);
2965 commentInput.on('input', async function (_, { skipReset } = {}) {2897 commentInput.on('input', async function (_, { skipReset } = {}) {
2966 const uid = $(this).data('uid');2898 const uid = $(this).data('uid');
@@ -2970,157 +2902,43 @@ export async function getWorldEntry(name, data, entry) {
2970 setWIOriginalDataValue(data, uid, 'comment', data.entries[uid].comment);2902 setWIOriginalDataValue(data, uid, 'comment', data.entries[uid].comment);
2971 await saveWorldInfo(name, data);2903 await saveWorldInfo(name, data);
2972 });2904 });
2973 commentToggle.data('uid', entry.uid);
2974 commentToggle.on('input', async function () {
2975 const uid = $(this).data('uid');
2976 const value = $(this).prop('checked');
2977 const commentContainer = $(this).closest('.world_entry').find('.commentContainer');
2978 data.entries[uid].addMemo = value;
2979 await saveWorldInfo(name, data);
2980 value ? commentContainer.show() : commentContainer.hide();
2981 });
2982 commentInput.val(entry.comment).trigger('input', { skipReset: true });2905 commentInput.val(entry.comment).trigger('input', { skipReset: true });
2983 commentToggle.prop('checked', true).trigger('input');
2984 commentToggle.parent().hide();
2985
2986 // Content
2987 const counter = template.find('.world_entry_form_token_counter');
2988 const countTokensDebounced = debounce(async function (counter, value) {
2989 const numberOfTokens = await getTokenCountAsync(value);
2990 $(counter).text(numberOfTokens);
2991 }, debounce_timeout.relaxed);
2992 const contentInputId = `world_entry_content_${entry.uid}`;
2993 const contentInput = template.find('textarea[name="content"]');
2994 contentInput.data('uid', entry.uid);
2995 contentInput.attr('id', contentInputId);
2996 contentInput.on('input', async function (_, { skipCount } = {}) {
2997 const uid = $(this).data('uid');
2998 const value = $(this).val();
2999 data.entries[uid].content = value;
3000 setWIOriginalDataValue(data, uid, 'content', data.entries[uid].content);
3001 await saveWorldInfo(name, data);
3002 if (!skipCount) countTokensDebounced(counter, value);
3003 });
3004 contentInput.val(entry.content).trigger('input', { skipCount: true });
3005 template.find('.editor_maximize').attr('data-for', contentInputId);
3006 template.find('.inline-drawer-toggle').on('click', function () {
3007 if (counter.data('first-run')) {
3008 counter.data('first-run', false);
3009 countTokensDebounced(counter, contentInput.val());
3010 if (!keyInput.isFancy) initScrollHeight(keyInput.control);
3011 if (!keySecondaryInput.isFancy) initScrollHeight(keySecondaryInput.control);
3012 }
3013 });
3014
3015 // Selective
3016 const selectiveInput = template.find('input[name="selective"]');
3017 selectiveInput.data('uid', entry.uid);
3018 selectiveInput.on('input', async function () {
3019 const uid = $(this).data('uid');
3020 const value = $(this).prop('checked');
3021 data.entries[uid].selective = value;
3022 setWIOriginalDataValue(data, uid, 'selective', data.entries[uid].selective);
3023 await saveWorldInfo(name, data);
3024 const keysecondary = $(this).closest('.world_entry').find('.keysecondary');
3025 const keysecondarytextpole = $(this).closest('.world_entry').find('.keysecondarytextpole');
3026 const keyprimaryselect = $(this).closest('.world_entry').find('.keyprimaryselect');
3027 const keyprimaryHeight = keyprimaryselect.outerHeight();
3028 keysecondarytextpole.css('height', keyprimaryHeight + 'px');
3029 value ? keysecondary.show() : keysecondary.hide();
3030 });
3031 selectiveInput.prop('checked', true).trigger('input');
3032 selectiveInput.parent().hide();
30332906
3034 // Order2907 // Order
3035 const orderInput = template.find('input[name="order"]');2908 const orderInput = headerTemplate.find('input[name="order"]');
3036 orderInput.data('uid', entry.uid);2909 orderInput.data('uid', entry.uid);
3037 orderInput.on('input', async function () {2910 orderInput.on('input', async function () {
3038 const uid = $(this).data('uid');2911 const uid = $(this).data('uid');
3039 const value = Number($(this).val());2912 const value = Number($(this).val());
3040 data.entries[uid].order = !isNaN(value) ? value : 0;2913 data.entries[uid].order = !isNaN(value) ? value : 0;
3041 updatePosOrdDisplayHelper({ template, data, uid });2914 updatePosOrdDisplayHelper({ template: headerTemplate, data, uid });
3042 setWIOriginalDataValue(data, uid, 'insertion_order', data.entries[uid].order);2915 setWIOriginalDataValue(data, uid, 'insertion_order', data.entries[uid].order);
3043 await saveWorldInfo(name, data);2916 await saveWorldInfo(name, data);
3044 });2917 });
3045 orderInput.val(entry.order).trigger('input');2918 orderInput.val(entry.order).trigger('input');
3046 orderInput.css('width', 'calc(3em + 15px)');2919 orderInput.css('width', 'calc(3em + 15px)');
30472920
3048 // Group
3049 const groupInput = template.find('input[name="group"]');
3050 groupInput.data('uid', entry.uid);
3051 groupInput.on('input', async function () {
3052 const uid = $(this).data('uid');
3053 const value = String($(this).val()).trim();
3054 data.entries[uid].group = value;
3055 setWIOriginalDataValue(data, uid, 'extensions.group', data.entries[uid].group);
3056 await saveWorldInfo(name, data);
3057 });
3058 groupInput.val(entry.group ?? '').trigger('input');
3059 setTimeout(() => createEntryInputAutocomplete(groupInput, getInclusionGroupCallback(data), { allowMultiple: true }), 1);
3060
3061 // Inclusion priority
3062 const groupOverrideInput = template.find('input[name="groupOverride"]');
3063 groupOverrideInput.data('uid', entry.uid);
3064 groupOverrideInput.on('input', async function () {
3065 const uid = $(this).data('uid');
3066 const value = $(this).prop('checked');
3067 data.entries[uid].groupOverride = value;
3068 setWIOriginalDataValue(data, uid, 'extensions.group_override', data.entries[uid].groupOverride);
3069 await saveWorldInfo(name, data);
3070 });
3071 groupOverrideInput.prop('checked', entry.groupOverride).trigger('input');
3072
3073 // Group weight
3074 handleNumberInputHelper({
3075 inputElem: template.find('input[name="groupWeight"]'),
3076 entry, entryKey: 'groupWeight', data, name, setWIOriginalDataValue, saveWorldInfo,
3077 min: 1, max: 10000, clamp: true,
3078 });
3079
3080 // Sticky, cooldown, delay
3081 handleNumberInputHelper({
3082 inputElem: template.find('input[name="sticky"]'),
3083 entry, entryKey: 'sticky', data, name, setWIOriginalDataValue, saveWorldInfo,
3084 min: 1, max: 10000, clamp: false,
3085 });
3086 handleNumberInputHelper({
3087 inputElem: template.find('input[name="cooldown"]'),
3088 entry, entryKey: 'cooldown', data, name, setWIOriginalDataValue, saveWorldInfo,
3089 min: 1, max: 10000, clamp: false,
3090 });
3091 handleNumberInputHelper({
3092 inputElem: template.find('input[name="delay"]'),
3093 entry, entryKey: 'delay', data, name, setWIOriginalDataValue, saveWorldInfo,
3094 min: 1, max: 10000, clamp: false,
3095 });
3096
3097 // Probability2921 // Probability
3098 handleProbabilityInputHelper({ probabilityInput: template.find('input[name="probability"]'), data, entry, name, setWIOriginalDataValue, saveWorldInfo });2922 handleProbabilityInputHelper({ probabilityInput: headerTemplate.find('input[name="probability"]'), data, entry, name, setWIOriginalDataValue, saveWorldInfo });
3099 handleProbabilityToggleHelper({
3100 probabilityToggle: template.find('input[name="useProbability"]'),
3101 data, entry, name,
3102 probabilityInput: template.find('input[name="probability"]'),
3103 setWIOriginalDataValue, saveWorldInfo,
3104 });
31052923
3106 // Depth2924 // Depth
3107 handleNumberInputHelper({2925 handleNumberInputHelper({
3108 inputElem: template.find('input[name="depth"]'),2926 inputElem: headerTemplate.find('input[name="depth"]'),
3109 entry, entryKey: 'depth', data, name, setWIOriginalDataValue, saveWorldInfo,2927 entry, entryKey: 'depth', data, name, setWIOriginalDataValue, saveWorldInfo,
3110 min: 0, max: MAX_SCAN_DEPTH, clamp: false,2928 min: 0, max: MAX_SCAN_DEPTH, clamp: false,
3111 });2929 });
3112 template.find('input[name="depth"]').css('width', 'calc(3em + 15px)');2930 headerTemplate.find('input[name="depth"]').css('width', 'calc(3em + 15px)');
31132931
3114 // Position2932 // Position
3115 if (entry.position === undefined) entry.position = 0;2933 if (entry.position === undefined) entry.position = 0;
3116 const positionInput = template.find('select[name="position"]');2934 const positionInput = headerTemplate.find('select[name="position"]');
3117 positionInput.data('uid', entry.uid);2935 positionInput.data('uid', entry.uid);
3118 positionInput.on('click', e => e.stopPropagation());2936 positionInput.on('click', e => e.stopPropagation());
3119 positionInput.on('input', async function () {2937 positionInput.on('input', async function () {
3120 const uid = $(this).data('uid');2938 const uid = $(this).data('uid');
3121 const value = Number($(this).val());2939 const value = Number($(this).val());
3122 data.entries[uid].position = !isNaN(value) ? value : 0;2940 data.entries[uid].position = !isNaN(value) ? value : 0;
3123 const depthInput = template.find('input[name="depth"]');2941 const depthInput = headerTemplate.find('input[name="depth"]');
3124 if (value === world_info_position.atDepth) {2942 if (value === world_info_position.atDepth) {
3125 depthInput.prop('disabled', false);2943 depthInput.prop('disabled', false);
3126 depthInput.css('visibility', 'visible');2944 depthInput.css('visibility', 'visible');
@@ -3131,64 +2949,29 @@ export async function getWorldEntry(name, data, entry) {
3131 depthInput.css('visibility', 'hidden');2949 depthInput.css('visibility', 'hidden');
3132 data.entries[uid].role = null;2950 data.entries[uid].role = null;
3133 }2951 }
3134 updatePosOrdDisplayHelper({ template, data, uid });2952 updatePosOrdDisplayHelper({ template: headerTemplate, data, uid });
3135 setWIOriginalDataValue(data, uid, 'position', data.entries[uid].position == 0 ? 'before_char' : 'after_char');2953 setWIOriginalDataValue(data, uid, 'position', data.entries[uid].position == 0 ? 'before_char' : 'after_char');
3136 setWIOriginalDataValue(data, uid, 'extensions.position', data.entries[uid].position);2954 setWIOriginalDataValue(data, uid, 'extensions.position', data.entries[uid].position);
3137 setWIOriginalDataValue(data, uid, 'extensions.role', data.entries[uid].role);2955 setWIOriginalDataValue(data, uid, 'extensions.role', data.entries[uid].role);
3138 await saveWorldInfo(name, data);2956 await saveWorldInfo(name, data);
3139 });2957 });
3140 const roleValue = entry.position === world_info_position.atDepth ? String(entry.role ?? extension_prompt_roles.SYSTEM) : '';2958 const roleValue = entry.position === world_info_position.atDepth ? String(entry.role ?? extension_prompt_roles.SYSTEM) : '';
3141 template.find(`select[name="position"] option[value="${entry.position}"][data-role="${roleValue}"]`).prop('selected', true).trigger('input');2959 headerTemplate.find(`select[name="position"] option[value="${entry.position}"][data-role="${roleValue}"]`).prop('selected', true).trigger('input');
3142
3143 // UID display
3144 template.find('.world_entry_form_uid_value').text(`(UID: ${entry.uid})`);
31452960
3146 // Tri-state selector2961 // Tri-state selector
3147 handleEntryStateSelectorHelper({2962 handleEntryStateSelectorHelper({
3148 entryStateSelector: template.find('select[name="entryStateSelector"]'),2963 entryStateSelector: headerTemplate.find('select[name="entryStateSelector"]'),
3149 entry, data, name, setWIOriginalDataValue, saveWorldInfo,2964 entry, data, name, setWIOriginalDataValue, saveWorldInfo,
3150 });2965 });
31512966
3152 // Kill switch2967 // Kill switch
3153 handleEntryKillSwitchHelper({2968 handleEntryKillSwitchHelper({
3154 entryKillSwitch: template.find('div[name="entryKillSwitch"]'),2969 entryKillSwitch: headerTemplate.find('div[name="entryKillSwitch"]'),
3155 entry, data, name, setWIOriginalDataValue, saveWorldInfo, template,2970 entry, data, name, setWIOriginalDataValue, saveWorldInfo, template: headerTemplate,
3156 });
3157
3158 // Exclude/prevent recursion
3159 handleMatchCheckboxHelper({ template, entry, fieldName: 'excludeRecursion', data, name });
3160 handleMatchCheckboxHelper({ template, entry, fieldName: 'preventRecursion', data, name });
3161
3162 // Delay until recursion
3163 const delayUntilRecursionInput = template.find('input[name="delay_until_recursion"]');
3164 delayUntilRecursionInput.data('uid', entry.uid);
3165 const delayUntilRecursionLevelInput = template.find('input[name="delayUntilRecursionLevel"]');
3166 delayUntilRecursionLevelInput.data('uid', entry.uid);
3167 delayUntilRecursionInput.on('input', async function () {
3168 const uid = $(this).data('uid');
3169 const toggled = $(this).prop('checked');
3170 const value = toggled ? data.entries[uid].delayUntilRecursion || true : false;
3171 if (!toggled) delayUntilRecursionLevelInput.val('');
3172 data.entries[uid].delayUntilRecursion = value;
3173 setWIOriginalDataValue(data, uid, 'extensions.delay_until_recursion', data.entries[uid].delayUntilRecursion);
3174 await saveWorldInfo(name, data);
3175 });
3176 delayUntilRecursionInput.prop('checked', entry.delayUntilRecursion).trigger('input');
3177 delayUntilRecursionLevelInput.on('input', async function () {
3178 const uid = $(this).data('uid');
3179 const content = $(this).val();
3180 const value = content === '' ? (typeof data.entries[uid].delayUntilRecursion === 'boolean' ? data.entries[uid].delayUntilRecursion : true)
3181 : content === 1 ? true
3182 : !isNaN(Number(content)) ? Number(content)
3183 : false;
3184 data.entries[uid].delayUntilRecursion = value;
3185 setWIOriginalDataValue(data, uid, 'extensions.delay_until_recursion', data.entries[uid].delayUntilRecursion);
3186 await saveWorldInfo(name, data);
3187 });2971 });
3188 delayUntilRecursionLevelInput.val(['number', 'string'].includes(typeof entry.delayUntilRecursion) ? entry.delayUntilRecursion : '').trigger('input');
31892972
3190 // Duplicate/delete/move buttons2973 // Duplicate/delete/move buttons
3191 template.find('.duplicate_entry_button').data('uid', entry.uid).on('click', async function () {2974 headerTemplate.find('.duplicate_entry_button').data('uid', entry.uid).on('click', async function () {
3192 const uid = $(this).data('uid');2975 const uid = $(this).data('uid');
3193 const entryDup = duplicateWorldInfoEntry(data, uid);2976 const entryDup = duplicateWorldInfoEntry(data, uid);
3194 if (entryDup) {2977 if (entryDup) {
@@ -3196,7 +2979,7 @@ export async function getWorldEntry(name, data, entry) {
3196 updateEditor(entryDup.uid);2979 updateEditor(entryDup.uid);
3197 }2980 }
3198 });2981 });
3199 template.find('.delete_entry_button').data('uid', entry.uid).on('click', async function (e) {2982 headerTemplate.find('.delete_entry_button').data('uid', entry.uid).on('click', async function (e) {
3200 e.stopPropagation();2983 e.stopPropagation();
3201 const uid = $(this).data('uid');2984 const uid = $(this).data('uid');
3202 const deleted = await deleteWorldInfoEntry(data, uid);2985 const deleted = await deleteWorldInfoEntry(data, uid);
@@ -3205,7 +2988,7 @@ export async function getWorldEntry(name, data, entry) {
3205 await saveWorldInfo(name, data);2988 await saveWorldInfo(name, data);
3206 updateEditor(navigation_option.previous);2989 updateEditor(navigation_option.previous);
3207 });2990 });
3208 template.find('.move_entry_button').attr('data-uid', entry.uid).attr('data-current-world', name).on('click', async function (e) {2991 headerTemplate.find('.move_entry_button').attr('data-uid', entry.uid).attr('data-current-world', name).on('click', async function (e) {
3209 e.stopPropagation();2992 e.stopPropagation();
3210 const sourceUid = $(this).attr('data-uid');2993 const sourceUid = $(this).attr('data-uid');
3211 const sourceWorld = $(this).attr('data-current-world');2994 const sourceWorld = $(this).attr('data-current-world');
@@ -3257,8 +3040,167 @@ export async function getWorldEntry(name, data, entry) {
3257 await moveWorldInfoEntry(sourceWorld, selectedValue, sourceUid);3040 await moveWorldInfoEntry(sourceWorld, selectedValue, sourceUid);
3258 });3041 });
32593042
3043 let drawerInitialized = false;
3044 let drawerDestroyTimeout = null;
3045 headerTemplate.find('.inline-drawer-toggle').on('click', function () {
3046 if (drawerDestroyTimeout) {
3047 clearTimeout(drawerDestroyTimeout);
3048 drawerDestroyTimeout = null;
3049 }
3050 if (drawerInitialized) {
3051 drawerDestroyTimeout = setTimeout(() => {
3052 // Drawer was reopened, so we don't destroy it
3053 if (editOutlet.is(':visible')) {
3054 return;
3055 }
3056 drawerInitialized = false;
3057 clearEntryList(editOutlet);
3058 }, debounce_timeout.relaxed);
3059 } else {
3060 drawerInitialized = true;
3061 addEditorDrawerContent();
3062 }
3063 });
3064
3065 const editOutlet = headerTemplate.find('.inline-drawer-outlet');
3066
3067 function addEditorDrawerContent() {
3068 const editTemplate = WI_ENTRY_EDIT_TEMPLATE.clone();
3069
3070 // UID display
3071 editTemplate.find('.world_entry_form_uid_value').text(`(UID: ${entry.uid})`);
3072
3073 // Key inputs
3074 const keyInput = enableKeysInputHelper({ template: editTemplate, entry, entryPropName: 'key', originalDataValueName: 'keys', name, data });
3075 const keySecondaryInput = enableKeysInputHelper({ template: editTemplate, entry, entryPropName: 'keysecondary', originalDataValueName: 'secondary_keys', name, data });
3076
3077 // Key input switch
3078 editTemplate.find('.switch_input_type_icon').on('click', function () {
3079 power_user.wi_key_input_plaintext = !power_user.wi_key_input_plaintext;
3080 saveSettingsDebounced();
3081 const uid = ($(this).parents('.world_entry')).data('uid');
3082 updateEditor(uid, false);
3083 $(`.world_entry[uid="${uid}"] .inline-drawer-icon`).trigger('click');
3084 }).each((_, icon) => {
3085 $(icon).attr('title', $(icon).data(power_user.wi_key_input_plaintext ? 'tooltip-on' : 'tooltip-off'));
3086 $(icon).text($(icon).data(power_user.wi_key_input_plaintext ? 'icon-on' : 'icon-off'));
3087 });
3088
3089 // Probability toggle
3090 handleProbabilityToggleHelper({
3091 probabilityToggle: editTemplate.find('input[name="useProbability"]'),
3092 data, entry, name,
3093 probabilityInput: headerTemplate.find('input[name="probability"]'),
3094 setWIOriginalDataValue, saveWorldInfo,
3095 });
3096
3097 // Comment toggle
3098 const commentToggle = editTemplate.find('input[name="addMemo"]');
3099 commentToggle.data('uid', entry.uid);
3100 commentToggle.on('input', async function () {
3101 const uid = $(this).data('uid');
3102 const value = $(this).prop('checked');
3103 const commentContainer = $(this).closest('.world_entry').find('.commentContainer');
3104 data.entries[uid].addMemo = value;
3105 await saveWorldInfo(name, data);
3106 value ? commentContainer.show() : commentContainer.hide();
3107 });
3108 commentToggle.prop('checked', true).trigger('input');
3109 commentToggle.parent().hide();
3110
3111 // Logic AND/NOT
3112 const selectiveLogicDropdown = editTemplate.find('select[name="entryLogicType"]');
3113 selectiveLogicDropdown.data('uid', entry.uid);
3114 selectiveLogicDropdown.on('click', e => e.stopPropagation());
3115 selectiveLogicDropdown.on('input', async function () {
3116 const uid = $(this).data('uid');
3117 const value = Number($(this).val());
3118 data.entries[uid].selectiveLogic = !isNaN(value) ? value : world_info_logic.AND_ANY;
3119 setWIOriginalDataValue(data, uid, 'selectiveLogic', data.entries[uid].selectiveLogic);
3120 await saveWorldInfo(name, data);
3121 });
3122 editTemplate.find(`select[name="entryLogicType"] option[value=${entry.selectiveLogic}]`).prop('selected', true).trigger('input');
3123
3124 // Selective
3125 const selectiveInput = editTemplate.find('input[name="selective"]');
3126 selectiveInput.data('uid', entry.uid);
3127 selectiveInput.on('input', async function () {
3128 const uid = $(this).data('uid');
3129 const value = $(this).prop('checked');
3130 data.entries[uid].selective = value;
3131 setWIOriginalDataValue(data, uid, 'selective', data.entries[uid].selective);
3132 await saveWorldInfo(name, data);
3133 const keysecondary = $(this).closest('.world_entry').find('.keysecondary');
3134 const keysecondarytextpole = $(this).closest('.world_entry').find('.keysecondarytextpole');
3135 const keyprimaryselect = $(this).closest('.world_entry').find('.keyprimaryselect');
3136 const keyprimaryHeight = keyprimaryselect.outerHeight();
3137 keysecondarytextpole.css('height', keyprimaryHeight + 'px');
3138 value ? keysecondary.show() : keysecondary.hide();
3139 });
3140 selectiveInput.prop('checked', true).trigger('input');
3141 selectiveInput.parent().hide();
3142
3143 // Character filter
3144 const characterFilterLabel = editTemplate.find('label[for="characterFilter"] > small');
3145 characterFilterLabel.text(entry.characterFilter?.isExclude ? 'Exclude Character(s)' : 'Filter to Character(s)');
3146 const characterExclusionInput = editTemplate.find('input[name="character_exclusion"]');
3147 characterExclusionInput.data('uid', entry.uid);
3148 characterExclusionInput.on('input', async function () {
3149 const uid = $(this).data('uid');
3150 const value = $(this).prop('checked');
3151 characterFilterLabel.text(value ? 'Exclude Character(s)' : 'Filter to Character(s)');
3152 if (data.entries[uid].characterFilter) {
3153 if (!value && data.entries[uid].characterFilter.names.length === 0 && data.entries[uid].characterFilter.tags.length === 0) {
3154 delete data.entries[uid].characterFilter;
3155 } else {
3156 data.entries[uid].characterFilter.isExclude = value;
3157 }
3158 } else if (value) {
3159 Object.assign(data.entries[uid], { characterFilter: { isExclude: true, names: [], tags: [] } });
3160 }
3161 if (data.entries[uid]?.characterFilter?.names?.length > 0) {
3162 for (const name of [...data.entries[uid].characterFilter.names]) {
3163 if (!getContext().characters.find(x => x.avatar.replace(/\.[^/.]+$/, '') === name)) {
3164 data.entries[uid].characterFilter.names = data.entries[uid].characterFilter.names.filter(x => x !== name);
3165 }
3166 }
3167 }
3168 setWIOriginalDataValue(data, uid, 'character_filter', data.entries[uid].characterFilter);
3169 await saveWorldInfo(name, data);
3170 });
3171 characterExclusionInput.prop('checked', entry.characterFilter?.isExclude ?? false).trigger('input');
3172
3173 const characterFilter = editTemplate.find('select[name="characterFilter"]');
3174 characterFilter.data('uid', entry.uid);
3175 initCharacterFilterSelect2Helper(characterFilter, t);
3176 fillCharacterAndTagOptionsHelper({ characterFilter, entry, getContext });
3177 handleCharacterFilterChangeHelper({
3178 characterFilter, data, entry, name, world_names, getContext, setWIOriginalDataValue, saveWorldInfo, t,
3179 });
3180
3181 // Content
3182 const counter = editTemplate.find('.world_entry_form_token_counter');
3183 const countTokensDebounced = debounce(async function (counter, value) {
3184 const numberOfTokens = await getTokenCountAsync(value);
3185 $(counter).text(numberOfTokens);
3186 }, debounce_timeout.relaxed);
3187 const contentInputId = `world_entry_content_${entry.uid}`;
3188 const contentInput = editTemplate.find('textarea[name="content"]');
3189 contentInput.data('uid', entry.uid);
3190 contentInput.attr('id', contentInputId);
3191 contentInput.on('input', async function (_, { skipCount } = {}) {
3192 const uid = $(this).data('uid');
3193 const value = $(this).val();
3194 data.entries[uid].content = value;
3195 setWIOriginalDataValue(data, uid, 'content', data.entries[uid].content);
3196 await saveWorldInfo(name, data);
3197 if (!skipCount) countTokensDebounced(counter, value);
3198 });
3199 contentInput.val(entry.content).trigger('input', { skipCount: true });
3200 editTemplate.find('.editor_maximize').attr('data-for', contentInputId);
3201
3260 // Scan depth3202 // Scan depth
3261 const scanDepthInput = template.find('input[name="scanDepth"]');3203 const scanDepthInput = editTemplate.find('input[name="scanDepth"]');
3262 scanDepthInput.data('uid', entry.uid);3204 scanDepthInput.data('uid', entry.uid);
3263 scanDepthInput.on('input', async function () {3205 scanDepthInput.on('input', async function () {
3264 const uid = $(this).data('uid');3206 const uid = $(this).data('uid');
@@ -3280,30 +3222,111 @@ export async function getWorldEntry(name, data, entry) {
3280 });3222 });
3281 scanDepthInput.val(entry.scanDepth ?? null).trigger('input');3223 scanDepthInput.val(entry.scanDepth ?? null).trigger('input');
32823224
3225 // Group
3226 const groupInput = editTemplate.find('input[name="group"]');
3227 groupInput.data('uid', entry.uid);
3228 groupInput.on('input', async function () {
3229 const uid = $(this).data('uid');
3230 const value = String($(this).val()).trim();
3231 data.entries[uid].group = value;
3232 setWIOriginalDataValue(data, uid, 'extensions.group', data.entries[uid].group);
3233 await saveWorldInfo(name, data);
3234 });
3235 groupInput.val(entry.group ?? '').trigger('input');
3236 setTimeout(() => createEntryInputAutocomplete(groupInput, getInclusionGroupCallback(data), { allowMultiple: true }), 1);
3237
3238 // Inclusion priority
3239 const groupOverrideInput = editTemplate.find('input[name="groupOverride"]');
3240 groupOverrideInput.data('uid', entry.uid);
3241 groupOverrideInput.on('input', async function () {
3242 const uid = $(this).data('uid');
3243 const value = $(this).prop('checked');
3244 data.entries[uid].groupOverride = value;
3245 setWIOriginalDataValue(data, uid, 'extensions.group_override', data.entries[uid].groupOverride);
3246 await saveWorldInfo(name, data);
3247 });
3248 groupOverrideInput.prop('checked', entry.groupOverride).trigger('input');
3249
3250 // Group weight
3251 handleNumberInputHelper({
3252 inputElem: editTemplate.find('input[name="groupWeight"]'),
3253 entry, entryKey: 'groupWeight', data, name, setWIOriginalDataValue, saveWorldInfo,
3254 min: 1, max: 10000, clamp: true,
3255 });
3256
3257 // Sticky, cooldown, delay
3258 handleNumberInputHelper({
3259 inputElem: editTemplate.find('input[name="sticky"]'),
3260 entry, entryKey: 'sticky', data, name, setWIOriginalDataValue, saveWorldInfo,
3261 min: 1, max: 10000, clamp: false,
3262 });
3263 handleNumberInputHelper({
3264 inputElem: editTemplate.find('input[name="cooldown"]'),
3265 entry, entryKey: 'cooldown', data, name, setWIOriginalDataValue, saveWorldInfo,
3266 min: 1, max: 10000, clamp: false,
3267 });
3268 handleNumberInputHelper({
3269 inputElem: editTemplate.find('input[name="delay"]'),
3270 entry, entryKey: 'delay', data, name, setWIOriginalDataValue, saveWorldInfo,
3271 min: 1, max: 10000, clamp: false,
3272 });
3273
3274 // Exclude/prevent recursion
3275 handleMatchCheckboxHelper({ template: editTemplate, entry, fieldName: 'excludeRecursion', data, name });
3276 handleMatchCheckboxHelper({ template: editTemplate, entry, fieldName: 'preventRecursion', data, name });
3277
3278 // Delay until recursion
3279 const delayUntilRecursionInput = editTemplate.find('input[name="delay_until_recursion"]');
3280 delayUntilRecursionInput.data('uid', entry.uid);
3281 const delayUntilRecursionLevelInput = editTemplate.find('input[name="delayUntilRecursionLevel"]');
3282 delayUntilRecursionLevelInput.data('uid', entry.uid);
3283 delayUntilRecursionInput.on('input', async function () {
3284 const uid = $(this).data('uid');
3285 const toggled = $(this).prop('checked');
3286 const value = toggled ? data.entries[uid].delayUntilRecursion || true : false;
3287 if (!toggled) delayUntilRecursionLevelInput.val('');
3288 data.entries[uid].delayUntilRecursion = value;
3289 setWIOriginalDataValue(data, uid, 'extensions.delay_until_recursion', data.entries[uid].delayUntilRecursion);
3290 await saveWorldInfo(name, data);
3291 });
3292 delayUntilRecursionInput.prop('checked', entry.delayUntilRecursion).trigger('input');
3293 delayUntilRecursionLevelInput.on('input', async function () {
3294 const uid = $(this).data('uid');
3295 const content = $(this).val();
3296 const value = content === '' ? (typeof data.entries[uid].delayUntilRecursion === 'boolean' ? data.entries[uid].delayUntilRecursion : true)
3297 : content === 1 ? true
3298 : !isNaN(Number(content)) ? Number(content)
3299 : false;
3300 data.entries[uid].delayUntilRecursion = value;
3301 setWIOriginalDataValue(data, uid, 'extensions.delay_until_recursion', data.entries[uid].delayUntilRecursion);
3302 await saveWorldInfo(name, data);
3303 });
3304 delayUntilRecursionLevelInput.val(['number', 'string'].includes(typeof entry.delayUntilRecursion) ? entry.delayUntilRecursion : '').trigger('input');
3305
3283 // Boolean selects3306 // Boolean selects
3284 handleBooleanSelectHelper({3307 handleBooleanSelectHelper({
3285 selectElem: template.find('select[name="caseSensitive"]'),3308 selectElem: editTemplate.find('select[name="caseSensitive"]'),
3286 entry, entryKey: 'caseSensitive', data, name, setWIOriginalDataValue, saveWorldInfo,3309 entry, entryKey: 'caseSensitive', data, name, setWIOriginalDataValue, saveWorldInfo,
3287 });3310 });
3288 handleBooleanSelectHelper({3311 handleBooleanSelectHelper({
3289 selectElem: template.find('select[name="matchWholeWords"]'),3312 selectElem: editTemplate.find('select[name="matchWholeWords"]'),
3290 entry, entryKey: 'matchWholeWords', data, name, setWIOriginalDataValue, saveWorldInfo,3313 entry, entryKey: 'matchWholeWords', data, name, setWIOriginalDataValue, saveWorldInfo,
3291 });3314 });
3292 handleBooleanSelectHelper({3315 handleBooleanSelectHelper({
3293 selectElem: template.find('select[name="useGroupScoring"]'),3316 selectElem: editTemplate.find('select[name="useGroupScoring"]'),
3294 entry, entryKey: 'useGroupScoring', data, name, setWIOriginalDataValue, saveWorldInfo,3317 entry, entryKey: 'useGroupScoring', data, name, setWIOriginalDataValue, saveWorldInfo,
3295 });3318 });
32963319
3297 // Match checkboxes3320 // Match checkboxes
3298 handleMatchCheckboxHelper({ template, entry, fieldName: 'matchPersonaDescription', data, name });3321 handleMatchCheckboxHelper({ template: editTemplate, entry, fieldName: 'matchPersonaDescription', data, name });
3299 handleMatchCheckboxHelper({ template, entry, fieldName: 'matchCharacterDescription', data, name });3322 handleMatchCheckboxHelper({ template: editTemplate, entry, fieldName: 'matchCharacterDescription', data, name });
3300 handleMatchCheckboxHelper({ template, entry, fieldName: 'matchCharacterPersonality', data, name });3323 handleMatchCheckboxHelper({ template: editTemplate, entry, fieldName: 'matchCharacterPersonality', data, name });
3301 handleMatchCheckboxHelper({ template, entry, fieldName: 'matchCharacterDepthPrompt', data, name });3324 handleMatchCheckboxHelper({ template: editTemplate, entry, fieldName: 'matchCharacterDepthPrompt', data, name });
3302 handleMatchCheckboxHelper({ template, entry, fieldName: 'matchScenario', data, name });3325 handleMatchCheckboxHelper({ template: editTemplate, entry, fieldName: 'matchScenario', data, name });
3303 handleMatchCheckboxHelper({ template, entry, fieldName: 'matchCreatorNotes', data, name });3326 handleMatchCheckboxHelper({ template: editTemplate, entry, fieldName: 'matchCreatorNotes', data, name });
33043327
3305 // Automation ID3328 // Automation ID
3306 const automationIdInput = template.find('input[name="automationId"]');3329 const automationIdInput = editTemplate.find('input[name="automationId"]');
3307 automationIdInput.data('uid', entry.uid);3330 automationIdInput.data('uid', entry.uid);
3308 automationIdInput.on('input', async function () {3331 automationIdInput.on('input', async function () {
3309 const uid = $(this).data('uid');3332 const uid = $(this).data('uid');
@@ -3315,9 +3338,17 @@ export async function getWorldEntry(name, data, entry) {
3315 automationIdInput.val(entry.automationId ?? '').trigger('input');3338 automationIdInput.val(entry.automationId ?? '').trigger('input');
3316 setTimeout(() => createEntryInputAutocomplete(automationIdInput, getAutomationIdCallback(data)), 1);3339 setTimeout(() => createEntryInputAutocomplete(automationIdInput, getAutomationIdCallback(data)), 1);
33173340
3318 template.find('.inline-drawer-content').css('display', 'none');3341 countTokensDebounced(counter, contentInput.val());
3342 if (!keyInput.isFancy) initScrollHeight(keyInput.control);
3343 if (!keySecondaryInput.isFancy) initScrollHeight(keySecondaryInput.control);
3344
3345 editTemplate.find('.inline-drawer-content').css('display', 'none');
3346 editOutlet.append(editTemplate);
3347 }
3348
3349 headerTemplate.find('.inline-drawer-content').css('display', 'none');
33193350
3320 return template;3351 return headerTemplate;
3321}3352}
33223353
3323/**3354/**