Files
dmtools/assets/controllers/tracker_picker_controller.js
FrankandClaude Sonnet 5 cbe4b0a0e1 Combat tracker: multiple named encounters
- 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>
2026-09-06 19:24:37 +02:00

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, '&quot;')}">`);
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();
}
}