mirror of
https://github.com/open-webui/open-webui
synced 2025-03-23 06:17:24 +00:00
refac: tab text variable select
This commit is contained in:
parent
0107a70343
commit
6c0d3ce736
@ -53,8 +53,9 @@
|
||||
|
||||
let recording = false;
|
||||
|
||||
let chatTextAreaElement: HTMLTextAreaElement;
|
||||
let chatInputContainerElement;
|
||||
let chatInputElement;
|
||||
|
||||
let filesInputElement;
|
||||
let commandsElement;
|
||||
|
||||
@ -70,9 +71,10 @@
|
||||
);
|
||||
|
||||
$: if (prompt) {
|
||||
if (chatTextAreaElement) {
|
||||
chatTextAreaElement.style.height = '';
|
||||
chatTextAreaElement.style.height = Math.min(chatTextAreaElement.scrollHeight, 200) + 'px';
|
||||
if (chatInputContainerElement) {
|
||||
chatInputContainerElement.style.height = '';
|
||||
chatInputContainerElement.style.height =
|
||||
Math.min(chatInputContainerElement.scrollHeight, 200) + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
@ -320,7 +322,8 @@
|
||||
atSelectedModel = data.data;
|
||||
}
|
||||
|
||||
chatTextAreaElement?.focus();
|
||||
const chatInputElement = document.getElementById('chat-input');
|
||||
chatInputElement?.focus();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@ -482,7 +485,9 @@
|
||||
}}
|
||||
onClose={async () => {
|
||||
await tick();
|
||||
chatTextAreaElement?.focus();
|
||||
|
||||
const chatInput = document.getElementById('chat-input');
|
||||
chatInput?.focus();
|
||||
}}
|
||||
>
|
||||
<button
|
||||
@ -506,9 +511,11 @@
|
||||
|
||||
<div
|
||||
bind:this={chatInputContainerElement}
|
||||
id="chat-input-container"
|
||||
class="scrollbar-hidden text-left bg-gray-50 dark:bg-gray-850 dark:text-gray-100 outline-none w-full py-3 px-1 rounded-xl resize-none h-[48px] overflow-auto"
|
||||
>
|
||||
<RichTextInput
|
||||
bind:this={chatInputElement}
|
||||
id="chat-input"
|
||||
placeholder={placeholder ? placeholder : $i18n.t('Send a Message')}
|
||||
bind:value={prompt}
|
||||
@ -634,26 +641,6 @@
|
||||
]?.at(-1);
|
||||
|
||||
commandOptionButton?.click();
|
||||
} else if (e.key === 'Tab') {
|
||||
const words = findWordIndices(prompt);
|
||||
|
||||
if (words.length > 0) {
|
||||
const word = words.at(0);
|
||||
const fullPrompt = prompt;
|
||||
|
||||
prompt = prompt.substring(0, word?.endIndex + 1);
|
||||
await tick();
|
||||
|
||||
e.target.scrollTop = e.target.scrollHeight;
|
||||
prompt = fullPrompt;
|
||||
await tick();
|
||||
|
||||
e.preventDefault();
|
||||
e.target.setSelectionRange(word?.startIndex, word.endIndex + 1);
|
||||
}
|
||||
|
||||
e.target.style.height = '';
|
||||
e.target.style.height = Math.min(e.target.scrollHeight, 200) + 'px';
|
||||
}
|
||||
|
||||
if (e.key === 'Escape') {
|
||||
|
@ -110,21 +110,17 @@
|
||||
|
||||
prompt = text;
|
||||
|
||||
const chatInputContainerElement = document.getElementById('chat-input-container');
|
||||
const chatInputElement = document.getElementById('chat-input');
|
||||
|
||||
await tick();
|
||||
|
||||
chatInputElement.style.height = '';
|
||||
chatInputElement.style.height = Math.min(chatInputElement.scrollHeight, 200) + 'px';
|
||||
if (chatInputContainerElement) {
|
||||
chatInputContainerElement.style.height = '';
|
||||
chatInputContainerElement.style.height =
|
||||
Math.min(chatInputContainerElement.scrollHeight, 200) + 'px';
|
||||
|
||||
chatInputElement?.focus();
|
||||
|
||||
await tick();
|
||||
|
||||
const words = findWordIndices(prompt);
|
||||
if (words.length > 0) {
|
||||
const word = words.at(0);
|
||||
chatInputElement.setSelectionRange(word?.startIndex, word.endIndex + 1);
|
||||
chatInputElement?.focus();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
@ -164,6 +164,60 @@
|
||||
return liftListItem(schema.nodes.list_item)(state, dispatch);
|
||||
}
|
||||
|
||||
function findNextTemplate(doc, from = 0) {
|
||||
const patterns = [
|
||||
{ start: '[', end: ']' },
|
||||
{ start: '{{', end: '}}' }
|
||||
];
|
||||
|
||||
let result = null;
|
||||
|
||||
doc.nodesBetween(from, doc.content.size, (node, pos) => {
|
||||
if (result) return false; // Stop if we've found a match
|
||||
if (node.isText) {
|
||||
const text = node.text;
|
||||
let index = Math.max(0, from - pos);
|
||||
while (index < text.length) {
|
||||
for (const pattern of patterns) {
|
||||
if (text.startsWith(pattern.start, index)) {
|
||||
const endIndex = text.indexOf(pattern.end, index + pattern.start.length);
|
||||
if (endIndex !== -1) {
|
||||
result = {
|
||||
from: pos + index,
|
||||
to: pos + endIndex + pattern.end.length
|
||||
};
|
||||
return false; // Stop searching
|
||||
}
|
||||
}
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function selectNextTemplate(state, dispatch) {
|
||||
const { doc, selection } = state;
|
||||
const from = selection.to;
|
||||
let template = findNextTemplate(doc, from);
|
||||
|
||||
if (!template) {
|
||||
// If not found, search from the beginning
|
||||
template = findNextTemplate(doc, 0);
|
||||
}
|
||||
|
||||
if (template) {
|
||||
if (dispatch) {
|
||||
const tr = state.tr.setSelection(TextSelection.create(doc, template.from, template.to));
|
||||
dispatch(tr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
const initialDoc = markdownToProseMirrorDoc(value || ''); // Convert the initial content
|
||||
|
||||
@ -234,14 +288,16 @@
|
||||
},
|
||||
|
||||
// Prevent default tab navigation and provide indent/outdent behavior inside lists:
|
||||
Tab: (state, dispatch, view) => {
|
||||
Tab: chainCommands((state, dispatch, view) => {
|
||||
const { $from } = state.selection;
|
||||
console.log('Tab key pressed', $from.parent, $from.parent.type);
|
||||
if (isInList(state)) {
|
||||
return sinkListItem(schema.nodes.list_item)(state, dispatch);
|
||||
} else {
|
||||
return selectNextTemplate(state, dispatch);
|
||||
}
|
||||
return true; // Prevent Tab from moving the focus
|
||||
},
|
||||
}),
|
||||
'Shift-Tab': (state, dispatch, view) => {
|
||||
const { $from } = state.selection;
|
||||
console.log('Shift-Tab key pressed', $from.parent, $from.parent.type);
|
||||
@ -327,6 +383,16 @@
|
||||
selection: TextSelection.atEnd(newDoc) // This sets the cursor at the end
|
||||
});
|
||||
view.updateState(newState);
|
||||
|
||||
// After updating the state, try to find and select the next template
|
||||
setTimeout(() => {
|
||||
const templateFound = selectNextTemplate(view.state, view.dispatch);
|
||||
if (!templateFound) {
|
||||
// If no template found, set cursor at the end
|
||||
const endPos = view.state.doc.content.size;
|
||||
view.dispatch(view.state.tr.setSelection(TextSelection.create(view.state.doc, endPos)));
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
|
||||
// Destroy ProseMirror instance on unmount
|
||||
|
Loading…
Reference in New Issue
Block a user