Allowed renaming of teams in Finska score card
All checks were successful
/ publish (push) Successful in 1m40s
All checks were successful
/ publish (push) Successful in 1m40s
This commit is contained in:
parent
c7ff8597aa
commit
3953adedd3
|
|
@ -20,8 +20,18 @@
|
|||
<table class="score-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<td colspan="2">Team A</td>
|
||||
<td colspan="2">Team B</td>
|
||||
<td colspan="2" data-finska-scorecard-target="team1Header">
|
||||
<span class="team-header">
|
||||
<span class="team-name">Team A</span>
|
||||
<button class="edit-btn" data-action="finska-scorecard#editTeam1" aria-label="Edit Team A name">✎</button>
|
||||
</span>
|
||||
</td>
|
||||
<td colspan="2" data-finska-scorecard-target="team2Header">
|
||||
<span class="team-header">
|
||||
<span class="team-name">Team B</span>
|
||||
<button class="edit-btn" data-action="finska-scorecard#editTeam2" aria-label="Edit Team B name">✎</button>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody data-finska-scorecard-target="scoreTable">
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { Scorecard, getStoreDAO } from "./models.js";
|
|||
const storeDao = getStoreDAO();
|
||||
|
||||
export class FinskaScorecardController extends Controller {
|
||||
static targets = ["score1Input", "score2Input", "scoreTable"];
|
||||
static targets = ["score1Input", "score2Input", "scoreTable", "team1Header", "team2Header"];
|
||||
static values = {
|
||||
maxScore: Number,
|
||||
overflowScoreTo: Number
|
||||
|
|
@ -18,9 +18,96 @@ export class FinskaScorecardController extends Controller {
|
|||
|
||||
this._undoStack = [];
|
||||
this._scorecard = storeDao.loadOrCreate(rules);
|
||||
this._loadTeamNames();
|
||||
this.updateTable();
|
||||
}
|
||||
|
||||
_loadTeamNames() {
|
||||
const stored1 = localStorage.getItem('finska-team1-name');
|
||||
const stored2 = localStorage.getItem('finska-team2-name');
|
||||
this._team1Name = stored1 || 'Team A';
|
||||
this._team2Name = stored2 || 'Team B';
|
||||
this._renderTeamHeader(this.team1HeaderTarget, this._team1Name, 'editTeam1');
|
||||
this._renderTeamHeader(this.team2HeaderTarget, this._team2Name, 'editTeam2');
|
||||
}
|
||||
|
||||
_renderTeamHeader(td, name, editAction) {
|
||||
td.innerHTML = `<span class="team-header">
|
||||
<span class="team-name">${this._escapeHtml(name)}</span>
|
||||
<button class="edit-btn" data-action="finska-scorecard#${editAction}" aria-label="Edit ${this._escapeHtml(name)} name">✎</button>
|
||||
</span>`;
|
||||
}
|
||||
|
||||
_renderEditHeader(td, currentName, teamNum) {
|
||||
td.innerHTML = `<span class="team-header-edit">
|
||||
<input type="text" value="${this._escapeAttr(currentName)}" data-action="keydown->finska-scorecard#editKeyDown${teamNum}">
|
||||
<button class="confirm-btn" data-action="finska-scorecard#confirmTeam${teamNum}" aria-label="Confirm">✓</button>
|
||||
<button class="cancel-btn" data-action="finska-scorecard#cancelTeam${teamNum}" aria-label="Cancel">✗</button>
|
||||
</span>`;
|
||||
td.querySelector('input').focus();
|
||||
td.querySelector('input').select();
|
||||
}
|
||||
|
||||
editTeam1() {
|
||||
this._renderEditHeader(this.team1HeaderTarget, this._team1Name, '1');
|
||||
}
|
||||
|
||||
editTeam2() {
|
||||
this._renderEditHeader(this.team2HeaderTarget, this._team2Name, '2');
|
||||
}
|
||||
|
||||
confirmTeam1() {
|
||||
const input = this.team1HeaderTarget.querySelector('input');
|
||||
const newName = input.value.trim() || 'Team A';
|
||||
this._team1Name = newName;
|
||||
localStorage.setItem('finska-team1-name', newName);
|
||||
this._renderTeamHeader(this.team1HeaderTarget, this._team1Name, 'editTeam1');
|
||||
}
|
||||
|
||||
confirmTeam2() {
|
||||
const input = this.team2HeaderTarget.querySelector('input');
|
||||
const newName = input.value.trim() || 'Team B';
|
||||
this._team2Name = newName;
|
||||
localStorage.setItem('finska-team2-name', newName);
|
||||
this._renderTeamHeader(this.team2HeaderTarget, this._team2Name, 'editTeam2');
|
||||
}
|
||||
|
||||
cancelTeam1() {
|
||||
this._renderTeamHeader(this.team1HeaderTarget, this._team1Name, 'editTeam1');
|
||||
}
|
||||
|
||||
cancelTeam2() {
|
||||
this._renderTeamHeader(this.team2HeaderTarget, this._team2Name, 'editTeam2');
|
||||
}
|
||||
|
||||
editKeyDown1(e) {
|
||||
this._editKeyDown(e, this.confirmTeam1.bind(this), this.cancelTeam1.bind(this));
|
||||
}
|
||||
|
||||
editKeyDown2(e) {
|
||||
this._editKeyDown(e, this.confirmTeam2.bind(this), this.cancelTeam2.bind(this));
|
||||
}
|
||||
|
||||
_editKeyDown(e, confirmFn, cancelFn) {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
confirmFn();
|
||||
} else if (e.key === 'Escape') {
|
||||
e.preventDefault();
|
||||
cancelFn();
|
||||
}
|
||||
}
|
||||
|
||||
_escapeHtml(str) {
|
||||
const div = document.createElement('div');
|
||||
div.textContent = str;
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
_escapeAttr(str) {
|
||||
return str.replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
|
||||
}
|
||||
|
||||
updateTable() {
|
||||
let tableBody = this.scoreTableTarget;
|
||||
let tableRows = tableBody.querySelectorAll("tr");
|
||||
|
|
@ -155,6 +242,12 @@ export class FinskaScorecardController extends Controller {
|
|||
this._scorecard.reset();
|
||||
storeDao.clear();
|
||||
this._undoStack = [];
|
||||
this._team1Name = 'Team A';
|
||||
this._team2Name = 'Team B';
|
||||
localStorage.removeItem('finska-team1-name');
|
||||
localStorage.removeItem('finska-team2-name');
|
||||
this._renderTeamHeader(this.team1HeaderTarget, this._team1Name, 'editTeam1');
|
||||
this._renderTeamHeader(this.team2HeaderTarget, this._team2Name, 'editTeam2');
|
||||
this.updateTable();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,3 +19,66 @@ tfoot input {
|
|||
background-color: #DEFC85;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.team-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.team-header .team-name {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.team-header .edit-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: 0.1rem 0.3rem;
|
||||
font-size: 0.9rem;
|
||||
margin: 0;
|
||||
width: auto;
|
||||
line-height: 1;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.team-header .edit-btn:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.team-header-edit {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.team-header-edit input {
|
||||
border-width: 1px;
|
||||
margin: 0;
|
||||
padding: 0.2rem 0.4rem;
|
||||
font-size: 0.9rem;
|
||||
width: 6rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.team-header-edit .confirm-btn,
|
||||
.team-header-edit .cancel-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: 0.1rem 0.3rem;
|
||||
font-size: 1rem;
|
||||
margin: 0;
|
||||
width: auto;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.team-header-edit .confirm-btn {
|
||||
color: #2e7d32;
|
||||
}
|
||||
|
||||
.team-header-edit .cancel-btn {
|
||||
color: #c62828;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue