162 lines
4.6 KiB
JavaScript
162 lines
4.6 KiB
JavaScript
import { FIGHTER, SPAWN } from "../constants.js";
|
|
|
|
const STORAGE_KEYS = {
|
|
names: "arena.match.playerNames",
|
|
spawnPlacement: "arena.match.spawnPlacement",
|
|
};
|
|
|
|
export function createMatchForm() {
|
|
const form = getElement("#fighter-form");
|
|
const namesInput = getElement("#player-names");
|
|
const namesWarningNode = getElement("#player-names-warning");
|
|
const namesWarningTitleNode = getElement("[data-player-names-warning-title]");
|
|
const namesWarningCountNode = getElement("[data-player-names-warning-count]");
|
|
const namesWarningLimitNode = getElement("[data-player-names-warning-limit]");
|
|
const namesWarningReasonNode = getElement("[data-player-names-warning-reason]");
|
|
const appNode = document.querySelector("#app");
|
|
const statusNode = document.querySelector("#match-status");
|
|
const statusTextNodes = document.querySelectorAll("[data-status-text]");
|
|
const spawnPlacementInputs = getElements('input[name="spawnPlacement"]');
|
|
const setPlayerNamesWarning = (warning = null) => {
|
|
const hasWarning = Boolean(warning);
|
|
|
|
if (!hasWarning) {
|
|
namesWarningNode.hidden = true;
|
|
namesInput.removeAttribute("aria-invalid");
|
|
return;
|
|
}
|
|
|
|
namesWarningTitleNode.textContent = warning.title;
|
|
namesWarningCountNode.textContent = warning.fighterCount.toLocaleString("ko-KR");
|
|
namesWarningLimitNode.textContent = warning.maxFighterCount.toLocaleString("ko-KR");
|
|
namesWarningReasonNode.textContent = warning.reason ?? "";
|
|
namesWarningReasonNode.hidden = !warning.reason;
|
|
namesWarningNode.hidden = false;
|
|
namesInput.setAttribute("aria-invalid", "true");
|
|
};
|
|
|
|
const readMatchConfig = () => ({
|
|
names: nicknameValues(namesInput.value),
|
|
spawnPlacement: selectedSpawnPlacement(spawnPlacementInputs),
|
|
});
|
|
|
|
restoreSavedMatchSettings(namesInput, spawnPlacementInputs);
|
|
namesInput.addEventListener("input", () => {
|
|
setPlayerNamesWarning();
|
|
saveMatchSettings(namesInput, spawnPlacementInputs);
|
|
});
|
|
spawnPlacementInputs.forEach((input) => {
|
|
input.addEventListener("change", () => {
|
|
saveMatchSettings(namesInput, spawnPlacementInputs);
|
|
});
|
|
});
|
|
|
|
return {
|
|
onSubmit(handler) {
|
|
form.addEventListener("submit", (event) => {
|
|
event.preventDefault();
|
|
handler(readMatchConfig());
|
|
});
|
|
},
|
|
readMatchConfig,
|
|
setPlayerNamesWarning,
|
|
setStatus(message) {
|
|
if (statusNode) {
|
|
statusNode.setAttribute("aria-hidden", "false");
|
|
statusNode.title = message;
|
|
}
|
|
|
|
statusTextNodes.forEach((node) => {
|
|
node.textContent = message;
|
|
});
|
|
|
|
appNode?.classList.add("status-active");
|
|
},
|
|
};
|
|
}
|
|
|
|
function getElement(selector) {
|
|
const element = document.querySelector(selector);
|
|
|
|
if (!element) {
|
|
throw new Error(`Missing required element: ${selector}`);
|
|
}
|
|
|
|
return element;
|
|
}
|
|
|
|
function getElements(selector) {
|
|
const elements = [...document.querySelectorAll(selector)];
|
|
|
|
if (elements.length === 0) {
|
|
throw new Error(`Missing required elements: ${selector}`);
|
|
}
|
|
|
|
return elements;
|
|
}
|
|
|
|
function nicknameValues(value) {
|
|
return value
|
|
.split(/\r?\n|,/)
|
|
.map((name) => name.trim().slice(0, FIGHTER.NICKNAME_LENGTH))
|
|
.filter(Boolean);
|
|
}
|
|
|
|
function restoreSavedMatchSettings(namesInput, spawnPlacementInputs) {
|
|
const storage = getLocalStorage();
|
|
|
|
if (!storage) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const savedNames = storage.getItem(STORAGE_KEYS.names);
|
|
const savedSpawnPlacement = storage.getItem(STORAGE_KEYS.spawnPlacement);
|
|
|
|
if (savedNames !== null) {
|
|
namesInput.value = savedNames;
|
|
}
|
|
|
|
setSpawnPlacement(spawnPlacementInputs, savedSpawnPlacement);
|
|
} catch {
|
|
// Storage may be unavailable in private or restricted browser contexts.
|
|
}
|
|
}
|
|
|
|
function saveMatchSettings(namesInput, spawnPlacementInputs) {
|
|
const storage = getLocalStorage();
|
|
|
|
if (!storage) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
storage.setItem(STORAGE_KEYS.names, namesInput.value);
|
|
storage.setItem(STORAGE_KEYS.spawnPlacement, selectedSpawnPlacement(spawnPlacementInputs));
|
|
} catch {
|
|
// Ignore storage failures so the match form remains usable.
|
|
}
|
|
}
|
|
|
|
function selectedSpawnPlacement(inputs) {
|
|
return inputs.find((input) => input.checked)?.value ?? SPAWN.DEFAULT_PLACEMENT;
|
|
}
|
|
|
|
function setSpawnPlacement(inputs, value) {
|
|
const savedInput = inputs.find((input) => input.value === value);
|
|
const defaultInput = inputs.find((input) => input.value === SPAWN.DEFAULT_PLACEMENT);
|
|
const nextInput = savedInput ?? defaultInput;
|
|
|
|
if (nextInput) {
|
|
nextInput.checked = true;
|
|
}
|
|
}
|
|
|
|
function getLocalStorage() {
|
|
try {
|
|
return window.localStorage;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|