WI: Split entry header and editor

9a82b688baf495ef42af5afbf4f2675dda5327f2

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

3 files changed, +625 -587Ignore whitespace
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+294 -291
@@ -6193,6 +6193,298 @@
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_edit">
6197 <div class="flex-container wide100p alignitemscenter">
6198 <div name="keywordsAndLogicBlock" class="flex-container wide100p alignitemscenter">
6199 <div class="world_entry_form_control keyprimary flex1">
6200 <small class="displayNone">
6201 <span data-i18n="Comma separated (required)">
6202 Comma separated (required)
6203 </span>
6204 </small>
6205 <small class="textAlignCenter" data-i18n="Primary Keywords">Primary Keywords</small>
6206 <select class="keyprimaryselect keyselect select2_multi_sameline" name="key" data-i18n="[placeholder]Keywords or Regexes" placeholder="Keywords or Regexes" multiple="multiple"></select>
6207 <textarea class="text_pole keyprimarytextpole mobile" name="key" rows="1" data-i18n="[placeholder]Comma separated list" placeholder="Comma separated list" style="display: none;"></textarea>
6208 <button type="button" class="switch_input_type_icon" tabindex="-1" title="Switch to plaintext mode" data-i18n="[title]Switch to plaintext mode" data-icon-on="✨" data-icon-off="⌨️" data-tooltip-on="Switch to fancy mode" data-tooltip-off="Switch to plaintext mode">
6209 ⌨️
6210 </button>
6211 </div>
6212 <div class="world_entry_form_control">
6213 <small class="textAlignCenter" data-i18n="Logic">Logic</small>
6214 <select name="entryLogicType" class="text_pole widthFitContent margin0">
6215 <option value="0" data-i18n="AND ANY">AND ANY</option>
6216 <option value="3" data-i18n="AND ALL">AND ALL</option>
6217 <option value="1" data-i18n="NOT ALL">NOT ALL</option>
6218 <option value="2" data-i18n="NOT ANY">NOT ANY</option>
6219 </select>
6220 </div>
6221 <div class="world_entry_form_control keysecondary flex1">
6222 <small class="displayNone">
6223 <span data-i18n="(ignored if empty)">
6224 (ignored if empty)
6225 </span>
6226 </small>
6227 <small class="textAlignCenter" data-i18n="Optional Filter">Optional Filter</small>
6228 <select class="keysecondaryselect keyselect select2_multi_sameline" name="keysecondary" data-i18n="[placeholder]Keywords or Regexes (ignored if empty)" placeholder="Keywords or Regexes (ignored if empty)" multiple="multiple"></select>
6229 <textarea class="text_pole keysecondarytextpole mobile" name="keysecondary" rows="1" data-i18n="[placeholder]Comma separated list (ignored if empty)" placeholder="Comma separated list (ignored if empty)" style="display: none;"></textarea>
6230 <button type="button" class="switch_input_type_icon" tabindex="-1" title="Switch to plaintext mode" data-i18n="[title]Switch to plaintext mode" data-icon-on="✨" data-icon-off="⌨️" data-tooltip-on="Switch to fancy mode" data-tooltip-off="Switch to plaintext mode">
6231 ⌨️
6232 </button>
6233 </div>
6234 </div>
6235 <div name="perEntryOverridesBlock" class="flex-container wide100p alignitemscenter">
6236 <div class="world_entry_form_control flex1">
6237 <small class="textAlignCenter" data-i18n="Scan Depth">Scan Depth</small>
6238 <input class="text_pole margin0" name="scanDepth" type="number" placeholder="Use global setting" data-i18n="[placeholder]Use global setting" max="1000">
6239 </div>
6240 <div class="world_entry_form_control flex1">
6241 <small class="textAlignCenter" data-i18n="Case-Sensitive">Case-Sensitive</small>
6242 <select name="caseSensitive" class="text_pole widthNatural margin0">
6243 <option value="null" data-i18n="Use global">Use global</option>
6244 <option value="true" data-i18n="Yes">Yes</option>
6245 <option value="false" data-i18n="No">No</option>
6246 </select>
6247 </div>
6248 <div class="world_entry_form_control flex1">
6249 <small class="textAlignCenter" data-i18n="Whole Words">Whole Words</small>
6250 <select name="matchWholeWords" class="text_pole widthNatural margin0">
6251 <option value="null" data-i18n="Use global">Use global</option>
6252 <option value="true" data-i18n="Yes">Yes</option>
6253 <option value="false" data-i18n="No">No</option>
6254 </select>
6255 </div>
6256 <div class="world_entry_form_control flex1">
6257 <small class="textAlignCenter" data-i18n="Group Scoring">Group Scoring</small>
6258 <select name="useGroupScoring" class="text_pole widthNatural margin0">
6259 <option value="null" data-i18n="Use global">Use global</option>
6260 <option value="true" data-i18n="Yes">Yes</option>
6261 <option value="false" data-i18n="No">No</option>
6262 </select>
6263 </div>
6264 <div class="world_entry_form_control flex1" title="Can be used to automatically activate Quick Replies" data-i18n="[title]Can be used to automatically activate Quick Replies">
6265 <small class="textAlignCenter" data-i18n="Automation ID">Automation ID</small>
6266 <input class="text_pole margin0" name="automationId" type="text" placeholder="( None )" data-i18n="[placeholder]( None )">
6267 </div>
6268 <div class="world_entry_form_control flex1" title="Defines delay levels for recursive scans.&#13;&#13;Initially, only the first level (smallest number) will match.&#13;Once no matches are found, the next level becomes eligible for matching.&#13;This repeats until all levels are checked.&#13;&#13;Tied to the &quot;Delay until recursion&quot; setting." data-i18n="[title]delay_until_recursion_level">
6269 <small class="textAlignCenter">
6270 <span data-i18n="Recursion Level">Recursion Level</span>
6271 <div class="fa-solid fa-circle-info opacity50p"></div>
6272 </small>
6273 <input class="text_pole margin0" name="delayUntilRecursionLevel" type="text" placeholder="1">
6274 </div>
6275 </div>
6276 <div name="contentAndCharFilterBlock" class="world_entry_thin_controls flex2">
6277 <div class="world_entry_form_control flex1">
6278 <label for="content ">
6279 <small>
6280 <span class="alignitemscenter flex-container flexnowrap wide100p justifySpaceBetween">
6281 <span class="alignitemscenter flex-container">
6282 <span data-i18n="Content" class="mdhotkey_location">
6283 Content
6284 </span>
6285 <i class="editor_maximize fa-solid fa-maximize right_menu_button" title="Expand the editor" data-i18n="[title]Expand the editor"></i>
6286 </span>
6287 <span>
6288 (<span data-i18n="extension_token_counter">Tokens:</span>&nbsp; <span class="world_entry_form_token_counter" data-first-run="true">counting...</span>)&nbsp;
6289 <span class="world_entry_form_uid_value" data-first-run="true"></span>
6290 </span>
6291 <div>
6292 <label class="checkbox flex-container alignitemscenter flexNoGap">
6293 <input type="checkbox" name="exclude_recursion" />
6294 <span data-i18n="Non-recursable (will not be activated by another)">
6295 Non-recursable (will not be activated by another)
6296 </span>
6297 </label>
6298 <label class="checkbox flex-container alignitemscenter flexNoGap">
6299 <input type="checkbox" name="prevent_recursion" />
6300 <span data-i18n="Prevent further recursion (this entry will not activate others)">
6301 Prevent further recursion (will not activate others)
6302 </span>
6303 </label>
6304 <label class="checkbox flex-container alignitemscenter flexNoGap">
6305 <input type="checkbox" name="delay_until_recursion" />
6306 <span data-i18n="Delay until recursion (can only be activated on recursive checking)">
6307 Delay until recursion (can only be activated on recursive checking)
6308 </span>
6309 </label>
6310 </div>
6311 </span>
6312 </small>
6313 <small class="displayNone">
6314 <span data-i18n="What this keyword should mean to the AI, sent verbatim">
6315 What this keyword should mean to the AI, sent verbatim
6316 </span>
6317 </small>
6318 </label>
6319 <textarea class="text_pole mdHotkeys" name="content" rows="8" data-i18n="[placeholder]What this keyword should mean to the AI, sent verbatim" placeholder="What this keyword should mean to the AI, sent verbatim"></textarea>
6320 </div>
6321 </div>
6322 <div class="world_entry_thin_controls commentContainer">
6323 </div>
6324 </div>
6325 <div class="flex-container wide100p flexGap10">
6326 <div class="flex4 flex-container flexFlowColumn flexNoGap">
6327 <div class="flex-container justifySpaceBetween">
6328 <small for="group">
6329 <span data-i18n="Inclusion Group">Inclusion Group</span>
6330 <a href="https://docs.sillytavern.app/usage/core-concepts/worldinfo/#inclusion-group" class="notes-link" target="_blank" title="Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.&#13;Supports multiple comma-separated groups.&#13;&#13;Documentation: World Info - Inclusion Group" data-i18n="[title]Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group">
6331 <span class="fa-solid fa-circle-question note-link-span"></span>
6332 </a>
6333 </small>
6334 <label class="checkbox_label flexNoGap margin-r5" for="groupOverride">
6335 <input type="checkbox" name="groupOverride" />
6336 <span>
6337 <small title="Prioritize this entry: When checked, this entry is prioritized out of all selections.&#13;If multiple are prioritized, the one with the highest 'Order' is chosen.&#13;" data-i18n="[title]Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen.">
6338 <span data-i18n="Prioritize">Prioritize</span>
6339 <div class="fa-solid fa-circle-info opacity50p"></div>
6340 </small>
6341 </span>
6342 </label>
6343 </div>
6344 <div class="range-block-range">
6345 <input type="text" class="text_pole margin0" name="group" rows="1" data-i18n="[placeholder]Only one entry with the same label will be activated" placeholder="Only one entry with the same label will be activated">
6346 </div>
6347 </div>
6348 <div class="flex2 flex-container flexFlowColumn flexNoGap" data-i18n="[title]A relative likelihood of entry activation within the group" title="A relative likelihood of entry activation within the group">
6349 <div class="flex-container justifySpaceBetween marginBot5">
6350 <small for="groupWeight" data-i18n="Group Weight">
6351 Group Weight
6352 </small>
6353 </div>
6354 <div class="range-block-range">
6355 <input type="number" class="text_pole margin0" name="groupWeight" rows="1" placeholder="100" min="1" max="999999">
6356 </div>
6357 </div>
6358 <div class="flex2 flex-container flexFlowColumn flexNoGap" data-i18n="[title]Sticky entries will stay active for N messages after being triggered." title="Sticky entries will stay active for N messages after being triggered.">
6359 <div class="flex-container justifySpaceBetween marginBot5">
6360 <small class="flex-container alignItemsBaseline" for="sticky">
6361 <span data-i18n="Sticky">
6362 Sticky
6363 </span>
6364 <i class="fa-solid fa-comments fa-xs"></i>
6365 </small>
6366 </div>
6367 <div class="range-block-range">
6368 <input class="text_pole margin0" name="sticky" type="number" data-i18n="[placeholder]Non-sticky" placeholder="Non-sticky" min="0" max="999999">
6369 </div>
6370 </div>
6371 <div class="flex2 flex-container flexFlowColumn flexNoGap" data-i18n="[title]Entries with a cooldown can't be activated N messages after being triggered." title="Entries with a cooldown can't be activated N messages after being triggered.">
6372 <div class="flex-container justifySpaceBetween marginBot5">
6373 <small class="flex-container alignItemsBaseline" for="cooldown">
6374 <span data-i18n="Cooldown">
6375 Cooldown
6376 </span>
6377 <i class="fa-solid fa-comments fa-xs"></i>
6378 </small>
6379 </div>
6380 <div class="range-block-range">
6381 <input class="text_pole margin0" name="cooldown" type="number" data-i18n="[placeholder]No cooldown" placeholder="No cooldown" min="0" max="999999">
6382 </div>
6383 </div>
6384 <div class="flex2 flex-container flexFlowColumn flexNoGap" data-i18n="[title]Entries with a delay can't be activated until there are N messages present in the chat." title="Entries with a delay can't be activated until there are N messages present in the chat.">
6385 <div class="flex-container justifySpaceBetween marginBot5">
6386 <small class="flex-container alignItemsBaseline" for="delay">
6387 <span data-i18n="Delay">
6388 Delay
6389 </span>
6390 <i class="fa-solid fa-comments fa-xs"></i>
6391 </small>
6392 </div>
6393 <div class="range-block-range">
6394 <input class="text_pole margin0" name="delay" type="number" data-i18n="[placeholder]No delay" placeholder="No delay" min="0" max="999999">
6395 </div>
6396 </div>
6397 </div>
6398 <div class="flex-container wide100p flexGap10">
6399 <div class="flex4 flex-container flexFlowColumn flexNoGap">
6400 <div class="flex-container justifySpaceBetween">
6401 <small for="characterFilter" data-i18n="Filter to Characters or Tags">
6402 Filter to Characters or Tags
6403 </small>
6404 <label class="checkbox_label flexNoGap margin-r5" for="character_exclusion">
6405 <input type="checkbox" name="character_exclusion" />
6406 <span>
6407 <small title="Switch the Character/Tags filter around to exclude the listed characters and tags from matching for this entry" data-i18n="[title]Switch the Character/Tags filter around to exclude the listed characters and tags from matching for this entry">
6408 <span data-i18n="Exclude">Exclude</span>
6409 <div class="fa-solid fa-circle-info opacity50p"></div>
6410 </small>
6411 </span>
6412 </label>
6413 </div>
6414 <div class="range-block-range">
6415 <select name="characterFilter" class="select2_multi_sameline" multiple>
6416 <option value="" data-i18n="-- Characters not found --">
6417 -- Characters not found --
6418 </option>
6419 </select>
6420 </div>
6421 </div>
6422 </div>
6423 <div name="WIEntryBottomControls" class="flex-container flex1 justifySpaceBetween world_entry_form_horizontal">
6424 <div class="flex-container flexFlowColumn flexNoGap wi-enter-footer-text">
6425 <label class="checkbox flex-container">
6426 <input type="checkbox" name="selective" />
6427 <span data-i18n="Selective">Selective</span>
6428 </label>
6429 <label class="checkbox flex-container">
6430 <input type="checkbox" name="useProbability" />
6431 <span data-i18n="Use Probability">Use Probability</span>
6432 </label>
6433 <label class="checkbox flex-container">
6434 <input type="checkbox" name="addMemo">
6435 <span data-i18n="Add Memo">Add Memo</span>
6436 </label>
6437 </div>
6438 </div>
6439 <div class="inline-drawer wide100p flexFlowColumn">
6440 <div class="inline-drawer-toggle inline-drawer-header inline-drawer-header-pointer userSettingsInnerExpandable">
6441 <strong data-i18n="Additional Matching Sources">Additional Matching Sources</strong>
6442 <div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div>
6443 </div>
6444 <div class="inline-drawer-content flex-container flexFlowRow flexGap10 paddingBottom5px">
6445 <small class="flex-container flex1 flexFlowColumn">
6446 <label class="checkbox flex-container alignItemsCenter flexNoGap">
6447 <input type="checkbox" name="matchCharacterDescription" />
6448 <span data-i18n="Character Description">
6449 Character Description
6450 </span>
6451 </label>
6452 <label class="checkbox flex-container alignItemsCenter flexNoGap">
6453 <input type="checkbox" name="matchCharacterPersonality" />
6454 <span data-i18n="Character Personality">
6455 Character Personality
6456 </span>
6457 </label>
6458 <label class="checkbox flex-container alignItemsCenter flexNoGap">
6459 <input type="checkbox" name="matchScenario" />
6460 <span data-i18n="Scenario">
6461 Scenario
6462 </span>
6463 </label>
6464 </small>
6465 <small class="flex-container flex1 flexFlowColumn">
6466 <label class="checkbox flex-container alignItemsCenter flexNoGap">
6467 <input type="checkbox" name="matchPersonaDescription" />
6468 <span data-i18n="Persona Description">
6469 Persona Description
6470 </span>
6471 </label>
6472 <label class="checkbox flex-container alignItemsCenter flexNoGap">
6473 <input type="checkbox" name="matchCharacterDepthPrompt" />
6474 <span data-i18n="Character's Note">
6475 Character's Note
6476 </span>
6477 </label>
6478 <label class="checkbox flex-container alignItemsCenter flexNoGap">
6479 <input type="checkbox" name="matchCreatorNotes" />
6480 <span data-i18n="Creator's Notes">
6481 Creator's Notes
6482 </span>
6483 </label>
6484 </small>
6485 </div>
6486 </div>
6487 </div>
6196 <div class="world_entry">6488 <div class="world_entry">
6197 <form class="world_entry_form wi-card-entry">6489 <form class="world_entry_form wi-card-entry">
6198 <div class="inline-drawer wide100p">6490 <div class="inline-drawer wide100p">
@@ -6265,297 +6557,8 @@
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>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>
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>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>
6267 </div>6559 </div>
6268 <div class="inline-drawer-content flex-container paddingBottom5px wide100p">6560 <div class="inline-drawer-content inline-drawer-outlet flex-container paddingBottom5px wide100p ">
6269 <div class="flex-container wide100p alignitemscenter">6561 <!-- Outlet for world_entry_edit -->
6270 <div name="keywordsAndLogicBlock" class="flex-container wide100p alignitemscenter">
6271 <div class="world_entry_form_control keyprimary flex1">
6272 <small class="displayNone">
6273 <span data-i18n="Comma separated (required)">
6274 Comma separated (required)
6275 </span>
6276 </small>
6277 <small class="textAlignCenter" data-i18n="Primary Keywords">Primary Keywords</small>
6278 <select class="keyprimaryselect keyselect select2_multi_sameline" name="key" data-i18n="[placeholder]Keywords or Regexes" placeholder="Keywords or Regexes" multiple="multiple"></select>
6279 <textarea class="text_pole keyprimarytextpole mobile" name="key" rows="1" data-i18n="[placeholder]Comma separated list" placeholder="Comma separated list" style="display: none;"></textarea>
6280 <button type="button" class="switch_input_type_icon" tabindex="-1" title="Switch to plaintext mode" data-i18n="[title]Switch to plaintext mode" data-icon-on="✨" data-icon-off="⌨️" data-tooltip-on="Switch to fancy mode" data-tooltip-off="Switch to plaintext mode">
6281 ⌨️
6282 </button>
6283 </div>
6284 <div class="world_entry_form_control">
6285 <small class="textAlignCenter" data-i18n="Logic">Logic</small>
6286 <select name="entryLogicType" class="text_pole widthFitContent margin0">
6287 <option value="0" data-i18n="AND ANY">AND ANY</option>
6288 <option value="3" data-i18n="AND ALL">AND ALL</option>
6289 <option value="1" data-i18n="NOT ALL">NOT ALL</option>
6290 <option value="2" data-i18n="NOT ANY">NOT ANY</option>
6291 </select>
6292 </div>
6293 <div class="world_entry_form_control keysecondary flex1">
6294 <small class="displayNone">
6295 <span data-i18n="(ignored if empty)">
6296 (ignored if empty)
6297 </span>
6298 </small>
6299 <small class="textAlignCenter" data-i18n="Optional Filter">Optional Filter</small>
6300 <select class="keysecondaryselect keyselect select2_multi_sameline" name="keysecondary" data-i18n="[placeholder]Keywords or Regexes (ignored if empty)" placeholder="Keywords or Regexes (ignored if empty)" multiple="multiple"></select>
6301 <textarea class="text_pole keysecondarytextpole mobile" name="keysecondary" rows="1" data-i18n="[placeholder]Comma separated list (ignored if empty)" placeholder="Comma separated list (ignored if empty)" style="display: none;"></textarea>
6302 <button type="button" class="switch_input_type_icon" tabindex="-1" title="Switch to plaintext mode" data-i18n="[title]Switch to plaintext mode" data-icon-on="✨" data-icon-off="⌨️" data-tooltip-on="Switch to fancy mode" data-tooltip-off="Switch to plaintext mode">
6303 ⌨️
6304 </button>
6305 </div>
6306 </div>
6307 <div name="perEntryOverridesBlock" class="flex-container wide100p alignitemscenter">
6308 <div class="world_entry_form_control flex1">
6309 <small class="textAlignCenter" data-i18n="Scan Depth">Scan Depth</small>
6310 <input class="text_pole margin0" name="scanDepth" type="number" placeholder="Use global setting" data-i18n="[placeholder]Use global setting" max="1000">
6311 </div>
6312 <div class="world_entry_form_control flex1">
6313 <small class="textAlignCenter" data-i18n="Case-Sensitive">Case-Sensitive</small>
6314 <select name="caseSensitive" class="text_pole widthNatural margin0">
6315 <option value="null" data-i18n="Use global">Use global</option>
6316 <option value="true" data-i18n="Yes">Yes</option>
6317 <option value="false" data-i18n="No">No</option>
6318 </select>
6319 </div>
6320 <div class="world_entry_form_control flex1">
6321 <small class="textAlignCenter" data-i18n="Whole Words">Whole Words</small>
6322 <select name="matchWholeWords" class="text_pole widthNatural margin0">
6323 <option value="null" data-i18n="Use global">Use global</option>
6324 <option value="true" data-i18n="Yes">Yes</option>
6325 <option value="false" data-i18n="No">No</option>
6326 </select>
6327 </div>
6328 <div class="world_entry_form_control flex1">
6329 <small class="textAlignCenter" data-i18n="Group Scoring">Group Scoring</small>
6330 <select name="useGroupScoring" class="text_pole widthNatural margin0">
6331 <option value="null" data-i18n="Use global">Use global</option>
6332 <option value="true" data-i18n="Yes">Yes</option>
6333 <option value="false" data-i18n="No">No</option>
6334 </select>
6335 </div>
6336 <div class="world_entry_form_control flex1" title="Can be used to automatically activate Quick Replies" data-i18n="[title]Can be used to automatically activate Quick Replies">
6337 <small class="textAlignCenter" data-i18n="Automation ID">Automation ID</small>
6338 <input class="text_pole margin0" name="automationId" type="text" placeholder="( None )" data-i18n="[placeholder]( None )">
6339 </div>
6340 <div class="world_entry_form_control flex1" title="Defines delay levels for recursive scans.&#13;&#13;Initially, only the first level (smallest number) will match.&#13;Once no matches are found, the next level becomes eligible for matching.&#13;This repeats until all levels are checked.&#13;&#13;Tied to the &quot;Delay until recursion&quot; setting." data-i18n="[title]delay_until_recursion_level">
6341 <small class="textAlignCenter">
6342 <span data-i18n="Recursion Level">Recursion Level</span>
6343 <div class="fa-solid fa-circle-info opacity50p"></div>
6344 </small>
6345 <input class="text_pole margin0" name="delayUntilRecursionLevel" type="text" placeholder="1">
6346 </div>
6347 </div>
6348 <div name="contentAndCharFilterBlock" class="world_entry_thin_controls flex2">
6349 <div class="world_entry_form_control flex1">
6350 <label for="content ">
6351 <small>
6352 <span class="alignitemscenter flex-container flexnowrap wide100p justifySpaceBetween">
6353 <span class="alignitemscenter flex-container">
6354 <span data-i18n="Content" class="mdhotkey_location">
6355 Content
6356 </span>
6357 <i class="editor_maximize fa-solid fa-maximize right_menu_button" title="Expand the editor" data-i18n="[title]Expand the editor"></i>
6358 </span>
6359 <span>
6360 (<span data-i18n="extension_token_counter">Tokens:</span>&nbsp; <span class="world_entry_form_token_counter" data-first-run="true">counting...</span>)&nbsp;
6361 <span class="world_entry_form_uid_value" data-first-run="true"></span>
6362 </span>
6363 <div>
6364 <label class="checkbox flex-container alignitemscenter flexNoGap">
6365 <input type="checkbox" name="exclude_recursion" />
6366 <span data-i18n="Non-recursable (will not be activated by another)">
6367 Non-recursable (will not be activated by another)
6368 </span>
6369 </label>
6370 <label class="checkbox flex-container alignitemscenter flexNoGap">
6371 <input type="checkbox" name="prevent_recursion" />
6372 <span data-i18n="Prevent further recursion (this entry will not activate others)">
6373 Prevent further recursion (will not activate others)
6374 </span>
6375 </label>
6376 <label class="checkbox flex-container alignitemscenter flexNoGap">
6377 <input type="checkbox" name="delay_until_recursion" />
6378 <span data-i18n="Delay until recursion (can only be activated on recursive checking)">
6379 Delay until recursion (can only be activated on recursive checking)
6380 </span>
6381 </label>
6382 </div>
6383 </span>
6384 </small>
6385 <small class="displayNone">
6386 <span data-i18n="What this keyword should mean to the AI, sent verbatim">
6387 What this keyword should mean to the AI, sent verbatim
6388 </span>
6389 </small>
6390 </label>
6391 <textarea class="text_pole mdHotkeys" name="content" rows="8" data-i18n="[placeholder]What this keyword should mean to the AI, sent verbatim" placeholder="What this keyword should mean to the AI, sent verbatim"></textarea>
6392 </div>
6393 </div>
6394 <div class="world_entry_thin_controls commentContainer">
6395 </div>
6396 </div>
6397 <div class="flex-container wide100p flexGap10">
6398 <div class="flex4 flex-container flexFlowColumn flexNoGap">
6399 <div class="flex-container justifySpaceBetween">
6400 <small for="group">
6401 <span data-i18n="Inclusion Group">Inclusion Group</span>
6402 <a href="https://docs.sillytavern.app/usage/core-concepts/worldinfo/#inclusion-group" class="notes-link" target="_blank" title="Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.&#13;Supports multiple comma-separated groups.&#13;&#13;Documentation: World Info - Inclusion Group" data-i18n="[title]Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group">
6403 <span class="fa-solid fa-circle-question note-link-span"></span>
6404 </a>
6405 </small>
6406 <label class="checkbox_label flexNoGap margin-r5" for="groupOverride">
6407 <input type="checkbox" name="groupOverride" />
6408 <span>
6409 <small title="Prioritize this entry: When checked, this entry is prioritized out of all selections.&#13;If multiple are prioritized, the one with the highest 'Order' is chosen.&#13;" data-i18n="[title]Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen.">
6410 <span data-i18n="Prioritize">Prioritize</span>
6411 <div class="fa-solid fa-circle-info opacity50p"></div>
6412 </small>
6413 </span>
6414 </label>
6415 </div>
6416 <div class="range-block-range">
6417 <input type="text" class="text_pole margin0" name="group" rows="1" data-i18n="[placeholder]Only one entry with the same label will be activated" placeholder="Only one entry with the same label will be activated">
6418 </div>
6419 </div>
6420 <div class="flex2 flex-container flexFlowColumn flexNoGap" data-i18n="[title]A relative likelihood of entry activation within the group" title="A relative likelihood of entry activation within the group">
6421 <div class="flex-container justifySpaceBetween marginBot5">
6422 <small for="groupWeight" data-i18n="Group Weight">
6423 Group Weight
6424 </small>
6425 </div>
6426 <div class="range-block-range">
6427 <input type="number" class="text_pole margin0" name="groupWeight" rows="1" placeholder="100" min="1" max="999999">
6428 </div>
6429 </div>
6430 <div class="flex2 flex-container flexFlowColumn flexNoGap" data-i18n="[title]Sticky entries will stay active for N messages after being triggered." title="Sticky entries will stay active for N messages after being triggered.">
6431 <div class="flex-container justifySpaceBetween marginBot5">
6432 <small class="flex-container alignItemsBaseline" for="sticky">
6433 <span data-i18n="Sticky">
6434 Sticky
6435 </span>
6436 <i class="fa-solid fa-comments fa-xs"></i>
6437 </small>
6438 </div>
6439 <div class="range-block-range">
6440 <input class="text_pole margin0" name="sticky" type="number" data-i18n="[placeholder]Non-sticky" placeholder="Non-sticky" min="0" max="999999">
6441 </div>
6442 </div>
6443 <div class="flex2 flex-container flexFlowColumn flexNoGap" data-i18n="[title]Entries with a cooldown can't be activated N messages after being triggered." title="Entries with a cooldown can't be activated N messages after being triggered.">
6444 <div class="flex-container justifySpaceBetween marginBot5">
6445 <small class="flex-container alignItemsBaseline" for="cooldown">
6446 <span data-i18n="Cooldown">
6447 Cooldown
6448 </span>
6449 <i class="fa-solid fa-comments fa-xs"></i>
6450 </small>
6451 </div>
6452 <div class="range-block-range">
6453 <input class="text_pole margin0" name="cooldown" type="number" data-i18n="[placeholder]No cooldown" placeholder="No cooldown" min="0" max="999999">
6454 </div>
6455 </div>
6456 <div class="flex2 flex-container flexFlowColumn flexNoGap" data-i18n="[title]Entries with a delay can't be activated until there are N messages present in the chat." title="Entries with a delay can't be activated until there are N messages present in the chat.">
6457 <div class="flex-container justifySpaceBetween marginBot5">
6458 <small class="flex-container alignItemsBaseline" for="delay">
6459 <span data-i18n="Delay">
6460 Delay
6461 </span>
6462 <i class="fa-solid fa-comments fa-xs"></i>
6463 </small>
6464 </div>
6465 <div class="range-block-range">
6466 <input class="text_pole margin0" name="delay" type="number" data-i18n="[placeholder]No delay" placeholder="No delay" min="0" max="999999">
6467 </div>
6468 </div>
6469 </div>
6470 <div class="flex-container wide100p flexGap10">
6471 <div class="flex4 flex-container flexFlowColumn flexNoGap">
6472 <div class="flex-container justifySpaceBetween">
6473 <small for="characterFilter" data-i18n="Filter to Characters or Tags">
6474 Filter to Characters or Tags
6475 </small>
6476 <label class="checkbox_label flexNoGap margin-r5" for="character_exclusion">
6477 <input type="checkbox" name="character_exclusion" />
6478 <span>
6479 <small title="Switch the Character/Tags filter around to exclude the listed characters and tags from matching for this entry" data-i18n="[title]Switch the Character/Tags filter around to exclude the listed characters and tags from matching for this entry">
6480 <span data-i18n="Exclude">Exclude</span>
6481 <div class="fa-solid fa-circle-info opacity50p"></div>
6482 </small>
6483 </span>
6484 </label>
6485 </div>
6486 <div class="range-block-range">
6487 <select name="characterFilter" class="select2_multi_sameline" multiple>
6488 <option value="" data-i18n="-- Characters not found --">
6489 -- Characters not found --
6490 </option>
6491 </select>
6492 </div>
6493 </div>
6494 </div>
6495 <div name="WIEntryBottomControls" class="flex-container flex1 justifySpaceBetween world_entry_form_horizontal">
6496 <div class="flex-container flexFlowColumn flexNoGap wi-enter-footer-text ">
6497 <label class="checkbox flex-container">
6498 <input type="checkbox" name="selective" />
6499 <span data-i18n="Selective">Selective</span>
6500 </label>
6501 <label class="checkbox flex-container">
6502 <input type="checkbox" name="useProbability" />
6503 <span data-i18n="Use Probability">Use Probability</span>
6504 </label>
6505 <label class="checkbox flex-container">
6506 <input type="checkbox" name="addMemo">
6507 <span data-i18n="Add Memo">Add Memo</span>
6508 </label>
6509 </div>
6510 </div>
6511 <div class="inline-drawer wide100p flexFlowColumn">
6512 <div class="inline-drawer-toggle inline-drawer-header inline-drawer-header-pointer userSettingsInnerExpandable">
6513 <strong data-i18n="Additional Matching Sources">Additional Matching Sources</strong>
6514 <div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div>
6515 </div>
6516 <div class="inline-drawer-content flex-container flexFlowRow flexGap10 paddingBottom5px">
6517 <small class="flex-container flex1 flexFlowColumn">
6518 <label class="checkbox flex-container alignItemsCenter flexNoGap">
6519 <input type="checkbox" name="matchCharacterDescription" />
6520 <span data-i18n="Character Description">
6521 Character Description
6522 </span>
6523 </label>
6524 <label class="checkbox flex-container alignItemsCenter flexNoGap">
6525 <input type="checkbox" name="matchCharacterPersonality" />
6526 <span data-i18n="Character Personality">
6527 Character Personality
6528 </span>
6529 </label>
6530 <label class="checkbox flex-container alignItemsCenter flexNoGap">
6531 <input type="checkbox" name="matchScenario" />
6532 <span data-i18n="Scenario">
6533 Scenario
6534 </span>
6535 </label>
6536 </small>
6537 <small class="flex-container flex1 flexFlowColumn">
6538 <label class="checkbox flex-container alignItemsCenter flexNoGap">
6539 <input type="checkbox" name="matchPersonaDescription" />
6540 <span data-i18n="Persona Description">
6541 Persona Description
6542 </span>
6543 </label>
6544 <label class="checkbox flex-container alignItemsCenter flexNoGap">
6545 <input type="checkbox" name="matchCharacterDepthPrompt" />
6546 <span data-i18n="Character's Note">
6547 Character's Note
6548 </span>
6549 </label>
6550 <label class="checkbox flex-container alignItemsCenter flexNoGap">
6551 <input type="checkbox" name="matchCreatorNotes" />
6552 <span data-i18n="Creator's Notes">
6553 Creator's Notes
6554 </span>
6555 </label>
6556 </small>
6557 </div>
6558 </div>
6559 </div>6562 </div>
6560 </div>6563 </div>
6561 </form>6564 </form>
public/scripts/world-info.js+327 -296
@@ -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,67 +3040,315 @@ export async function getWorldEntry(name, data, entry) {
3257 await moveWorldInfoEntry(sourceWorld, selectedValue, sourceUid);3040 await moveWorldInfoEntry(sourceWorld, selectedValue, sourceUid);
3258 });3041 });
32593042
3260 // Scan depth3043 let drawerInitialized = false;
3261 const scanDepthInput = template.find('input[name="scanDepth"]');3044 let drawerDestroyTimeout = null;
3262 scanDepthInput.data('uid', entry.uid);3045 headerTemplate.find('.inline-drawer-toggle').on('click', function () {
3263 scanDepthInput.on('input', async function () {3046 if (drawerDestroyTimeout) {
3264 const uid = $(this).data('uid');3047 clearTimeout(drawerDestroyTimeout);
3265 const isEmpty = $(this).val() === '';3048 drawerDestroyTimeout = null;
3266 const value = Number($(this).val());3049 }
3267 if (value < 0) {3050 if (drawerInitialized) {
3268 $(this).val(0).trigger('input');3051 drawerDestroyTimeout = setTimeout(() => {
3269 toastr.warning('Scan depth cannot be negative');3052 // Drawer was reopened, so we don't destroy it
3270 return;3053 if (editOutlet.is(':visible')) {
3271 }3054 return;
3272 if (value > MAX_SCAN_DEPTH) {3055 }
3273 $(this).val(MAX_SCAN_DEPTH).trigger('input');3056 drawerInitialized = false;
3274 toastr.warning(`Scan depth cannot exceed ${MAX_SCAN_DEPTH}`);3057 clearEntryList(editOutlet);
3275 return;3058 }, debounce_timeout.relaxed);
3059 } else {
3060 drawerInitialized = true;
3061 addEditorDrawerContent();
3276 }3062 }
3277 data.entries[uid].scanDepth = !isEmpty && !isNaN(value) && value >= 0 && value <= MAX_SCAN_DEPTH ? Math.floor(value) : null;
3278 setWIOriginalDataValue(data, uid, 'extensions.scan_depth', data.entries[uid].scanDepth);
3279 await saveWorldInfo(name, data);
3280 });3063 });
3281 scanDepthInput.val(entry.scanDepth ?? null).trigger('input');
32823064
3283 // Boolean selects3065 const editOutlet = headerTemplate.find('.inline-drawer-outlet');
3284 handleBooleanSelectHelper({
3285 selectElem: template.find('select[name="caseSensitive"]'),
3286 entry, entryKey: 'caseSensitive', data, name, setWIOriginalDataValue, saveWorldInfo,
3287 });
3288 handleBooleanSelectHelper({
3289 selectElem: template.find('select[name="matchWholeWords"]'),
3290 entry, entryKey: 'matchWholeWords', data, name, setWIOriginalDataValue, saveWorldInfo,
3291 });
3292 handleBooleanSelectHelper({
3293 selectElem: template.find('select[name="useGroupScoring"]'),
3294 entry, entryKey: 'useGroupScoring', data, name, setWIOriginalDataValue, saveWorldInfo,
3295 });
32963066
3297 // Match checkboxes3067 function addEditorDrawerContent() {
3298 handleMatchCheckboxHelper({ template, entry, fieldName: 'matchPersonaDescription', data, name });3068 const editTemplate = WI_ENTRY_EDIT_TEMPLATE.clone();
3299 handleMatchCheckboxHelper({ template, entry, fieldName: 'matchCharacterDescription', data, name });3069
3300 handleMatchCheckboxHelper({ template, entry, fieldName: 'matchCharacterPersonality', data, name });3070 // UID display
3301 handleMatchCheckboxHelper({ template, entry, fieldName: 'matchCharacterDepthPrompt', data, name });3071 editTemplate.find('.world_entry_form_uid_value').text(`(UID: ${entry.uid})`);
3302 handleMatchCheckboxHelper({ template, entry, fieldName: 'matchScenario', data, name });3072
3303 handleMatchCheckboxHelper({ template, entry, fieldName: 'matchCreatorNotes', data, name });3073 // Key inputs
33043074 const keyInput = enableKeysInputHelper({ template: editTemplate, entry, entryPropName: 'key', originalDataValueName: 'keys', name, data });
3305 // Automation ID3075 const keySecondaryInput = enableKeysInputHelper({ template: editTemplate, entry, entryPropName: 'keysecondary', originalDataValueName: 'secondary_keys', name, data });
3306 const automationIdInput = template.find('input[name="automationId"]');3076
3307 automationIdInput.data('uid', entry.uid);3077 // Key input switch
3308 automationIdInput.on('input', async function () {3078 editTemplate.find('.switch_input_type_icon').on('click', function () {
3309 const uid = $(this).data('uid');3079 power_user.wi_key_input_plaintext = !power_user.wi_key_input_plaintext;
3310 const value = $(this).val();3080 saveSettingsDebounced();
3311 data.entries[uid].automationId = value;3081 const uid = ($(this).parents('.world_entry')).data('uid');
3312 setWIOriginalDataValue(data, uid, 'extensions.automation_id', data.entries[uid].automationId);3082 updateEditor(uid, false);
3313 await saveWorldInfo(name, data);3083 $(`.world_entry[uid="${uid}"] .inline-drawer-icon`).trigger('click');
3314 });3084 }).each((_, icon) => {
3315 automationIdInput.val(entry.automationId ?? '').trigger('input');3085 $(icon).attr('title', $(icon).data(power_user.wi_key_input_plaintext ? 'tooltip-on' : 'tooltip-off'));
3316 setTimeout(() => createEntryInputAutocomplete(automationIdInput, getAutomationIdCallback(data)), 1);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
3202 // Scan depth
3203 const scanDepthInput = editTemplate.find('input[name="scanDepth"]');
3204 scanDepthInput.data('uid', entry.uid);
3205 scanDepthInput.on('input', async function () {
3206 const uid = $(this).data('uid');
3207 const isEmpty = $(this).val() === '';
3208 const value = Number($(this).val());
3209 if (value < 0) {
3210 $(this).val(0).trigger('input');
3211 toastr.warning('Scan depth cannot be negative');
3212 return;
3213 }
3214 if (value > MAX_SCAN_DEPTH) {
3215 $(this).val(MAX_SCAN_DEPTH).trigger('input');
3216 toastr.warning(`Scan depth cannot exceed ${MAX_SCAN_DEPTH}`);
3217 return;
3218 }
3219 data.entries[uid].scanDepth = !isEmpty && !isNaN(value) && value >= 0 && value <= MAX_SCAN_DEPTH ? Math.floor(value) : null;
3220 setWIOriginalDataValue(data, uid, 'extensions.scan_depth', data.entries[uid].scanDepth);
3221 await saveWorldInfo(name, data);
3222 });
3223 scanDepthInput.val(entry.scanDepth ?? null).trigger('input');
3224
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
3306 // Boolean selects
3307 handleBooleanSelectHelper({
3308 selectElem: editTemplate.find('select[name="caseSensitive"]'),
3309 entry, entryKey: 'caseSensitive', data, name, setWIOriginalDataValue, saveWorldInfo,
3310 });
3311 handleBooleanSelectHelper({
3312 selectElem: editTemplate.find('select[name="matchWholeWords"]'),
3313 entry, entryKey: 'matchWholeWords', data, name, setWIOriginalDataValue, saveWorldInfo,
3314 });
3315 handleBooleanSelectHelper({
3316 selectElem: editTemplate.find('select[name="useGroupScoring"]'),
3317 entry, entryKey: 'useGroupScoring', data, name, setWIOriginalDataValue, saveWorldInfo,
3318 });
3319
3320 // Match checkboxes
3321 handleMatchCheckboxHelper({ template: editTemplate, entry, fieldName: 'matchPersonaDescription', data, name });
3322 handleMatchCheckboxHelper({ template: editTemplate, entry, fieldName: 'matchCharacterDescription', data, name });
3323 handleMatchCheckboxHelper({ template: editTemplate, entry, fieldName: 'matchCharacterPersonality', data, name });
3324 handleMatchCheckboxHelper({ template: editTemplate, entry, fieldName: 'matchCharacterDepthPrompt', data, name });
3325 handleMatchCheckboxHelper({ template: editTemplate, entry, fieldName: 'matchScenario', data, name });
3326 handleMatchCheckboxHelper({ template: editTemplate, entry, fieldName: 'matchCreatorNotes', data, name });
3327
3328 // Automation ID
3329 const automationIdInput = editTemplate.find('input[name="automationId"]');
3330 automationIdInput.data('uid', entry.uid);
3331 automationIdInput.on('input', async function () {
3332 const uid = $(this).data('uid');
3333 const value = $(this).val();
3334 data.entries[uid].automationId = value;
3335 setWIOriginalDataValue(data, uid, 'extensions.automation_id', data.entries[uid].automationId);
3336 await saveWorldInfo(name, data);
3337 });
3338 automationIdInput.val(entry.automationId ?? '').trigger('input');
3339 setTimeout(() => createEntryInputAutocomplete(automationIdInput, getAutomationIdCallback(data)), 1);
3340
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 }
33173348
3318 template.find('.inline-drawer-content').css('display', 'none');3349 headerTemplate.find('.inline-drawer-content').css('display', 'none');
33193350
3320 return template;3351 return headerTemplate;
3321}3352}
33223353
3323/**3354/**