VII WERMELINGER-FEST
Encontro da Família Wermelinger
Pesqueiro Portal do Vale — Duas Barras, RJ
26 de julho de 2009
= 2; });
if (terms.length === 0) return escapeHtml(text);
var safe = escapeHtml(text); var safeNoDiac = removeDiacritics(safe).toLowerCase(); var ranges = [];
terms.forEach(function (term) { var t = removeDiacritics(term).toLowerCase(); var pos = 0; while ((pos = safeNoDiac.indexOf(t, pos)) !== -1) { ranges.push([pos, pos + t.length]); pos += t.length; } });
if (ranges.length === 0) return safe;
ranges.sort(function (a, b) { return a[0] - b[0]; });
var merged = [ranges[0]];
for (var i = 1; i < ranges.length; i++) { var last = merged[merged.length - 1]; if (ranges[i][0] <= last[1]) { last[1] = Math.max(last[1], ranges[i][1]); } else { merged.push(ranges[i]); } }
var out = ''; var cursor = 0;
merged.forEach(function (r) { out += safe.slice(cursor, r[0]) + '' + safe.slice(r[0], r[1]) + ''; cursor = r[1]; });
out += safe.slice(cursor); return out;
}
function makeSnippet(text, query, length) { text = stripHtml(text); if (!query) return text.slice(0, length) + (text.length > length ? '\u2026' : ''); var firstTerm = query.split(/\s+/)[0]; if (!firstTerm) return text.slice(0, length); var noDiacText = removeDiacritics(text).toLowerCase(); var idx = noDiacText.indexOf(removeDiacritics(firstTerm).toLowerCase()); if (idx === -1) { return text.slice(0, length) + (text.length > length ? '\u2026' : ''); } var start = Math.max(0, idx - 40); var end = Math.min(text.length, idx + length - 40); return (start > 0 ? '\u2026' : '') + text.slice(start, end) + (end < text.length ? '\u2026' : ''); }
function debounce(fn, ms) { return function () { var args = arguments, ctx = this; clearTimeout(state.debounceTimer); state.debounceTimer = setTimeout(function () { fn.apply(ctx, args); }, ms); }; }
function parseFeedEntry(entry) { var title = (entry.title && entry.title.$t) || ''; var url = ''; if (entry.link) { for (var i = 0; i < entry.link.length; i++) { if (entry.link[i].rel === 'alternate') { url = entry.link[i].href; break; } } } var content = ''; if (entry.content && entry.content.$t) content = entry.content.$t; else if (entry.summary && entry.summary.$t) content = entry.summary.$t; var published = (entry.published && entry.published.$t) || ''; var year = published ? published.substring(0, 4) : ''; var labels = []; if (entry.category) { for (var j = 0; j < entry.category.length; j++) { if (entry.category[j].term) labels.push(entry.category[j].term); } } return { id: (entry.id && entry.id.$t) || url, title: title, url: url, content: stripHtml(content), published: published, year: year, labels: labels }; }
function fetchFeed() { return fetch(CONFIG.feedUrl, { credentials: 'omit' }).then(function (r) { if (!r.ok) throw new Error('Feed HTTP ' + r.status); return r.json(); }).then(function (json) { if (!json.feed || !json.feed.entry) return []; return json.feed.entry.map(parseFeedEntry).filter(function (d) { return d.title && d.url; }); }); }
function loadCache() { try { var raw = sessionStorage.getItem(CONFIG.cacheKey); if (!raw) return null; var data = JSON.parse(raw); if (!data.ts || (Date.now() - data.ts) > CONFIG.cacheTTL) return null; return data.docs; } catch (e) { return null; } }
function saveCache(docs) { try { sessionStorage.setItem(CONFIG.cacheKey, JSON.stringify({ ts: Date.now(), docs: docs })); } catch (e) {} }
function buildIndex(docs) { return lunr(function () { if (lunr.multiLanguage && lunr.pt && lunr.de) { this.use(lunr.multiLanguage('en', 'pt', 'de')); } else if (lunr.pt) { this.use(lunr.pt); } this.ref('id'); this.field('title', { boost: 10 }); this.field('labels', { boost: 5 }); this.field('content'); var self = this; docs.forEach(function (doc) { self.add({ id: doc.id, title: doc.title, labels: doc.labels.join(' '), content: doc.content }); }); }); }
function populateFilters(docs) { var years = {}; var labels = {}; docs.forEach(function (d) { if (d.year) years[d.year] = (years[d.year] || 0) + 1; d.labels.forEach(function (l) { labels[l] = (labels[l] || 0) + 1; }); }); var sortedYears = Object.keys(years).sort().reverse(); var sortedLabels = Object.keys(labels).sort(); sortedYears.forEach(function (y) { var opt = document.createElement('option'); opt.value = y; opt.textContent = y + ' (' + years[y] + ')'; $filterY.appendChild(opt); }); sortedLabels.forEach(function (l) { var opt = document.createElement('option'); opt.value = l; opt.textContent = l + ' (' + labels[l] + ')'; $filterL.appendChild(opt); }); }
function ensureIndex() { if (state.isReady) return Promise.resolve(); if (state.isBuilding) { return new Promise(function (resolve) { var check = setInterval(function () { if (state.isReady) { clearInterval(check); resolve(); } }, 50); }); } state.isBuilding = true; setStatus(t('search_loading'), true); var cached = loadCache(); var docsPromise = cached ? Promise.resolve(cached) : fetchFeed().then(function (docs) { saveCache(docs); return docs; }); return docsPromise.then(function (docs) { state.docs = docs; state.idx = buildIndex(docs); populateFilters(docs); state.isReady = true; state.isBuilding = false; setStatus(docs.length + ' ' + t('search_indexed_suffix'), false); setTimeout(function () { if (!$input.value) setStatus('', false); }, 2000); }).catch(function (err) { state.isBuilding = false; setStatus('', false); $results.innerHTML = '' + t('search_error') + '
'; }); }
function setStatus(msg, loading) { $status.textContent = msg || ''; $status.classList.toggle('is-loading', !!loading); }
function t(key) { var lang = window.WM_CURRENT_LANG || 'pt'; var dict = (window.WM_I18N && window.WM_I18N[lang]) || {}; return dict[key] !== undefined ? dict[key] : key; }
function buildLunrQuery(raw) { var tokens = raw.split(/\s+/).filter(Boolean); return tokens.map(function (t) { var clean = t.replace(/[+\-^~*"():]/g, ''); if (!clean) return ''; return clean + '* ' + clean + '~1'; }).filter(Boolean).join(' '); }
function performSearch(query) { var hasQuery = query && query.length >= CONFIG.minQueryLength; var hasFilter = $filterY.value || $filterL.value; if (!hasQuery && !hasFilter) { $results.innerHTML = ''; setStatus('', false); $wrapper.classList.remove('has-query'); return; } $wrapper.classList.add('has-query'); ensureIndex().then(function () { if (!state.isReady) return; var hits = []; if (hasQuery) { try { var lunrQuery = buildLunrQuery(query); var raw = state.idx.search(lunrQuery); hits = raw.map(function (r) { var doc = state.docs.find(function (d) { return d.id === r.ref; }); return doc ? { doc: doc, score: r.score } : null; }).filter(Boolean); } catch (e) { var qLow = removeDiacritics(query).toLowerCase(); hits = state.docs.filter(function (d) { return removeDiacritics(d.title + ' ' + d.content).toLowerCase().indexOf(qLow) !== -1; }).map(function (d) { return { doc: d, score: 1 }; }); } } else { hits = state.docs.map(function (d) { return { doc: d, score: 0 }; }); } hits = hits.filter(function (h) { if ($filterY.value && h.doc.year !== $filterY.value) return false; if ($filterL.value && h.doc.labels.indexOf($filterL.value) === -1) return false; return true; }); renderResults(hits, query); }); }
function renderResults(hits, query) { if (hits.length === 0) { $results.innerHTML = '' + t('search_no_results') + '
'; setStatus('', false); return; } var top = hits.slice(0, CONFIG.maxResults); var html = top.map(function (h) { var d = h.doc; var snippet = makeSnippet(d.content, query || '', CONFIG.snippetLength); var labelHtml = d.labels.length ? d.labels.slice(0, 2).join(' \u00b7 ') : ''; var metaParts = []; if (d.year) metaParts.push(d.year); if (labelHtml) metaParts.push(labelHtml); return '' + highlight(d.title, query) + '
' + (metaParts.length ? '' + escapeHtml(metaParts.join(' \u00b7 ')) + '
' : '') + '' + highlight(snippet, query) + '
'; }).join(''); if (hits.length > CONFIG.maxResults && query) { html += '
' + t('search_view_all_prefix') + ' ' + hits.length + ' ' + t('search_view_all_suffix') + '
'; } $results.innerHTML = html; setStatus(hits.length + ' ' + (hits.length === 1 ? t('search_result_singular') : t('search_results_suffix')), false); }
// Hook chamado quando idioma muda
window.wmSearchOnLangChange = function (newLang) {
// Atualiza o option default dos selects
if ($filterY && $filterY.options[0]) $filterY.options[0].textContent = t('search_filter_year_all');
if ($filterL && $filterL.options[0]) $filterL.options[0].textContent = t('search_filter_label_all');
// Re-renderiza resultados se houver
if ($input && ($input.value.trim() || $filterY.value || $filterL.value)) { performSearch($input.value.trim()); }
};
var debouncedSearch = debounce(function () { performSearch($input.value.trim()); }, CONFIG.debounceMs);
$input.addEventListener('input', debouncedSearch);
$input.addEventListener('focus', function () { ensureIndex(); });
$clear.addEventListener('click', function () { $input.value = ''; $filterY.value = ''; $filterL.value = ''; performSearch(''); $input.focus(); });
$filterY.addEventListener('change', function () { performSearch($input.value.trim()); });
$filterL.addEventListener('change', function () { performSearch($input.value.trim()); });
$input.addEventListener('keydown', function (e) { if (e.key === 'Enter') { e.preventDefault(); var q = $input.value.trim(); if (q.length >= CONFIG.minQueryLength) { window.location.href = CONFIG.searchPagePath + encodeURIComponent(q); } } if (e.key === 'Escape') { $input.value = ''; performSearch(''); } });
})();
//]]>