diff --git a/css/styles.css b/css/styles.css
index f4c22d5..fceddde 100644
--- a/css/styles.css
+++ b/css/styles.css
@@ -7,6 +7,10 @@ thead {
border-bottom: 3px solid black;
}
+thead th {
+ position: relative;
+}
+
tbody tr:nth-child(even) {
background-color: #ededed;
}
@@ -15,10 +19,10 @@ tbody tr:nth-child(odd) {
background-color: #f6f6f6;
}
-thead tr th:has(+th[class="formula"]),
-tbody tr th:last-of-type,
-thead tr th[class="formula"]:has(+th),
-tbody tr td:first-of-type:has(+td) {
+thead th:has(+th[class="formula"]),
+tbody th:last-of-type,
+thead th[class="formula"]:has(+th),
+tbody td:first-of-type:has(+td) {
border-right: 3px solid black;
}
@@ -26,7 +30,7 @@ thead .formula-input-wrapper input {
width: 8rem !important;
}
-tbody .formula-input-wrapper input {
+tbody input {
width: 3.5rem !important;
text-align: center;
}
@@ -36,6 +40,20 @@ td, th {
padding: 0.5rem;
height: 3.5rem;
text-align: center;
+ min-width: 5rem;
+}
+
+thead th button {
+ position: absolute;
+ top: 0;
+ right: 0;
+ border-top: none;
+ border-right: none;
+ border-left: 1px solid black;
+ border-bottom: 1px solid black;
+ background: transparent;
+ cursor: pointer;
+ font-size: 12px;
}
.bit, .variable {
diff --git a/templates/formulation.xhtml.j2 b/templates/formulation.xhtml.j2
index 2cc6388..4efb22f 100644
--- a/templates/formulation.xhtml.j2
+++ b/templates/formulation.xhtml.j2
@@ -23,10 +23,7 @@
-
-
-
-
+
|
{% endfor %}
diff --git a/ts/.prettierignore b/ts/.prettierignore
index bf6669f..cebbe43 100644
--- a/ts/.prettierignore
+++ b/ts/.prettierignore
@@ -1 +1 @@
-ts/parser/generated/**/*
+src/parser/generated/**/*
diff --git a/ts/src/formula_input_element.ts b/ts/src/formula_input_element.ts
index 7acb2dc..61374f6 100644
--- a/ts/src/formula_input_element.ts
+++ b/ts/src/formula_input_element.ts
@@ -125,8 +125,6 @@ export class FormulaInput {
this.#inputElement.addEventListener("input", () => {
this.setInputValidity("valid");
});
-
- this.#displayElement.addEventListener("click", () => this.viewInputField());
}
}
diff --git a/ts/src/intermediate_formulas.ts b/ts/src/intermediate_formulas.ts
index 42e4898..c2de5dc 100644
--- a/ts/src/intermediate_formulas.ts
+++ b/ts/src/intermediate_formulas.ts
@@ -1,8 +1,47 @@
import { OutputFormat } from "./parser/parser";
-import { createFormulaInput, type FormulaInput } from "./formula_input_element";
+import { createFormulaInput } from "./formula_input_element";
const tableElement = document.querySelector("table")!;
+function createIntermediateFormulaHeader(
+ formula: string,
+ formulaId: number,
+ format: OutputFormat,
+ data: Record,
+ enabled: boolean,
+): HTMLTableCellElement {
+ const cellElement = document.createElement("th");
+
+ const formulaInput = createFormulaInput(formula, format, enabled);
+ cellElement.appendChild(formulaInput.element);
+
+ if (enabled) {
+ formulaInput.inputElement.addEventListener("change", () => {
+ const formulas = (data["intermediate-formulas"] ?? {}) as Record;
+ formulas[formulaId] = formulaInput.getInput();
+ data["intermediate-formulas"] = formulas;
+ });
+
+ const editButton = document.createElement("button");
+ editButton.tabIndex = -1;
+ editButton.innerHTML = "✏️";
+
+ editButton.addEventListener("mousedown", (e) => {
+ // This prevents the edit button to trigger the blur event of the input element.
+ e.preventDefault();
+ });
+
+ editButton.addEventListener("click", (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ formulaInput.viewInputField();
+ });
+ cellElement.appendChild(editButton);
+ }
+
+ return cellElement;
+}
+
export function setupButtonToAddIntermediateFormula(attempt: object, total_rows: number, format: OutputFormat) {
// @ts-expect-error Attempt object definition is not here.
const data = attempt.data as Record;
@@ -15,31 +54,22 @@ export function setupButtonToAddIntermediateFormula(attempt: object, total_rows:
const rows = tableElement.querySelectorAll("tr");
for (const [index, row] of rows.entries()) {
- let cellElement, intermediateFormulaInput;
+ let cellElement;
if (index === 0) {
// The first row of the table contains the formulas.
- cellElement = document.createElement("th");
- intermediateFormulaInput = createIntermediateFormulaInput(
+ cellElement = createIntermediateFormulaHeader(
"",
intermediateFormulaId,
format,
- true,
data,
+ // @ts-expect-error Attempt object definition is not here.
+ !attempt.readOnly,
);
initValues(data, intermediateFormulaId, total_rows);
} else {
- cellElement = document.createElement("td");
- intermediateFormulaInput = createIntermediateResultInput(
- "",
- intermediateFormulaId,
- index - 1,
- format,
- true,
- data,
- );
+ cellElement = createIntermediateResultInput("", intermediateFormulaId, index - 1, true, data);
}
- cellElement.appendChild(intermediateFormulaInput.element);
row.appendChild(cellElement);
}
@@ -58,7 +88,7 @@ function initValues(data: Record, intermediateFormulaId: number
data["intermediate-results"] = intermediateResults;
}
-export function viewExistingIntermediateFormulas(format: OutputFormat, attempt: object) {
+export function initIntermediateFormulas(format: OutputFormat, attempt: object) {
// @ts-expect-error Attempt object definition is not here.
const data = attempt.data as Record;
// @ts-expect-error Attempt object definition is not here.
@@ -69,83 +99,58 @@ export function viewExistingIntermediateFormulas(format: OutputFormat, attempt:
const rows = tableElement.querySelectorAll("tr");
for (const [intermediateFormulaId, intermediateFormula] of Object.entries(intermediateFormulas)) {
- const cellElement = document.createElement("th");
- const intermediateFormulaInput = createIntermediateFormulaInput(
+ const cellElement = createIntermediateFormulaHeader(
intermediateFormula,
parseInt(intermediateFormulaId),
format,
- isActive,
data,
+ isActive,
);
- cellElement.appendChild(intermediateFormulaInput.element);
rows[0].appendChild(cellElement);
for (const [index, intermediateResult] of Object.entries(intermediateResults[intermediateFormulaId])) {
- const cellElement = document.createElement("td");
- const intermediateResultInput = createIntermediateResultInput(
+ const cellElement = createIntermediateResultInput(
intermediateResult,
parseInt(intermediateFormulaId),
parseInt(index),
- format,
isActive,
data,
);
- cellElement.appendChild(intermediateResultInput.element);
rows[parseInt(index) + 1].appendChild(cellElement);
}
}
}
-function createIntermediateFormulaInput(
- formula: string,
- intermediateFormulaId: number,
- format: OutputFormat,
- enabled: boolean,
- data: Record,
-): FormulaInput {
- const formulaInputElement = createFormulaInput(formula, format, enabled);
- formulaInputElement.inputElement.setAttribute("data-intermediate-formula", `${intermediateFormulaId}`);
-
- const intermediateFormulas = (data["intermediate-formulas"] ?? {}) as Record;
-
- if (enabled) {
- formulaInputElement.inputElement.addEventListener("change", () => {
- const formulaId = formulaInputElement.inputElement.getAttribute("data-intermediate-formula")!;
- intermediateFormulas[formulaId] = formulaInputElement.getInput();
- data["intermediate-formulas"] = intermediateFormulas;
- });
- }
-
- return formulaInputElement;
-}
-
function createIntermediateResultInput(
formula: string,
intermediateFormulaId: number,
row: number,
- format: OutputFormat,
enabled: boolean,
data: Record,
-): FormulaInput {
- const resultInputElement = createFormulaInput(formula, format, enabled);
- resultInputElement.inputElement.maxLength = 1;
- resultInputElement.inputElement.pattern = "0|1";
- resultInputElement.inputElement.setAttribute("data-intermediate-result", `${row}`);
- resultInputElement.inputElement.setAttribute("data-intermediate-result-belongs-to", `${intermediateFormulaId}`);
+): HTMLTableCellElement {
+ const cellElement = document.createElement("td");
+ // Create the input element for the result.
+ const resultInputElement = document.createElement("input");
+ resultInputElement.value = formula;
+ resultInputElement.maxLength = 1;
+ resultInputElement.pattern = "0|1";
+ resultInputElement.disabled = !enabled;
const intermediateResults = (data["intermediate-results"] ?? {}) as Record;
if (enabled) {
- resultInputElement.inputElement.addEventListener("change", () => {
- const resultId = parseInt(resultInputElement.inputElement.getAttribute("data-intermediate-result")!);
- const belongsToFormulaId = resultInputElement.inputElement.getAttribute(
- "data-intermediate-result-belongs-to",
- )!;
-
- intermediateResults[belongsToFormulaId][resultId] = resultInputElement.getInput();
+ resultInputElement.addEventListener("change", () => {
+ intermediateResults[intermediateFormulaId][row] = resultInputElement.value;
data["intermediate-results"] = intermediateResults;
});
+
+ resultInputElement.addEventListener("keydown", (event) => {
+ if (event.key === "Enter") {
+ event.preventDefault();
+ }
+ });
}
- return resultInputElement;
+ cellElement.appendChild(resultInputElement);
+ return cellElement;
}
diff --git a/ts/src/main.ts b/ts/src/main.ts
index d15de8b..953fa0a 100644
--- a/ts/src/main.ts
+++ b/ts/src/main.ts
@@ -1,12 +1,10 @@
import { type OutputFormat } from "./parser/parser.js";
import { renderBora } from "./utils";
-import { FormulaInput } from "./formula_input_element";
-import { setupButtonToAddIntermediateFormula, viewExistingIntermediateFormulas } from "./intermediate_formulas";
+import { initIntermediateFormulas, setupButtonToAddIntermediateFormula } from "./intermediate_formulas";
export function init(attempt: object, [format, total_rows]: [OutputFormat, number]) {
initFormulaElements(format);
- initFormulaInputElements(format, attempt);
- viewExistingIntermediateFormulas(format, attempt);
+ initIntermediateFormulas(format, attempt);
// @ts-expect-error Attempt object definition is not here.
if (!attempt.readOnly) {
setupButtonToAddIntermediateFormula(attempt, total_rows, format);
@@ -18,14 +16,13 @@ function initFormulaElements(format: OutputFormat) {
for (const formulaElement of formulaElements) {
renderBora(formulaElement.textContent!, formulaElement, format);
}
-}
-function initFormulaInputElements(format: OutputFormat, attempt: object) {
- const wrapperElements: NodeListOf = document.querySelectorAll(".formula-input-wrapper");
- for (const wrapperElement of wrapperElements) {
- const inputElement: HTMLInputElement = wrapperElement.querySelector(".formula-input")!;
- const displayElement: HTMLSpanElement = wrapperElement.querySelector(".formula-display")!;
- // @ts-expect-error Attempt object definition is not here.
- new FormulaInput(wrapperElement, inputElement, displayElement, format, !attempt.readOnly);
+ const formulaInputElements = document.querySelectorAll(".formula-input") as NodeListOf;
+ for (const formulaInputElement of formulaInputElements) {
+ formulaInputElement.addEventListener("keydown", (event) => {
+ if (event.key === "Enter") {
+ event.preventDefault();
+ }
+ });
}
}
diff --git a/ts/src/mathjax/base.ts b/ts/src/mathjax/base.ts
index 882c20b..4608811 100644
--- a/ts/src/mathjax/base.ts
+++ b/ts/src/mathjax/base.ts
@@ -24,7 +24,7 @@ export abstract class BaseMathJaxHelper {
return this.loadPromise;
}
- return this.loadPromise = new Promise((resolve, reject) => {
+ return (this.loadPromise = new Promise((resolve, reject) => {
const script = document.createElement("script");
script.type = "text/javascript";
script.src = this.cdnUrl;
@@ -40,7 +40,7 @@ export abstract class BaseMathJaxHelper {
script.onerror = () => reject(new Error(`Failed to load ${this.cdnUrl}.`));
document.head.appendChild(script);
- });
+ }));
}
/**
diff --git a/ts/src/mathjax/index.ts b/ts/src/mathjax/index.ts
index 2720710..01aaf6e 100644
--- a/ts/src/mathjax/index.ts
+++ b/ts/src/mathjax/index.ts
@@ -25,7 +25,7 @@ export function renderLaTeX(element: Element, inline: boolean = true): Promise {
// We need to manually chain every render call.
// https://docs.mathjax.org/en/v3.2/web/typeset.html#handling-asynchronous-typesetting
- return this.queue = this.queue.then(() => {
+ return (this.queue = this.queue.then(() => {
// Get the delimiters.
const inlineDelimiters = this.mathjax.config.tex?.inlineMath?.[0] ?? ["\\(", "\\)"];
const displayDelimiters = this.mathjax.config.tex?.displayMath?.[0] ?? ["\\[", "\\]"];
@@ -48,6 +48,6 @@ export class MathJax3Helper extends BaseMathJaxHelper {
// Perform the rendering.
return this.mathjax.typesetPromise([element]);
- });
+ }));
}
}
diff --git a/ts/src/mathjax/v4.ts b/ts/src/mathjax/v4.ts
index b6a6c13..c6845f1 100644
--- a/ts/src/mathjax/v4.ts
+++ b/ts/src/mathjax/v4.ts
@@ -41,6 +41,6 @@ export class MathJax4Helper extends BaseMathJaxHelper {
// Add the delimiters.
element.textContent = `${openingDelimiter} ${element.textContent} ${closingDelimiter}`;
- return this.mathjax.typesetPromise([element])
+ return this.mathjax.typesetPromise([element]);
}
}