Generalise abstract Table: rename generic to TRow, add docs

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
CentreMetre
2026-06-14 17:28:57 +01:00
parent 026de5987b
commit d7c2851008

View File

@@ -43,6 +43,13 @@ export abstract class Table<TRow extends Object> {
this.messageEl = messageElement === undefined ? document.createElement("p") : messageElement; this.messageEl = messageElement === undefined ? document.createElement("p") : messageElement;
} }
/**
* Creates the table headers from the provided example object and the headers orders and names if provided (otherwise inferred)
* @param exampleObject An example object of TRow, e.g. User = { id: 0, name: "Name"}. Used to store the types for each column.
* @param displayNamesAndOrder The order and names of the columns on the table.
* e.g. User = { fullname: "Full Name", id: "User ID" }, the headers would be "Full Name" and "User ID" in column order and headers,
* @return A array of {@link Header<TRow>} type shape that holds the header/column info.
*/
createHeadersFromType( createHeadersFromType(
exampleObject: TRow, // Needed for runtime, since types don't exist in JS. exampleObject: TRow, // Needed for runtime, since types don't exist in JS.
displayNamesAndOrder?: Record<keyof TRow, string> displayNamesAndOrder?: Record<keyof TRow, string>
@@ -59,6 +66,9 @@ export abstract class Table<TRow extends Object> {
})); }));
} }
/**
* Sets the header values on the header row from the {@link headers} object on this object.
*/
setHeaderRow() { setHeaderRow() {
const thead = document.createElement("thead"); const thead = document.createElement("thead");
const headerRow = document.createElement("tr"); const headerRow = document.createElement("tr");
@@ -73,13 +83,15 @@ export abstract class Table<TRow extends Object> {
this.table.appendChild(thead); this.table.appendChild(thead);
} }
/** /**
* Loads the CSS for tables into the html file for proper styling. * Loads the CSS for tables into the html file for custom styling.
* @param relativePathAndName The path to go to for the cess file, including the filename and extension.
*/ */
loadCSS() { loadCSS(relativePathAndName: string) {
const link = document.createElement("link"); const link = document.createElement("link");
link.rel = "stylesheet" link.rel = "stylesheet"
link.href = "../css/table.css"; // Relative path from JS folder. link.href = relativePathAndName;
link.type = 'text/css'; link.type = 'text/css';
document.head.appendChild(link); document.head.appendChild(link);
} }
@@ -100,6 +112,10 @@ export abstract class Table<TRow extends Object> {
this.tableBody.appendChild(row) this.tableBody.appendChild(row)
} }
/**
* Appends multiple rows to the table, at the end off the table.
* @param data The rows to append to the table, in shape of {@link TRow}.
*/
appendRows(data: TRow[]): void { appendRows(data: TRow[]): void {
if (data.length === 0) { if (data.length === 0) {
this.setMessage("No data to append. Empty list provided.") this.setMessage("No data to append. Empty list provided.")
@@ -177,20 +193,35 @@ export abstract class Table<TRow extends Object> {
this.appendRows(data) this.appendRows(data)
} }
getMessageElement() { /**
* Get the message element for the table.
* @return The HTMLElement thats used for showing messaged. Or null if its not set.
*/
getMessageElement(): HTMLElement | null {
return this.messageEl; return this.messageEl;
} }
/**
* Clears the {@link messageEl}.textContent value to "". If the message element is not set it does nothing.
*/
clearMessage() { clearMessage() {
if (!this.messageEl) return; if (!this.messageEl) return;
this.messageEl.textContent = "" this.messageEl.textContent = ""
} }
/**
* Appends a message to the alread existing table message, if the message element is set. Works even if current message is empty ("").
* @param message The message to append to the current message.
*/
appendMessage(message: string) { appendMessage(message: string) {
if (!this.messageEl) return; if (!this.messageEl) return;
this.messageEl.textContent = `${this.messageEl.textContent} ${message}` this.messageEl.textContent = `${this.messageEl.textContent} ${message}`
} }
/**
* Sets the message, overwriting what it was before. Id the message element is not set, it does nothing.
* @param message The message to set the message element to.
*/
setMessage(message: string) { setMessage(message: string) {
if (!this.messageEl) return; if (!this.messageEl) return;
this.clearMessage(); this.clearMessage();
@@ -198,8 +229,8 @@ export abstract class Table<TRow extends Object> {
} }
} }
type Header<R> = { type Header<TRow> = {
key: keyof R; // The name of the field. key: keyof TRow; // The name of the field.
value: string; // The name of the header cell value: string; // The name of the header cell
type: string; // The type of the field, can be string since typesof are returned as strings. type: string; // The type of the field, can be string since typesof are returned as strings.
} }