mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Scored search sorting for personas
This commit is contained in:
@ -4186,6 +4186,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<input id="persona_search_bar" class="text_pole width100p flex1 margin0" type="search" data-i18n="[placeholder]Search..." placeholder="Search..." maxlength="100">
|
<input id="persona_search_bar" class="text_pole width100p flex1 margin0" type="search" data-i18n="[placeholder]Search..." placeholder="Search..." maxlength="100">
|
||||||
<select id="persona_sort_order" class="margin0">
|
<select id="persona_sort_order" class="margin0">
|
||||||
|
<option value="search" data-i18n="Search" hidden>Search</option>
|
||||||
<option value="asc">A-Z</option>
|
<option value="asc">A-Z</option>
|
||||||
<option value="desc">Z-A</option>
|
<option value="desc">Z-A</option>
|
||||||
</select>
|
</select>
|
||||||
|
@ -5914,17 +5914,16 @@ export async function getUserAvatars(doRender = true, openPageAt = '') {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
allEntities.sort((a, b) => {
|
|
||||||
const aName = String(power_user.personas[a] || a);
|
|
||||||
const bName = String(power_user.personas[b] || b);
|
|
||||||
return power_user.persona_sort_order === 'asc' ? aName.localeCompare(bName) : bName.localeCompare(aName);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!doRender) {
|
if (!doRender) {
|
||||||
return allEntities;
|
return allEntities;
|
||||||
}
|
}
|
||||||
|
|
||||||
const entities = personasFilter.applyFilters(allEntities);
|
// Before printing the personas, we check if we should enable/disable search sorting
|
||||||
|
verifyPersonaSearchSortRule();
|
||||||
|
|
||||||
|
let entities = personasFilter.applyFilters(allEntities);
|
||||||
|
entities = sortPersonas(entities);
|
||||||
|
|
||||||
const storageKey = 'Personas_PerPage';
|
const storageKey = 'Personas_PerPage';
|
||||||
const listId = '#user_avatar_block';
|
const listId = '#user_avatar_block';
|
||||||
const perPage = Number(localStorage.getItem(storageKey)) || 5;
|
const perPage = Number(localStorage.getItem(storageKey)) || 5;
|
||||||
@ -5978,6 +5977,50 @@ function highlightSelectedAvatar() {
|
|||||||
$(`#user_avatar_block .avatar-container[imgfile="${user_avatar}"]`).addClass('selected');
|
$(`#user_avatar_block .avatar-container[imgfile="${user_avatar}"]`).addClass('selected');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort the given personas
|
||||||
|
* @param {string[]} personas - The persona names to sort
|
||||||
|
* @returns {string[]} The sorted persona names arrray, same reference as passed in
|
||||||
|
*/
|
||||||
|
function sortPersonas(personas) {
|
||||||
|
const option = $('#persona_sort_order').find(':selected');
|
||||||
|
if (option.attr('value') === 'search') {
|
||||||
|
personas.sort((a, b) => {
|
||||||
|
const aScore = personasFilter.getScore(FILTER_TYPES.WORLD_INFO_SEARCH, a);
|
||||||
|
const bScore = personasFilter.getScore(FILTER_TYPES.WORLD_INFO_SEARCH, b);
|
||||||
|
return (aScore - bScore);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
personas.sort((a, b) => {
|
||||||
|
const aName = String(power_user.personas[a] || a);
|
||||||
|
const bName = String(power_user.personas[b] || b);
|
||||||
|
return power_user.persona_sort_order === 'asc' ? aName.localeCompare(bName) : bName.localeCompare(aName);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return personas;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Checks the state of the current search, and adds/removes the search sorting option accordingly */
|
||||||
|
function verifyPersonaSearchSortRule() {
|
||||||
|
const searchTerm = personasFilter.getFilterData(FILTER_TYPES.PERSONA_SEARCH);
|
||||||
|
const searchOption = $('#persona_sort_order option[value="search"]');
|
||||||
|
const selector = $('#persona_sort_order');
|
||||||
|
const isHidden = searchOption.attr('hidden') !== undefined;
|
||||||
|
|
||||||
|
// If we have a search term, we are displaying the sorting option for it
|
||||||
|
if (searchTerm && isHidden) {
|
||||||
|
searchOption.removeAttr('hidden');
|
||||||
|
selector.val(searchOption.attr('value'));
|
||||||
|
flashHighlight(selector);
|
||||||
|
}
|
||||||
|
// If search got cleared, we make sure to hide the option and go back to the one before
|
||||||
|
if (!searchTerm && !isHidden) {
|
||||||
|
searchOption.attr('hidden', '');
|
||||||
|
selector.val(power_user.persona_sort_order);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a rendered avatar block.
|
* Gets a rendered avatar block.
|
||||||
* @param {string} name Avatar file name
|
* @param {string} name Avatar file name
|
||||||
@ -8698,7 +8741,7 @@ jQuery(async function () {
|
|||||||
personasFilter.setFilterData(FILTER_TYPES.PERSONA_SEARCH, searchQuery);
|
personasFilter.setFilterData(FILTER_TYPES.PERSONA_SEARCH, searchQuery);
|
||||||
});
|
});
|
||||||
$('#persona_search_bar').on('input', function () {
|
$('#persona_search_bar').on('input', function () {
|
||||||
const searchQuery = String($(this).val()).toLowerCase();
|
const searchQuery = String($(this).val());
|
||||||
debouncedPersonaSearch(searchQuery);
|
debouncedPersonaSearch(searchQuery);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -151,9 +151,7 @@ export class FilterHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const fuzzySearchResults = fuzzySearchWorldInfo(data, term);
|
const fuzzySearchResults = fuzzySearchWorldInfo(data, term);
|
||||||
|
this.cacheScores(FILTER_TYPES.WORLD_INFO_SEARCH, new Map(fuzzySearchResults.map(i => [i.item?.uid, i.score])));
|
||||||
var wiScoreMap = new Map(fuzzySearchResults.map(i => [i.item?.uid, i.score]));
|
|
||||||
this.cacheScores(FILTER_TYPES.WORLD_INFO_SEARCH, wiScoreMap);
|
|
||||||
|
|
||||||
const filteredData = data.filter(entity => fuzzySearchResults.find(x => x.item === entity));
|
const filteredData = data.filter(entity => fuzzySearchResults.find(x => x.item === entity));
|
||||||
return filteredData;
|
return filteredData;
|
||||||
@ -172,7 +170,10 @@ export class FilterHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const fuzzySearchResults = fuzzySearchPersonas(data, term);
|
const fuzzySearchResults = fuzzySearchPersonas(data, term);
|
||||||
return data.filter(entity => fuzzySearchResults.includes(entity));
|
this.cacheScores(FILTER_TYPES.PERSONA_SEARCH, new Map(fuzzySearchResults.map(i => [i.item.key, i.score])));
|
||||||
|
|
||||||
|
const filteredData = data.filter(name => fuzzySearchResults.find(x => x.item.key === name));
|
||||||
|
return filteredData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -362,7 +363,7 @@ export class FilterHelper {
|
|||||||
typeScores.set(uid, score);
|
typeScores.set(uid, score);
|
||||||
}
|
}
|
||||||
this.scoreCache.set(type, typeScores);
|
this.scoreCache.set(type, typeScores);
|
||||||
console.debug('scores chached', type, typeScores);
|
console.debug('search scores chached', type, typeScores);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -635,7 +635,9 @@ export function initPersonas() {
|
|||||||
$('#personas_restore').on('click', () => $('#personas_restore_input').trigger('click'));
|
$('#personas_restore').on('click', () => $('#personas_restore_input').trigger('click'));
|
||||||
$('#personas_restore_input').on('change', onPersonasRestoreInput);
|
$('#personas_restore_input').on('change', onPersonasRestoreInput);
|
||||||
$('#persona_sort_order').val(power_user.persona_sort_order).on('input', function () {
|
$('#persona_sort_order').val(power_user.persona_sort_order).on('input', function () {
|
||||||
power_user.persona_sort_order = String($(this).val());
|
const value = String($(this).val());
|
||||||
|
// Save sort order, but do not save search sorting, as this is a temporary sorting option
|
||||||
|
if (value !== 'search') power_user.persona_sort_order = value;
|
||||||
getUserAvatars(true, user_avatar);
|
getUserAvatars(true, user_avatar);
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
});
|
});
|
||||||
|
@ -1912,8 +1912,14 @@ export function fuzzySearchWorldInfo(data, searchValue) {
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fuzzy search persona entries by a search term
|
||||||
|
* @param {*[]} data - persona data array
|
||||||
|
* @param {string} searchValue - The search term
|
||||||
|
* @returns {{item?: *, refIndex: number, score: number}[]} Results as items with their score
|
||||||
|
*/
|
||||||
export function fuzzySearchPersonas(data, searchValue) {
|
export function fuzzySearchPersonas(data, searchValue) {
|
||||||
data = data.map(x => ({ key: x, description: power_user.persona_descriptions[x]?.description ?? '', name: power_user.personas[x] ?? '' }));
|
data = data.map(x => ({ key: x, name: power_user.personas[x] ?? '', description: power_user.persona_descriptions[x]?.description ?? '' }));
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const fuse = new Fuse(data, {
|
const fuse = new Fuse(data, {
|
||||||
keys: [
|
keys: [
|
||||||
@ -1927,7 +1933,7 @@ export function fuzzySearchPersonas(data, searchValue) {
|
|||||||
|
|
||||||
const results = fuse.search(searchValue);
|
const results = fuse.search(searchValue);
|
||||||
console.debug('Personas fuzzy search results for ' + searchValue, results);
|
console.debug('Personas fuzzy search results for ' + searchValue, results);
|
||||||
return results.map(x => x.item?.key);
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fuzzySearchTags(searchValue) {
|
export function fuzzySearchTags(searchValue) {
|
||||||
|
@ -681,7 +681,7 @@ function sortEntries(data) {
|
|||||||
if (!data.length) return data;
|
if (!data.length) return data;
|
||||||
|
|
||||||
// If we have a search term for WI, we are sorting by weighting scores
|
// If we have a search term for WI, we are sorting by weighting scores
|
||||||
if ('search') {
|
if (sortRule === 'search') {
|
||||||
data.sort((a, b) => {
|
data.sort((a, b) => {
|
||||||
const aScore = worldInfoFilter.getScore(FILTER_TYPES.WORLD_INFO_SEARCH, a.uid);
|
const aScore = worldInfoFilter.getScore(FILTER_TYPES.WORLD_INFO_SEARCH, a.uid);
|
||||||
const bScore = worldInfoFilter.getScore(FILTER_TYPES.WORLD_INFO_SEARCH, b.uid);
|
const bScore = worldInfoFilter.getScore(FILTER_TYPES.WORLD_INFO_SEARCH, b.uid);
|
||||||
@ -767,7 +767,7 @@ function displayWorldEntries(name, data, navigation = navigation_option.none) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Before printing the WI, we check if we should enable/disable search sorting
|
// Before printing the WI, we check if we should enable/disable search sorting
|
||||||
verifySearchSortRule();
|
verifyWorldInfoSearchSortRule();
|
||||||
|
|
||||||
function getDataArray(callback) {
|
function getDataArray(callback) {
|
||||||
// Convert the data.entries object into an array
|
// Convert the data.entries object into an array
|
||||||
@ -1011,13 +1011,13 @@ const originalDataKeyMap = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/** Checks the state of the current search, and adds/removes the search sorting option accordingly */
|
/** Checks the state of the current search, and adds/removes the search sorting option accordingly */
|
||||||
function verifySearchSortRule() {
|
function verifyWorldInfoSearchSortRule() {
|
||||||
const searchTerm = worldInfoFilter.getFilterData(FILTER_TYPES.WORLD_INFO_SEARCH);
|
const searchTerm = worldInfoFilter.getFilterData(FILTER_TYPES.WORLD_INFO_SEARCH);
|
||||||
const searchOption = $('#world_info_sort_order option[data-rule="search"]');
|
const searchOption = $('#world_info_sort_order option[data-rule="search"]');
|
||||||
const selector = $('#world_info_sort_order');
|
const selector = $('#world_info_sort_order');
|
||||||
const isHidden = searchOption.attr('hidden') !== undefined;
|
const isHidden = searchOption.attr('hidden') !== undefined;
|
||||||
|
|
||||||
// If we have a search term for WI, we are displaying the sorting option for it
|
// If we have a search term, we are displaying the sorting option for it
|
||||||
if (searchTerm && isHidden) {
|
if (searchTerm && isHidden) {
|
||||||
searchOption.removeAttr('hidden');
|
searchOption.removeAttr('hidden');
|
||||||
selector.val(searchOption.attr('value') || '0');
|
selector.val(searchOption.attr('value') || '0');
|
||||||
@ -3088,9 +3088,7 @@ jQuery(() => {
|
|||||||
$('#world_info_sort_order').on('change', function () {
|
$('#world_info_sort_order').on('change', function () {
|
||||||
const value = String($(this).find(':selected').val());
|
const value = String($(this).find(':selected').val());
|
||||||
// Save sort order, but do not save search sorting, as this is a temporary sorting option
|
// Save sort order, but do not save search sorting, as this is a temporary sorting option
|
||||||
if (value !== 'search') {
|
if (value !== 'search') localStorage.setItem(SORT_ORDER_KEY, value);
|
||||||
localStorage.setItem(SORT_ORDER_KEY, value);
|
|
||||||
}
|
|
||||||
updateEditor(navigation_option.none);
|
updateEditor(navigation_option.none);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user