Add scroll behavior options for media appending

c14fba88298867ddec8b33728cecc2bb8ebabec6

Cohee <18619528+Cohee1207@users.noreply.github.com>

5 files changed, +31 -17Ignore whitespace
public/script.js+11 -8
@@ -183,7 +183,7 @@ import {
183 trimSpaces,183 trimSpaces,
184 clamp,184 clamp,
185} from './scripts/utils.js';185} from './scripts/utils.js';
186import { debounce_timeout, GENERATION_TYPE_TRIGGERS, IGNORE_SYMBOL, inject_ids, MEDIA_DISPLAY, MEDIA_TYPE, SWIPE_DIRECTION } from './scripts/constants.js';186import { debounce_timeout, GENERATION_TYPE_TRIGGERS, IGNORE_SYMBOL, inject_ids, MEDIA_DISPLAY, MEDIA_TYPE, SCROLL_BEHAVIOR, SWIPE_DIRECTION } from './scripts/constants.js';
187187
188import { cancelDebouncedMetadataSave, doDailyExtensionUpdatesCheck, extension_settings, initExtensions, loadExtensionSettings, runGenerationInterceptors, saveMetadataDebounced } from './scripts/extensions.js';188import { cancelDebouncedMetadataSave, doDailyExtensionUpdatesCheck, extension_settings, initExtensions, loadExtensionSettings, runGenerationInterceptors, saveMetadataDebounced } from './scripts/extensions.js';
189import { COMMENT_NAME_DEFAULT, CONNECT_API_MAP, executeSlashCommandsOnChatInput, initDefaultSlashCommands, isExecutingCommandsFromChatInput, pauseScriptExecution, stopScriptExecution, UNIQUE_APIS } from './scripts/slash-commands.js';189import { COMMENT_NAME_DEFAULT, CONNECT_API_MAP, executeSlashCommandsOnChatInput, initDefaultSlashCommands, isExecutingCommandsFromChatInput, pauseScriptExecution, stopScriptExecution, UNIQUE_APIS } from './scripts/slash-commands.js';
@@ -2071,9 +2071,9 @@ export function getMediaIndex(mes) {
2071 * Appends image or file to the message element.2071 * Appends image or file to the message element.
2072 * @param {ChatMessage} mes Message object2072 * @param {ChatMessage} mes Message object
2073 * @param {JQuery<HTMLElement>} messageElement Message element2073 * @param {JQuery<HTMLElement>} messageElement Message element
2074 * @param {boolean} [adjustScroll=true] Whether to adjust the scroll position after appending the media2074 * @param {string} [scrollBehavior] Scroll behavior when adjusting scroll position
2075 */2075 */
2076export function appendMediaToMessage(mes, messageElement, adjustScroll = true) {2076export function appendMediaToMessage(mes, messageElement, scrollBehavior = SCROLL_BEHAVIOR.ADJUST) {
2077 ensureMessageMediaIsArray(mes);2077 ensureMessageMediaIsArray(mes);
20782078
2079 const hasMedia = Array.isArray(mes?.extra?.media) && mes.extra.media.length > 0;2079 const hasMedia = Array.isArray(mes?.extra?.media) && mes.extra.media.length > 0;
@@ -2084,13 +2084,16 @@ export function appendMediaToMessage(mes, messageElement, adjustScroll = true) {
2084 const mediaBlocks = [];2084 const mediaBlocks = [];
2085 const mediaPromises = [];2085 const mediaPromises = [];
20862086
2087 const chatHeight = adjustScroll && (hasMedia || hasFiles) ? chatElement.prop('scrollHeight') : 0;2087 const chatHeight = (hasMedia || hasFiles) ? chatElement.prop('scrollHeight') : 0;
2088 const scrollPosition = chatElement.scrollTop();2088 const scrollPosition = (hasMedia || hasFiles) ? chatElement.scrollTop() : 0;
2089 const doAdjustScroll = () => {2089 const doAdjustScroll = () => {
2090 if (!hasMedia && !hasFiles) {2090 if (!hasMedia && !hasFiles) {
2091 return;2091 return;
2092 }2092 }
2093 if (!adjustScroll) {2093 if (scrollBehavior === SCROLL_BEHAVIOR.NONE) {
2094 return;
2095 }
2096 if (scrollBehavior === SCROLL_BEHAVIOR.KEEP) {
2094 chatElement.scrollTop(scrollPosition);2097 chatElement.scrollTop(scrollPosition);
2095 return;2098 return;
2096 }2099 }
@@ -2397,7 +2400,7 @@ export function addOneMessage(mes, { type = 'normal', insertAfter = null, scroll
2397 swipeMessage.find('.mes_text').html(messageText).attr('title', title);2400 swipeMessage.find('.mes_text').html(messageText).attr('title', title);
2398 swipeMessage.find('.timestamp').text(timestamp).attr('title', `${params.extra.api} - ${params.extra.model}`);2401 swipeMessage.find('.timestamp').text(timestamp).attr('title', `${params.extra.api} - ${params.extra.model}`);
2399 updateReasoningUI(swipeMessage);2402 updateReasoningUI(swipeMessage);
2400 appendMediaToMessage(mes, swipeMessage);2403 appendMediaToMessage(mes, swipeMessage, scroll ? SCROLL_BEHAVIOR.ADJUST : SCROLL_BEHAVIOR.NONE);
2401 if (power_user.timestamp_model_icon && params.extra?.api) {2404 if (power_user.timestamp_model_icon && params.extra?.api) {
2402 insertSVGIcon(swipeMessage, params.extra);2405 insertSVGIcon(swipeMessage, params.extra);
2403 }2406 }
@@ -2412,7 +2415,7 @@ export function addOneMessage(mes, { type = 'normal', insertAfter = null, scroll
2412 } else {2415 } else {
2413 const messageId = forceId ?? chat.length - 1;2416 const messageId = forceId ?? chat.length - 1;
2414 chatElement.find(`[mesid="${messageId}"] .mes_text`).append(messageText);2417 chatElement.find(`[mesid="${messageId}"] .mes_text`).append(messageText);
2415 appendMediaToMessage(mes, newMessage);2418 appendMediaToMessage(mes, newMessage, scroll ? SCROLL_BEHAVIOR.ADJUST : SCROLL_BEHAVIOR.NONE);
2416 showSwipes && hideSwipeButtons();2419 showSwipes && hideSwipeButtons();
2417 }2420 }
24182421
public/scripts/chats.js+5 -5
@@ -57,7 +57,7 @@ import { renderTemplateAsync } from './templates.js';
57import { t } from './i18n.js';57import { t } from './i18n.js';
58import { humanizedDateTime } from './RossAscends-mods.js';58import { humanizedDateTime } from './RossAscends-mods.js';
59import { accountStorage } from './util/AccountStorage.js';59import { accountStorage } from './util/AccountStorage.js';
60import { MEDIA_DISPLAY, MEDIA_TYPE, SWIPE_DIRECTION } from './constants.js';60import { MEDIA_DISPLAY, MEDIA_TYPE, SCROLL_BEHAVIOR, SWIPE_DIRECTION } from './constants.js';
6161
62/**62/**
63 * @typedef {Object} FileAttachment63 * @typedef {Object} FileAttachment
@@ -418,7 +418,7 @@ async function deleteMessageFile(messageBlock, messageId, fileIndex) {
418 await saveChatConditional();418 await saveChatConditional();
419 await deleteFileFromServer(url);419 await deleteFileFromServer(url);
420420
421 appendMediaToMessage(message, messageBlock, false);421 appendMediaToMessage(message, messageBlock, SCROLL_BEHAVIOR.KEEP);
422}422}
423423
424/**424/**
@@ -489,7 +489,7 @@ function embedMessageFile(messageId, messageBlock) {
489489
490 await populateFileAttachment(message, 'embed_file_input');490 await populateFileAttachment(message, 'embed_file_input');
491 await eventSource.emit(event_types.MESSAGE_FILE_EMBEDDED, messageId);491 await eventSource.emit(event_types.MESSAGE_FILE_EMBEDDED, messageId);
492 appendMediaToMessage(message, messageBlock, false);492 appendMediaToMessage(message, messageBlock, SCROLL_BEHAVIOR.KEEP);
493 await saveChatConditional();493 await saveChatConditional();
494 }494 }
495}495}
@@ -1022,7 +1022,7 @@ async function deleteMessageMedia(messageId, mediaIndex, messageBlock) {
1022 }1022 }
10231023
1024 await saveChatConditional();1024 await saveChatConditional();
1025 appendMediaToMessage(message, messageBlock, false);1025 appendMediaToMessage(message, messageBlock, SCROLL_BEHAVIOR.KEEP);
1026}1026}
10271027
1028/**1028/**
@@ -1051,7 +1051,7 @@ async function switchMessageMediaDisplay(messageId, messageBlock, targetDisplay)
10511051
1052 message.extra.media_display = targetDisplay;1052 message.extra.media_display = targetDisplay;
1053 await saveChatConditional();1053 await saveChatConditional();
1054 appendMediaToMessage(message, messageBlock, false);1054 appendMediaToMessage(message, messageBlock, SCROLL_BEHAVIOR.KEEP);
1055}1055}
10561056
1057/**1057/**
public/scripts/constants.js+11 -0
@@ -94,6 +94,17 @@ export const MEDIA_TYPE = {
94};94};
9595
96/**96/**
97 * Scroll behavior options when appending media to messages.
98 * @enum {string}
99 * @readonly
100 */
101export const SCROLL_BEHAVIOR = {
102 NONE: 'none',
103 KEEP: 'keep',
104 ADJUST: 'adjust',
105};
106
107/**
97 * @type {{readonly LEFT: 'left', readonly RIGHT: 'right'}}108 * @type {{readonly LEFT: 'left', readonly RIGHT: 'right'}}
98 */109 */
99export const SWIPE_DIRECTION = {110export const SWIPE_DIRECTION = {
public/scripts/extensions/caption/index.js+2 -2
@@ -10,7 +10,7 @@ import { SlashCommand } from '../../slash-commands/SlashCommand.js';
10import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';10import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';
11import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';11import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';
12import { callGenericPopup, Popup, POPUP_TYPE } from '../../popup.js';12import { callGenericPopup, Popup, POPUP_TYPE } from '../../popup.js';
13import { MEDIA_DISPLAY, MEDIA_TYPE } from '../../constants.js';13import { MEDIA_DISPLAY, MEDIA_TYPE, SCROLL_BEHAVIOR } from '../../constants.js';
14export { MODULE_NAME };14export { MODULE_NAME };
1515
16const MODULE_NAME = 'caption';16const MODULE_NAME = 'caption';
@@ -692,7 +692,7 @@ jQuery(async function () {
692 const imageIndex = Number(imageBlock.attr('data-index'));692 const imageIndex = Number(imageBlock.attr('data-index'));
693 const data = getContext().chat[messageId];693 const data = getContext().chat[messageId];
694 await captionExistingMessage(data, imageIndex);694 await captionExistingMessage(data, imageIndex);
695 appendMediaToMessage(data, messageBlock, false);695 appendMediaToMessage(data, messageBlock, SCROLL_BEHAVIOR.KEEP);
696 await saveChatConditional();696 await saveChatConditional();
697 } catch (e) {697 } catch (e) {
698 console.error('Message image recaption failed', e);698 console.error('Message image recaption failed', e);
public/scripts/extensions/stable-diffusion/index.js+2 -2
@@ -52,7 +52,7 @@ import {
52 SlashCommandArgument,52 SlashCommandArgument,
53 SlashCommandNamedArgument,53 SlashCommandNamedArgument,
54} from '../../slash-commands/SlashCommandArgument.js';54} from '../../slash-commands/SlashCommandArgument.js';
55import { debounce_timeout, MEDIA_DISPLAY, MEDIA_TYPE, VIDEO_EXTENSIONS } from '../../constants.js';55import { debounce_timeout, MEDIA_DISPLAY, MEDIA_TYPE, SCROLL_BEHAVIOR, VIDEO_EXTENSIONS } from '../../constants.js';
56import { SlashCommandEnumValue } from '../../slash-commands/SlashCommandEnumValue.js';56import { SlashCommandEnumValue } from '../../slash-commands/SlashCommandEnumValue.js';
57import { callGenericPopup, Popup, POPUP_TYPE } from '../../popup.js';57import { callGenericPopup, Popup, POPUP_TYPE } from '../../popup.js';
58import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';58import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';
@@ -4290,7 +4290,7 @@ async function sdMessageButton(e) {
4290 message.extra.media.push(newMediaAttachment);4290 message.extra.media.push(newMediaAttachment);
4291 message.extra.media_index = message.extra.media.length - 1;4291 message.extra.media_index = message.extra.media.length - 1;
42924292
4293 appendMediaToMessage(message, messageElement, false);4293 appendMediaToMessage(message, messageElement, SCROLL_BEHAVIOR.KEEP);
42944294
4295 await context.saveChat();4295 await context.saveChat();
4296}4296}