Extracted `messageEdit` and `messageEditCancel` from `.mes_edit` and `.mes_edit_cancel` (#4633) * Extracted `messageEdit` and `messageEditCancel` from `.mes_edit` and `.mes_edit_cancel` * Fixed. https://github.com/SillyTavern/SillyTavern/pull/4633#discussion_r241505 https://github.com/SillyTavern/SillyTavern/pull/4633#pullrequestreview-3316588180 * Fixed.. https://github.com/SillyTavern/SillyTavern/pull/4633#issuecomment-3383321321 https://github.com/SillyTavern/SillyTavern/pull/4633#pullrequestreview-3316602505 * Fixed... * Fixed.... https://github.com/SillyTavern/SillyTavern/pull/4633#discussion_r2415124843 https://github.com/SillyTavern/SillyTavern/pull/4633#discussion_r2415124845 * Fix type conversion errors * Fix type error * Fix being unable to close message edit on first message with escape * Fixed. https://github.com/SillyTavern/SillyTavern/pull/4633#issuecomment-3412364573 Another bug found (sorry): Open edit on the last message, move it up, then move it back down. Swipe buttons appear, as far as I understand your intention, they shan't. * showSwipeButtons: return early if message edit is open --------- Co-authored-by: user <user@exmaple.com> Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
Signed| @@ -554,9 +554,10 @@ export let is_send_press = false; //Send generation | ||
| 554 | 554 | |
| 555 | 555 | let this_del_mes = -1; |
| 556 | 556 | |
| 557 | -//message editing | |
| 557 | +/** @type {string} */ | |
| 558 | 558 | varlet this_edit_mes_chname = ''; |
| 559 | -var this_edit_mes_id; | |
| 559 | +/** @type {number|undefined} */ | |
| 560 | +let this_edit_mes_id = undefined; | |
| 560 | 561 | |
| 561 | 562 | //settings |
| 562 | 563 | export let settings; |
| @@ -1494,7 +1495,7 @@ export async function reloadCurrentChat() { | ||
| 1494 | 1495 | export async function sendTextareaMessage() { |
| 1495 | 1496 | if (is_send_press) return; |
| 1496 | 1497 | if (isExecutingCommandsFromChatInput) return; |
| 1497 | 1498 | if (this_edit_mes_id >= 0) return; // don't proceed if editing a message |
| 1498 | 1499 | |
| 1499 | 1500 | let generateType; |
| 1500 | 1501 | // "Continue on send" is activated when the user hits "send" (or presses enter) on an empty chat box, and the last |
| @@ -7210,6 +7211,117 @@ function messageEditAuto(div) { | ||
| 7210 | 7211 | saveChatDebounced(); |
| 7211 | 7212 | } |
| 7212 | 7213 | |
| 7214 | +/** | |
| 7215 | + * Create the message edit UI. | |
| 7216 | + * @param {number} edit_mes_id | |
| 7217 | + */ | |
| 7218 | +async function messageEdit(edit_mes_id) { | |
| 7219 | + hideSwipeButtons(); | |
| 7220 | + let chatScrollPosition = chatElement.scrollTop(); | |
| 7221 | + | |
| 7222 | + this_edit_mes_id = edit_mes_id; | |
| 7223 | + | |
| 7224 | + let thisMesDiv = chatElement.children().filter(`.mes[mesid="${edit_mes_id}"]`); | |
| 7225 | + | |
| 7226 | + let thisMesBlock = thisMesDiv.find('.mes_block'); | |
| 7227 | + let thisMesText = thisMesBlock.find('.mes_text'); | |
| 7228 | + | |
| 7229 | + thisMesText.empty(); | |
| 7230 | + thisMesBlock.find('.mes_buttons').css('display', 'none'); | |
| 7231 | + thisMesBlock.find('.mes_edit_buttons').css('display', 'inline-flex'); | |
| 7232 | + | |
| 7233 | + // Also edit reasoning, if it exists | |
| 7234 | + const reasoningEdit = thisMesBlock.find('.mes_reasoning_edit:visible'); | |
| 7235 | + if (reasoningEdit.length > 0) { | |
| 7236 | + reasoningEdit.trigger('click'); | |
| 7237 | + } | |
| 7238 | + | |
| 7239 | + let text = chat[edit_mes_id]['mes']; | |
| 7240 | + if (chat[edit_mes_id]['is_user']) { | |
| 7241 | + this_edit_mes_chname = name1; | |
| 7242 | + } else if (chat[edit_mes_id]['force_avatar']) { | |
| 7243 | + this_edit_mes_chname = chat[edit_mes_id]['name']; | |
| 7244 | + } else { | |
| 7245 | + this_edit_mes_chname = name2; | |
| 7246 | + } | |
| 7247 | + if (power_user.trim_spaces) { | |
| 7248 | + text = text.trim(); | |
| 7249 | + } | |
| 7250 | + thisMesText.append( | |
| 7251 | + '<textarea id=\'curEditTextarea\' class=\'edit_textarea mdHotkeys\'></textarea>', | |
| 7252 | + ); | |
| 7253 | + | |
| 7254 | + let edit_textarea = thisMesBlock.find('.edit_textarea'); | |
| 7255 | + edit_textarea.val(text); | |
| 7256 | + | |
| 7257 | + const cssAutofit = CSS.supports('field-sizing', 'content'); | |
| 7258 | + if (!cssAutofit) { | |
| 7259 | + edit_textarea.height(0); | |
| 7260 | + edit_textarea.height(edit_textarea[0].scrollHeight); | |
| 7261 | + } | |
| 7262 | + edit_textarea.trigger('focus'); | |
| 7263 | + const textAreaElement = /** @type {HTMLTextAreaElement} */ (edit_textarea[0]); | |
| 7264 | + // Sets the cursor at the end of the text | |
| 7265 | + textAreaElement.setSelectionRange( | |
| 7266 | + String(edit_textarea.val()).length, | |
| 7267 | + String(edit_textarea.val()).length, | |
| 7268 | + ); | |
| 7269 | + if (Number(this_edit_mes_id) === chat.length - 1) { | |
| 7270 | + chatElement.scrollTop(chatScrollPosition); | |
| 7271 | + } | |
| 7272 | + | |
| 7273 | + updateEditArrowClasses(); | |
| 7274 | +} | |
| 7275 | + | |
| 7276 | +/** | |
| 7277 | + * Close the open message editor. | |
| 7278 | + * This deletes the user's unsaved changes. | |
| 7279 | + * @param {number} [messageId=this_edit_mes_id] | |
| 7280 | + */ | |
| 7281 | +async function messageEditCancel(messageId = this_edit_mes_id) { | |
| 7282 | + let text = chat[messageId]['mes']; | |
| 7283 | + let thisMesDiv; | |
| 7284 | + // If this is the button then select it's parent. Otherwise, select by messageId. | |
| 7285 | + if (this?.classList?.contains('mes_edit_cancel')) { | |
| 7286 | + thisMesDiv = $(this).closest('.mes'); | |
| 7287 | + } else | |
| 7288 | + { | |
| 7289 | + thisMesDiv = chatElement.children().filter(`[mesid="${messageId}"]`); | |
| 7290 | + } | |
| 7291 | + | |
| 7292 | + const thisMesBlock = thisMesDiv.find('.mes_block'); | |
| 7293 | + thisMesBlock.find('.mes_text').empty(); | |
| 7294 | + thisMesDiv.find('.mes_edit_buttons').css('display', 'none'); | |
| 7295 | + thisMesBlock.find('.mes_buttons').css('display', ''); | |
| 7296 | + thisMesBlock.find('.mes_text') | |
| 7297 | + .append(messageFormatting( | |
| 7298 | + text, | |
| 7299 | + this_edit_mes_chname, | |
| 7300 | + chat[messageId].is_system, | |
| 7301 | + chat[messageId].is_user, | |
| 7302 | + messageId, | |
| 7303 | + {}, | |
| 7304 | + false, | |
| 7305 | + )); | |
| 7306 | + appendMediaToMessage(chat[messageId], thisMesDiv); | |
| 7307 | + addCopyToCodeBlocks(thisMesDiv); | |
| 7308 | + | |
| 7309 | + const reasoningEditDone = thisMesBlock.find('.mes_reasoning_edit_cancel:visible'); | |
| 7310 | + if (reasoningEditDone.length > 0) { | |
| 7311 | + reasoningEditDone.trigger('click'); | |
| 7312 | + } | |
| 7313 | + | |
| 7314 | + await eventSource.emit(event_types.MESSAGE_UPDATED, messageId); | |
| 7315 | + if (messageId == this_edit_mes_id) { | |
| 7316 | + this_edit_mes_id = undefined; | |
| 7317 | + } | |
| 7318 | + else { | |
| 7319 | + console.warn(`The message editor was closed on message #${messageId} while #${this_edit_mes_id} is being edited.`); | |
| 7320 | + } | |
| 7321 | + | |
| 7322 | + showSwipeButtons(); | |
| 7323 | +} | |
| 7324 | + | |
| 7213 | 7325 | async function messageEditDone(div) { |
| 7214 | 7326 | let { mesBlock, text, mes, bias } = updateMessage(div); |
| 7215 | 7327 | if (this_edit_mes_id == 0) { |
| @@ -7245,6 +7357,7 @@ async function messageEditDone(div) { | ||
| 7245 | 7357 | await eventSource.emit(event_types.MESSAGE_UPDATED, this_edit_mes_id); |
| 7246 | 7358 | this_edit_mes_id = undefined; |
| 7247 | 7359 | await saveChatConditional(); |
| 7360 | + showSwipeButtons(); | |
| 7248 | 7361 | } |
| 7249 | 7362 | |
| 7250 | 7363 | /** |
| @@ -7901,7 +8014,7 @@ export function callPopup(text, type, inputValue = '', { okButton, rows, wide, w | ||
| 7901 | 8014 | } |
| 7902 | 8015 | |
| 7903 | 8016 | export function showSwipeButtons() { |
| 7904 | 8017 | if (chat.length === 0 || this_edit_mes_id >= 0) { |
| 7905 | 8018 | return; |
| 7906 | 8019 | } |
| 7907 | 8020 | |
| @@ -8105,7 +8218,7 @@ function updateEditArrowClasses() { | ||
| 8105 | 8218 | chatElement.find('.mes .mes_edit_up').removeClass('disabled'); |
| 8106 | 8219 | chatElement.find('.mes .mes_edit_down').removeClass('disabled'); |
| 8107 | 8220 | |
| 8108 | 8221 | if (this_edit_mes_id !=>= undefined0) { |
| 8109 | 8222 | const down = chatElement.find(`.mes[mesid="${this_edit_mes_id}"] .mes_edit_down`); |
| 8110 | 8223 | const up = chatElement.find(`.mes[mesid="${this_edit_mes_id}"] .mes_edit_up`); |
| 8111 | 8224 | const lastId = Number(chatElement.find('.mes').last().attr('mesid')); |
| @@ -8127,7 +8240,7 @@ function updateEditArrowClasses() { | ||
| 8127 | 8240 | */ |
| 8128 | 8241 | export function closeMessageEditor(what = 'all') { |
| 8129 | 8242 | if (what === 'message' || what === 'all') { |
| 8130 | 8243 | if (this_edit_mes_id >= 0) { |
| 8131 | 8244 | chatElement.find(`.mes[mesid="${this_edit_mes_id}"] .mes_edit_cancel`).trigger('click'); |
| 8132 | 8245 | } |
| 8133 | 8246 | } |
| @@ -10046,7 +10159,7 @@ jQuery(async function () { | ||
| 10046 | 10159 | } |
| 10047 | 10160 | |
| 10048 | 10161 | else if (id == 'option_continue') { |
| 10049 | 10162 | if (this_edit_mes_id >= 0) return; // don't proceed if editing a message |
| 10050 | 10163 | |
| 10051 | 10164 | if (is_send_press == false || fromSlashCommand) { |
| 10052 | 10165 | is_send_press = true; |
| @@ -10236,8 +10349,7 @@ jQuery(async function () { | ||
| 10236 | 10349 | return; |
| 10237 | 10350 | }*/ |
| 10238 | 10351 | |
| 10239 | - let chatScrollPosition = chatElement.scrollTop(); | |
| 10352 | + if (this_edit_mes_id >= 0) { | |
| 10240 | - if (this_edit_mes_id !== undefined) { | |
| 10241 | 10353 | let mes_edited = chatElement.find(`[mesid="${this_edit_mes_id}"]`).find('.mes_edit_done'); |
| 10242 | 10354 | if (Number(edit_mes_id) == chat.length - 1) { //if the generating swipe (...) |
| 10243 | 10355 | let run_edit = true; |
| @@ -10252,55 +10364,9 @@ jQuery(async function () { | ||
| 10252 | 10364 | } |
| 10253 | 10365 | await messageEditDone(mes_edited); |
| 10254 | 10366 | } |
| 10255 | 10367 | var edit_mes_id = Number($(this).closest('.mes_blockmes').findattr('.mes_textmesid').empty(); |
| 10256 | - $(this).closest('.mes_block').find('.mes_buttons').css('display', 'none'); | |
| 10257 | - $(this).closest('.mes_block').find('.mes_edit_buttons').css('display', 'inline-flex'); | |
| 10258 | - var edit_mes_id = $(this).closest('.mes').attr('mesid'); | |
| 10259 | - this_edit_mes_id = edit_mes_id; | |
| 10260 | - | |
| 10261 | - // Also edit reasoning, if it exists | |
| 10262 | - const reasoningEdit = $(this).closest('.mes_block').find('.mes_reasoning_edit:visible'); | |
| 10263 | - if (reasoningEdit.length > 0) { | |
| 10264 | - reasoningEdit.trigger('click'); | |
| 10265 | - } | |
| 10266 | 10368 | |
| 10267 | - var text = chat[edit_mes_id]['mes']; | |
| 10369 | + await messageEdit(edit_mes_id); | |
| 10268 | - if (chat[edit_mes_id]['is_user']) { | |
| 10269 | - this_edit_mes_chname = name1; | |
| 10270 | - } else if (chat[edit_mes_id]['force_avatar']) { | |
| 10271 | - this_edit_mes_chname = chat[edit_mes_id]['name']; | |
| 10272 | - } else { | |
| 10273 | - this_edit_mes_chname = name2; | |
| 10274 | - } | |
| 10275 | - if (power_user.trim_spaces) { | |
| 10276 | - text = text.trim(); | |
| 10277 | - } | |
| 10278 | - $(this) | |
| 10279 | - .closest('.mes_block') | |
| 10280 | - .find('.mes_text') | |
| 10281 | - .append( | |
| 10282 | - '<textarea id=\'curEditTextarea\' class=\'edit_textarea mdHotkeys\'></textarea>', | |
| 10283 | - ); | |
| 10284 | - $('#curEditTextarea').val(text); | |
| 10285 | - let edit_textarea = $(this) | |
| 10286 | - .closest('.mes_block') | |
| 10287 | - .find('.edit_textarea'); | |
| 10288 | - if (!cssAutofit) { | |
| 10289 | - edit_textarea.height(0); | |
| 10290 | - edit_textarea.height(edit_textarea[0].scrollHeight); | |
| 10291 | - } | |
| 10292 | - edit_textarea.trigger('focus'); | |
| 10293 | - const textAreaElement = /** @type {HTMLTextAreaElement} */ (edit_textarea[0]); | |
| 10294 | - // Sets the cursor at the end of the text | |
| 10295 | - textAreaElement.setSelectionRange( | |
| 10296 | - String(edit_textarea.val()).length, | |
| 10297 | - String(edit_textarea.val()).length, | |
| 10298 | - ); | |
| 10299 | - if (Number(this_edit_mes_id) === chat.length - 1) { | |
| 10300 | - chatElement.scrollTop(chatScrollPosition); | |
| 10301 | - } | |
| 10302 | - | |
| 10303 | - updateEditArrowClasses(); | |
| 10304 | 10370 | } |
| 10305 | 10371 | }); |
| 10306 | 10372 | |
| @@ -10379,33 +10445,7 @@ jQuery(async function () { | ||
| 10379 | 10445 | }); |
| 10380 | 10446 | |
| 10381 | 10447 | $(document).on('click', '.mes_edit_cancel', async function () { |
| 10382 | - let text = chat[this_edit_mes_id]['mes']; | |
| 10448 | + await messageEditCancel.call(this, this_edit_mes_id); | |
| 10383 | - | |
| 10384 | - $(this).closest('.mes_block').find('.mes_text').empty(); | |
| 10385 | - $(this).closest('.mes_edit_buttons').css('display', 'none'); | |
| 10386 | - $(this).closest('.mes_block').find('.mes_buttons').css('display', ''); | |
| 10387 | - $(this) | |
| 10388 | - .closest('.mes_block') | |
| 10389 | - .find('.mes_text') | |
| 10390 | - .append(messageFormatting( | |
| 10391 | - text, | |
| 10392 | - this_edit_mes_chname, | |
| 10393 | - chat[this_edit_mes_id].is_system, | |
| 10394 | - chat[this_edit_mes_id].is_user, | |
| 10395 | - this_edit_mes_id, | |
| 10396 | - {}, | |
| 10397 | - false, | |
| 10398 | - )); | |
| 10399 | - appendMediaToMessage(chat[this_edit_mes_id], $(this).closest('.mes')); | |
| 10400 | - addCopyToCodeBlocks($(this).closest('.mes')); | |
| 10401 | - | |
| 10402 | - const reasoningEditDone = $(this).closest('.mes_block').find('.mes_reasoning_edit_cancel:visible'); | |
| 10403 | - if (reasoningEditDone.length > 0) { | |
| 10404 | - reasoningEditDone.trigger('click'); | |
| 10405 | - } | |
| 10406 | - | |
| 10407 | - await eventSource.emit(event_types.MESSAGE_UPDATED, this_edit_mes_id); | |
| 10408 | - this_edit_mes_id = undefined; | |
| 10409 | 10449 | }); |
| 10410 | 10450 | |
| 10411 | 10451 | $(document).on('click', '.mes_edit_up', async function () { |
| @@ -10413,7 +10453,6 @@ jQuery(async function () { | ||
| 10413 | 10453 | return; |
| 10414 | 10454 | } |
| 10415 | 10455 | |
| 10416 | - hideSwipeButtons(); | |
| 10417 | 10456 | const targetId = Number(this_edit_mes_id) - 1; |
| 10418 | 10457 | const target = chatElement.find(`.mes[mesid="${targetId}"]`); |
| 10419 | 10458 | const root = $(this).closest('.mes'); |
| @@ -10434,7 +10473,6 @@ jQuery(async function () { | ||
| 10434 | 10473 | this_edit_mes_id = targetId; |
| 10435 | 10474 | updateViewMessageIds(); |
| 10436 | 10475 | await saveChatConditional(); |
| 10437 | - showSwipeButtons(); | |
| 10438 | 10476 | }); |
| 10439 | 10477 | |
| 10440 | 10478 | $(document).on('click', '.mes_edit_down', async function () { |
| @@ -10442,7 +10480,6 @@ jQuery(async function () { | ||
| 10442 | 10480 | return; |
| 10443 | 10481 | } |
| 10444 | 10482 | |
| 10445 | - hideSwipeButtons(); | |
| 10446 | 10483 | const targetId = Number(this_edit_mes_id) + 1; |
| 10447 | 10484 | const target = chatElement.find(`.mes[mesid="${targetId}"]`); |
| 10448 | 10485 | const root = $(this).closest('.mes'); |
| @@ -10463,7 +10500,6 @@ jQuery(async function () { | ||
| 10463 | 10500 | this_edit_mes_id = targetId; |
| 10464 | 10501 | updateViewMessageIds(); |
| 10465 | 10502 | await saveChatConditional(); |
| 10466 | - showSwipeButtons(); | |
| 10467 | 10503 | }); |
| 10468 | 10504 | |
| 10469 | 10505 | $(document).on('click', '.mes_edit_copy', async function () { |
| @@ -10493,7 +10529,7 @@ jQuery(async function () { | ||
| 10493 | 10529 | |
| 10494 | 10530 | $(document).on('click', '.mes_edit_delete', async function (event, customData) { |
| 10495 | 10531 | const fromSlashCommand = customData?.fromSlashCommand || false; |
| 10496 | 10532 | 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 && parseIntNumber(this_edit_mes_id) === chat.length - 1); |
| 10497 | 10533 | |
| 10498 | 10534 | let deleteOnlySwipe = false; |
| 10499 | 10535 | if (power_user.confirm_message_delete && fromSlashCommand !== true) { |
| @@ -10886,7 +10922,7 @@ jQuery(async function () { | ||
| 10886 | 10922 | $('#send_textarea').trigger('focus'); |
| 10887 | 10923 | return; |
| 10888 | 10924 | } |
| 10889 | 10925 | if (!this_edit_mes_id === undefined && $('#mes_stop').is(':visible')) { |
| 10890 | 10926 | $('#mes_stop').trigger('click'); |
| 10891 | 10927 | if (chat.length && Array.isArray(chat[chat.length - 1].swipes) && chat[chat.length - 1].swipe_id == chat[chat.length - 1].swipes.length) { |
| 10892 | 10928 | $('.last_mes .swipe_left').trigger('click'); |