[Feature Request] Filter via Tags on Group Chat's "Add Members" Search Box #388

This commit is contained in:
Cohee
2023-06-28 18:26:23 +03:00
parent fca732c933
commit d0ab763d2e
5 changed files with 85 additions and 57 deletions

View File

@ -2659,7 +2659,9 @@
<div name="Unadded Char List" class="flex-container flexFlowColumn overflowYAuto flex1"> <div name="Unadded Char List" class="flex-container flexFlowColumn overflowYAuto flex1">
<div id="rm_group_add_members_header"> <div id="rm_group_add_members_header">
<input id="rm_group_filter" class="text_pole margin0" type="search" placeholder="Filter..." maxlength="100" /> <input id="rm_group_filter" class="text_pole margin0" type="search" placeholder="Filter..." maxlength="100" />
<div id="group_fav_filter" class="menu_button fa-solid fa-ranking-star margin0" title="Show only favorites"></div> </div>
<div class="rm_tag_controls">
<div class="tags rm_tag_filter"></div>
</div> </div>
<div id="rm_group_add_members" class="overflowYAuto flex-container"></div> <div id="rm_group_add_members" class="overflowYAuto flex-container"></div>
</div> </div>
@ -2695,7 +2697,7 @@
</select> </select>
</form> </form>
<div class="rm_tag_controls"> <div class="rm_tag_controls">
<div id="rm_tag_filter" class="tags"></div> <div class="tags rm_tag_filter"></div>
</div> </div>
</div> </div>
<div id="rm_print_characters_block"></div> <div id="rm_print_characters_block"></div>
@ -3265,7 +3267,11 @@
<div class="avatar"> <div class="avatar">
<img alt="Avatar" src="" /> <img alt="Avatar" src="" />
</div> </div>
<div class="group_member_name">
<div class="ch_name"></div> <div class="ch_name"></div>
<div class="tags tags_inline"></div>
</div>
<input class="ch_fav" value="" hidden />
<div class="group_member_icon"> <div class="group_member_icon">
<div title="Temporarily disable automatic replies from this character" data-action="disable" class="right_menu_button fa-solid fa-lg fa-comment-slash"></div> <div title="Temporarily disable automatic replies from this character" data-action="disable" class="right_menu_button fa-solid fa-lg fa-comment-slash"></div>
<div title="Enable automatic replies from this character" data-action="enable" class="right_menu_button fa-solid fa-lg fa-comment-slash"></div> <div title="Enable automatic replies from this character" data-action="enable" class="right_menu_button fa-solid fa-lg fa-comment-slash"></div>

View File

@ -142,11 +142,12 @@ import {
tag_map, tag_map,
tags, tags,
loadTagsSettings, loadTagsSettings,
printTags, printTagFilters,
getTagsList, getTagsList,
appendTagToList, appendTagToList,
createTagMapFromList, createTagMapFromList,
renameTagKey, renameTagKey,
tag_filter_types,
} from "./scripts/tags.js"; } from "./scripts/tags.js";
import { import {
SECRET_KEYS, SECRET_KEYS,
@ -832,7 +833,8 @@ async function printCharacters() {
$("#rm_print_characters_block").append(template); $("#rm_print_characters_block").append(template);
}); });
printTags(); printTagFilters(tag_filter_types.character);
printTagFilters(tag_filter_types.group_member);
printGroups(); printGroups();
sortCharactersList(); sortCharactersList();
favsToHotswap(); favsToHotswap();

View File

