diff --git a/public/script.js b/public/script.js index ceeb5f7b3..5da35d80f 100644 --- a/public/script.js +++ b/public/script.js @@ -2405,19 +2405,27 @@ async function processCommands(message, abortController) { deactivateSendButtons(); is_send_press = true; + /**@type {HTMLTextAreaElement}*/ const ta = document.querySelector('#send_textarea'); ta.value = ''; ta.dispatchEvent(new Event('input', { bubbles:true })); await executeSlashCommandsWithOptions(message, { abortController: abortController, + onProgress: (done, total)=>ta.style.setProperty('--prog', `${done / total * 100}%`), }); + delay(1000).then(()=>clearCommandProgressDebounced()); is_send_press = false; activateSendButtons(); return true; } +function clearCommandProgress() { + if (is_send_press) return; + document.querySelector('#send_textarea').style.setProperty('--prog', '0%'); +} +const clearCommandProgressDebounced = debounce(clearCommandProgress); function sendSystemMessage(type, text, extra = {}) { const systemMessage = system_messages[type]; diff --git a/public/scripts/RossAscends-mods.js b/public/scripts/RossAscends-mods.js index 04d556fa4..cb73279eb 100644 --- a/public/scripts/RossAscends-mods.js +++ b/public/scripts/RossAscends-mods.js @@ -700,7 +700,7 @@ const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1; */ function autoFitSendTextArea() { const originalScrollBottom = chatBlock.scrollHeight - (chatBlock.scrollTop + chatBlock.offsetHeight); - if (sendTextArea.scrollHeight == sendTextArea.offsetHeight) { + if (sendTextArea.scrollHeight + 2 == sendTextArea.offsetHeight) { // Needs to be pulled dynamically because it is affected by font size changes const sendTextAreaMinHeight = window.getComputedStyle(sendTextArea).getPropertyValue('min-height'); sendTextArea.style.height = sendTextAreaMinHeight; diff --git a/public/scripts/slash-commands.js b/public/scripts/slash-commands.js index dcd43d0be..3cc8858bc 100644 --- a/public/scripts/slash-commands.js +++ b/public/scripts/slash-commands.js @@ -2557,6 +2557,7 @@ function modelCallback(_, model) { * @param {boolean} [options.handleExecutionErrors] * @param {PARSER_FLAG[]} [options.parserFlags] * @param {AbortController} [options.abortController] + * @param {(done:number, total:number)=>void} [options.onProgress] * @returns {Promise} */ async function executeSlashCommandsWithOptions(text, options = {}) { @@ -2567,6 +2568,7 @@ async function executeSlashCommandsWithOptions(text, options = {}) { options.handleExecutionErrors ?? false, options.parserFlags ?? null, options.abortController ?? null, + options.onProgress ?? null, ); } /** @@ -2579,7 +2581,7 @@ async function executeSlashCommandsWithOptions(text, options = {}) { * @param {AbortController} abortController * @returns {Promise} */ -async function executeSlashCommands(text, handleParserErrors = true, scope = null, handleExecutionErrors = false, parserFlags = null, abortController = null) { +async function executeSlashCommands(text, handleParserErrors = true, scope = null, handleExecutionErrors = false, parserFlags = null, abortController = null, onProgress = null) { if (!text) { return null; } @@ -2588,6 +2590,7 @@ async function executeSlashCommands(text, handleParserErrors = true, scope = nul try { closure = parser.parse(text, true, parserFlags, abortController); closure.scope.parent = scope; + closure.onProgress = onProgress; } catch (e) { if (handleParserErrors && e instanceof SlashCommandParserError) { /**@type {SlashCommandParserError}*/ diff --git a/public/scripts/slash-commands/SlashCommandClosure.js b/public/scripts/slash-commands/SlashCommandClosure.js index a0c94b185..5ebdd1873 100644 --- a/public/scripts/slash-commands/SlashCommandClosure.js +++ b/public/scripts/slash-commands/SlashCommandClosure.js @@ -15,6 +15,7 @@ export class SlashCommandClosure { /**@type {SlashCommandExecutor[]}*/ executorList = []; /**@type {string}*/ keptText; /**@type {AbortController}*/ abortController; + /**@type {(done:number, total:number)=>void}*/ onProgress; constructor(parent) { this.scope = new SlashCommandScope(parent); @@ -79,6 +80,7 @@ export class SlashCommandClosure { closure.executorList = this.executorList; closure.keptText = this.keptText; closure.abortController = this.abortController; + closure.onProgress = this.onProgress; return closure; } @@ -142,7 +144,10 @@ export class SlashCommandClosure { this.scope.setVariable(key, v); } + let done = 0; for (const executor of this.executorList) { + done += 0.5; + this.onProgress?.(done, this.executorList.length); if (executor instanceof SlashCommandClosureExecutor) { const closure = this.scope.getVariable(executor.name); if (!closure || !(closure instanceof SlashCommandClosure)) throw new Error(`${executor.name} is not a closure.`); @@ -233,6 +238,8 @@ export class SlashCommandClosure { return abortResult; } this.scope.pipe = await executor.command.callback(args, value ?? ''); + done += 0.5; + this.onProgress?.(done, this.executorList.length); // eslint-disable-next-line no-cond-assign if (abortResult = this.testAbortController()) { return abortResult; diff --git a/public/style.css b/public/style.css index 3c9e274f5..7951973c0 100644 --- a/public/style.css +++ b/public/style.css @@ -1062,6 +1062,13 @@ select { text-shadow: 0px 0px calc(var(--shadowWidth) * 1px) var(--SmartThemeShadowColor); flex: 1; order: 3; + + --progColor: rgba(0, 128, 0, 0.839); + --progWidth: 3px; + --prog: 0%; + border-top: var(--progWidth) solid var(--progColor); + clip-path: polygon(0% 0%, var(--prog) 0%, var(--prog) 5px, 100% 5px, 100% 100%, 0% 100%); + transition: clip-path 200ms; } .slashCommandAutoComplete-wrap {