Merge pull request #1025 from Carlos-err406/fix/dom-queries

rf: less dom queries using bind:this
This commit is contained in:
Timothy Jaeryang Baek 2024-03-04 16:22:31 -05:00 committed by GitHub
commit 2d59847fb9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 87 additions and 82 deletions

View file

@ -19,7 +19,7 @@
export let suggestionPrompts = []; export let suggestionPrompts = [];
export let autoScroll = true; export let autoScroll = true;
let chatTextAreaElement:HTMLTextAreaElement
let filesInputElement; let filesInputElement;
let promptsElement; let promptsElement;
@ -43,11 +43,9 @@
let speechRecognition; let speechRecognition;
$: if (prompt) { $: if (prompt) {
const chatInput = document.getElementById('chat-textarea'); if (chatTextAreaElement) {
chatTextAreaElement.style.height = '';
if (chatInput) { chatTextAreaElement.style.height = Math.min(chatTextAreaElement.scrollHeight, 200) + 'px';
chatInput.style.height = '';
chatInput.style.height = Math.min(chatInput.scrollHeight, 200) + 'px';
} }
} }
@ -86,9 +84,7 @@
if (res) { if (res) {
prompt = res.text; prompt = res.text;
await tick(); await tick();
chatTextAreaElement?.focus();
const inputElement = document.getElementById('chat-textarea');
inputElement?.focus();
if (prompt !== '' && $settings?.speechAutoSend === true) { if (prompt !== '' && $settings?.speechAutoSend === true) {
submitPrompt(prompt, user); submitPrompt(prompt, user);
@ -191,8 +187,7 @@
prompt = `${prompt}${transcript}`; prompt = `${prompt}${transcript}`;
await tick(); await tick();
const inputElement = document.getElementById('chat-textarea'); chatTextAreaElement?.focus();
inputElement?.focus();
// Restart the inactivity timeout // Restart the inactivity timeout
timeoutId = setTimeout(() => { timeoutId = setTimeout(() => {
@ -294,8 +289,7 @@
}; };
onMount(() => { onMount(() => {
const chatInput = document.getElementById('chat-textarea'); window.setTimeout(() => chatTextAreaElement?.focus(), 0);
window.setTimeout(() => chatInput?.focus(), 0);
const dropZone = document.querySelector('body'); const dropZone = document.querySelector('body');
@ -663,6 +657,7 @@
<textarea <textarea
id="chat-textarea" id="chat-textarea"
bind:this={chatTextAreaElement}
class=" dark:bg-gray-900 dark:text-gray-100 outline-none w-full py-3 px-3 {fileUploadEnabled class=" dark:bg-gray-900 dark:text-gray-100 outline-none w-full py-3 px-3 {fileUploadEnabled
? '' ? ''
: ' pl-4'} rounded-xl resize-none h-[48px]" : ' pl-4'} rounded-xl resize-none h-[48px]"

View file

@ -40,7 +40,7 @@
let edit = false; let edit = false;
let editedContent = ''; let editedContent = '';
let editTextAreaElement: HTMLTextAreaElement;
let tooltipInstance = null; let tooltipInstance = null;
let sentencesAudio = {}; let sentencesAudio = {};
@ -247,10 +247,9 @@
editedContent = message.content; editedContent = message.content;
await tick(); await tick();
const editElement = document.getElementById(`message-edit-${message.id}`);
editElement.style.height = ''; editTextAreaElement.style.height = '';
editElement.style.height = `${editElement.scrollHeight}px`; editTextAreaElement.style.height = `${editTextAreaElement.scrollHeight}px`;
}; };
const editMessageConfirmHandler = async () => { const editMessageConfirmHandler = async () => {
@ -341,6 +340,7 @@
<div class=" w-full"> <div class=" w-full">
<textarea <textarea
id="message-edit-{message.id}" id="message-edit-{message.id}"
bind:this={editTextAreaElement}
class=" bg-transparent outline-none w-full resize-none" class=" bg-transparent outline-none w-full resize-none"
bind:value={editedContent} bind:value={editedContent}
on:input={(e) => { on:input={(e) => {

View file

@ -20,18 +20,17 @@
let edit = false; let edit = false;
let editedContent = ''; let editedContent = '';
let messageEditTextAreaElement: HTMLTextAreaElement;
const editMessageHandler = async () => { const editMessageHandler = async () => {
edit = true; edit = true;
editedContent = message.content; editedContent = message.content;
await tick(); await tick();
const editElement = document.getElementById(`message-edit-${message.id}`);
editElement.style.height = ''; messageEditTextAreaElement.style.height = '';
editElement.style.height = `${editElement.scrollHeight}px`; messageEditTextAreaElement.style.height = `${messageEditTextAreaElement.scrollHeight}px`;
editElement?.focus(); messageEditTextAreaElement?.focus();
}; };
const editMessageConfirmHandler = async () => { const editMessageConfirmHandler = async () => {
@ -165,10 +164,11 @@
<div class=" w-full"> <div class=" w-full">
<textarea <textarea
id="message-edit-{message.id}" id="message-edit-{message.id}"
bind:this={messageEditTextAreaElement}
class=" bg-transparent outline-none w-full resize-none" class=" bg-transparent outline-none w-full resize-none"
bind:value={editedContent} bind:value={editedContent}
on:input={(e) => { on:input={(e) => {
e.target.style.height = `${e.target.scrollHeight}px`; messageEditTextAreaElement.style.height = `${messageEditTextAreaElement.scrollHeight}px`;
}} }}
/> />

View file

@ -15,6 +15,7 @@
let name = ''; let name = '';
let showJWTToken = false; let showJWTToken = false;
let JWTTokenCopied = false; let JWTTokenCopied = false;
let profileImageInputElement: HTMLInputElement;
const submitHandler = async () => { const submitHandler = async () => {
const updatedUser = await updateUserProfile(localStorage.token, name, profileImageUrl).catch( const updatedUser = await updateUserProfile(localStorage.token, name, profileImageUrl).catch(
@ -40,11 +41,12 @@
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80"> <div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80">
<input <input
id="profile-image-input" id="profile-image-input"
bind:this={profileImageInputElement}
type="file" type="file"
hidden hidden
accept="image/*" accept="image/*"
on:change={(e) => { on:change={(e) => {
const files = e?.target?.files ?? []; const files = profileImageInputElement.files ?? [];
let reader = new FileReader(); let reader = new FileReader();
reader.onload = (event) => { reader.onload = (event) => {
let originalImageUrl = `${event.target.result}`; let originalImageUrl = `${event.target.result}`;
@ -86,7 +88,7 @@
// Display the compressed image // Display the compressed image
profileImageUrl = compressedSrc; profileImageUrl = compressedSrc;
e.target.files = null; profileImageInputElement.files = null;
}; };
}; };
@ -107,9 +109,7 @@
<button <button
class="relative rounded-full dark:bg-gray-700" class="relative rounded-full dark:bg-gray-700"
type="button" type="button"
on:click={() => { on:click={profileImageInputElement.click}
document.getElementById('profile-image-input')?.click();
}}
> >
<img <img
src={profileImageUrl !== '' ? profileImageUrl : '/user.png'} src={profileImageUrl !== '' ? profileImageUrl : '/user.png'}

View file

@ -22,6 +22,7 @@
let saveChatHistory = true; let saveChatHistory = true;
let importFiles; let importFiles;
let showDeleteConfirm = false; let showDeleteConfirm = false;
let chatImportInputElement: HTMLInputElement;
$: if (importFiles) { $: if (importFiles) {
console.log(importFiles); console.log(importFiles);
@ -159,12 +160,17 @@
<hr class=" dark:border-gray-700" /> <hr class=" dark:border-gray-700" />
<div class="flex flex-col"> <div class="flex flex-col">
<input id="chat-import-input" bind:files={importFiles} type="file" accept=".json" hidden /> <input
id="chat-import-input"
bind:this={chatImportInputElement}
bind:files={importFiles}
type="file"
accept=".json"
hidden
/>
<button <button
class=" flex rounded-md py-2 px-3.5 w-full hover:bg-gray-200 dark:hover:bg-gray-800 transition" class=" flex rounded-md py-2 px-3.5 w-full hover:bg-gray-200 dark:hover:bg-gray-800 transition"
on:click={() => { on:click={chatImportInputElement.click}
document.getElementById('chat-import-input').click();
}}
> >
<div class=" self-center mr-3"> <div class=" self-center mr-3">
<svg <svg

View file

@ -13,7 +13,7 @@
let showLiteLLM = false; let showLiteLLM = false;
let showLiteLLMParams = false; let showLiteLLMParams = false;
let modelUploadInputElement: HTMLInputElement;
let liteLLMModelInfo = []; let liteLLMModelInfo = [];
let liteLLMModel = ''; let liteLLMModel = '';
@ -546,6 +546,7 @@
<div class="flex-1 {modelInputFile && modelInputFile.length > 0 ? 'mr-2' : ''}"> <div class="flex-1 {modelInputFile && modelInputFile.length > 0 ? 'mr-2' : ''}">
<input <input
id="model-upload-input" id="model-upload-input"
bind:this={modelUploadInputElement}
type="file" type="file"
bind:files={modelInputFile} bind:files={modelInputFile}
on:change={() => { on:change={() => {
@ -559,9 +560,7 @@
<button <button
type="button" type="button"
class="w-full rounded text-left py-2 px-4 dark:text-gray-300 dark:bg-gray-850" class="w-full rounded text-left py-2 px-4 dark:text-gray-300 dark:bg-gray-850"
on:click={() => { on:click={modelUploadInputElement.click}
document.getElementById('model-upload-input').click();
}}
> >
{#if modelInputFile && modelInputFile.length > 0} {#if modelInputFile && modelInputFile.length > 0}
{modelInputFile[0].name} {modelInputFile[0].name}

View file

@ -15,7 +15,7 @@
export let show = false; export let show = false;
export let selectedDoc; export let selectedDoc;
let uploadDocInputElement: HTMLInputElement;
let inputFiles; let inputFiles;
let tags = []; let tags = [];
@ -69,7 +69,7 @@
} }
inputFiles = null; inputFiles = null;
document.getElementById('upload-doc-input').value = ''; uploadDocInputElement.value = '';
} else { } else {
toast.error(`File not found.`); toast.error(`File not found.`);
} }
@ -126,14 +126,19 @@
}} }}
> >
<div class="mb-3 w-full"> <div class="mb-3 w-full">
<input id="upload-doc-input" hidden bind:files={inputFiles} type="file" multiple /> <input
id="upload-doc-input"
bind:this={uploadDocInputElement}
hidden
bind:files={inputFiles}
type="file"
multiple
/>
<button <button
class="w-full text-sm font-medium py-3 bg-gray-850 hover:bg-gray-800 text-center rounded-xl" class="w-full text-sm font-medium py-3 bg-gray-850 hover:bg-gray-800 text-center rounded-xl"
type="button" type="button"
on:click={() => { on:click={uploadDocInputElement.click}
document.getElementById('upload-doc-input')?.click();
}}
> >
{#if inputFiles} {#if inputFiles}
{inputFiles.length > 0 ? `${inputFiles.length}` : ''} document(s) selected. {inputFiles.length > 0 ? `${inputFiles.length}` : ''} document(s) selected.

View file

@ -2,12 +2,11 @@
import { onMount } from 'svelte'; import { onMount } from 'svelte';
export let messages = []; export let messages = [];
let textAreaElement: HTMLTextAreaElement;
onMount(() => { onMount(() => {
messages.forEach((message, idx) => { messages.forEach((message, idx) => {
let textareaElement = document.getElementById(`${message.role}-${idx}-textarea`); textAreaElement.style.height = '';
textareaElement.style.height = ''; textAreaElement.style.height = textAreaElement.scrollHeight + 'px';
textareaElement.style.height = textareaElement.scrollHeight + 'px';
}); });
}); });
</script> </script>
@ -27,16 +26,17 @@
<div class="flex-1"> <div class="flex-1">
<textarea <textarea
id="{message.role}-{idx}-textarea" id="{message.role}-{idx}-textarea"
bind:this={textAreaElement}
class="w-full bg-transparent outline-none rounded-lg p-2 text-sm resize-none overflow-hidden" class="w-full bg-transparent outline-none rounded-lg p-2 text-sm resize-none overflow-hidden"
placeholder="Enter {message.role === 'user' ? 'a user' : 'an assistant'} message here" placeholder="Enter {message.role === 'user' ? 'a user' : 'an assistant'} message here"
rows="1" rows="1"
on:input={(e) => { on:input={(e) => {
e.target.style.height = ''; textAreaElement.style.height = '';
e.target.style.height = e.target.scrollHeight + 'px'; textAreaElement.style.height = textAreaElement.scrollHeight + 'px';
}} }}
on:focus={(e) => { on:focus={(e) => {
e.target.style.height = ''; textAreaElement.style.height = '';
e.target.style.height = e.target.scrollHeight + 'px'; textAreaElement.style.height = textAreaElement.scrollHeight + 'px';
// e.target.style.height = Math.min(e.target.scrollHeight, 200) + 'px'; // e.target.style.height = Math.min(e.target.scrollHeight, 200) + 'px';
}} }}

View file

@ -37,7 +37,7 @@
let ollamaVersion = ''; let ollamaVersion = '';
let loaded = false; let loaded = false;
let showShortcutsButtonElement:HTMLButtonElement
let DB = null; let DB = null;
let localDBChats = []; let localDBChats = [];
@ -184,7 +184,7 @@
if (isCtrlPressed && event.key === '/') { if (isCtrlPressed && event.key === '/') {
event.preventDefault(); event.preventDefault();
console.log('showShortcuts'); console.log('showShortcuts');
document.getElementById('show-shortcuts-button')?.click(); showShortcutsButtonElement.click();
} }
}); });
@ -203,6 +203,7 @@
<div class=" hidden lg:flex fixed bottom-0 right-0 px-3 py-3 z-10"> <div class=" hidden lg:flex fixed bottom-0 right-0 px-3 py-3 z-10">
<button <button
id="show-shortcuts-button" id="show-shortcuts-button"
bind:this={showShortcutsButtonElement}
class="text-gray-600 dark:text-gray-300 bg-gray-300/20 w-6 h-6 flex items-center justify-center text-xs rounded-full" class="text-gray-600 dark:text-gray-300 bg-gray-300/20 w-6 h-6 flex items-center justify-center text-xs rounded-full"
on:click={() => { on:click={() => {
showShortcuts = !showShortcuts; showShortcuts = !showShortcuts;

View file

@ -42,7 +42,7 @@
let stopResponseFlag = false; let stopResponseFlag = false;
let autoScroll = true; let autoScroll = true;
let processing = ''; let processing = '';
let messagesContainerElement: HTMLDivElement;
let currentRequestId = null; let currentRequestId = null;
let selectedModels = ['']; let selectedModels = [''];
@ -140,8 +140,7 @@
}; };
const scrollToBottom = () => { const scrollToBottom = () => {
const element = document.getElementById('messages-container'); messagesContainerElement.scrollTop = messagesContainerElement.scrollHeight;
element.scrollTop = element.scrollHeight;
}; };
////////////////////////// //////////////////////////
@ -821,8 +820,11 @@
<div <div
class=" pb-2.5 flex flex-col justify-between w-full flex-auto overflow-auto h-0" class=" pb-2.5 flex flex-col justify-between w-full flex-auto overflow-auto h-0"
id="messages-container" id="messages-container"
bind:this={messagesContainerElement}
on:scroll={(e) => { on:scroll={(e) => {
autoScroll = e.target.scrollHeight - e.target.scrollTop <= e.target.clientHeight + 50; autoScroll =
messagesContainerElement.scrollHeight - messagesContainerElement.scrollTop <=
messagesContainerElement.clientHeight + 50;
}} }}
> >
<div <div

View file

@ -45,7 +45,7 @@
let stopResponseFlag = false; let stopResponseFlag = false;
let autoScroll = true; let autoScroll = true;
let processing = ''; let processing = '';
let messagesContainerElement: HTMLDivElement;
let currentRequestId = null; let currentRequestId = null;
// let chatId = $page.params.id; // let chatId = $page.params.id;
@ -160,8 +160,7 @@
}; };
const scrollToBottom = () => { const scrollToBottom = () => {
const element = document.getElementById('messages-container'); messagesContainerElement.scrollTop = messagesContainerElement.scrollHeight;
element.scrollTop = element.scrollHeight;
}; };
////////////////////////// //////////////////////////
@ -852,8 +851,11 @@
<div <div
class=" pb-2.5 flex flex-col justify-between w-full flex-auto overflow-auto h-0" class=" pb-2.5 flex flex-col justify-between w-full flex-auto overflow-auto h-0"
id="messages-container" id="messages-container"
bind:this={messagesContainerElement}
on:scroll={(e) => { on:scroll={(e) => {
autoScroll = e.target.scrollHeight - e.target.scrollTop <= e.target.clientHeight + 50; autoScroll =
messagesContainerElement.scrollHeight - messagesContainerElement.scrollTop <=
messagesContainerElement.clientHeight + 50;
}} }}
> >
<div <div

View file

@ -21,7 +21,7 @@
let inputFiles = ''; let inputFiles = '';
let query = ''; let query = '';
let documentsImportInputElement: HTMLInputElement;
let tags = []; let tags = [];
let showSettingsModal = false; let showSettingsModal = false;
@ -524,6 +524,7 @@
<div class="flex space-x-2"> <div class="flex space-x-2">
<input <input
id="documents-import-input" id="documents-import-input"
bind:this={documentsImportInputElement}
bind:files={importFiles} bind:files={importFiles}
type="file" type="file"
accept=".json" accept=".json"
@ -558,9 +559,7 @@
<button <button
class="flex text-xs items-center space-x-1 px-3 py-1.5 rounded-xl bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 dark:text-gray-200 transition" class="flex text-xs items-center space-x-1 px-3 py-1.5 rounded-xl bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 dark:text-gray-200 transition"
on:click={async () => { on:click={documentsImportInputElement.click}
document.getElementById('documents-import-input')?.click();
}}
> >
<div class=" self-center mr-2 font-medium">Import Documents Mapping</div> <div class=" self-center mr-2 font-medium">Import Documents Mapping</div>

View file

@ -16,7 +16,7 @@
let localModelfiles = []; let localModelfiles = [];
let importFiles; let importFiles;
let modelfilesImportInputElement: HTMLInputElement;
const deleteModelHandler = async (tagName) => { const deleteModelHandler = async (tagName) => {
let success = null; let success = null;
@ -235,6 +235,7 @@
<div class="flex space-x-1"> <div class="flex space-x-1">
<input <input
id="modelfiles-import-input" id="modelfiles-import-input"
bind:this={modelfilesImportInputElement}
bind:files={importFiles} bind:files={importFiles}
type="file" type="file"
accept=".json" accept=".json"
@ -262,9 +263,7 @@
<button <button
class="flex text-xs items-center space-x-1 px-3 py-1.5 rounded-xl bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 dark:text-gray-200 transition" class="flex text-xs items-center space-x-1 px-3 py-1.5 rounded-xl bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 dark:text-gray-200 transition"
on:click={async () => { on:click={modelfilesImportInputElement.click}
document.getElementById('modelfiles-import-input')?.click();
}}
> >
<div class=" self-center mr-2 font-medium">Import Modelfiles</div> <div class=" self-center mr-2 font-medium">Import Modelfiles</div>

View file

@ -1,4 +1,4 @@
<script> <script lang="ts">
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { onMount, tick } from 'svelte'; import { onMount, tick } from 'svelte';
@ -21,7 +21,6 @@
let mode = 'chat'; let mode = 'chat';
let loaded = false; let loaded = false;
let text = ''; let text = '';
let selectedModelId = ''; let selectedModelId = '';
@ -30,6 +29,9 @@
let currentRequestId; let currentRequestId;
let stopResponseFlag = false; let stopResponseFlag = false;
let messagesContainerElement: HTMLDivElement;
let textCompletionAreaElement: HTMLTextAreaElement;
let system = ''; let system = '';
let messages = [ let messages = [
{ {
@ -39,13 +41,7 @@
]; ];
const scrollToBottom = () => { const scrollToBottom = () => {
let element; const element = mode === 'chat' ? messagesContainerElement : textCompletionAreaElement;
if (mode === 'chat') {
element = document.getElementById('messages-container');
} else {
element = document.getElementById('text-completion-textarea');
}
if (element) { if (element) {
element.scrollTop = element?.scrollHeight; element.scrollTop = element?.scrollHeight;
@ -417,12 +413,14 @@
<div <div
class=" pb-2.5 flex flex-col justify-between w-full flex-auto overflow-auto h-0" class=" pb-2.5 flex flex-col justify-between w-full flex-auto overflow-auto h-0"
id="messages-container" id="messages-container"
bind:this={messagesContainerElement}
> >
<div class=" h-full w-full flex flex-col"> <div class=" h-full w-full flex flex-col">
<div class="flex-1 p-1"> <div class="flex-1 p-1">
{#if mode === 'complete'} {#if mode === 'complete'}
<textarea <textarea
id="text-completion-textarea" id="text-completion-textarea"
bind:this={textCompletionAreaElement}
class="w-full h-full p-3 bg-transparent outline outline-1 outline-gray-200 dark:outline-gray-800 resize-none rounded-lg text-sm" class="w-full h-full p-3 bg-transparent outline outline-1 outline-gray-200 dark:outline-gray-800 resize-none rounded-lg text-sm"
bind:value={text} bind:value={text}
placeholder="You're a helpful assistant." placeholder="You're a helpful assistant."

View file

@ -11,7 +11,7 @@
let importFiles = ''; let importFiles = '';
let query = ''; let query = '';
let promptsImportInputElement: HTMLInputElement;
const sharePrompt = async (prompt) => { const sharePrompt = async (prompt) => {
toast.success('Redirecting you to OpenWebUI Community'); toast.success('Redirecting you to OpenWebUI Community');
@ -208,6 +208,7 @@
<div class="flex space-x-2"> <div class="flex space-x-2">
<input <input
id="prompts-import-input" id="prompts-import-input"
bind:this={promptsImportInputElement}
bind:files={importFiles} bind:files={importFiles}
type="file" type="file"
accept=".json" accept=".json"
@ -241,9 +242,7 @@
<button <button
class="flex text-xs items-center space-x-1 px-3 py-1.5 rounded-xl bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 dark:text-gray-200 transition" class="flex text-xs items-center space-x-1 px-3 py-1.5 rounded-xl bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 dark:text-gray-200 transition"
on:click={async () => { on:click={promptsImportInputElement.click}
document.getElementById('prompts-import-input')?.click();
}}
> >
<div class=" self-center mr-2 font-medium">Import Prompts</div> <div class=" self-center mr-2 font-medium">Import Prompts</div>
@ -266,7 +265,7 @@
<button <button
class="flex text-xs items-center space-x-1 px-3 py-1.5 rounded-xl bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 dark:text-gray-200 transition" class="flex text-xs items-center space-x-1 px-3 py-1.5 rounded-xl bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 dark:text-gray-200 transition"
on:click={async () => { on:click={async () => {
// document.getElementById('modelfiles-import-input')?.click(); // promptsImportInputElement.click();
let blob = new Blob([JSON.stringify($prompts)], { let blob = new Blob([JSON.stringify($prompts)], {
type: 'application/json' type: 'application/json'
}); });