// MSC Tracker — JS compartido entre todas las paginas const MSC_BASE = '/msc-api'; function mscUrl(path) { if (!path) return MSC_BASE + '/'; if (path.startsWith('http')) return path; return MSC_BASE + '/' + path.replace(/^\/+/, ''); } function toast(msg, type) { const t = document.getElementById('toast'); if (!t) { alert(msg); return; } t.textContent = msg; t.className = 'toast' + (type === 'error' ? ' error' : ''); setTimeout(() => t.classList.add('hidden'), 4000); } async function apiReq(path, opts) { opts = opts || {}; const r = await fetch(mscUrl(path), { ...opts, headers: { 'Content-Type': 'application/json', ...(opts.headers || {}) }, credentials: 'same-origin', }); if (r.status === 401) { window.location.href = MSC_BASE + '/login'; throw new Error('no auth'); } if (!r.ok) { const t = await r.text(); throw new Error(r.status + ': ' + t); } if (r.status === 204) return null; return r.json(); } async function logoutUser() { try { await apiReq('/api/logout', { method: 'POST' }); } catch (e) {} window.location.href = MSC_BASE + '/login'; } // Cambiar mi password (compartido en todas las paginas) function showChangePw() { document.getElementById('pw-modal').classList.remove('hidden'); setTimeout(() => document.getElementById('pw-old').focus(), 100); } function closePw(ev) { if (ev && ev.target !== ev.currentTarget) return; document.getElementById('pw-modal').classList.add('hidden'); document.getElementById('pw-old').value = ''; document.getElementById('pw-new').value = ''; document.getElementById('pw-new2').value = ''; document.getElementById('pw-err').textContent = ''; } async function submitChangePw() { const oldp = document.getElementById('pw-old').value; const newp = document.getElementById('pw-new').value; const newp2 = document.getElementById('pw-new2').value; const err = document.getElementById('pw-err'); err.textContent = ''; if (!oldp || !newp) { err.textContent = 'completá los dos campos'; return; } if (newp !== newp2) { err.textContent = 'los nuevos no coinciden'; return; } if (newp.length < 6) { err.textContent = 'minimo 6 chars'; return; } try { await apiReq('/api/me/password', { method: 'POST', body: JSON.stringify({ old_password: oldp, new_password: newp }) }); alert('cambiado. tu sesion actual se invalido, volve a entrar'); logoutUser(); } catch (e) { err.textContent = e.message; } } // Copy button (en code blocks) function copyCode(btn, text) { navigator.clipboard.writeText(text).then(() => { const orig = btn.textContent; btn.textContent = 'copiado!'; btn.classList.add('copied'); setTimeout(() => { btn.textContent = orig; btn.classList.remove('copied'); }, 1500); }).catch(err => { const ta = document.createElement('textarea'); ta.value = text; ta.style.position = 'fixed'; ta.style.opacity = '0'; document.body.appendChild(ta); ta.select(); try { document.execCommand('copy'); btn.textContent = 'copiado!'; setTimeout(() => btn.textContent = 'copiar', 1500); } catch (e) { btn.textContent = 'error'; } document.body.removeChild(ta); }); } // Lightweight app-like navigation: prefetch internal pages and soften full reloads. (function enhanceNavigationFeel() { const prefetched = new Set(); function isInternalPageLink(a) { if (!a || !a.href || a.target === '_blank' || a.hasAttribute('download')) return false; const u = new URL(a.href, window.location.href); if (u.origin !== window.location.origin) return false; if (u.hash && u.pathname === window.location.pathname) return false; return true; } function prefetch(a) { if (!isInternalPageLink(a)) return; const u = new URL(a.href, window.location.href); const key = u.pathname + u.search; if (prefetched.has(key)) return; prefetched.add(key); const l = document.createElement('link'); l.rel = 'prefetch'; l.href = u.href; l.as = 'document'; document.head.appendChild(l); } document.addEventListener('mouseover', ev => { const a = ev.target.closest && ev.target.closest('a[href]'); if (a) prefetch(a); }, { passive: true }); document.addEventListener('touchstart', ev => { const a = ev.target.closest && ev.target.closest('a[href]'); if (a) prefetch(a); }, { passive: true }); document.addEventListener('click', ev => { const a = ev.target.closest && ev.target.closest('a[href]'); if (!isInternalPageLink(a)) return; if (ev.metaKey || ev.ctrlKey || ev.shiftKey || ev.altKey || ev.button !== 0) return; const u = new URL(a.href, window.location.href); if (u.pathname === window.location.pathname && u.search === window.location.search) return; ev.preventDefault(); document.documentElement.classList.add('page-leaving'); setTimeout(() => { window.location.href = u.href; }, 90); }); })();