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>
<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">
<option value="search" data-i18n="Search" hidden>Search</option>
<option value="asc">A-Z</option>
<option value="desc">Z-A</option>
</select>

View File

@ -5914,17 +5914,16 @@ export async function getUserAvatars(doRender = true, openPageAt = '') {
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) {
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 listId = '#user_avatar_block';
const perPage = Number(localStorage.getItem(storageKey)) || 5;
@ -5978,6 +5977,50 @@ function highlightSelectedAvatar() {
$(`#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.
* @param {string} name Avatar file name
@ -8698,7 +8741,7 @@ jQuery(async function () {
personasFilter.setFilterData(FILTER_TYPES.PERSONA_SEARCH, searchQuery);
});
$('#persona_search_bar').on('input', function () {
const searchQuery = String($(this).val()).toLowerCase();
const searchQuery = String($(this).val());
debouncedPersonaSearch(searchQuery);
});

View File

@ -151,9 +151,7 @@ export class FilterHelper {
}
const fuzzySearchResults = fuzzySearchWorldInfo(data, term);
var wiScoreMap = new Map(fuzzySearchResults.map(i => [i.item?.uid, i.score]));
this.cacheScores(FILTER_TYPES.WORLD_INFO_SEARCH, wiScoreMap);
this.cacheScores(FILTER_TYPES.WORLD_INFO_SEARCH, new Map(fuzzySearchResults.map(i => [i.item?.uid, i.score])));
const filteredData = data.filter(entity => fuzzySearchResults.find(x => x.item === entity));
return filteredData;
@ -172,7 +170,10 @@ export class FilterHelper {
}
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);
}
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_input').on('change', onPersonasRestoreInput);
$('#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);
saveSettingsDebounced();
});

View File

@ -1912,8 +1912,14 @@ export function fuzzySearchWorldInfo(data, searchValue) {
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) {
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
const fuse = new Fuse(data, {
keys: [
@ -1927,7 +1933,7 @@ export function fuzzySearchPersonas(data, searchValue) {
const results = fuse.search(searchValue);
console.debug('Personas fuzzy search results for ' + searchValue, results);
return results.map(x => x.item?.key);
return results;
}
export function fuzzySearchTags(searchValue) {

View File

@ -681,7 +681,7 @@ function sortEntries(data) {
if (!data.length) return data;
// If we have a search term for WI, we are sorting by weighting scores
if ('search') {
if (sortRule === 'search') {
data.sort((a, b) => {
const aScore = worldInfoFilter.getScore(FILTER_TYPES.WORLD_INFO_SEARCH, a.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
verifySearchSortRule();
verifyWorldInfoSearchSortRule();
function getDataArray(callback) {
// 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 */
function verifySearchSortRule() {
function verifyWorldInfoSearchSortRule() {
const searchTerm = worldInfoFilter.getFilterData(FILTER_TYPES.WORLD_INFO_SEARCH);
const searchOption = $('#world_info_sort_order option[data-rule="search"]');
const selector = $('#world_info_sort_order');
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) {
searchOption.removeAttr('hidden');
selector.val(searchOption.attr('value') || '0');
@ -3088,9 +3088,7 @@ jQuery(() => {
$('#world_info_sort_order').on('change', function () {
const value = String($(this).find(':selected').val());
// Save sort order, but do not save search sorting, as this is a temporary sorting option
if (value !== 'search') {
localStorage.setItem(SORT_ORDER_KEY, value);
}
if (value !== 'search') localStorage.setItem(SORT_ORDER_KEY, value);
updateEditor(navigation_option.none);
});