Scored search sorting for personas

This commit is contained in:
Wolfsblvt
2024-04-30 02:27:44 +02:00
parent a850352eab
commit d1cdd60883
6 changed files with 74 additions and 23 deletions

View File

@ -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>

View File

@ -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);
}); });

View File

@ -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);
} }
/** /**

View File

@ -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();
}); });

View File

@ -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) {

View File

@ -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);
}); });