From d2b14dbe942ce5ef2d67b005f83a3b6e8a6f7865 Mon Sep 17 00:00:00 2001 From: trotFunky Date: Wed, 11 Jun 2025 18:48:44 +0100 Subject: [PATCH] Dialog: Provide hints for the sender name The dialog form has a simple text input for the sender's name. This can lead to typos or mistakes if the GM wants to send a message using the same sender name as a previous message. Add a new function that goes through all the players' histories and compiles a list of all unique senders, which we can then use to build a list of hints that will be used to show suggestions when the GM fills the sender name in the form. This is currently quite ineficcient as it re-does all the work for every single dialog. A better way would be to cache it or store it explicitly somewhere when we send a message, but this would require a way for the GM to edit it. --- README.md | 2 ++ scripts/send_dialog_form.mjs | 37 ++++++++++++++++++++++++++++++++++++ scripts/utils.mjs | 25 ++++++++++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/README.md b/README.md index ae2fb53..7f15a8e 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,8 @@ each page containing the messages from one specific recipient. Both the journals and pages will be created automatically. Players only have observer permissions on their own journal, which will take the name of their character, or their own if they don't control one yet. +If the history is enabled, the message form will go look for previous senders' names and provide +a list for autocompletion. The GM can send a message to an offline player, which will add it to its history if it is enabled, but won't show up as a pop-up when they next log in. diff --git a/scripts/send_dialog_form.mjs b/scripts/send_dialog_form.mjs index 4083ea0..4ff787f 100644 --- a/scripts/send_dialog_form.mjs +++ b/scripts/send_dialog_form.mjs @@ -3,6 +3,10 @@ * so they can be used in the main module. */ +import { get_existing_senders } from "./utils.mjs"; + +const sender_hints_id = "sender_hints" + /** * @typedef {Object} MessageFormResponse * @property {string[]} recipients The list of player IDs the message will be sent to @@ -16,6 +20,23 @@ * @property {MessageFormResponse} form_response The response form the dialog form */ +/** + * Generate the HTML for a whose options are the provided senders. + * @param {String} hints_id The ID to use for the providing the hints + * @param {String[]} senders The list of existing senders, or an empty string if invalid. + */ +function generate_sender_hints(hints_id, senders) { + // Both arguments need to be usable to generate something useful. + if (!hints_id || !senders || senders.length === 0) { + return ""; + } + let sender_hints_html = `` + for (let sender of senders) { + sender_hints_html += `"; +} + /** * Given that "required" does not seem to have much impact, check that everything * has been properly filled. @@ -88,6 +109,22 @@ export function prepare_send_message_html(existing_values = null, chain = false) localize: true }) + /* + * If we can find previous senders in player's histories, create a datalist + * with them so that the names can appear as autocompletion when filling the form. + */ + /* + * TODO: This is very silly : it re-computes everything for every form that is opened. + * Find a way to cache it or store the senders list it explicitly rather than deduce it + * from the history. + */ + let existing_senders = get_existing_senders(); + if (existing_senders.length > 0) { + sender_input.setAttribute("list", sender_hints_id) + // This keeps the datalist withing the input group as proper HTML. + sender_group.insertAdjacentHTML("beforeend", generate_sender_hints(sender_hints_id, existing_senders)) + } + const message_input = foundry.applications.elements.HTMLProseMirrorElement.create({ name: "message", required: true, diff --git a/scripts/utils.mjs b/scripts/utils.mjs index 2504c28..109c0ea 100644 --- a/scripts/utils.mjs +++ b/scripts/utils.mjs @@ -50,3 +50,28 @@ export async function create_history_journal(user) { return user.setFlag(module_id, history_flag, journal.id).then(() => journal); }); } + +/** + * Go through all the user's histories to build a list of existing senders, + * so that they can be displayed or re-used. + * The final list is sorted and does not contain duplicates, as one sender + * can send messages to multiple players at once. + * @returns {String[]} A sorted array of the sender names, if any + */ +export function get_existing_senders() { + /** @type {String[]} */ + let senders = [] + for (let user of game.users.players) { + /** @type {JournalEntry} */ + let history = game.journal.get(user.getFlag(module_id, history_flag)) + if (!history) { + continue; + } + for (let page of history.pages) { + if (!senders.includes(page.name)) { + senders.push(page.name); + } + } + } + return senders.sort(); +}