Update persona.js code documentation for exported

e27e045054e19d120fa26690cdcea07d09b9d375

Wolfsblvt <wolfsblvt@gmail.com>

1 files changed, +86 -17Ignore whitespace
public/scripts/personas.js+86 -17
@@ -61,7 +61,11 @@ let savePersonasPage = 0;
61const GRID_STORAGE_KEY = 'Personas_GridView';61const GRID_STORAGE_KEY = 'Personas_GridView';
62const DEFAULT_DEPTH = 2;62const DEFAULT_DEPTH = 2;
63const DEFAULT_ROLE = 0;63const DEFAULT_ROLE = 0;
64
65/** @type {string} The currently selected persona (identified by its avatar) */
64export let user_avatar = '';66export let user_avatar = '';
67
68/** @type {FilterHelper} Filter helper for the persona list */
65export const personasFilter = new FilterHelper(debounce(getUserAvatars, debounce_timeout.quick));69export const personasFilter = new FilterHelper(debounce(getUserAvatars, debounce_timeout.quick));
6670
6771
@@ -441,13 +445,25 @@ export function initPersona(avatarId, personaName, personaDescription) {
441 saveSettingsDebounced();445 saveSettingsDebounced();
442}446}
443447
448/**
449 * Converts a character given character (either by character id or the current character) to a persona.
450 *
451 * If a persona with the same name already exists, the user is prompted to confirm whether or not to overwrite it.
452 * If the character description contains {{char}} or {{user}} macros, the user is prompted to confirm whether or not to swap them for persona macros.
453 *
454 * The function creates a new persona with the same name as the character, and sets the persona description to the character description with the macros swapped.
455 * The function also saves the settings and refreshes the persona selector.
456 *
457 * @param {number} [characterId] - The ID of the character to convert to a persona. Defaults to the current character ID.
458 * @returns {Promise<boolean>} A promise that resolves to true if the character was converted, false otherwise.
459 */
444export async function convertCharacterToPersona(characterId = null) {460export async function convertCharacterToPersona(characterId = null) {
445 if (null === characterId) characterId = this_chid;461 if (null === characterId) characterId = this_chid;
446462
447 const avatarUrl = characters[characterId]?.avatar;463 const avatarUrl = characters[characterId]?.avatar;
448 if (!avatarUrl) {464 if (!avatarUrl) {
449 console.log('No avatar found for this character');465 console.log('No avatar found for this character');
450 return;466 return false;
451 }467 }
452468
453 const name = characters[characterId]?.name;469 const name = characters[characterId]?.name;
@@ -458,7 +474,7 @@ export async function convertCharacterToPersona(characterId = null) {
458 const confirm = await Popup.show.confirm(t`Overwrite Existing Persona`, t`This character exists as a persona already. Do you want to overwrite it?`);474 const confirm = await Popup.show.confirm(t`Overwrite Existing Persona`, t`This character exists as a persona already. Do you want to overwrite it?`);
459 if (!confirm) {475 if (!confirm) {
460 console.log('User cancelled the overwrite of the persona');476 console.log('User cancelled the overwrite of the persona');
461 return;477 return false;
462 }478 }
463 }479 }
464480
@@ -496,6 +512,7 @@ export async function convertCharacterToPersona(characterId = null) {
496 await getUserAvatars(true, overwriteName);512 await getUserAvatars(true, overwriteName);
497 // Reload the persona description513 // Reload the persona description
498 setPersonaDescription();514 setPersonaDescription();
515 return true;
499}516}
500517
501/**518/**
@@ -507,6 +524,9 @@ const countPersonaDescriptionTokens = debounce(async () => {
507 $('#persona_description_token_count').text(String(count));524 $('#persona_description_token_count').text(String(count));
508}, debounce_timeout.relaxed);525}, debounce_timeout.relaxed);
509526
527/**
528 * Updates the UI for the Persona Management page with the current persona values
529 */
510export function setPersonaDescription() {530export function setPersonaDescription() {
511 $('#your_name').text(name1);531 $('#your_name').text(name1);
512532
@@ -683,22 +703,33 @@ export async function askForPersonaSelection(title, text, personas, { okButton =
683 return Number(result) >= 100 ? personas[Number(result) - 100] : null;703 return Number(result) >= 100 ? personas[Number(result) - 100] : null;
684}704}
685705
706/**
707 * Automatically selects a persona based on the given name if a matching persona exists.
708 * @param {string} name - The name to search for
709 * @returns {boolean} True if a matching persona was found and selected, false otherwise
710 */
686export function autoSelectPersona(name) {711export function autoSelectPersona(name) {
687 for (const [key, value] of Object.entries(power_user.personas)) {712 for (const [key, value] of Object.entries(power_user.personas)) {
688 if (value === name) {713 if (value === name) {
689 console.log(`Auto-selecting persona ${key} for name ${name}`);714 console.log(`Auto-selecting persona ${key} for name ${name}`);
690 setUserAvatar(key);715 setUserAvatar(key);
691 return;716 return true;
692 }717 }
693 }718 }
719 return false;
694}720}
695721
722/**
723 * Renames the persona with the given avatar ID by showing a popup to enter a new name.
724 * @param {string} avatarId - ID of the avatar to rename
725 * @returns {Promise<boolean>} A promise that resolves to true if the persona was renamed, false otherwise
726 */
696async function renamePersona(avatarId) {727async function renamePersona(avatarId) {
697 const currentName = power_user.personas[avatarId];728 const currentName = power_user.personas[avatarId];
698 const newName = await Popup.show.input(t`Rename Persona`, t`Enter a new name for this persona:`, currentName);729 const newName = await Popup.show.input(t`Rename Persona`, t`Enter a new name for this persona:`, currentName);
699 if (!newName || newName === currentName) {730 if (!newName || newName === currentName) {
700 console.debug('User cancelled renaming persona or name is unchanged');731 console.debug('User cancelled renaming persona or name is unchanged');
701 return;732 return false;
702 }733 }
703734
704 power_user.personas[avatarId] = newName;735 power_user.personas[avatarId] = newName;
@@ -712,9 +743,16 @@ async function renamePersona(avatarId) {
712 await getUserAvatars(true, avatarId);743 await getUserAvatars(true, avatarId);
713 updatePersonaUIStates();744 updatePersonaUIStates();
714 setPersonaDescription();745 setPersonaDescription();
746 return true;
715}747}
716748
717function selectCurrentPersona({ toastPersonaNameChange = true } = {}) {749/**
750 * Selects the persona with the currently set avatar ID by updating the user name and persona description, and updating the locked persona if the setting is enabled.
751 * @param {object} [options={}] - Optional settings
752 * @param {boolean} [options.toastPersonaNameChange=true] - Whether to show a toast when the persona name is changed
753 * @returns {Promise<void>}
754 */
755async function selectCurrentPersona({ toastPersonaNameChange = true } = {}) {
718 const personaName = power_user.personas[user_avatar];756 const personaName = power_user.personas[user_avatar];
719 if (personaName) {757 if (personaName) {
720 const shouldAutoLock = power_user.persona_auto_lock && user_avatar !== chat_metadata['persona'];758 const shouldAutoLock = power_user.persona_auto_lock && user_avatar !== chat_metadata['persona'];
@@ -1211,6 +1249,14 @@ function getPersonaStates(avatarId) {
1211 };1249 };
1212}1250}
12131251
1252/**
1253 * Updates the UI to reflect the current states of all personas and the selected user's persona.
1254 * This includes updating class states on avatar containers to indicate default status, chat lock,
1255 * and character lock, as well as updating icons and labels in the persona management panel to reflect
1256 * the current state of the user's persona.
1257 * Additionally, it manages the display of temporary persona lock information.
1258 */
1259
1214function updatePersonaUIStates() {1260function updatePersonaUIStates() {
1215 // Update the persona list1261 // Update the persona list
1216 $('#user_avatar_block .avatar-container').each(function () {1262 $('#user_avatar_block .avatar-container').each(function () {
@@ -1258,15 +1304,21 @@ function updatePersonaUIStates() {
1258}1304}
12591305
1260/**1306/**
1261 * Checks if the currently selected persona is temporary due to either a different default persona1307 * @typedef {Object} PersonaLockInfo
1262 * or a different persona being locked to the current chat. If so, it also returns a string that1308 * @property {boolean} isTemporary - Whether the selected persona is temporary based on current locks.
1263 * can be used to describe this situation to the user.1309 * @property {boolean} hasDifferentChatLock - True if the chat persona is set and differs from the user avatar.
1310 * @property {boolean} hasDifferentDefaultLock - True if the default persona is set and differs from the user avatar.
1311 * @property {string} info - Detailed information about the current, chat, and default personas.
1312 */
1313
1314/**
1315 * Computes temporary lock information for the current persona.
1316 *
1317 * This function checks whether the currently selected persona is temporary by comparing
1318 * the chat persona and the default persona to the user avatar. If either is different,
1319 * the currently selected persona is considered temporary and a detailed message is generated.
1264 *1320 *
1265 * @returns {{isTemporary: boolean, hasDifferentChatLock: boolean, hasDifferentDefaultLock: boolean, info: string?}} An object containing 4 properties:1321 * @returns {PersonaLockInfo} An object containing flags and a message describing the persona lock status.
1266 * - isTemporary: A boolean indicating if the current persona is temporary
1267 * - hasDifferentChatLock: A boolean indicating if the current chat has a different persona locked to it
1268 * - hasDifferentDefaultLock: A boolean indicating if there is a different default persona set
1269 * - info: A string describing the situation, or an empty if not temporary
1270 */1322 */
1271function getPersonaTemporaryLockInfo() {1323function getPersonaTemporaryLockInfo() {
1272 const hasDifferentChatLock = !!chat_metadata['persona'] && chat_metadata['persona'] !== user_avatar;1324 const hasDifferentChatLock = !!chat_metadata['persona'] && chat_metadata['persona'] !== user_avatar;
@@ -1286,6 +1338,13 @@ function getPersonaTemporaryLockInfo() {
1286 };1338 };
1287}1339}
12881340
1341/**
1342 * Loads the appropriate persona for the current chat session based on locks (chat lock, char lock, default persona)
1343 *
1344 * @param {Object} [options={}] - Optional arguments
1345 * @param {boolean} [options.doRender=false] - Whether to render the persona immediately
1346 * @returns {Promise<boolean>} - A promise that resolves to a boolean indicating whether a persona was selected
1347 */
1289async function loadPersonaForCurrentChat({ doRender = false } = {}) {1348async function loadPersonaForCurrentChat({ doRender = false } = {}) {
1290 // Cache persona list to check if they exist1349 // Cache persona list to check if they exist
1291 const userAvatars = await getUserAvatars(doRender);1350 const userAvatars = await getUserAvatars(doRender);
@@ -1317,7 +1376,7 @@ async function loadPersonaForCurrentChat({ doRender = false } = {}) {
1317 if (chatPersona) {1376 if (chatPersona) {
1318 // If the chat-bound persona is the currently selected one, we can simply exit out1377 // If the chat-bound persona is the currently selected one, we can simply exit out
1319 if (chatPersona === user_avatar) {1378 if (chatPersona === user_avatar) {
1320 return;1379 return false;
1321 }1380 }
1322 // Otherwise ask if we want to switch1381 // Otherwise ask if we want to switch
1323 const autoLock = power_user.persona_auto_lock;1382 const autoLock = power_user.persona_auto_lock;
@@ -1328,11 +1387,11 @@ async function loadPersonaForCurrentChat({ doRender = false } = {}) {
1328 if (autoLock) {1387 if (autoLock) {
1329 lockPersona('chat');1388 lockPersona('chat');
1330 }1389 }
1331 return;1390 return false;
1332 }1391 }
1333 } else {1392 } else {
1334 // If we don't have a chat-bound persona, we simply return and keep the current one we have1393 // If we don't have a chat-bound persona, we simply return and keep the current one we have
1335 return;1394 return false;
1336 }1395 }
1337 }1396 }
13381397
@@ -1392,6 +1451,8 @@ async function loadPersonaForCurrentChat({ doRender = false } = {}) {
1392 }1451 }
13931452
1394 updatePersonaUIStates();1453 updatePersonaUIStates();
1454
1455 return !!chatPersona;
1395}1456}
13961457
1397/**1458/**
@@ -1462,7 +1523,6 @@ export async function showCharConnections() {
1462 *1523 *
1463 * @returns {PersonaConnection} An object representing the current connection1524 * @returns {PersonaConnection} An object representing the current connection
1464 */1525 */
1465
1466export function getCurrentConnectionObj() {1526export function getCurrentConnectionObj() {
1467 if (selected_group)1527 if (selected_group)
1468 return { type: 'group', id: selected_group };1528 return { type: 'group', id: selected_group };
@@ -1579,6 +1639,11 @@ async function syncUserNameToPersona() {
1579 await reloadCurrentChat();1639 await reloadCurrentChat();
1580}1640}
15811641
1642/**
1643 * Retriggers the first message to reload it from the char definition.
1644 *
1645 * Only works if only the first message is present, and not in group mode.
1646 */
1582export function retriggerFirstMessageOnEmptyChat() {1647export function retriggerFirstMessageOnEmptyChat() {
1583 if (this_chid >= 0 && !selected_group && chat.length === 1) {1648 if (this_chid >= 0 && !selected_group && chat.length === 1) {
1584 $('#firstmessage_textarea').trigger('input');1649 $('#firstmessage_textarea').trigger('input');
@@ -1812,6 +1877,10 @@ function registerPersonaSlashCommands() {
1812 }));1877 }));
1813}1878}
18141879
1880/**
1881 * Initializes the persona management and all its functionality.
1882 * This is called during the initialization of the page.
1883 */
1815export async function initPersonas() {1884export async function initPersonas() {
1816 await migrateNonPersonaUser();1885 await migrateNonPersonaUser();
1817 registerPersonaSlashCommands();1886 registerPersonaSlashCommands();