77 lines
3.2 KiB
JavaScript
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, '<')
|
|
.replace(/>/g, '>')
|
|
.replace(/"/g, '"');
|
|
}
|
|
|
|
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');
|
|
}
|
|
}
|