mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Merge branch 'staging' into parser-followup-2
This commit is contained in:
@ -1,3 +1,4 @@
|
||||
import { shouldSendOnEnter } from './RossAscends-mods.js';
|
||||
import { power_user } from './power-user.js';
|
||||
import { removeFromArray, runAfterAnimation, uuidv4 } from './utils.js';
|
||||
|
||||
@ -35,6 +36,7 @@ export const POPUP_RESULT = {
|
||||
* @property {boolean?} [transparent=false] - Whether to display the popup in transparent mode (no background, border, shadow or anything, only its content)
|
||||
* @property {boolean?} [allowHorizontalScrolling=false] - Whether to allow horizontal scrolling in the popup
|
||||
* @property {boolean?} [allowVerticalScrolling=false] - Whether to allow vertical scrolling in the popup
|
||||
* @property {'slow'|'fast'|'none'?} [animation='slow'] - Animation speed for the popup (opening, closing, ...)
|
||||
* @property {POPUP_RESULT|number?} [defaultResult=POPUP_RESULT.AFFIRMATIVE] - The default result of this popup when Enter is pressed. Can be changed from `POPUP_RESULT.AFFIRMATIVE`.
|
||||
* @property {CustomPopupButton[]|string[]?} [customButtons=null] - Custom buttons to add to the popup. If only strings are provided, the buttons will be added with default options, and their result will be in order from `2` onward.
|
||||
* @property {CustomPopupInput[]?} [customInputs=null] - Custom inputs to add to the popup. The display below the content and the input box, one by one.
|
||||
@ -98,7 +100,7 @@ const showPopupHelper = {
|
||||
const result = await popup.show();
|
||||
if (typeof result === 'string' || typeof result === 'boolean') throw new Error(`Invalid popup result. CONFIRM popups only support numbers, or null. Result: ${result}`);
|
||||
return result;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export class Popup {
|
||||
@ -142,7 +144,7 @@ export class Popup {
|
||||
* @param {string} [inputValue=''] - The initial value of the input field
|
||||
* @param {PopupOptions} [options={}] - Additional options for the popup
|
||||
*/
|
||||
constructor(content, type, inputValue = '', { okButton = null, cancelButton = null, rows = 1, wide = false, wider = false, large = false, transparent = false, allowHorizontalScrolling = false, allowVerticalScrolling = false, defaultResult = POPUP_RESULT.AFFIRMATIVE, customButtons = null, customInputs = null, onClosing = null, onClose = null, cropAspect = null, cropImage = null } = {}) {
|
||||
constructor(content, type, inputValue = '', { okButton = null, cancelButton = null, rows = 1, wide = false, wider = false, large = false, transparent = false, allowHorizontalScrolling = false, allowVerticalScrolling = false, animation = 'fast', defaultResult = POPUP_RESULT.AFFIRMATIVE, customButtons = null, customInputs = null, onClosing = null, onClose = null, cropAspect = null, cropImage = null } = {}) {
|
||||
Popup.util.popups.push(this);
|
||||
|
||||
// Make this popup uniquely identifiable
|
||||
@ -175,6 +177,7 @@ export class Popup {
|
||||
if (transparent) this.dlg.classList.add('transparent_dialogue_popup');
|
||||
if (allowHorizontalScrolling) this.dlg.classList.add('horizontal_scrolling_dialogue_popup');
|
||||
if (allowVerticalScrolling) this.dlg.classList.add('vertical_scrolling_dialogue_popup');
|
||||
if (animation) this.dlg.classList.add('popup--animation-' + animation);
|
||||
|
||||
// If custom button captions are provided, we set them beforehand
|
||||
this.okButton.textContent = typeof okButton === 'string' ? okButton : 'OK';
|
||||
@ -210,7 +213,7 @@ export class Popup {
|
||||
this.customInputs = customInputs;
|
||||
this.customInputs?.forEach(input => {
|
||||
if (!input.id || !(typeof input.id === 'string')) {
|
||||
console.warn('Given custom input does not have a valid id set')
|
||||
console.warn('Given custom input does not have a valid id set');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -318,20 +321,20 @@ export class Popup {
|
||||
if (String(undefined) === String(resultControl.dataset.result)) return;
|
||||
if (isNaN(result)) throw new Error('Invalid result control. Result must be a number. ' + resultControl.dataset.result);
|
||||
const type = resultControl.dataset.resultEvent || 'click';
|
||||
resultControl.addEventListener(type, () => this.complete(result));
|
||||
resultControl.addEventListener(type, async () => await this.complete(result));
|
||||
});
|
||||
|
||||
// Bind dialog listeners manually, so we can be sure context is preserved
|
||||
const cancelListener = (evt) => {
|
||||
this.complete(POPUP_RESULT.CANCELLED);
|
||||
const cancelListener = async (evt) => {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
await this.complete(POPUP_RESULT.CANCELLED);
|
||||
window.removeEventListener('cancel', cancelListenerBound);
|
||||
};
|
||||
const cancelListenerBound = cancelListener.bind(this);
|
||||
this.dlg.addEventListener('cancel', cancelListenerBound);
|
||||
|
||||
const keyListener = (evt) => {
|
||||
const keyListener = async (evt) => {
|
||||
switch (evt.key) {
|
||||
case 'Enter': {
|
||||
// CTRL+Enter counts as a closing action, but all other modifiers (ALT, SHIFT) should not trigger this
|
||||
@ -342,15 +345,23 @@ export class Popup {
|
||||
if (this.dlg != document.activeElement?.closest('.popup'))
|
||||
return;
|
||||
|
||||
// Check if the current focus is a result control. Only should we apply the compelete action
|
||||
// Check if the current focus is a result control. Only should we apply the complete action
|
||||
const resultControl = document.activeElement?.closest('.result-control');
|
||||
if (!resultControl)
|
||||
return;
|
||||
|
||||
const result = Number(document.activeElement.getAttribute('data-result') ?? this.defaultResult);
|
||||
this.complete(result);
|
||||
// Check if we are inside an input type text or a textarea field and send on enter is disabled
|
||||
const textarea = document.activeElement?.closest('textarea');
|
||||
if (textarea instanceof HTMLTextAreaElement && !shouldSendOnEnter())
|
||||
return;
|
||||
const input = document.activeElement?.closest('input[type="text"]');
|
||||
if (input instanceof HTMLInputElement && !shouldSendOnEnter())
|
||||
return;
|
||||
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
const result = Number(document.activeElement.getAttribute('data-result') ?? this.defaultResult);
|
||||
await this.complete(result);
|
||||
window.removeEventListener('keydown', keyListenerBound);
|
||||
|
||||
break;
|
||||
@ -430,8 +441,10 @@ export class Popup {
|
||||
* - All other will return the result value as provided as `POPUP_RESULT` or a custom number value
|
||||
*
|
||||
* @param {POPUP_RESULT|number} result - The result of the popup (either an existing `POPUP_RESULT` or a custom result value)
|
||||
*
|
||||
* @returns {Promise<string|number|boolean?>} A promise that resolves with the value of the popup when it is completed.
|
||||
*/
|
||||
complete(result) {
|
||||
async complete(result) {
|
||||
// In all cases besides INPUT the popup value should be the result
|
||||
/** @type {POPUP_RESULT|number|boolean|string?} */
|
||||
let value = result;
|
||||
@ -468,6 +481,8 @@ export class Popup {
|
||||
|
||||
Popup.util.lastResult = { value, result, inputResults: this.inputResults };
|
||||
this.#hide();
|
||||
|
||||
return this.#promise;
|
||||
}
|
||||
completeAffirmative() {
|
||||
return this.complete(POPUP_RESULT.AFFIRMATIVE);
|
||||
@ -627,8 +642,13 @@ export function fixToastrForDialogs() {
|
||||
// Now another case is if we only have one popup and that is currently closing. In that case the toastr container exists,
|
||||
// but we don't have an open dialog to move it into. It's just inside the existing one that will be gone in milliseconds.
|
||||
// To prevent new toasts from being showing up in there and then vanish in an instant,
|
||||
// we move the toastr back to the main body
|
||||
// we move the toastr back to the main body, or delete if its empty
|
||||
if (!dlg && isAlreadyPresent) {
|
||||
document.body.appendChild(toastContainer);
|
||||
if (!toastContainer.childNodes.length) {
|
||||
toastContainer.remove();
|
||||
} else {
|
||||
document.body.appendChild(toastContainer);
|
||||
toastContainer.classList.add('toast-top-center');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user