mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-03-17 20:40:10 +01:00
Merge branch 'staging' into timed-wi
This commit is contained in:
commit
5de80f4c6d
@ -109,7 +109,6 @@ dialog {
|
||||
|
||||
.menu_button.popup-button-ok {
|
||||
background-color: var(--crimson70a);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.menu_button.popup-button-ok:hover {
|
||||
@ -132,3 +131,17 @@ dialog {
|
||||
filter: brightness(1.3) saturate(1.3);
|
||||
}
|
||||
|
||||
.popup .popup-button-close {
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
right: -6px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
font-size: 20px;
|
||||
padding: 2px 3px 3px 2px;
|
||||
|
||||
filter: brightness(0.8);
|
||||
|
||||
/* Fix weird animation issue with font-scaling during popup open */
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
|
@ -4855,10 +4855,11 @@
|
||||
</div>
|
||||
<textarea class="popup-input text_pole result-control" rows="1" data-result="1"></textarea>
|
||||
<div class="popup-controls">
|
||||
<div class="popup-button-ok menu_button result-control" data-i18n="Delete" data-result="1" tabindex="0">Delete</div>
|
||||
<div class="popup-button-cancel menu_button result-control" data-i18n="Cancel" data-result="0" tabindex="0">Cancel</div>
|
||||
<div class="popup-button-ok menu_button result-control" data-result="1" data-i18n="Delete">Delete</div>
|
||||
<div class="popup-button-cancel menu_button result-control" data-result="0" data-i18n="Cancel">Cancel</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="popup-button-close right_menu_button fa-solid fa-circle-xmark" data-result="0" title="Close popup" data-i18n="[title]Close popup"></div>
|
||||
</dialog>
|
||||
</template>
|
||||
<div id="shadow_popup">
|
||||
|
@ -3,6 +3,7 @@
|
||||
"checkJs": true,
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"allowUmdGlobalAccess": true,
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
|
@ -239,6 +239,8 @@ import { initCustomSelectedSamplers, validateDisabledSamplers } from './scripts/
|
||||
import { DragAndDropHandler } from './scripts/dragdrop.js';
|
||||
import { INTERACTABLE_CONTROL_CLASS, initKeyboard } from './scripts/keyboard.js';
|
||||
import { initDynamicStyles } from './scripts/dynamic-styles.js';
|
||||
import { SlashCommandEnumValue, enumTypes } from './scripts/slash-commands/SlashCommandEnumValue.js';
|
||||
import { enumIcons } from './scripts/slash-commands/SlashCommandCommonEnumsProvider.js';
|
||||
|
||||
//exporting functions and vars for mods
|
||||
export {
|
||||
@ -2122,7 +2124,7 @@ export function addCopyToCodeBlocks(messageElement) {
|
||||
hljs.highlightElement(codeBlocks.get(i));
|
||||
if (navigator.clipboard !== undefined) {
|
||||
const copyButton = document.createElement('i');
|
||||
copyButton.classList.add('fa-solid', 'fa-copy', 'code-copy');
|
||||
copyButton.classList.add('fa-solid', 'fa-copy', 'code-copy', 'interactable');
|
||||
copyButton.title = 'Copy code';
|
||||
codeBlocks.get(i).appendChild(copyButton);
|
||||
copyButton.addEventListener('pointerup', function (event) {
|
||||
@ -2376,6 +2378,10 @@ export function substituteParamsExtended(content, additionalMacro = {}) {
|
||||
* @returns {string} The string with substituted parameters.
|
||||
*/
|
||||
export function substituteParams(content, _name1, _name2, _original, _group, _replaceCharacterCard = true, additionalMacro = {}) {
|
||||
if (!content) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const environment = {};
|
||||
|
||||
if (typeof _original === 'string') {
|
||||
@ -8817,6 +8823,9 @@ jQuery(async function () {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Collect all unique API names in an array
|
||||
const uniqueAPIs = [...new Set(Object.values(CONNECT_API_MAP).map(x => x.selected))];
|
||||
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'dupe',
|
||||
callback: DupeChar,
|
||||
@ -8825,16 +8834,15 @@ jQuery(async function () {
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'api',
|
||||
callback: connectAPISlash,
|
||||
namedArgumentList: [],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'API to connect to',
|
||||
[ARGUMENT_TYPE.STRING],
|
||||
true,
|
||||
false,
|
||||
null,
|
||||
Object.keys(CONNECT_API_MAP),
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'API to connect to',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: false,
|
||||
enumList: Object.entries(CONNECT_API_MAP).map(([api, { selected }]) =>
|
||||
new SlashCommandEnumValue(api, selected, enumTypes.getBasedOnIndex(uniqueAPIs.findIndex(x => x === selected)),
|
||||
selected[0].toUpperCase() ?? enumIcons.default)),
|
||||
}),
|
||||
],
|
||||
helpString: `
|
||||
<div>
|
||||
@ -8923,11 +8931,12 @@ jQuery(async function () {
|
||||
name: 'instruct',
|
||||
callback: selectInstructCallback,
|
||||
returns: 'current preset',
|
||||
namedArgumentList: [],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'name', [ARGUMENT_TYPE.STRING], false,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'instruct preset name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
enumProvider: () => instruct_presets.map(preset => new SlashCommandEnumValue(preset.name, null, enumTypes.enum, enumIcons.preset)),
|
||||
}),
|
||||
],
|
||||
helpString: `
|
||||
<div>
|
||||
@ -8958,9 +8967,11 @@ jQuery(async function () {
|
||||
callback: selectContextCallback,
|
||||
returns: 'template name',
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'name', [ARGUMENT_TYPE.STRING], false,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'context preset name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
enumProvider: () => context_presets.map(preset => new SlashCommandEnumValue(preset.name, null, enumTypes.enum, enumIcons.preset)),
|
||||
}),
|
||||
],
|
||||
helpString: 'Selects context template by name. Gets the current template if no name is provided',
|
||||
}));
|
||||
|
@ -38,6 +38,7 @@ const chara_note_position = {
|
||||
function setNoteTextCommand(_, text) {
|
||||
$('#extension_floating_prompt').val(text).trigger('input');
|
||||
toastr.success('Author\'s Note text updated');
|
||||
return '';
|
||||
}
|
||||
|
||||
function setNoteDepthCommand(_, text) {
|
||||
@ -50,6 +51,7 @@ function setNoteDepthCommand(_, text) {
|
||||
|
||||
$('#extension_floating_depth').val(Math.abs(value)).trigger('input');
|
||||
toastr.success('Author\'s Note depth updated');
|
||||
return '';
|
||||
}
|
||||
|
||||
function setNoteIntervalCommand(_, text) {
|
||||
@ -62,6 +64,7 @@ function setNoteIntervalCommand(_, text) {
|
||||
|
||||
$('#extension_floating_interval').val(Math.abs(value)).trigger('input');
|
||||
toastr.success('Author\'s Note frequency updated');
|
||||
return '';
|
||||
}
|
||||
|
||||
function setNotePositionCommand(_, text) {
|
||||
@ -79,6 +82,7 @@ function setNotePositionCommand(_, text) {
|
||||
|
||||
$(`input[name="extension_floating_position"][value="${position}"]`).prop('checked', true).trigger('input');
|
||||
toastr.info('Author\'s Note position updated');
|
||||
return '';
|
||||
}
|
||||
|
||||
function updateSettings() {
|
||||
|
@ -750,8 +750,10 @@ export class AutoComplete {
|
||||
}
|
||||
// autocomplete shown or not, cursor anywhere
|
||||
switch (evt.key) {
|
||||
// The first is a non-breaking space, the second is a regular space.
|
||||
case ' ':
|
||||
case ' ': {
|
||||
if (evt.ctrlKey) {
|
||||
if (evt.ctrlKey || evt.altKey) {
|
||||
if (this.isActive && this.isReplaceable) {
|
||||
// ctrl-space to toggle details for selected item
|
||||
this.toggleDetails();
|
||||
@ -759,6 +761,8 @@ export class AutoComplete {
|
||||
// ctrl-space to force show autocomplete
|
||||
this.show(false, true);
|
||||
}
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
@ -143,6 +143,11 @@ export class AutoCompleteOption {
|
||||
}
|
||||
li.append(specs);
|
||||
}
|
||||
const stopgap = document.createElement('span'); {
|
||||
stopgap.classList.add('stopgap');
|
||||
stopgap.textContent = '';
|
||||
li.append(stopgap);
|
||||
}
|
||||
const help = document.createElement('span'); {
|
||||
help.classList.add('help');
|
||||
const content = document.createElement('span'); {
|
||||
|
@ -95,7 +95,7 @@ function onLockBackgroundClick(e) {
|
||||
|
||||
if (!chatName) {
|
||||
toastr.warning('Select a chat to lock the background for it');
|
||||
return;
|
||||
return '';
|
||||
}
|
||||
|
||||
const relativeBgImage = getUrlParameter(this);
|
||||
@ -103,6 +103,7 @@ function onLockBackgroundClick(e) {
|
||||
saveBackgroundMetadata(relativeBgImage);
|
||||
setCustomBackground();
|
||||
highlightLockedBackground();
|
||||
return '';
|
||||
}
|
||||
|
||||
function onUnlockBackgroundClick(e) {
|
||||
@ -110,6 +111,7 @@ function onUnlockBackgroundClick(e) {
|
||||
removeBackgroundMetadata();
|
||||
unsetCustomBackground();
|
||||
highlightLockedBackground();
|
||||
return '';
|
||||
}
|
||||
|
||||
function hasCustomBackground() {
|
||||
@ -319,7 +321,7 @@ async function autoBackgroundCommand() {
|
||||
const options = bgTitles.map(x => ({ element: x, text: x.innerText.trim() })).filter(x => x.text.length > 0);
|
||||
if (options.length == 0) {
|
||||
toastr.warning('No backgrounds to choose from. Please upload some images to the "backgrounds" folder.');
|
||||
return;
|
||||
return '';
|
||||
}
|
||||
|
||||
const list = options.map(option => `- ${option.text}`).join('\n');
|
||||
@ -330,11 +332,12 @@ async function autoBackgroundCommand() {
|
||||
|
||||
if (bestMatch.length == 0) {
|
||||
toastr.warning('No match found. Please try again.');
|
||||
return;
|
||||
return '';
|
||||
}
|
||||
|
||||
console.debug('Automatically choosing background:', bestMatch);
|
||||
bestMatch[0].item.element.click();
|
||||
return '';
|
||||
}
|
||||
|
||||
export async function getBackgrounds() {
|
||||
|
@ -35,7 +35,7 @@ import {
|
||||
extractTextFromOffice,
|
||||
} from './utils.js';
|
||||
import { extension_settings, renderExtensionTemplateAsync, saveMetadataDebounced } from './extensions.js';
|
||||
import { POPUP_RESULT, POPUP_TYPE, callGenericPopup } from './popup.js';
|
||||
import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js';
|
||||
import { ScraperManager } from './scrapers.js';
|
||||
import { DragAndDropHandler } from './dragdrop.js';
|
||||
|
||||
@ -566,7 +566,7 @@ export function isExternalMediaAllowed() {
|
||||
return !power_user.forbid_external_media;
|
||||
}
|
||||
|
||||
function enlargeMessageImage() {
|
||||
async function enlargeMessageImage() {
|
||||
const mesBlock = $(this).closest('.mes');
|
||||
const mesId = mesBlock.attr('mesid');
|
||||
const message = chat[mesId];
|
||||
@ -580,14 +580,28 @@ function enlargeMessageImage() {
|
||||
const img = document.createElement('img');
|
||||
img.classList.add('img_enlarged');
|
||||
img.src = imgSrc;
|
||||
const imgHolder = document.createElement('div');
|
||||
imgHolder.classList.add('img_enlarged_holder');
|
||||
imgHolder.append(img);
|
||||
const imgContainer = $('<div><pre><code></code></pre></div>');
|
||||
imgContainer.prepend(img);
|
||||
imgContainer.prepend(imgHolder);
|
||||
imgContainer.addClass('img_enlarged_container');
|
||||
imgContainer.find('code').addClass('txt').text(title);
|
||||
const titleEmpty = !title || title.trim().length === 0;
|
||||
imgContainer.find('pre').toggle(!titleEmpty);
|
||||
addCopyToCodeBlocks(imgContainer);
|
||||
callGenericPopup(imgContainer, POPUP_TYPE.TEXT, '', { wide: true, large: true });
|
||||
|
||||
const popup = new Popup(imgContainer, POPUP_TYPE.DISPLAY, '', { large: true, transparent: true });
|
||||
|
||||
popup.dlg.style.width = 'unset';
|
||||
popup.dlg.style.height = 'unset';
|
||||
|
||||
img.addEventListener('click', () => {
|
||||
const shouldZoom = !img.classList.contains('zoomed');
|
||||
img.classList.toggle('zoomed', shouldZoom);
|
||||
});
|
||||
|
||||
await popup.show();
|
||||
}
|
||||
|
||||
async function deleteMessageImage() {
|
||||
|
@ -2,6 +2,10 @@ import { deleteAttachment, getDataBankAttachments, getDataBankAttachmentsForSour
|
||||
import { extension_settings, renderExtensionTemplateAsync } from '../../extensions.js';
|
||||
import { SlashCommand } from '../../slash-commands/SlashCommand.js';
|
||||
import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';
|
||||
import { SlashCommandClosure } from '../../slash-commands/SlashCommandClosure.js';
|
||||
import { enumIcons } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';
|
||||
import { SlashCommandEnumValue, enumTypes } from '../../slash-commands/SlashCommandEnumValue.js';
|
||||
import { SlashCommandExecutor } from '../../slash-commands/SlashCommandExecutor.js';
|
||||
import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
|
||||
|
||||
/**
|
||||
@ -196,9 +200,31 @@ jQuery(async () => {
|
||||
const buttons = await renderExtensionTemplateAsync('attachments', 'buttons', {});
|
||||
$('#extensionsMenu').prepend(buttons);
|
||||
|
||||
/** A collection of local enum providers for this context of data bank */
|
||||
const localEnumProviders = {
|
||||
/**
|
||||
* All attachments in the data bank based on the source argument. If not provided, defaults to 'chat'.
|
||||
* @param {'name' | 'url'} returnField - Whether the enum should return the 'name' field or the 'url'
|
||||
* @param {'chat' | 'character' | 'global' | ''} fallbackSource - The source to use if the source argument is not provided. Empty string to use all sources.
|
||||
* */
|
||||
attachments: (returnField = 'name', fallbackSource = 'chat') => (/** @type {SlashCommandExecutor} */ executor) => {
|
||||
const source = executor.namedArgumentList.find(it => it.name == 'source')?.value ?? fallbackSource;
|
||||
if (source instanceof SlashCommandClosure) throw new Error('Argument \'source\' does not support closures');
|
||||
const attachments = getAttachments(source);
|
||||
|
||||
return attachments.map(attachment => new SlashCommandEnumValue(
|
||||
returnField === 'name' ? attachment.name : attachment.url,
|
||||
`${enumIcons.getStateIcon(!extension_settings.disabled_attachments.includes(attachment.url))} [${source}] ${returnField === 'url' ? attachment.name : attachment.url}`,
|
||||
enumTypes.enum, enumIcons.file));
|
||||
},
|
||||
};
|
||||
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'db',
|
||||
callback: () => document.getElementById('manageAttachments')?.click(),
|
||||
callback: () => {
|
||||
document.getElementById('manageAttachments')?.click();
|
||||
return '';
|
||||
},
|
||||
aliases: ['databank', 'data-bank'],
|
||||
helpString: 'Open the data bank',
|
||||
}));
|
||||
@ -224,7 +250,13 @@ jQuery(async () => {
|
||||
new SlashCommandNamedArgument('source', 'The source of the attachment.', ARGUMENT_TYPE.STRING, false, false, '', TYPES),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument('The name or URL of the attachment.', ARGUMENT_TYPE.STRING, true, false),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'The name or URL of the attachment.',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
acceptsMultiple: false,
|
||||
enumProvider: localEnumProviders.attachments('name', ''),
|
||||
}),
|
||||
],
|
||||
returns: ARGUMENT_TYPE.STRING,
|
||||
}));
|
||||
@ -251,8 +283,18 @@ jQuery(async () => {
|
||||
helpString: 'Update an attachment in the Data Bank, preserving its name. Returns a new URL of the attachment.',
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument('source', 'The source for the attachment.', ARGUMENT_TYPE.STRING, false, false, 'chat', TYPES),
|
||||
new SlashCommandNamedArgument('name', 'The name of the attachment.', ARGUMENT_TYPE.STRING, false, false),
|
||||
new SlashCommandNamedArgument('url', 'The URL of the attachment to update.', ARGUMENT_TYPE.STRING, false, false),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'name',
|
||||
description: 'The name of the attachment.',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
enumProvider: localEnumProviders.attachments('name'),
|
||||
}),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'url',
|
||||
description: 'The URL of the attachment.',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
enumProvider: localEnumProviders.attachments('url'),
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument('The content of the file attachment.', ARGUMENT_TYPE.STRING, true, false),
|
||||
@ -269,7 +311,12 @@ jQuery(async () => {
|
||||
new SlashCommandNamedArgument('source', 'The source of the attachment.', ARGUMENT_TYPE.STRING, false, false, '', TYPES),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument('The name or URL of the attachment.', ARGUMENT_TYPE.STRING, true, false),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'The name or URL of the attachment.',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: localEnumProviders.attachments('name', ''),
|
||||
}),
|
||||
],
|
||||
}));
|
||||
|
||||
@ -282,7 +329,12 @@ jQuery(async () => {
|
||||
new SlashCommandNamedArgument('source', 'The source of the attachment.', ARGUMENT_TYPE.STRING, false, false, '', TYPES),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument('The name or URL of the attachment.', ARGUMENT_TYPE.STRING, true, false),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'The name or URL of the attachment.',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: localEnumProviders.attachments('name', ''),
|
||||
}),
|
||||
],
|
||||
}));
|
||||
|
||||
@ -295,7 +347,12 @@ jQuery(async () => {
|
||||
new SlashCommandNamedArgument('source', 'The source of the attachment.', ARGUMENT_TYPE.STRING, false, false, 'chat', TYPES),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument('The name or URL of the attachment.', ARGUMENT_TYPE.STRING, true, false),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'The name or URL of the attachment.',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: localEnumProviders.attachments(),
|
||||
}),
|
||||
],
|
||||
}));
|
||||
});
|
||||
|
@ -8,6 +8,8 @@ import { textgen_types, textgenerationwebui_settings } from '../../textgen-setti
|
||||
import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
|
||||
import { SlashCommand } from '../../slash-commands/SlashCommand.js';
|
||||
import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';
|
||||
import { SlashCommandEnumValue } from '../../slash-commands/SlashCommandEnumValue.js';
|
||||
import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';
|
||||
export { MODULE_NAME };
|
||||
|
||||
const MODULE_NAME = 'caption';
|
||||
@ -451,11 +453,14 @@ jQuery(async function () {
|
||||
returns: 'caption',
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument(
|
||||
'quiet', 'suppress sending a captioned message', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false', ['true', 'false'],
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'id', 'get image from a message with this ID', [ARGUMENT_TYPE.NUMBER], false, false,
|
||||
'quiet', 'suppress sending a captioned message', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false',
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'id',
|
||||
description: 'get image from a message with this ID',
|
||||
typeList: [ARGUMENT_TYPE.NUMBER],
|
||||
enumProvider: commonEnumProviders.messages(),
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
|
@ -10,7 +10,8 @@ import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
|
||||
import { SlashCommand } from '../../slash-commands/SlashCommand.js';
|
||||
import { ARGUMENT_TYPE, SlashCommandArgument } from '../../slash-commands/SlashCommandArgument.js';
|
||||
import { isFunctionCallingSupported } from '../../openai.js';
|
||||
import { SlashCommandEnumValue } from '../../slash-commands/SlashCommandEnumValue.js';
|
||||
import { SlashCommandEnumValue, enumTypes } from '../../slash-commands/SlashCommandEnumValue.js';
|
||||
import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';
|
||||
export { MODULE_NAME };
|
||||
|
||||
const MODULE_NAME = 'expressions';
|
||||
@ -2044,6 +2045,14 @@ function migrateSettings() {
|
||||
});
|
||||
eventSource.on(event_types.MOVABLE_PANELS_RESET, updateVisualNovelModeDebounced);
|
||||
eventSource.on(event_types.GROUP_UPDATED, updateVisualNovelModeDebounced);
|
||||
|
||||
const localEnumProviders = {
|
||||
expressions: () => getCachedExpressions().map(expression => {
|
||||
const isCustom = extension_settings.expressions.custom?.includes(expression);
|
||||
return new SlashCommandEnumValue(expression, null, isCustom ? enumTypes.name : enumTypes.enum, isCustom ? 'C' : 'D');
|
||||
}),
|
||||
};
|
||||
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'sprite',
|
||||
aliases: ['emote'],
|
||||
@ -2053,7 +2062,7 @@ function migrateSettings() {
|
||||
description: 'spriteId',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: () => getCachedExpressions().map((x) => new SlashCommandEnumValue(x)),
|
||||
enumProvider: localEnumProviders.expressions,
|
||||
}),
|
||||
],
|
||||
helpString: 'Force sets the sprite for the current character.',
|
||||
@ -2075,9 +2084,12 @@ function migrateSettings() {
|
||||
callback: (_, value) => lastExpression[String(value).trim()] ?? '',
|
||||
returns: 'sprite',
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'charName', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'character name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: commonEnumProviders.characters('character'),
|
||||
}),
|
||||
],
|
||||
helpString: 'Returns the last set sprite / expression for the named character.',
|
||||
}));
|
||||
|
@ -12,6 +12,7 @@ import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
|
||||
import { SlashCommand } from '../../slash-commands/SlashCommand.js';
|
||||
import { ARGUMENT_TYPE, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';
|
||||
import { DragAndDropHandler } from '../../dragdrop.js';
|
||||
import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';
|
||||
|
||||
const extensionName = 'gallery';
|
||||
const extensionFolderPath = `scripts/extensions/${extensionName}/`;
|
||||
@ -401,7 +402,10 @@ function viewWithDragbox(items) {
|
||||
// Registers a simple command for opening the char gallery.
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'show-gallery',
|
||||
aliases: ['sg'],
|
||||
callback: showGalleryCommand,
|
||||
callback: () => {
|
||||
showCharGallery();
|
||||
return '';
|
||||
},
|
||||
helpString: 'Shows the gallery.',
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'list-gallery',
|
||||
@ -409,21 +413,22 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'list-gallery
|
||||
callback: listGalleryCommand,
|
||||
returns: 'list of images',
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument(
|
||||
'char', 'character name', [ARGUMENT_TYPE.STRING], false,
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'group', 'group name', [ARGUMENT_TYPE.STRING], false,
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'char',
|
||||
description: 'character name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
enumProvider: commonEnumProviders.characters('character'),
|
||||
}),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'group',
|
||||
description: 'group name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
enumProvider: commonEnumProviders.characters('group'),
|
||||
}),
|
||||
],
|
||||
helpString: 'List images in the gallery of the current char / group or a specified char / group.',
|
||||
}));
|
||||
|
||||
|
||||
function showGalleryCommand(args) {
|
||||
showCharGallery();
|
||||
}
|
||||
|
||||
async function listGalleryCommand(args) {
|
||||
try {
|
||||
let url = args.char ?? (args.group ? groups.find(it=>it.name == args.group)?.id : null) ?? (selected_group || this_chid);
|
||||
|
@ -24,6 +24,7 @@ import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
|
||||
import { SlashCommand } from '../../slash-commands/SlashCommand.js';
|
||||
import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';
|
||||
import { resolveVariable } from '../../variables.js';
|
||||
import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';
|
||||
export { MODULE_NAME };
|
||||
|
||||
const MODULE_NAME = '1_memory';
|
||||
@ -919,7 +920,14 @@ jQuery(async function () {
|
||||
callback: summarizeCallback,
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument('source', 'API to use for summarization', [ARGUMENT_TYPE.STRING], false, false, '', ['main', 'extras']),
|
||||
new SlashCommandNamedArgument('prompt', 'prompt to use for summarization', [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.VARIABLE_NAME], false, false, ''),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'prompt',
|
||||
description: 'prompt to use for summarization',
|
||||
typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.VARIABLE_NAME],
|
||||
defaultValue: '',
|
||||
enumProvider: commonEnumProviders.variables('all'),
|
||||
forceEnum: false,
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument('text to summarize', [ARGUMENT_TYPE.STRING], false, false, ''),
|
||||
|
@ -1,9 +1,13 @@
|
||||
import { SlashCommand } from '../../../slash-commands/SlashCommand.js';
|
||||
import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../../slash-commands/SlashCommandArgument.js';
|
||||
import { enumIcons } from '../../../slash-commands/SlashCommandCommonEnumsProvider.js';
|
||||
import { SlashCommandEnumValue, enumTypes } from '../../../slash-commands/SlashCommandEnumValue.js';
|
||||
import { SlashCommandParser } from '../../../slash-commands/SlashCommandParser.js';
|
||||
import { isTrueBoolean } from '../../../utils.js';
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
import { QuickReplyApi } from '../api/QuickReplyApi.js';
|
||||
import { QuickReply } from './QuickReply.js';
|
||||
import { QuickReplySet } from './QuickReplySet.js';
|
||||
|
||||
export class SlashCommandHandler {
|
||||
/**@type {QuickReplyApi}*/ api;
|
||||
@ -19,6 +23,50 @@ export class SlashCommandHandler {
|
||||
|
||||
|
||||
init() {
|
||||
function getExecutionIcons(/**@type {QuickReply} */ qr) {
|
||||
let icons = '';
|
||||
if (qr.preventAutoExecute) icons += '🚫';
|
||||
if (qr.isHidden) icons += '👁️';
|
||||
if (qr.executeOnStartup) icons += '🚀';
|
||||
if (qr.executeOnUser) icons += enumIcons.user;
|
||||
if (qr.executeOnAi) icons += enumIcons.assistant;
|
||||
if (qr.executeOnChatChange) icons += '💬';
|
||||
if (qr.executeOnGroupMemberDraft) icons += enumIcons.group;
|
||||
return icons;
|
||||
}
|
||||
|
||||
const localEnumProviders = {
|
||||
/** All quick reply sets, optionally filtering out sets that wer already used in the "set" named argument */
|
||||
qrSets: (executor) => QuickReplySet.list.filter(qrSet => qrSet.name != String(executor.namedArgumentList.find(x => x.name == 'set')?.value))
|
||||
.map(qrSet => new SlashCommandEnumValue(qrSet.name, null, enumTypes.enum, 'S')),
|
||||
|
||||
/** All QRs inside a set, utilizing the "set" named argument */
|
||||
qrEntries: (executor) => QuickReplySet.get(String(executor.namedArgumentList.find(x => x.name == 'set')?.value))?.qrList.map(qr => {
|
||||
const icons = getExecutionIcons(qr);
|
||||
const message = `${qr.automationId ? `[${qr.automationId}]` : ''}${icons ? `[auto: ${icons}]` : ''} ${qr.title || qr.message}`.trim();
|
||||
return new SlashCommandEnumValue(qr.label, message, enumTypes.enum, enumIcons.qr);
|
||||
}) ?? [],
|
||||
|
||||
/** All QRs as a set.name string, to be able to execute, for example via the /run command */
|
||||
qrExecutables: () => {
|
||||
const globalSetList = this.api.settings.config.setList;
|
||||
const chatSetList = this.api.settings.chatConfig?.setList;
|
||||
|
||||
const globalQrs = globalSetList.map(link => link.set.qrList.map(qr => ({ set: link.set, qr }))).flat();
|
||||
const chatQrs = chatSetList?.map(link => link.set.qrList.map(qr => ({ set: link.set, qr }))).flat() ?? [];
|
||||
const otherQrs = QuickReplySet.list.filter(set => !globalSetList.some(link => link.set.name === set.name && !chatSetList?.some(link => link.set.name === set.name)))
|
||||
.map(set => set.qrList.map(qr => ({ set, qr }))).flat();
|
||||
|
||||
return [
|
||||
...globalQrs.map(x => new SlashCommandEnumValue(`${x.set.name}.${x.qr.label}`, `[global] ${x.qr.title || x.qr.message}`, enumTypes.name, enumIcons.qr)),
|
||||
...chatQrs.map(x => new SlashCommandEnumValue(`${x.set.name}.${x.qr.label}`, `[chat] ${x.qr.title || x.qr.message}`, enumTypes.enum, enumIcons.qr)),
|
||||
...otherQrs.map(x => new SlashCommandEnumValue(`${x.set.name}.${x.qr.label}`, `${x.qr.title || x.qr.message}`, enumTypes.qr, enumIcons.qr)),
|
||||
];
|
||||
},
|
||||
}
|
||||
|
||||
window['qrEnumProviderExecutables'] = localEnumProviders.qrExecutables;
|
||||
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr',
|
||||
callback: (_, value) => this.executeQuickReplyByIndex(Number(value)),
|
||||
unnamedArgumentList: [
|
||||
@ -29,110 +77,166 @@ export class SlashCommandHandler {
|
||||
helpString: 'Activates the specified Quick Reply',
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qrset',
|
||||
callback: () => toastr.warning('The command /qrset has been deprecated. Use /qr-set, /qr-set-on, and /qr-set-off instead.'),
|
||||
callback: () => {
|
||||
toastr.warning('The command /qrset has been deprecated. Use /qr-set, /qr-set-on, and /qr-set-off instead.');
|
||||
return '';
|
||||
},
|
||||
helpString: '<strong>DEPRECATED</strong> – The command /qrset has been deprecated. Use /qr-set, /qr-set-on, and /qr-set-off instead.',
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-set',
|
||||
callback: (args, value) => this.toggleGlobalSet(value, args),
|
||||
callback: (args, value) => {
|
||||
this.toggleGlobalSet(value, args);
|
||||
return '';
|
||||
},
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument(
|
||||
'visible', 'set visibility', [ARGUMENT_TYPE.BOOLEAN], false, false, 'true',
|
||||
),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'QR set name', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'QR set name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: localEnumProviders.qrSets,
|
||||
}),
|
||||
],
|
||||
helpString: 'Toggle global QR set',
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-set-on',
|
||||
callback: (args, value) => this.addGlobalSet(value, args),
|
||||
callback: (args, value) => {
|
||||
this.addGlobalSet(value, args);
|
||||
return '';
|
||||
},
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument(
|
||||
'visible', 'set visibility', [ARGUMENT_TYPE.BOOLEAN], false, false, 'true',
|
||||
),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'QR set name', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'QR set name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: localEnumProviders.qrSets,
|
||||
}),
|
||||
],
|
||||
helpString: 'Activate global QR set',
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-set-off',
|
||||
callback: (_, value) => this.removeGlobalSet(value),
|
||||
callback: (_, value) => {
|
||||
this.removeGlobalSet(value);
|
||||
return '';
|
||||
},
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'QR set name', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'QR set name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: localEnumProviders.qrSets,
|
||||
}),
|
||||
],
|
||||
helpString: 'Deactivate global QR set',
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-chat-set',
|
||||
callback: (args, value) => this.toggleChatSet(value, args),
|
||||
callback: (args, value) => {
|
||||
this.toggleChatSet(value, args);
|
||||
return '';
|
||||
},
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument(
|
||||
'visible', 'set visibility', [ARGUMENT_TYPE.BOOLEAN], false, false, 'true',
|
||||
),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'QR set name', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'QR set name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: localEnumProviders.qrSets,
|
||||
}),
|
||||
],
|
||||
helpString: 'Toggle chat QR set',
|
||||
}));
|
||||
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-chat-set-on',
|
||||
callback: (args, value) => this.addChatSet(value, args),
|
||||
callback: (args, value) => {
|
||||
this.addChatSet(value, args);
|
||||
return '';
|
||||
},
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument(
|
||||
'visible', 'whether the QR set should be visible', [ARGUMENT_TYPE.BOOLEAN], false, false, 'true', ['true', 'false'],
|
||||
'visible', 'whether the QR set should be visible', [ARGUMENT_TYPE.BOOLEAN], false, false, 'true',
|
||||
),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'QR set name', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'QR set name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: localEnumProviders.qrSets,
|
||||
}),
|
||||
],
|
||||
helpString: 'Activate chat QR set',
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-chat-set-off',
|
||||
callback: (_, value) => this.removeChatSet(value),
|
||||
callback: (_, value) => {
|
||||
this.removeChatSet(value);
|
||||
return '';
|
||||
},
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'QR set name', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'QR set name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: localEnumProviders.qrSets,
|
||||
}),
|
||||
],
|
||||
helpString: 'Deactivate chat QR set',
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-set-list',
|
||||
callback: (_, value) => this.listSets(value ?? 'all'),
|
||||
callback: (_, value) => JSON.stringify(this.listSets(value ?? 'all')),
|
||||
returns: 'list of QR sets',
|
||||
namedArgumentList: [],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'set type', [ARGUMENT_TYPE.STRING], false, false, null, ['all', 'global', 'chat'],
|
||||
'set type', [ARGUMENT_TYPE.STRING], false, false, 'all', ['all', 'global', 'chat'],
|
||||
),
|
||||
],
|
||||
helpString: 'Gets a list of the names of all quick reply sets.',
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-list',
|
||||
callback: (_, value) => this.listQuickReplies(value),
|
||||
callback: (_, value) => {
|
||||
return JSON.stringify(this.listQuickReplies(value));
|
||||
},
|
||||
returns: 'list of QRs',
|
||||
namedArgumentList: [],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'set name', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'QR set name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: localEnumProviders.qrSets,
|
||||
}),
|
||||
],
|
||||
helpString: 'Gets a list of the names of all quick replies in this quick reply set.',
|
||||
}));
|
||||
|
||||
const qrArgs = [
|
||||
new SlashCommandNamedArgument('label', 'text on the button, e.g., label=MyButton', [ARGUMENT_TYPE.STRING]),
|
||||
new SlashCommandNamedArgument('set', 'name of the QR set, e.g., set=PresetName1', [ARGUMENT_TYPE.STRING]),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'set',
|
||||
description: 'name of the QR set, e.g., set=PresetName1',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: localEnumProviders.qrSets,
|
||||
}),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'label',
|
||||
description: 'text on the button, e.g., label=MyButton',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: localEnumProviders.qrLabels,
|
||||
}),
|
||||
new SlashCommandNamedArgument('hidden', 'whether the button should be hidden, e.g., hidden=true', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false'),
|
||||
new SlashCommandNamedArgument('startup', 'auto execute on app startup, e.g., startup=true', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false'),
|
||||
new SlashCommandNamedArgument('user', 'auto execute on user message, e.g., user=true', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false'),
|
||||
@ -144,8 +248,12 @@ export class SlashCommandHandler {
|
||||
const qrUpdateArgs = [
|
||||
new SlashCommandNamedArgument('newlabel', 'new text for the button', [ARGUMENT_TYPE.STRING], false),
|
||||
];
|
||||
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-create',
|
||||
callback: (args, message) => this.createQuickReply(args, message),
|
||||
callback: (args, message) => {
|
||||
this.createQuickReply(args, message);
|
||||
return '';
|
||||
},
|
||||
namedArgumentList: qrArgs,
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
@ -165,9 +273,15 @@ export class SlashCommandHandler {
|
||||
`,
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-update',
|
||||
callback: (args, message) => this.updateQuickReply(args, message),
|
||||
callback: (args, message) => {
|
||||
this.updateQuickReply(args, message);
|
||||
return '';
|
||||
},
|
||||
returns: 'updated quick reply',
|
||||
namedArgumentList: [...qrUpdateArgs, ...qrArgs],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument('command', [ARGUMENT_TYPE.STRING]),
|
||||
],
|
||||
helpString: `
|
||||
<div>
|
||||
Updates Quick Reply.
|
||||
@ -183,34 +297,57 @@ export class SlashCommandHandler {
|
||||
`,
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-delete',
|
||||
callback: (args, name) => this.deleteQuickReply(args, name),
|
||||
callback: (args, name) => {
|
||||
this.deleteQuickReply(args, name);
|
||||
return '';
|
||||
},
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument(
|
||||
'set', 'Quick Reply set', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'label', 'Quick Reply label', [ARGUMENT_TYPE.STRING], false,
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'set',
|
||||
description: 'QR set name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: localEnumProviders.qrSets,
|
||||
}),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'label',
|
||||
description: 'Quick Reply label',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
enumProvider: localEnumProviders.qrEntries,
|
||||
}),
|
||||
],
|
||||
helpString: 'Deletes a Quick Reply from the specified set. If no label is provided, the entire set is deleted.',
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-contextadd',
|
||||
callback: (args, name) => this.createContextItem(args, name),
|
||||
callback: (args, name) => {
|
||||
this.createContextItem(args, name);
|
||||
return '';
|
||||
},
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument(
|
||||
'set', 'string', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'label', 'string', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'set',
|
||||
description: 'QR set name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: localEnumProviders.qrSets,
|
||||
}),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'label',
|
||||
description: 'Quick Reply label',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
enumProvider: localEnumProviders.qrEntries,
|
||||
}),
|
||||
new SlashCommandNamedArgument(
|
||||
'chain', 'boolean', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false',
|
||||
),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'preset name', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'QR set name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: localEnumProviders.qrSets,
|
||||
}),
|
||||
],
|
||||
helpString: `
|
||||
<div>
|
||||
@ -227,19 +364,32 @@ export class SlashCommandHandler {
|
||||
`,
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-contextdel',
|
||||
callback: (args, name) => this.deleteContextItem(args, name),
|
||||
callback: (args, name) => {
|
||||
this.deleteContextItem(args, name);
|
||||
return '';
|
||||
},
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument(
|
||||
'set', 'string', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'label', 'string', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'set',
|
||||
description: 'QR set name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: localEnumProviders.qrSets,
|
||||
}),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'label',
|
||||
description: 'Quick Reply label',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
enumProvider: localEnumProviders.qrEntries,
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'preset name', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'QR set name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: localEnumProviders.qrSets,
|
||||
}),
|
||||
],
|
||||
helpString: `
|
||||
<div>
|
||||
@ -256,16 +406,25 @@ export class SlashCommandHandler {
|
||||
`,
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-contextclear',
|
||||
callback: (args, label) => this.clearContextMenu(args, label),
|
||||
callback: (args, label) => {
|
||||
this.clearContextMenu(args, label);
|
||||
return '';
|
||||
},
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument(
|
||||
'set', 'context menu preset name', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'set',
|
||||
description: 'QR set name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: localEnumProviders.qrSets,
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'label', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'Quick Reply label',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
enumProvider: localEnumProviders.qrEntries,
|
||||
}),
|
||||
],
|
||||
helpString: `
|
||||
<div>
|
||||
@ -288,13 +447,20 @@ export class SlashCommandHandler {
|
||||
new SlashCommandNamedArgument('inject', 'inject user input automatically (if disabled use {{input}})', [ARGUMENT_TYPE.BOOLEAN], false),
|
||||
];
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-set-create',
|
||||
callback: (args, name) => this.createSet(name, args),
|
||||
callback: (args, name) => {
|
||||
this.createSet(name, args);
|
||||
return '';
|
||||
},
|
||||
aliases: ['qr-presetadd'],
|
||||
namedArgumentList: presetArgs,
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'name', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'QR set name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: localEnumProviders.qrSets,
|
||||
forceEnum: false,
|
||||
}),
|
||||
],
|
||||
helpString: `
|
||||
<div>
|
||||
@ -312,11 +478,19 @@ export class SlashCommandHandler {
|
||||
}));
|
||||
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-set-update',
|
||||
callback: (args, name) => this.updateSet(name, args),
|
||||
callback: (args, name) => {
|
||||
this.updateSet(name, args);
|
||||
return '';
|
||||
},
|
||||
aliases: ['qr-presetupdate'],
|
||||
namedArgumentList: presetArgs,
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument('name', [ARGUMENT_TYPE.STRING], true),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'QR set name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: localEnumProviders.qrSets,
|
||||
}),
|
||||
],
|
||||
helpString: `
|
||||
<div>
|
||||
@ -329,10 +503,18 @@ export class SlashCommandHandler {
|
||||
`,
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'qr-set-delete',
|
||||
callback: (args, name) => this.deleteSet(name),
|
||||
callback: (_, name) => {
|
||||
this.deleteSet(name);
|
||||
return '';
|
||||
},
|
||||
aliases: ['qr-presetdelete'],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument('name', [ARGUMENT_TYPE.STRING], true),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'QR set name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: localEnumProviders.qrSets,
|
||||
}),
|
||||
],
|
||||
helpString: `
|
||||
<div>
|
||||
@ -468,7 +650,7 @@ export class SlashCommandHandler {
|
||||
}
|
||||
deleteQuickReply(args, label) {
|
||||
try {
|
||||
this.api.deleteQuickReply(args.set, label);
|
||||
this.api.deleteQuickReply(args.set, args.label ?? label);
|
||||
} catch (ex) {
|
||||
toastr.error(ex.message);
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ function getRegexedString(rawString, placement, { characterOverride, isMarkdown,
|
||||
|
||||
/**
|
||||
* Runs the provided regex script on the given string
|
||||
* @param {object} regexScript The regex script to run
|
||||
* @param {import('./index.js').RegexScript} regexScript The regex script to run
|
||||
* @param {string} rawString The string to run the regex script on
|
||||
* @param {RegexScriptParams} params The parameters to use for the regex script
|
||||
* @returns {string} The new string
|
||||
|
@ -3,11 +3,32 @@ import { extension_settings, renderExtensionTemplateAsync, writeExtensionField }
|
||||
import { selected_group } from '../../group-chats.js';
|
||||
import { SlashCommand } from '../../slash-commands/SlashCommand.js';
|
||||
import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';
|
||||
import { enumIcons } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';
|
||||
import { SlashCommandEnumValue, enumTypes } from '../../slash-commands/SlashCommandEnumValue.js';
|
||||
import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
|
||||
import { download, getFileText, getSortableDelay, uuidv4 } from '../../utils.js';
|
||||
import { resolveVariable } from '../../variables.js';
|
||||
import { regex_placement, runRegexScript } from './engine.js';
|
||||
|
||||
/**
|
||||
* @typedef {object} RegexScript
|
||||
* @property {string} scriptName - The name of the script
|
||||
* @property {boolean} disabled - Whether the script is disabled
|
||||
* @property {string} replaceString - The replace string
|
||||
* @property {string[]} trimStrings - The trim strings
|
||||
* @property {string?} findRegex - The find regex
|
||||
* @property {string?} substituteRegex - The substitute regex
|
||||
*/
|
||||
|
||||
/**
|
||||
* Retrieves the list of regex scripts by combining the scripts from the extension settings and the character data
|
||||
*
|
||||
* @return {RegexScript[]} An array of regex scripts, where each script is an object containing the necessary information.
|
||||
*/
|
||||
export function getRegexScripts() {
|
||||
return [...(extension_settings.regex ?? []), ...(characters[this_chid]?.data?.extensions?.regex_scripts ?? [])];
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a regex script to the extension settings or character data.
|
||||
* @param {import('../../char-data.js').RegexScriptData} regexScript
|
||||
@ -339,7 +360,7 @@ function runRegexCallback(args, value) {
|
||||
}
|
||||
|
||||
const scriptName = String(resolveVariable(args.name));
|
||||
const scripts = [...(extension_settings.regex ?? []), ...(characters[this_chid]?.data?.extensions?.regex_scripts ?? [])];
|
||||
const scripts = getRegexScripts();
|
||||
|
||||
for (const script of scripts) {
|
||||
if (String(script.scriptName).toLowerCase() === String(scriptName).toLowerCase()) {
|
||||
@ -551,14 +572,26 @@ jQuery(async () => {
|
||||
await loadRegexScripts();
|
||||
$('#saved_regex_scripts').sortable('enable');
|
||||
|
||||
const localEnumProviders = {
|
||||
regexScripts: () => getRegexScripts().map(script => {
|
||||
const isGlobal = extension_settings.regex?.some(x => x.scriptName === script.scriptName);
|
||||
return new SlashCommandEnumValue(script.scriptName, `${enumIcons.getStateIcon(!script.disabled)} [${isGlobal ? 'global' : 'scoped'}] ${script.findRegex}`,
|
||||
isGlobal ? enumTypes.enum : enumTypes.name, isGlobal ? 'G' : 'S');
|
||||
}),
|
||||
};
|
||||
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'regex',
|
||||
callback: runRegexCallback,
|
||||
returns: 'replaced text',
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument(
|
||||
'name', 'script name', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'name',
|
||||
description: 'script name',
|
||||
typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.VARIABLE_NAME],
|
||||
isRequired: true,
|
||||
enumProvider: localEnumProviders.regexScripts,
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
|
@ -31,6 +31,8 @@ import { SlashCommand } from '../../slash-commands/SlashCommand.js';
|
||||
import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';
|
||||
import { resolveVariable } from '../../variables.js';
|
||||
import { debounce_timeout } from '../../constants.js';
|
||||
import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';
|
||||
import { SlashCommandEnumValue } from '../../slash-commands/SlashCommandEnumValue.js';
|
||||
export { MODULE_NAME };
|
||||
|
||||
const MODULE_NAME = 'sd';
|
||||
@ -3349,11 +3351,14 @@ jQuery(async () => {
|
||||
aliases: ['sd', 'img', 'image'],
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument(
|
||||
'quiet', 'whether to post the generated image to chat', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false', ['false', 'true'],
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'negative', 'negative prompt prefix', [ARGUMENT_TYPE.STRING], false, false, '',
|
||||
'quiet', 'whether to post the generated image to chat', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false',
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'negative',
|
||||
description: 'negative prompt prefix',
|
||||
typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.VARIABLE_NAME],
|
||||
enumProvider: commonEnumProviders.variables('all'),
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
@ -3362,7 +3367,7 @@ jQuery(async () => {
|
||||
],
|
||||
helpString: `
|
||||
<div>
|
||||
Requests to generate an image and posts it to chat (unless quiet=true argument is specified). Supported arguments: <code>${Object.values(triggerWords).flat().join(', ')}</code>.
|
||||
Requests to generate an image and posts it to chat (unless <code>quiet=true</code> argument is specified).</code>.
|
||||
</div>
|
||||
<div>
|
||||
Anything else would trigger a "free mode" to make generate whatever you prompted. Example: <code>/imagine apple tree</code> would generate a picture of an apple tree. Returns a link to the generated image.
|
||||
@ -3375,9 +3380,12 @@ jQuery(async () => {
|
||||
callback: changeComfyWorkflow,
|
||||
aliases: ['icw'],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'workflowName', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'workflow name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: () => Array.from(document.querySelectorAll('#sd_comfy_workflow > [value]')).map(x => x.getAttribute('value')).map(workflow => new SlashCommandEnumValue(workflow)),
|
||||
}),
|
||||
],
|
||||
helpString: '(workflowName) - change the workflow to be used for image generation with ComfyUI, e.g. <pre><code>/imagine-comfy-workflow MyWorkflow</code></pre>',
|
||||
}));
|
||||
|
@ -123,6 +123,7 @@ async function doCount() {
|
||||
//toastr success with the token count of the chat
|
||||
const count = await getTokenCountAsync(allMessages);
|
||||
toastr.success(`Token count: ${count}`);
|
||||
return count;
|
||||
}
|
||||
|
||||
jQuery(() => {
|
||||
@ -134,7 +135,7 @@ jQuery(() => {
|
||||
$('#extensionsMenu').prepend(buttonHtml);
|
||||
$('#token_counter').on('click', doTokenCounter);
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'count',
|
||||
callback: doCount,
|
||||
callback: async () => String(await doCount()),
|
||||
returns: 'number of tokens',
|
||||
helpString: 'Counts the number of tokens in the current chat.',
|
||||
}));
|
||||
|
@ -19,6 +19,8 @@ import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
|
||||
import { SlashCommand } from '../../slash-commands/SlashCommand.js';
|
||||
import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';
|
||||
import { debounce_timeout } from '../../constants.js';
|
||||
import { SlashCommandEnumValue, enumTypes } from '../../slash-commands/SlashCommandEnumValue.js';
|
||||
import { enumIcons } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';
|
||||
export { talkingAnimation };
|
||||
|
||||
const UPDATE_INTERVAL = 1000;
|
||||
@ -1204,12 +1206,19 @@ $(document).ready(function () {
|
||||
eventSource.makeLast(event_types.USER_MESSAGE_RENDERED, onMessageEvent);
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'speak',
|
||||
callback: onNarrateText,
|
||||
callback: async (args, value) => {
|
||||
await onNarrateText(args, value);
|
||||
return '';
|
||||
},
|
||||
aliases: ['narrate', 'tts'],
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument(
|
||||
'voice', 'character voice name', [ARGUMENT_TYPE.STRING], false,
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'voice',
|
||||
description: 'character voice name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: false,
|
||||
enumProvider: () => Object.keys(voiceMap).map(voiceName => new SlashCommandEnumValue(voiceName, null, enumTypes.enum, enumIcons.voice)),
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
|
@ -233,9 +233,20 @@ export async function getGroupChat(groupId, reload = false) {
|
||||
if (freshChat) await eventSource.emit(event_types.GROUP_CHAT_CREATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the members of a group
|
||||
*
|
||||
* @param {string} [groupId=selected_group] - The ID of the group to retrieve members from. Defaults to the currently selected group.
|
||||
* @returns {import('../script.js').Character[]} An array of character objects representing the members of the group. If the group is not found, an empty array is returned.
|
||||
*/
|
||||
export function getGroupMembers(groupId = selected_group) {
|
||||
const group = groups.find((x) => x.id === groupId);
|
||||
return group?.members.map(member => characters.find(x => x.avatar === member)) ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the character ID for a group member.
|
||||
* @param {string} arg 1-based member index or character name
|
||||
* @param {string} arg 0-based member index or character name
|
||||
* @returns {number} 0-based character ID
|
||||
*/
|
||||
export function findGroupMemberId(arg) {
|
||||
@ -253,8 +264,7 @@ export function findGroupMemberId(arg) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Index is 1-based
|
||||
const index = parseInt(arg) - 1;
|
||||
const index = parseInt(arg);
|
||||
const searchByName = isNaN(index);
|
||||
|
||||
if (searchByName) {
|
||||
|
@ -71,6 +71,7 @@ import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
|
||||
import { SlashCommand } from './slash-commands/SlashCommand.js';
|
||||
import { ARGUMENT_TYPE, SlashCommandArgument } from './slash-commands/SlashCommandArgument.js';
|
||||
import { renderTemplateAsync } from './templates.js';
|
||||
import { SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js';
|
||||
|
||||
export {
|
||||
openai_messages_count,
|
||||
@ -199,16 +200,18 @@ const custom_prompt_post_processing_types = {
|
||||
CLAUDE: 'claude',
|
||||
};
|
||||
|
||||
const prefixMap = selected_group ? {
|
||||
assistant: '',
|
||||
user: '',
|
||||
system: 'OOC: ',
|
||||
function getPrefixMap() {
|
||||
return selected_group ? {
|
||||
assistant: '',
|
||||
user: '',
|
||||
system: 'OOC: ',
|
||||
}
|
||||
: {
|
||||
assistant: '{{char}}:',
|
||||
user: '{{user}}:',
|
||||
system: '',
|
||||
};
|
||||
}
|
||||
: {
|
||||
assistant: '{{char}}:',
|
||||
user: '{{user}}:',
|
||||
system: '',
|
||||
};
|
||||
|
||||
const default_settings = {
|
||||
preset_settings_openai: 'Default',
|
||||
@ -1709,7 +1712,7 @@ async function sendOpenAIRequest(type, messages, signal) {
|
||||
|
||||
if (isAI21) {
|
||||
const joinedMsgs = messages.reduce((acc, obj) => {
|
||||
const prefix = prefixMap[obj.role];
|
||||
const prefix = getPrefixMap()[obj.role];
|
||||
return acc + (prefix ? (selected_group ? '\n' : prefix + ' ') : '') + obj.content + '\n';
|
||||
}, '');
|
||||
messages = substituteParams(joinedMsgs) + (isImpersonate ? `${name1}:` : `${name2}:`);
|
||||
@ -4602,9 +4605,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
returns: 'current proxy',
|
||||
namedArgumentList: [],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'name', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: () => proxies.map(preset => new SlashCommandEnumValue(preset.name, preset.url)),
|
||||
}),
|
||||
],
|
||||
helpString: 'Sets a proxy preset by name.',
|
||||
}));
|
||||
|
@ -3,33 +3,39 @@ import { removeFromArray, runAfterAnimation, uuidv4 } from './utils.js';
|
||||
/** @readonly */
|
||||
/** @enum {Number} */
|
||||
export const POPUP_TYPE = {
|
||||
'TEXT': 1,
|
||||
'CONFIRM': 2,
|
||||
'INPUT': 3,
|
||||
/** Main popup type. Containing any content displayed, with buttons below. Can also contain additional input controls. */
|
||||
TEXT: 1,
|
||||
/** Popup mainly made to confirm something, answering with a simple Yes/No or similar. Focus on the button controls. */
|
||||
CONFIRM: 2,
|
||||
/** Popup who's main focus is the input text field, which is displayed here. Can contain additional content above. Return value for this is the input string. */
|
||||
INPUT: 3,
|
||||
/** Popup without any button controls. Used to simply display content, with a small X in the corner. */
|
||||
DISPLAY: 4,
|
||||
};
|
||||
|
||||
/** @readonly */
|
||||
/** @enum {number?} */
|
||||
export const POPUP_RESULT = {
|
||||
'AFFIRMATIVE': 1,
|
||||
'NEGATIVE': 0,
|
||||
'CANCELLED': null,
|
||||
AFFIRMATIVE: 1,
|
||||
NEGATIVE: 0,
|
||||
CANCELLED: null,
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {object} PopupOptions
|
||||
* @property {string|boolean?} [okButton] - Custom text for the OK button, or `true` to use the default (If set, the button will always be displayed, no matter the type of popup)
|
||||
* @property {string|boolean?} [cancelButton] - Custom text for the Cancel button, or `true` to use the default (If set, the button will always be displayed, no matter the type of popup)
|
||||
* @property {number?} [rows] - The number of rows for the input field
|
||||
* @property {boolean?} [wide] - Whether to display the popup in wide mode (wide screen, 1/1 aspect ratio)
|
||||
* @property {boolean?} [wider] - Whether to display the popup in wider mode (just wider, no height scaling)
|
||||
* @property {boolean?} [large] - Whether to display the popup in large mode (90% of screen)
|
||||
* @property {boolean?} [allowHorizontalScrolling] - Whether to allow horizontal scrolling in the popup
|
||||
* @property {boolean?} [allowVerticalScrolling] - Whether to allow vertical scrolling in the popup
|
||||
* @property {POPUP_RESULT|number?} [defaultResult] - The default result of this popup when Enter is pressed. Can be changed from `POPUP_RESULT.AFFIRMATIVE`.
|
||||
* @property {CustomPopupButton[]|string[]?} [customButtons] - 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 {(popup: Popup) => boolean?} [onClosing] - Handler called before the popup closes, return `false` to cancel the close
|
||||
* @property {(popup: Popup) => void?} [onClose] - Handler called after the popup closes, but before the DOM is cleaned up
|
||||
* @property {string|boolean?} [okButton=null] - Custom text for the OK button, or `true` to use the default (If set, the button will always be displayed, no matter the type of popup)
|
||||
* @property {string|boolean?} [cancelButton=null] - Custom text for the Cancel button, or `true` to use the default (If set, the button will always be displayed, no matter the type of popup)
|
||||
* @property {number?} [rows=1] - The number of rows for the input field
|
||||
* @property {boolean?} [wide=false] - Whether to display the popup in wide mode (wide screen, 1/1 aspect ratio)
|
||||
* @property {boolean?} [wider=false] - Whether to display the popup in wider mode (just wider, no height scaling)
|
||||
* @property {boolean?} [large=false] - Whether to display the popup in large mode (90% of screen)
|
||||
* @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 {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 {(popup: Popup) => boolean?} [onClosing=null] - Handler called before the popup closes, return `false` to cancel the close
|
||||
* @property {(popup: Popup) => void?} [onClose=null] - Handler called after the popup closes, but before the DOM is cleaned up
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -75,8 +81,9 @@ export class Popup {
|
||||
/** @type {HTMLElement} */ content;
|
||||
/** @type {HTMLTextAreaElement} */ input;
|
||||
/** @type {HTMLElement} */ controls;
|
||||
/** @type {HTMLElement} */ ok;
|
||||
/** @type {HTMLElement} */ cancel;
|
||||
/** @type {HTMLElement} */ okButton;
|
||||
/** @type {HTMLElement} */ cancelButton;
|
||||
/** @type {HTMLElement} */ closeButton;
|
||||
/** @type {POPUP_RESULT|number?} */ defaultResult;
|
||||
/** @type {CustomPopupButton[]|string[]?} */ customButtons;
|
||||
|
||||
@ -99,7 +106,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, allowHorizontalScrolling = false, allowVerticalScrolling = false, defaultResult = POPUP_RESULT.AFFIRMATIVE, customButtons = null, onClosing = null, onClose = null } = {}) {
|
||||
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, onClosing = null, onClose = null } = {}) {
|
||||
Popup.util.popups.push(this);
|
||||
|
||||
// Make this popup uniquely identifiable
|
||||
@ -118,19 +125,21 @@ export class Popup {
|
||||
this.content = this.dlg.querySelector('.popup-content');
|
||||
this.input = this.dlg.querySelector('.popup-input');
|
||||
this.controls = this.dlg.querySelector('.popup-controls');
|
||||
this.ok = this.dlg.querySelector('.popup-button-ok');
|
||||
this.cancel = this.dlg.querySelector('.popup-button-cancel');
|
||||
this.okButton = this.dlg.querySelector('.popup-button-ok');
|
||||
this.cancelButton = this.dlg.querySelector('.popup-button-cancel');
|
||||
this.closeButton = this.dlg.querySelector('.popup-button-close');
|
||||
|
||||
this.dlg.setAttribute('data-id', this.id);
|
||||
if (wide) this.dlg.classList.add('wide_dialogue_popup');
|
||||
if (wider) this.dlg.classList.add('wider_dialogue_popup');
|
||||
if (large) this.dlg.classList.add('large_dialogue_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 custom button captions are provided, we set them beforehand
|
||||
this.ok.textContent = typeof okButton === 'string' ? okButton : 'OK';
|
||||
this.cancel.textContent = typeof cancelButton === 'string' ? cancelButton : template.getAttribute('popup-button-cancel');
|
||||
this.okButton.textContent = typeof okButton === 'string' ? okButton : 'OK';
|
||||
this.cancelButton.textContent = typeof cancelButton === 'string' ? cancelButton : template.getAttribute('popup-button-cancel');
|
||||
|
||||
this.defaultResult = defaultResult;
|
||||
this.customButtons = customButtons;
|
||||
@ -141,17 +150,14 @@ export class Popup {
|
||||
const buttonElement = document.createElement('div');
|
||||
buttonElement.classList.add('menu_button', 'popup-button-custom', 'result-control');
|
||||
buttonElement.classList.add(...(button.classes ?? []));
|
||||
buttonElement.setAttribute('data-result', String(button.result ?? undefined));
|
||||
buttonElement.dataset.result = String(button.result ?? undefined);
|
||||
buttonElement.textContent = button.text;
|
||||
buttonElement.tabIndex = 0;
|
||||
|
||||
if (button.action) buttonElement.addEventListener('click', button.action);
|
||||
if (button.result) buttonElement.addEventListener('click', () => this.complete(button.result));
|
||||
|
||||
if (button.appendAtEnd) {
|
||||
this.controls.appendChild(buttonElement);
|
||||
} else {
|
||||
this.controls.insertBefore(buttonElement, this.ok);
|
||||
this.controls.insertBefore(buttonElement, this.okButton);
|
||||
}
|
||||
});
|
||||
|
||||
@ -159,23 +165,30 @@ export class Popup {
|
||||
const defaultButton = this.controls.querySelector(`[data-result="${this.defaultResult}"]`);
|
||||
if (defaultButton) defaultButton.classList.add('menu_button_default');
|
||||
|
||||
// Styling differences depending on the popup type
|
||||
// General styling for all types first, that might be overriden for specific types below
|
||||
this.input.style.display = 'none';
|
||||
this.closeButton.style.display = 'none';
|
||||
|
||||
switch (type) {
|
||||
case POPUP_TYPE.TEXT: {
|
||||
this.input.style.display = 'none';
|
||||
if (!cancelButton) this.cancel.style.display = 'none';
|
||||
if (!cancelButton) this.cancelButton.style.display = 'none';
|
||||
break;
|
||||
}
|
||||
case POPUP_TYPE.CONFIRM: {
|
||||
this.input.style.display = 'none';
|
||||
if (!okButton) this.ok.textContent = template.getAttribute('popup-button-yes');
|
||||
if (!cancelButton) this.cancel.textContent = template.getAttribute('popup-button-no');
|
||||
if (!okButton) this.okButton.textContent = template.getAttribute('popup-button-yes');
|
||||
if (!cancelButton) this.cancelButton.textContent = template.getAttribute('popup-button-no');
|
||||
break;
|
||||
}
|
||||
case POPUP_TYPE.INPUT: {
|
||||
this.input.style.display = 'block';
|
||||
if (!okButton) this.ok.textContent = template.getAttribute('popup-button-save');
|
||||
if (!okButton) this.okButton.textContent = template.getAttribute('popup-button-save');
|
||||
break;
|
||||
}
|
||||
case POPUP_TYPE.DISPLAY: {
|
||||
this.controls.style.display = 'none';
|
||||
this.closeButton.style.display = 'block';
|
||||
}
|
||||
default: {
|
||||
console.warn('Unknown popup type.', type);
|
||||
break;
|
||||
@ -202,8 +215,14 @@ export class Popup {
|
||||
// Set focus event that remembers the focused element
|
||||
this.dlg.addEventListener('focusin', (evt) => { if (evt.target instanceof HTMLElement && evt.target != this.dlg) this.lastFocus = evt.target; });
|
||||
|
||||
this.ok.addEventListener('click', () => this.complete(POPUP_RESULT.AFFIRMATIVE));
|
||||
this.cancel.addEventListener('click', () => this.complete(POPUP_RESULT.NEGATIVE));
|
||||
// Bind event listeners for all result controls to their defined event type
|
||||
this.dlg.querySelectorAll(`[data-result]`).forEach(resultControl => {
|
||||
if (!(resultControl instanceof HTMLElement)) return;
|
||||
const result = Number(resultControl.dataset.result);
|
||||
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));
|
||||
});
|
||||
|
||||
// Bind dialog listeners manually, so we can be sure context is preserved
|
||||
const cancelListener = (evt) => {
|
||||
@ -296,6 +315,9 @@ export class Popup {
|
||||
|
||||
if (applyAutoFocus) {
|
||||
control.setAttribute('autofocus', '');
|
||||
// Manually enable tabindex too, as this might only be applied by the interactable functionality in the background, but too late for HTML autofocus
|
||||
// interactable only gets applied when inserted into the DOM
|
||||
control.tabIndex = 0;
|
||||
} else {
|
||||
control.focus();
|
||||
}
|
||||
|
@ -46,7 +46,8 @@ import { PARSER_FLAG, SlashCommandParser } from './slash-commands/SlashCommandPa
|
||||
import { SlashCommand } from './slash-commands/SlashCommand.js';
|
||||
import { ARGUMENT_TYPE, SlashCommandArgument } from './slash-commands/SlashCommandArgument.js';
|
||||
import { AUTOCOMPLETE_WIDTH } from './autocomplete/AutoComplete.js';
|
||||
import { SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js';
|
||||
import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js';
|
||||
import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js';
|
||||
|
||||
export {
|
||||
loadPowerUserSettings,
|
||||
@ -2917,7 +2918,7 @@ function setAvgBG() {
|
||||
return `rgba(${rNew.toFixed(0)}, ${gNew.toFixed(0)}, ${bNew.toFixed(0)}, 1)`;
|
||||
}
|
||||
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
async function setThemeCallback(_, text) {
|
||||
@ -3922,9 +3923,11 @@ $(document).ready(() => {
|
||||
name: 'random',
|
||||
callback: doRandomChat,
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'optional tag name', [ARGUMENT_TYPE.STRING], false,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'optional tag name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
enumProvider: () => tags.filter(tag => Object.values(tag_map).some(x => x.includes(tag.id))).map(tag => new SlashCommandEnumValue(tag.name, null, enumTypes.enum, enumIcons.tag)),
|
||||
}),
|
||||
],
|
||||
helpString: 'Start a new chat with a random character. If an argument is provided, only considers characters that have the specified tag.',
|
||||
}));
|
||||
@ -3944,9 +3947,13 @@ $(document).ready(() => {
|
||||
callback: doMesCut,
|
||||
returns: 'the text of cut messages separated by a newline',
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'number or range', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE], true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'number or range',
|
||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE],
|
||||
isRequired: true,
|
||||
acceptsMultiple: true,
|
||||
enumProvider: commonEnumProviders.messages(),
|
||||
}),
|
||||
],
|
||||
helpString: `
|
||||
<div>
|
||||
|
@ -22,6 +22,8 @@ import { kai_settings } from './kai-settings.js';
|
||||
import { context_presets, getContextSettings, power_user } from './power-user.js';
|
||||
import { SlashCommand } from './slash-commands/SlashCommand.js';
|
||||
import { ARGUMENT_TYPE, SlashCommandArgument } from './slash-commands/SlashCommandArgument.js';
|
||||
import { enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js';
|
||||
import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js';
|
||||
import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
|
||||
import {
|
||||
textgenerationwebui_preset_names,
|
||||
@ -482,11 +484,12 @@ export async function initPresetManager() {
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'preset',
|
||||
callback: presetCommandCallback,
|
||||
returns: 'current preset',
|
||||
namedArgumentList: [],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'name', [ARGUMENT_TYPE.STRING], false,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
enumProvider: () => getPresetManager().getAllPresets().map(preset => new SlashCommandEnumValue(preset, null, enumTypes.enum, enumIcons.preset)),
|
||||
}),
|
||||
],
|
||||
helpString: `
|
||||
<div>
|
||||
|
@ -433,6 +433,24 @@ class FandomScraper {
|
||||
}
|
||||
}
|
||||
|
||||
const iso6391Codes = [
|
||||
'aa', 'ab', 'ae', 'af', 'ak', 'am', 'an', 'ar', 'as', 'av', 'ay', 'az',
|
||||
'ba', 'be', 'bg', 'bh', 'bi', 'bm', 'bn', 'bo', 'br', 'bs', 'ca', 'ce',
|
||||
'ch', 'co', 'cr', 'cs', 'cu', 'cv', 'cy', 'da', 'de', 'dv', 'dz', 'ee',
|
||||
'el', 'en', 'eo', 'es', 'et', 'eu', 'fa', 'ff', 'fi', 'fj', 'fo', 'fr',
|
||||
'fy', 'ga', 'gd', 'gl', 'gn', 'gu', 'gv', 'ha', 'he', 'hi', 'ho', 'hr',
|
||||
'ht', 'hu', 'hy', 'hz', 'ia', 'id', 'ie', 'ig', 'ii', 'ik', 'io', 'is',
|
||||
'it', 'iu', 'ja', 'jv', 'ka', 'kg', 'ki', 'kj', 'kk', 'kl', 'km', 'kn',
|
||||
'ko', 'kr', 'ks', 'ku', 'kv', 'kw', 'ky', 'la', 'lb', 'lg', 'li', 'ln',
|
||||
'lo', 'lt', 'lu', 'lv', 'mg', 'mh', 'mi', 'mk', 'ml', 'mn', 'mr', 'ms',
|
||||
'mt', 'my', 'na', 'nb', 'nd', 'ne', 'ng', 'nl', 'nn', 'no', 'nr', 'nv',
|
||||
'ny', 'oc', 'oj', 'om', 'or', 'os', 'pa', 'pi', 'pl', 'ps', 'pt', 'qu',
|
||||
'rm', 'rn', 'ro', 'ru', 'rw', 'sa', 'sc', 'sd', 'se', 'sg', 'si', 'sk',
|
||||
'sl', 'sm', 'sn', 'so', 'sq', 'sr', 'ss', 'st', 'su', 'sv', 'sw', 'ta',
|
||||
'te', 'tg', 'th', 'ti', 'tk', 'tl', 'tn', 'to', 'tr', 'ts', 'tt', 'tw',
|
||||
'ty', 'ug', 'uk', 'ur', 'uz', 've', 'vi', 'vo', 'wa', 'wo', 'xh', 'yi',
|
||||
'yo', 'za', 'zh', 'zu'];
|
||||
|
||||
/**
|
||||
* Scrape transcript from a YouTube video.
|
||||
* @implements {Scraper}
|
||||
@ -464,7 +482,7 @@ class YouTubeScraper {
|
||||
helpString: 'Scrape a transcript from a YouTube video by ID or URL.',
|
||||
returns: ARGUMENT_TYPE.STRING,
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument('lang', 'ISO 639-1 language code of the transcript, e.g. "en"', ARGUMENT_TYPE.STRING, false, false, ''),
|
||||
new SlashCommandNamedArgument('lang', 'ISO 639-1 language code of the transcript, e.g. "en"', ARGUMENT_TYPE.STRING, false, false, '', iso6391Codes),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument('URL or ID of the YouTube video', ARGUMENT_TYPE.STRING, true, false),
|
||||
@ -514,7 +532,7 @@ class YouTubeScraper {
|
||||
}
|
||||
|
||||
const toast = toastr.info('Working, please wait...');
|
||||
const { transcript, id } = await this.getScript(videoUrl, lang);
|
||||
const { transcript, id } = await this.getScript(String(videoUrl), lang);
|
||||
toastr.clear(toast);
|
||||
|
||||
const file = new File([transcript], `YouTube - ${id} - ${Date.now()}.txt`, { type: 'text/plain' });
|
||||
|
@ -42,9 +42,9 @@ import { PARSER_FLAG, SlashCommandParser } from './slash-commands/SlashCommandPa
|
||||
import { SlashCommandParserError } from './slash-commands/SlashCommandParserError.js';
|
||||
import { getMessageTimeStamp } from './RossAscends-mods.js';
|
||||
import { hideChatMessageRange } from './chats.js';
|
||||
import { getContext, saveMetadataDebounced } from './extensions.js';
|
||||
import { extension_settings, getContext, saveMetadataDebounced } from './extensions.js';
|
||||
import { getRegexedString, regex_placement } from './extensions/regex/engine.js';
|
||||
import { findGroupMemberId, groups, is_group_generating, openGroupById, resetSelectedGroup, saveGroupChat, selected_group } from './group-chats.js';
|
||||
import { findGroupMemberId, getGroupMembers, groups, is_group_generating, openGroupById, resetSelectedGroup, saveGroupChat, selected_group } from './group-chats.js';
|
||||
import { chat_completion_sources, oai_settings, setupChatCompletionPromptManager } from './openai.js';
|
||||
import { autoSelectPersona, retriggerFirstMessageOnEmptyChat, user_avatar } from './personas.js';
|
||||
import { addEphemeralStoppingString, chat_styles, flushEphemeralStoppingStrings, power_user } from './power-user.js';
|
||||
@ -61,8 +61,9 @@ import { AutoComplete } from './autocomplete/AutoComplete.js';
|
||||
import { SlashCommand } from './slash-commands/SlashCommand.js';
|
||||
import { SlashCommandAbortController } from './slash-commands/SlashCommandAbortController.js';
|
||||
import { SlashCommandNamedArgumentAssignment } from './slash-commands/SlashCommandNamedArgumentAssignment.js';
|
||||
import { SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js';
|
||||
import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js';
|
||||
import { POPUP_TYPE, Popup, callGenericPopup } from './popup.js';
|
||||
import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js';
|
||||
export {
|
||||
executeSlashCommands, executeSlashCommandsWithOptions, getSlashCommandsHelp, registerSlashCommand,
|
||||
};
|
||||
@ -78,9 +79,16 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: '?',
|
||||
callback: helpCommandCallback,
|
||||
aliases: ['help'],
|
||||
unnamedArgumentList: [new SlashCommandArgument(
|
||||
'help topic', ARGUMENT_TYPE.STRING, false, false, null, ['slash', 'format', 'hotkeys', 'macros'],
|
||||
)],
|
||||
unnamedArgumentList: [SlashCommandArgument.fromProps({
|
||||
description: 'help topic',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
enumList: [
|
||||
new SlashCommandEnumValue('slash', 'slash commands (STscript)', enumTypes.command, '/'),
|
||||
new SlashCommandEnumValue('macros', '{{macros}} (text replacement)', enumTypes.macro, enumIcons.macro),
|
||||
new SlashCommandEnumValue('format', 'chat/text formatting', enumTypes.name, '★'),
|
||||
new SlashCommandEnumValue('hotkeys', 'keyboard shortcuts', enumTypes.enum, '⏎'),
|
||||
],
|
||||
})],
|
||||
helpString: 'Get help on macros, chat formatting and commands.',
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
@ -93,9 +101,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'persona name', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'persona name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: commonEnumProviders.personas,
|
||||
}),
|
||||
],
|
||||
helpString: 'Selects the given persona with its name and avatar (by name or avatar url). If no matching persona exists, applies a temporary name.',
|
||||
aliases: ['name'],
|
||||
@ -122,9 +133,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: () => [...document.querySelectorAll('.bg_example')]
|
||||
.map((it) => new SlashCommandEnumValue(it.getAttribute('bgfile')))
|
||||
.filter(it => it.value?.length)
|
||||
,
|
||||
.map(it => new SlashCommandEnumValue(it.getAttribute('bgfile')))
|
||||
.filter(it => it.value?.length),
|
||||
}),
|
||||
],
|
||||
helpString: `
|
||||
@ -145,16 +155,22 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'sendas',
|
||||
callback: sendMessageAs,
|
||||
namedArgumentList: [
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'name',
|
||||
description: 'Character name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: commonEnumProviders.characters('character'),
|
||||
forceEnum: false,
|
||||
}),
|
||||
new SlashCommandNamedArgument(
|
||||
'name', 'Character name', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'compact', 'Use compact layout', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false', ['true', 'false'],
|
||||
'compact', 'Use compact layout', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false',
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'at',
|
||||
description: 'position to insert the message',
|
||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
||||
enumProvider: commonEnumProviders.messages({ allowIdAfter: true, allowVars: true }),
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
@ -197,6 +213,7 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'at',
|
||||
description: 'position to insert the message',
|
||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
||||
enumProvider: commonEnumProviders.messages({ allowIdAfter: true, allowVars: true }),
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
@ -250,6 +267,7 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'at',
|
||||
description: 'position to insert the message',
|
||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
||||
enumProvider: commonEnumProviders.messages({ allowIdAfter: true, allowVars: true }),
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
@ -333,10 +351,7 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
description: 'name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: () => [
|
||||
...characters.map(it => new SlashCommandEnumValue(it.name, null, 'qr', 'C')),
|
||||
...groups.map(it => new SlashCommandEnumValue(it.name, null, 'variable', 'G')),
|
||||
],
|
||||
enumProvider: commonEnumProviders.characters('all'),
|
||||
}),
|
||||
],
|
||||
helpString: 'Opens up a chat with the character or group by its name',
|
||||
@ -384,7 +399,7 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
description: 'character name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: () => characters.map(it => new SlashCommandEnumValue(it.name, null, 'qr', 'C')),
|
||||
enumProvider: commonEnumProviders.characters('character'),
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
@ -399,9 +414,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
callback: deleteMessagesByNameCallback,
|
||||
namedArgumentList: [],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'name', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: commonEnumProviders.characters('character'),
|
||||
}),
|
||||
],
|
||||
aliases: ['cancel'],
|
||||
helpString: `
|
||||
@ -434,15 +452,18 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'at',
|
||||
description: 'position to insert the message',
|
||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
||||
enumProvider: commonEnumProviders.messages({ allowIdAfter: true, allowVars: true }),
|
||||
}),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'name',
|
||||
description: 'display name',
|
||||
typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.VARIABLE_NAME],
|
||||
defaultValue: '{{user}}',
|
||||
enumProvider: () => [
|
||||
...commonEnumProviders.characters('character')(),
|
||||
...commonEnumProviders.variables('all')().map(x => { x.description = 'Variable'; return x; }),
|
||||
],
|
||||
}),
|
||||
new SlashCommandNamedArgument(
|
||||
'name',
|
||||
'display name',
|
||||
[ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.VARIABLE_NAME],
|
||||
false,
|
||||
false,
|
||||
'{{user}}',
|
||||
),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
@ -487,6 +508,14 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
'false',
|
||||
),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'group member index (starts with 0) or name',
|
||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
|
||||
isRequired: false,
|
||||
enumProvider: commonEnumProviders.groupMembers(),
|
||||
}),
|
||||
],
|
||||
helpString: `
|
||||
<div>
|
||||
Triggers a message generation. If in group, can trigger a message for the specified group member index or name.
|
||||
@ -500,9 +529,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'hide',
|
||||
callback: hideMessageCallback,
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'message index or range', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE], true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'message index (starts with 0) or range',
|
||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE],
|
||||
isRequired: true,
|
||||
enumProvider: commonEnumProviders.messages(),
|
||||
}),
|
||||
],
|
||||
helpString: 'Hides a chat message from the prompt.',
|
||||
}));
|
||||
@ -510,9 +542,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'unhide',
|
||||
callback: unhideMessageCallback,
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'message index or range', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE], true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'message index (starts with 0) or range',
|
||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE],
|
||||
isRequired: true,
|
||||
enumProvider: commonEnumProviders.messages(),
|
||||
}),
|
||||
],
|
||||
helpString: 'Unhides a message from the prompt.',
|
||||
}));
|
||||
@ -521,9 +556,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
callback: disableGroupMemberCallback,
|
||||
aliases: ['disable', 'disablemember', 'memberdisable'],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'member index or name', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'member index (starts with 0) or name',
|
||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: commonEnumProviders.groupMembers(),
|
||||
}),
|
||||
],
|
||||
helpString: 'Disables a group member from being drafted for replies.',
|
||||
}));
|
||||
@ -532,9 +570,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
aliases: ['enable', 'enablemember', 'memberenable'],
|
||||
callback: enableGroupMemberCallback,
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'member index or name', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'member index (starts with 0) or name',
|
||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: commonEnumProviders.groupMembers(),
|
||||
}),
|
||||
],
|
||||
helpString: 'Enables a group member to be drafted for replies.',
|
||||
}));
|
||||
@ -543,9 +584,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
callback: addGroupMemberCallback,
|
||||
aliases: ['addmember', 'memberadd'],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'character name', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'character name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: () => selected_group ? commonEnumProviders.characters('character')() : [],
|
||||
}),
|
||||
],
|
||||
helpString: `
|
||||
<div>
|
||||
@ -566,9 +610,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
callback: removeGroupMemberCallback,
|
||||
aliases: ['removemember', 'memberremove'],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'member index or name', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'member index (starts with 0) or name',
|
||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: commonEnumProviders.groupMembers(),
|
||||
}),
|
||||
],
|
||||
helpString: `
|
||||
<div>
|
||||
@ -590,9 +637,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
callback: moveGroupMemberUpCallback,
|
||||
aliases: ['upmember', 'memberup'],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'member index or name', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'member index (starts with 0) or name',
|
||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: commonEnumProviders.groupMembers(),
|
||||
}),
|
||||
],
|
||||
helpString: 'Moves a group member up in the group chat list.',
|
||||
}));
|
||||
@ -601,9 +651,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
callback: moveGroupMemberDownCallback,
|
||||
aliases: ['downmember', 'memberdown'],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'member index or name', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'member index (starts with 0) or name',
|
||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: commonEnumProviders.groupMembers(),
|
||||
}),
|
||||
],
|
||||
helpString: 'Moves a group member down in the group chat list.',
|
||||
}));
|
||||
@ -611,9 +664,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'peek',
|
||||
callback: peekCallback,
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'message index or range', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE], false, true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'member index (starts with 0) or name',
|
||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: commonEnumProviders.groupMembers(),
|
||||
}),
|
||||
],
|
||||
helpString: `
|
||||
<div>
|
||||
@ -623,12 +679,8 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
<strong>Examples:</strong>
|
||||
<ul>
|
||||
<li>
|
||||
<pre><code>/peek 5</code></pre>
|
||||
Shows the character card for the 5th message.
|
||||
</li>
|
||||
<li>
|
||||
<pre><code>/peek 2-5</code></pre>
|
||||
Shows the character cards for messages 2 through 5.
|
||||
<pre><code>/peek Gloria</code></pre>
|
||||
Shows the character card for the character named "Gloria".
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@ -639,9 +691,14 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
callback: deleteSwipeCallback,
|
||||
aliases: ['swipedel'],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'1-based swipe id', [ARGUMENT_TYPE.NUMBER],
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: '1-based swipe id',
|
||||
typeList: [ARGUMENT_TYPE.NUMBER],
|
||||
isRequired: true,
|
||||
enumProvider: () => Array.isArray(chat[chat.length - 1]?.swipes) ?
|
||||
chat[chat.length - 1].swipes.map((/** @type {string} */ swipe, /** @type {number} */ i) => new SlashCommandEnumValue(String(i + 1), swipe, enumTypes.enum, enumIcons.message))
|
||||
: [],
|
||||
}),
|
||||
],
|
||||
helpString: `
|
||||
<div>
|
||||
@ -670,9 +727,18 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
new SlashCommandNamedArgument(
|
||||
'title', 'title of the toast message', [ARGUMENT_TYPE.STRING], false,
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'severity', 'severity level of the toast message', [ARGUMENT_TYPE.STRING], false, false, null, ['info', 'warning', 'error', 'success'],
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'severity',
|
||||
description: 'severity level of the toast message',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
defaultValue: 'info',
|
||||
enumProvider: () => [
|
||||
new SlashCommandEnumValue('info', 'info', enumTypes.macro, 'ℹ️'),
|
||||
new SlashCommandEnumValue('warning', 'warning', enumTypes.enum, '⚠️'),
|
||||
new SlashCommandEnumValue('error', 'error', enumTypes.enum, '❗'),
|
||||
new SlashCommandEnumValue('success', 'success', enumTypes.enum, '✅'),
|
||||
],
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
@ -699,17 +765,28 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
returns: 'generated text',
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument(
|
||||
'lock', 'lock user input during generation', [ARGUMENT_TYPE.BOOLEAN], false, false, null, ['on', 'off'],
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'name', 'in-prompt name for instruct mode', [ARGUMENT_TYPE.STRING], false, false, 'System',
|
||||
'lock', 'lock user input during generation', [ARGUMENT_TYPE.BOOLEAN], false, false, null, commonEnumProviders.boolean('onOff')(),
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'name',
|
||||
description: 'in-prompt name for instruct mode',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
defaultValue: 'System',
|
||||
enumProvider: () => [...commonEnumProviders.characters('character')(), new SlashCommandEnumValue('System', null, enumTypes.enum, enumIcons.assistant)],
|
||||
forceEnum: false,
|
||||
}),
|
||||
new SlashCommandNamedArgument(
|
||||
'length', 'API response length in tokens', [ARGUMENT_TYPE.NUMBER], false,
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'as', 'role of the output prompt', [ARGUMENT_TYPE.STRING], false, false, 'system', ['system', 'char'],
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'as',
|
||||
description: 'role of the output prompt',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
enumList: [
|
||||
new SlashCommandEnumValue('system', null, enumTypes.enum, enumIcons.assistant),
|
||||
new SlashCommandEnumValue('char', null, enumTypes.enum, enumIcons.character),
|
||||
],
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
@ -731,17 +808,23 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
returns: 'generated text',
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument(
|
||||
'lock', 'lock user input during generation', [ARGUMENT_TYPE.BOOLEAN], false, false, null, ['on', 'off'],
|
||||
'lock', 'lock user input during generation', [ARGUMENT_TYPE.BOOLEAN], false, false, null, commonEnumProviders.boolean('onOff')(),
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'instruct', 'use instruct mode', [ARGUMENT_TYPE.BOOLEAN], false, false, 'on', ['on', 'off'],
|
||||
'instruct', 'use instruct mode', [ARGUMENT_TYPE.BOOLEAN], false, false, 'on', commonEnumProviders.boolean('onOff')(),
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'stop', 'one-time custom stop strings', [ARGUMENT_TYPE.LIST], false,
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'as', 'role of the output prompt', [ARGUMENT_TYPE.STRING], false, false, 'system', ['system', 'char'],
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'as',
|
||||
description: 'role of the output prompt',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
enumList: [
|
||||
new SlashCommandEnumValue('system', null, enumTypes.enum, enumIcons.assistant),
|
||||
new SlashCommandEnumValue('char', null, enumTypes.enum, enumIcons.character),
|
||||
],
|
||||
}),
|
||||
new SlashCommandNamedArgument(
|
||||
'system', 'system prompt at the start', [ARGUMENT_TYPE.STRING], false,
|
||||
),
|
||||
@ -792,7 +875,6 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
description: 'Whether to suppress the toast message notifying about the /abort call.',
|
||||
typeList: [ARGUMENT_TYPE.BOOLEAN],
|
||||
defaultValue: 'true',
|
||||
enumList: ['true', 'false'],
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
@ -845,7 +927,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'pass',
|
||||
callback: (_, arg) => arg,
|
||||
callback: (_, arg) => {
|
||||
// We do not support arrays of closures. Arrays of strings will be send as JSON
|
||||
if (Array.isArray(arg) && arg.some(x => x instanceof SlashCommandClosure)) throw new Error('Command /pass does not support multiple closures');
|
||||
if (Array.isArray(arg)) return JSON.stringify(arg);
|
||||
return arg;
|
||||
},
|
||||
returns: 'the provided value',
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
@ -898,10 +985,10 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
'default', 'default value of the input field', [ARGUMENT_TYPE.STRING], false, false, '"string"',
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'large', 'show large input field', [ARGUMENT_TYPE.BOOLEAN], false, false, 'off', ['on', 'off'],
|
||||
'large', 'show large input field', [ARGUMENT_TYPE.BOOLEAN], false, false, 'off', commonEnumProviders.boolean('onOff')(),
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'wide', 'show wide input field', [ARGUMENT_TYPE.BOOLEAN], false, false, 'off', ['on', 'off'],
|
||||
'wide', 'show wide input field', [ARGUMENT_TYPE.BOOLEAN], false, false, 'off', commonEnumProviders.boolean('onOff')(),
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'okButton', 'text for the ok button', [ARGUMENT_TYPE.STRING], false,
|
||||
@ -933,9 +1020,15 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'scoped variable or qr label', [ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'scoped variable or qr label',
|
||||
typeList: [ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: () => [
|
||||
...commonEnumProviders.variables('scope')(),
|
||||
...(typeof window['qrEnumProviderExecutables'] === 'function') ? window['qrEnumProviderExecutables']() : [],
|
||||
],
|
||||
}),
|
||||
],
|
||||
helpString: `
|
||||
<div>
|
||||
@ -950,19 +1043,29 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
aliases: ['message'],
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument(
|
||||
'names', 'show message author names', [ARGUMENT_TYPE.BOOLEAN], false, false, 'off', ['off', 'on'],
|
||||
'names', 'show message author names', [ARGUMENT_TYPE.BOOLEAN], false, false, 'off', commonEnumProviders.boolean('onOff')(),
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'hidden', 'include hidden messages', [ARGUMENT_TYPE.BOOLEAN], false, false, 'on', ['off', 'on'],
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'role', 'filter messages by role', [ARGUMENT_TYPE.STRING], false, false, null, ['system', 'assistant', 'user'],
|
||||
'hidden', 'include hidden messages', [ARGUMENT_TYPE.BOOLEAN], false, false, 'on', commonEnumProviders.boolean('onOff')(),
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'role',
|
||||
description: 'filter messages by role',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
enumList: [
|
||||
new SlashCommandEnumValue('system', null, enumTypes.enum, enumIcons.system),
|
||||
new SlashCommandEnumValue('assistant', null, enumTypes.enum, enumIcons.assistant),
|
||||
new SlashCommandEnumValue('user', null, enumTypes.enum, enumIcons.user),
|
||||
],
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'message index or range', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE], false, true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'message index (starts with 0) or range',
|
||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE],
|
||||
isRequired: true,
|
||||
enumProvider: commonEnumProviders.messages(),
|
||||
}),
|
||||
],
|
||||
returns: 'the specified message or range of messages as a string',
|
||||
helpString: `
|
||||
@ -1018,10 +1121,10 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
returns: 'popup text',
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument(
|
||||
'large', 'show large popup', [ARGUMENT_TYPE.BOOLEAN], false, false, null, ['on', 'off'],
|
||||
'large', 'show large popup', [ARGUMENT_TYPE.BOOLEAN], false, false, null, commonEnumProviders.boolean('onOff')(),
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'wide', 'show wide popup', [ARGUMENT_TYPE.BOOLEAN], false, false, null, ['on', 'off'],
|
||||
'wide', 'show wide popup', [ARGUMENT_TYPE.BOOLEAN], false, false, null, commonEnumProviders.boolean('onOff')(),
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'okButton', 'text for the OK button', [ARGUMENT_TYPE.STRING], false,
|
||||
@ -1084,9 +1187,16 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
new SlashCommandNamedArgument(
|
||||
'limit', 'number of tokens to keep', [ARGUMENT_TYPE.NUMBER], true,
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'direction', 'trim direction', [ARGUMENT_TYPE.STRING], true, false, null, ['start', 'end'],
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'direction',
|
||||
description: 'trim direction',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumList: [
|
||||
new SlashCommandEnumValue('start', null, enumTypes.enum, '⏪'),
|
||||
new SlashCommandEnumValue('end', null, enumTypes.enum, '⏩'),
|
||||
],
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
@ -1145,9 +1255,17 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'inject',
|
||||
callback: injectCallback,
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument(
|
||||
'id', 'injection ID', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'id',
|
||||
description: 'injection ID or variable name pointing to ID',
|
||||
typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.VARIABLE_NAME],
|
||||
isRequired: true,
|
||||
|
||||
enumProvider: () => [
|
||||
...commonEnumProviders.injects(),
|
||||
...commonEnumProviders.variables('all')().map(x => { x.description = 'Variable'; return x; }),
|
||||
],
|
||||
}),
|
||||
new SlashCommandNamedArgument(
|
||||
'position', 'injection position', [ARGUMENT_TYPE.STRING], false, false, 'after', ['before', 'after', 'chat'],
|
||||
),
|
||||
@ -1157,11 +1275,19 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
new SlashCommandNamedArgument(
|
||||
'scan', 'include injection content into World Info scans', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false',
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'role',
|
||||
description: 'role for in-chat injections',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: false,
|
||||
enumList: [
|
||||
new SlashCommandEnumValue('system', null, enumTypes.enum, enumIcons.system),
|
||||
new SlashCommandEnumValue('assistant', null, enumTypes.enum, enumIcons.assistant),
|
||||
new SlashCommandEnumValue('user', null, enumTypes.enum, enumIcons.user),
|
||||
],
|
||||
}),
|
||||
new SlashCommandNamedArgument(
|
||||
'role', 'role for in-chat injections', [ARGUMENT_TYPE.STRING], false, false, 'system', ['system', 'user', 'assistant'],
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'ephemeral', 'remove injection after generation', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false', ['true', 'false'],
|
||||
'ephemeral', 'remove injection after generation', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false',
|
||||
),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
@ -1180,16 +1306,25 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'flushinject',
|
||||
aliases: ['flushinjects'],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'injection ID or a variable name pointing to ID', [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.VARIABLE_NAME], false, false, '',
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'injection ID or a variable name pointing to ID',
|
||||
typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.VARIABLE_NAME],
|
||||
defaultValue: '',
|
||||
enumProvider: () => [
|
||||
...commonEnumProviders.injects(),
|
||||
...commonEnumProviders.variables('all')().map(x => { x.description = 'Variable'; return x; }),
|
||||
],
|
||||
}),
|
||||
],
|
||||
callback: flushInjectsCallback,
|
||||
helpString: 'Removes a script injection for the current chat. If no ID is provided, removes all script injections.',
|
||||
}));
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'tokens',
|
||||
callback: (_, text) => getTokenCountAsync(text),
|
||||
callback: (_, text) => {
|
||||
if (text instanceof SlashCommandClosure || Array.isArray(text)) throw new Error('Unnamed argument cannot be a closure for command /tokens');
|
||||
return getTokenCountAsync(text).then(count => String(count));
|
||||
},
|
||||
returns: 'number of tokens',
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
@ -1203,9 +1338,11 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
callback: modelCallback,
|
||||
returns: 'current model',
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'model name', [ARGUMENT_TYPE.STRING], false,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'model name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
enumProvider: () => getModelOptions()?.options.map(option => new SlashCommandEnumValue(option.value, option.value !== option.text ? option.text : null)),
|
||||
}),
|
||||
],
|
||||
helpString: 'Sets the model for the current API. Gets the current model name if no argument is provided.',
|
||||
}));
|
||||
@ -1214,12 +1351,28 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
aliases: ['setpromptentries'],
|
||||
callback: setPromptEntryCallback,
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument(
|
||||
'identifier', 'Prompt entry identifier(s) to target', [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST], false, true,
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'name', 'Prompt entry name(s) to target', [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST], false, true,
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'identifier',
|
||||
description: 'Prompt entry identifier(s) to target',
|
||||
typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST],
|
||||
acceptsMultiple: true,
|
||||
enumProvider: () => {
|
||||
const promptManager = setupChatCompletionPromptManager(oai_settings);
|
||||
const prompts = promptManager.serviceSettings.prompts;
|
||||
return prompts.map(prompt => new SlashCommandEnumValue(prompt.identifier, prompt.name, enumTypes.enum));
|
||||
},
|
||||
}),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'name',
|
||||
description: 'Prompt entry name(s) to target',
|
||||
typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST],
|
||||
acceptsMultiple: true,
|
||||
enumProvider: () => {
|
||||
const promptManager = setupChatCompletionPromptManager(oai_settings);
|
||||
const prompts = promptManager.serviceSettings.prompts;
|
||||
return prompts.map(prompt => new SlashCommandEnumValue(prompt.name, prompt.identifier, enumTypes.enum));
|
||||
},
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
SlashCommandArgument.fromProps({
|
||||
@ -1228,7 +1381,7 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
isRequired: true,
|
||||
acceptsMultiple: false,
|
||||
defaultValue: 'toggle', // unnamed arguments don't support default values yet
|
||||
enumList: ['on', 'off', 'toggle'],
|
||||
enumList: commonEnumProviders.boolean('onOffToggle')(),
|
||||
}),
|
||||
],
|
||||
helpString: 'Sets the specified prompt manager entry/entries on or off.',
|
||||
@ -1505,7 +1658,7 @@ async function popupCallback(args, value) {
|
||||
await delay(1);
|
||||
await callGenericPopup(safeValue, POPUP_TYPE.TEXT, '', popupOptions);
|
||||
await delay(1);
|
||||
return value;
|
||||
return String(value);
|
||||
}
|
||||
|
||||
function getMessagesCallback(args, value) {
|
||||
@ -1609,13 +1762,13 @@ async function runCallback(args, name) {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {object} param0
|
||||
* @param {SlashCommandAbortController} param0._abortController
|
||||
* @param {string} [param0.quiet]
|
||||
* @param {import('./slash-commands/SlashCommand.js').NamedArguments} param0
|
||||
* @param {string} [reason]
|
||||
*/
|
||||
function abortCallback({ _abortController, quiet }, reason) {
|
||||
if (quiet instanceof SlashCommandClosure) throw new Error('argument \'quiet\' cannot be a closure for command /abort');
|
||||
_abortController.abort((reason ?? '').toString().length == 0 ? '/abort command executed' : reason, !isFalseBoolean(quiet ?? 'true'));
|
||||
return '';
|
||||
}
|
||||
|
||||
async function delayCallback(_, amount) {
|
||||
@ -1644,9 +1797,9 @@ async function inputCallback(args, prompt) {
|
||||
};
|
||||
// Do not remove this delay, otherwise the prompt will not show up
|
||||
await delay(1);
|
||||
const result = await callPopup(safeValue, 'input', defaultInput, popupOptions);
|
||||
const result = await callGenericPopup(safeValue, POPUP_TYPE.INPUT, defaultInput, popupOptions);
|
||||
await delay(1);
|
||||
return result || '';
|
||||
return String(result || '');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2766,12 +2919,11 @@ function setBackgroundCallback(_, bg) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a model for the current API.
|
||||
* @param {object} _ Unused
|
||||
* @param {string} model New model name
|
||||
* @returns {string} New or existing model name
|
||||
* Retrieves the available model options based on the currently selected main API and its subtype
|
||||
*
|
||||
* @returns {{control: HTMLSelectElement, options: HTMLOptionElement[]}?} An array of objects representing the available model options, or null if not supported
|
||||
*/
|
||||
function modelCallback(_, model) {
|
||||
function getModelOptions() {
|
||||
const modelSelectMap = [
|
||||
{ id: 'model_togetherai_select', api: 'textgenerationwebui', type: textgen_types.TOGETHERAI },
|
||||
{ id: 'openrouter_model', api: 'textgenerationwebui', type: textgen_types.OPENROUTER },
|
||||
@ -2812,17 +2964,33 @@ function modelCallback(_, model) {
|
||||
|
||||
if (!modelSelectItem) {
|
||||
toastr.info('Setting a model for your API is not supported or not implemented yet.');
|
||||
return '';
|
||||
return null;
|
||||
}
|
||||
|
||||
const modelSelectControl = document.getElementById(modelSelectItem);
|
||||
|
||||
if (!(modelSelectControl instanceof HTMLSelectElement)) {
|
||||
toastr.error(`Model select control not found: ${main_api}[${apiSubType}]`);
|
||||
return '';
|
||||
return null;
|
||||
}
|
||||
|
||||
const options = Array.from(modelSelectControl.options);
|
||||
return { control: modelSelectControl, options };
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a model for the current API.
|
||||
* @param {object} _ Unused
|
||||
* @param {string} model New model name
|
||||
* @returns {string} New or existing model name
|
||||
*/
|
||||
function modelCallback(_, model) {
|
||||
const { control: modelSelectControl, options } = getModelOptions();
|
||||
|
||||
// If no model was found, the reason was already logged, we just return here
|
||||
if (options === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (!options.length) {
|
||||
toastr.warning('No model options found. Check your API settings.');
|
||||
|
@ -175,6 +175,11 @@ export class SlashCommand {
|
||||
}
|
||||
li.append(specs);
|
||||
}
|
||||
const stopgap = document.createElement('span'); {
|
||||
stopgap.classList.add('stopgap');
|
||||
stopgap.textContent = '';
|
||||
li.append(stopgap);
|
||||
}
|
||||
const help = document.createElement('span'); {
|
||||
help.classList.add('help');
|
||||
const content = document.createElement('span'); {
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { SlashCommandClosure } from './SlashCommandClosure.js';
|
||||
import { commonEnumProviders } from './SlashCommandCommonEnumsProvider.js';
|
||||
import { SlashCommandEnumValue } from './SlashCommandEnumValue.js';
|
||||
import { SlashCommandExecutor } from './SlashCommandExecutor.js';
|
||||
|
||||
|
||||
|
||||
/**@readonly*/
|
||||
/**@enum {string}*/
|
||||
export const ARGUMENT_TYPE = {
|
||||
@ -18,20 +17,18 @@ export const ARGUMENT_TYPE = {
|
||||
'DICTIONARY': 'dictionary',
|
||||
};
|
||||
|
||||
|
||||
|
||||
export class SlashCommandArgument {
|
||||
/**
|
||||
* Creates an unnamed argument from a properties object.
|
||||
* @param {Object} props
|
||||
* @param {string} props.description description of the argument
|
||||
* @param {ARGUMENT_TYPE|ARGUMENT_TYPE[]} props.typeList default: ARGUMENT_TYPE.STRING - list of accepted types (from ARGUMENT_TYPE)
|
||||
* @param {boolean} [props.isRequired] default: false - whether the argument is required (false = optional argument)
|
||||
* @param {boolean} [props.acceptsMultiple] default: false - whether argument accepts multiple values
|
||||
* @param {string|SlashCommandClosure} [props.defaultValue] default value if no value is provided
|
||||
* @param {string|SlashCommandEnumValue|(string|SlashCommandEnumValue)[]} [props.enumList] list of accepted values
|
||||
* @param {(executor:SlashCommandExecutor)=>SlashCommandEnumValue[]} [props.enumProvider] function that returns auto complete options
|
||||
* @param {boolean} [props.forceEnum] default: true - whether the input must match one of the enum values
|
||||
* @param {ARGUMENT_TYPE|ARGUMENT_TYPE[]} [props.typeList=[ARGUMENT_TYPE.STRING]] default: ARGUMENT_TYPE.STRING - list of accepted types (from ARGUMENT_TYPE)
|
||||
* @param {boolean} [props.isRequired=false] default: false - whether the argument is required (false = optional argument)
|
||||
* @param {boolean} [props.acceptsMultiple=false] default: false - whether argument accepts multiple values
|
||||
* @param {string|SlashCommandClosure} [props.defaultValue=null] default value if no value is provided
|
||||
* @param {string|SlashCommandEnumValue|(string|SlashCommandEnumValue)[]} [props.enumList=[]] list of accepted values
|
||||
* @param {(executor:SlashCommandExecutor)=>SlashCommandEnumValue[]} [props.enumProvider=null] function that returns auto complete options
|
||||
* @param {boolean} [props.forceEnum=false] default: false - whether the input must match one of the enum values
|
||||
*/
|
||||
static fromProps(props) {
|
||||
return new SlashCommandArgument(
|
||||
@ -42,13 +39,10 @@ export class SlashCommandArgument {
|
||||
props.defaultValue ?? null,
|
||||
props.enumList ?? [],
|
||||
props.enumProvider ?? null,
|
||||
props.forceEnum ?? true,
|
||||
props.forceEnum ?? false,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**@type {string}*/ description;
|
||||
/**@type {ARGUMENT_TYPE[]}*/ typeList = [];
|
||||
/**@type {boolean}*/ isRequired = false;
|
||||
@ -56,8 +50,7 @@ export class SlashCommandArgument {
|
||||
/**@type {string|SlashCommandClosure}*/ defaultValue;
|
||||
/**@type {SlashCommandEnumValue[]}*/ enumList = [];
|
||||
/**@type {(executor:SlashCommandExecutor)=>SlashCommandEnumValue[]}*/ enumProvider = null;
|
||||
/**@type {boolean}*/ forceEnum = true;
|
||||
|
||||
/**@type {boolean}*/ forceEnum = false;
|
||||
|
||||
/**
|
||||
* @param {string} description
|
||||
@ -78,25 +71,26 @@ export class SlashCommandArgument {
|
||||
});
|
||||
this.enumProvider = enumProvider;
|
||||
this.forceEnum = forceEnum;
|
||||
|
||||
// If no enums were set explictly and the type is one where we know possible enum values, we set them here
|
||||
if (!this.enumList.length && this.typeList.includes(ARGUMENT_TYPE.BOOLEAN)) this.enumList = commonEnumProviders.boolean()();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
export class SlashCommandNamedArgument extends SlashCommandArgument {
|
||||
/**
|
||||
* Creates an unnamed argument from a properties object.
|
||||
* @param {Object} props
|
||||
* @param {string} props.name the argument's name
|
||||
* @param {string[]} [props.aliasList] list of aliases
|
||||
* @param {string} props.description description of the argument
|
||||
* @param {ARGUMENT_TYPE|ARGUMENT_TYPE[]} props.typeList default: ARGUMENT_TYPE.STRING - list of accepted types (from ARGUMENT_TYPE)
|
||||
* @param {boolean} [props.isRequired] default: false - whether the argument is required (false = optional argument)
|
||||
* @param {boolean} [props.acceptsMultiple] default: false - whether argument accepts multiple values
|
||||
* @param {string|SlashCommandClosure} [props.defaultValue] default value if no value is provided
|
||||
* @param {string|SlashCommandEnumValue|(string|SlashCommandEnumValue)[]} [props.enumList] list of accepted values
|
||||
* @param {(executor:SlashCommandExecutor)=>SlashCommandEnumValue[]} [props.enumProvider] function that returns auto complete options
|
||||
* @param {boolean} [props.forceEnum] default: true - whether the input must match one of the enum values
|
||||
* @param {string[]} [props.aliasList=[]] list of aliases
|
||||
* @param {ARGUMENT_TYPE|ARGUMENT_TYPE[]} [props.typeList=[ARGUMENT_TYPE.STRING]] default: ARGUMENT_TYPE.STRING - list of accepted types (from ARGUMENT_TYPE)
|
||||
* @param {boolean} [props.isRequired=false] default: false - whether the argument is required (false = optional argument)
|
||||
* @param {boolean} [props.acceptsMultiple=false] default: false - whether argument accepts multiple values
|
||||
* @param {string|SlashCommandClosure} [props.defaultValue=null] default value if no value is provided
|
||||
* @param {string|SlashCommandEnumValue|(string|SlashCommandEnumValue)[]} [props.enumList=[]] list of accepted values
|
||||
* @param {(executor:SlashCommandExecutor)=>SlashCommandEnumValue[]} [props.enumProvider=null] function that returns auto complete options
|
||||
* @param {boolean} [props.forceEnum=true] default: true - whether the input must match one of the enum values
|
||||
*/
|
||||
static fromProps(props) {
|
||||
return new SlashCommandNamedArgument(
|
||||
@ -113,21 +107,20 @@ export class SlashCommandNamedArgument extends SlashCommandArgument {
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**@type {string}*/ name;
|
||||
/**@type {string[]}*/ aliasList = [];
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {string} description
|
||||
* @param {ARGUMENT_TYPE|ARGUMENT_TYPE[]} types
|
||||
* @param {string|SlashCommandClosure} defaultValue
|
||||
* @param {string|SlashCommandEnumValue|(string|SlashCommandEnumValue)[]} enums
|
||||
* @param {(executor:SlashCommandExecutor)=>SlashCommandEnumValue[]} enumProvider function that returns auto complete options
|
||||
* @param {boolean} forceEnum
|
||||
* @param {boolean} [isRequired=false]
|
||||
* @param {boolean} [acceptsMultiple=false]
|
||||
* @param {string|SlashCommandClosure} [defaultValue=null]
|
||||
* @param {string|SlashCommandEnumValue|(string|SlashCommandEnumValue)[]} [enums=[]]
|
||||
* @param {string[]} [aliases=[]]
|
||||
* @param {(executor:SlashCommandExecutor)=>SlashCommandEnumValue[]} [enumProvider=null] function that returns auto complete options
|
||||
* @param {boolean} [forceEnum=true]
|
||||
*/
|
||||
constructor(name, description, types, isRequired = false, acceptsMultiple = false, defaultValue = null, enums = [], aliases = [], enumProvider = null, forceEnum = true) {
|
||||
super(description, types, isRequired, acceptsMultiple, defaultValue, enums, enumProvider, forceEnum);
|
||||
|
@ -93,7 +93,7 @@ export class SlashCommandClosure {
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns Promise<SlashCommandClosureResult>
|
||||
* @returns {Promise<SlashCommandClosureResult>}
|
||||
*/
|
||||
async execute() {
|
||||
const closure = this.getCopy();
|
||||
|
232
public/scripts/slash-commands/SlashCommandCommonEnumsProvider.js
Normal file
232
public/scripts/slash-commands/SlashCommandCommonEnumsProvider.js
Normal file
@ -0,0 +1,232 @@
|
||||
import { chat_metadata, characters, substituteParams, chat, extension_prompt_roles, extension_prompt_types } from "../../script.js";
|
||||
import { extension_settings } from "../extensions.js";
|
||||
import { getGroupMembers, groups, selected_group } from "../group-chats.js";
|
||||
import { power_user } from "../power-user.js";
|
||||
import { searchCharByName, getTagsList, tags } from "../tags.js";
|
||||
import { SlashCommandClosure } from "./SlashCommandClosure.js";
|
||||
import { SlashCommandEnumValue, enumTypes } from "./SlashCommandEnumValue.js";
|
||||
import { SlashCommandExecutor } from "./SlashCommandExecutor.js";
|
||||
|
||||
/**
|
||||
* A collection of regularly used enum icons
|
||||
*/
|
||||
export const enumIcons = {
|
||||
default: '◊',
|
||||
|
||||
// Variables
|
||||
variable: '𝑥',
|
||||
localVariable: 'L',
|
||||
globalVariable: 'G',
|
||||
scopeVariable: 'S',
|
||||
|
||||
// Common types
|
||||
character: '👤',
|
||||
group: '🧑🤝🧑',
|
||||
persona: '🧙♂️',
|
||||
qr: 'QR',
|
||||
closure: '𝑓',
|
||||
macro: '{{',
|
||||
tag: '🏷️',
|
||||
world: '🌐',
|
||||
preset: '⚙️',
|
||||
file: '📄',
|
||||
message: '💬',
|
||||
voice: '🎤',
|
||||
|
||||
true: '✔️',
|
||||
false: '❌',
|
||||
|
||||
// Value types
|
||||
boolean: '🔲',
|
||||
string: '📝',
|
||||
number: '1️⃣',
|
||||
array: '[]',
|
||||
enum: '📚',
|
||||
dictionary: '{}',
|
||||
|
||||
// Roles
|
||||
system: '⚙️',
|
||||
user: '👤',
|
||||
assistant: '🤖',
|
||||
|
||||
// WI Icons
|
||||
constant: '🔵',
|
||||
normal: '🟢',
|
||||
disabled: '❌',
|
||||
vectorized: '🔗',
|
||||
|
||||
/**
|
||||
* Returns the appropriate state icon based on a boolean
|
||||
*
|
||||
* @param {boolean} state - The state to determine the icon for
|
||||
* @returns {string} The corresponding state icon
|
||||
*/
|
||||
getStateIcon: (state) => {
|
||||
return state ? enumIcons.true : enumIcons.false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the appropriate WI icon based on the entry
|
||||
*
|
||||
* @param {Object} entry - WI entry
|
||||
* @returns {string} The corresponding WI icon
|
||||
*/
|
||||
getWiStatusIcon: (entry) => {
|
||||
if (entry.constant) return enumIcons.constant;
|
||||
if (entry.disable) return enumIcons.disabled;
|
||||
if (entry.vectorized) return enumIcons.vectorized;
|
||||
return enumIcons.normal;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the appropriate icon based on the role
|
||||
*
|
||||
* @param {extension_prompt_roles} role - The role to get the icon for
|
||||
* @returns {string} The corresponding icon
|
||||
*/
|
||||
getRoleIcon: (role) => {
|
||||
switch (role) {
|
||||
case extension_prompt_roles.SYSTEM: return enumIcons.system;
|
||||
case extension_prompt_roles.USER: return enumIcons.user;
|
||||
case extension_prompt_roles.ASSISTANT: return enumIcons.assistant;
|
||||
default: return enumIcons.default;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* A function to get the data type icon
|
||||
*
|
||||
* @param {string} type - The type of the data
|
||||
* @returns {string} The corresponding data type icon
|
||||
*/
|
||||
getDataTypeIcon: (type) => {
|
||||
// Remove possible nullable types definition to match type icon
|
||||
type = type.replace(/\?$/, '');
|
||||
return enumIcons[type] ?? enumIcons.default;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A collection of common enum providers
|
||||
*
|
||||
* Can be used on `SlashCommandNamedArgument` and `SlashCommandArgument` and their `enumProvider` property.
|
||||
*/
|
||||
export const commonEnumProviders = {
|
||||
/**
|
||||
* Enum values for booleans. Either using true/false or on/off
|
||||
* Optionally supports "toggle".
|
||||
*
|
||||
* @param {('onOff'|'onOffToggle'|'trueFalse')?} [mode='trueFalse'] - The mode to use. Default is 'trueFalse'.
|
||||
* @returns {() => SlashCommandEnumValue[]}
|
||||
*/
|
||||
boolean: (mode = 'trueFalse') => () => {
|
||||
switch (mode) {
|
||||
case 'onOff': return [new SlashCommandEnumValue('on', null, 'macro', enumIcons.true), new SlashCommandEnumValue('off', null, 'macro', enumIcons.false)];
|
||||
case 'onOffToggle': return [new SlashCommandEnumValue('on', null, 'macro', enumIcons.true), new SlashCommandEnumValue('off', null, 'macro', enumIcons.false), new SlashCommandEnumValue('toggle', null, 'macro', enumIcons.boolean)];
|
||||
case 'trueFalse': return [new SlashCommandEnumValue('true', null, 'macro', enumIcons.true), new SlashCommandEnumValue('false', null, 'macro', enumIcons.false)];
|
||||
default: throw new Error(`Invalid boolean enum provider mode: ${mode}`);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* All possible variable names
|
||||
*
|
||||
* Can be filtered by `type` to only show global or local variables
|
||||
*
|
||||
* @param {...('global'|'local'|'scope'|'all')} type - The type of variables to include in the array. Can be 'all', 'global', or 'local'.
|
||||
* @returns {() => SlashCommandEnumValue[]}
|
||||
*/
|
||||
variables: (...type) => () => {
|
||||
const types = type.flat();
|
||||
const isAll = types.includes('all');
|
||||
return [
|
||||
...isAll || types.includes('global') ? Object.keys(extension_settings.variables.global ?? []).map(name => new SlashCommandEnumValue(name, null, enumTypes.macro, enumIcons.globalVariable)) : [],
|
||||
...isAll || types.includes('local') ? Object.keys(chat_metadata.variables ?? []).map(name => new SlashCommandEnumValue(name, null, enumTypes.name, enumIcons.localVariable)) : [],
|
||||
...isAll || types.includes('scope') ? [].map(name => new SlashCommandEnumValue(name, null, enumTypes.variable, enumIcons.scopeVariable)) : [], // TODO: Add scoped variables here, Lenny
|
||||
]
|
||||
},
|
||||
|
||||
/**
|
||||
* All possible char entities, like characters and groups. Can be filtered down to just one type.
|
||||
*
|
||||
* @param {('all' | 'character' | 'group')?} [mode='all'] - Which type to return
|
||||
* @returns {() => SlashCommandEnumValue[]}
|
||||
*/
|
||||
characters: (mode = 'all') => () => {
|
||||
return [
|
||||
...['all', 'character'].includes(mode) ? characters.map(char => new SlashCommandEnumValue(char.name, null, enumTypes.name, enumIcons.character)) : [],
|
||||
...['all', 'group'].includes(mode) ? groups.map(group => new SlashCommandEnumValue(group.name, null, enumTypes.qr, enumIcons.group)) : [],
|
||||
];
|
||||
},
|
||||
|
||||
/**
|
||||
* All group members of the given group, or default the current active one
|
||||
*
|
||||
* @param {string?} groupId - The id of the group - pass in `undefined` to use the current active group
|
||||
* @returns {() =>SlashCommandEnumValue[]}
|
||||
*/
|
||||
groupMembers: (groupId = undefined) => () => getGroupMembers(groupId).map((character, index) => new SlashCommandEnumValue(String(index), character.name, enumTypes.enum, enumIcons.character)),
|
||||
|
||||
/**
|
||||
* All possible personas
|
||||
*
|
||||
* @returns {SlashCommandEnumValue[]}
|
||||
*/
|
||||
personas: () => Object.values(power_user.personas).map(persona => new SlashCommandEnumValue(persona, null, enumTypes.name, enumIcons.persona)),
|
||||
|
||||
/**
|
||||
* All possible tags for a given char/group entity
|
||||
*
|
||||
* @param {('all' | 'existing' | 'not-existing')?} [mode='all'] - Which types of tags to show
|
||||
* @returns {() => SlashCommandEnumValue[]}
|
||||
*/
|
||||
tagsForChar: (mode = 'all') => (/** @type {SlashCommandExecutor} */ executor) => {
|
||||
// Try to see if we can find the char during execution to filter down the tags list some more. Otherwise take all tags.
|
||||
const charName = executor.namedArgumentList.find(it => it.name == 'name')?.value;
|
||||
if (charName instanceof SlashCommandClosure) throw new Error('Argument \'name\' does not support closures');
|
||||
const key = searchCharByName(substituteParams(charName), { suppressLogging: true });
|
||||
const assigned = key ? getTagsList(key) : [];
|
||||
return tags.filter(it => !key || mode === 'all' || mode === 'existing' && assigned.includes(it) || mode === 'not-existing' && !assigned.includes(it))
|
||||
.map(tag => new SlashCommandEnumValue(tag.name, null, enumTypes.command, enumIcons.tag));
|
||||
},
|
||||
|
||||
/**
|
||||
* All messages in the current chat, returning the message id
|
||||
*
|
||||
* Optionally supports variable names, and/or a placeholder for the last/new message id
|
||||
*
|
||||
* @param {object} [options={}] - Optional arguments
|
||||
* @param {boolean} [options.allowIdAfter=false] - Whether to add an enum option for the new message id after the last message
|
||||
* @param {boolean} [options.allowVars=false] - Whether to add enum option for variable names
|
||||
* @returns {() => SlashCommandEnumValue[]}
|
||||
*/
|
||||
messages: ({ allowIdAfter = false, allowVars = false } = {}) => () => {
|
||||
return [
|
||||
...chat.map((message, index) => new SlashCommandEnumValue(String(index), `${message.name}: ${message.mes}`, enumTypes.number, message.is_user ? enumIcons.user : message.is_system ? enumIcons.system : enumIcons.assistant)),
|
||||
...allowIdAfter ? [new SlashCommandEnumValue(String(chat.length), '>> After Last Message >>', enumTypes.enum, '➕')] : [],
|
||||
...allowVars ? commonEnumProviders.variables('all')() : [],
|
||||
];
|
||||
},
|
||||
|
||||
/**
|
||||
* All existing worlds / lorebooks
|
||||
*
|
||||
* @returns {SlashCommandEnumValue[]}
|
||||
*/
|
||||
worlds: () => $('#world_info').children().toArray().map(x => new SlashCommandEnumValue(x.textContent, null, enumTypes.name, enumIcons.world)),
|
||||
|
||||
/**
|
||||
* All existing injects for the current chat
|
||||
*
|
||||
* @returns {SlashCommandEnumValue[]}
|
||||
*/
|
||||
injects: () => {
|
||||
if (!chat_metadata.script_injects || !Object.keys(chat_metadata.script_injects).length) return [];
|
||||
return Object.entries(chat_metadata.script_injects)
|
||||
.map(([id, inject]) => {
|
||||
const positionName = (Object.entries(extension_prompt_types)).find(([_, value]) => value === inject.position)?.[0] ?? 'unknown';
|
||||
return new SlashCommandEnumValue(id, `${enumIcons.getRoleIcon(inject.role ?? extension_prompt_roles.SYSTEM)}[Inject](${positionName}, depth: ${inject.depth}, scan: ${inject.scan ?? false}) ${inject.value}`,
|
||||
enumTypes.enum, '💉');
|
||||
});
|
||||
},
|
||||
};
|
@ -1,13 +1,63 @@
|
||||
|
||||
/**
|
||||
* @typedef {'enum' | 'command' | 'namedArgument' | 'variable' | 'qr' | 'macro' | 'number' | 'name'} EnumType
|
||||
*/
|
||||
|
||||
/**
|
||||
* Collection of the enum types that can be used with `SlashCommandEnumValue`
|
||||
*
|
||||
* Contains documentation on which color this will result to
|
||||
*/
|
||||
export const enumTypes = {
|
||||
/** 'enum' - [string] - light orange @type {EnumType} */
|
||||
enum: 'enum',
|
||||
/** 'command' - [cmd] - light yellow @type {EnumType} */
|
||||
command: 'command',
|
||||
/** 'namedArgument' - [argName] - sky blue @type {EnumType} */
|
||||
namedArgument: 'namedArgument',
|
||||
/** 'variable' - [punctuationL1] - pink @type {EnumType} */
|
||||
variable: 'variable',
|
||||
/** 'qr' - [variable] - light blue @type {EnumType} */
|
||||
qr: 'qr',
|
||||
/** 'macro' - [variableLanguage] - blue @type {EnumType} */
|
||||
macro: 'macro',
|
||||
/** 'number' - [number] - light green @type {EnumType} */
|
||||
number: 'number',
|
||||
/** 'name' - [type] - forest green @type {EnumType} */
|
||||
name: 'name',
|
||||
|
||||
/**
|
||||
* Gets the value of the enum type based on the provided index
|
||||
*
|
||||
* Can be used to get differing colors or even random colors, by providing the index of a unique set
|
||||
*
|
||||
* @param {number?} index - The index used to retrieve the enum type
|
||||
* @return {EnumType} The enum type corresponding to the index
|
||||
*/
|
||||
getBasedOnIndex(index) {
|
||||
const keys = Object.keys(this);
|
||||
return this[keys[(index ?? 0) % keys.length]];
|
||||
}
|
||||
}
|
||||
|
||||
export class SlashCommandEnumValue {
|
||||
/**@type {string}*/ value;
|
||||
/**@type {string}*/ description;
|
||||
/**@type {string}*/ type = 'enum';
|
||||
/**@type {EnumType}*/ type = 'enum';
|
||||
/**@type {string}*/ typeIcon = '◊';
|
||||
|
||||
/**
|
||||
* A constructor for creating a SlashCommandEnumValue instance.
|
||||
*
|
||||
* @param {string} value - The value
|
||||
* @param {string?} description - Optional description, displayed in a second line
|
||||
* @param {EnumType?} type - type of the enum (defining its color)
|
||||
* @param {string} typeIcon - The icon to display (Can be pulled from `enumIcons` for common ones)
|
||||
*/
|
||||
constructor(value, description = null, type = 'enum', typeIcon = '◊') {
|
||||
this.value = value;
|
||||
this.description = description;
|
||||
this.type = type;
|
||||
this.type = type ?? 'enum';
|
||||
this.typeIcon = typeIcon;
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,10 @@ import { SlashCommandAutoCompleteNameResult } from './SlashCommandAutoCompleteNa
|
||||
import { SlashCommandUnnamedArgumentAssignment } from './SlashCommandUnnamedArgumentAssignment.js';
|
||||
import { SlashCommandEnumValue } from './SlashCommandEnumValue.js';
|
||||
import { MacroAutoCompleteOption } from '../autocomplete/MacroAutoCompleteOption.js';
|
||||
import { commonEnumProviders } from './SlashCommandCommonEnumsProvider.js';
|
||||
|
||||
/** @typedef {import('./SlashCommand.js').NamedArgumentsCapture} NamedArgumentsCapture */
|
||||
/** @typedef {import('./SlashCommand.js').NamedArguments} NamedArguments */
|
||||
|
||||
/**@readonly*/
|
||||
/**@enum {Number}*/
|
||||
@ -32,7 +36,7 @@ export class SlashCommandParser {
|
||||
/**
|
||||
* @deprecated Use SlashCommandParser.addCommandObject() instead.
|
||||
* @param {string} command Command name
|
||||
* @param {(namedArguments:Object.<string,string|SlashCommandClosure>, unnamedArguments:string|SlashCommandClosure|(string|SlashCommandClosure)[])=>string|SlashCommandClosure|void|Promise<string|SlashCommandClosure|void>} callback The function to execute when the command is called
|
||||
* @param {(namedArguments:NamedArguments|NamedArgumentsCapture, unnamedArguments:string|SlashCommandClosure|(string|SlashCommandClosure)[])=>string|SlashCommandClosure|Promise<string|SlashCommandClosure>} callback callback The function to execute when the command is called
|
||||
* @param {string[]} aliases List of alternative command names
|
||||
* @param {string} helpString Help text shown in autocomplete and command browser
|
||||
*/
|
||||
@ -131,7 +135,7 @@ export class SlashCommandParser {
|
||||
description: 'The state of the parser flag to set.',
|
||||
typeList: [ARGUMENT_TYPE.BOOLEAN],
|
||||
defaultValue: 'on',
|
||||
enumList: ['on', 'off'],
|
||||
enumList: commonEnumProviders.boolean('onOff')(),
|
||||
}),
|
||||
],
|
||||
splitUnnamedArgument: true,
|
||||
|
@ -9,6 +9,8 @@ import {
|
||||
eventSource,
|
||||
event_types,
|
||||
DEFAULT_PRINT_TIMEOUT,
|
||||
substituteParams,
|
||||
printCharacters,
|
||||
} from '../script.js';
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
import { FILTER_TYPES, FILTER_STATES, DEFAULT_FILTER_STATE, isFilterState, FilterHelper } from './filters.js';
|
||||
@ -25,6 +27,7 @@ import { debounce_timeout } from './constants.js';
|
||||
import { INTERACTABLE_CONTROL_CLASS } from './keyboard.js';
|
||||
import { SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js';
|
||||
import { SlashCommandExecutor } from './slash-commands/SlashCommandExecutor.js';
|
||||
import { commonEnumProviders } from './slash-commands/SlashCommandCommonEnumsProvider.js';
|
||||
import { renderTemplateAsync } from './templates.js';
|
||||
|
||||
export {
|
||||
@ -491,6 +494,27 @@ export function getTagKeyForEntityElement(element) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the key for char/group by searching based on the name or avatar. If none can be found, a toastr will be shown and null returned.
|
||||
* This function is mostly used in slash commands.
|
||||
*
|
||||
* @param {string?} [charName] The optionally provided char name
|
||||
* @param {object} [options] - Optional arguments
|
||||
* @param {boolean} [options.suppressLogging=false] - Whether to suppress the toastr warning
|
||||
* @returns {string?} - The char/group key, or null if none found
|
||||
*/
|
||||
export function searchCharByName(charName, { suppressLogging = false } = {}) {
|
||||
const entity = charName
|
||||
? (characters.find(x => x.name === charName) || groups.find(x => x.name == charName))
|
||||
: (selected_group ? groups.find(x => x.id == selected_group) : characters[this_chid]);
|
||||
const key = getTagKeyForEntity(entity);
|
||||
if (!key) {
|
||||
if (!suppressLogging) toastr.warning(`Character ${charName} not found.`);
|
||||
return null;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds one or more tags to a given entity
|
||||
*
|
||||
@ -752,7 +776,7 @@ async function handleTagImport(character, { forceShow = false } = {}) {
|
||||
async function showTagImportPopup(character, existingTags, newTags, folderTags) {
|
||||
/** @type {{[key: string]: import('./popup.js').CustomPopupButton}} */
|
||||
const importButtons = {
|
||||
NONE: { result: 2, text: 'Import None', },
|
||||
NONE: { result: 2, text: 'Import None' },
|
||||
ALL: { result: 3, text: 'Import All' },
|
||||
EXISTING: { result: 4, text: 'Import Existing' },
|
||||
};
|
||||
@ -1768,22 +1792,6 @@ function printViewTagList(tagContainer, empty = true) {
|
||||
}
|
||||
|
||||
function registerTagsSlashCommands() {
|
||||
/**
|
||||
* Gets the key for char/group for a slash command. If none can be found, a toastr will be shown and null returned.
|
||||
* @param {string?} [charName] The optionally provided char name
|
||||
* @returns {string?} - The char/group key, or null if none found
|
||||
*/
|
||||
function paraGetCharKey(charName) {
|
||||
const entity = charName
|
||||
? (characters.find(x => x.name === charName) || groups.find(x => x.name == charName))
|
||||
: (selected_group ? groups.find(x => x.id == selected_group) : characters[this_chid]);
|
||||
const key = getTagKeyForEntity(entity);
|
||||
if (!key) {
|
||||
toastr.warning(`Character ${charName} not found.`);
|
||||
return null;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
/**
|
||||
* Gets a tag by its name. Optionally can create the tag if it does not exist.
|
||||
* @param {string} tagName - The name of the tag
|
||||
@ -1812,11 +1820,12 @@ function registerTagsSlashCommands() {
|
||||
returns: 'true/false - Whether the tag was added or was assigned already',
|
||||
/** @param {{name: string}} namedArgs @param {string} tagName @returns {string} */
|
||||
callback: ({ name }, tagName) => {
|
||||
const key = paraGetCharKey(name);
|
||||
const key = searchCharByName(name);
|
||||
if (!key) return 'false';
|
||||
const tag = paraGetTag(tagName, { allowCreate: true });
|
||||
if (!tag) return 'false';
|
||||
const result = addTagsToEntity(tag, key);
|
||||
printCharacters();
|
||||
return String(result);
|
||||
},
|
||||
namedArgumentList: [
|
||||
@ -1824,22 +1833,14 @@ function registerTagsSlashCommands() {
|
||||
description: 'Character name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
defaultValue: '{{char}}',
|
||||
enumProvider: ()=>[
|
||||
...characters.map(it=>new SlashCommandEnumValue(it.name, null, 'qr', 'C')),
|
||||
...groups.map(it=>new SlashCommandEnumValue(it.name, null, 'variable', 'G')),
|
||||
],
|
||||
enumProvider: commonEnumProviders.characters(),
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
SlashCommandArgument.fromProps({ description: 'tag name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: (executor)=>{
|
||||
const key = paraGetCharKey(/**@type {string}*/(executor.namedArgumentList.find(it=>it.name == 'name')?.value));
|
||||
if (!key) return tags.map(it=>new SlashCommandEnumValue(it.name, it.title));
|
||||
const assigned = getTagsList(key);
|
||||
return tags.filter(it=>!assigned.includes(it)).map(it=>new SlashCommandEnumValue(it.name, it.title));
|
||||
},
|
||||
enumProvider: commonEnumProviders.tagsForChar('not-existing'),
|
||||
forceEnum: false,
|
||||
}),
|
||||
],
|
||||
@ -1864,11 +1865,12 @@ function registerTagsSlashCommands() {
|
||||
returns: 'true/false - Whether the tag was removed or wasn\'t assigned already',
|
||||
/** @param {{name: string}} namedArgs @param {string} tagName @returns {string} */
|
||||
callback: ({ name }, tagName) => {
|
||||
const key = paraGetCharKey(name);
|
||||
const key = searchCharByName(name);
|
||||
if (!key) return 'false';
|
||||
const tag = paraGetTag(tagName);
|
||||
if (!tag) return 'false';
|
||||
const result = removeTagFromEntity(tag, key);
|
||||
printCharacters();
|
||||
return String(result);
|
||||
},
|
||||
namedArgumentList: [
|
||||
@ -1876,10 +1878,7 @@ function registerTagsSlashCommands() {
|
||||
description: 'Character name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
defaultValue: '{{char}}',
|
||||
enumProvider: ()=>[
|
||||
...characters.map(it=>new SlashCommandEnumValue(it.name, null, 'qr', 'C')),
|
||||
...groups.map(it=>new SlashCommandEnumValue(it.name, null, 'variable', 'G')),
|
||||
],
|
||||
enumProvider: commonEnumProviders.characters(),
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
@ -1887,11 +1886,7 @@ function registerTagsSlashCommands() {
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
/**@param {SlashCommandExecutor} executor */
|
||||
enumProvider: (executor)=>{
|
||||
const key = paraGetCharKey(/**@type {string}*/(executor.namedArgumentList.find(it=>it.name == 'name')?.value));
|
||||
if (!key) return tags.map(it=>new SlashCommandEnumValue(it.name, it.title));
|
||||
return getTagsList(key).map(it=>new SlashCommandEnumValue(it.name, it.title));
|
||||
},
|
||||
enumProvider: commonEnumProviders.tagsForChar('existing'),
|
||||
}),
|
||||
],
|
||||
helpString: `
|
||||
@ -1914,17 +1909,29 @@ function registerTagsSlashCommands() {
|
||||
returns: 'true/false - Whether the given tag name is assigned to the character',
|
||||
/** @param {{name: string}} namedArgs @param {string} tagName @returns {string} */
|
||||
callback: ({ name }, tagName) => {
|
||||
const key = paraGetCharKey(name);
|
||||
const key = searchCharByName(name);
|
||||
if (!key) return 'false';
|
||||
const tag = paraGetTag(tagName);
|
||||
if (!tag) return 'false';
|
||||
return String(tag_map[key].includes(tag.id));
|
||||
},
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument('name', 'Character name', [ARGUMENT_TYPE.STRING], false, false, '{{char}}'),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'name',
|
||||
description: 'Character name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
defaultValue: '{{char}}',
|
||||
enumProvider: commonEnumProviders.characters(),
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument('tag name', [ARGUMENT_TYPE.STRING], true),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'tag name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
/**@param {SlashCommandExecutor} executor */
|
||||
enumProvider: commonEnumProviders.tagsForChar('all'),
|
||||
}),
|
||||
],
|
||||
helpString: `
|
||||
<div>
|
||||
@ -1946,13 +1953,19 @@ function registerTagsSlashCommands() {
|
||||
returns: 'Comma-separated list of all assigned tags',
|
||||
/** @param {{name: string}} namedArgs @returns {string} */
|
||||
callback: ({ name }) => {
|
||||
const key = paraGetCharKey(name);
|
||||
const key = searchCharByName(name);
|
||||
if (!key) return '';
|
||||
const tags = getTagsList(key);
|
||||
return tags.map(x => x.name).join(', ');
|
||||
},
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument('name', 'Character name', [ARGUMENT_TYPE.STRING], false, false, '{{char}}'),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'name',
|
||||
description: 'Character name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
defaultValue: '{{char}}',
|
||||
enumProvider: commonEnumProviders.characters(),
|
||||
}),
|
||||
],
|
||||
helpString: `
|
||||
<div>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -13,6 +13,10 @@ import { getRegexedString, regex_placement } from './extensions/regex/engine.js'
|
||||
import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
|
||||
import { SlashCommand } from './slash-commands/SlashCommand.js';
|
||||
import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js';
|
||||
import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js';
|
||||
import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js';
|
||||
import { SlashCommandExecutor } from './slash-commands/SlashCommandExecutor.js';
|
||||
import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js';
|
||||
|
||||
export {
|
||||
world_info,
|
||||
@ -962,21 +966,56 @@ function registerWorldInfoSlashCommands() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/** A collection of local enum providers for this context of world info */
|
||||
const localEnumProviders = {
|
||||
/** All possible fields that can be set in a WI entry */
|
||||
wiEntryFields: () => Object.entries(newEntryDefinition).map(([key, value]) =>
|
||||
new SlashCommandEnumValue(key, `[${value.type}] default: ${(typeof value.default === 'string' ? `'${value.default}'` : value.default)}`,
|
||||
enumTypes.enum, enumIcons.getDataTypeIcon(value.type))),
|
||||
|
||||
/** All existing UIDs based on the file argument as world name */
|
||||
wiUids: (/** @type {SlashCommandExecutor} */ executor) => {
|
||||
const file = executor.namedArgumentList.find(it => it.name == 'file')?.value;
|
||||
if (file instanceof SlashCommandClosure) throw new Error('Argument \'file\' does not support closures');
|
||||
// Try find world from cache
|
||||
const world = worldInfoCache[file];
|
||||
if (!world) return [];
|
||||
return Object.entries(world.entries).map(([uid, data]) =>
|
||||
new SlashCommandEnumValue(uid, `${data.comment ? `${data.comment}: ` : ''}${data.key.join(', ')}${data.keysecondary?.length ? ` [${Object.entries(world_info_logic).find(([_, value]) => value == data.selectiveLogic)[0]}] ${data.keysecondary.join(', ')}` : ''} [${getWiPositionString(data)}]`,
|
||||
enumTypes.enum, enumIcons.getWiStatusIcon(data)));
|
||||
},
|
||||
};
|
||||
|
||||
function getWiPositionString(entry) {
|
||||
switch (entry.position) {
|
||||
case world_info_position.before: return '↑Char';
|
||||
case world_info_position.after: return '↓Char';
|
||||
case world_info_position.EMTop: return '↑EM';
|
||||
case world_info_position.EMBottom: return '↓EM';
|
||||
case world_info_position.ANTop: return '↑AT';
|
||||
case world_info_position.ANBottom: return '↓AT';
|
||||
case world_info_position.atDepth: return `@D${enumIcons.getRoleIcon(entry.role)}`;
|
||||
default: return '<Unknown>';
|
||||
}
|
||||
}
|
||||
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'world',
|
||||
callback: onWorldInfoChange,
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument(
|
||||
'state', 'set world state', [ARGUMENT_TYPE.STRING], false, false, null, ['off', 'toggle'],
|
||||
'state', 'set world state', [ARGUMENT_TYPE.STRING], false, false, null, commonEnumProviders.boolean('onOffToggle')(),
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'silent', 'suppress toast messages', [ARGUMENT_TYPE.BOOLEAN], false,
|
||||
),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'name', [ARGUMENT_TYPE.STRING], false,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'world name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
enumProvider: commonEnumProviders.worlds,
|
||||
}),
|
||||
],
|
||||
helpString: `
|
||||
<div>
|
||||
@ -992,18 +1031,27 @@ function registerWorldInfoSlashCommands() {
|
||||
helpString: 'Get a name of the chat-bound lorebook or create a new one if was unbound, and pass it down the pipe.',
|
||||
aliases: ['getchatlore', 'getchatwi'],
|
||||
}));
|
||||
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'findentry',
|
||||
aliases: ['findlore', 'findwi'],
|
||||
returns: 'UID',
|
||||
callback: findBookEntryCallback,
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument(
|
||||
'file', 'bookName', ARGUMENT_TYPE.STRING, true,
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'field', 'field value for fuzzy match (default: key)', ARGUMENT_TYPE.STRING, false, false, 'key',
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'file',
|
||||
description: 'book name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: commonEnumProviders.worlds,
|
||||
}),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'field',
|
||||
description: 'field value for fuzzy match (default: key)',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
defaultValue: 'key',
|
||||
enumList: localEnumProviders.wiEntryFields(),
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
@ -1030,17 +1078,28 @@ function registerWorldInfoSlashCommands() {
|
||||
callback: getEntryFieldCallback,
|
||||
returns: 'field value',
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument(
|
||||
'file', 'bookName', ARGUMENT_TYPE.STRING, true,
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'field', 'field to retrieve (default: content)', ARGUMENT_TYPE.STRING, false, false, 'content',
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'file',
|
||||
description: 'book name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: commonEnumProviders.worlds,
|
||||
}),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'field',
|
||||
description: 'field to retrieve (default: content)',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
defaultValue: 'content',
|
||||
enumList: localEnumProviders.wiEntryFields(),
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
'UID', ARGUMENT_TYPE.STRING, true,
|
||||
),
|
||||
SlashCommandArgument.fromProps({
|
||||
description: 'record UID',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: localEnumProviders.wiUids,
|
||||
}),
|
||||
],
|
||||
helpString: `
|
||||
<div>
|
||||
@ -1062,9 +1121,13 @@ function registerWorldInfoSlashCommands() {
|
||||
aliases: ['createlore', 'createwi'],
|
||||
returns: 'UID of the new record',
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument(
|
||||
'file', 'book name', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'file',
|
||||
description: 'book name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: commonEnumProviders.worlds,
|
||||
}),
|
||||
new SlashCommandNamedArgument(
|
||||
'key', 'record key', [ARGUMENT_TYPE.STRING], false,
|
||||
),
|
||||
@ -1093,15 +1156,27 @@ function registerWorldInfoSlashCommands() {
|
||||
callback: setEntryFieldCallback,
|
||||
aliases: ['setlorefield', 'setwifield'],
|
||||
namedArgumentList: [
|
||||
new SlashCommandNamedArgument(
|
||||
'file', 'book name', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'uid', 'record UID', [ARGUMENT_TYPE.STRING], true,
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'field', 'field name', [ARGUMENT_TYPE.STRING], true, false, 'content',
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'file',
|
||||
description: 'book name',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: commonEnumProviders.worlds,
|
||||
}),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'uid',
|
||||
description: 'record UID',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
isRequired: true,
|
||||
enumProvider: localEnumProviders.wiUids,
|
||||
}),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'field',
|
||||
description: 'field name (default: content)',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
defaultValue: 'content',
|
||||
enumList: localEnumProviders.wiEntryFields(),
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
@ -2748,38 +2823,49 @@ function deleteWorldInfoEntry(data, uid) {
|
||||
delete data.entries[uid];
|
||||
}
|
||||
|
||||
const newEntryTemplate = {
|
||||
key: [],
|
||||
keysecondary: [],
|
||||
comment: '',
|
||||
content: '',
|
||||
constant: false,
|
||||
vectorized: false,
|
||||
selective: true,
|
||||
selectiveLogic: world_info_logic.AND_ANY,
|
||||
addMemo: false,
|
||||
order: 100,
|
||||
position: 0,
|
||||
disable: false,
|
||||
excludeRecursion: false,
|
||||
preventRecursion: false,
|
||||
delayUntilRecursion: false,
|
||||
probability: 100,
|
||||
useProbability: true,
|
||||
depth: DEFAULT_DEPTH,
|
||||
group: '',
|
||||
groupOverride: false,
|
||||
groupWeight: DEFAULT_WEIGHT,
|
||||
scanDepth: null,
|
||||
caseSensitive: null,
|
||||
matchWholeWords: null,
|
||||
useGroupScoring: null,
|
||||
automationId: '',
|
||||
role: 0,
|
||||
sticky: null,
|
||||
cooldown: null,
|
||||
/**
|
||||
* Definitions of types for new WI entries
|
||||
*
|
||||
* Use `newEntryTemplate` if you just need the template that contains default values
|
||||
*
|
||||
* @type {{[key: string]: { default: any, type: string }}}
|
||||
*/
|
||||
const newEntryDefinition = {
|
||||
key: { default: [], type: 'array' },
|
||||
keysecondary: { default: [], type: 'array' },
|
||||
comment: { default: '', type: 'string' },
|
||||
content: { default: '', type: 'string' },
|
||||
constant: { default: false, type: 'boolean' },
|
||||
vectorized: { default: false, type: 'boolean' },
|
||||
selective: { default: true, type: 'boolean' },
|
||||
selectiveLogic: { default: world_info_logic.AND_ANY, type: 'enum' },
|
||||
addMemo: { default: false, type: 'boolean' },
|
||||
order: { default: 100, type: 'number' },
|
||||
position: { default: 0, type: 'number' },
|
||||
disable: { default: false, type: 'boolean' },
|
||||
excludeRecursion: { default: false, type: 'boolean' },
|
||||
preventRecursion: { default: false, type: 'boolean' },
|
||||
delayUntilRecursion: { default: false, type: 'boolean' },
|
||||
probability: { default: 100, type: 'number' },
|
||||
useProbability: { default: true, type: 'boolean' },
|
||||
depth: { default: DEFAULT_DEPTH, type: 'number' },
|
||||
group: { default: '', type: 'string' },
|
||||
groupOverride: { default: false, type: 'boolean' },
|
||||
groupWeight: { default: DEFAULT_WEIGHT, type: 'number' },
|
||||
scanDepth: { default: null, type: 'number?' },
|
||||
caseSensitive: { default: null, type: 'boolean?' },
|
||||
matchWholeWords: { default: null, type: 'boolean?' },
|
||||
useGroupScoring: { default: null, type: 'boolean?' },
|
||||
automationId: { default: '', type: 'string' },
|
||||
role: { default: 0, type: 'enum' },
|
||||
sticky: { default: null, type: 'number?' },
|
||||
cooldown: { default: null, type: 'number?' },
|
||||
};
|
||||
|
||||
const newEntryTemplate = Object.fromEntries(
|
||||
Object.entries(newEntryDefinition).map(([key, value]) => [key, value.default]),
|
||||
);
|
||||
|
||||
function createWorldInfoEntry(_name, data) {
|
||||
const newUid = getFreeWorldEntryUid(data);
|
||||
|
||||
@ -3829,6 +3915,7 @@ function onWorldInfoChange(args, text) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'on':
|
||||
default: {
|
||||
selected_world_info.push(name);
|
||||
wiElement.prop('selected', true);
|
||||
|
123
public/style.css
123
public/style.css
@ -366,16 +366,6 @@ input[type='checkbox']:focus-visible {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.img_enlarged_container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
padding: 10px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.img_enlarged_container pre code,
|
||||
.mes_text pre code {
|
||||
position: relative;
|
||||
display: block;
|
||||
@ -1521,6 +1511,14 @@ body[data-stscript-style] .autoComplete [data-option-type] {
|
||||
&[data-option-type="macro"] .type {
|
||||
color: var(--ac-color-variableLanguage);
|
||||
}
|
||||
|
||||
&[data-option-type="number"] .type {
|
||||
color: var(--ac-color-number);
|
||||
}
|
||||
|
||||
&[data-option-type="name"] .type {
|
||||
color: var(--ac-color-type);
|
||||
}
|
||||
}
|
||||
|
||||
body[data-stscript-style] .hljs.language-stscript {
|
||||
@ -1630,6 +1628,11 @@ body[data-stscript-style] .hljs.language-stscript {
|
||||
gap: 0.5em;
|
||||
display: contents;
|
||||
|
||||
>.stopgap {
|
||||
opacity: 0.75;
|
||||
display: none;
|
||||
}
|
||||
|
||||
@container (max-width: 80em) {
|
||||
.specs {
|
||||
grid-column: 2 / 4;
|
||||
@ -1641,6 +1644,10 @@ body[data-stscript-style] .hljs.language-stscript {
|
||||
opacity: 0.75;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
>.stopgap {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
&.blank {
|
||||
@ -3144,6 +3151,16 @@ grammarly-extension {
|
||||
min-width: 750px;
|
||||
}
|
||||
|
||||
.transparent_dialogue_popup {
|
||||
background-color: transparent;
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.transparent_dialogue_popup:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#dialogue_popup .horizontal_scrolling_dialogue_popup {
|
||||
overflow-x: unset !important;
|
||||
}
|
||||
@ -4457,38 +4474,106 @@ a {
|
||||
|
||||
.mes_img_controls {
|
||||
position: absolute;
|
||||
top: 0.5em;
|
||||
top: 0.1em;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
display: none;
|
||||
display: flex;
|
||||
opacity: 0;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.mes_img_controls .right_menu_button {
|
||||
padding: 0;
|
||||
filter: brightness(80%);
|
||||
padding: 1px;
|
||||
height: 1.25em;
|
||||
width: 1.25em;
|
||||
}
|
||||
|
||||
.mes_img_controls .right_menu_button::before {
|
||||
/* Fix weird alignment with this font-awesome icons on focus */
|
||||
position: relative;
|
||||
top: 0.6125em;
|
||||
}
|
||||
|
||||
.mes_img_controls .right_menu_button:hover {
|
||||
filter: brightness(150%);
|
||||
}
|
||||
|
||||
.mes_img_container:hover .mes_img_controls {
|
||||
display: flex;
|
||||
.mes_img_container:hover .mes_img_controls,
|
||||
.mes_img_container:focus-within .mes_img_controls {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.mes .mes_img_container.img_extra {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.img_enlarged_holder {
|
||||
/* Scaling via flex-grow and object-fit only works if we have some kind of base-height set */
|
||||
min-height: 120px;
|
||||
}
|
||||
|
||||
.img_enlarged_holder:has(.zoomed) {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.img_enlarged {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
border-radius: 2px;
|
||||
border: 1px solid transparent;
|
||||
object-fit: contain;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: zoom-in
|
||||
}
|
||||
|
||||
.img_enlarged.zoomed {
|
||||
object-fit: cover;
|
||||
width: auto;
|
||||
height: auto;
|
||||
cursor: zoom-out;
|
||||
}
|
||||
|
||||
.img_enlarged_container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding: 10px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.img_enlarged_holder::-webkit-scrollbar-corner {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.img_enlarged_container pre code {
|
||||
position: relative;
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.popup:has(.img_enlarged.zoomed).large_dialogue_popup {
|
||||
height: 100vh !important;
|
||||
height: 100svh !important;
|
||||
max-height: 100vh !important;
|
||||
max-height: 100svh !important;
|
||||
max-width: 100vw !important;
|
||||
max-width: 100svw !important;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.popup:has(.img_enlarged.zoomed).large_dialogue_popup .popup-content {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.popup:has(.img_enlarged.zoomed).large_dialogue_popup .img_enlarged_container pre {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.popup:has(.img_enlarged.zoomed).large_dialogue_popup .popup-button-close {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.cropper-container {
|
||||
|
Loading…
x
Reference in New Issue
Block a user