Merge pull request 'Fix Texas Hold'em dealer page: script timing crash and seat overlap' (#11) from feature/casino-texas-holdem into master
Build and Deploy / build-deploy (push) Successful in 1m8s
Build and Deploy / build-deploy (push) Successful in 1m8s
Reviewed-on: #11
This commit was merged in pull request #11.
This commit is contained in:
@@ -34,6 +34,13 @@
|
||||
</section>
|
||||
|
||||
<aside id="holdemSidebar">
|
||||
<section id="seatEditorPanel" class="sidebarPanel seatEditorPanel">
|
||||
<h2 id="seatEditorTitle">Select a seat</h2>
|
||||
<div id="seatEditorBody">
|
||||
<p class="fieldHint">Click a seat at the table to edit their name, cards, chips and anything else.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<details class="sidebarPanel" open>
|
||||
<summary>Table Setup</summary>
|
||||
<div class="panelBody">
|
||||
@@ -81,10 +88,18 @@
|
||||
<button class="dealerChip" title="Make this seat the dealer button">D</button>
|
||||
<span class="blindBadge sbBadge">SB</span>
|
||||
<span class="blindBadge bbBadge">BB</span>
|
||||
<div class="seatCard">
|
||||
<div class="seatCardTop">
|
||||
<input type="text" class="seatNameInput" placeholder="Seat" maxlength="24" />
|
||||
<div class="seatPuckName"></div>
|
||||
<div class="seatPuckCards"></div>
|
||||
<div class="seatPuckTotal"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="seatEditorTemplate">
|
||||
<div class="seatEditorForm">
|
||||
<label class="fieldRow">
|
||||
<span>Name</span>
|
||||
<input type="text" class="seatNameInput" placeholder="Seat" maxlength="24" />
|
||||
</label>
|
||||
<div class="seatCardToggles">
|
||||
<label class="inHandToggle" title="This seat is playing the current hand">
|
||||
<input type="checkbox" class="inHandCheckbox" />
|
||||
@@ -110,7 +125,6 @@
|
||||
<div class="customFields"></div>
|
||||
<button class="holdemBtn holdemBtnSmall addFieldBtn">+ field</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="chipLegendRowTemplate">
|
||||
|
||||
@@ -117,7 +117,7 @@ body {
|
||||
#pokerTableWrap {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding-bottom: 62%;
|
||||
padding-bottom: 72%;
|
||||
}
|
||||
|
||||
#pokerTable {
|
||||
@@ -161,19 +161,21 @@ body {
|
||||
inset: 0;
|
||||
}
|
||||
|
||||
/* ---------- Seats ---------- */
|
||||
/* ---------- Seats (compact pucks on the table) ---------- */
|
||||
|
||||
.seat {
|
||||
position: absolute;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 190px;
|
||||
width: 96px;
|
||||
min-height: 54px;
|
||||
background: #232323;
|
||||
border: 1px solid #3a3a3a;
|
||||
border: 2px solid #3a3a3a;
|
||||
border-radius: 10px;
|
||||
padding: 0.6rem;
|
||||
padding: 0.3rem 0.4rem;
|
||||
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.4);
|
||||
cursor: grab;
|
||||
z-index: 1;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.seat.dragging {
|
||||
@@ -189,30 +191,60 @@ body {
|
||||
opacity: 0.45;
|
||||
}
|
||||
|
||||
.seat.seatFolded .seatCard {
|
||||
opacity: 0.55;
|
||||
.seat.seatFolded {
|
||||
border-style: dashed;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.seat.seatSelected {
|
||||
border-color: #09ff00;
|
||||
box-shadow: 0 0 0 2px rgba(9, 255, 0, 0.35), 0 4px 10px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.seatChairNumber {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 5px;
|
||||
font-size: 0.6rem;
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.seatPuckName {
|
||||
font-size: 0.72rem;
|
||||
font-weight: 600;
|
||||
color: #eee;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin-top: 0.6rem;
|
||||
}
|
||||
|
||||
.seatPuckCards {
|
||||
font-size: 0.65rem;
|
||||
color: #888;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
margin-bottom: 0.3rem;
|
||||
font-family: var(--font-mono, monospace);
|
||||
color: #bbb;
|
||||
min-height: 0.9em;
|
||||
}
|
||||
|
||||
.seatPuckTotal {
|
||||
font-size: 0.7rem;
|
||||
font-weight: 700;
|
||||
color: #9be6a8;
|
||||
min-height: 1em;
|
||||
}
|
||||
|
||||
.dealerChip {
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
right: -10px;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border-radius: 50%;
|
||||
background: #444;
|
||||
color: #ccc;
|
||||
border: 2px solid #666;
|
||||
font-weight: 700;
|
||||
font-size: 0.75rem;
|
||||
font-size: 0.68rem;
|
||||
cursor: pointer;
|
||||
z-index: 2;
|
||||
}
|
||||
@@ -226,10 +258,10 @@ body {
|
||||
.blindBadge {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
font-size: 0.65rem;
|
||||
top: -9px;
|
||||
font-size: 0.58rem;
|
||||
font-weight: 700;
|
||||
padding: 0.1rem 0.4rem;
|
||||
padding: 0.05rem 0.3rem;
|
||||
border-radius: 8px;
|
||||
z-index: 2;
|
||||
}
|
||||
@@ -245,15 +277,43 @@ body {
|
||||
}
|
||||
|
||||
.bbBadge {
|
||||
left: 26px;
|
||||
left: 22px;
|
||||
background: #b7791f;
|
||||
color: #fff7e6;
|
||||
}
|
||||
|
||||
.seatCardTop {
|
||||
/* ---------- Seat editor panel (sidebar form for the selected seat) ---------- */
|
||||
|
||||
.seatEditorPanel {
|
||||
padding: 0.9rem;
|
||||
}
|
||||
|
||||
.seatEditorPanel h2 {
|
||||
margin: 0 0 0.6rem;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 500;
|
||||
color: #f5f5f5;
|
||||
}
|
||||
|
||||
.seatEditorForm {
|
||||
display: flex;
|
||||
gap: 0.4rem;
|
||||
margin-bottom: 0.35rem;
|
||||
flex-direction: column;
|
||||
gap: 0.6rem;
|
||||
}
|
||||
|
||||
.seatCardToggles {
|
||||
display: flex;
|
||||
gap: 0.6rem;
|
||||
font-size: 0.8rem;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.inHandToggle,
|
||||
.foldToggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.seatNameInput {
|
||||
@@ -267,22 +327,6 @@ body {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.seatCardToggles {
|
||||
display: flex;
|
||||
gap: 0.6rem;
|
||||
margin-bottom: 0.4rem;
|
||||
font-size: 0.7rem;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.inHandToggle,
|
||||
.foldToggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.seatCards {
|
||||
display: flex;
|
||||
gap: 0.35rem;
|
||||
@@ -598,6 +642,7 @@ body {
|
||||
}
|
||||
|
||||
.seat {
|
||||
width: 150px;
|
||||
width: 78px;
|
||||
min-height: 44px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
(function () {
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const state = HoldemState.load();
|
||||
|
||||
const hooks = {
|
||||
@@ -67,4 +67,4 @@
|
||||
document.getElementById("potWizardOverlay").addEventListener("click", e => {
|
||||
if (e.target.id === "potWizardOverlay") PotWizard.close();
|
||||
});
|
||||
})();
|
||||
});
|
||||
|
||||
@@ -1,19 +1,30 @@
|
||||
// All DOM rendering + drag/drop for the table. Talks to the outside world only through
|
||||
// the `hooks` object passed to mount(): hooks.save(state) persists, hooks.rerender()
|
||||
// re-draws everything (used after structural changes like resizing seats or the chip
|
||||
// legend), hooks.rerenderPotBadge(state) just updates the pot total display.
|
||||
// legend).
|
||||
//
|
||||
// The table itself only shows compact seat "pucks" — name, cards, total, blind/dealer
|
||||
// badges — because a full data-entry form (chip counts, custom fields, etc.) doesn't fit
|
||||
// next to nine others arranged in a circle at any screen size. Clicking a puck opens the
|
||||
// full form in the seat editor panel instead.
|
||||
const Render = {
|
||||
state: null,
|
||||
hooks: null,
|
||||
selectedSeatIndex: null,
|
||||
|
||||
mount(state, hooks) {
|
||||
this.state = state;
|
||||
this.hooks = hooks;
|
||||
this.selectedSeatIndex = null;
|
||||
this.renderAll();
|
||||
},
|
||||
|
||||
renderAll() {
|
||||
if (this.selectedSeatIndex !== null && this.selectedSeatIndex >= this.state.seatCount) {
|
||||
this.selectedSeatIndex = null;
|
||||
}
|
||||
this.renderSeats();
|
||||
this.renderSeatEditor();
|
||||
this.renderChipLegend();
|
||||
this.renderNotes();
|
||||
this.updatePotBadge();
|
||||
@@ -36,29 +47,22 @@ const Render = {
|
||||
document.getElementById("potBadgeAmount").textContent = Money.format(total);
|
||||
},
|
||||
|
||||
commitAndRedrawSeat(seatEl, seatIndex) {
|
||||
this.hooks.save(this.state);
|
||||
this.updatePotBadge();
|
||||
this.renderSeatTotal(seatEl, this.state.seats[seatIndex]);
|
||||
},
|
||||
|
||||
renderSeatTotal(seatEl, player) {
|
||||
const total = HoldemState.computeContribution(player, this.state.chipLegend, this.state.basePotAmount);
|
||||
seatEl.querySelector(".seatTotalAmount").textContent = Money.format(total);
|
||||
},
|
||||
|
||||
// ---- Seats around the table ----
|
||||
// ---- Seats around the table (compact pucks) ----
|
||||
|
||||
seatPosition(index, count) {
|
||||
const angle = -90 + (360 / count) * index;
|
||||
const radians = (angle * Math.PI) / 180;
|
||||
const rx = 44;
|
||||
const ry = 40;
|
||||
const ry = 42;
|
||||
const left = 50 + rx * Math.cos(radians);
|
||||
const top = 50 + ry * Math.sin(radians);
|
||||
return { left, top };
|
||||
},
|
||||
|
||||
puckLabel(player, seatIndex) {
|
||||
return player.name && player.name.trim() ? player.name.trim() : `Seat ${seatIndex + 1}`;
|
||||
},
|
||||
|
||||
renderSeats() {
|
||||
const layer = document.getElementById("seatsLayer");
|
||||
layer.innerHTML = "";
|
||||
@@ -72,11 +76,12 @@ const Render = {
|
||||
node.style.top = `${pos.top}%`;
|
||||
node.dataset.seatIndex = String(index);
|
||||
|
||||
node.querySelector(".seatChairNumber").textContent = `Seat ${index + 1}`;
|
||||
node.querySelector(".seatChairNumber").textContent = index + 1;
|
||||
|
||||
const dealerChip = node.querySelector(".dealerChip");
|
||||
dealerChip.classList.toggle("active", index === dealerIndex);
|
||||
dealerChip.addEventListener("click", () => {
|
||||
dealerChip.addEventListener("click", e => {
|
||||
e.stopPropagation();
|
||||
this.state.dealerSeatIndex = index;
|
||||
this.hooks.save(this.state);
|
||||
this.renderSeats();
|
||||
@@ -85,12 +90,14 @@ const Render = {
|
||||
node.querySelector(".sbBadge").classList.toggle("visible", index === sbIndex);
|
||||
node.querySelector(".bbBadge").classList.toggle("visible", index === bbIndex);
|
||||
|
||||
this.wireSeatFields(node, player, index);
|
||||
this.renderChipCounts(node, player);
|
||||
this.renderCustomFields(node, player);
|
||||
this.renderSeatTotal(node, player);
|
||||
node.classList.toggle("seatInactive", !player.inHand);
|
||||
node.classList.toggle("seatFolded", player.folded);
|
||||
this.updatePuckContent(node, player, index);
|
||||
node.classList.toggle("seatSelected", index === this.selectedSeatIndex);
|
||||
|
||||
node.addEventListener("click", () => {
|
||||
this.selectedSeatIndex = index;
|
||||
this.renderSeats();
|
||||
this.renderSeatEditor();
|
||||
});
|
||||
|
||||
this.wireDragAndDrop(node, index);
|
||||
|
||||
@@ -98,106 +105,21 @@ const Render = {
|
||||
});
|
||||
},
|
||||
|
||||
wireSeatFields(node, player, index) {
|
||||
const nameInput = node.querySelector(".seatNameInput");
|
||||
nameInput.value = player.name;
|
||||
nameInput.addEventListener("input", () => {
|
||||
player.name = nameInput.value;
|
||||
this.hooks.save(this.state);
|
||||
});
|
||||
|
||||
const inHandCheckbox = node.querySelector(".inHandCheckbox");
|
||||
inHandCheckbox.checked = player.inHand;
|
||||
inHandCheckbox.addEventListener("change", () => {
|
||||
player.inHand = inHandCheckbox.checked;
|
||||
if (!player.inHand) player.folded = false;
|
||||
this.renderSeats();
|
||||
this.hooks.save(this.state);
|
||||
this.updatePotBadge();
|
||||
});
|
||||
|
||||
const foldCheckbox = node.querySelector(".foldCheckbox");
|
||||
foldCheckbox.checked = player.folded;
|
||||
foldCheckbox.disabled = !player.inHand;
|
||||
foldCheckbox.addEventListener("change", () => {
|
||||
player.folded = foldCheckbox.checked;
|
||||
updatePuckContent(node, player, index) {
|
||||
node.querySelector(".seatPuckName").textContent = player.name && player.name.trim() ? player.name.trim() : "";
|
||||
const cards = (player.cards || []).filter(Boolean).join(" ");
|
||||
node.querySelector(".seatPuckCards").textContent = cards;
|
||||
const total = HoldemState.computeContribution(player, this.state.chipLegend, this.state.basePotAmount);
|
||||
node.querySelector(".seatPuckTotal").textContent = total > 0 ? Money.format(total) : "";
|
||||
node.classList.toggle("seatInactive", !player.inHand);
|
||||
node.classList.toggle("seatFolded", player.folded);
|
||||
this.hooks.save(this.state);
|
||||
});
|
||||
|
||||
const card1 = node.querySelector(".card1Input");
|
||||
const card2 = node.querySelector(".card2Input");
|
||||
card1.value = player.cards[0] || "";
|
||||
card2.value = player.cards[1] || "";
|
||||
[card1, card2].forEach((input, cardIdx) => {
|
||||
input.addEventListener("input", () => {
|
||||
input.value = input.value.toUpperCase();
|
||||
player.cards[cardIdx] = input.value;
|
||||
this.hooks.save(this.state);
|
||||
});
|
||||
});
|
||||
|
||||
const amountInput = node.querySelector(".amountOverrideInput");
|
||||
amountInput.value = player.amountOverride ?? "";
|
||||
amountInput.addEventListener("input", () => {
|
||||
player.amountOverride = amountInput.value === "" ? null : amountInput.value;
|
||||
this.commitAndRedrawSeat(node, index);
|
||||
});
|
||||
|
||||
const addFieldBtn = node.querySelector(".addFieldBtn");
|
||||
addFieldBtn.addEventListener("click", () => {
|
||||
player.customFields.push({ label: "", value: "" });
|
||||
this.renderCustomFields(node, player);
|
||||
this.hooks.save(this.state);
|
||||
});
|
||||
},
|
||||
|
||||
renderChipCounts(node, player) {
|
||||
const container = node.querySelector(".chipCounts");
|
||||
container.innerHTML = "";
|
||||
const template = document.getElementById("chipCountTemplate");
|
||||
|
||||
this.state.chipLegend.forEach(chip => {
|
||||
const row = template.content.firstElementChild.cloneNode(true);
|
||||
row.querySelector(".chipSwatch").style.background = chip.color;
|
||||
row.title = `$${chip.value} chips`;
|
||||
const input = row.querySelector(".chipCountInput");
|
||||
input.value = player.chipCounts[chip.id] || 0;
|
||||
input.addEventListener("input", () => {
|
||||
const count = Math.max(0, Math.floor(Number(input.value)) || 0);
|
||||
player.chipCounts[chip.id] = count;
|
||||
this.commitAndRedrawSeat(node, Number(node.dataset.seatIndex));
|
||||
});
|
||||
container.appendChild(row);
|
||||
});
|
||||
},
|
||||
|
||||
renderCustomFields(node, player) {
|
||||
const container = node.querySelector(".customFields");
|
||||
container.innerHTML = "";
|
||||
const template = document.getElementById("customFieldTemplate");
|
||||
|
||||
player.customFields.forEach((field, fieldIdx) => {
|
||||
const row = template.content.firstElementChild.cloneNode(true);
|
||||
const labelInput = row.querySelector(".customFieldLabel");
|
||||
const valueInput = row.querySelector(".customFieldValue");
|
||||
labelInput.value = field.label;
|
||||
valueInput.value = field.value;
|
||||
labelInput.addEventListener("input", () => {
|
||||
field.label = labelInput.value;
|
||||
this.hooks.save(this.state);
|
||||
});
|
||||
valueInput.addEventListener("input", () => {
|
||||
field.value = valueInput.value;
|
||||
this.hooks.save(this.state);
|
||||
});
|
||||
row.querySelector(".removeFieldBtn").addEventListener("click", () => {
|
||||
player.customFields.splice(fieldIdx, 1);
|
||||
this.renderCustomFields(node, player);
|
||||
this.hooks.save(this.state);
|
||||
});
|
||||
container.appendChild(row);
|
||||
});
|
||||
// Cheaper than a full renderSeats() — used after edits so the seat editor's inputs
|
||||
// (which live in a separate panel) never lose focus.
|
||||
refreshPuck(index) {
|
||||
const node = document.querySelector(`.seat[data-seat-index="${index}"]`);
|
||||
if (node) this.updatePuckContent(node, this.state.seats[index], index);
|
||||
},
|
||||
|
||||
wireDragAndDrop(node, index) {
|
||||
@@ -222,6 +144,151 @@ const Render = {
|
||||
[seats[sourceIndex], seats[targetIndex]] = [seats[targetIndex], seats[sourceIndex]];
|
||||
this.hooks.save(this.state);
|
||||
this.renderSeats();
|
||||
if (this.selectedSeatIndex === sourceIndex || this.selectedSeatIndex === targetIndex) {
|
||||
this.renderSeatEditor();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// ---- Seat editor panel (the full form for whichever seat is selected) ----
|
||||
|
||||
renderSeatEditor() {
|
||||
const title = document.getElementById("seatEditorTitle");
|
||||
const body = document.getElementById("seatEditorBody");
|
||||
|
||||
if (this.selectedSeatIndex === null) {
|
||||
title.textContent = "Select a seat";
|
||||
body.innerHTML = '<p class="fieldHint">Click a seat at the table to edit their name, cards, chips and anything else.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
const index = this.selectedSeatIndex;
|
||||
const player = this.state.seats[index];
|
||||
title.textContent = this.puckLabel(player, index);
|
||||
|
||||
body.innerHTML = "";
|
||||
const template = document.getElementById("seatEditorTemplate");
|
||||
const form = template.content.firstElementChild.cloneNode(true);
|
||||
|
||||
this.wireSeatFields(form, player, index);
|
||||
this.renderChipCounts(form, player, index);
|
||||
this.renderCustomFields(form, player, index);
|
||||
this.renderSeatTotal(form, player);
|
||||
|
||||
body.appendChild(form);
|
||||
},
|
||||
|
||||
renderSeatTotal(form, player) {
|
||||
const total = HoldemState.computeContribution(player, this.state.chipLegend, this.state.basePotAmount);
|
||||
form.querySelector(".seatTotalAmount").textContent = Money.format(total);
|
||||
},
|
||||
|
||||
commitSeatChange(form, player, index) {
|
||||
this.hooks.save(this.state);
|
||||
this.updatePotBadge();
|
||||
this.renderSeatTotal(form, player);
|
||||
this.refreshPuck(index);
|
||||
},
|
||||
|
||||
wireSeatFields(form, player, index) {
|
||||
const nameInput = form.querySelector(".seatNameInput");
|
||||
nameInput.value = player.name;
|
||||
nameInput.addEventListener("input", () => {
|
||||
player.name = nameInput.value;
|
||||
document.getElementById("seatEditorTitle").textContent = this.puckLabel(player, index);
|
||||
this.commitSeatChange(form, player, index);
|
||||
});
|
||||
|
||||
const inHandCheckbox = form.querySelector(".inHandCheckbox");
|
||||
inHandCheckbox.checked = player.inHand;
|
||||
inHandCheckbox.addEventListener("change", () => {
|
||||
player.inHand = inHandCheckbox.checked;
|
||||
if (!player.inHand) player.folded = false;
|
||||
foldCheckboxRef.checked = player.folded;
|
||||
foldCheckboxRef.disabled = !player.inHand;
|
||||
this.commitSeatChange(form, player, index);
|
||||
});
|
||||
|
||||
const foldCheckboxRef = form.querySelector(".foldCheckbox");
|
||||
foldCheckboxRef.checked = player.folded;
|
||||
foldCheckboxRef.disabled = !player.inHand;
|
||||
foldCheckboxRef.addEventListener("change", () => {
|
||||
player.folded = foldCheckboxRef.checked;
|
||||
this.commitSeatChange(form, player, index);
|
||||
});
|
||||
|
||||
const card1 = form.querySelector(".card1Input");
|
||||
const card2 = form.querySelector(".card2Input");
|
||||
card1.value = player.cards[0] || "";
|
||||
card2.value = player.cards[1] || "";
|
||||
[card1, card2].forEach((input, cardIdx) => {
|
||||
input.addEventListener("input", () => {
|
||||
input.value = input.value.toUpperCase();
|
||||
player.cards[cardIdx] = input.value;
|
||||
this.commitSeatChange(form, player, index);
|
||||
});
|
||||
});
|
||||
|
||||
const amountInput = form.querySelector(".amountOverrideInput");
|
||||
amountInput.value = player.amountOverride ?? "";
|
||||
amountInput.addEventListener("input", () => {
|
||||
player.amountOverride = amountInput.value === "" ? null : amountInput.value;
|
||||
this.commitSeatChange(form, player, index);
|
||||
});
|
||||
|
||||
const addFieldBtn = form.querySelector(".addFieldBtn");
|
||||
addFieldBtn.addEventListener("click", () => {
|
||||
player.customFields.push({ label: "", value: "" });
|
||||
this.renderCustomFields(form, player, index);
|
||||
this.hooks.save(this.state);
|
||||
});
|
||||
},
|
||||
|
||||
renderChipCounts(form, player, index) {
|
||||
const container = form.querySelector(".chipCounts");
|
||||
container.innerHTML = "";
|
||||
const template = document.getElementById("chipCountTemplate");
|
||||
|
||||
this.state.chipLegend.forEach(chip => {
|
||||
const row = template.content.firstElementChild.cloneNode(true);
|
||||
row.querySelector(".chipSwatch").style.background = chip.color;
|
||||
row.title = `$${chip.value} chips`;
|
||||
const input = row.querySelector(".chipCountInput");
|
||||
input.value = player.chipCounts[chip.id] || 0;
|
||||
input.addEventListener("input", () => {
|
||||
const count = Math.max(0, Math.floor(Number(input.value)) || 0);
|
||||
player.chipCounts[chip.id] = count;
|
||||
this.commitSeatChange(form, player, index);
|
||||
});
|
||||
container.appendChild(row);
|
||||
});
|
||||
},
|
||||
|
||||
renderCustomFields(form, player, index) {
|
||||
const container = form.querySelector(".customFields");
|
||||
container.innerHTML = "";
|
||||
const template = document.getElementById("customFieldTemplate");
|
||||
|
||||
player.customFields.forEach((field, fieldIdx) => {
|
||||
const row = template.content.firstElementChild.cloneNode(true);
|
||||
const labelInput = row.querySelector(".customFieldLabel");
|
||||
const valueInput = row.querySelector(".customFieldValue");
|
||||
labelInput.value = field.label;
|
||||
valueInput.value = field.value;
|
||||
labelInput.addEventListener("input", () => {
|
||||
field.label = labelInput.value;
|
||||
this.hooks.save(this.state);
|
||||
});
|
||||
valueInput.addEventListener("input", () => {
|
||||
field.value = valueInput.value;
|
||||
this.hooks.save(this.state);
|
||||
});
|
||||
row.querySelector(".removeFieldBtn").addEventListener("click", () => {
|
||||
player.customFields.splice(fieldIdx, 1);
|
||||
this.renderCustomFields(form, player, index);
|
||||
this.hooks.save(this.state);
|
||||
});
|
||||
container.appendChild(row);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -242,12 +309,12 @@ const Render = {
|
||||
colorInput.addEventListener("input", () => {
|
||||
chip.color = colorInput.value;
|
||||
this.hooks.save(this.state);
|
||||
this.renderSeats();
|
||||
});
|
||||
valueInput.addEventListener("input", () => {
|
||||
chip.value = Number(valueInput.value) || 0;
|
||||
this.hooks.save(this.state);
|
||||
this.renderSeats();
|
||||
this.renderSeatEditor();
|
||||
this.updatePotBadge();
|
||||
});
|
||||
row.querySelector(".removeChipColorBtn").addEventListener("click", () => {
|
||||
|
||||
Reference in New Issue
Block a user