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.
This commit is contained in:
trotFunky 2025-06-11 18:48:44 +01:00
parent 30c0324799
commit d2b14dbe94
3 changed files with 64 additions and 0 deletions

View file

@ -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 <datalist> whose options are the provided senders.
* @param {String} hints_id The ID to use for the <datalist> 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 = `<datalist id="${hints_id}">`
for (let sender of senders) {
sender_hints_html += `<option value="${sender}">`;
}
return sender_hints_html + "</datalist>";
}
/**
* 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,

View file

@ -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();
}