update besar besaran

This commit is contained in:
TigerStable
2026-06-12 16:36:31 +07:00
parent 515c830342
commit 017fe392bc
63 changed files with 4219 additions and 75 deletions
+18
View File
@@ -0,0 +1,18 @@
'use strict';
/* ═══════════════════════════════════════════════════════════
1. HELPERS
═══════════════════════════════════════════════════════════ */
const H = {
uid: () => Math.random().toString(36).slice(2,9) + Date.now().toString(36),
esc: s => String(s||'').replace(/[&<>"']/g, c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;'}[c])),
fmDist: m => m==null?'-': m>=1000? (m/1000).toFixed(2)+' km': Math.round(m).toLocaleString('id-ID')+' m',
fmArea: m => m==null?'-': m>=10000? (m/10000).toFixed(4)+' ha': Math.round(m).toLocaleString('id-ID')+' m²',
fmNum: n => (n||0).toLocaleString('id-ID'),
today: () => new Date().toISOString().slice(0,10),
geoLen: lls => { let t=0; for(let i=0;i<lls.length-1;i++) t+=lls[i].distanceTo(lls[i+1]); return Math.round(t); },
geoArea: lls => {
const R=6371008.8; let a=0,n=lls.length;
for(let i=0;i<n;i++){const j=(i+1)%n,φ1=lls[i].lat*Math.PI/180,φ2=lls[j].lat*Math.PI/180,=(lls[j].lng-lls[i].lng)*Math.PI/180;a+=*(2+Math.sin(φ1)+Math.sin(φ2));}
return Math.round(Math.abs(a*R*R/2));
},
};
+55
View File
@@ -0,0 +1,55 @@
/* ═══════════════════════════════════════════════════════════
2. STORAGE (MySQL API Version)
═══════════════════════════════════════════════════════════ */
const Store = (() => {
const API_URL = '../api/index.php';
let db = {
spbu: [],
jalan: [],
parsil: [],
warga: [],
rumahIbadah: []
};
const request = async (action, payload = {}) => {
try {
const res = await fetch(`${API_URL}?action=${action}`, {
method: action === 'alldb' ? 'GET' : 'POST',
headers: { 'Content-Type': 'application/json' },
body: action === 'alldb' ? null : JSON.stringify(payload)
});
return await res.json();
} catch (err) {
console.error('API Error:', err);
throw err;
}
};
return {
load: async () => {
try {
const data = await request('alldb');
if (data) db = { ...db, ...data };
} catch (e) {
console.error("Gagal load data dari server", e);
}
},
all: ln => db[ln]||[],
find: (ln,id) => (db[ln]||[]).find(r=>r.id===id)||null,
add: async (ln,rec) => {
db[ln].push(rec);
await request('add', { layer: ln, data: rec });
},
update: async (ln,id,patch) => {
const i=db[ln].findIndex(r=>r.id===id); if(i<0)return;
db[ln][i]={...db[ln][i],...patch};
await request('update', { layer: ln, id: id, patch: patch });
},
remove: async (ln,id) => {
db[ln]=db[ln].filter(r=>r.id!==id);
await request('remove', { layer: ln, id: id });
},
allDb: () => db,
};
})();
+9
View File
@@ -0,0 +1,9 @@
/* ═══════════════════════════════════════════════════════════
3. TOAST
═══════════════════════════════════════════════════════════ */
const Toast = {
_show(msg,type){ const c=document.getElementById('toasts'),el=document.createElement('div');
el.className=`toast ${type}`;el.innerHTML=`<span>${{success:'✓',error:'✕',info:''}[type]||''}</span>${H.esc(msg)}`;
c.appendChild(el);setTimeout(()=>{el.classList.add('out');el.addEventListener('animationend',()=>el.remove(),{once:true})},2800); },
success: m=>Toast._show(m,'success'), error: m=>Toast._show(m,'error'), info: m=>Toast._show(m,'info'),
};