diff --git a/app.js b/app.js index 91fa837..b2c54ca 100644 --- a/app.js +++ b/app.js @@ -10,16 +10,19 @@ let allMusicians = []; let allInstruments = []; let allTunings = []; let allReferenceSites = []; +let allTerms = []; let sortCol = 'name'; let sortDir = 'asc'; // editing state -let editingTuneId = null; // null = add mode -let editingEntryId = null; // null = no existing instrument entry +let editingTuneId = null; // null = add mode +let editingEntryId = null; // null = no existing instrument entry +let editingOriginalRefIds = []; // ref IDs present when edit modal opened // notes modal state -let notesTuneId = null; -let notesEntryId = null; +let notesTuneId = null; +let notesEntryId = null; +let noteEditorState = null; // { type: 'tune'|'inst', noteId: null|number } let unlocked = false; @@ -41,6 +44,7 @@ const sourceDatalist = $('source-list'); const musicianDatalist = $('musician-list'); const instrumentSelect = $('instrument-select'); const tuningDatalist = $('tuning-list'); +const termDatalist = $('term-list'); const btnDeleteTune = $('btn-delete-tune'); const btnEditNotes = $('btn-edit-notes'); const btnBulkEdit = $('btn-bulk-edit'); @@ -114,18 +118,20 @@ function setStatus(msg, isError = false) { async function loadAll() { setStatus('Loading…'); try { - [allTunes, allSources, allMusicians, allInstruments, allTunings, allReferenceSites] = await Promise.all([ + [allTunes, allSources, allMusicians, allInstruments, allTunings, allReferenceSites, allTerms] = await Promise.all([ apiFetch('/tunes/'), apiFetch('/sources/'), apiFetch('/musicians/'), apiFetch('/instruments'), apiFetch('/tunings/'), apiFetch('/reference_sites/'), + apiFetch('/terms/'), ]); populateFilterOptions(); populateDatalist(sourceDatalist, allSources); populateDatalist(musicianDatalist, allMusicians); populateDatalist(tuningDatalist, allTunings); + populateDatalist(termDatalist, allTerms); populateDatalist(refSiteDatalist, allReferenceSites); populateInstrumentSelect(); renderTable(); @@ -202,6 +208,12 @@ $('btn-quick-add-tuning').addEventListener('click', async () => { }); }); +$('btn-quick-add-term').addEventListener('click', async () => { + await quickAdd('/terms/', 'New term name:', allTerms, termDatalist, item => { + tuneForm.elements.inst_term.value = item.name; + }); +}); + $('btn-quick-add-instrument').addEventListener('click', async () => { const item = await quickAdd('/instruments', 'New instrument name:', allInstruments, null); if (item) { @@ -229,6 +241,11 @@ function resolveTuningId(name) { return allTunings.find(x => x.name.toLowerCase() === name.toLowerCase())?.id ?? null; } +function resolveTermId(name) { + if (!name) return null; + return allTerms.find(x => x.name.toLowerCase() === name.toLowerCase())?.id ?? null; +} + // ── Rows: one per instrument entry ──────────────────────────── // For tunes with no instrument entries, emit one row with empty instrument cols function buildRows(tunes) { @@ -416,7 +433,7 @@ function renderTable() { emptyMsg.hidden = rows.length > 0; rows.forEach(({ tune, entry }) => { - const hasNotes = (tune.notes?.length > 0) || (entry?.notes?.length > 0); + const hasNotes = tune.has_notes ?? false; // ── Mobile 2-line card data ────────────────────────────────── const nameRaw = tune.name ?? ''; @@ -431,7 +448,7 @@ function renderTable() { const mobPills = entry ? pillStatus(entry.status, 'mob-pill') : ''; const mobActions = [ hasNotes ? `` : '', - tune.references?.length > 0 ? `` : '', + (tune.reference_count ?? 0) > 0 ? `` : '', ``, ].join(''); @@ -440,13 +457,13 @@ function renderTable() { ${esc(nameRaw)} ${esc(sourceRaw)} ${esc(keyStr)} - ${esc(entry?.instrument_name ?? '')} - ${esc(entry?.tuning ?? '')} + ${esc(entry?.instrument_name ?? '')} + ${esc(entry?.tuning ?? '')} ${pillStatus(entry?.status)} ${hasNotes ? `` : ''} - ${tune.references?.length > 0 + ${(tune.reference_count ?? 0) > 0 ? `` : ''} + - + @@ -50,7 +51,8 @@ @@ -120,6 +122,14 @@ +