mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-03-09 00:17:47 +01:00
Tag Folders: hidden/closed folders
- Implement folder types: Open, Closed, None - Closed folders hide characters from most places - "character(s)" singular wording on entity list - small refactoring for that code
This commit is contained in:
parent
c0e112d195
commit
e578d3dbb6
@ -158,7 +158,7 @@
|
|||||||
border: 1px solid red;
|
border: 1px solid red;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tag.excluded:after {
|
.tag.excluded::after {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
@ -177,22 +177,21 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tag_as_folder {
|
.tag_as_folder {
|
||||||
filter: brightness(25%) saturate(0.25);
|
|
||||||
}
|
|
||||||
.tag_as_folder.yes_folder {
|
|
||||||
filter: brightness(75%) saturate(0.6);
|
filter: brightness(75%) saturate(0.6);
|
||||||
}
|
}
|
||||||
.tag_as_folder:hover {
|
.tag_as_folder:hover {
|
||||||
filter: brightness(150%) saturate(0.6);
|
filter: brightness(150%) saturate(0.6) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tag_as_folder.yes_folder:after {
|
.tag_as_folder.no_folder {
|
||||||
|
filter: brightness(25%) saturate(0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag_as_folder .tag_folder_indicator {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: calc(var(--mainFontSize) * -0.5);
|
top: calc(var(--mainFontSize) * -0.5);
|
||||||
right: calc(var(--mainFontSize) * -0.5);
|
right: calc(var(--mainFontSize) * -0.5);
|
||||||
content: "\2714";
|
|
||||||
font-size: calc(var(--mainFontSize) * 1);
|
font-size: calc(var(--mainFontSize) * 1);
|
||||||
color: green;
|
|
||||||
line-height: calc(var(--mainFontSize) * 1.3);
|
line-height: calc(var(--mainFontSize) * 1.3);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
text-shadow: 1px 1px 0px black,
|
text-shadow: 1px 1px 0px black,
|
||||||
@ -202,23 +201,7 @@
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tag_as_folder.no_folder:after {
|
.tag.indicator::after {
|
||||||
position: absolute;
|
|
||||||
top: calc(var(--mainFontSize) * -0.5);
|
|
||||||
right: calc(var(--mainFontSize) * -0.5);
|
|
||||||
content: "\2715";
|
|
||||||
font-size: calc(var(--mainFontSize) * 1);
|
|
||||||
color: red;
|
|
||||||
line-height: calc(var(--mainFontSize) * 1.3);
|
|
||||||
text-align: center;
|
|
||||||
text-shadow: 1px 1px 0px black,
|
|
||||||
-1px -1px 0px black,
|
|
||||||
-1px 1px 0px black,
|
|
||||||
1px -1px 0px black;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tag.indicator:after {
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: calc(var(--mainFontSize) * -0.5);
|
top: calc(var(--mainFontSize) * -0.5);
|
||||||
right: -2px;
|
right: -2px;
|
||||||
@ -239,7 +222,7 @@
|
|||||||
margin-left: calc(var(--mainFontSize) * 2);
|
margin-left: calc(var(--mainFontSize) * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rm_tag_bogus_drilldown .tag:not(:first-child):before {
|
.rm_tag_bogus_drilldown .tag:not(:first-child)::before {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: calc(var(--mainFontSize) * -2);
|
left: calc(var(--mainFontSize) * -2);
|
||||||
top: -1px;
|
top: -1px;
|
||||||
|
@ -4544,7 +4544,9 @@
|
|||||||
<div id="tag_view_template" class="template_element">
|
<div id="tag_view_template" class="template_element">
|
||||||
<div class="tag_view_item">
|
<div class="tag_view_item">
|
||||||
<div class="drag-handle" data-i18n="[title]Drag to reorder tag">☰</div>
|
<div class="drag-handle" data-i18n="[title]Drag to reorder tag">☰</div>
|
||||||
<div title="Tag as folder" class="tag_as_folder fa-solid fa-folder-open right_menu_button" data-i18n="[title]Use tag as folder"></div>
|
<div title="Tag as folder" class="tag_as_folder fa-solid fa-folder-open right_menu_button" data-i18n="[title]Use tag as folder">
|
||||||
|
<span class="tag_folder_indicator"></span>
|
||||||
|
</div>
|
||||||
<div class="tagColorPickerHolder"></div>
|
<div class="tagColorPickerHolder"></div>
|
||||||
<div class="tagColorPicker2Holder"></div>
|
<div class="tagColorPicker2Holder"></div>
|
||||||
<div class="tag_view_name" contenteditable="true"></div>
|
<div class="tag_view_name" contenteditable="true"></div>
|
||||||
@ -5011,7 +5013,7 @@
|
|||||||
<div class="ch_name"></div>
|
<div class="ch_name"></div>
|
||||||
<small class="group_select_unit" data="characters">group of</small>
|
<small class="group_select_unit" data="characters">group of</small>
|
||||||
<small class="character_version group_select_counter">5</small>
|
<small class="character_version group_select_counter">5</small>
|
||||||
<small class="group_select_unit" data="characters">characters</small>
|
<small class="group_select_unit character_unit_name" data="characters">characters</small>
|
||||||
</div>
|
</div>
|
||||||
<i class='group_fav_icon fa-solid fa-star'></i>
|
<i class='group_fav_icon fa-solid fa-star'></i>
|
||||||
<input class="ch_fav" value="" hidden />
|
<input class="ch_fav" value="" hidden />
|
||||||
@ -5023,13 +5025,13 @@
|
|||||||
<div id="bogus_folder_template" class="template_element">
|
<div id="bogus_folder_template" class="template_element">
|
||||||
<div class="bogus_folder_select flex-container wide100p alignitemsflexstart">
|
<div class="bogus_folder_select flex-container wide100p alignitemsflexstart">
|
||||||
<div class="avatar flex alignitemscenter textAlignCenter">
|
<div class="avatar flex alignitemscenter textAlignCenter">
|
||||||
<i class="bogus_folder_icon fa-solid fa-folder-open fa-xl"></i>
|
<i class="bogus_folder_icon fa-solid fa-xl"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-container wide100pLess70px character_select_container">
|
<div class="flex-container wide100pLess70px character_select_container">
|
||||||
<div class="wide100p character_name_block">
|
<div class="wide100p character_name_block">
|
||||||
<span class="ch_name"></span>
|
<span class="ch_name"></span>
|
||||||
<small class="character_version bogus_folder_counter"></small>
|
<small class="character_version bogus_folder_counter"></small>
|
||||||
<small class="bogus_folder_unit" data="characters">characters</small>
|
<small class="bogus_folder_unit character_unit_name" data="characters">characters</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="bogus_folder_avatars_block avatars_inline tags tags_inline"></div>
|
<div class="bogus_folder_avatars_block avatars_inline tags tags_inline"></div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -153,8 +153,10 @@ import {
|
|||||||
import { ModuleWorkerWrapper, doDailyExtensionUpdatesCheck, extension_settings, getContext, loadExtensionSettings, renderExtensionTemplate, runGenerationInterceptors, saveMetadataDebounced } from './scripts/extensions.js';
|
import { ModuleWorkerWrapper, doDailyExtensionUpdatesCheck, extension_settings, getContext, loadExtensionSettings, renderExtensionTemplate, runGenerationInterceptors, saveMetadataDebounced } from './scripts/extensions.js';
|
||||||
import { COMMENT_NAME_DEFAULT, executeSlashCommands, getSlashCommandsHelp, processChatSlashCommands, registerSlashCommand } from './scripts/slash-commands.js';
|
import { COMMENT_NAME_DEFAULT, executeSlashCommands, getSlashCommandsHelp, processChatSlashCommands, registerSlashCommand } from './scripts/slash-commands.js';
|
||||||
import {
|
import {
|
||||||
|
TAG_FOLDER_DEFAULT_TYPE,
|
||||||
tag_map,
|
tag_map,
|
||||||
tags,
|
tags,
|
||||||
|
filterByTagState,
|
||||||
loadTagsSettings,
|
loadTagsSettings,
|
||||||
printTagFilters,
|
printTagFilters,
|
||||||
getTagsList,
|
getTagsList,
|
||||||
@ -164,6 +166,7 @@ import {
|
|||||||
importTags,
|
importTags,
|
||||||
tag_filter_types,
|
tag_filter_types,
|
||||||
compareTagsForSort,
|
compareTagsForSort,
|
||||||
|
TAG_FOLDER_TYPES,
|
||||||
} from './scripts/tags.js';
|
} from './scripts/tags.js';
|
||||||
import {
|
import {
|
||||||
SECRET_KEYS,
|
SECRET_KEYS,
|
||||||
@ -273,6 +276,7 @@ export {
|
|||||||
isOdd,
|
isOdd,
|
||||||
countOccurrences,
|
countOccurrences,
|
||||||
chooseBogusFolder,
|
chooseBogusFolder,
|
||||||
|
isBogusFolder,
|
||||||
};
|
};
|
||||||
|
|
||||||
showLoader();
|
showLoader();
|
||||||
@ -1158,25 +1162,24 @@ export async function selectCharacterById(id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getTagBlock(item, entities) {
|
function getTagBlock(item, entities) {
|
||||||
let count = 0;
|
let count = entities.length;
|
||||||
let subEntities = [];
|
|
||||||
|
|
||||||
for (const entity of entities) {
|
const tagFolder = TAG_FOLDER_TYPES[item.folder_type];
|
||||||
if (entitiesFilter.isElementTagged(entity, item.id)) {
|
|
||||||
count++;
|
|
||||||
subEntities.push(entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const template = $('#bogus_folder_template .bogus_folder_select').clone();
|
const template = $('#bogus_folder_template .bogus_folder_select').clone();
|
||||||
|
template.addClass(tagFolder.class);
|
||||||
template.attr({ 'tagid': item.id, 'id': `BogusFolder${item.id}` });
|
template.attr({ 'tagid': item.id, 'id': `BogusFolder${item.id}` });
|
||||||
template.find('.avatar').css({ 'background-color': item.color, 'color': item.color2 }).attr('title', `[Folder] ${item.name}`);
|
template.find('.avatar').css({ 'background-color': item.color, 'color': item.color2 }).attr('title', `[Folder] ${item.name}`);
|
||||||
template.find('.ch_name').text(item.name).attr('title', `[Folder] ${item.name}`);;
|
template.find('.ch_name').text(item.name).attr('title', `[Folder] ${item.name}`);
|
||||||
template.find('.bogus_folder_counter').text(count);
|
template.find('.bogus_folder_counter').text(count);
|
||||||
|
template.find('.bogus_folder_icon').addClass(tagFolder.fa_icon);
|
||||||
|
if (count == 1) {
|
||||||
|
template.find('.character_unit_name').text('character');
|
||||||
|
}
|
||||||
|
|
||||||
// Fill inline character images
|
// Fill inline character images
|
||||||
const inlineAvatars = template.find('.bogus_folder_avatars_block');
|
const inlineAvatars = template.find('.bogus_folder_avatars_block');
|
||||||
for (const entitiy of subEntities) {
|
for (const entitiy of entities) {
|
||||||
const id = entitiy.id;
|
const id = entitiy.id;
|
||||||
|
|
||||||
// Populate the template
|
// Populate the template
|
||||||
@ -1314,7 +1317,7 @@ async function printCharacters(fullRefresh = false) {
|
|||||||
$(listId).append(getGroupBlock(i.item));
|
$(listId).append(getGroupBlock(i.item));
|
||||||
break;
|
break;
|
||||||
case 'tag':
|
case 'tag':
|
||||||
$(listId).append(getTagBlock(i.item, entities));
|
$(listId).append(getTagBlock(i.item, i.entities ?? entities));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1334,6 +1337,14 @@ async function printCharacters(fullRefresh = false) {
|
|||||||
favsToHotswap();
|
favsToHotswap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether a given tag is defined as a folder. Meaning it's neither undefined nor 'NONE'.
|
||||||
|
* @returns {boolean} If it's a tag folder
|
||||||
|
*/
|
||||||
|
function isBogusFolder(tag) {
|
||||||
|
return tag?.folder_type !== undefined && tag.folder_type !== TAG_FOLDER_DEFAULT_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether a user is currently in a bogus folder.
|
* Indicates whether a user is currently in a bogus folder.
|
||||||
* @returns {boolean} If currently viewing a folder
|
* @returns {boolean} If currently viewing a folder
|
||||||
@ -1341,7 +1352,7 @@ async function printCharacters(fullRefresh = false) {
|
|||||||
function isBogusFolderOpen() {
|
function isBogusFolderOpen() {
|
||||||
const anyIsFolder = entitiesFilter.getFilterData(FILTER_TYPES.TAG)?.selected
|
const anyIsFolder = entitiesFilter.getFilterData(FILTER_TYPES.TAG)?.selected
|
||||||
.map(tagId => tags.find(x => x.id === tagId))
|
.map(tagId => tags.find(x => x.id === tagId))
|
||||||
.some(x => !!x.is_folder);
|
.some(isBogusFolder);
|
||||||
|
|
||||||
return !!anyIsFolder;
|
return !!anyIsFolder;
|
||||||
}
|
}
|
||||||
@ -1356,33 +1367,33 @@ export function getEntitiesList({ doFilter } = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function tagToEntity(tag) {
|
function tagToEntity(tag) {
|
||||||
return { item: structuredClone(tag), id: tag.id, type: 'tag' };
|
return { item: structuredClone(tag), id: tag.id, type: 'tag', entities: [] };
|
||||||
}
|
}
|
||||||
|
|
||||||
let entities = [
|
let entities = [
|
||||||
...characters.map((item, index) => characterToEntity(item, index)),
|
...characters.map((item, index) => characterToEntity(item, index)),
|
||||||
...groups.map(item => groupToEntity(item)),
|
...groups.map(item => groupToEntity(item)),
|
||||||
...(power_user.bogus_folders ? tags.filter(x => x.is_folder).sort(compareTagsForSort).map(item => tagToEntity(item)) : []),
|
...(power_user.bogus_folders ? tags.filter(isBogusFolder).sort(compareTagsForSort).map(item => tagToEntity(item)) : []),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// First run filters, that will hide what should never be displayed
|
||||||
if (doFilter) {
|
if (doFilter) {
|
||||||
entities = entitiesFilter.applyFilters(entities);
|
entities = entitiesFilter.applyFilters(entities);
|
||||||
|
entities = filterByTagState(entities);
|
||||||
}
|
}
|
||||||
|
|
||||||
const filterData = structuredClone(entitiesFilter.getFilterData(FILTER_TYPES.TAG));
|
// Run over all entities between first and second filter to save some states
|
||||||
|
for(const entity of entities) {
|
||||||
entities = entities.filter(entity => {
|
// For folders, we remember the sub entities so they can be displayed later, even if they might be filtered
|
||||||
if (entity.type === 'tag') {
|
if (entity.type === 'tag') {
|
||||||
// Remove filtered tags/bogus folders
|
entity.entities = filterByTagState(entities, { subForEntity: entity });
|
||||||
if (filterData.selected.includes(entity.id) || filterData.excluded.includes(entity.id)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if tag is used in any other entities, removing 0 count folders
|
|
||||||
return entities.some(e => e.type !== 'tag' && entitiesFilter.isElementTagged(e, entity.id));
|
|
||||||
}
|
}
|
||||||
return true;
|
}
|
||||||
});
|
|
||||||
|
// Second run filters, hiding whatever should be filtered later
|
||||||
|
if (doFilter) {
|
||||||
|
entities = filterByTagState(entities, { globalDisplayFilters: true });
|
||||||
|
}
|
||||||
|
|
||||||
sortEntitiesList(entities);
|
sortEntitiesList(entities);
|
||||||
return entities;
|
return entities;
|
||||||
@ -8089,22 +8100,12 @@ function doTogglePanels() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function chooseBogusFolder(source, tagId, remove = false) {
|
function chooseBogusFolder(source, tagId, remove = false) {
|
||||||
// Take the filter as the base on what bogus is currently selected
|
|
||||||
const filterData = structuredClone(entitiesFilter.getFilterData(FILTER_TYPES.TAG));
|
|
||||||
|
|
||||||
if (!Array.isArray(filterData.selected)) {
|
|
||||||
filterData.selected = [];
|
|
||||||
filterData.excluded = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const filteredFolders = filterData.selected
|
|
||||||
.map(tagId => tags.find(x => x.id === tagId))
|
|
||||||
.filter(x => !!x.is_folder);
|
|
||||||
|
|
||||||
// If we are here via the 'back' action, we implicitly take the last filtered folder as one to remove
|
// If we are here via the 'back' action, we implicitly take the last filtered folder as one to remove
|
||||||
const isBack = tagId === 'back';
|
const isBack = tagId === 'back';
|
||||||
if (isBack) {
|
if (isBack) {
|
||||||
tagId = filteredFolders?.[filteredFolders.length - 1].id;
|
const drilldown = $(source).closest('#rm_characters_block').find('.rm_tag_bogus_drilldown');
|
||||||
|
const lastTag = drilldown.find('.tag:last').last();
|
||||||
|
tagId = lastTag.attr('id');
|
||||||
remove = true;
|
remove = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8293,7 +8294,7 @@ jQuery(async function () {
|
|||||||
|
|
||||||
$(document).on('click', '.bogus_folder_select', function () {
|
$(document).on('click', '.bogus_folder_select', function () {
|
||||||
const tagId = $(this).attr('tagid');
|
const tagId = $(this).attr('tagid');
|
||||||
console.log('Bogus folder clicked', tagId);
|
console.debug('Bogus folder clicked', tagId);
|
||||||
chooseBogusFolder($(this), tagId);
|
chooseBogusFolder($(this), tagId);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -544,6 +544,9 @@ export function getGroupBlock(group) {
|
|||||||
template.find('.ch_fav').val(group.fav);
|
template.find('.ch_fav').val(group.fav);
|
||||||
template.find('.group_select_counter').text(count);
|
template.find('.group_select_counter').text(count);
|
||||||
template.find('.group_select_block_list').append(namesList.join(''));
|
template.find('.group_select_block_list').append(namesList.join(''));
|
||||||
|
if (count == 1) {
|
||||||
|
template.find('.character_unit_name').text('character');
|
||||||
|
}
|
||||||
|
|
||||||
// Display inline tags
|
// Display inline tags
|
||||||
const tags = getTagsList(group.id);
|
const tags = getTagsList(group.id);
|
||||||
|
@ -8,6 +8,7 @@ import {
|
|||||||
entitiesFilter,
|
entitiesFilter,
|
||||||
printCharacters,
|
printCharacters,
|
||||||
chooseBogusFolder,
|
chooseBogusFolder,
|
||||||
|
isBogusFolder,
|
||||||
} from '../script.js';
|
} from '../script.js';
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
import { FILTER_TYPES, FilterHelper } from './filters.js';
|
import { FILTER_TYPES, FilterHelper } from './filters.js';
|
||||||
@ -17,8 +18,11 @@ import { download, onlyUnique, parseJsonFile, uuidv4, getSortableDelay } from '.
|
|||||||
import { power_user } from './power-user.js';
|
import { power_user } from './power-user.js';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
TAG_FOLDER_TYPES,
|
||||||
|
TAG_FOLDER_DEFAULT_TYPE,
|
||||||
tags,
|
tags,
|
||||||
tag_map,
|
tag_map,
|
||||||
|
filterByTagState,
|
||||||
loadTagsSettings,
|
loadTagsSettings,
|
||||||
printTagFilters,
|
printTagFilters,
|
||||||
getTagsList,
|
getTagsList,
|
||||||
@ -61,9 +65,85 @@ const DEFAULT_TAGS = [
|
|||||||
{ id: uuidv4(), name: 'AliChat', create_date: Date.now() },
|
{ id: uuidv4(), name: 'AliChat', create_date: Date.now() },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const TAG_FOLDER_TYPES = {
|
||||||
|
OPEN: { icon: '✔', class: 'folder_open', fa_icon: 'fa-folder-open', tooltip: 'Open Folder (Show all characters even if not selected)', color: 'green', size: '1' },
|
||||||
|
CLOSED: { icon: '👁', class: 'folder_closed', fa_icon: 'fa-eye-slash', tooltip: 'Closed Folder (Hide all characters unless selected)', color: 'lightgoldenrodyellow', size: '0.7' },
|
||||||
|
NONE: { icon: '✕', class: 'no_folder', tooltip: 'No Folder', color: 'red', size: '1' },
|
||||||
|
};
|
||||||
|
const TAG_FOLDER_DEFAULT_TYPE = 'NONE';
|
||||||
|
|
||||||
|
|
||||||
let tags = [];
|
let tags = [];
|
||||||
let tag_map = {};
|
let tag_map = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the basic filter for the current state of the tags and their selection on an entity list.
|
||||||
|
* @param {*} entities List of entities for display, consisting of tags, characters and groups.
|
||||||
|
*/
|
||||||
|
function filterByTagState(entities, { globalDisplayFilters = false, subForEntity = undefined } = {}) {
|
||||||
|
const filterData = structuredClone(entitiesFilter.getFilterData(FILTER_TYPES.TAG));
|
||||||
|
|
||||||
|
entities = entities.filter(entity => {
|
||||||
|
if (entity.type === 'tag') {
|
||||||
|
// Remove folders that are already filtered on
|
||||||
|
if (filterData.selected.includes(entity.id) || filterData.excluded.includes(entity.id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (globalDisplayFilters) {
|
||||||
|
// Prepare some data for caching and performance
|
||||||
|
const closedFolders = entities.filter(x => x.type === 'tag' && TAG_FOLDER_TYPES[x.item.folder_type] === TAG_FOLDER_TYPES.CLOSED);
|
||||||
|
|
||||||
|
entities = entities.filter(entity => {
|
||||||
|
// Hide entities that are in a closed folder, unless that one is opened
|
||||||
|
if (entity.type !== 'tag' && closedFolders.some(f => entitiesFilter.isElementTagged(entity, f.id) && !filterData.selected.includes(f.id))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide folders that have 0 visible sub entities after the first filtering round
|
||||||
|
if (entity.type === 'tag') {
|
||||||
|
return entity.entities.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subForEntity !== undefined && subForEntity.type === 'tag') {
|
||||||
|
entities = filterTagSubEntities(subForEntity.item, entities);
|
||||||
|
}
|
||||||
|
|
||||||
|
return entities;
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterTagSubEntities(tag, entities) {
|
||||||
|
const filterData = structuredClone(entitiesFilter.getFilterData(FILTER_TYPES.TAG));
|
||||||
|
|
||||||
|
const closedFolders = entities.filter(x => x.type === 'tag' && TAG_FOLDER_TYPES[x.item.folder_type] === TAG_FOLDER_TYPES.CLOSED);
|
||||||
|
|
||||||
|
entities = entities.filter(sub => {
|
||||||
|
// Filter out all tags and and all who isn't tagged for this item
|
||||||
|
if (sub.type === 'tag' || !entitiesFilter.isElementTagged(sub, tag.id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide entities that are in a closed folder, unless the closed folder is opened or we display a closed folder
|
||||||
|
if (sub.type !== 'tag' && TAG_FOLDER_TYPES[tag.folder_type] !== TAG_FOLDER_TYPES.CLOSED && closedFolders.some(f => entitiesFilter.isElementTagged(sub, f.id) && !filterData.selected.includes(f.id))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return entities;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies the favorite filter to the character list.
|
* Applies the favorite filter to the character list.
|
||||||
* @param {FilterHelper} filterHelper Instance of FilterHelper class.
|
* @param {FilterHelper} filterHelper Instance of FilterHelper class.
|
||||||
@ -282,7 +362,7 @@ function createNewTag(tagName) {
|
|||||||
const tag = {
|
const tag = {
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
name: tagName,
|
name: tagName,
|
||||||
is_folder: false,
|
folder_type: TAG_FOLDER_DEFAULT_TYPE,
|
||||||
sort_order: tags.length,
|
sort_order: tags.length,
|
||||||
color: '',
|
color: '',
|
||||||
color2: '',
|
color2: '',
|
||||||
@ -372,7 +452,7 @@ function onTagFilterClick(listElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update bogus folder if applicable
|
// Update bogus folder if applicable
|
||||||
if (existingTag?.is_folder) {
|
if (isBogusFolder(existingTag)) {
|
||||||
// Update bogus drilldown
|
// Update bogus drilldown
|
||||||
if ($(this).hasClass('selected')) {
|
if ($(this).hasClass('selected')) {
|
||||||
appendTagToList('.rm_tag_controls .rm_tag_bogus_drilldown', existingTag, { removable: true, selectable: false, isGeneralList: false });
|
appendTagToList('.rm_tag_controls .rm_tag_bogus_drilldown', existingTag, { removable: true, selectable: false, isGeneralList: false });
|
||||||
@ -760,7 +840,6 @@ function appendViewTagToList(list, tag, everything) {
|
|||||||
template.find('.tag_as_folder').hide();
|
template.find('.tag_as_folder').hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
template.find('.tag_as_folder').addClass(tag.is_folder == true ? 'yes_folder' : 'no_folder');
|
|
||||||
template.find('.tagColorPickerHolder').html(
|
template.find('.tagColorPickerHolder').html(
|
||||||
`<toolcool-color-picker id="${colorPickerId}" color="${tag.color}" class="tag-color"></toolcool-color-picker>`,
|
`<toolcool-color-picker id="${colorPickerId}" color="${tag.color}" class="tag-color"></toolcool-color-picker>`,
|
||||||
);
|
);
|
||||||
@ -786,6 +865,8 @@ function appendViewTagToList(list, tag, everything) {
|
|||||||
});
|
});
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
|
updateDrawTagFolder(template, tag);
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
$(colorPickerId).color = tag.color;
|
$(colorPickerId).color = tag.color;
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -793,12 +874,16 @@ function appendViewTagToList(list, tag, everything) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onTagAsFolderClick() {
|
function onTagAsFolderClick() {
|
||||||
const id = $(this).closest('.tag_view_item').attr('id');
|
const element = $(this).closest('.tag_view_item');
|
||||||
|
const id = element.attr('id');
|
||||||
const tag = tags.find(x => x.id === id);
|
const tag = tags.find(x => x.id === id);
|
||||||
|
|
||||||
// Toggle
|
// Cycle through folder types
|
||||||
tag.is_folder = tag.is_folder != true;
|
const types = Object.keys(TAG_FOLDER_TYPES);
|
||||||
$(`.tag_view_item[id="${id}"] .tag_as_folder`).toggleClass('yes_folder').toggleClass('no_folder');
|
let currentTypeIndex = types.indexOf(tag.folder_type);
|
||||||
|
tag.folder_type = types[(currentTypeIndex + 1) % types.length];
|
||||||
|
|
||||||
|
updateDrawTagFolder(element, tag);
|
||||||
|
|
||||||
// If folder display has changed, we have to redraw the character list, otherwise this folders state would not change
|
// If folder display has changed, we have to redraw the character list, otherwise this folders state would not change
|
||||||
printCharacters(true);
|
printCharacters(true);
|
||||||
@ -806,6 +891,23 @@ function onTagAsFolderClick() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateDrawTagFolder(element, tag) {
|
||||||
|
const tagFolder = TAG_FOLDER_TYPES[tag.folder_type] || TAG_FOLDER_TYPES[TAG_FOLDER_DEFAULT_TYPE];
|
||||||
|
const folderElement = element.find('.tag_as_folder');
|
||||||
|
|
||||||
|
// Update css class and remove all others
|
||||||
|
Object.keys(TAG_FOLDER_TYPES).forEach(x => {
|
||||||
|
folderElement.toggleClass(TAG_FOLDER_TYPES[x].class, TAG_FOLDER_TYPES[x] === tagFolder);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Draw/update css attributes for this class
|
||||||
|
folderElement.attr('title', tagFolder.tooltip);
|
||||||
|
const indicator = folderElement.find('.tag_folder_indicator');
|
||||||
|
indicator.text(tagFolder.icon);
|
||||||
|
indicator.css('color', tagFolder.color);
|
||||||
|
indicator.css('font-size', `calc(var(--mainFontSize) * ${tagFolder.size})`);
|
||||||
|
}
|
||||||
|
|
||||||
function onTagDeleteClick() {
|
function onTagDeleteClick() {
|
||||||
if (!confirm('Are you sure?')) {
|
if (!confirm('Are you sure?')) {
|
||||||
return;
|
return;
|
||||||
@ -859,7 +961,6 @@ function onTagColorize2(evt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onTagListHintClick() {
|
function onTagListHintClick() {
|
||||||
console.debug($(this));
|
|
||||||
$(this).toggleClass('selected');
|
$(this).toggleClass('selected');
|
||||||
$(this).siblings('.tag:not(.actionable)').toggle(100);
|
$(this).siblings('.tag:not(.actionable)').toggle(100);
|
||||||
$(this).siblings('.innerActionable').toggleClass('hidden');
|
$(this).siblings('.innerActionable').toggleClass('hidden');
|
||||||
@ -867,7 +968,7 @@ function onTagListHintClick() {
|
|||||||
power_user.show_tag_filters = $(this).hasClass('selected');
|
power_user.show_tag_filters = $(this).hasClass('selected');
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
|
|
||||||
console.log('show_tag_filters', power_user.show_tag_filters);
|
console.debug('show_tag_filters', power_user.show_tag_filters);
|
||||||
}
|
}
|
||||||
|
|
||||||
jQuery(() => {
|
jQuery(() => {
|
||||||
|
@ -966,7 +966,10 @@ hr {
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
height: calc(var(--avatar-base-height) * var(--inline-avatar-factor) + 2 * var(--avatar-base-border-radius));
|
height: calc(var(--avatar-base-height) * var(--inline-avatar-factor) + 2 * var(--avatar-base-border-radius));
|
||||||
/* margin-top: calc(var(--avatar-base-height) * var(--inline-avatar-factor) * 0.2); */
|
}
|
||||||
|
|
||||||
|
.bogus_folder_select:not(.folder_closed) .bogus_folder_avatars_block {
|
||||||
|
opacity: 1 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bogus_folder_avatars_block .avatar {
|
.bogus_folder_avatars_block .avatar {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user