@ -974,12 +974,19 @@ function select_group_chats(groupId, skipAnimation) {
? getThumbnailUrl('avatar', character.avatar) ? getThumbnailUrl('avatar', character.avatar)
: default_avatar; : default_avatar;
const template = $("#group_member_template .group_member").clone(); const template = $("#group_member_template .group_member").clone();
const isFav = character.fav || character.fav == 'true';
template.data("id", character.avatar); template.data("id", character.avatar);
template.find(".avatar img").attr("src", avatar); template.find(".avatar img").attr("src", avatar);
template.find(".avatar img").attr("title", character.avatar); template.find(".avatar img").attr("title", character.avatar);
template.find(".ch_name").text(character.name); template.find(".ch_name").text(character.name);
template.attr("chid", characters.indexOf(character)); template.attr("chid", characters.indexOf(character));
template.toggleClass('is_fav', character.fav || character.fav == 'true'); template.find('.ch_fav').val(isFav);
template.toggleClass('is_fav', isFav);
// Display inline tags
const tags = getTagsList(character.avatar);
const tagsElement = template.find('.tags');
tags.forEach(tag => appendTagToList(tagsElement, tag, {}));
if (!group) { if (!group) {
template.find('[data-action="speak"]').hide(); template.find('[data-action="speak"]').hide();
@ -999,7 +1006,6 @@ function select_group_chats(groupId, skipAnimation) {
} }
sortGroupMembers("#rm_group_add_members .group_member"); sortGroupMembers("#rm_group_add_members .group_member");
filterMembersByFavorites(false);
const groupHasMembers = !!$("#rm_group_members").children().length; const groupHasMembers = !!$("#rm_group_members").children().length;
$("#rm_group_submit").prop("disabled", !groupHasMembers); $("#rm_group_submit").prop("disabled", !groupHasMembers);
@ -1278,24 +1284,6 @@ async function createGroup() {
} }
} }
function toggleFilterByFavorites() {
filterMembersByFavorites(!fav_filter_on);
}
function filterMembersByFavorites(value) {
fav_filter_on = value;
$('#group_fav_filter').toggleClass('fav_on', fav_filter_on);
if (!fav_filter_on) {
$("#rm_group_add_members .group_member").removeClass('hiddenByFav');
} else {
$("#rm_group_add_members .group_member").each(function () {
const isValidSearch = $(this).hasClass("is_fav");
$(this).toggleClass('hiddenByFav', !isValidSearch);
});
}
}
export async function createNewGroupChat(groupId) { export async function createNewGroupChat(groupId) {
const group = groups.find(x => x.id === groupId); const group = groups.find(x => x.id === groupId);
@ -1491,7 +1479,6 @@ function stopAutoModeGeneration() {
jQuery(() => { jQuery(() => {
$(document).on("click", ".group_select", selectGroup); $(document).on("click", ".group_select", selectGroup);
$("#rm_group_filter").on("input", filterGroupMembers); $("#rm_group_filter").on("input", filterGroupMembers);
$("#group_fav_filter").on("click", toggleFilterByFavorites);
$("#rm_group_submit").on("click", createGroup); $("#rm_group_submit").on("click", createGroup);
$("#rm_group_scenario").on("click", setScenarioOverride); $("#rm_group_scenario").on("click", setScenarioOverride);
$("#rm_group_automode").on("input", function () { $("#rm_group_automode").on("input", function () {

View File

@ -13,7 +13,7 @@ export {
tags, tags,
tag_map, tag_map,
loadTagsSettings, loadTagsSettings,
printTags, printTagFilters,
isElementTagged, isElementTagged,
getTagsList, getTagsList,
appendTagToList, appendTagToList,
@ -24,12 +24,28 @@ export {
const random_id = () => Math.round(Date.now() * Math.random()).toString(); const random_id = () => Math.round(Date.now() * Math.random()).toString();
const TAG_LOGIC_AND = true; // switch to false to use OR logic for combining tags const TAG_LOGIC_AND = true; // switch to false to use OR logic for combining tags
const CHARACTER_SELECTOR = '#rm_print_characters_block > div'; const CHARACTER_SELECTOR = '#rm_print_characters_block > div';
const GROUP_MEMBER_SELECTOR = '#rm_group_add_members > div';
const CHARACTER_FILTER_SELECTOR = '#rm_characters_block .rm_tag_filter';
const GROUP_FILTER_SELECTOR = '#rm_group_chats_block .rm_tag_filter';
function getCharacterSelector(listSelector) {
if ($(listSelector).is(GROUP_FILTER_SELECTOR)) {
return GROUP_MEMBER_SELECTOR;
}
return CHARACTER_SELECTOR;
}
export const tag_filter_types = {
character: 0,
group_member: 1,
};
const ACTIONABLE_TAGS = { const ACTIONABLE_TAGS = {
FAV: { id: 1, name: 'Show only favorites', color: 'rgba(255, 255, 0, 0.5)', action: applyFavFilter, icon: 'fa-solid fa-star' }, FAV: { id: 1, name: 'Show only favorites', color: 'rgba(255, 255, 0, 0.5)', action: applyFavFilter, icon: 'fa-solid fa-star', class: 'filterByFavorites' },
GROUP: { id: 0, name: 'Show only groups', color: 'rgba(100, 100, 100, 0.5)', action: filterByGroups, icon: 'fa-solid fa-users' }, GROUP: { id: 0, name: 'Show only groups', color: 'rgba(100, 100, 100, 0.5)', action: filterByGroups, icon: 'fa-solid fa-users', class: 'filterByGroups' },
HINT: { id: 3, name: 'Show Tag List', color: 'rgba(150, 100, 100, 0.5)', action: onTagListHintClick, icon: 'fa-solid fa-tags' }, HINT: { id: 3, name: 'Show Tag List', color: 'rgba(150, 100, 100, 0.5)', action: onTagListHintClick, icon: 'fa-solid fa-tags', class: 'showTagList' },
} }
const InListActionable = { const InListActionable = {
@ -48,14 +64,14 @@ const DEFAULT_TAGS = [
let tags = []; let tags = [];
let tag_map = {}; let tag_map = {};
function applyFavFilter() { function applyFavFilter(characterSelector) {
const isSelected = $(this).hasClass('selected'); const isSelected = $(this).hasClass('selected');
const displayFavoritesOnly = !isSelected; const displayFavoritesOnly = !isSelected;
$(this).toggleClass('selected', displayFavoritesOnly); $(this).toggleClass('selected', displayFavoritesOnly);
$(CHARACTER_SELECTOR).removeClass('hiddenByFav'); $(characterSelector).removeClass('hiddenByFav');
$(CHARACTER_SELECTOR).each(function () { $(characterSelector).each(function () {
if (displayFavoritesOnly) { if (displayFavoritesOnly) {
if ($(this).find(".ch_fav").length !== 0) { if ($(this).find(".ch_fav").length !== 0) {
const shouldBeDisplayed = $(this).find(".ch_fav").val().toLowerCase().includes(true); const shouldBeDisplayed = $(this).find(".ch_fav").val().toLowerCase().includes(true);
@ -67,13 +83,13 @@ function applyFavFilter() {
updateVisibleDivs('#rm_print_characters_block', true); updateVisibleDivs('#rm_print_characters_block', true);
} }
function filterByGroups() { function filterByGroups(characterSelector) {
const isSelected = $(this).hasClass('selected'); const isSelected = $(this).hasClass('selected');
const displayGroupsOnly = !isSelected; const displayGroupsOnly = !isSelected;
$(this).toggleClass('selected', displayGroupsOnly); $(this).toggleClass('selected', displayGroupsOnly);
$(CHARACTER_SELECTOR).removeClass('hiddenByGroup'); $(characterSelector).removeClass('hiddenByGroup');
$(CHARACTER_SELECTOR).each((_, element) => { $(characterSelector).each((_, element) => {
$(element).toggleClass('hiddenByGroup', displayGroupsOnly && !$(element).hasClass('group_select')); $(element).toggleClass('hiddenByGroup', displayGroupsOnly && !$(element).hasClass('group_select'));
}); });
updateVisibleDivs('#rm_print_characters_block', true); updateVisibleDivs('#rm_print_characters_block', true);
@ -195,7 +211,8 @@ function selectTag(event, ui, listSelector) {
appendTagToList(getInlineListSelector(), tag, { removable: false }); appendTagToList(getInlineListSelector(), tag, { removable: false });
addTagToMap(tag.id); addTagToMap(tag.id);
saveSettingsDebounced(); saveSettingsDebounced();
printTags(); printTagFilters(tag_filter_types.character);
printTagFilters(tag_filter_types.group_member);
// need to return false to keep the input clear // need to return false to keep the input clear
return false; return false;
@ -216,6 +233,8 @@ function appendTagToList(listElement, tag, { removable, selectable, action }) {
return; return;
} }
const characterSelector = getCharacterSelector($(listElement));
let tagElement = $('#tag_template .tag').clone(); let tagElement = $('#tag_template .tag').clone();
tagElement.attr('id', tag.id); tagElement.attr('id', tag.id);
@ -226,16 +245,20 @@ function appendTagToList(listElement, tag, { removable, selectable, action }) {
const removeButton = tagElement.find(".tag_remove"); const removeButton = tagElement.find(".tag_remove");
removable ? removeButton.show() : removeButton.hide(); removable ? removeButton.show() : removeButton.hide();
if (tag.class) {
tagElement.addClass(tag.class);
}
if (tag.icon) { if (tag.icon) {
tagElement.find('.tag_name').text('').attr('title', tag.name).addClass(tag.icon); tagElement.find('.tag_name').text('').attr('title', tag.name).addClass(tag.icon);
} }
if (selectable) { if (selectable) {
tagElement.on('click', () => onTagFilterClick.bind(tagElement)(listElement)); tagElement.on('click', () => onTagFilterClick.bind(tagElement)(listElement, characterSelector));
} }
if (action) { if (action) {
tagElement.on('click', () => action.bind(tagElement)()); tagElement.on('click', () => action.bind(tagElement)(characterSelector));
tagElement.addClass('actionable'); tagElement.addClass('actionable');
} }
if (action && tag.id === 2) { if (action && tag.id === 2) {
@ -245,7 +268,7 @@ function appendTagToList(listElement, tag, { removable, selectable, action }) {
$(listElement).append(tagElement); $(listElement).append(tagElement);
} }
function onTagFilterClick(listElement) { function onTagFilterClick(listElement, characterSelector) {
if ($(this).hasClass('selected')) { if ($(this).hasClass('selected')) {
$(this).removeClass('selected'); $(this).removeClass('selected');
$(this).addClass('excluded'); $(this).addClass('excluded');
@ -259,7 +282,7 @@ function onTagFilterClick(listElement) {
const tagIds = [...($(listElement).find(".tag.selected:not(.actionable)").map((_, el) => $(el).attr("id")))]; const tagIds = [...($(listElement).find(".tag.selected:not(.actionable)").map((_, el) => $(el).attr("id")))];
const excludedTagIds = [...($(listElement).find(".tag.excluded:not(.actionable)").map((_, el) => $(el).attr("id")))]; const excludedTagIds = [...($(listElement).find(".tag.excluded:not(.actionable)").map((_, el) => $(el).attr("id")))];
$(CHARACTER_SELECTOR).each((_, element) => applyFilterToElement(tagIds, excludedTagIds, element)); $(characterSelector).each((_, element) => applyFilterToElement(tagIds, excludedTagIds, element));
updateVisibleDivs('#rm_print_characters_block', true); updateVisibleDivs('#rm_print_characters_block', true);
} }
@ -282,7 +305,7 @@ function applyFilterToElement(tagIds, excludedTagIds, element) {
function isElementTagged(element, tagId) { function isElementTagged(element, tagId) {
const isGroup = $(element).hasClass('group_select'); const isGroup = $(element).hasClass('group_select');
const isCharacter = $(element).hasClass('character_select'); const isCharacter = $(element).hasClass('character_select') || $(element).hasClass('group_member');
const idAttr = isGroup ? 'grid' : 'chid'; const idAttr = isGroup ? 'grid' : 'chid';
const elementId = $(element).attr(idAttr); const elementId = $(element).attr(idAttr);
const lookupValue = isCharacter ? characters[elementId].avatar : elementId; const lookupValue = isCharacter ? characters[elementId].avatar : elementId;
@ -290,13 +313,13 @@ function isElementTagged(element, tagId) {
return isTagged; return isTagged;
} }
function clearTagsFilter() { function clearTagsFilter(characterSelector) {
$('#rm_tag_filter .tag').removeClass('selected'); $('.rm_tag_filter .tag').removeClass('selected');
$(CHARACTER_SELECTOR).removeClass('hiddenByTag'); $(characterSelector).removeClass('hiddenByTag');
} }
function printTags() { function printTagFilters(type = tag_filter_types.character) {
const FILTER_SELECTOR = '#rm_tag_filter'; const FILTER_SELECTOR = type === tag_filter_types.character ? CHARACTER_FILTER_SELECTOR : GROUP_FILTER_SELECTOR;
const selectedTagIds = [...($(FILTER_SELECTOR).find(".tag.selected").map((_, el) => $(el).attr("id")))]; const selectedTagIds = [...($(FILTER_SELECTOR).find(".tag.selected").map((_, el) => $(el).attr("id")))];
$(FILTER_SELECTOR).empty(); $(FILTER_SELECTOR).empty();
const characterTagIds = Object.values(tag_map).flat(); const characterTagIds = Object.values(tag_map).flat();
@ -330,7 +353,8 @@ function onTagRemoveClick(event) {
removeTagFromMap(tagId); removeTagFromMap(tagId);
$(`${getInlineListSelector()} .tag[id="${tagId}"]`).remove(); $(`${getInlineListSelector()} .tag[id="${tagId}"]`).remove();
printTags(); printTagFilters(tag_filter_types.character);
printTagFilters(tag_filter_types.group_member);
saveSettingsDebounced(); saveSettingsDebounced();
} }
@ -350,6 +374,8 @@ function onCharacterCreateClick() {
function onGroupCreateClick() { function onGroupCreateClick() {
$("#groupTagList").empty(); $("#groupTagList").empty();
printTagFilters(tag_filter_types.character);
printTagFilters(tag_filter_types.group_member);
} }
export function applyTagsOnCharacterSelect() { export function applyTagsOnCharacterSelect() {
@ -371,6 +397,8 @@ function applyTagsOnGroupSelect() {
const tags = getTagsList(key); const tags = getTagsList(key);
$("#groupTagList").empty(); $("#groupTagList").empty();
printTagFilters(tag_filter_types.character);
printTagFilters(tag_filter_types.group_member);
for (const tag of tags) { for (const tag of tags) {
appendTagToList("#groupTagList", tag, { removable: true }); appendTagToList("#groupTagList", tag, { removable: true });

View File

@ -2433,7 +2433,7 @@ input[type="range"]::-webkit-slider-thumb {
.mes_buttons .mes_edit, .mes_buttons .mes_edit,
.mes_buttons .mes_bookmark, .mes_buttons .mes_bookmark,
.extraMesButtonsHint, .extraMesButtonsHint,
#tagListHint, .tagListHint,
.extraMesButtons div { .extraMesButtons div {
cursor: pointer; cursor: pointer;
transition: 0.3s ease-in-out; transition: 0.3s ease-in-out;
@ -2444,7 +2444,7 @@ input[type="range"]::-webkit-slider-thumb {
.mes_buttons .mes_edit:hover, .mes_buttons .mes_edit:hover,
.mes_buttons .mes_bookmark:hover, .mes_buttons .mes_bookmark:hover,
.extraMesButtonsHint:hover, .extraMesButtonsHint:hover,
#tagListHint:hover, .tagListHint:hover,
.extraMesButtons div:hover { .extraMesButtons div:hover {
opacity: 1; opacity: 1;
} }
@ -2838,10 +2838,13 @@ h5 {
text-shadow: none !important; text-shadow: none !important;
} }
#rm_tag_filter .tag:not(.actionable) { .rm_tag_filter .tag:not(.actionable) {
display: none; display: none;
} }
#rm_group_chats_block .tag.filterByGroups {
display: none;
}
.tag.actionable { .tag.actionable {
border-radius: 50%; border-radius: 50%;
@ -2855,7 +2858,7 @@ h5 {
align-items: center; align-items: center;
} }
#tagListHint { .tagListHint {
align-self: center; align-self: center;
display: flex; display: flex;
margin-right: 10px; margin-right: 10px;
@ -2927,7 +2930,7 @@ h5 {
margin: 5px; margin: 5px;
} }
#rm_tag_filter .tag { .rm_tag_filter .tag {
cursor: pointer; cursor: pointer;
opacity: 0.6; opacity: 0.6;
filter: brightness(0.8); filter: brightness(0.8);
@ -3151,15 +3154,17 @@ body .ui-widget-content li:hover {
border-radius: 10px; border-radius: 10px;
} }
.group_member .ch_name { .group_member .group_member_name {
flex-grow: 1; flex-grow: 1;
margin-left: 10px; margin-left: 10px;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
width: calc(100% - 110px); width: calc(100% - 110px);
display: flex; display: flex;
align-items: center;
gap: 5px; gap: 5px;
height: 100%;
flex-direction: column;
justify-content: center;
} }
.group_member_icon .flex-container { .group_member_icon .flex-container {