Added deleteMessage method (#4666) * Added deleteMessage * Simpler swipeDeletion param * Added to context * Fix review comments * Only offer swipe deletion if count of swipes > 1 * Improve array check * Fix generation broken after message deleted * Use named constant for confirmation result * Save chat immediately --------- Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
Signed| @@ -1467,6 +1467,68 @@ export async function deleteLastMessage() { | |||
| 1467 | await eventSource.emit(event_types.MESSAGE_DELETED, chat.length); | 1467 | await eventSource.emit(event_types.MESSAGE_DELETED, chat.length); |
| 1468 | } | 1468 | } |
| 1469 | 1469 | ||
| 1470 | /** | ||
| 1471 | * Deletes a message from the chat by its ID, optionally asking for confirmation. | ||
| 1472 | * @param {number} id The ID of the message to delete. | ||
| 1473 | * @param {number} [swipeDeletionIndex] Deletes the swipe with that index. | ||
| 1474 | * @param {boolean} [askConfirmation=false] Whether to ask for confirmation before deleting. | ||
| 1475 | */ | ||
| 1476 | export async function deleteMessage(id, swipeDeletionIndex = undefined, askConfirmation = false) { | ||
| 1477 | if (swipeDeletionIndex !== undefined) { | ||
| 1478 | if (swipeDeletionIndex < 0) { | ||
| 1479 | throw new Error('Swipe index cannot be negative'); | ||
| 1480 | } | ||
| 1481 | if (!Array.isArray(chat[id].swipes)) { | ||
| 1482 | throw new Error('Message has no swipes to delete'); | ||
| 1483 | } | ||
| 1484 | if (chat[id].swipes.length <= swipeDeletionIndex) { | ||
| 1485 | throw new Error('Swipe index out of bounds'); | ||
| 1486 | } | ||
| 1487 | } | ||
| 1488 | |||
| 1489 | const messageElement = chatElement.find(`.mes[mesid="${id}"]`); | ||
| 1490 | if (messageElement.length === 0) { | ||
| 1491 | return; | ||
| 1492 | } | ||
| 1493 | |||
| 1494 | const canDeleteSwipe = swipeDeletionIndex !== undefined; | ||
| 1495 | let deleteOnlySwipe = canDeleteSwipe; | ||
| 1496 | if (askConfirmation) { | ||
| 1497 | const result = await callGenericPopup(t`Are you sure you want to delete this message?`, POPUP_TYPE.CONFIRM, null, { | ||
| 1498 | okButton: canDeleteSwipe ? t`Delete Swipe` : t`Delete Message`, | ||
| 1499 | cancelButton: 'Cancel', | ||
| 1500 | customButtons: canDeleteSwipe ? [t`Delete Message`] : null, | ||
| 1501 | }); | ||
| 1502 | if (!result) { | ||
| 1503 | return; | ||
| 1504 | } | ||
| 1505 | deleteOnlySwipe = canDeleteSwipe && result === POPUP_RESULT.AFFIRMATIVE; // Default button, not the custom one | ||
| 1506 | } | ||
| 1507 | |||
| 1508 | if (deleteOnlySwipe) { | ||
| 1509 | await deleteSwipe(swipeDeletionIndex, id); | ||
| 1510 | return; | ||
| 1511 | } | ||
| 1512 | |||
| 1513 | chat.splice(id, 1); | ||
| 1514 | messageElement.remove(); | ||
| 1515 | |||
| 1516 | chat_metadata['tainted'] = true; | ||
| 1517 | |||
| 1518 | const startFromZero = id === 0; | ||
| 1519 | updateViewMessageIds(startFromZero); | ||
| 1520 | await saveChatConditional(); | ||
| 1521 | |||
| 1522 | if (this_edit_mes_id === id) { | ||
| 1523 | this_edit_mes_id = undefined; | ||
| 1524 | } | ||
| 1525 | |||
| 1526 | hideSwipeButtons(); | ||
| 1527 | showSwipeButtons(); | ||
| 1528 | |||
| 1529 | await eventSource.emit(event_types.MESSAGE_DELETED, chat.length); | ||
| 1530 | } | ||
| 1531 | |||
| 1470 | export async function reloadCurrentChat() { | 1532 | export async function reloadCurrentChat() { |
| 1471 | preserveNeutralChat(); | 1533 | preserveNeutralChat(); |
| 1472 | await clearChat(); | 1534 | await clearChat(); |
| @@ -10531,48 +10593,11 @@ jQuery(async function () { | |||
| 10531 | 10593 | ||
| 10532 | $(document).on('click', '.mes_edit_delete', async function (event, customData) { | 10594 | $(document).on('click', '.mes_edit_delete', async function (event, customData) { |
| 10533 | const fromSlashCommand = customData?.fromSlashCommand || false; | 10595 | const fromSlashCommand = customData?.fromSlashCommand || false; |
| 10534 | const canDeleteSwipe = (Array.isArray(chat[this_edit_mes_id].swipes) && chat[this_edit_mes_id].swipes.length > 1 && !chat[this_edit_mes_id].is_user && Number(this_edit_mes_id) === chat.length - 1); | ||
| 10535 | |||
| 10536 | let deleteOnlySwipe = false; | ||
| 10537 | if (power_user.confirm_message_delete && fromSlashCommand !== true) { | ||
| 10538 | const result = await callGenericPopup(t`Are you sure you want to delete this message?`, POPUP_TYPE.CONFIRM, null, { | ||
| 10539 | okButton: canDeleteSwipe ? t`Delete Swipe` : t`Delete Message`, | ||
| 10540 | cancelButton: 'Cancel', | ||
| 10541 | customButtons: canDeleteSwipe ? [t`Delete Message`] : null, | ||
| 10542 | }); | ||
| 10543 | if (!result) { | ||
| 10544 | return; | ||
| 10545 | } | ||
| 10546 | deleteOnlySwipe = canDeleteSwipe && result === 1; // Default button, not the custom one | ||
| 10547 | } | ||
| 10548 | |||
| 10549 | const messageElement = $(this).closest('.mes'); | ||
| 10550 | if (!messageElement) { | ||
| 10551 | return; | ||
| 10552 | } | ||
| 10553 | |||
| 10554 | if (deleteOnlySwipe) { | ||
| 10555 | const message = chat[this_edit_mes_id]; | 10596 | const message = chat[this_edit_mes_id]; |
| 10556 | const swipe_id = message.swipe_id; | 10597 | const selectedSwipe = message['swipe_id'] ?? undefined; |
| 10557 | await deleteSwipe(swipe_id, Number(this_edit_mes_id)); | 10598 | const swipesArray = Array.isArray(message['swipes']) ? message['swipes'] : []; |
| 10558 | return; | 10599 | const canDeleteSwipe = !message.is_user && swipesArray.length > 1 && this_edit_mes_id === chat.length - 1 && selectedSwipe !== undefined; |
| 10559 | } | 10600 | await deleteMessage(Number(this_edit_mes_id), canDeleteSwipe ? selectedSwipe : undefined, power_user.confirm_message_delete && fromSlashCommand !== true); |
| 10560 | |||
| 10561 | chat.splice(this_edit_mes_id, 1); | ||
| 10562 | messageElement.remove(); | ||
| 10563 | |||
| 10564 | let startFromZero = Number(this_edit_mes_id) === 0; | ||
| 10565 | |||
| 10566 | this_edit_mes_id = undefined; | ||
| 10567 | chat_metadata['tainted'] = true; | ||
| 10568 | |||
| 10569 | updateViewMessageIds(startFromZero); | ||
| 10570 | saveChatDebounced(); | ||
| 10571 | |||
| 10572 | hideSwipeButtons(); | ||
| 10573 | showSwipeButtons(); | ||
| 10574 | |||
| 10575 | await eventSource.emit(event_types.MESSAGE_DELETED, chat.length); | ||
| 10576 | }); | 10601 | }); |
| 10577 | 10602 | ||
| 10578 | $(document).on('click', '.mes_edit_done', async function () { | 10603 | $(document).on('click', '.mes_edit_done', async function () { |
| @@ -55,6 +55,7 @@ import { | |||
| 55 | generateRaw, | 55 | generateRaw, |
| 56 | showSwipeButtons, | 56 | showSwipeButtons, |
| 57 | hideSwipeButtons, | 57 | hideSwipeButtons, |
| 58 | deleteMessage, | ||
| 58 | } from '../script.js'; | 59 | } from '../script.js'; |
| 59 | import { | 60 | import { |
| 60 | extension_settings, | 61 | extension_settings, |
| @@ -119,6 +120,7 @@ export function getContext() { | |||
| 119 | eventTypes: event_types, | 120 | eventTypes: event_types, |
| 120 | addOneMessage, | 121 | addOneMessage, |
| 121 | deleteLastMessage, | 122 | deleteLastMessage, |
| 123 | deleteMessage, | ||
| 122 | generate: Generate, | 124 | generate: Generate, |
| 123 | sendStreamingRequest, | 125 | sendStreamingRequest, |
| 124 | sendGenerationRequest, | 126 | sendGenerationRequest, |