- Encounter entity; Combatant now belongs to an encounter (ON DELETE
CASCADE). Migration adds encounter_id, rehoming any existing combatants.
- /tracker lists encounters (name, count, last updated) with a "New
encounter" form; /tracker/{id} is the HP tracker for one encounter.
- Encounters can be renamed, have their combatants cleared, or be deleted.
- The Enemies list gains an encounter picker next to "Add to tracker"
(existing encounter or "— New encounter —", which prompts for a name);
an encounter's "Add enemies" link pre-selects it via ?encounter=.
- Routes for combatant HP/remove moved under /tracker/combatant/ to keep
the numeric {id} for encounters.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
52 lines
2.0 KiB
JavaScript
52 lines
2.0 KiB
JavaScript
import { Controller } from '@hotwired/stimulus';
|
|
|
|
/*
|
|
* Collects the ticked rows (+ their quantity) from a DataTable and POSTs them
|
|
* to the combat tracker.
|
|
*
|
|
* <div data-controller="tracker-picker"
|
|
* data-tracker-picker-url-value="/tracker/add"
|
|
* data-tracker-picker-token-value="...">
|
|
* <button data-action="tracker-picker#submit">Add to tracker</button>
|
|
* </div>
|
|
*/
|
|
export default class extends Controller {
|
|
static values = { url: String, token: String };
|
|
|
|
submit() {
|
|
const picks = [...document.querySelectorAll('.track-check:checked')].map((cb) => {
|
|
const qtyEl = cb.closest('.track-pick')?.querySelector('.track-qty');
|
|
const qty = Math.max(1, Math.min(50, parseInt(qtyEl?.value ?? '1', 10) || 1));
|
|
return { id: cb.value, qty };
|
|
});
|
|
|
|
if (picks.length === 0) {
|
|
window.alert('Tick at least one enemy first.');
|
|
return;
|
|
}
|
|
|
|
const select = this.element.querySelector('.encounter-select');
|
|
let encounter = select ? select.value : 'new';
|
|
let name = '';
|
|
if (encounter === 'new') {
|
|
name = window.prompt('Name for the new encounter', 'Encounter');
|
|
if (name === null) return; // cancelled
|
|
}
|
|
|
|
const form = document.createElement('form');
|
|
form.method = 'post';
|
|
form.action = this.urlValue;
|
|
form.insertAdjacentHTML('beforeend',
|
|
`<input type="hidden" name="_token" value="${this.tokenValue}">` +
|
|
`<input type="hidden" name="encounter" value="${encounter}">` +
|
|
`<input type="hidden" name="name" value="${name.replace(/"/g, '"')}">`);
|
|
picks.forEach((p, i) => {
|
|
form.insertAdjacentHTML('beforeend',
|
|
`<input type="hidden" name="picks[${i}][id]" value="${p.id}">` +
|
|
`<input type="hidden" name="picks[${i}][qty]" value="${p.qty}">`);
|
|
});
|
|
document.body.appendChild(form);
|
|
form.requestSubmit();
|
|
}
|
|
}
|