errors for invalid option values

This commit is contained in:
MathMan05
2025-10-27 11:43:54 -05:00
parent c36d2c2cd4
commit 35f90d71d9
5 changed files with 83 additions and 36 deletions
+2 -1
View File
@@ -1583,7 +1583,8 @@ class Channel extends SnowFlake {
curWatch = () => {};
async submitCommand() {
if (!this.curCommand) return;
if (await this.curCommand.submit(this)) {
const typebox = document.getElementById("typebox") as CustomHTMLDivElement;
if (await this.curCommand.submit(typebox, this)) {
this.curCommand = undefined;
const typebox = document.getElementById("typebox") as CustomHTMLDivElement;
typebox.markdown.boxEnabled = true;
+1 -1
View File
@@ -67,7 +67,7 @@ class I18n {
//thanks to geotale for the regex
msg = msg.replace(/\$\d+/g, (match) => {
const number = Number(match.slice(1));
if (params[number - 1]) {
if (params[number - 1] !== undefined) {
return params[number - 1];
} else {
return match;
+50 -32
View File
@@ -4,6 +4,7 @@ import {I18n} from "../i18n.js";
import {commandJson, commandOptionJson} from "../jsontypes.js";
import {Localuser} from "../localuser.js";
import {SnowFlake} from "../snowflake.js";
import {removeAni} from "../utils/utils.js";
function focusInput(html: HTMLElement) {
const input = html.getElementsByTagName("input")[0];
if (input) input.focus();
@@ -250,38 +251,50 @@ export class Command extends SnowFlake {
return this.owner.headers;
}
async submit(channel: Channel) {
const nonce = Math.floor(Math.random() * 10 ** 9) + "";
const states = this.state.get(channel);
if (!states) {
return true;
}
const opts = states.filter((_) => typeof _ !== "string");
async submit(html: HTMLElement, channel: Channel) {
try {
const nonce = Math.floor(Math.random() * 10 ** 9) + "";
const states = this.state.get(channel);
if (!states) {
return true;
}
const opts = states.filter((_) => typeof _ !== "string");
await fetch(this.info.api + "/interactions", {
method: "POST",
headers: this.headers,
body: JSON.stringify({
type: 2,
nonce: nonce,
guild_id: channel.owner.id,
channel_id: channel.id,
application_id: this.applicationId,
session_id: this.localuser.session_id,
data: {
application_command: this.rawJson,
attachments: [],
id: this.id,
name: this.name,
options: opts.map(({option, state}) => {
return option.toJson(state);
}),
type: 1,
version: this.version,
},
}),
});
this.state.delete(channel);
await fetch(this.info.api + "/interactions", {
method: "POST",
headers: this.headers,
body: JSON.stringify({
type: 2,
nonce: nonce,
guild_id: channel.owner.id,
channel_id: channel.id,
application_id: this.applicationId,
session_id: this.localuser.session_id,
data: {
application_command: this.rawJson,
attachments: [],
id: this.id,
name: this.name,
options: opts.map(({option, state}) => {
return option.toJson(state);
}),
type: 1,
version: this.version,
},
}),
});
this.state.delete(channel);
} catch (e) {
if (e instanceof OptionError) {
const message = e.message;
const error = document.createElement("span");
error.classList.add("commandError");
error.textContent = message;
html.parentElement?.append(error);
removeAni(error, 25000);
}
return false;
}
return true;
}
}
@@ -364,6 +377,11 @@ class ErrorOption extends Option {
return span;
}
}
class OptionError extends Error {
constructor(reason: string) {
super(reason);
}
}
class StringOption extends Option {
minLeng: number;
maxLeng: number;
@@ -471,7 +489,7 @@ class StringOption extends Option {
if (choice) {
return choice.value;
}
throw new Error(I18n.commands.errorNotValid(state, this.localizedName));
throw new OptionError(I18n.commands.errorNotValid(state || '""', this.localizedName));
}
return state;
}
+28
View File
@@ -1142,6 +1142,31 @@ textarea {
display: none;
}
}
.commandError {
position: absolute;
top: -36px;
left: 34px;
z-index: 1;
background: var(--red);
padding: 6px;
border-radius: 4px;
&.removeElm {
animation-duration: 10s;
animation-name: errorElm;
animation-fill-mode: forwards;
animation-timing-function: ease-in-out;
}
}
@keyframes errorElm {
100%,
0% {
opacity: 0;
}
5%,
95% {
opacity: 1;
}
}
/* Animations */
@keyframes fade {
0%,
@@ -1978,6 +2003,7 @@ span.instanceStatus {
border-radius: 4px;
}
#typebox {
position: relative;
margin: -10px 0px;
flex-grow: 1;
width: 1px;
@@ -2003,6 +2029,7 @@ span.instanceStatus {
border-radius: 4px;
display: flex;
flex-direction: row;
position: relative;
}
.searchBox:empty {
@@ -4349,6 +4376,7 @@ img.error::after {
}
}
}
#sentdms .groupDmDiv {
background: transparent;
width: 48px;
+2 -2
View File
@@ -665,12 +665,12 @@ async function isAnimated(src: string) {
return src.endsWith(".apng") || src.endsWith(".gif");
}
const staticImgMap = new Map<string, string | Promise<string>>();
export async function removeAni(elm: HTMLElement) {
export async function removeAni(elm: HTMLElement, time = 500) {
elm.classList.add("removeElm");
const ani = elm.getAnimations();
await Promise.race([
Promise.all(ani.map((_) => _.finished)),
new Promise<void>((res) => setTimeout(res, 500)),
new Promise<void>((res) => setTimeout(res, time)),
]);
elm.remove();
}