Files
ShooterHub/frontend/js/calibers.js
2026-04-02 11:24:30 +02:00

77 lines
3.2 KiB
JavaScript

// ── Shared caliber picker utilities ───────────────────────────────────────────
// Requires api.js loaded first.
function esc(s) {
if (s == null) return '';
return String(s)
.replace(/&/g, '&')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;');
}
async function loadCalibersIntoSelect(selectEl) {
selectEl.innerHTML = '<option value="">Loading calibers…</option>';
try {
const items = await apiGetAll('/calibers/?status=VERIFIED&page_size=1000');
selectEl.innerHTML = '<option value="">— Select caliber —</option>' +
items.map(c => `<option value="${c.id}">${esc(c.name)}</option>`).join('');
} catch(e) {
selectEl.innerHTML = '<option value="">— Calibers unavailable —</option>';
}
}
// Returns HTML for a caliber <select> + inline suggest sub-form.
// selectId: id attribute for the <select>
// suggestId: id prefix for the suggest sub-form elements
function buildCaliberPickerHtml(selectId, suggestId) {
return `
<select class="form-select form-select-sm" id="${selectId}">
<option value="">Loading…</option>
</select>
<div class="mt-1">
<a href="#" class="small text-primary" onclick="event.preventDefault(); document.getElementById('${suggestId}').classList.toggle('d-none')">
<i class="bi bi-plus-circle me-1"></i>Suggest new caliber
</a>
<div id="${suggestId}" class="d-none mt-1 p-2 border rounded bg-light small">
<div class="row g-1 mb-1">
<div class="col"><input type="text" class="form-control form-control-sm" id="${suggestId}Name" placeholder="Name *"></div>
<div class="col"><input type="text" class="form-control form-control-sm" id="${suggestId}Short" placeholder="Short name (opt)"></div>
</div>
<div id="${suggestId}Alert" class="alert alert-danger d-none py-1 small mb-1"></div>
<button class="btn btn-sm btn-outline-primary w-100"
onclick="addCaliberSuggestion('${suggestId}', '${selectId}')">
<i class="bi bi-send me-1"></i>Submit
</button>
</div>
</div>`;
}
async function addCaliberSuggestion(suggestId, selectId) {
const alertEl = document.getElementById(suggestId + 'Alert');
alertEl.classList.add('d-none');
const name = document.getElementById(suggestId + 'Name')?.value?.trim();
const short = document.getElementById(suggestId + 'Short')?.value?.trim();
if (!name) {
alertEl.textContent = 'Caliber name is required.';
alertEl.classList.remove('d-none');
return;
}
try {
const payload = { name };
if (short) payload.short_name = short;
const created = await apiPost('/calibers/', payload);
const sel = document.getElementById(selectId);
if (sel) {
const opt = new Option(created.name, created.id, true, true);
sel.appendChild(opt);
}
document.getElementById(suggestId).classList.add('d-none');
document.getElementById(suggestId + 'Name').value = '';
document.getElementById(suggestId + 'Short').value = '';
} catch(e) {
alertEl.textContent = (e.data && formatErrors(e.data)) || 'Submission failed.';
alertEl.classList.remove('d-none');
}
}