mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
put large message editor into additional options dlg
This commit is contained in:
67
public/scripts/extensions/quick-reply/html/qrEditor.html
Normal file
67
public/scripts/extensions/quick-reply/html/qrEditor.html
Normal file
@@ -0,0 +1,67 @@
|
||||
<div id="qr--modalEditor">
|
||||
<div id="qr--main">
|
||||
<h3>Labels and Message</h3>
|
||||
<div class="qr--labels">
|
||||
<label>
|
||||
<span class="qr--labelText">Label</span>
|
||||
<input type="text" class="text_pole" id="qr--modal-label">
|
||||
</label>
|
||||
<label>
|
||||
<span class="qr--labelText">Title</span>
|
||||
<small class="qr--labelHint">(tooltip, leave empty to show message or /command)</small>
|
||||
<input type="text" class="text_pole" id="qr--modal-title">
|
||||
</label>
|
||||
</div>
|
||||
<div class="qr--modal-messageContainer">
|
||||
<label for="qr--modal-message">Message / Command:</label>
|
||||
<textarea id="qr--modal-message"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div id="qr--qrOptions">
|
||||
<h3>Context Menu</h3>
|
||||
<div id="qr--ctxEditor">
|
||||
<template id="qr--ctxItem">
|
||||
<div class="qr--ctxItem" data-order="0">
|
||||
<div class="drag-handle ui-sortable-handle">☰</div>
|
||||
<select class="qr--set"></select>
|
||||
<label class="qr--isChainedLabel checkbox_label" title="When enabled, the current Quick Reply will be sent together with (before) the clicked QR from the context menu.">
|
||||
Chaining:
|
||||
<input type="checkbox" class="qr--isChained">
|
||||
</label>
|
||||
<div class="qr--delete menu_button menu_button_icon fa-solid fa-trash-can" title="Remove entry"></div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="qr--ctxEditorActions">
|
||||
<span id="qr--ctxAdd" class="menu_button menu_button_icon fa-solid fa-plus" title="Add quick reply set to context menu"></span>
|
||||
</div>
|
||||
|
||||
|
||||
<h3>Auto-Execute</h3>
|
||||
<div class="flex-container flexFlowColumn">
|
||||
<label class="checkbox_label">
|
||||
<input type="checkbox" id="qr--isHidden" >
|
||||
<span><i class="fa-solid fa-fw fa-eye-slash"></i> Invisible (auto-execute only)</span>
|
||||
</label>
|
||||
<label class="checkbox_label">
|
||||
<input type="checkbox" id="qr--executeOnStartup" >
|
||||
<span><i class="fa-solid fa-fw fa-rocket"></i> Execute on app startup</span>
|
||||
</label>
|
||||
<label class="checkbox_label">
|
||||
<input type="checkbox" id="qr--executeOnUser" >
|
||||
<span><i class="fa-solid fa-fw fa-user"></i> Execute on user message</span>
|
||||
</label>
|
||||
<label class="checkbox_label">
|
||||
<input type="checkbox" id="qr--executeOnAi" >
|
||||
<span><i class="fa-solid fa-fw fa-robot"></i> Execute on AI message</span>
|
||||
</label>
|
||||
<label class="checkbox_label">
|
||||
<input type="checkbox" id="qr--executeOnChatChange" >
|
||||
<span><i class="fa-solid fa-fw fa-message"></i> Execute on opening chat</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@@ -1,53 +0,0 @@
|
||||
<div id="qr--qrOptions">
|
||||
<h3>Context Menu</h3>
|
||||
<div id="qr--ctxEditor">
|
||||
<template id="qr--ctxItem">
|
||||
<div class="qr--ctxItem" data-order="0">
|
||||
<div class="drag-handle ui-sortable-handle">☰</div>
|
||||
<select class="qr--set"></select>
|
||||
<label class="qr--isChainedLabel checkbox_label" title="When enabled, the current Quick Reply will be sent together with (before) the clicked QR from the context menu.">
|
||||
Chaining:
|
||||
<input type="checkbox" class="qr--isChained">
|
||||
</label>
|
||||
<div class="qr--delete menu_button menu_button_icon fa-solid fa-trash-can" title="Remove entry"></div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="qr--ctxEditorActions">
|
||||
<span id="qr--ctxAdd" class="menu_button menu_button_icon fa-solid fa-plus" title="Add quick reply set to context menu"></span>
|
||||
</div>
|
||||
|
||||
|
||||
<h3>Auto-Execute</h3>
|
||||
<div class="flex-container flexFlowColumn">
|
||||
<label class="checkbox_label">
|
||||
<input type="checkbox" id="qr--isHidden" >
|
||||
<span><i class="fa-solid fa-fw fa-eye-slash"></i> Invisible (auto-execute only)</span>
|
||||
</label>
|
||||
<label class="checkbox_label">
|
||||
<input type="checkbox" id="qr--executeOnStartup" >
|
||||
<span><i class="fa-solid fa-fw fa-rocket"></i> Execute on app startup</span>
|
||||
</label>
|
||||
<label class="checkbox_label">
|
||||
<input type="checkbox" id="qr--executeOnUser" >
|
||||
<span><i class="fa-solid fa-fw fa-user"></i> Execute on user message</span>
|
||||
</label>
|
||||
<label class="checkbox_label">
|
||||
<input type="checkbox" id="qr--executeOnAi" >
|
||||
<span><i class="fa-solid fa-fw fa-robot"></i> Execute on AI message</span>
|
||||
</label>
|
||||
<label class="checkbox_label">
|
||||
<input type="checkbox" id="qr--executeOnChatChange" >
|
||||
<span><i class="fa-solid fa-fw fa-message"></i> Execute on opening chat</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
<h3>UI Options</h3>
|
||||
<div class="flex-container flexFlowColumn">
|
||||
<label>
|
||||
Title (tooltip, leave empty to show the message or /command)
|
||||
<input type="text" class="text_pole" id="qr--title">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
@@ -38,6 +38,8 @@ export class QuickReply {
|
||||
/**@type {HTMLElement}*/ dom;
|
||||
/**@type {HTMLElement}*/ domLabel;
|
||||
/**@type {HTMLElement}*/ settingsDom;
|
||||
/**@type {HTMLInputElement}*/ settingsDomLabel;
|
||||
/**@type {HTMLTextAreaElement}*/ settingsDomMessage;
|
||||
|
||||
|
||||
get hasContext() {
|
||||
@@ -124,6 +126,7 @@ export class QuickReply {
|
||||
const lblContainer = document.createElement('div'); {
|
||||
lblContainer.classList.add('qr--set-itemLabelContainer');
|
||||
const lbl = document.createElement('input'); {
|
||||
this.settingsDomLabel = lbl;
|
||||
lbl.classList.add('qr--set-itemLabel');
|
||||
lbl.classList.add('text_pole');
|
||||
lbl.value = this.label;
|
||||
@@ -139,29 +142,14 @@ export class QuickReply {
|
||||
opt.classList.add('menu_button');
|
||||
opt.classList.add('fa-solid');
|
||||
opt.textContent = '⁝';
|
||||
opt.title = 'Additional options:\n - context menu\n - auto-execution\n - tooltip';
|
||||
opt.addEventListener('click', ()=>this.showOptions());
|
||||
opt.title = 'Additional options:\n - large editor\n - context menu\n - auto-execution\n - tooltip';
|
||||
opt.addEventListener('click', ()=>this.showEditor());
|
||||
optContainer.append(opt);
|
||||
}
|
||||
item.append(optContainer);
|
||||
}
|
||||
const expandContainer = document.createElement('div'); {
|
||||
expandContainer.classList.add('qr--set-optionsContainer');
|
||||
const expand = document.createElement('div'); {
|
||||
expand.classList.add('qr--expand');
|
||||
expand.classList.add('menu_button');
|
||||
expand.classList.add('menu_button_icon');
|
||||
expand.classList.add('editor_maximize');
|
||||
expand.classList.add('fa-solid');
|
||||
expand.classList.add('fa-maximize');
|
||||
expand.title = 'Expand the editor';
|
||||
expand.setAttribute('data-for', `qr--set--item${this.id}`);
|
||||
expand.setAttribute('data-tab', 'true');
|
||||
expandContainer.append(expand);
|
||||
}
|
||||
item.append(expandContainer);
|
||||
}
|
||||
const mes = document.createElement('textarea'); {
|
||||
this.settingsDomMessage = mes;
|
||||
mes.id = `qr--set--item${this.id}`;
|
||||
mes.classList.add('qr--set-itemMessage');
|
||||
mes.value = this.message;
|
||||
@@ -191,14 +179,67 @@ export class QuickReply {
|
||||
this.settingsDom?.remove();
|
||||
}
|
||||
|
||||
async showOptions() {
|
||||
const response = await fetch('/scripts/extensions/quick-reply/html/qrOptions.html', { cache: 'no-store' });
|
||||
async showEditor() {
|
||||
const response = await fetch('/scripts/extensions/quick-reply/html/qrEditor.html', { cache: 'no-store' });
|
||||
if (response.ok) {
|
||||
this.template = document.createRange().createContextualFragment(await response.text()).querySelector('#qr--qrOptions');
|
||||
this.template = document.createRange().createContextualFragment(await response.text()).querySelector('#qr--modalEditor');
|
||||
/**@type {HTMLElement} */
|
||||
// @ts-ignore
|
||||
const dom = this.template.cloneNode(true);
|
||||
const popupResult = callPopup(dom, 'text', undefined, { okButton: 'OK', wide: false, large: false, rows: 1 });
|
||||
const popupResult = callPopup(dom, 'text', undefined, { okButton: 'OK', wide: true, large: true, rows: 1 });
|
||||
|
||||
// basics
|
||||
/**@type {HTMLInputElement}*/
|
||||
const label = dom.querySelector('#qr--modal-label');
|
||||
label.value = this.label;
|
||||
label.addEventListener('input', ()=>{
|
||||
this.updateLabel(label.value);
|
||||
});
|
||||
/**@type {HTMLInputElement}*/
|
||||
const title = dom.querySelector('#qr--modal-title');
|
||||
title.value = this.title;
|
||||
title.addEventListener('input', () => {
|
||||
this.updateTitle(title.value);
|
||||
});
|
||||
/**@type {HTMLTextAreaElement}*/
|
||||
const message = dom.querySelector('#qr--modal-message');
|
||||
message.value = this.message;
|
||||
message.addEventListener('input', () => {
|
||||
this.updateMessage(message.value);
|
||||
});
|
||||
//TODO move tab support for textarea into its own helper(?) and use for both this and .editor_maximize
|
||||
message.addEventListener('keydown', (evt) => {
|
||||
if (evt.key == 'Tab' && !evt.shiftKey && !evt.ctrlKey && !evt.altKey) {
|
||||
evt.preventDefault();
|
||||
const start = message.selectionStart;
|
||||
const end = message.selectionEnd;
|
||||
if (end - start > 0 && message.value.substring(start, end).includes('\n')) {
|
||||
const lineStart = message.value.lastIndexOf('\n', start);
|
||||
const count = message.value.substring(lineStart, end).split('\n').length - 1;
|
||||
message.value = `${message.value.substring(0, lineStart)}${message.value.substring(lineStart, end).replace(/\n/g, '\n\t')}${message.value.substring(end)}`;
|
||||
message.selectionStart = start + 1;
|
||||
message.selectionEnd = end + count;
|
||||
this.updateMessage(message.value);
|
||||
} else {
|
||||
message.value = `${message.value.substring(0, start)}\t${message.value.substring(end)}`;
|
||||
message.selectionStart = start + 1;
|
||||
message.selectionEnd = end + 1;
|
||||
this.updateMessage(message.value);
|
||||
}
|
||||
} else if (evt.key == 'Tab' && evt.shiftKey && !evt.ctrlKey && !evt.altKey) {
|
||||
evt.preventDefault();
|
||||
const start = message.selectionStart;
|
||||
const end = message.selectionEnd;
|
||||
const lineStart = message.value.lastIndexOf('\n', start);
|
||||
const count = message.value.substring(lineStart, end).split('\n\t').length - 1;
|
||||
message.value = `${message.value.substring(0, lineStart)}${message.value.substring(lineStart, end).replace(/\n\t/g, '\n')}${message.value.substring(end)}`;
|
||||
message.selectionStart = start - 1;
|
||||
message.selectionEnd = end - count;
|
||||
this.updateMessage(message.value);
|
||||
}
|
||||
});
|
||||
|
||||
// context menu
|
||||
/**@type {HTMLTemplateElement}*/
|
||||
const tpl = dom.querySelector('#qr--ctxItem');
|
||||
const linkList = dom.querySelector('#qr--ctxEditor');
|
||||
@@ -300,18 +341,9 @@ export class QuickReply {
|
||||
this.updateContext();
|
||||
});
|
||||
|
||||
// UI options
|
||||
/**@type {HTMLInputElement}*/
|
||||
const title = dom.querySelector('#qr--title');
|
||||
title.value = this.title;
|
||||
title.addEventListener('input', () => {
|
||||
this.title = title.value.trim();
|
||||
this.updateContext();
|
||||
});
|
||||
|
||||
await popupResult;
|
||||
} else {
|
||||
warn('failed to fetch qrOptions template');
|
||||
warn('failed to fetch qrEditor template');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,6 +363,9 @@ export class QuickReply {
|
||||
*/
|
||||
updateMessage(value) {
|
||||
if (this.onUpdate) {
|
||||
if (this.settingsDomMessage.value != value) {
|
||||
this.settingsDomMessage.value = value;
|
||||
}
|
||||
this.message = value;
|
||||
this.updateRender();
|
||||
this.onUpdate(this);
|
||||
@@ -342,12 +377,26 @@ export class QuickReply {
|
||||
*/
|
||||
updateLabel(value) {
|
||||
if (this.onUpdate) {
|
||||
if (this.settingsDomLabel.value != value) {
|
||||
this.settingsDomLabel.value = value;
|
||||
}
|
||||
this.label = value;
|
||||
this.updateRender();
|
||||
this.onUpdate(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
*/
|
||||
updateTitle(value) {
|
||||
if (this.onUpdate) {
|
||||
this.title = value;
|
||||
this.updateRender();
|
||||
this.onUpdate(this);
|
||||
}
|
||||
}
|
||||
|
||||
updateContext() {
|
||||
if (this.onUpdate) {
|
||||
this.updateRender();
|
||||
|
@@ -184,12 +184,9 @@
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
#qr--settings #qr--set-qrList .qr--set-qrListContents > .qr--set-item > :nth-child(4) {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
#qr--settings #qr--set-qrList .qr--set-qrListContents > .qr--set-item > :nth-child(5) {
|
||||
flex: 1 1 75%;
|
||||
}
|
||||
#qr--settings #qr--set-qrList .qr--set-qrListContents > .qr--set-item > :nth-child(6) {
|
||||
#qr--settings #qr--set-qrList .qr--set-qrListContents > .qr--set-item > :nth-child(5) {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
#qr--settings #qr--set-qrList .qr--set-qrListContents > .qr--set-item .qr--set-itemLabel,
|
||||
@@ -212,3 +209,49 @@
|
||||
gap: 0.5em;
|
||||
align-items: baseline;
|
||||
}
|
||||
#dialogue_popup:has(#qr--modalEditor) {
|
||||
aspect-ratio: unset;
|
||||
}
|
||||
#dialogue_popup:has(#qr--modalEditor) #dialogue_popup_text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
#dialogue_popup:has(#qr--modalEditor) #dialogue_popup_text > #qr--modalEditor {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 1em;
|
||||
}
|
||||
#dialogue_popup:has(#qr--modalEditor) #dialogue_popup_text > #qr--modalEditor > #qr--main {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
#dialogue_popup:has(#qr--modalEditor) #dialogue_popup_text > #qr--modalEditor > #qr--main > .qr--labels {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 0.5em;
|
||||
}
|
||||
#dialogue_popup:has(#qr--modalEditor) #dialogue_popup_text > #qr--modalEditor > #qr--main > .qr--labels > label {
|
||||
flex: 1 1 1px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
#dialogue_popup:has(#qr--modalEditor) #dialogue_popup_text > #qr--modalEditor > #qr--main > .qr--labels > label > .qr--labelText {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
#dialogue_popup:has(#qr--modalEditor) #dialogue_popup_text > #qr--modalEditor > #qr--main > .qr--labels > label > .qr--labelHint {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
#dialogue_popup:has(#qr--modalEditor) #dialogue_popup_text > #qr--modalEditor > #qr--main > .qr--labels > label > input {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
#dialogue_popup:has(#qr--modalEditor) #dialogue_popup_text > #qr--modalEditor > #qr--main > .qr--modal-messageContainer {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
#dialogue_popup:has(#qr--modalEditor) #dialogue_popup_text > #qr--modalEditor > #qr--main > .qr--modal-messageContainer > #qr--modal-message {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
@@ -198,9 +198,8 @@
|
||||
> :nth-child(1) { flex: 0 0 auto; }
|
||||
> :nth-child(2) { flex: 1 1 25%; }
|
||||
> :nth-child(3) { flex: 0 0 auto; }
|
||||
> :nth-child(4) { flex: 0 0 auto; }
|
||||
> :nth-child(5) { flex: 1 1 75%; }
|
||||
> :nth-child(6) { flex: 0 0 auto; }
|
||||
> :nth-child(4) { flex: 1 1 75%; }
|
||||
> :nth-child(5) { flex: 0 0 auto; }
|
||||
.qr--set-itemLabel, .qr--action {
|
||||
margin: 0;
|
||||
}
|
||||
@@ -233,3 +232,55 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#dialogue_popup:has(#qr--modalEditor) {
|
||||
aspect-ratio: unset;
|
||||
|
||||
#dialogue_popup_text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
> #qr--modalEditor {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 1em;
|
||||
|
||||
> #qr--main {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
> .qr--labels {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 0.5em;
|
||||
> label {
|
||||
flex: 1 1 1px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
> .qr--labelText {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
> .qr--labelHint {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
> input {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
> .qr--modal-messageContainer {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
> #qr--modal-message {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user