Replace ajax with fetch (#4241) * Replace ajax with fetch Fix type errors in power-user / group-chats modules * Fix single sprite upload * Return empty object on failed upload
Signed| @@ -73,4 +73,10 @@ declare global { | ||
| 73 | 73 | * @param args - The arguments for the conversion function. |
| 74 | 74 | */ |
| 75 | 75 | function convertVideoToAnimatedWebp(args: ConvertVideoArgs): Promise<Uint8Array>; |
| 76 | + | |
| 77 | + interface ColorPickerEvent extends JQuery.ChangeEvent<HTMLElement> { | |
| 78 | + detail: { | |
| 79 | + rgba: string; | |
| 80 | + }; | |
| 81 | + } | |
| 76 | 82 | } |
| @@ -784,11 +784,17 @@ export let active_group = ''; | ||
| 784 | 784 | |
| 785 | 785 | export const entitiesFilter = new FilterHelper(printCharactersDebounced); |
| 786 | 786 | |
| 787 | 787 | export function getRequestHeaders({ omitContentType = false } = {}) { |
| 788 | 788 | returnconst headers = { |
| 789 | 789 | 'Content-Type': 'application/json', |
| 790 | 790 | 'X-CSRF-Token': token, |
| 791 | 791 | }; |
| 792 | + | |
| 793 | + if (omitContentType) { | |
| 794 | + delete headers['Content-Type']; | |
| 795 | + } | |
| 796 | + | |
| 797 | + return headers; | |
| 792 | 798 | } |
| 793 | 799 | |
| 794 | 800 | export function getSlideToggleOptions() { |
| @@ -7078,50 +7084,51 @@ export async function saveSettings(loopCounter = 0) { | ||
| 7078 | 7084 | TempResponseLength.restore(null); |
| 7079 | 7085 | } |
| 7080 | 7086 | |
| 7081 | - //console.log('Entering settings with name1 = '+name1); | |
| 7087 | + const payload = { | |
| 7082 | - return jQuery.ajax({ | |
| 7088 | + firstRun: firstRun, | |
| 7083 | - type: 'POST', | |
| 7089 | + accountStorage: accountStorage.getState(), | |
| 7084 | - url: '/api/settings/save', | |
| 7090 | + currentVersion: currentVersion, | |
| 7085 | - data: JSON.stringify({ | |
| 7091 | + username: name1, | |
| 7086 | 7092 | firstRun active_character: firstRunactive_character, |
| 7087 | - accountStorage: accountStorage.getState(), | |
| 7093 | + active_group: active_group, | |
| 7088 | 7094 | currentVersion user_avatar: currentVersionuser_avatar, |
| 7089 | 7095 | username amount_gen: name1amount_gen, |
| 7090 | 7096 | active_character max_context: active_charactermax_context, |
| 7091 | 7097 | active_group main_api: active_groupmain_api, |
| 7092 | - user_avatar: user_avatar, | |
| 7098 | + world_info_settings: getWorldInfoSettings(), | |
| 7093 | 7099 | amount_gen textgenerationwebui_settings: amount_gentextgen_settings, |
| 7094 | 7100 | max_context swipes: max_contextswipes, |
| 7095 | 7101 | main_api horde_settings: main_apihorde_settings, |
| 7096 | - world_info_settings: getWorldInfoSettings(), | |
| 7102 | + power_user: power_user, | |
| 7097 | 7103 | textgenerationwebui_settings extension_settings: textgen_settingsextension_settings, |
| 7098 | 7104 | swipes tags: swipestags, |
| 7099 | 7105 | horde_settings tag_map: horde_settingstag_map, |
| 7100 | 7106 | power_user nai_settings: power_usernai_settings, |
| 7101 | 7107 | extension_settings kai_settings: extension_settingskai_settings, |
| 7102 | 7108 | tags oai_settings: tagsoai_settings, |
| 7103 | 7109 | tag_map background: tag_mapbackground_settings, |
| 7104 | 7110 | nai_settings proxies: nai_settingsproxies, |
| 7105 | 7111 | kai_settings selected_proxy: kai_settingsselected_proxy, |
| 7106 | - oai_settings: oai_settings, | |
| 7112 | + }; | |
| 7107 | - background: background_settings, | |
| 7113 | + | |
| 7108 | - proxies: proxies, | |
| 7114 | + try { | |
| 7109 | - selected_proxy: selected_proxy, | |
| 7115 | + const result = await fetch('/api/settings/save', { | |
| 7110 | - }, null, 4), | |
| 7116 | + method: 'POST', | |
| 7111 | - beforeSend: function () { }, | |
| 7117 | + headers: getRequestHeaders(), | |
| 7112 | - cache: false, | |
| 7118 | + body: JSON.stringify(payload), | |
| 7113 | 7119 | dataType cache: 'jsonno-cache', |
| 7114 | - contentType: 'application/json', | |
| 7120 | + }); | |
| 7115 | - //processData: false, | |
| 7121 | + | |
| 7116 | 7122 | success: async functionif (data!result.ok) { |
| 7117 | - eventSource.emit(event_types.SETTINGS_UPDATED); | |
| 7123 | + throw new Error(`Failed to save settings: ${result.statusText}`); | |
| 7118 | 7124 | }, |
| 7119 | - error: function (jqXHR, exception) { | |
| 7125 | + | |
| 7120 | - toastr.error(t`Check the server connection and reload the page to prevent data loss.`, t`Settings could not be saved`); | |
| 7126 | + settings = payload; | |
| 7121 | - console.log(exception); | |
| 7127 | + await eventSource.emit(event_types.SETTINGS_UPDATED); | |
| 7122 | - console.log(jqXHR); | |
| 7128 | + } catch (error) { | |
| 7123 | - }, | |
| 7129 | + console.error('Error saving settings:', error); | |
| 7124 | - }); | |
| 7130 | + toastr.error(t`Check the server connection and reload the page to prevent data loss.`, t`Settings could not be saved`); | |
| 7131 | + } | |
| 7125 | 7132 | } |
| 7126 | 7133 | |
| 7127 | 7134 | /** |
| @@ -8079,12 +8086,10 @@ export async function saveChatConditional() { | ||
| 8079 | 8086 | * @param {EventTarget} eventTarget Event target to trigger the event on. |
| 8080 | 8087 | */ |
| 8081 | 8088 | async function importCharacterChat(formData, eventTarget) { |
| 8082 | - const headers = getRequestHeaders(); | |
| 8083 | - delete headers['Content-Type']; | |
| 8084 | 8089 | const fetchResult = await fetch('/api/chats/import', { |
| 8085 | 8090 | method: 'POST', |
| 8086 | 8091 | body: formData, |
| 8087 | - headers: headers, | |
| 8092 | + headers: getRequestHeaders({ omitContentType: true }), | |
| 8088 | 8093 | cache: 'no-cache', |
| 8089 | 8094 | }); |
| 8090 | 8095 | |
| @@ -8388,8 +8393,7 @@ async function createOrEditCharacter(e) { | ||
| 8388 | 8393 | formData.set('avatar', convertedFile); |
| 8389 | 8394 | } |
| 8390 | 8395 | |
| 8391 | 8396 | const headers = getRequestHeaders({ omitContentType: true }); |
| 8392 | - delete headers['Content-Type']; | |
| 8393 | 8397 | |
| 8394 | 8398 | if ($('#form_create').attr('actiontype') == 'createcharacter') { |
| 8395 | 8399 | if (String($('#character_name_pole').val()).length === 0) { |
| @@ -9013,32 +9017,38 @@ async function importCharacter(file, { preserveFileName = '', importTags = false | ||
| 9013 | 9017 | formData.append('file_type', format); |
| 9014 | 9018 | if (preserveFileName) formData.append('preserved_name', preserveFileName); |
| 9015 | 9019 | |
| 9016 | - const data = await jQuery.ajax({ | |
| 9020 | + try { | |
| 9017 | - type: 'POST', | |
| 9021 | + const result = await fetch('/api/characters/import', { | |
| 9018 | - url: '/api/characters/import', | |
| 9022 | + method: 'POST', | |
| 9019 | 9023 | data body: formData, |
| 9020 | - async: true, | |
| 9024 | + headers: getRequestHeaders({ omitContentType: true }), | |
| 9021 | 9025 | cache: false'no-cache', |
| 9022 | - contentType: false, | |
| 9026 | + }); | |
| 9023 | - processData: false, | |
| 9024 | - }); | |
| 9025 | 9027 | |
| 9026 | 9028 | if (data!result.errorok) { |
| 9027 | - toastr.error(t`The file is likely invalid or corrupted.`, t`Could not import character`); | |
| 9029 | + throw new Error(`Failed to import character: ${result.statusText}`); | |
| 9028 | - return; | |
| 9030 | + } | |
| 9029 | - } | |
| 9030 | 9031 | |
| 9031 | - if (data.file_name !== undefined) { | |
| 9032 | + const data = await result.json(); | |
| 9032 | - $('#character_search_bar').val('').trigger('input'); | |
| 9033 | 9033 | |
| 9034 | - toastr.success(t`Character Created: ${String(data.file_name).replace('.png', '')}`); | |
| 9034 | + if (data.error) { | |
| 9035 | - let avatarFileName = `${data.file_name}.png`; | |
| 9035 | + throw new Error(`Server returned an error: ${data.error}`); | |
| 9036 | - if (importTags) { | |
| 9036 | + } | |
| 9037 | - await importCharactersTags([avatarFileName]); | |
| 9038 | 9037 | |
| 9039 | - selectImportedChar(data.file_name); | |
| 9038 | + if (data.file_name !== undefined) { | |
| 9039 | + $('#character_search_bar').val('').trigger('input'); | |
| 9040 | + | |
| 9041 | + toastr.success(t`Character Created: ${String(data.file_name).replace('.png', '')}`); | |
| 9042 | + let avatarFileName = `${data.file_name}.png`; | |
| 9043 | + if (importTags) { | |
| 9044 | + await importCharactersTags([avatarFileName]); | |
| 9045 | + selectImportedChar(data.file_name); | |
| 9046 | + } | |
| 9047 | + return avatarFileName; | |
| 9040 | 9048 | } |
| 9041 | - return avatarFileName; | |
| 9049 | + } catch (error) { | |
| 9050 | + console.error('Error importing character', error); | |
| 9051 | + toastr.error(t`The file is likely invalid or corrupted.`, t`Could not import character`); | |
| 9042 | 9052 | } |
| 9043 | 9053 | } |
| 9044 | 9054 | |
| @@ -636,12 +636,9 @@ async function uploadBackground(formData) { | ||
| 636 | 636 | return; |
| 637 | 637 | } |
| 638 | 638 | |
| 639 | - const headers = getRequestHeaders(); | |
| 640 | - delete headers['Content-Type']; | |
| 641 | - | |
| 642 | 639 | const response = await fetch('/api/backgrounds/upload', { |
| 643 | 640 | method: 'POST', |
| 644 | - headers: headers, | |
| 641 | + headers: getRequestHeaders({ omitContentType: true }), | |
| 645 | 642 | body: formData, |
| 646 | 643 | cache: 'no-cache', |
| 647 | 644 | }); |
| @@ -1758,27 +1758,38 @@ async function onExpressionFallbackChanged() { | ||
| 1758 | 1758 | saveSettingsDebounced(); |
| 1759 | 1759 | } |
| 1760 | 1760 | |
| 1761 | +/** | |
| 1762 | + * Handles the file upload process for a sprite image. | |
| 1763 | + * @param {string} url URL to upload the file to | |
| 1764 | + * @param {FormData} formData FormData object containing the file and other data to upload | |
| 1765 | + * @returns {Promise<any>} - The response data from the server | |
| 1766 | + */ | |
| 1761 | 1767 | async function handleFileUpload(url, formData) { |
| 1762 | 1768 | try { |
| 1763 | 1769 | const dataresult = await jQuery.ajaxfetch(url, { |
| 1764 | 1770 | typemethod: 'POST', |
| 1765 | - url: url, | |
| 1771 | + headers: getRequestHeaders({ omitContentType: true }), | |
| 1766 | 1772 | databody: formData, |
| 1767 | - beforeSend: function () { }, | |
| 1773 | + cache: 'no-cache', | |
| 1768 | - cache: false, | |
| 1769 | - contentType: false, | |
| 1770 | - processData: false, | |
| 1771 | 1774 | }); |
| 1772 | 1775 | |
| 1776 | + if (!result.ok) { | |
| 1777 | + throw new Error(`Upload failed with status ${result.status}`); | |
| 1778 | + } | |
| 1779 | + | |
| 1780 | + const data = await result.json(); | |
| 1781 | + | |
| 1773 | 1782 | // Refresh sprites list |
| 1774 | 1783 | const name = formData.get('name').toString(); |
| 1775 | 1784 | delete spriteCache[name]; |
| 1776 | 1785 | await fetchImagesNoCache(); |
| 1777 | 1786 | await validateImages(name); |
| 1778 | 1787 | |
| 1779 | 1788 | return data ?? {}; |
| 1780 | 1789 | } catch (error) { |
| 1790 | + console.error('Error uploading image:', error); | |
| 1781 | 1791 | toastr.error('Failed to upload image'); |
| 1792 | + return {}; | |
| 1782 | 1793 | } |
| 1783 | 1794 | } |
| 1784 | 1795 | |
| @@ -1996,7 +2007,11 @@ async function onClickExpressionUploadPackButton() { | ||
| 1996 | 2007 | const uploadToast = toastr.info('Please wait...', 'Upload is processing', { timeOut: 0, extendedTimeOut: 0 }); |
| 1997 | 2008 | const { count } = await handleFileUpload('/api/sprites/upload-zip', formData); |
| 1998 | 2009 | toastr.clear(uploadToast); |
| 1999 | - toastr.success(`Uploaded ${count} image(s) for ${name}`); | |
| 2010 | + | |
| 2011 | + // Only show success message if at least one image was uploaded | |
| 2012 | + if (count) { | |
| 2013 | + toastr.success(`Uploaded ${count} image(s) for ${name}`); | |
| 2014 | + } | |
| 2000 | 2015 | |
| 2001 | 2016 | // Reset the input |
| 2002 | 2017 | e.target.form.reset(); |
| @@ -311,7 +311,7 @@ export function getGroupNames() { | ||
| 311 | 311 | * @returns {number|Object} 0-based character ID or key-value object if full is true |
| 312 | 312 | */ |
| 313 | 313 | export function findGroupMemberId(arg, full = false) { |
| 314 | 314 | arg = arg?.toString()?.trim(); |
| 315 | 315 | |
| 316 | 316 | if (!arg) { |
| 317 | 317 | console.warn('WARN: No argument provided for findGroupMemberId'); |
| @@ -1358,7 +1358,7 @@ function isGroupMember(group, avatarId) { | ||
| 1358 | 1358 | } |
| 1359 | 1359 | } |
| 1360 | 1360 | |
| 1361 | 1361 | function getGroupCharacters({ doFilter = false, onlyMembers = false } = {}) { |
| 1362 | 1362 | function sortMembersFn(a, b) { |
| 1363 | 1363 | const membersArray = thisGroup?.members ?? newGroupMembers; |
| 1364 | 1364 | const aIndex = membersArray.indexOf(a.item.avatar); |
| @@ -1757,7 +1757,7 @@ async function onGroupActionClick(event) { | ||
| 1757 | 1757 | |
| 1758 | 1758 | function updateFavButtonState(state) { |
| 1759 | 1759 | fav_grp_checked = state; |
| 1760 | 1760 | $('#rm_group_fav').val(String(fav_grp_checked)); |
| 1761 | 1761 | $('#group_favorite_button').toggleClass('fav_on', fav_grp_checked); |
| 1762 | 1762 | $('#group_favorite_button').toggleClass('fav_off', !fav_grp_checked); |
| 1763 | 1763 | } |
| @@ -2047,11 +2047,9 @@ export async function deleteGroupChat(groupId, chatId) { | ||
| 2047 | 2047 | * @param {EventTarget} eventTarget Element that triggered the import |
| 2048 | 2048 | */ |
| 2049 | 2049 | export async function importGroupChat(formData, eventTarget) { |
| 2050 | - const headers = getRequestHeaders(); | |
| 2051 | - delete headers['Content-Type']; | |
| 2052 | 2050 | const fetchResult = await fetch('/api/chats/group/import', { |
| 2053 | 2051 | method: 'POST', |
| 2054 | - headers: headers, | |
| 2052 | + headers: getRequestHeaders({ omitContentType: true }), | |
| 2055 | 2053 | body: formData, |
| 2056 | 2054 | cache: 'no-cache', |
| 2057 | 2055 | }); |
| @@ -317,12 +317,9 @@ async function uploadUserAvatar(url, name) { | ||
| 317 | 317 | formData.append('overwrite_name', name); |
| 318 | 318 | } |
| 319 | 319 | |
| 320 | - const headers = getRequestHeaders(); | |
| 321 | - delete headers['Content-Type']; | |
| 322 | - | |
| 323 | 320 | await fetch('/api/avatars/upload', { |
| 324 | 321 | method: 'POST', |
| 325 | - headers: headers, | |
| 322 | + headers: getRequestHeaders({ omitContentType: true }), | |
| 326 | 323 | cache: 'no-cache', |
| 327 | 324 | body: formData, |
| 328 | 325 | }); |
| @@ -368,12 +365,9 @@ async function changeUserAvatar(e) { | ||
| 368 | 365 | formData.set('avatar', convertedFile); |
| 369 | 366 | } |
| 370 | 367 | |
| 371 | - const headers = getRequestHeaders(); | |
| 372 | - delete headers['Content-Type']; | |
| 373 | - | |
| 374 | 368 | const response = await fetch(url, { |
| 375 | 369 | method: 'POST', |
| 376 | - headers: headers, | |
| 370 | + headers: getRequestHeaders({ omitContentType:true }), | |
| 377 | 371 | cache: 'no-cache', |
| 378 | 372 | body: formData, |
| 379 | 373 | }); |
| @@ -61,18 +61,6 @@ import { accountStorage } from './util/AccountStorage.js'; | ||
| 61 | 61 | import { DEFAULT_REASONING_TEMPLATE, loadReasoningTemplates } from './reasoning.js'; |
| 62 | 62 | import { bindModelTemplates } from './chat-templates.js'; |
| 63 | 63 | |
| 64 | -export { | |
| 65 | - loadPowerUserSettings, | |
| 66 | - loadMovingUIState, | |
| 67 | - collapseNewlines, | |
| 68 | - playMessageSound, | |
| 69 | - fixMarkdown, | |
| 70 | - power_user, | |
| 71 | - send_on_enter_options, | |
| 72 | - getContextSettings, | |
| 73 | - applyPowerUserSettings, | |
| 74 | -}; | |
| 75 | - | |
| 76 | 64 | export const toastPositionClasses = [ |
| 77 | 65 | 'toast-top-left', |
| 78 | 66 | 'toast-top-center', |
| @@ -108,7 +96,7 @@ export const chat_styles = { | ||
| 108 | 96 | DOCUMENT: 2, |
| 109 | 97 | }; |
| 110 | 98 | |
| 111 | 99 | export const send_on_enter_options = { |
| 112 | 100 | DISABLED: -1, |
| 113 | 101 | AUTO: 0, |
| 114 | 102 | ENABLED: 1, |
| @@ -126,7 +114,7 @@ export const persona_description_positions = { | ||
| 126 | 114 | NONE: 9, |
| 127 | 115 | }; |
| 128 | 116 | |
| 129 | 117 | letexport const power_user = { |
| 130 | 118 | charListGrid: false, |
| 131 | 119 | tokenizer: tokenizers.BEST_MATCH, |
| 132 | 120 | token_padding: 64, |
| @@ -370,7 +358,7 @@ const debug_functions = []; | ||
| 370 | 358 | |
| 371 | 359 | const setHotswapsDebounced = debounce(favsToHotswap); |
| 372 | 360 | |
| 373 | 361 | export function playMessageSound() { |
| 374 | 362 | if (!power_user.play_message_sound) { |
| 375 | 363 | return; |
| 376 | 364 | } |
| @@ -395,7 +383,7 @@ function playMessageSound() { | ||
| 395 | 383 | * @example |
| 396 | 384 | * collapseNewlines("\n\n\n"); // "\n" |
| 397 | 385 | */ |
| 398 | 386 | export function collapseNewlines(x) { |
| 399 | 387 | return x.replaceAll(/\n+/g, '\n'); |
| 400 | 388 | } |
| 401 | 389 | |
| @@ -416,7 +404,7 @@ function collapseNewlines(x) { | ||
| 416 | 404 | * // and you HAVE to handle the cases where multiple pairs of asterisks exist in the same line |
| 417 | 405 | * "^example * text* * harder problem *\n" // "^example *text* *harder problem*\n" |
| 418 | 406 | */ |
| 419 | 407 | export function fixMarkdown(text, forDisplay) { |
| 420 | 408 | // Find pairs of formatting characters and capture the text in between them |
| 421 | 409 | const format = /([*_]{1,2})([\s\S]*?)\1/gm; |
| 422 | 410 | let matches = []; |
| @@ -862,13 +850,13 @@ async function CreateZenSliders(elmnt) { | ||
| 862 | 850 | }) |
| 863 | 851 | //trigger slider changes when user clicks away |
| 864 | 852 | .on('mouseup blur', function () { |
| 865 | 853 | let manualInput = parseFloat(parseFloat(handle.text()).toFixed(decimals)); |
| 866 | 854 | if (isManualInput) { |
| 867 | 855 | //disallow manual inputs outside acceptable range |
| 868 | 856 | if (manualInput >= sliderMin && manualInput <= sliderMax) { |
| 869 | 857 | //if value is ok, assign to slider and update handle text and position |
| 870 | 858 | newSlider.val(manualInput); |
| 871 | 859 | handleSlideEvent.call(newSlider, null, { value: parseFloat(manualInput) }, 'manual'); |
| 872 | 860 | valueBeforeManualInput = manualInput; |
| 873 | 861 | } else { |
| 874 | 862 | //if value not ok, warn and reset to last known valid value |
| @@ -890,13 +878,13 @@ async function CreateZenSliders(elmnt) { | ||
| 890 | 878 | |
| 891 | 879 | function handleSlideEvent(event, ui, type) { |
| 892 | 880 | var handle = $(this).find('.ui-slider-handle'); |
| 893 | 881 | var numVal = parseFloat(Number(ui.value).toFixed(decimals)); |
| 894 | 882 | offVal = parseFloat(Number(offVal).toFixed(decimals)); |
| 895 | 883 | allVal = parseFloat(Number(allVal).toFixed(decimals)); |
| 896 | 884 | console.log(numVal, sliderMin, sliderMax, numVal > sliderMax, numVal < sliderMin); |
| 897 | 885 | if (numVal > sliderMax) { numVal = sliderMax; } |
| 898 | 886 | if (numVal < sliderMin) { numVal = sliderMin; } |
| 899 | 887 | var stepNumber = parseFloat(((ui.value - sliderMin) / stepScale).toFixed(0)); |
| 900 | 888 | var handleText = (ui.value); |
| 901 | 889 | var leftMargin = (stepNumber / numSteps) * 50 * -1; |
| 902 | 890 | var perStepPercent = 1 / numSteps; //how far in % each step should be on the slider |
| @@ -1035,10 +1023,9 @@ function applyAvatarStyle() { | ||
| 1035 | 1023 | } |
| 1036 | 1024 | |
| 1037 | 1025 | function applyChatDisplay() { |
| 1038 | - | |
| 1026 | + if ([null, undefined].includes(power_user.chat_display)) { | |
| 1039 | - if (!power_user.chat_display === (null || undefined)) { | |
| 1040 | 1027 | console.debug('applyChatDisplay: saw no chat display type defined'); |
| 1041 | - return; | |
| 1028 | + power_user.chat_display = chat_styles.DEFAULT; | |
| 1042 | 1029 | } |
| 1043 | 1030 | console.debug(`poweruser.chat_display ${power_user.chat_display}`); |
| 1044 | 1031 | $('#chat_display').val(power_user.chat_display).prop('selected', true); |
| @@ -1417,7 +1404,7 @@ async function showDebugMenu() { | ||
| 1417 | 1404 | callGenericPopup(template, POPUP_TYPE.TEXT, '', { wide: true, large: true, allowVerticalScrolling: true }); |
| 1418 | 1405 | } |
| 1419 | 1406 | |
| 1420 | 1407 | export function applyPowerUserSettings() { |
| 1421 | 1408 | switchUiMode(); |
| 1422 | 1409 | applyFontScale('forced'); |
| 1423 | 1410 | applyThemeColor(); |
| @@ -1496,7 +1483,7 @@ function getExampleMessagesBehavior() { | ||
| 1496 | 1483 | } |
| 1497 | 1484 | |
| 1498 | 1485 | //MARK: loadPowerUser |
| 1499 | 1486 | export async function loadPowerUserSettings(settings, data) { |
| 1500 | 1487 | const defaultStscript = JSON.parse(JSON.stringify(power_user.stscript)); |
| 1501 | 1488 | // Load from settings.json |
| 1502 | 1489 | if (settings.power_user !== undefined) { |
| @@ -1552,15 +1539,15 @@ async function loadPowerUserSettings(settings, data) { | ||
| 1552 | 1539 | context_presets = data.context; |
| 1553 | 1540 | } |
| 1554 | 1541 | |
| 1555 | 1542 | if (typeof power_user.chat_display =!== 'number') { |
| 1556 | 1543 | power_user.chat_display = chat_styles.DEFAULT; |
| 1557 | 1544 | } |
| 1558 | 1545 | |
| 1559 | 1546 | if (typeof power_user.waifuMode =!== 'boolean') { |
| 1560 | 1547 | power_user.waifuMode = false; |
| 1561 | 1548 | } |
| 1562 | 1549 | |
| 1563 | 1550 | if (typeof power_user.chat_width =!== 'number') { |
| 1564 | 1551 | power_user.chat_width = 50; |
| 1565 | 1552 | } |
| 1566 | 1553 | |
| @@ -1618,8 +1605,8 @@ async function loadPowerUserSettings(settings, data) { | ||
| 1618 | 1605 | $('#auto_scroll_chat_to_bottom').prop('checked', power_user.auto_scroll_chat_to_bottom); |
| 1619 | 1606 | $('#bogus_folders').prop('checked', power_user.bogus_folders); |
| 1620 | 1607 | $('#zoomed_avatar_magnification').prop('checked', power_user.zoomed_avatar_magnification); |
| 1621 | 1608 | $(`#tokenizer option[value="${power_user.tokenizer}"]`).attrprop('selected', true); |
| 1622 | 1609 | $(`#send_on_enter option[value=${power_user.send_on_enter}]`).attrprop('selected', true); |
| 1623 | 1610 | $('#confirm_message_delete').prop('checked', power_user.confirm_message_delete !== undefined ? !!power_user.confirm_message_delete : true); |
| 1624 | 1611 | $('#spoiler_free_mode').prop('checked', power_user.spoiler_free_mode); |
| 1625 | 1612 | $('#collapse-newlines-checkbox').prop('checked', power_user.collapse_newlines); |
| @@ -1655,8 +1642,8 @@ async function loadPowerUserSettings(settings, data) { | ||
| 1655 | 1642 | $('#enableZenSliders').prop('checked', power_user.enableZenSliders).trigger('input'); |
| 1656 | 1643 | $('#enableLabMode').prop('checked', power_user.enableLabMode).trigger('input', { fromInit: true }); |
| 1657 | 1644 | $(`input[name="avatar_style"][value="${power_user.avatar_style}"]`).prop('checked', true); |
| 1658 | 1645 | $(`#chat_display option[value=${power_user.chat_display}]`).attrprop('selected', true).trigger('change'); |
| 1659 | 1646 | $(`#toastr_position option[value=${power_user.toastr_position}]`).attrprop('selected', true).trigger('change'); |
| 1660 | 1647 | $('#chat_width_slider').val(power_user.chat_width); |
| 1661 | 1648 | $('#token_padding').val(power_user.token_padding); |
| 1662 | 1649 | $('#aux_field').val(power_user.aux_field); |
| @@ -1763,7 +1750,7 @@ function loadCharListState() { | ||
| 1763 | 1750 | document.body.classList.toggle('charListGrid', power_user.charListGrid); |
| 1764 | 1751 | } |
| 1765 | 1752 | |
| 1766 | 1753 | export function loadMovingUIState() { |
| 1767 | 1754 | if (!isMobile() |
| 1768 | 1755 | && power_user.movingUIState |
| 1769 | 1756 | && power_user.movingUI === true) { |
| @@ -1853,7 +1840,7 @@ function switchMaxContextSize() { | ||
| 1853 | 1840 | } |
| 1854 | 1841 | |
| 1855 | 1842 | // Fetch a compiled object of all preset settings |
| 1856 | 1843 | export function getContextSettings() { |
| 1857 | 1844 | let compiledSettings = {}; |
| 1858 | 1845 | |
| 1859 | 1846 | contextControls.forEach((control) => { |
| @@ -2397,7 +2384,7 @@ async function saveTheme(name = undefined, theme = undefined) { | ||
| 2397 | 2384 | } |
| 2398 | 2385 | else { |
| 2399 | 2386 | themes[themeIndex] = theme; |
| 2400 | 2387 | $(`#themes option[value="${name}"]`).attrprop('selected', true); |
| 2401 | 2388 | } |
| 2402 | 2389 | |
| 2403 | 2390 | power_user.theme = name; |
| @@ -2504,7 +2491,7 @@ async function saveMovingUI() { | ||
| 2504 | 2491 | } |
| 2505 | 2492 | else { |
| 2506 | 2493 | movingUIPresets[movingUIPresetIndex] = movingUIPreset; |
| 2507 | 2494 | $(`#movingUIPresets option[value="${name}"]`).attrprop('selected', true); |
| 2508 | 2495 | } |
| 2509 | 2496 | |
| 2510 | 2497 | power_user.movingUIPreset = name; |
| @@ -3162,7 +3149,7 @@ jQuery(() => { | ||
| 3162 | 3149 | }); |
| 3163 | 3150 | |
| 3164 | 3151 | const reportZoomLevelDebounced = debounce(() => { |
| 3165 | 3152 | const zoomLevel = parseFloat(Number(window.devicePixelRatio).toFixed(2)) || 1; |
| 3166 | 3153 | const winWidth = window.innerWidth; |
| 3167 | 3154 | const winHeight = window.innerHeight; |
| 3168 | 3155 | const originalWidth = winWidth * zoomLevel; |
| @@ -3187,8 +3174,8 @@ jQuery(() => { | ||
| 3187 | 3174 | |
| 3188 | 3175 | //attempt to scale movingUI elements naturally across window resizing/zooms |
| 3189 | 3176 | //this will still break if the zoom level causes mobile styles to come into play. |
| 3190 | 3177 | const scaleY = parseFloat(Number(window.innerHeight / coreTruthWinHeight).toFixed(4)); |
| 3191 | 3178 | const scaleX = parseFloat(Number(window.innerWidth / coreTruthWinWidth).toFixed(4)); |
| 3192 | 3179 | |
| 3193 | 3180 | if (Object.keys(power_user.movingUIState).length > 0) { |
| 3194 | 3181 | for (var elmntName of Object.keys(power_user.movingUIState)) { |
| @@ -3362,7 +3349,7 @@ jQuery(() => { | ||
| 3362 | 3349 | }); |
| 3363 | 3350 | |
| 3364 | 3351 | $('#waifuMode').on('change', () => { |
| 3365 | 3352 | power_user.waifuMode = !!$('#waifuMode').prop('checked'); |
| 3366 | 3353 | switchWaifuMode(); |
| 3367 | 3354 | saveSettingsDebounced(); |
| 3368 | 3355 | }); |
| @@ -3410,7 +3397,7 @@ jQuery(() => { | ||
| 3410 | 3397 | |
| 3411 | 3398 | $('#chat_width_slider').on('input', function (e, data) { |
| 3412 | 3399 | const applyMode = data?.forced ? 'forced' : 'normal'; |
| 3413 | 3400 | power_user.chat_width = Number(e.target$(this).valueval()); |
| 3414 | 3401 | applyChatWidth(applyMode); |
| 3415 | 3402 | saveSettingsDebounced(); |
| 3416 | 3403 | setHotswapsDebounced(); |
| @@ -3440,81 +3427,81 @@ jQuery(() => { | ||
| 3440 | 3427 | |
| 3441 | 3428 | $('input[name="font_scale"]').on('input', async function (e, data) { |
| 3442 | 3429 | const applyMode = data?.forced ? 'forced' : 'normal'; |
| 3443 | 3430 | power_user.font_scale = Number(e.target$(this).valueval()); |
| 3444 | 3431 | $('#font_scale_counter').val(power_user.font_scale); |
| 3445 | 3432 | applyFontScale(applyMode); |
| 3446 | 3433 | saveSettingsDebounced(); |
| 3447 | 3434 | }); |
| 3448 | 3435 | |
| 3449 | 3436 | $('input[name="blur_strength"]').on('input', async function (e) { |
| 3450 | 3437 | power_user.blur_strength = Number(e.target$(this).valueval()); |
| 3451 | 3438 | $('#blur_strength_counter').val(power_user.blur_strength); |
| 3452 | 3439 | applyBlurStrength(); |
| 3453 | 3440 | saveSettingsDebounced(); |
| 3454 | 3441 | }); |
| 3455 | 3442 | |
| 3456 | 3443 | $('input[name="shadow_width"]').on('input', async function (e) { |
| 3457 | 3444 | power_user.shadow_width = Number(e.target$(this).valueval()); |
| 3458 | 3445 | $('#shadow_width_counter').val(power_user.shadow_width); |
| 3459 | 3446 | applyShadowWidth(); |
| 3460 | 3447 | saveSettingsDebounced(); |
| 3461 | 3448 | }); |
| 3462 | 3449 | |
| 3463 | 3450 | $('#main-text-color-picker').on('change', (/** @type {ColorPickerEvent} */ evt) => { |
| 3464 | 3451 | power_user.main_text_color = evt.detail.rgba; |
| 3465 | 3452 | applyThemeColor('main'); |
| 3466 | 3453 | saveSettingsDebounced(); |
| 3467 | 3454 | }); |
| 3468 | 3455 | |
| 3469 | 3456 | $('#italics-color-picker').on('change', (/** @type {ColorPickerEvent} */ evt) => { |
| 3470 | 3457 | power_user.italics_text_color = evt.detail.rgba; |
| 3471 | 3458 | applyThemeColor('italics'); |
| 3472 | 3459 | saveSettingsDebounced(); |
| 3473 | 3460 | }); |
| 3474 | 3461 | |
| 3475 | 3462 | $('#underline-color-picker').on('change', (/** @type {ColorPickerEvent} */ evt) => { |
| 3476 | 3463 | power_user.underline_text_color = evt.detail.rgba; |
| 3477 | 3464 | applyThemeColor('underline'); |
| 3478 | 3465 | saveSettingsDebounced(); |
| 3479 | 3466 | }); |
| 3480 | 3467 | |
| 3481 | 3468 | $('#quote-color-picker').on('change', (/** @type {ColorPickerEvent} */ evt) => { |
| 3482 | 3469 | power_user.quote_text_color = evt.detail.rgba; |
| 3483 | 3470 | applyThemeColor('quote'); |
| 3484 | 3471 | saveSettingsDebounced(); |
| 3485 | 3472 | }); |
| 3486 | 3473 | |
| 3487 | 3474 | $('#blur-tint-color-picker').on('change', (/** @type {ColorPickerEvent} */ evt) => { |
| 3488 | 3475 | power_user.blur_tint_color = evt.detail.rgba; |
| 3489 | 3476 | applyThemeColor('blurTint'); |
| 3490 | 3477 | saveSettingsDebounced(); |
| 3491 | 3478 | }); |
| 3492 | 3479 | |
| 3493 | 3480 | $('#chat-tint-color-picker').on('change', (/** @type {ColorPickerEvent} */ evt) => { |
| 3494 | 3481 | power_user.chat_tint_color = evt.detail.rgba; |
| 3495 | 3482 | applyThemeColor('chatTint'); |
| 3496 | 3483 | saveSettingsDebounced(); |
| 3497 | 3484 | }); |
| 3498 | 3485 | |
| 3499 | 3486 | $('#user-mes-blur-tint-color-picker').on('change', (/** @type {ColorPickerEvent} */ evt) => { |
| 3500 | 3487 | power_user.user_mes_blur_tint_color = evt.detail.rgba; |
| 3501 | 3488 | applyThemeColor('userMesBlurTint'); |
| 3502 | 3489 | saveSettingsDebounced(); |
| 3503 | 3490 | }); |
| 3504 | 3491 | |
| 3505 | 3492 | $('#bot-mes-blur-tint-color-picker').on('change', (/** @type {ColorPickerEvent} */ evt) => { |
| 3506 | 3493 | power_user.bot_mes_blur_tint_color = evt.detail.rgba; |
| 3507 | 3494 | applyThemeColor('botMesBlurTint'); |
| 3508 | 3495 | saveSettingsDebounced(); |
| 3509 | 3496 | }); |
| 3510 | 3497 | |
| 3511 | 3498 | $('#shadow-color-picker').on('change', (/** @type {ColorPickerEvent} */ evt) => { |
| 3512 | 3499 | power_user.shadow_color = evt.detail.rgba; |
| 3513 | 3500 | applyThemeColor('shadow'); |
| 3514 | 3501 | saveSettingsDebounced(); |
| 3515 | 3502 | }); |
| 3516 | 3503 | |
| 3517 | 3504 | $('#border-color-picker').on('change', (/** @type {ColorPickerEvent} */ evt) => { |
| 3518 | 3505 | power_user.border_color = evt.detail.rgba; |
| 3519 | 3506 | applyThemeColor('border'); |
| 3520 | 3507 | saveSettingsDebounced(); |
| @@ -577,12 +577,9 @@ async function createPermanentAssistant() { | ||
| 577 | 577 | console.warn('Error fetching system avatar. Fallback image will be used.', error); |
| 578 | 578 | } |
| 579 | 579 | |
| 580 | - const headers = getRequestHeaders(); | |
| 581 | - delete headers['Content-Type']; | |
| 582 | - | |
| 583 | 580 | const fetchResult = await fetch('/api/characters/create', { |
| 584 | 581 | method: 'POST', |
| 585 | - headers: headers, | |
| 582 | + headers: getRequestHeaders({ omitContentType: true }), | |
| 586 | 583 | body: formData, |
| 587 | 584 | cache: 'no-cache', |
| 588 | 585 | }); |
| @@ -5199,6 +5199,10 @@ export function onWorldInfoChange(args, text) { | ||
| 5199 | 5199 | return ''; |
| 5200 | 5200 | } |
| 5201 | 5201 | |
| 5202 | +/** | |
| 5203 | + * Imports world info from a file. | |
| 5204 | + * @param {File} file File to import | |
| 5205 | + */ | |
| 5202 | 5206 | export async function importWorldInfo(file) { |
| 5203 | 5207 | if (!file) { |
| 5204 | 5208 | return; |
| @@ -5252,28 +5256,34 @@ export async function importWorldInfo(file) { | ||
| 5252 | 5256 | return false; |
| 5253 | 5257 | } |
| 5254 | 5258 | |
| 5255 | - jQuery.ajax({ | |
| 5259 | + try { | |
| 5256 | - type: 'POST', | |
| 5260 | + const result = await fetch('/api/worldinfo/import', { | |
| 5257 | - url: '/api/worldinfo/import', | |
| 5261 | + method: 'POST', | |
| 5258 | - data: formData, | |
| 5262 | + headers: getRequestHeaders({ omitContentType: true }), | |
| 5259 | - beforeSend: () => { }, | |
| 5263 | + body: formData, | |
| 5260 | 5264 | cache: false'no-cache', |
| 5261 | - contentType: false, | |
| 5265 | + }); | |
| 5262 | - processData: false, | |
| 5266 | + | |
| 5263 | 5267 | success: async functionif (data!result.ok) { |
| 5264 | - if (data.name) { | |
| 5268 | + throw new Error(`Failed to import world info: ${result.statusText}`); | |
| 5265 | - await updateWorldInfoList(); | |
| 5269 | + } | |
| 5266 | 5270 | |
| 5267 | 5271 | const newIndexdata = world_namesawait result.indexOfjson(data.name); |
| 5268 | - if (newIndex >= 0) { | |
| 5269 | - $('#world_editor_select').val(newIndex).trigger('change'); | |
| 5270 | - } | |
| 5271 | 5272 | |
| 5272 | - toastr.success(`World Info "${data.name}" imported successfully!`); | |
| 5273 | + if (data.name) { | |
| 5274 | + await updateWorldInfoList(); | |
| 5275 | + | |
| 5276 | + const newIndex = world_names.indexOf(data.name); | |
| 5277 | + if (newIndex >= 0) { | |
| 5278 | + $('#world_editor_select').val(newIndex).trigger('change'); | |
| 5273 | 5279 | } |
| 5274 | - }, | |
| 5280 | + | |
| 5275 | - error: (_jqXHR, _exception) => { }, | |
| 5281 | + toastr.success(t`World Info "${data.name}" imported successfully!`); | |
| 5276 | - }); | |
| 5282 | + } | |
| 5283 | + } catch (error) { | |
| 5284 | + console.error('Error importing world info:', error); | |
| 5285 | + toastr.error(t`Failed to import World Info`); | |
| 5286 | + } | |
| 5277 | 5287 | } |
| 5278 | 5288 | |
| 5279 | 5289 | /** |
| @@ -216,7 +216,7 @@ router.post('/upload-zip', async (request, response) => { | ||
| 216 | 216 | |
| 217 | 217 | // Remove uploaded ZIP file |
| 218 | 218 | fs.unlinkSync(spritePackPath); |
| 219 | 219 | return response.send({ ok: true, count: sprites.length }); |
| 220 | 220 | } catch (error) { |
| 221 | 221 | console.error(error); |
| 222 | 222 | return response.sendStatus(500); |
| @@ -262,7 +262,7 @@ router.post('/upload', async (request, response) => { | ||
| 262 | 262 | fs.cpSync(spritePath, pathToFile); |
| 263 | 263 | // Remove uploaded file |
| 264 | 264 | fs.unlinkSync(spritePath); |
| 265 | 265 | return response.sendStatussend(200{ ok: true }); |
| 266 | 266 | } catch (error) { |
| 267 | 267 | console.error(error); |
| 268 | 268 | return response.sendStatus(500); |