diff --git a/classes/message.d.ts b/classes/message.d.ts index 1efdb16..fa7113c 100644 --- a/classes/message.d.ts +++ b/classes/message.d.ts @@ -32,28 +32,28 @@ export default class Message { /** * Responds to the message - * @param text - The text to respond (to the message) with + * @param text The text to respond (to the message) with * @returns A promise that resolves when the message is sent successfully */ reply(text: string): Promise; /** * Privately responds to the message - * @param text - The text to privately respond (to the message) with + * @param text The text to privately respond (to the message) with */ privateReply(text: string): void; /** * Sends HTML in the message context (chatroom for 'chat', PMs for 'pm') - * @param html - The HTML to send - * @param opts - An instance of HTMLopts (name/rank/change) + * @param html The HTML to send + * @param opts HTML options. If a string is passed, it is used as HTMLopts.name. */ - sendHTML(html: any, opts?: HTMLopts): boolean; + sendHTML(html: any, opts?: HTMLopts | string): boolean; /** * Privately sends HTML in the message context (chatroom for 'chat', PMs for 'pm') - * @param html - The HTML to send - * @param opts - An instance of HTMLopts (name/rank/change) + * @param html The HTML to send + * @param opts HTML options. If a string is passed, it is used as HTMLopts.name. */ - replyHTML(html: any, opts?: HTMLopts): boolean; + replyHTML(html: any, opts?: HTMLopts | string): boolean; } diff --git a/classes/room.d.ts b/classes/room.d.ts index 036ea03..77b362f 100644 --- a/classes/room.d.ts +++ b/classes/room.d.ts @@ -5,30 +5,30 @@ import type User from './user.d.ts'; export default class Room { /** - * Formatted name of the room + * Formatted name of the room. * @example Bot Development */ title: string; /** - * Room ID + * Room ID. * @example botdevelopment */ roomid: string; /** - * Room ID + * Room ID. * @example botdevelopment */ id: string; /** - * The Bot that this room is registered to + * The Bot that this room is registered to. */ parent: Client; /** - * Whether the room is a chatroom or a battleroom + * Whether the room is a chatroom or a battleroom. */ type: 'chat' | 'battle'; /** - * Room visibility + * Room visibility. */ visibility: 'public' | 'secret'; /** @@ -36,12 +36,12 @@ export default class Room { */ modchat?: string; /** - * Can be undefined if no auth is defined in the room + * Can be undefined if no auth is defined in the room. * @example { '*': ['partbot'] } */ auth?: { [key: string]: string[] }; /** - * List of all users currently online, formatted as shown in chat + * List of all users currently online, formatted as shown in chat. * @example ['#PartMan@!', '*PartBot'] */ users: string[]; @@ -49,51 +49,59 @@ export default class Room { constructor(name: string, parent: Client); /** - * Sends a message to the room - * @param text - The text to send + * Sends a message to the room. + * @param text The text to send * @returns A promise that resolves when the message is sent successfully */ send(text: string): Promise; /** - * Privately sends a message to a user in the room - * @param user - The user to send the text to - * @param text - The text to privately send + * Privately sends a message to a user in the room. + * @param user The user to send the text to + * @param text The text to privately send */ privateSend(user: User | string, text: string): string | false; /** - * Sends HTML in the room - * @param html - The HTML to send - * @param opts - An instance of HTMLopts (name/rank/change) + * Sends HTML in the room. + * @param html The HTML to send + * @param opts HTML options. If a string is passed, it is used as HTMLopts.name. */ - sendHTML(html: any, opts?: HTMLopts): string | false; + sendHTML(html: any, opts?: HTMLopts | string): string | false; /** * Privately sends HTML in the room - * @param user - The user to send the HTML to - * @param html - The HTML to send - * @param opts - An instance of HTMLopts (name/rank/change) + * @param user The user to send the HTML to + * @param html The HTML to send + * @param opts HTML options. If a string is passed, it is used as HTMLopts.name. */ - privateHTML(user: User | string | (User | string)[], html: any, opts?: HTMLopts): string | false; + privateHTML(user: User | string | (User | string)[], html: any, opts?: HTMLopts | string): string | false; /** - * Alias for User#sendHTML() that passes opts.room - * @param user - The user to send the HTML to - * @param html - The HTML to send - * @param opts - An instance of HTMLopts (name/rank/change) + * Sends HTML pages to multiple users from the room. + * @param user The user to send the HTML to + * @param html The HTML to send + * @param opts HTML options. If a string is passed, it is used as HTMLopts.name. */ - pmHTML(user: User | string, html: any, opts?: HTMLopts): string | false; + pageHTML(user: User | string | (User | string)[], html: any, opts?: HTMLopts | string): string | false; /** - * Waits for the first message in the room that fulfills the given condition - * @param condition - A function to run on the message. Return a truthy value to satisfy - * @param time - The time (in ms) to wait before rejecting as a timeout + * Alias for User#sendHTML() that passes opts.room. + * @param user The user to send the HTML to + * @param html The HTML to send + * @param opts HTML options. If a string is passed, it is used as HTMLopts.name. + */ + pmHTML(user: User | string, html: any, opts?: HTMLopts | string): string | false; + + /** + * Waits for the first message in the room that fulfills the given condition. + * @param condition A function to run on the message. Return a truthy value to satisfy + * @param time The time (in ms) to wait before rejecting as a timeout */ waitFor(condition: (message: Message) => boolean, time?: number): Promise; /** - * Re-fetch the room's details from the server + * Re-fetch the room's details from the server. */ update(): void; } diff --git a/classes/room.js b/classes/room.js index d5a2daf..de951ee 100644 --- a/classes/room.js +++ b/classes/room.js @@ -45,10 +45,23 @@ class Room { const fallbackName = this.parent.status.username + Date.now().toString(36); const formatted = opts.notransform ? html : this.parent.opts.transformHTML(html, opts); const command = `${opts.change ? 'change' : 'send'}privateuhtml`; - this.send(`/${command} ${userList.map(user => user.userid).join('|')}, ${opts.name ?? fallbackName}, ${formatted}`); + this.send(`/${command} ${users.map(user => user.userid).join('|')}, ${opts.name ?? fallbackName}, ${formatted}`); + return formatted; + } + pageHTML(userList, html, opts = {}) { + if (!['*', '#', '&'].includes(this.users.find(u => toID(u) === this.parent.status.userid)?.charAt(0))) return false; + const users = (Array.isArray(userList) ? userList : [userList]).map(user => this.parent.getUser(user)); + if (!users.length) return false; + if (!html) throw new Error('Missing HTML argument'); + if (typeof opts === 'string') opts = { name: opts }; + if (!opts || typeof opts !== 'object') throw new TypeError('Options must be an object'); + const fallbackName = this.parent.status.username + Date.now().toString(36); + const formatted = opts.notransform ? html : this.parent.opts.transformHTML(html, opts); + this.send(`/sendhtmlpage ${users.map(user => user.userid).join('|')}, ${opts.name ?? fallbackName}, ${formatted}`); return formatted; } pmHTML(user, html, opts = {}) { + if (typeof opts === 'string') opts = { name: opts }; user = this.parent.getUser(user); return user?.sendHTML(html, { ...opts, room: this }); } diff --git a/classes/user.d.ts b/classes/user.d.ts index 4c14b12..5fbffb7 100644 --- a/classes/user.d.ts +++ b/classes/user.d.ts @@ -61,16 +61,16 @@ export default class User { /** * Sends HTML to the user * @param html The HTML to send - * @param opts HTML options + * @param opts HTML options. If a string is passed, it is used as HTMLopts.name. */ - sendHTML(html: any, opts?: HTMLopts): string; + sendHTML(html: any, opts?: HTMLopts | string): string; /** * Sends an HTML page to the user * @param html The HTML to send - * @param opts HTML options + * @param opts HTML options. If a string is passed, it is used as HTMLopts.name. */ - pageHTML(html: any, opts?: HTMLopts): string; + pageHTML(html: any, opts?: HTMLopts | string): string; /** * Waits for the first message in the room that fulfills the given condition diff --git a/classes/user.js b/classes/user.js index 2c6267a..9482e11 100644 --- a/classes/user.js +++ b/classes/user.js @@ -9,18 +9,10 @@ class User { this._waits = []; this.alts = new Set(); } - send(text) { - const user = this; - return new Promise(function (resolve, reject) { - text = `|/pm ${user.userid},${text?.toString() || String(text)}`; - user.parent.sendQueue(text, resolve, reject); - }); - } - sendHTML(html, opts = {}) { - if (!html) throw new Error('Missing HTML argument'); + #validateHTML(opts = {}) { if (typeof opts === 'string') opts = { name: opts }; if (!opts || typeof opts !== 'object') throw new TypeError('Options must be an object'); - if (!opts.name) opts.name = this.parent.status.username + Date.now().toString(36); + const fallbackName = this.parent.status.username + Date.now().toString(36); let room; if (opts.room) room = typeof opts.room === 'string' ? this.parent.getRoom(opts.room) : opts.room; else { @@ -31,24 +23,26 @@ class User { } room = rooms.public || rooms.hidden || rooms.secret || rooms.private; } + return { opts: opts.name ? opts : { ...opts, name: fallbackName }, room }; + } + send(text) { + const user = this; + return new Promise(function (resolve, reject) { + text = `|/pm ${user.userid},${text?.toString() || String(text)}`; + user.parent.sendQueue(text, resolve, reject); + }); + } + sendHTML(html, _opts = {}) { + if (!html) throw new Error('Missing HTML argument'); + const { opts, room } = this.#validateHTML(_opts); if (!room) return false; const formatted = opts.notransform ? html : this.parent.opts.transformHTML(html, opts); room.send(`/pmuhtml${opts.change ? 'change' : ''} ${this.userid}, ${opts.name}, ${formatted}`); return formatted; } - pageHTML(html, opts = {}) { + pageHTML(html, _opts = {}) { if (!html) throw new Error('Missing HTML argument'); - if (!opts.name) opts.name = this.parent.status.username + Date.now().toString(36); - let room; - if (opts.room) room = typeof opts.room === 'string' ? this.parent.getRoom(opts.room) : opts.room; - else { - const rooms = {}; - for (const room of this.parent.rooms.values()) { - if (room.auth?.['*']?.includes(this.parent.status.userid) || room.auth?.['#']?.includes(this.parent.status.userid)) - rooms[room.visibility] = room; - } - room = rooms.public || rooms.hidden || rooms.secret || rooms.private; - } + const { opts, room } = this.#validateHTML(_opts); if (!room) return false; const formatted = opts.notransform ? html : this.parent.opts.transformHTML(html, opts); room.send(`/sendhtmlpage ${this.userid}, ${opts.name}, ${formatted}`);