Updated code documentation

- Updated code documentation for all methods added/changed with this PR
- Expanded tooltip to "bulk edit" to explain how it works
This commit is contained in:
Wolfsblvt 2024-03-29 04:41:16 +01:00
parent 9005d3f790
commit 167673fcf5
3 changed files with 63 additions and 27 deletions

View File

@ -4327,7 +4327,7 @@
<div id="rm_print_characters_pagination"> <div id="rm_print_characters_pagination">
<i id="charListGridToggle" class="fa-solid fa-table-cells-large menu_button" title="Toggle character grid view" data-i18n="[title]Toggle character grid view"></i> <i id="charListGridToggle" class="fa-solid fa-table-cells-large menu_button" title="Toggle character grid view" data-i18n="[title]Toggle character grid view"></i>
<i id="bulkEditButton" class="fa-solid fa-edit menu_button bulkEditButton" title="Bulk edit characters" data-i18n="[title]Bulk edit characters"></i> <i id="bulkEditButton" class="fa-solid fa-edit menu_button bulkEditButton" title="Bulk edit characters&#13;&#13;Click to toggle characters&#13;Shift + Click to select/deselect a range of characters&#13;Right-click for actions" data-i18n="[title]Bulk edit characters&#13;&#13;Click to toggle characters&#13;Shift + Click to select/deselect a range of characters&#13;Right-click for actions"></i>
<div id="bulkSelectedCount" class="bulkEditOptionElement paginationjs-nav"></div> <div id="bulkSelectedCount" class="bulkEditOptionElement paginationjs-nav"></div>
<i id="bulkSelectAllButton" class="fa-solid fa-check-double menu_button bulkEditOptionElement bulkSelectAllButton" title="Bulk select all characters" data-i18n="[title]Bulk select all characters" style="display: none;"></i> <i id="bulkSelectAllButton" class="fa-solid fa-check-double menu_button bulkEditOptionElement bulkSelectAllButton" title="Bulk select all characters" data-i18n="[title]Bulk select all characters" style="display: none;"></i>
<i id="bulkDeleteButton" class="fa-solid fa-trash menu_button bulkEditOptionElement bulkDeleteButton" title="Bulk delete characters" data-i18n="[title]Bulk delete characters" style="display: none;"></i> <i id="bulkDeleteButton" class="fa-solid fa-trash menu_button bulkEditOptionElement bulkDeleteButton" title="Bulk delete characters" data-i18n="[title]Bulk delete characters" style="display: none;"></i>

View File

