Localize topógrafos e técnicos de cadastro por nome ou concelho utilizando as caixas de pesquisa. Pode também clicar em “Perto de mim” para centrar o mapa no local onde está.
Na lista à esquerda, clique num membro para ver a localização no mapa.
No mapa, clique num marcador para ver os dados de contacto.
Sem resultados.
`;
} else {
Object.keys(byC).sort().forEach(c=>{
const arr = byC[c];
html += `${escapeHtml(c)} (${arr.length})
`; arr.forEach(m=>{ const email = m.email ? String(m.email) : ''; const phone = m.telemovel ? String(m.telemovel) : ''; const phoneClean = cleanTel(phone); html += `${escapeHtml(m.nome||'')}
`+
(email ? `` : ``) +
(phone ? `` : ``) +
`
${currentFiltered.length} Topógrafo${currentFiltered.length===1?'':'s'} na rede
`;
}
iframeWrite(baseIframeHtml(html));
const doc = iframe.contentDocument || iframe.contentWindow.document;
doc.querySelectorAll('.item').forEach(el=>{
el.addEventListener('click', ()=>{
const id = parseInt(el.getAttribute('data-id'),10);
const m = all.find(x=>x._id===id);
if (m) map.setView([m._lat,m._lng], Math.max(map.getZoom(), 11), {animate:true});
});
});
}
// Helper: concelho selecionado (case-insensitive → devolve o label oficial ou '')
function getSelectedConcelho(){
const val = (concelhoInput.value || '').trim().toLowerCase();
if (!val) return '';
const g = groups.find(x => String(x.concelho).toLowerCase() === val);
return g ? g.concelho : '';
}
// LISTA depende de Nome e Concelho selecionado
let currentFiltered = [];
function recomputeList(){
const fSearch = (document.getElementById('filter-search').value || '');
const nameTerms = normalizeStr(fSearch).split(' ').filter(Boolean);
const concelhoSel = getSelectedConcelho(); // '' se não houver seleção válida
currentFiltered = all.filter(m=>{
if (concelhoSel && m._concelho !== concelhoSel) return false;
if (nameTerms.length){
const hay = normalizeStr(m.nome||'');
for (let t of nameTerms){ if (!hay.includes(t)) return false; }
}
return true;
});
if (currentFiltered.length === 0) renderIframeEmpty(); else renderIframeList();
}
// ——— Autocomplete de Concelho (só recentra + filtra lista) ———
let acIndex = -1;
let acOpen = false;
function acBuildList() {
const needle = (concelhoInput.value || '').toLowerCase().trim();
const set = new Set();
groups.forEach(g => {
const name = String(g.concelho);
if (!needle || name.toLowerCase().includes(needle)) set.add(name);
});
const arr = Array.from(set).sort();
if (arr.length === 0) {
acMenu.innerHTML = 'Sem correspondências
';
} else {
acMenu.innerHTML = arr.map((name) =>
''+escapeHtml(name)+'
'
).join('');
}
acMenu.querySelectorAll('.opt[role="option"]').forEach((el) => {
el.addEventListener('mousedown', (ev) => {
ev.preventDefault();
acSelect(el.getAttribute('data-val'));
});
});
acIndex = -1;
}
function acOpenMenu() {
if (acOpen) return;
acOpen = true;
acMenu.style.display = 'block';
concelhoInput.setAttribute('aria-expanded', 'true');
acBuildList();
}
function acCloseMenu() {
if (!acOpen) return;
acOpen = false;
acMenu.style.display = 'none';
concelhoInput.setAttribute('aria-expanded', 'false');
}
function acFocus(idx) {
acMenu.querySelectorAll('.opt[aria-selected="true"]').forEach(el=>el.setAttribute('aria-selected','false'));
const els = acMenu.querySelectorAll('.opt[role="option"]');
if (!els.length) return;
if (idx = els.length) idx = els.length - 1;
acIndex = idx;
const el = els[acIndex];
el.setAttribute('aria-selected','true');
el.scrollIntoView({ block:'nearest' });
}
function acSelect(name) {
concelhoInput.value = name || '';
acCloseMenu();
const c = concelhoToCoords[name];
if (c) map.setView([c.lat, c.lng], Math.max(map.getZoom(), 10), {animate:true});
recomputeList(); // {
clearTimeout(acTimer);
acTimer = setTimeout(() => {
if (!acOpen) acOpenMenu(); else acBuildList();
}, 100);
});
concelhoInput.addEventListener('keydown', (e) => {
if (!acOpen && (e.key === 'ArrowDown' || e.key === 'ArrowUp')) {
acOpenMenu(); e.preventDefault(); return;
}
switch (e.key) {
case 'ArrowDown': acFocus((acIndex { setTimeout(()=>{ acCloseMenu(); recomputeList(); }, 150); });
concelhoClearBtn.addEventListener('click', () => {
concelhoInput.value = '';
acCloseMenu();
recomputeList(); // limpar → repõe lista (considerando pesquisa de nome)
});
// Pesquisa por Nome → só a LISTA
let searchTimer;
searchInput.addEventListener('input', ()=>{
clearTimeout(searchTimer);
searchTimer = setTimeout(()=>recomputeList(), 160);
});
// Perto de mim (geolocalização) → apenas recentrar
nearBtn.addEventListener('click', ()=>{
if (!navigator.geolocation) { alert('Geolocalização não suportada.'); return; }
nearBtn.disabled = true;
navigator.geolocation.getCurrentPosition((pos)=>{
const latlng = [pos.coords.latitude, pos.coords.longitude];
if (window._userMarker) map.removeLayer(window._userMarker);
if (window._userCircle) map.removeLayer(window._userCircle);
window._userMarker = L.circleMarker(latlng, { radius:6, weight:2, color:'#2563eb', fillColor:'#2563eb', fillOpacity:0.7 }).addTo(map);
window._userCircle = L.circle(latlng, { radius: 15000, weight:1, color:'#2563eb', fillOpacity:0.05 }).addTo(map);
map.setView(latlng, Math.max(map.getZoom(), 11), {animate:true});
nearBtn.disabled = false;
}, (err)=>{
alert('Não foi possível obter localização ('+err.message+').');
nearBtn.disabled = false;
}, { enableHighAccuracy:true, timeout:8000, maximumAge:0 });
});
// INIT
map.setView(initialCenter, initialZoom);
currentFiltered = all.slice(); // lista completa ao abrir
renderIframeList();
})();