diff --git a/public/index.html b/public/index.html index 78cddd92e..a5bc480f0 100644 --- a/public/index.html +++ b/public/index.html @@ -2131,6 +2131,11 @@ Chat Timestamps + + + Show Message IDs + + Auto-scroll Chat @@ -3256,6 +3261,7 @@ + diff --git a/public/script.js b/public/script.js index 898cffaa8..41d93ea06 100644 --- a/public/script.js +++ b/public/script.js @@ -1154,6 +1154,7 @@ function getMessageFromTemplate({ mes.find('.ch_name .name_text').text(characterName); mes.find('.mes_bias').html(bias); mes.find('.timestamp').text(timestamp); + mes.find('.mesIDDisplay').text(`#${mesId}`); title && mes.attr('title', title); timerValue && mes.find('.mes_timer').attr('title', timerTitle).text(timerValue); @@ -5413,6 +5414,7 @@ async function importCharacterChat(formData) { function updateViewMessageIds() { $('#chat').find(".mes").each(function (index, element) { $(element).attr("mesid", index); + $(element).find('.mesIDDisplay').text(`#${index}`); }); $('#chat .mes').removeClass('last_mes'); diff --git a/public/scripts/power-user.js b/public/scripts/power-user.js index 5a6330e90..7641eba9a 100644 --- a/public/scripts/power-user.js +++ b/public/scripts/power-user.js @@ -154,6 +154,7 @@ let power_user = { hotswap_enabled: true, timer_enabled: true, timestamps_enabled: true, + mesIDDisplay_enabled: false, max_context_unlocked: false, prefer_character_prompt: true, prefer_character_jailbreak: true, @@ -208,6 +209,7 @@ const storage_keys = { hotswap_enabled: 'HotswapEnabled', timer_enabled: 'TimerEnabled', timestamps_enabled: 'TimestampsEnabled', + mesIDDisplay_enabled: 'mesIDDisplayEnabled', }; let browser_has_focus = true; @@ -285,6 +287,13 @@ function switchTimestamps() { $("#messageTimestampsEnabled").prop("checked", power_user.timestamps_enabled); } +function switchMesIDDisplay() { + const value = localStorage.getItem(storage_keys.mesIDDisplay_enabled); + power_user.mesIDDisplay_enabled = value === null ? true : value == "true"; + $("body").toggleClass("no-mesIDDisplay", !power_user.mesIDDisplay_enabled); + $("#MesIDDisplayEnabled").prop("checked", power_user.mesIDDisplay_enabled); +} + function switchUiMode() { const fastUi = localStorage.getItem(storage_keys.fast_ui_mode); power_user.fast_ui_mode = fastUi === null ? true : fastUi == "true"; @@ -499,6 +508,13 @@ async function applyTheme(name) { switchTimestamps(); } }, + { + key: 'mesIDDisplay_enabled', + action: async () => { + localStorage.setItem(storage_keys.mesIDDisplay_enabled, power_user.mesIDDisplay_enabled); + switchMesIDDisplay(); + } + }, { key: 'hotswap_enabled', action: async () => { @@ -537,6 +553,7 @@ noShadows(); switchHotswap(); switchTimer(); switchTimestamps(); +switchMesIDDisplay(); function loadPowerUserSettings(settings, data) { // Load from settings.json @@ -559,12 +576,14 @@ function loadPowerUserSettings(settings, data) { const hotswap = localStorage.getItem(storage_keys.hotswap_enabled); const timer = localStorage.getItem(storage_keys.timer_enabled); const timestamps = localStorage.getItem(storage_keys.timestamps_enabled); + const mesIDDisplay = localStorage.getItem(storage_keys.mesIDDisplay_enabled); power_user.fast_ui_mode = fastUi === null ? true : fastUi == "true"; power_user.movingUI = movingUI === null ? false : movingUI == "true"; power_user.noShadows = noShadows === null ? false : noShadows == "true"; power_user.hotswap_enabled = hotswap === null ? true : hotswap == "true"; power_user.timer_enabled = timer === null ? true : timer == "true"; power_user.timestamps_enabled = timestamps === null ? true : timestamps == "true"; + power_user.mesIDDisplay_enabled = mesIDDisplay === null ? true : mesIDDisplay == "true"; power_user.avatar_style = Number(localStorage.getItem(storage_keys.avatar_style) ?? avatar_styles.ROUND); power_user.chat_display = Number(localStorage.getItem(storage_keys.chat_display) ?? chat_styles.DEFAULT); power_user.sheld_width = Number(localStorage.getItem(storage_keys.sheld_width) ?? sheld_width.DEFAULT); @@ -614,6 +633,7 @@ function loadPowerUserSettings(settings, data) { $("#hotswapEnabled").prop("checked", power_user.hotswap_enabled); $("#messageTimerEnabled").prop("checked", power_user.timer_enabled); $("#messageTimestampsEnabled").prop("checked", power_user.timestamps_enabled); + $("#mesIDDisplayEnabled").prop("checked", power_user.mesIDDisplay_enabled); $("#prefer_character_prompt").prop("checked", power_user.prefer_character_prompt); $("#prefer_character_jailbreak").prop("checked", power_user.prefer_character_jailbreak); $(`input[name="avatar_style"][value="${power_user.avatar_style}"]`).prop("checked", true); @@ -899,6 +919,7 @@ async function saveTheme() { sheld_width: power_user.sheld_width, timer_enabled: power_user.timer_enabled, timestamps_enabled: power_user.timestamps_enabled, + mesIDDisplay_enabled: power_user.mesIDDisplay_enabled, hotswap_enabled: power_user.hotswap_enabled, }; @@ -989,6 +1010,33 @@ function doRandomChat() { } +async function doMesCut(_, text) { + + //reject invalid args or no args + if (text && isNaN(text) || !text) { + toastr.error('Must enter a message ID number.') + return + } + + //reject attempts to delete firstmes + if (text === 0) { + toastr.error('Cannot delete the First Message') + return + } + + let mesIDToCut = Number(text).toFixed(0) + let mesToCut = $("#chat").find(`.mes[mesid=${mesIDToCut}]`) + + if (!mesToCut.length) { + toastr.error(`Could not find message with ID: ${mesIDToCut}`) + return + } + + mesToCut.find('.mes_edit_delete').trigger('click'); + $('#dialogue_popup_ok').trigger('click'); +} + + async function doDelMode(_, text) { //first enter delmode @@ -1402,6 +1450,13 @@ $(document).ready(() => { switchTimestamps(); }); + $("#mesIDDisplayEnabled").on("input", function () { + const value = !!$(this).prop('checked'); + power_user.mesIDDisplay_enabled = value; + localStorage.setItem(storage_keys.mesIDDisplay_enabled, power_user.mesIDDisplay_enabled); + switchMesIDDisplay(); + }); + $("#hotswapEnabled").on("input", function () { const value = !!$(this).prop('checked'); power_user.hotswap_enabled = value; @@ -1429,8 +1484,9 @@ $(document).ready(() => { browser_has_focus = false; }); - registerSlashCommand('vn', toggleWaifu, ['vn'], ' – swaps Visual Novel Mode On/Off', false, true); + registerSlashCommand('vn', toggleWaifu, [], ' – swaps Visual Novel Mode On/Off', false, true); registerSlashCommand('newchat', doNewChat, ['newchat'], ' – start a new chat with current character', true, true); registerSlashCommand('random', doRandomChat, ['random'], ' – start a new chat with a random character', true, true); - registerSlashCommand('delmode', doDelMode, ['del'], ' – enter message deletion mode', true, true); + registerSlashCommand('delmode', doDelMode, ['del'], '(optional number) – enter message deletion mode, and auto-deletes N messages if numeric argument is provided', true, true); + registerSlashCommand('cut', doMesCut, [], ' (requred number) – cuts the specified message from the chat', true, true); }); diff --git a/public/style.css b/public/style.css index 933b578a0..f767bdd7b 100644 --- a/public/style.css +++ b/public/style.css @@ -193,7 +193,8 @@ table.responsiveTable { text-align: right; } -.mes_text br, .mes_bias br { +.mes_text br, +.mes_bias br { content: ' '; } @@ -230,7 +231,8 @@ table.responsiveTable { padding: 1em; } -.mes .mes_timer { +.mes .mes_timer, +.mes .mesIDDisplay { cursor: default; opacity: 0.7; font-size: calc(var(--mainFontSize) * 0.9); @@ -800,7 +802,8 @@ body.no-timer .mes_timer { display: none !important; } -body.no-timestamps .timestamp { +body.no-timestamps .timestamp, +body.no-mesIDDisplay .mesIDDisplay { display: none !important; } @@ -5001,4 +5004,4 @@ body.waifuMode .zoomed_avatar { background-color: var(--SmartThemeBlurTintColor); text-align: center; line-height: 14px; -} +} \ No newline at end of file