Scored search sorting for personas
This commit is contained in:
parent
a850352eab
commit
d1cdd60883
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue