downgrade target from ES2022 to ES6 for better compatibility with older browsers

main
Inga 🏳‍🌈 1 week ago
parent 7393819e8b
commit d808cebd81
  1. 15
      README.md
  2. 22
      src/frontend/components/board-game.ts
  3. 12
      src/frontend/components/progressive-form.ts
  4. 3
      tsconfig.json

@ -287,12 +287,17 @@ None.
## Supported browser engines ## Supported browser engines
* Gecko (Firefox): works in v132, both with JS enabled (offline mode) and with JS disabled (plain old client-server mode). * Gecko (Firefox): works in v132, both with JS enabled (offline mode) and with JS disabled (plain old client-server mode).
* Blink (e.g. Chromium and Chromium-based browsers): not checked, should work in reasonably recent versions, Should work in offline mode starting with Firefox 63 (2018); should work in plain old client-server mode in all versions,
both with JS enabled (offline mode) and with JS disabled (plain old client-server mode). although the design in Firefox 51 (2017) and older will probably not look very good due to the lack of the recent CSS features.
* Blink (e.g. Chromium and Chromium-based browsers): superficially checked in Chromium 130, basic functionality seems to work.
Should work in offline mode starting with Chrome 67 (2018); should work in plain old client-server mode in all versions,
although the design in Chrome 56 (2017) and older will probably not look very good due to the lack of the recent CSS features.
* WebKit (e.g. qutebrowser and notably Safari): not checked; should **not** work in offline mode, * WebKit (e.g. qutebrowser and notably Safari): not checked; should **not** work in offline mode,
because WebKit does not fully implement decade-old standard which Gecko and Blink supported since 2018: because WebKit does not fully implement decade-old standard which Gecko and Blink supported since 2018:
https://github.com/WebKit/standards-positions/issues/97. https://github.com/WebKit/standards-positions/issues/97.
Everything should still work in online mode, falling back on client-server communication. Everything should still work in online mode, falling back on client-server communication,
except that the design in Safari before 10.1 (2017) will not look very good (but will still be functional),
and will probably become disfunctional in Safari before 3.1 (2008).
* Servo: checked, does **not** work in nightly as of 2024-11-20, and I don't have an opportunity to figure out why * Servo: checked, does **not** work in nightly as of 2024-11-20, and I don't have an opportunity to figure out why
(it's not packaged for Alpine (...yet), their regular Linux builds don't work on Alpine, (it's not packaged for Alpine (...yet), their regular Linux builds don't work on Alpine,
so I had to check it on someone else's Windows machine). so I had to check it on someone else's Windows machine).
@ -315,10 +320,6 @@ None.
* Implement error handling and handling of incorrect / malformed game states (since they come from the client). * Implement error handling and handling of incorrect / malformed game states (since they come from the client).
* Improve UI for large boards (disable autoplayers when board is too large, * Improve UI for large boards (disable autoplayers when board is too large,
hide "enable autoplayer" buttons, provide clear indication to the user instead). hide "enable autoplayer" buttons, provide clear indication to the user instead).
* Target older ES versions on the frontend,
so that offline-only game can work in all browsers fully supporting Web Components
(i.e. Blink-based and Firefox not older than 2018);
right now ES2022 is targeted.
* Figure out better API for game board, * Figure out better API for game board,
`board.get(row, column)` and `board.get(row, column)` seemed to be a good way to encapsulate readonly state, `board.get(row, column)` and `board.get(row, column)` seemed to be a good way to encapsulate readonly state,
but they became very inconvenient as the codebase grew and became more complex, but they became very inconvenient as the codebase grew and became more complex,

@ -24,20 +24,20 @@ export class BoardGameComponent extends HTMLElement {
return; return;
} }
for (const playerNameElement of this.querySelectorAll(".current-player-name")) { this.querySelectorAll(".current-player-name").forEach((playerNameElement) => {
if ((playerNameElement as HTMLElement).innerText !== gameState.currentPlayerName) { if ((playerNameElement as HTMLElement).innerText !== gameState.currentPlayerName) {
(playerNameElement as HTMLElement).innerText = gameState.currentPlayerName; (playerNameElement as HTMLElement).innerText = gameState.currentPlayerName;
} }
} });
const buttonValues = getButtonValues(gameState); const buttonValues = getButtonValues(gameState);
for (const button of this.querySelectorAll("button")) { this.querySelectorAll("button").forEach((button) => {
for (const className of button.classList) { button.classList.forEach((className) => {
if (Object.hasOwn(buttonValues, className)) { if (Object.prototype.hasOwnProperty.call(buttonValues, className)) {
button.value = buttonValues[className as keyof ButtonValues].serialize(); button.value = buttonValues[className as keyof ButtonValues].serialize();
} }
} });
} });
const currentOutcome = gameState.board ? rules.getBoardOutcome(gameState.board) : CurrentOutcome.Undecided; const currentOutcome = gameState.board ? rules.getBoardOutcome(gameState.board) : CurrentOutcome.Undecided;
@ -46,7 +46,7 @@ export class BoardGameComponent extends HTMLElement {
this.classList.toggle(className, shouldEnable); this.classList.toggle(className, shouldEnable);
} }
for (const tbodyUntyped of this.querySelectorAll("tbody.game-board")) { this.querySelectorAll("tbody.game-board").forEach((tbodyUntyped) => {
const tbody = tbodyUntyped as HTMLTableSectionElement; const tbody = tbodyUntyped as HTMLTableSectionElement;
while (gameState.rows < tbody.rows.length) { while (gameState.rows < tbody.rows.length) {
@ -90,7 +90,7 @@ export class BoardGameComponent extends HTMLElement {
row: rowNumber, row: rowNumber,
column: columnNumber, column: columnNumber,
}); });
for (const button of cell.querySelectorAll("button")) { cell.querySelectorAll("button").forEach((button) => {
button.value = nextGameState.serialize(); button.value = nextGameState.serialize();
if (button.disabled !== isDisabled) { if (button.disabled !== isDisabled) {
button.disabled = isDisabled; button.disabled = isDisabled;
@ -101,10 +101,10 @@ export class BoardGameComponent extends HTMLElement {
if (button.className !== className) { if (button.className !== className) {
button.className = className; button.className = className;
} }
});
} }
} }
} });
}
} }
connectedCallback() { connectedCallback() {

@ -1,8 +1,18 @@
import { goToLocation } from "../utils/navigation-utils.ts"; import { goToLocation } from "../utils/navigation-utils.ts";
import { updateWithQueryParams } from "../utils/url-utils.ts"; import { updateWithQueryParams } from "../utils/url-utils.ts";
// Needed for backwards compatibility with browsers that predate FormData as iterator
const getFormDataEntries = (formData: FormData) => {
const result: [string, FormDataEntryValue][] = [];
formData.forEach((value, key) => {
result.push([key, value]);
});
return result;
};
const submitListener = function (this: HTMLFormElement, e: SubmitEvent) { const submitListener = function (this: HTMLFormElement, e: SubmitEvent) {
goToLocation(updateWithQueryParams(new URL(this.action), new FormData(this, e.submitter))); goToLocation(updateWithQueryParams(new URL(this.action), getFormDataEntries(new FormData(this, e.submitter))));
e.preventDefault(); e.preventDefault();
}; };

@ -6,8 +6,9 @@
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"jsx": "react-jsx", "jsx": "react-jsx",
"jsxImportSource": "preact", "jsxImportSource": "preact",
"lib": ["DOM", "ES6"],
"module": "NodeNext", "module": "NodeNext",
"noEmit": true, "noEmit": true,
"target": "ES2022" "target": "ES6"
} }
} }

Loading…
Cancel
Save