Refactor: Replace Deprecated Code (#4221) * refactor: :recycle: Replace deprecated code defined within this repository - Replace ““/public/scripts.js” > `callPopup`” with ““/public/scripts/popup.js” > `callGenericPopup`”. - Replace ““/public/scripts/tokenizers.js” > `getTokenCount`” with ““/public/scripts/tokenizers.js” > `getTokenCountAsync`”. - Replace ““/public/scripts/extensions/assets/index.js” > `executeSlashCommands`” with ““/public/scripts/extensions/assets/index.js” > `executeSlashCommandsWithOptions`”. * refactor: :recycle: Replace deprecated code from standard library 1. Replace set of deprecated `escape` and deprecated `unescape` functions with `encodeURIComponent` and `decodeURIComponent` functions. 2. Replace set of `encodeURIComponent` and deprecated `unescape` functions with a custom `convertTextToBinaryString` function. * refactor: :recycle: Replace deprecated code imported from external library All of them is from jQuery. 1. Replace `$(document).ready(() => { ... })` → `jQuery(() => { ... })`. 2. Replace event type direct calls. 1) Change - `$('...').change(function () { ... })` → `$('...').on('change', function () { ... })`. 2) Click - `$('...').click(function () { ... })` → `$('...').on('click', function () { ... })`. - `$('...').click()` → `$('...').trigger('click')`. 3) Focus - `$('...').focus(function () { ... })` → `$('...').on('focus', function () { ... })`. - `$('...').focus()` → `$('...').trigger('focus')`. 4) Blur - `$('...').blur(function () { ... })` → `$('...').on('blur', function () { ... })`. 5) Keyup - `$('...').keyup(function () { ... })` → `$('...').on('keyup', function () { ... })`. * refactor(Attachment): :recycle: Merge `convertTextToBinaryString` and `convertTextToBase64` `convertTextToBase64` function use `Uint8Array.prototype.toBase64` if supported by the Browser and use a combination of `Window.btoa` and `String.fromCharCode` as fallback. * fix: :bug: Fix Bind World Info to Character Card Using the new `Popup` class. * fix: :bug: Fix Bind World Info to Character Card Using the new `Popup` class. * refactor: 🐛 Refactor and fix Character World Info popup Add singleton back and some optimization. - **🛡️ Singleton Pattern:** Implemented a singleton pattern using the `characterWorldPopup` variable. This prevents multiple instances of the popup from being created, ensuring a clean and predictable UI. If the popup is already open, it will be brought into focus instead of creating a duplicate. - **♻️ Improved Readability:** The event handling logic has been extracted into clearly named functions (`handlePrimaryWorldSelect`, `handleExtrasWorldSelect`), making the `Popup` constructor cleaner and the overall code more readable and maintainable. - **⚙️ Optimized Performance:** The new implementation caches frequently accessed values and jQuery selectors, reducing redundant DOM lookups and improving performance. --- * refactor(Chat): ♻️ Modernize chat deletion confirmation Replaces the deprecated `callPopup` with the modern `callGenericPopup` for the chat deletion confirmation dialog. * Fix /delchat command * Remove unused code * Fix type. Change value to debug log * Remove value logs * Remove singleton pattern for openCharacterWorldPopup --------- Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
Signed| @@ -3560,7 +3560,7 @@ class StreamingProcessor { | ||
| 3560 | 3560 | |
| 3561 | 3561 | // Token count update. |
| 3562 | 3562 | const tokenCountText = this.reasoningHandler.reasoning + processedText; |
| 3563 | 3563 | const currentTokenCount = isFinal && power_user.message_token_count_enabled ? getTokenCountawait getTokenCountAsync(tokenCountText, 0) : 0; |
| 3564 | 3564 | if (currentTokenCount) { |
| 3565 | 3565 | chat[messageId]['extra']['token_count'] = currentTokenCount; |
| 3566 | 3566 | if (this.messageTokenCounterDom instanceof HTMLElement) { |
| @@ -8930,19 +8930,25 @@ function updateAlternateGreetingsHintVisibility(root) { | ||
| 8930 | 8930 | $(root).find('.alternate_grettings_hint').toggle(numberOfGreetings == 0); |
| 8931 | 8931 | } |
| 8932 | 8932 | |
| 8933 | 8933 | async function openCharacterWorldPopup() { |
| 8934 | 8934 | const chid = $('#set_character_world').data('chid'); |
| 8935 | - | |
| 8936 | 8935 | if (menu_type != 'create' && chid === undefined) { |
| 8937 | 8936 | toastr.error('Does not have an Id for this character in world select menu.'); |
| 8938 | 8937 | return; |
| 8939 | 8938 | } |
| 8940 | 8939 | |
| 8941 | - async function onSelectCharacterWorld() { | |
| 8940 | + // TODO: Maybe make this utility function not use the window context? | |
| 8942 | - const value = $('.character_world_info_selector').find('option:selected').val(); | |
| 8941 | + const fileName = getCharaFilename(chid); | |
| 8943 | 8942 | const worldIndexcharName = value(menu_type !== 'create' ? Number(value)create_save.name : NaNcharacters[chid]?.data?.name) || 'Nameless'; |
| 8944 | - const name = !isNaN(worldIndex) ? world_names[worldIndex] : ''; | |
| 8943 | + const worldId = (menu_type == 'create' ? create_save.world : characters[chid]?.data?.extensions?.world) || ''; | |
| 8944 | + const template = $('#character_world_template .character_world').clone(); | |
| 8945 | + template.find('.character_name').text(charName); | |
| 8945 | 8946 | |
| 8947 | + // --- Event Handlers --- | |
| 8948 | + async function handlePrimaryWorldSelect() { | |
| 8949 | + const selectedValue = $(this).val(); | |
| 8950 | + const worldIndex = selectedValue !== '' ? Number(selectedValue) : NaN; | |
| 8951 | + const name = !isNaN(worldIndex) ? world_names[worldIndex] : ''; | |
| 8946 | 8952 | const previousValue = $('#character_world').val(); |
| 8947 | 8953 | $('#character_world').val(name); |
| 8948 | 8954 | |
| @@ -8970,26 +8976,21 @@ function openCharacterWorldPopup() { | ||
| 8970 | 8976 | await createOrEditCharacter(); |
| 8971 | 8977 | } |
| 8972 | 8978 | |
| 8973 | 8979 | setWorldInfoButtonClass(undefined, !!valuename); |
| 8974 | 8980 | } |
| 8975 | 8981 | |
| 8976 | 8982 | function onExtraWorldInfoChangedhandleExtrasWorldSelect() { |
| 8977 | 8983 | const selectorFieldValueselectedValues = $('.character_extra_world_info_selector'this).val(); |
| 8978 | 8984 | const selectedWorlds = Array.isArray(selectorFieldValueselectedValues) ? selectorFieldValueselectedValues : []; |
| 8979 | 8985 | let charLore = world_info.charLore ?? []; |
| 8980 | - | |
| 8986 | + const tempExtraBooks = selectedWorlds.map((index) => world_names[index]).filter(Boolean); | |
| 8981 | - // TODO: Maybe make this utility function not use the window context? | |
| 8982 | - const fileName = getCharaFilename(chid); | |
| 8983 | - const tempExtraBooks = selectedWorlds.map((index) => world_names[index]).filter((e) => e !== undefined); | |
| 8984 | - | |
| 8985 | 8987 | const existingCharIndex = charLore.findIndex((e) => e.name === fileName); |
| 8986 | - if (existingCharIndex === -1) { | |
| 8987 | - const newCharLoreEntry = { | |
| 8988 | - name: fileName, | |
| 8989 | - extraBooks: tempExtraBooks, | |
| 8990 | - }; | |
| 8991 | 8988 | |
| 8992 | - charLore.push(newCharLoreEntry); | |
| 8989 | + if (existingCharIndex === -1) { | |
| 8990 | + // Add record only if at least 1 lorebook is selected. | |
| 8991 | + if (tempExtraBooks.length > 0) { | |
| 8992 | + charLore.push({ name: fileName, extraBooks: tempExtraBooks }); | |
| 8993 | + } | |
| 8993 | 8994 | } else if (tempExtraBooks.length === 0) { |
| 8994 | 8995 | charLore.splice(existingCharIndex, 1); |
| 8995 | 8996 | } else { |
| @@ -9000,62 +9001,42 @@ function openCharacterWorldPopup() { | ||
| 9000 | 9001 | saveSettingsDebounced(); |
| 9001 | 9002 | } |
| 9002 | 9003 | |
| 9003 | - const template = $('#character_world_template .character_world').clone(); | |
| 9004 | + // --- Populate Dropdowns --- | |
| 9004 | - const select = template.find('.character_world_info_selector'); | |
| 9005 | + // Append to primary dropdown. | |
| 9005 | 9006 | const extraSelectprimarySelect = template.find('.character_extra_world_info_selectorcharacter_world_info_selector'); |
| 9006 | - const name = (menu_type == 'create' ? create_save.name : characters[chid]?.data?.name) || 'Nameless'; | |
| 9007 | + world_names.forEach((item, i) => { | |
| 9007 | - const worldId = (menu_type == 'create' ? create_save.world : characters[chid]?.data?.extensions?.world) || ''; | |
| 9008 | + primarySelect.append(new Option(item, String(i), item === worldId, item === worldId)); | |
| 9008 | - template.find('.character_name').text(name); | |
| 9009 | - | |
| 9010 | - // Not needed on mobile | |
| 9011 | - if (!isMobile()) { | |
| 9012 | - $(extraSelect).select2({ | |
| 9013 | - width: '100%', | |
| 9014 | - placeholder: t`No auxillary Lorebooks set. Click here to select.`, | |
| 9015 | - allowClear: true, | |
| 9016 | - closeOnSelect: false, | |
| 9017 | 9009 | }); |
| 9018 | - } | |
| 9019 | 9010 | |
| 9020 | 9011 | // AppedAppend to baseextras dropdown. |
| 9012 | + const extrasSelect = template.find('.character_extra_world_info_selector'); | |
| 9013 | + const existingCharLore = world_info.charLore?.find((e) => e.name === fileName); | |
| 9021 | 9014 | world_names.forEach((item, i) => { |
| 9022 | 9015 | const optionisSelected = document!!existingCharLore?.createElementextraBooks.includes('option'item); |
| 9023 | - option.value = String(i); | |
| 9016 | + extrasSelect.append(new Option(item, String(i), isSelected, isSelected)); | |
| 9024 | - option.innerText = item; | |
| 9025 | - option.selected = item === worldId; | |
| 9026 | - select.append(option); | |
| 9027 | 9017 | }); |
| 9028 | 9018 | |
| 9029 | - // Append to extras dropdown | |
| 9019 | + const popup = new Popup(template, POPUP_TYPE.TEXT, '', { | |
| 9030 | - if (world_names.length > 0) { | |
| 9020 | + onOpen: function (popup) { | |
| 9031 | - extraSelect.empty(); | |
| 9021 | + const popupDialog = $(popup.dlg); | |
| 9032 | - } | |
| 9033 | - world_names.forEach((item, i) => { | |
| 9034 | - const option = document.createElement('option'); | |
| 9035 | - option.value = String(i); | |
| 9036 | - option.innerText = item; | |
| 9037 | 9022 | |
| 9038 | - const existingCharLore = world_info.charLore?.find((e) => e.name === getCharaFilename()); | |
| 9023 | + primarySelect.on('change', handlePrimaryWorldSelect); | |
| 9039 | - if (existingCharLore) { | |
| 9024 | + extrasSelect.on('change', handleExtrasWorldSelect); | |
| 9040 | - option.selected = existingCharLore.extraBooks.includes(item); | |
| 9041 | - } else { | |
| 9042 | - option.selected = false; | |
| 9043 | - } | |
| 9044 | - extraSelect.append(option); | |
| 9045 | - }); | |
| 9046 | 9025 | |
| 9047 | - select.on('change', onSelectCharacterWorld); | |
| 9026 | + // Not needed on mobile. | |
| 9048 | - extraSelect.on('mousedown change', async function (e) { | |
| 9027 | + if (!isMobile()) { | |
| 9049 | - // If there's no world names, don't do anything | |
| 9028 | + extrasSelect.select2({ | |
| 9050 | - if (world_names.length === 0) { | |
| 9029 | + width: '100%', | |
| 9051 | - e.preventDefault(); | |
| 9030 | + placeholder: t`No auxiliary Lorebooks set. Click here to select.`, | |
| 9052 | - return; | |
| 9031 | + allowClear: true, | |
| 9032 | + closeOnSelect: false, | |
| 9033 | + dropdownParent: popupDialog, | |
| 9034 | + }); | |
| 9053 | 9035 | } |
| 9054 | - | |
| 9036 | + }, | |
| 9055 | - onExtraWorldInfoChanged(); | |
| 9056 | 9037 | }); |
| 9057 | 9038 | |
| 9058 | - callPopup(template, 'text'); | |
| 9039 | + await popup.show(); | |
| 9059 | 9040 | } |
| 9060 | 9041 | |
| 9061 | 9042 | function openAlternateGreetings() { |
| @@ -10089,12 +10070,32 @@ export async function doNewChat({ deleteCurrentChat = false } = {}) { | ||
| 10089 | 10070 | } |
| 10090 | 10071 | |
| 10091 | 10072 | async function doDeleteChat() { |
| 10092 | - await displayPastChats(); | |
| 10073 | + return displayPastChats().then(() => new Promise((resolve) => { | |
| 10093 | - let currentChatDeleteButton = $('.select_chat_block[highlight=\'true\']').parent().find('.PastChat_cross'); | |
| 10074 | + let resolved = false; | |
| 10094 | - $(currentChatDeleteButton).trigger('click'); | |
| 10075 | + const timeOutId = setTimeout(() => { | |
| 10095 | - await delay(1); | |
| 10076 | + toastr.error(t`Chat deletion timed out. Please try again.`); | |
| 10096 | - $('#dialogue_popup_ok').trigger('click', { fromSlashCommand: true }); | |
| 10077 | + setResolved(); | |
| 10097 | - return ''; | |
| 10078 | + }, 5000); | |
| 10079 | + | |
| 10080 | + const setResolved = () => { | |
| 10081 | + if (resolved) { | |
| 10082 | + return; | |
| 10083 | + } | |
| 10084 | + resolved = true; | |
| 10085 | + [event_types.CHAT_DELETED, event_types.GROUP_CHAT_DELETED].forEach((eventType) => { | |
| 10086 | + eventSource.removeListener(eventType, setResolved); | |
| 10087 | + }); | |
| 10088 | + clearTimeout(timeOutId); | |
| 10089 | + resolve(''); | |
| 10090 | + }; | |
| 10091 | + | |
| 10092 | + [event_types.CHAT_DELETED, event_types.GROUP_CHAT_DELETED].forEach((eventType) => { | |
| 10093 | + eventSource.on(eventType, setResolved); | |
| 10094 | + }); | |
| 10095 | + | |
| 10096 | + const currentChatDeleteButton = $('.select_chat_block[highlight=\'true\']').parent().find('.PastChat_cross'); | |
| 10097 | + $(currentChatDeleteButton).trigger('click', { fromSlashCommand: true }); | |
| 10098 | + })); | |
| 10098 | 10099 | } |
| 10099 | 10100 | |
| 10100 | 10101 | async function doRenameChat(_, chatName) { |
| @@ -10764,10 +10765,10 @@ jQuery(async function () { | ||
| 10764 | 10765 | }); |
| 10765 | 10766 | $('#send_but, #option_regenerate, #option_continue, #mes_continue, #mes_impersonate').on('click', () => { |
| 10766 | 10767 | if (S_TAPreviouslyFocused) { |
| 10767 | 10768 | $('#send_textarea').focustrigger('focus'); |
| 10768 | 10769 | } |
| 10769 | 10770 | }); |
| 10770 | 10771 | $(document).clickon('click', event => { |
| 10771 | 10772 | if ($(':focus').attr('id') !== 'send_textarea') { |
| 10772 | 10773 | var validIDs = ['options_button', 'send_but', 'mes_impersonate', 'mes_continue', 'send_textarea', 'option_regenerate', 'option_continue']; |
| 10773 | 10774 | if (!validIDs.includes($(event.target).attr('id'))) { |
| @@ -10780,7 +10781,7 @@ jQuery(async function () { | ||
| 10780 | 10781 | |
| 10781 | 10782 | ///////////////// |
| 10782 | 10783 | |
| 10783 | 10784 | $('#swipes-checkbox').changeon('change', function () { |
| 10784 | 10785 | swipes = !!$('#swipes-checkbox').prop('checked'); |
| 10785 | 10786 | if (swipes) { |
| 10786 | 10787 | //console.log('toggle change calling showswipebtns'); |
| @@ -10923,11 +10924,51 @@ jQuery(async function () { | ||
| 10923 | 10924 | } |
| 10924 | 10925 | }); |
| 10925 | 10926 | |
| 10926 | - $(document).on('click', '.PastChat_cross', function (e) { | |
| 10927 | + /** | |
| 10928 | + * Handles the deletion of a chat file, including group chats. | |
| 10929 | + * | |
| 10930 | + * @param {string} chatFile - The name of the chat file to delete. | |
| 10931 | + * @param {object} group - The group object if the chat is part of a group. | |
| 10932 | + * @param {boolean} [fromSlashCommand=false] - Whether the deletion was triggered from a slash command. | |
| 10933 | + * @returns {Promise<void>} | |
| 10934 | + */ | |
| 10935 | + async function handleDeleteChat(chatFile, group, fromSlashCommand = false) { | |
| 10936 | + // Close past chat popup. | |
| 10937 | + $('#select_chat_cross').trigger('click'); | |
| 10938 | + showLoader(); | |
| 10939 | + if (group) { | |
| 10940 | + await deleteGroupChat(group, chatFile); | |
| 10941 | + } else { | |
| 10942 | + await delChat(chatFile); | |
| 10943 | + } | |
| 10944 | + | |
| 10945 | + if (fromSlashCommand) { // When called from `/delchat` command, don't re-open the history view. | |
| 10946 | + $('#options').hide(); // Hide option popup menu. | |
| 10947 | + hideLoader(); | |
| 10948 | + } else { // Open the history view again after 2 seconds (delay to avoid edge cases for deleting last chat). | |
| 10949 | + setTimeout(function () { | |
| 10950 | + $('#option_select_chat').trigger('click'); | |
| 10951 | + $('#options').hide(); // Hide option popup menu. | |
| 10952 | + hideLoader(); | |
| 10953 | + }, 2000); | |
| 10954 | + } | |
| 10955 | + } | |
| 10956 | + | |
| 10957 | + $(document).on('click', '.PastChat_cross', async function (e, { fromSlashCommand = false } = {}) { | |
| 10927 | 10958 | e.stopPropagation(); |
| 10928 | 10959 | chat_file_for_del = $(this).attr('file_name'); |
| 10929 | 10960 | console.debug('detected cross click for' + chat_file_for_del); |
| 10930 | - callPopup('<h3>' + t`Delete the Chat File?` + '</h3>', 'del_chat'); | |
| 10961 | + | |
| 10962 | + // Skip confirmation if called from a slash command. | |
| 10963 | + if (fromSlashCommand) { | |
| 10964 | + await handleDeleteChat(chat_file_for_del, selected_group, true); | |
| 10965 | + return; | |
| 10966 | + } | |
| 10967 | + | |
| 10968 | + const result = await callGenericPopup('<h3>' + t`Delete the Chat File?` + '</h3>', POPUP_TYPE.CONFIRM); | |
| 10969 | + if (result === POPUP_RESULT.AFFIRMATIVE) { | |
| 10970 | + await handleDeleteChat(chat_file_for_del, selected_group, false); | |
| 10971 | + } | |
| 10931 | 10972 | }); |
| 10932 | 10973 | |
| 10933 | 10974 | $('#advanced_div').on('click', function () { |
| @@ -10976,25 +11017,7 @@ jQuery(async function () { | ||
| 10976 | 11017 | }, animation_duration); |
| 10977 | 11018 | |
| 10978 | 11019 | if (popup_type == 'del_chat') { |
| 10979 | - //close past chat popup | |
| 11020 | + await handleDeleteChat(chat_file_for_del, selected_group, fromSlashCommand); | |
| 10980 | - $('#select_chat_cross').trigger('click'); | |
| 10981 | - showLoader(); | |
| 10982 | - if (selected_group) { | |
| 10983 | - await deleteGroupChat(selected_group, chat_file_for_del); | |
| 10984 | - } else { | |
| 10985 | - await delChat(chat_file_for_del); | |
| 10986 | - } | |
| 10987 | - | |
| 10988 | - if (fromSlashCommand) { // When called from `/delchat` command, don't re-open the history view. | |
| 10989 | - $('#options').hide(); // hide option popup menu | |
| 10990 | - hideLoader(); | |
| 10991 | - } else { // Open the history view again after 2 seconds (delay to avoid edge cases for deleting last chat). | |
| 10992 | - setTimeout(function () { | |
| 10993 | - $('#option_select_chat').trigger('click'); | |
| 10994 | - $('#options').hide(); // hide option popup menu | |
| 10995 | - hideLoader(); | |
| 10996 | - }, 2000); | |
| 10997 | - } | |
| 10998 | 11021 | } |
| 10999 | 11022 | |
| 11000 | 11023 | if (dialogueResolve) { |
| @@ -11457,7 +11480,7 @@ jQuery(async function () { | ||
| 11457 | 11480 | is_delete_mode = false; |
| 11458 | 11481 | }); |
| 11459 | 11482 | |
| 11460 | 11483 | $('#settings_preset').changeon('change', function () { |
| 11461 | 11484 | if ($('#settings_preset').find(':selected').val() != 'gui') { |
| 11462 | 11485 | preset_settings = $('#settings_preset').find(':selected').text(); |
| 11463 | 11486 | const preset = koboldai_settings[koboldai_setting_names[preset_settings]]; |
| @@ -11482,7 +11505,7 @@ jQuery(async function () { | ||
| 11482 | 11505 | saveSettingsDebounced(); |
| 11483 | 11506 | }); |
| 11484 | 11507 | |
| 11485 | 11508 | $('#settings_preset_novel').changeon('change', function () { |
| 11486 | 11509 | nai_settings.preset_settings_novel = $('#settings_preset_novel') |
| 11487 | 11510 | .find(':selected') |
| 11488 | 11511 | .text(); |
| @@ -11495,7 +11518,7 @@ jQuery(async function () { | ||
| 11495 | 11518 | saveSettingsDebounced(); |
| 11496 | 11519 | }); |
| 11497 | 11520 | |
| 11498 | 11521 | $('#main_api').changeon('change', function () { |
| 11499 | 11522 | cancelStatusCheck('Canceled because main api changed'); |
| 11500 | 11523 | changeMainAPI(); |
| 11501 | 11524 | saveSettingsDebounced(); |
| @@ -12023,7 +12046,7 @@ jQuery(async function () { | ||
| 12023 | 12046 | select_rm_characters(); |
| 12024 | 12047 | }); |
| 12025 | 12048 | |
| 12026 | 12049 | $('#dupe_button').clickon('click', async function () { |
| 12027 | 12050 | await duplicateCharacter(); |
| 12028 | 12051 | }); |
| 12029 | 12052 | |
| @@ -12223,18 +12246,18 @@ jQuery(async function () { | ||
| 12223 | 12246 | } |
| 12224 | 12247 | }); |
| 12225 | 12248 | |
| 12226 | 12249 | $(document).keyupon('keyup', function (e) { |
| 12227 | 12250 | if (e.key === 'Escape') { |
| 12228 | 12251 | const isEditVisible = $('#curEditTextarea').is(':visible') || $('.reasoning_edit_textarea').length > 0; |
| 12229 | 12252 | if (isEditVisible && power_user.auto_save_msg_edits === false) { |
| 12230 | 12253 | closeMessageEditor('all'); |
| 12231 | 12254 | $('#send_textarea').focustrigger('focus'); |
| 12232 | 12255 | return; |
| 12233 | 12256 | } |
| 12234 | 12257 | if (isEditVisible && power_user.auto_save_msg_edits === true) { |
| 12235 | 12258 | $(`#chat .mes[mesid="${this_edit_mes_id}"] .mes_edit_done`).trigger('click'); |
| 12236 | 12259 | closeMessageEditor('reasoning'); |
| 12237 | 12260 | $('#send_textarea').focustrigger('focus'); |
| 12238 | 12261 | return; |
| 12239 | 12262 | } |
| 12240 | 12263 | if (!this_edit_mes_id && $('#mes_stop').is(':visible')) { |
| @@ -12251,13 +12274,13 @@ jQuery(async function () { | ||
| 12251 | 12274 | const target = $(targetElement.selectedOptions).attr('id'); |
| 12252 | 12275 | switch (target) { |
| 12253 | 12276 | case 'set_character_world': |
| 12254 | 12277 | await openCharacterWorldPopup(); |
| 12255 | 12278 | break; |
| 12256 | 12279 | case 'set_chat_scenario': |
| 12257 | 12280 | await setScenarioOverride(); |
| 12258 | 12281 | break; |
| 12259 | 12282 | case 'renameCharButton': |
| 12260 | 12283 | await renameCharacter(); |
| 12261 | 12284 | break; |
| 12262 | 12285 | case 'import_character_info': |
| 12263 | 12286 | await importEmbeddedWorldInfo(); |
| @@ -12335,6 +12358,9 @@ jQuery(async function () { | ||
| 12335 | 12358 | }); |
| 12336 | 12359 | |
| 12337 | 12360 | $(document).on('change', '.range-block-counter input, .neo-range-input', function (e) { |
| 12361 | + if (!(e.target instanceof HTMLElement)) { | |
| 12362 | + return; | |
| 12363 | + } | |
| 12338 | 12364 | e.target.focus(); |
| 12339 | 12365 | e.target.dispatchEvent(new KeyboardEvent('keyup', { bubbles: true })); |
| 12340 | 12366 | }); |
| @@ -12355,7 +12381,6 @@ jQuery(async function () { | ||
| 12355 | 12381 | } else { |
| 12356 | 12382 | //if value not ok, warn and reset to last known valid value |
| 12357 | 12383 | toastr.warning(`Invalid value. Must be between ${$(this).attr('min')} and ${$(this).attr('max')}`); |
| 12358 | - console.log(valueBeforeManualInput); | |
| 12359 | 12384 | //newSlider.val(valueBeforeManualInput) |
| 12360 | 12385 | $(this).val(valueBeforeManualInput); |
| 12361 | 12386 | } |
| @@ -12365,7 +12390,6 @@ jQuery(async function () { | ||
| 12365 | 12390 | |
| 12366 | 12391 | $(document).on('keyup', '.range-block-counter input, .neo-range-input', function () { |
| 12367 | 12392 | valueBeforeManualInput = $(this).val(); |
| 12368 | - console.log(valueBeforeManualInput); | |
| 12369 | 12393 | isManualInput = true; |
| 12370 | 12394 | }); |
| 12371 | 12395 | |
| @@ -12383,7 +12407,6 @@ jQuery(async function () { | ||
| 12383 | 12407 | } else { |
| 12384 | 12408 | //if value not ok, warn and reset to last known valid value |
| 12385 | 12409 | toastr.warning(`Invalid value. Must be between ${$(this).attr('min')} and ${$(this).attr('max')}`); |
| 12386 | - console.log(valueBeforeManualInput); | |
| 12387 | 12410 | $(this).val(valueBeforeManualInput); |
| 12388 | 12411 | } |
| 12389 | 12412 | } |
| @@ -434,19 +434,19 @@ function OpenNavPanels() { | ||
| 434 | 434 | //auto-open R nav if locked and previously open |
| 435 | 435 | if (accountStorage.getItem('NavLockOn') == 'true' && accountStorage.getItem('NavOpened') == 'true') { |
| 436 | 436 | //console.log("RA -- clicking right nav to open"); |
| 437 | 437 | $('#rightNavDrawerIcon').clicktrigger('click'); |
| 438 | 438 | } |
| 439 | 439 | |
| 440 | 440 | //auto-open L nav if locked and previously open |
| 441 | 441 | if (accountStorage.getItem('LNavLockOn') == 'true' && accountStorage.getItem('LNavOpened') == 'true') { |
| 442 | 442 | console.debug('RA -- clicking left nav to open'); |
| 443 | 443 | $('#leftNavDrawerIcon').clicktrigger('click'); |
| 444 | 444 | } |
| 445 | 445 | |
| 446 | 446 | //auto-open WI if locked and previously open |
| 447 | 447 | if (accountStorage.getItem('WINavLockOn') == 'true' && accountStorage.getItem('WINavOpened') == 'true') { |
| 448 | 448 | console.debug('RA -- clicking WI to open'); |
| 449 | 449 | $('#WIDrawerIcon').clicktrigger('click'); |
| 450 | 450 | } |
| 451 | 451 | } |
| 452 | 452 | } |
| @@ -711,7 +711,7 @@ export function initRossMods() { | ||
| 711 | 711 | RA_autoconnect(); |
| 712 | 712 | } |
| 713 | 713 | |
| 714 | 714 | $('#main_api').changeon('change', function () { |
| 715 | 715 | var PrevAPI = main_api; |
| 716 | 716 | setTimeout(() => RA_autoconnect(PrevAPI), 100); |
| 717 | 717 | }); |
| @@ -834,11 +834,11 @@ export function initRossMods() { | ||
| 834 | 834 | }); |
| 835 | 835 | |
| 836 | 836 | var chatbarInFocus = false; |
| 837 | 837 | $('#send_textarea').focuson('focus', function () { |
| 838 | 838 | chatbarInFocus = true; |
| 839 | 839 | }); |
| 840 | 840 | |
| 841 | 841 | $('#send_textarea').bluron('blur', function () { |
| 842 | 842 | chatbarInFocus = false; |
| 843 | 843 | }); |
| 844 | 844 | |
| @@ -846,8 +846,8 @@ export function initRossMods() { | ||
| 846 | 846 | OpenNavPanels(); |
| 847 | 847 | }, 300); |
| 848 | 848 | |
| 849 | 849 | $(SelectedCharacterTab).clickon('click', function () { accountStorage.setItem('SelectedNavTab', 'rm_button_selected_ch'); }); |
| 850 | 850 | $('#rm_button_characters').clickon('click', function () { accountStorage.setItem('SelectedNavTab', 'rm_button_characters'); }); |
| 851 | 851 | |
| 852 | 852 | // when a char is selected from the list, save them as the auto-load character for next page load |
| 853 | 853 | |
| @@ -932,7 +932,7 @@ export function initRossMods() { | ||
| 932 | 932 | var SwipeTargetMesClassParent = $(e.target).closest('.last_mes'); |
| 933 | 933 | if (SwipeTargetMesClassParent !== null) { |
| 934 | 934 | if (SwipeButR.css('display') === 'flex') { |
| 935 | 935 | SwipeButR.clicktrigger('click'); |
| 936 | 936 | } |
| 937 | 937 | } |
| 938 | 938 | }); |
| @@ -956,7 +956,7 @@ export function initRossMods() { | ||
| 956 | 956 | var SwipeTargetMesClassParent = $(e.target).closest('.last_mes'); |
| 957 | 957 | if (SwipeTargetMesClassParent !== null) { |
| 958 | 958 | if (SwipeButL.css('display') === 'flex') { |
| 959 | 959 | SwipeButL.clicktrigger('click'); |
| 960 | 960 | } |
| 961 | 961 | } |
| 962 | 962 | }); |
| @@ -1159,7 +1159,7 @@ export function initRossMods() { | ||
| 1159 | 1159 | const lastMes = document.querySelector('.last_mes'); |
| 1160 | 1160 | const editMes = lastMes.querySelector('.mes_block .mes_edit'); |
| 1161 | 1161 | if (editMes !== null) { |
| 1162 | 1162 | $(editMes).clicktrigger('click'); |
| 1163 | 1163 | return; |
| 1164 | 1164 | } |
| 1165 | 1165 | } |
| @@ -135,7 +135,7 @@ function onCfgMenuItemClick() { | ||
| 135 | 135 | .siblings('.inline-drawer-content') |
| 136 | 136 | .css('display') !== 'block') { |
| 137 | 137 | $('#floatingPrompt').addClass('resizing'); |
| 138 | 138 | $('#CFGBlockToggle').clicktrigger('click'); |
| 139 | 139 | } |
| 140 | 140 | } else { |
| 141 | 141 | //hide AN if it's already displayed |
| @@ -44,6 +44,7 @@ import { | ||
| 44 | 44 | download, |
| 45 | 45 | getFileText, |
| 46 | 46 | getFileExtension, |
| 47 | + convertTextToBase64, | |
| 47 | 48 | } from './utils.js'; |
| 48 | 49 | import { extension_settings, renderExtensionTemplateAsync, saveMetadataDebounced } from './extensions.js'; |
| 49 | 50 | import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js'; |
| @@ -224,7 +225,7 @@ export async function populateFileAttachment(message, inputId = 'file_form_input | ||
| 224 | 225 | try { |
| 225 | 226 | const converter = getConverter(file.type); |
| 226 | 227 | const fileText = await converter(file); |
| 227 | 228 | base64Data = window.btoa(unescape(encodeURIComponentconvertTextToBase64(fileText))); |
| 228 | 229 | } catch (error) { |
| 229 | 230 | toastr.error(String(error), t`Could not convert file`); |
| 230 | 231 | console.error('Could not convert file', error); |
| @@ -477,7 +478,7 @@ export async function appendFileContent(message, messageText) { | ||
| 477 | 478 | export function encodeStyleTags(text) { |
| 478 | 479 | const styleRegex = /<style>(.+?)<\/style>/gims; |
| 479 | 480 | return text.replaceAll(styleRegex, (_, match) => { |
| 480 | 481 | return `<custom-style>${escapeencodeURIComponent(match)}</custom-style>`; |
| 481 | 482 | }); |
| 482 | 483 | } |
| 483 | 484 | |
| @@ -530,7 +531,7 @@ export function decodeStyleTags(text, { prefix } = { prefix: '.mes_text ' }) { | ||
| 530 | 531 | |
| 531 | 532 | return text.replaceAll(styleDecodeRegex, (_, style) => { |
| 532 | 533 | try { |
| 533 | 534 | let styleCleaned = unescapedecodeURIComponent(style).replaceAll(/<br\/>/g, ''); |
| 534 | 535 | const ast = css.parse(styleCleaned); |
| 535 | 536 | const sheet = ast?.stylesheet; |
| 536 | 537 | if (sheet) { |
| @@ -1497,14 +1498,14 @@ export async function uploadFileAttachmentToServer(file, target) { | ||
| 1497 | 1498 | try { |
| 1498 | 1499 | const converter = getConverter(file.type); |
| 1499 | 1500 | const fileText = await converter(file); |
| 1500 | 1501 | base64Data = window.btoa(unescape(encodeURIComponentconvertTextToBase64(fileText))); |
| 1501 | 1502 | } catch (error) { |
| 1502 | 1503 | toastr.error(String(error), t`Could not convert file`); |
| 1503 | 1504 | console.error('Could not convert file', error); |
| 1504 | 1505 | } |
| 1505 | 1506 | } else { |
| 1506 | 1507 | const fileText = await file.text(); |
| 1507 | 1508 | base64Data = window.btoa(unescape(encodeURIComponentconvertTextToBase64(fileText))); |
| 1508 | 1509 | } |
| 1509 | 1510 | |
| 1510 | 1511 | const fileUrl = await uploadFileAttachment(uniqueFileName, base64Data); |
| @@ -7,7 +7,7 @@ import { DOMPurify } from '../../../lib.js'; | ||
| 7 | 7 | import { getRequestHeaders, processDroppedFiles, eventSource, event_types } from '../../../script.js'; |
| 8 | 8 | import { deleteExtension, extensionNames, getContext, installExtension, renderExtensionTemplateAsync } from '../../extensions.js'; |
| 9 | 9 | import { POPUP_TYPE, Popup, callGenericPopup } from '../../popup.js'; |
| 10 | 10 | import { executeSlashCommandsexecuteSlashCommandsWithOptions } from '../../slash-commands.js'; |
| 11 | 11 | import { accountStorage } from '../../util/AccountStorage.js'; |
| 12 | 12 | import { flashHighlight, getStringHash, isValidUrl } from '../../utils.js'; |
| 13 | 13 | import { t } from '../../i18n.js'; |
| @@ -142,7 +142,7 @@ async function downloadAssetsList(url) { | ||
| 142 | 142 | const assetDelete = async function () { |
| 143 | 143 | if (assetType === 'character') { |
| 144 | 144 | toastr.error('Go to the characters menu to delete a character.', 'Character deletion not supported'); |
| 145 | 145 | await executeSlashCommandsexecuteSlashCommandsWithOptions(`/go ${asset['id']}`); |
| 146 | 146 | return; |
| 147 | 147 | } |
| 148 | 148 | element.off('click'); |
| @@ -9,19 +9,6 @@ import { POPUP_TYPE, callGenericPopup } from '../../popup.js'; | ||
| 9 | 9 | import { renderExtensionTemplateAsync } from '../../extensions.js'; |
| 10 | 10 | import { t } from '../../i18n.js'; |
| 11 | 11 | |
| 12 | -function rgb2hex(rgb) { | |
| 13 | - rgb = rgb.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i); | |
| 14 | - return (rgb && rgb.length === 4) ? '#' + | |
| 15 | - ('0' + parseInt(rgb[1], 10).toString(16)).slice(-2) + | |
| 16 | - ('0' + parseInt(rgb[2], 10).toString(16)).slice(-2) + | |
| 17 | - ('0' + parseInt(rgb[3], 10).toString(16)).slice(-2) : ''; | |
| 18 | -} | |
| 19 | - | |
| 20 | -$('button').click(function () { | |
| 21 | - var hex = rgb2hex($('input').val()); | |
| 22 | - $('.result').html(hex); | |
| 23 | -}); | |
| 24 | - | |
| 25 | 12 | async function doTokenCounter() { |
| 26 | 13 | const { tokenizerName, tokenizerId } = getFriendlyTokenizerName(main_api); |
| 27 | 14 | const html = await renderExtensionTemplateAsync('token-counter', 'window', { tokenizerName }); |
| @@ -296,20 +296,20 @@ class AllTalkTtsProvider { | ||
| 296 | 296 | const ttsNarrateDialoguesCheckbox = document.getElementById('tts_narrate_dialogues'); |
| 297 | 297 | if (this.settings.narrator_enabled) { |
| 298 | 298 | ttsPassAsterisksCheckbox.checked = false; |
| 299 | 299 | $('#tts_pass_asterisks').clicktrigger('click'); |
| 300 | 300 | $('#tts_pass_asterisks').trigger('change'); |
| 301 | 301 | } |
| 302 | 302 | if (!this.settings.narrator_enabled) { |
| 303 | 303 | ttsPassAsterisksCheckbox.checked = true; |
| 304 | 304 | $('#tts_pass_asterisks').clicktrigger('click'); |
| 305 | 305 | $('#tts_pass_asterisks').trigger('change'); |
| 306 | 306 | } |
| 307 | 307 | if (this.settings.narrator_enabled) { |
| 308 | 308 | ttsNarrateQuotedCheckbox.checked = true; |
| 309 | 309 | ttsNarrateDialoguesCheckbox.checked = true; |
| 310 | 310 | $('#tts_narrate_quoted').clicktrigger('click'); |
| 311 | 311 | $('#tts_narrate_quoted').trigger('change'); |
| 312 | 312 | $('#tts_narrate_dialogues').clicktrigger('click'); |
| 313 | 313 | $('#tts_narrate_dialogues').trigger('change'); |
| 314 | 314 | } |
| 315 | 315 | atNarratorSelect.value = this.settings.narrator_enabled.toString(); |
| @@ -783,21 +783,21 @@ class AllTalkTtsProvider { | ||
| 783 | 783 | |
| 784 | 784 | if (narratorOption === 'true') { |
| 785 | 785 | ttsPassAsterisksCheckbox.checked = false; |
| 786 | 786 | $('#tts_pass_asterisks').clicktrigger('click'); |
| 787 | 787 | $('#tts_pass_asterisks').trigger('change'); |
| 788 | 788 | ttsNarrateQuotedCheckbox.checked = true; |
| 789 | 789 | ttsNarrateDialoguesCheckbox.checked = true; |
| 790 | 790 | $('#tts_narrate_quoted').clicktrigger('click'); |
| 791 | 791 | $('#tts_narrate_quoted').trigger('change'); |
| 792 | 792 | $('#tts_narrate_dialogues').clicktrigger('click'); |
| 793 | 793 | $('#tts_narrate_dialogues').trigger('change'); |
| 794 | 794 | } else if (narratorOption === 'silent') { |
| 795 | 795 | ttsPassAsterisksCheckbox.checked = false; |
| 796 | 796 | $('#tts_pass_asterisks').clicktrigger('click'); |
| 797 | 797 | $('#tts_pass_asterisks').trigger('change'); |
| 798 | 798 | } else { |
| 799 | 799 | ttsPassAsterisksCheckbox.checked = true; |
| 800 | 800 | $('#tts_pass_asterisks').clicktrigger('click'); |
| 801 | 801 | $('#tts_pass_asterisks').trigger('change'); |
| 802 | 802 | } |
| 803 | 803 | |
| @@ -837,7 +837,7 @@ jQuery(function () { | ||
| 837 | 837 | saveSettingsDebounced(); |
| 838 | 838 | }); |
| 839 | 839 | |
| 840 | 840 | $('#model_novel_select').changeon('change', function () { |
| 841 | 841 | nai_settings.model_novel = String($('#model_novel_select').find(':selected').val()); |
| 842 | 842 | saveSettingsDebounced(); |
| 843 | 843 | |
| @@ -3151,7 +3151,7 @@ export function forceCharacterEditorTokenize() { | ||
| 3151 | 3151 | $('#character_popup').trigger('input'); |
| 3152 | 3152 | } |
| 3153 | 3153 | |
| 3154 | 3154 | $(document).readyjQuery(() => { |
| 3155 | 3155 | const adjustAutocompleteDebounced = debounce(() => { |
| 3156 | 3156 | $('.ui-autocomplete-input').each(function () { |
| 3157 | 3157 | const isOpen = $(this).autocomplete('widget')[0].style.display !== 'none'; |
| @@ -3236,7 +3236,7 @@ $(document).ready(() => { | ||
| 3236 | 3236 | }); |
| 3237 | 3237 | |
| 3238 | 3238 | // Settings that go to settings.json |
| 3239 | 3239 | $('#collapse-newlines-checkbox').changeon('change', function () { |
| 3240 | 3240 | power_user.collapse_newlines = !!$(this).prop('checked'); |
| 3241 | 3241 | saveSettingsDebounced(); |
| 3242 | 3242 | }); |
| @@ -3244,7 +3244,7 @@ $(document).ready(() => { | ||
| 3244 | 3244 | // include newline is the child of trim sentences |
| 3245 | 3245 | // if include newline is checked, trim sentences must be checked |
| 3246 | 3246 | // if trim sentences is unchecked, include newline must be unchecked |
| 3247 | 3247 | $('#trim_sentences_checkbox').changeon('change', function () { |
| 3248 | 3248 | power_user.trim_sentences = !!$(this).prop('checked'); |
| 3249 | 3249 | saveSettingsDebounced(); |
| 3250 | 3250 | }); |
| @@ -3293,7 +3293,7 @@ $(document).ready(() => { | ||
| 3293 | 3293 | |
| 3294 | 3294 | $('#bind_model_templates').on('change', updateBindModelTemplatesState); |
| 3295 | 3295 | |
| 3296 | 3296 | $('#always-force-name2-checkbox').changeon('change', function () { |
| 3297 | 3297 | power_user.always_force_name2 = !!$(this).prop('checked'); |
| 3298 | 3298 | saveSettingsDebounced(); |
| 3299 | 3299 | }); |
| @@ -3309,7 +3309,7 @@ $(document).ready(() => { | ||
| 3309 | 3309 | saveSettingsDebounced(); |
| 3310 | 3310 | }); |
| 3311 | 3311 | |
| 3312 | 3312 | $('#chat-show-reply-prefix-checkbox').changeon('change', function () { |
| 3313 | 3313 | power_user.show_user_prompt_bias = !!$(this).prop('checked'); |
| 3314 | 3314 | reloadCurrentChat(); |
| 3315 | 3315 | saveSettingsDebounced(); |
| @@ -3355,7 +3355,7 @@ $(document).ready(() => { | ||
| 3355 | 3355 | saveSettingsDebounced(); |
| 3356 | 3356 | }); |
| 3357 | 3357 | |
| 3358 | 3358 | $('#fast_ui_mode').changeon('change', function () { |
| 3359 | 3359 | power_user.fast_ui_mode = $(this).prop('checked'); |
| 3360 | 3360 | switchUiMode(); |
| 3361 | 3361 | saveSettingsDebounced(); |
| @@ -3373,13 +3373,13 @@ $(document).ready(() => { | ||
| 3373 | 3373 | applyCustomCSS(); |
| 3374 | 3374 | }); |
| 3375 | 3375 | |
| 3376 | 3376 | $('#movingUImode').changeon('change', function () { |
| 3377 | 3377 | power_user.movingUI = $(this).prop('checked'); |
| 3378 | 3378 | switchMovingUI(); |
| 3379 | 3379 | saveSettingsDebounced(); |
| 3380 | 3380 | }); |
| 3381 | 3381 | |
| 3382 | 3382 | $('#noShadowsmode').changeon('change', function () { |
| 3383 | 3383 | power_user.noShadows = $(this).prop('checked'); |
| 3384 | 3384 | applyNoShadows(); |
| 3385 | 3385 | saveSettingsDebounced(); |
| @@ -3848,7 +3848,7 @@ $(document).ready(() => { | ||
| 3848 | 3848 | saveSettingsDebounced(); |
| 3849 | 3849 | }); |
| 3850 | 3850 | |
| 3851 | 3851 | $('#custom_stopping_strings_macro').changeon('change', function () { |
| 3852 | 3852 | power_user.custom_stopping_strings_macro = !!$(this).prop('checked'); |
| 3853 | 3853 | saveSettingsDebounced(); |
| 3854 | 3854 | }); |
| @@ -46,7 +46,7 @@ function createServerAutocomplete() { | ||
| 46 | 46 | select: (e, u) => selectServer(e, u, serverLabel), |
| 47 | 47 | minLength: 0, |
| 48 | 48 | }) |
| 49 | 49 | .focuson('focus', onInputFocus); // <== show tag list on click |
| 50 | 50 | } |
| 51 | 51 | |
| 52 | 52 | function onInputFocus() { |
| @@ -1301,7 +1301,7 @@ export function createTagInput(inputSelector, listSelector, tagListOptions = {}) | ||
| 1301 | 1301 | select: (e, u) => selectTag(e, u, listSelector, { tagListOptions: tagListOptions }), |
| 1302 | 1302 | minLength: 0, |
| 1303 | 1303 | }) |
| 1304 | 1304 | .focuson('focus', onTagInputFocus); // <== show tag list on click |
| 1305 | 1305 | } |
| 1306 | 1306 | |
| 1307 | 1307 | async function onViewTagsListClick() { |
| @@ -1453,6 +1453,27 @@ export function getFileExtension(file) { | ||
| 1453 | 1453 | } |
| 1454 | 1454 | |
| 1455 | 1455 | /** |
| 1456 | + * Converts UTF-8 string into Base64-encoded string. | |
| 1457 | + * | |
| 1458 | + * @param {string} text The UTF-8 string | |
| 1459 | + * @returns {string} The Base64-encoded string | |
| 1460 | + */ | |
| 1461 | +export function convertTextToBase64(text) { | |
| 1462 | + const encoder = new TextEncoder(); | |
| 1463 | + const utf8Bytes = encoder.encode(text); | |
| 1464 | + /** | |
| 1465 | + * return `true` if `Uint8Array.prototype.toBase64` function is supported. | |
| 1466 | + * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/toBase64|MDN Reference} | |
| 1467 | + */ | |
| 1468 | + if ('toBase64' in Uint8Array.prototype) { | |
| 1469 | + return utf8Bytes.toBase64(); | |
| 1470 | + } | |
| 1471 | + // Creates binary string, where each character's code point directly matches the byte value (0-255). | |
| 1472 | + const binaryString = String.fromCharCode(...utf8Bytes); | |
| 1473 | + return window.btoa(binaryString); | |
| 1474 | +} | |
| 1475 | + | |
| 1476 | +/** | |
| 1456 | 1477 | * Loads either a CSS or JS file and appends it to the appropriate document section. |
| 1457 | 1478 | * |
| 1458 | 1479 | * @param {string} url - The URL of the file to be loaded. |