Add pagination for WI entries #964
This commit is contained in:
parent
4a30875030
commit
069a07a139
|
@ -39,7 +39,6 @@
|
|||
#world_popup_bottom_holder div {
|
||||
width: fit-content;
|
||||
user-select: none;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.world_popup_logo_block {
|
||||
|
@ -60,7 +59,6 @@
|
|||
#form_rename_world {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
opacity: 0.8;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
|
@ -178,4 +176,10 @@
|
|||
/* possible place for WI Entry header styling */
|
||||
/* .world_entry_form .inline-drawer-header {
|
||||
background-color: var(--SmartThemeShadowColor);
|
||||
} */
|
||||
} */
|
||||
|
||||
#world_editor_select {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
width: 10em;
|
||||
}
|
||||
|
|
|
@ -2507,8 +2507,8 @@
|
|||
<div id="world_popup_text">
|
||||
<div id="world_popup_header" class="flex-container flexGap5">
|
||||
<div class="world_popup_logo_block">
|
||||
<h3 data-i18n="World/Lore Editor">
|
||||
World/Lore Editor
|
||||
<h3 data-i18n="Editor">
|
||||
Editor
|
||||
<a href="https://docs.sillytavern.app/usage/core-concepts/worldinfo/#world-info-entry" class="notes-link" target="_blank"><span class="note-link-span">?</span></a>
|
||||
</h3>
|
||||
</div>
|
||||
|
@ -2524,13 +2524,13 @@
|
|||
<div id="world_import_button" class="menu_button fa-solid fa-file-import fa-fw" title="Import World Info" data-i18n="[title]Import World Info"></div>
|
||||
<div id="world_popup_export" class="menu_button fa-solid fa-file-export margin0 fa-fw" title="Export World Info" data-i18n="[title]Export World Info"></div>
|
||||
<div id="world_popup_delete" class="menu_button fa-solid fa-trash-can redWarningBG margin0 fa-fw" title="Delete World Info" data-i18n="[title]Delete World Info"></div>
|
||||
<span data-i18n="Editing:"> Editing:</span>
|
||||
<small data-i18n="Editing:"> Editing:</small>
|
||||
<select id="world_editor_select" class="margin0">
|
||||
<option value="" data-i18n="--- None ---">--- None ---</option>
|
||||
</select>
|
||||
<div id="world_popup_name_button" class="menu_button fa-solid fa-i-cursor fa-fw" title="Rename World Info" data-i18n="[title]Rename World Info"></div>
|
||||
<div id="world_info_pagination"></div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -3547,61 +3547,6 @@
|
|||
</div>
|
||||
|
||||
<!-- templates for JS to reuse when needed -->
|
||||
<div id="context_editor_template" class="template_element">
|
||||
<div class="context_editor">
|
||||
<h3>Context Template Editor</h3>
|
||||
<h4 class="template_name"></h4>
|
||||
|
||||
<div class="inline-drawer wide100p">
|
||||
<div class="inline-drawer-toggle inline-drawer-header">
|
||||
Substitution Parameters
|
||||
<div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div>
|
||||
</div>
|
||||
<div class="inline-drawer-content">
|
||||
<i>Click to copy.</i>
|
||||
<ul class="template_parameters_list justifyLeft margin0">
|
||||
<li><code>{{char}}</code> - current character name</li>
|
||||
<li><code>{{user}}</code> - current user name</li>
|
||||
<li><code>{{description}}</code> - character description</li>
|
||||
<li><code>{{scenario}}</code> - character or group scenario</li>
|
||||
<li><code>{{personality}}</code> - character personality</li>
|
||||
<li><code>{{mesExamples}}</code> - message examples</li>
|
||||
<li><code>{{wiBeforeCharacter}}</code> - activated World Info entries (Before Char)</li>
|
||||
<li><code>{{wiAfterCharacter}}</code> - activated World Info entries (After Char)</li>
|
||||
<li><code>{{instructSystemPrompt}}</code> - system prompt (Instruct mode only)</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="margin-bot-10px wide100p justifyLeft">
|
||||
Story String Template
|
||||
</div>
|
||||
<textarea class="wide100p textarea_compact story_string_template" rows="8"></textarea>
|
||||
<div>
|
||||
<small>Lines containing parameters resolving to an empty value will be removed from the template
|
||||
string.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="title_restorable">
|
||||
<span>Chat Injections</span>
|
||||
<div title="Add chat injection" data-i18n="[title]Add chat injection" class="menu_button chat_injection_add">
|
||||
<div class="fa-solid fa-plus"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chat_injections_list flex-container flexFlowColumn flexGap5 wide100p"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="chat_injection_template" class="template_element">
|
||||
<div class="chat_injection flex-container wide100p flexGap5 flexnowrap">
|
||||
<input class="chat_injection_text textarea_compact text_pole flex2" data-i18n="[placeholder]Injection text (supports parameters)" placeholder="Injection text (supports parameters)" type="text" />
|
||||
<input class="chat_injection_depth textarea_compact text_pole flex1" data-i18n="[placeholder]Injection depth" placeholder="Injection depth" type="number" min="0" max="100" />
|
||||
<div title="Remove injection" data-i18n="[title]Remove injection" class="menu_button fa-solid fa-xmark chat_injection_remove"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="scenario_override_template" class="template_element">
|
||||
<div class="scenario_override range-block flexFlowColumn flex-container">
|
||||
<div class="range-block-title title_restorable">
|
||||
|
@ -3743,7 +3688,7 @@
|
|||
<textarea class="text_pole keysecondarytextpole" name="keysecondary" rows="1" data-i18n="[placeholder]Comma separated (ignored if empty)" placeholder="Comma separated (ignored if empty)" maxlength="1000"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div>
|
||||
<div class="fa-fw fa-solid fa-circle-chevron-down inline-drawer-icon down"></div>
|
||||
</div>
|
||||
<div class="inline-drawer-content flex-container">
|
||||
<div class="WIEntryContentAndMemo flex-container">
|
||||
|
|
|
@ -133,6 +133,7 @@ import {
|
|||
isDataURL,
|
||||
getCharaFilename,
|
||||
isDigitsOnly,
|
||||
PAGINATION_TEMPLATE,
|
||||
} from "./scripts/utils.js";
|
||||
|
||||
import { extension_settings, getContext, loadExtensionSettings, runGenerationInterceptors, saveMetadataDebounced } from "./scripts/extensions.js";
|
||||
|
@ -1048,6 +1049,7 @@ async function printCharacters(fullRefresh = false) {
|
|||
showSizeChanger: true,
|
||||
prevText: '<',
|
||||
nextText: '>',
|
||||
formatNavigator: PAGINATION_TEMPLATE,
|
||||
showNavigator: true,
|
||||
callback: function (data) {
|
||||
$("#rm_print_characters_block").empty();
|
||||
|
|
|
@ -6,7 +6,8 @@ import {
|
|||
isDataURL,
|
||||
createThumbnail,
|
||||
extractAllWords,
|
||||
saveBase64AsFile
|
||||
saveBase64AsFile,
|
||||
PAGINATION_TEMPLATE,
|
||||
} from './utils.js';
|
||||
import { RA_CountCharTokens, humanizedDateTime, dragElement, favsToHotswap } from "./RossAscends-mods.js";
|
||||
import { loadMovingUIState, sortEntitiesList } from './power-user.js';
|
||||
|
@ -989,6 +990,7 @@ function printGroupCandidates() {
|
|||
showSizeChanger: false,
|
||||
prevText: '<',
|
||||
nextText: '>',
|
||||
formatNavigator: PAGINATION_TEMPLATE,
|
||||
showNavigator: true,
|
||||
showSizeChanger: true,
|
||||
pageSize: Number(localStorage.getItem(storageKey)) || 5,
|
||||
|
@ -1016,6 +1018,7 @@ function printGroupMembers() {
|
|||
showSizeChanger: false,
|
||||
prevText: '<',
|
||||
nextText: '>',
|
||||
formatNavigator: PAGINATION_TEMPLATE,
|
||||
showNavigator: true,
|
||||
showSizeChanger: true,
|
||||
pageSize: Number(localStorage.getItem(storageKey)) || 5,
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { getContext } from "./extensions.js";
|
||||
import { getRequestHeaders } from "../script.js";
|
||||
|
||||
export const PAGINATION_TEMPLATE = '<%= rangeStart %>-<%= rangeEnd %> of <%= totalNumber %>';
|
||||
|
||||
export function onlyUnique(value, index, array) {
|
||||
return array.indexOf(value) === index;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { saveSettings, callPopup, substituteParams, getTokenCount, getRequestHeaders, chat_metadata, this_chid, characters, saveCharacterDebounced, menu_type, eventSource, event_types } from "../script.js";
|
||||
import { download, debounce, initScrollHeight, resetScrollHeight, parseJsonFile, extractDataFromPng, getFileBuffer, getCharaFilename, deepClone, getSortableDelay, escapeRegex } from "./utils.js";
|
||||
import { download, debounce, initScrollHeight, resetScrollHeight, parseJsonFile, extractDataFromPng, getFileBuffer, getCharaFilename, deepClone, getSortableDelay, escapeRegex, PAGINATION_TEMPLATE } from "./utils.js";
|
||||
import { getContext } from "./extensions.js";
|
||||
import { NOTE_MODULE_NAME, metadata_keys, shouldWIAddPrompt } from "./authors-note.js";
|
||||
import { registerSlashCommand } from "./slash-commands.js";
|
||||
|
@ -45,11 +45,8 @@ const saveSettingsDebounced = debounce(() => {
|
|||
saveSettings()
|
||||
}, 1000);
|
||||
const sortFn = (a, b) => b.order - a.order;
|
||||
|
||||
const countTokensDebounced = debounce(function (counter, value) {
|
||||
const numberOfTokens = getTokenCount(value);
|
||||
$(counter).text(numberOfTokens);
|
||||
}, 1000);
|
||||
const navigation_option = { none: 0, previous: 1, last: 2, };
|
||||
let updateEditor = (navigation) => { navigation; };
|
||||
|
||||
export function getWorldInfoSettings() {
|
||||
return {
|
||||
|
@ -228,7 +225,9 @@ function nullWorldInfo() {
|
|||
toastr.info("Create or import a new World Info file first.", "World Info is not set", { timeOut: 10000, preventDuplicates: true });
|
||||
}
|
||||
|
||||
function displayWorldEntries(name, data) {
|
||||
function displayWorldEntries(name, data, navigation = navigation_option.none) {
|
||||
updateEditor = (navigation) => displayWorldEntries(name, data, navigation);
|
||||
|
||||
$("#world_popup_entries_list").empty().show();
|
||||
|
||||
if (!data || !("entries" in data)) {
|
||||
|
@ -237,22 +236,55 @@ function displayWorldEntries(name, data) {
|
|||
$("#world_popup_export").off('click').on('click', nullWorldInfo);
|
||||
$("#world_popup_delete").off('click').on('click', nullWorldInfo);
|
||||
$("#world_popup_entries_list").hide();
|
||||
$("#world_info_pagination").pagination('destroy');
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert the data.entries object into an array
|
||||
const entriesArray = Object.keys(data.entries).map(uid => {
|
||||
const entry = data.entries[uid];
|
||||
entry.displayIndex = entry.displayIndex ?? entry.uid;
|
||||
return entry;
|
||||
function getDataArray(callback) {
|
||||
// Convert the data.entries object into an array
|
||||
const entriesArray = Object.keys(data.entries).map(uid => {
|
||||
const entry = data.entries[uid];
|
||||
entry.displayIndex = entry.displayIndex ?? entry.uid;
|
||||
return entry;
|
||||
});
|
||||
|
||||
// Sort the entries array by displayIndex and uid
|
||||
entriesArray.sort((a, b) => a.displayIndex - b.displayIndex || a.uid - b.uid);
|
||||
callback(entriesArray);
|
||||
}
|
||||
|
||||
let startPage = 1;
|
||||
|
||||
if (navigation === navigation_option.previous) {
|
||||
startPage = $("#world_info_pagination").pagination('getCurrentPageNum');
|
||||
}
|
||||
|
||||
const storageKey = 'WI_PerPage';
|
||||
$("#world_info_pagination").pagination({
|
||||
dataSource: getDataArray,
|
||||
pageSize: Number(localStorage.getItem(storageKey)) || 10,
|
||||
sizeChangerOptions: [10, 25, 50, 100],
|
||||
pageRange: 1,
|
||||
pageNumber: startPage,
|
||||
position: 'top',
|
||||
showPageNumbers: false,
|
||||
showSizeChanger: true,
|
||||
prevText: '<',
|
||||
nextText: '>',
|
||||
formatNavigator: PAGINATION_TEMPLATE,
|
||||
showNavigator: true,
|
||||
callback: function (page) {
|
||||
$("#world_popup_entries_list").empty();
|
||||
const blocks = page.map(entry => getWorldEntry(name, data, entry));
|
||||
$("#world_popup_entries_list").append(blocks);
|
||||
},
|
||||
afterSizeSelectorChange: function (e) {
|
||||
localStorage.setItem(storageKey, e.target.value);
|
||||
}
|
||||
});
|
||||
|
||||
// Sort the entries array by displayIndex and uid
|
||||
entriesArray.sort((a, b) => a.displayIndex - b.displayIndex || a.uid - b.uid);
|
||||
|
||||
// Loop through the sorted array and call appendWorldEntry
|
||||
for (const entry of entriesArray) {
|
||||
appendWorldEntry(name, data, entry);
|
||||
if (navigation === navigation_option.last) {
|
||||
$("#world_info_pagination").pagination('go', $("#world_info_pagination").pagination('getTotalPage'));
|
||||
}
|
||||
|
||||
$("#world_popup_new").off('click').on('click', () => {
|
||||
|
@ -365,7 +397,7 @@ function deleteOriginalDataValue(data, uid) {
|
|||
}
|
||||
}
|
||||
|
||||
function appendWorldEntry(name, data, entry) {
|
||||
function getWorldEntry(name, data, entry) {
|
||||
const template = $("#entry_edit_template .world_entry").clone();
|
||||
template.data("uid", entry.uid);
|
||||
|
||||
|
@ -460,6 +492,10 @@ function appendWorldEntry(name, data, entry) {
|
|||
|
||||
// content
|
||||
const counter = template.find(".world_entry_form_token_counter");
|
||||
const countTokensDebounced = debounce(function (counter, value) {
|
||||
const numberOfTokens = getTokenCount(value);
|
||||
$(counter).text(numberOfTokens);
|
||||
}, 1000);
|
||||
|
||||
const contentInput = template.find('textarea[name="content"]');
|
||||
contentInput.data("uid", entry.uid);
|
||||
|
@ -661,11 +697,10 @@ function appendWorldEntry(name, data, entry) {
|
|||
const uid = $(this).data("uid");
|
||||
deleteWorldInfoEntry(data, uid);
|
||||
deleteOriginalDataValue(data, uid);
|
||||
$(this).closest(".world_entry").remove();
|
||||
saveWorldInfo(name, data);
|
||||
updateEditor(navigation_option.previous);
|
||||
});
|
||||
|
||||
template.appendTo("#world_popup_entries_list");
|
||||
template.find('.inline-drawer-content').css('display', 'none'); //entries start collapsed
|
||||
|
||||
return template;
|
||||
|
@ -706,8 +741,7 @@ function createWorldInfoEntry(name, data) {
|
|||
const newEntry = { uid: newUid, ...newEntryTemplate };
|
||||
data.entries[newUid] = newEntry;
|
||||
|
||||
const entryTemplate = appendWorldEntry(name, data, newEntry);
|
||||
entryTemplate.get(0).scrollIntoView({ behavior: "smooth" });
|
||||
updateEditor(navigation_option.last);
|
||||
}
|
||||
|
||||
async function _save(name, data) {
|
||||
|
|
Loading…
Reference in New Issue