feat: filtro de assunto (dc.subject) com tags recorrentes
This commit is contained in:
+34
-4
@@ -581,6 +581,10 @@
|
|||||||
<label for="f-author">Autor / fotógrafo</label>
|
<label for="f-author">Autor / fotógrafo</label>
|
||||||
<select id="f-author"><option value="">todos</option></select>
|
<select id="f-author"><option value="">todos</option></select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="f-row">
|
||||||
|
<label for="f-subject">Assunto</label>
|
||||||
|
<select id="f-subject"><option value="">todos</option></select>
|
||||||
|
</div>
|
||||||
<div class="f-row">
|
<div class="f-row">
|
||||||
<label for="f-type">Tipo de suporte</label>
|
<label for="f-type">Tipo de suporte</label>
|
||||||
<select id="f-type"><option value="">todos</option></select>
|
<select id="f-type"><option value="">todos</option></select>
|
||||||
@@ -1399,9 +1403,14 @@ function cleanAuthor(raw) {
|
|||||||
// same person, different word order or accents → same key
|
// 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(' ');
|
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) {
|
function setupFilters(mapData) {
|
||||||
const entries = Object.values(mapData.map);
|
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;
|
let minYear = Infinity, maxYear = -Infinity;
|
||||||
|
|
||||||
entries.forEach(e => {
|
entries.forEach(e => {
|
||||||
@@ -1409,6 +1418,10 @@ function setupFilters(mapData) {
|
|||||||
if (meta.community) instCounts.set(meta.community, (instCounts.get(meta.community) || 0) + 1);
|
if (meta.community) instCounts.set(meta.community, (instCounts.get(meta.community) || 0) + 1);
|
||||||
const t = cleanType(meta.type);
|
const t = cleanType(meta.type);
|
||||||
if (t) typeCounts.set(t, (typeCounts.get(t) || 0) + 1);
|
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);
|
const a = cleanAuthor(meta.contributor);
|
||||||
if (a) {
|
if (a) {
|
||||||
const k = authorKey(a), g = authorGroups.get(k) || { n: 0, forms: new Map() };
|
const k = authorKey(a), g = authorGroups.get(k) || { n: 0, forms: new Map() };
|
||||||
@@ -1446,6 +1459,18 @@ function setupFilters(mapData) {
|
|||||||
selAuthor.appendChild(opt);
|
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 decadeMin = Math.floor(minYear / 10) * 10;
|
||||||
const decadeMax = Math.floor(maxYear / 10) * 10;
|
const decadeMax = Math.floor(maxYear / 10) * 10;
|
||||||
const nDecades = (decadeMax - decadeMin) / 10 + 1;
|
const nDecades = (decadeMax - decadeMin) / 10 + 1;
|
||||||
@@ -1477,6 +1502,7 @@ function setupFilters(mapData) {
|
|||||||
const a = cleanAuthor(meta.contributor);
|
const a = cleanAuthor(meta.contributor);
|
||||||
m.userData._author = a ? authorKey(a) : '';
|
m.userData._author = a ? authorKey(a) : '';
|
||||||
m.userData._type = cleanType(meta.type);
|
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
|
// 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
|
// 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)
|
// searchable (people paste a handle or its number straight into the box)
|
||||||
@@ -1501,7 +1527,7 @@ function setupFilters(mapData) {
|
|||||||
bars.push(bar);
|
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() {
|
function resetYear() {
|
||||||
state.yearTouched = false;
|
state.yearTouched = false;
|
||||||
@@ -1523,6 +1549,7 @@ function setupFilters(mapData) {
|
|||||||
(!state.institution || meta.community === state.institution) &&
|
(!state.institution || meta.community === state.institution) &&
|
||||||
(!state.type || d._type === state.type) &&
|
(!state.type || d._type === state.type) &&
|
||||||
(!state.author || d._author === state.author) &&
|
(!state.author || d._author === state.author) &&
|
||||||
|
(!state.subject || d._subjects.has(state.subject)) &&
|
||||||
terms.every(t => d._hay.includes(t));
|
terms.every(t => d._hay.includes(t));
|
||||||
if (okRest && d._year != null) {
|
if (okRest && d._year != null) {
|
||||||
const i = Math.floor((d._year - decadeMin) / 10);
|
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.institution) out.push({ key: 'institution', text: state.institution });
|
||||||
if (state.yearTouched) out.push({ key: 'year', text: yearLabel(state.yearLo, state.yearHi) });
|
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.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 });
|
if (state.type) out.push({ key: 'type', text: state.type });
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@@ -1591,6 +1619,7 @@ function setupFilters(mapData) {
|
|||||||
if (key === 'search') { state.search = ''; searchInput.value = ''; }
|
if (key === 'search') { state.search = ''; searchInput.value = ''; }
|
||||||
if (key === 'institution') { state.institution = ''; selInst.value = ''; }
|
if (key === 'institution') { state.institution = ''; selInst.value = ''; }
|
||||||
if (key === 'type') { state.type = ''; selType.value = ''; }
|
if (key === 'type') { state.type = ''; selType.value = ''; }
|
||||||
|
if (key === 'subject') { state.subject = ''; selSubject.value = ''; }
|
||||||
if (key === 'author') { state.author = ''; selAuthor.value = ''; }
|
if (key === 'author') { state.author = ''; selAuthor.value = ''; }
|
||||||
if (key === 'year') resetYear();
|
if (key === 'year') resetYear();
|
||||||
apply();
|
apply();
|
||||||
@@ -1632,6 +1661,7 @@ function setupFilters(mapData) {
|
|||||||
});
|
});
|
||||||
searchX.addEventListener('click', () => { clearTimeout(searchTimer); clearOne('search'); searchInput.focus(); });
|
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(); });
|
selAuthor.addEventListener('change', () => { state.author = selAuthor.value; apply(); });
|
||||||
|
|
||||||
function onYear(e) {
|
function onYear(e) {
|
||||||
@@ -1651,8 +1681,8 @@ function setupFilters(mapData) {
|
|||||||
|
|
||||||
clearBtn.addEventListener('click', () => {
|
clearBtn.addEventListener('click', () => {
|
||||||
clearTimeout(searchTimer);
|
clearTimeout(searchTimer);
|
||||||
state.search = ''; state.institution = ''; state.type = ''; state.author = '';
|
state.search = ''; state.institution = ''; state.type = ''; state.author = ''; state.subject = '';
|
||||||
searchInput.value = ''; selInst.value = ''; selType.value = ''; selAuthor.value = '';
|
searchInput.value = ''; selInst.value = ''; selType.value = ''; selAuthor.value = ''; selSubject.value = '';
|
||||||
resetYear();
|
resetYear();
|
||||||
apply();
|
apply();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user