diff --git a/app.js b/app.js
index 1548cde..dd8e02a 100644
--- a/app.js
+++ b/app.js
@@ -9,6 +9,7 @@ let allSources = [];
let allMusicians = [];
let allInstruments = [];
let allTunings = [];
+let allReferenceSites = [];
let sortCol = 'name';
let sortDir = 'asc';
@@ -42,6 +43,13 @@ const instrumentSelect = $('instrument-select');
const tuningDatalist = $('tuning-list');
const btnDeleteTune = $('btn-delete-tune');
const btnEditNotes = $('btn-edit-notes');
+const btnBulkEdit = $('btn-bulk-edit');
+const bulkEditPopover = $('bulk-edit-popover');
+const bulkRefsModal = $('bulk-refs-modal');
+const bulkRefsList = $('bulk-refs-list');
+const refsModal = $('refs-modal');
+const refsModalList = $('refs-modal-list');
+const refSiteDatalist = $('ref-site-list');
// ── Config ───────────────────────────────────────────────────
const _cfg = window.REPERTORY_CONFIG || {};
@@ -68,6 +76,7 @@ function setUnlocked(val) {
unlocked = val;
btnUnlock.hidden = val;
btnAddTune.hidden = !val;
+ btnBulkEdit.hidden = !val;
// Show/hide edit column header and edit buttons
const editHeader = document.querySelector('.edit-col');
if (editHeader) editHeader.hidden = !val;
@@ -105,17 +114,19 @@ function setStatus(msg, isError = false) {
async function loadAll() {
setStatus('Loading…');
try {
- [allTunes, allSources, allMusicians, allInstruments, allTunings] = await Promise.all([
+ [allTunes, allSources, allMusicians, allInstruments, allTunings, allReferenceSites] = await Promise.all([
apiFetch('/tunes/'),
apiFetch('/sources/'),
apiFetch('/musicians/'),
apiFetch('/instruments'),
apiFetch('/tunings/'),
+ apiFetch('/reference_sites/'),
]);
populateFilterOptions();
populateDatalist(sourceDatalist, allSources);
populateDatalist(musicianDatalist, allMusicians);
populateDatalist(tuningDatalist, allTunings);
+ populateDatalist(refSiteDatalist, allReferenceSites);
populateInstrumentSelect();
renderTable();
setStatus(`${allTunes.length} tunes loaded`);
@@ -153,8 +164,13 @@ function populateFilterOptions() {
async function quickAdd(endpoint, promptText, list, datalist, onDone) {
const name = prompt(promptText);
if (!name) return null;
+ const existing = list.find(x => x.name.toLowerCase() === name.trim().toLowerCase());
+ if (existing) {
+ if (onDone) onDone(existing);
+ return existing;
+ }
try {
- const item = await apiFetch(endpoint, { method: 'POST', body: JSON.stringify({ name }) });
+ const item = await apiFetch(endpoint, { method: 'POST', body: JSON.stringify({ name: name.trim() }) });
list.push(item);
list.sort((a, b) => a.name.localeCompare(b.name));
if (datalist) populateDatalist(datalist, list);
@@ -396,8 +412,8 @@ function renderTable() {
const tr = document.createElement('tr');
tr.innerHTML = `
${esc(tune.name ?? '')} |
- ${esc(tune.key ?? '')} |
${esc(tune.source?.name ?? '')} |
+ ${esc(tune.key ?? '')} |
${tune.modal ? 'Yes' : '—'} |
${esc(entry?.instrument_name ?? '')} |
${esc(entry?.tuning ?? '')} |
@@ -407,6 +423,9 @@ function renderTable() {
${hasNotes
? ``
: ''} |
+ ${tune.references?.length > 0
+ ? ``
+ : ''} |
|