diff --git a/web/wall.html b/web/wall.html index a146131..5a2b6a4 100644 --- a/web/wall.html +++ b/web/wall.html @@ -581,6 +581,10 @@ +
+ + +
@@ -1399,9 +1403,14 @@ function cleanAuthor(raw) { // same person, different word order or accents → same key const authorKey = name => deburr(name).replace(/[^a-z0-9 ]/g, ' ').split(/\s+/).filter(Boolean).sort().join(' '); +// dc.subject folds accents and case; the select shows only tags that recur, since +// ~8000 distinct values (57% used once) would be an unusable list +const subjectKey = t => deburr(String(t)).replace(/\s+/g, ' ').trim(); +const SUBJECT_MIN = 20; + function setupFilters(mapData) { const entries = Object.values(mapData.map); - const instCounts = new Map(), typeCounts = new Map(), authorGroups = new Map(); + const instCounts = new Map(), typeCounts = new Map(), authorGroups = new Map(), subjectGroups = new Map(); let minYear = Infinity, maxYear = -Infinity; entries.forEach(e => { @@ -1409,6 +1418,10 @@ function setupFilters(mapData) { if (meta.community) instCounts.set(meta.community, (instCounts.get(meta.community) || 0) + 1); const t = cleanType(meta.type); if (t) typeCounts.set(t, (typeCounts.get(t) || 0) + 1); + new Set([].concat(meta.subject || []).map(subjectKey)).forEach(k => { + if (!k) return; + subjectGroups.set(k, (subjectGroups.get(k) || 0) + 1); + }); const a = cleanAuthor(meta.contributor); if (a) { const k = authorKey(a), g = authorGroups.get(k) || { n: 0, forms: new Map() }; @@ -1446,6 +1459,18 @@ function setupFilters(mapData) { selAuthor.appendChild(opt); }); + const subjectNames = new Map(); // key → a readable spelling + entries.forEach(e => [].concat((e.meta || {}).subject || []).forEach(t => { + const k = subjectKey(t); + if (k && subjectGroups.get(k) >= SUBJECT_MIN && !subjectNames.has(k)) subjectNames.set(k, String(t).trim()); + })); + const selSubject = document.getElementById('f-subject'); + [...subjectGroups.entries()].filter(([, n]) => n >= SUBJECT_MIN).sort((a, b) => b[1] - a[1]).forEach(([k, n]) => { + const opt = document.createElement('option'); + opt.value = k; opt.textContent = `${subjectNames.get(k)} (${n.toLocaleString('pt-BR')})`; + selSubject.appendChild(opt); + }); + const decadeMin = Math.floor(minYear / 10) * 10; const decadeMax = Math.floor(maxYear / 10) * 10; const nDecades = (decadeMax - decadeMin) / 10 + 1; @@ -1477,6 +1502,7 @@ function setupFilters(mapData) { const a = cleanAuthor(meta.contributor); m.userData._author = a ? authorKey(a) : ''; m.userData._type = cleanType(meta.type); + m.userData._subjects = new Set([].concat(meta.subject || []).map(subjectKey)); // one haystack per piece: every metadata field, not a chosen few // the handle is the map's key, not a field of meta — it still has to be // searchable (people paste a handle or its number straight into the box) @@ -1501,7 +1527,7 @@ function setupFilters(mapData) { bars.push(bar); } - const state = { search: '', institution: '', yearLo: decadeMin, yearHi: decadeMax, yearTouched: false, author: '', type: '' }; + const state = { search: '', institution: '', yearLo: decadeMin, yearHi: decadeMax, yearTouched: false, author: '', type: '', subject: '' }; function resetYear() { state.yearTouched = false; @@ -1523,6 +1549,7 @@ function setupFilters(mapData) { (!state.institution || meta.community === state.institution) && (!state.type || d._type === state.type) && (!state.author || d._author === state.author) && + (!state.subject || d._subjects.has(state.subject)) && terms.every(t => d._hay.includes(t)); if (okRest && d._year != null) { const i = Math.floor((d._year - decadeMin) / 10); @@ -1583,6 +1610,7 @@ function setupFilters(mapData) { if (state.institution) out.push({ key: 'institution', text: state.institution }); if (state.yearTouched) out.push({ key: 'year', text: yearLabel(state.yearLo, state.yearHi) }); if (state.author) out.push({ key: 'author', text: authorNames.get(state.author) }); + if (state.subject) out.push({ key: 'subject', text: subjectNames.get(state.subject) }); if (state.type) out.push({ key: 'type', text: state.type }); return out; } @@ -1591,6 +1619,7 @@ function setupFilters(mapData) { if (key === 'search') { state.search = ''; searchInput.value = ''; } if (key === 'institution') { state.institution = ''; selInst.value = ''; } if (key === 'type') { state.type = ''; selType.value = ''; } + if (key === 'subject') { state.subject = ''; selSubject.value = ''; } if (key === 'author') { state.author = ''; selAuthor.value = ''; } if (key === 'year') resetYear(); apply(); @@ -1632,6 +1661,7 @@ function setupFilters(mapData) { }); searchX.addEventListener('click', () => { clearTimeout(searchTimer); clearOne('search'); searchInput.focus(); }); + selSubject.addEventListener('change', () => { state.subject = selSubject.value; apply(); }); selAuthor.addEventListener('change', () => { state.author = selAuthor.value; apply(); }); function onYear(e) { @@ -1651,8 +1681,8 @@ function setupFilters(mapData) { clearBtn.addEventListener('click', () => { clearTimeout(searchTimer); - state.search = ''; state.institution = ''; state.type = ''; state.author = ''; - searchInput.value = ''; selInst.value = ''; selType.value = ''; selAuthor.value = ''; + state.search = ''; state.institution = ''; state.type = ''; state.author = ''; state.subject = ''; + searchInput.value = ''; selInst.value = ''; selType.value = ''; selAuthor.value = ''; selSubject.value = ''; resetYear(); apply(); });