@ -40,7 +40,7 @@ class CharacterContextMenu {
* Tag one or more characters, * Tag one or more characters,
* opens a popup. * opens a popup.
* *
* @param selectedCharacters * @param {Array<number>} selectedCharacters
*/ */
static tag = (selectedCharacters) => { static tag = (selectedCharacters) => {
BulkTagPopupHandler.show(selectedCharacters); BulkTagPopupHandler.show(selectedCharacters);
@ -49,7 +49,7 @@ class CharacterContextMenu {
/** /**
* Duplicate one or more characters * Duplicate one or more characters
* *
* @param characterId * @param {number} characterId
* @returns {Promise<any>} * @returns {Promise<any>}
*/ */
static duplicate = async (characterId) => { static duplicate = async (characterId) => {
@ -74,7 +74,7 @@ class CharacterContextMenu {
* Favorite a character * Favorite a character
* and highlight it. * and highlight it.
* *
* @param characterId * @param {number} characterId
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
static favorite = async (characterId) => { static favorite = async (characterId) => {
@ -110,7 +110,7 @@ class CharacterContextMenu {
* Convert one or more characters to persona, * Convert one or more characters to persona,
* may open a popup for one or more characters. * may open a popup for one or more characters.
* *
* @param characterId * @param {number} characterId
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
static persona = async (characterId) => await convertCharacterToPersona(characterId); static persona = async (characterId) => await convertCharacterToPersona(characterId);
@ -119,8 +119,8 @@ class CharacterContextMenu {
* Delete one or more characters, * Delete one or more characters,
* opens a popup. * opens a popup.
* *
* @param characterId * @param {number} characterId
* @param deleteChats * @param {boolean} [deleteChats]
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
static delete = async (characterId, deleteChats = false) => { static delete = async (characterId, deleteChats = false) => {
@ -234,7 +234,7 @@ class BulkTagPopupHandler {
/** /**
* Append and show the tag control * Append and show the tag control
* *
* @param characterIds - The characters assigned to this control * @param {Array<number>} characterIds - The characters assigned to this control
*/ */
static show(characterIds) { static show(characterIds) {
if (characterIds.length == 0) { if (characterIds.length == 0) {
@ -250,7 +250,7 @@ class BulkTagPopupHandler {
// Print the tag list with all mutuable tags, marking them as removable. That is the initial fill // Print the tag list with all mutuable tags, marking them as removable. That is the initial fill
printTagList($('#bulkTagList'), { tags: () => this.getMutualTags(characterIds), tagOptions: { removable: true } }); printTagList($('#bulkTagList'), { tags: () => this.getMutualTags(characterIds), tagOptions: { removable: true } });
// Tag input with empty tags so new tag gets added and it doesn't get emptied on redraw // Tag input with resolvable list for the mutual tags to get redrawn, so that newly added tags get sorted correctly
createTagInput('#bulkTagInput', '#bulkTagList', { tags: () => this.getMutualTags(characterIds), tagOptions: { removable: true }}); createTagInput('#bulkTagInput', '#bulkTagList', { tags: () => this.getMutualTags(characterIds), tagOptions: { removable: true }});
document.querySelector('#bulk_tag_popup_reset').addEventListener('click', this.resetTags.bind(this, characterIds)); document.querySelector('#bulk_tag_popup_reset').addEventListener('click', this.resetTags.bind(this, characterIds));
@ -258,6 +258,12 @@ class BulkTagPopupHandler {
document.querySelector('#bulk_tag_popup_cancel').addEventListener('click', this.hide.bind(this)); document.querySelector('#bulk_tag_popup_cancel').addEventListener('click', this.hide.bind(this));
} }
/**
* Builds a list of all tags that the provided characters have in common.
*
* @param {Array<number>} characterIds - The characters to find mutual tags for
* @returns {Array<object>} A list of mutual tags
*/
static getMutualTags(characterIds) { static getMutualTags(characterIds) {
if (characterIds.length == 0) { if (characterIds.length == 0) {
return []; return [];
@ -293,7 +299,7 @@ class BulkTagPopupHandler {
/** /**
* Empty the tag map for the given characters * Empty the tag map for the given characters
* *
* @param characterIds * @param {Array<number>} characterIds
*/ */
static resetTags(characterIds) { static resetTags(characterIds) {
for (const characterId of characterIds) { for (const characterId of characterIds) {
@ -307,9 +313,9 @@ class BulkTagPopupHandler {
} }
/** /**
* Empty the tag map for the given characters * Remove the mutual tags for all given characters
* *
* @param characterIds * @param {Array<number>} characterIds
*/ */
static removeMutual(characterIds) { static removeMutual(characterIds) {
const mutualTags = this.getMutualTags(characterIds); const mutualTags = this.getMutualTags(characterIds);
@ -627,6 +633,15 @@ class BulkEditOverlay {
this.#cancelNextToggle = false; this.#cancelNextToggle = false;
}; };
/**
* When shift click was held down, this function handles the multi select of characters in a single click.
*
* If the last clicked character was deselected, and the current one was deselected too, it will deselect all currently selected characters between those two.
* If the last clicked character was selected, and the current one was selected too, it will select all currently not selected characters between those two.
* If the states do not match, nothing will happen.
*
* @param {HTMLElement} currentCharacter - The html element of the currently toggled character
*/
handleShiftClick = (currentCharacter) => { handleShiftClick = (currentCharacter) => {
const characterId = currentCharacter.getAttribute('chid'); const characterId = currentCharacter.getAttribute('chid');
const select = !this.selectedCharacters.includes(characterId); const select = !this.selectedCharacters.includes(characterId);
@ -634,11 +649,18 @@ class BulkEditOverlay {
if (this.lastSelected.characterId && this.lastSelected.select !== undefined) { if (this.lastSelected.characterId && this.lastSelected.select !== undefined) {
// Only if select state and the last select state match we execute the range select // Only if select state and the last select state match we execute the range select
if (select === this.lastSelected.select) { if (select === this.lastSelected.select) {
this.selectCharactersInRange(currentCharacter, select); this.toggleCharactersInRange(currentCharacter, select);
} }
} }
}; };
/**
* Toggles the selection of a given characters
*
* @param {HTMLElement} character - The html element of a character
* @param {object} param1 - Optional params
* @param {boolean} [param1.markState] - Whether the toggle of this character should be remembered as the last done toggle
*/
toggleSingleCharacter = (character, { markState = true } = {}) => { toggleSingleCharacter = (character, { markState = true } = {}) => {
const characterId = character.getAttribute('chid'); const characterId = character.getAttribute('chid');
@ -648,11 +670,11 @@ class BulkEditOverlay {
if (select) { if (select) {
character.classList.add(BulkEditOverlay.selectedClass); character.classList.add(BulkEditOverlay.selectedClass);
if (legacyBulkEditCheckbox) legacyBulkEditCheckbox.checked = true; if (legacyBulkEditCheckbox) legacyBulkEditCheckbox.checked = true;
this.selectCharacter(characterId); this.#selectedCharacters.push(String(characterId));
} else { } else {
character.classList.remove(BulkEditOverlay.selectedClass); character.classList.remove(BulkEditOverlay.selectedClass);
if (legacyBulkEditCheckbox) legacyBulkEditCheckbox.checked = false; if (legacyBulkEditCheckbox) legacyBulkEditCheckbox.checked = false;
this.dismissCharacter(characterId); this.#selectedCharacters = this.#selectedCharacters.filter(item => String(characterId) !== item)
} }
this.updateSelectedCount(); this.updateSelectedCount();
@ -663,12 +685,24 @@ class BulkEditOverlay {
} }
}; };
/**
* Updates the selected count element with the current count
*
* @param {number} [countOverride] - optional override for a manual number to set
*/
updateSelectedCount = (countOverride = undefined) => { updateSelectedCount = (countOverride = undefined) => {
const count = countOverride ?? this.selectedCharacters.length; const count = countOverride ?? this.selectedCharacters.length;
$(`#${BulkEditOverlay.bulkSelectedCountId}`).text(count).attr('title', `${count} characters selected`); $(`#${BulkEditOverlay.bulkSelectedCountId}`).text(count).attr('title', `${count} characters selected`);
}; };
selectCharactersInRange = (currentCharacter, select) => { /**
* Toggles the selection of characters in a given range.
* The range is provided by the given character and the last selected one remembered in the selection state.
*
* @param {HTMLElement} currentCharacter - The html element of the currently toggled character
* @param {boolean} select - <c>true</c> if the characters in the range are to be selected, <c>false</c> if deselected
*/
toggleCharactersInRange = (currentCharacter, select) => {
const currentCharacterId = currentCharacter.getAttribute('chid'); const currentCharacterId = currentCharacter.getAttribute('chid');
const characters = Array.from(document.querySelectorAll('#' + BulkEditOverlay.containerId + ' .' + BulkEditOverlay.characterClass)); const characters = Array.from(document.querySelectorAll('#' + BulkEditOverlay.containerId + ' .' + BulkEditOverlay.characterClass));
@ -680,8 +714,10 @@ class BulkEditOverlay {
const characterId = character.getAttribute('chid'); const characterId = character.getAttribute('chid');
const isCharacterSelected = this.selectedCharacters.includes(characterId); const isCharacterSelected = this.selectedCharacters.includes(characterId);
if (select && !isCharacterSelected || !select && isCharacterSelected) { // Only toggle the character if it wasn't on the state we have are toggling towards.
this.toggleSingleCharacter(character, { markState: currentCharacterId == i }); // Also doing a weird type check, because typescript checker doesn't like the return of 'querySelectorAll'.
if ((select && !isCharacterSelected || !select && isCharacterSelected) && character instanceof HTMLElement) {
this.toggleSingleCharacter(character, { markState: currentCharacterId == characterId });
} }
} }
}; };
@ -771,10 +807,6 @@ class BulkEditOverlay {
addStateChangeCallback = callback => this.stateChangeCallbacks.push(callback); addStateChangeCallback = callback => this.stateChangeCallbacks.push(callback);
selectCharacter = characterId => this.selectedCharacters.push(String(characterId));
dismissCharacter = characterId => this.#selectedCharacters = this.selectedCharacters.filter(item => String(characterId) !== item);
/** /**
* Clears internal character storage and * Clears internal character storage and
* removes visual highlight. * removes visual highlight.

View File

@ -320,7 +320,8 @@ function getTagKey() {
/** /**
* Gets the tag key for any provided entity/id/key. If a valid tag key is provided, it just returns this. * Gets the tag key for any provided entity/id/key. If a valid tag key is provided, it just returns this.
* Robust method to find a valid tag key for any entity * Robust method to find a valid tag key for any entity.
*
* @param {object|number|string} entityOrKey An entity with id property (character, group, tag), or directly an id or tag key. * @param {object|number|string} entityOrKey An entity with id property (character, group, tag), or directly an id or tag key.
* @returns {string} The tag key that can be found. * @returns {string} The tag key that can be found.
*/ */
@ -394,9 +395,10 @@ function findTag(request, resolve, listSelector) {
} }
/** /**
* Select a tag and add it to the list. This function is mostly used as an event handler for the tag selector control. * Select a tag and add it to the list. This function is (mostly) used as an event handler for the tag selector control.
* @param {*} event - *
* @param {*} ui - * @param {*} event - The event that fired on autocomplete select
* @param {*} ui - An Object with label and value properties for the selected option
* @param {*} listSelector - The selector of the list to print/add to * @param {*} listSelector - The selector of the list to print/add to
* @param {PrintTagListOptions} [tagListOptions] - Optional parameters for printing the tag list. Can be set to be consistent with the expected behavior of tags in the list that was defined before. * @param {PrintTagListOptions} [tagListOptions] - Optional parameters for printing the tag list. Can be set to be consistent with the expected behavior of tags in the list that was defined before.
* @returns {boolean} <c>false</c>, to keep the input clear * @returns {boolean} <c>false</c>, to keep the input clear
@ -529,7 +531,8 @@ function createNewTag(tagName) {
*/ */
/** /**
* Prints the list of tags. * Prints the list of tags
*
* @param {JQuery<HTMLElement>} element - The container element where the tags are to be printed. * @param {JQuery<HTMLElement>} element - The container element where the tags are to be printed.
* @param {PrintTagListOptions} [options] - Optional parameters for printing the tag list. * @param {PrintTagListOptions} [options] - Optional parameters for printing the tag list.
*/ */
@ -798,6 +801,7 @@ function applyTagsOnGroupSelect() {
} }
/** /**
* Create a tag input by enabling the autocomplete feature of a given input element. Tags will be added to the given list.
* *
* @param {string} inputSelector - the selector for the tag input control * @param {string} inputSelector - the selector for the tag input control
* @param {string} listSelector - the selector for the list of the tags modified by the input control * @param {string} listSelector - the selector for the list of the tags modified by the input control