@@ -305,6 +305,23 @@
|
||||
|
||||
const normalize = s => (s||'').toString().toLowerCase();
|
||||
const debounce = (fn, wait=200) => { let t; return (...args)=>{ clearTimeout(t); t=setTimeout(()=>fn(...args), wait); }; };
|
||||
const openFamilyResult = (type, id) => {
|
||||
const params = {};
|
||||
if (type === 'student') {
|
||||
params.student_id = id;
|
||||
} else if (type === 'guardian') {
|
||||
params.guardian_id = id;
|
||||
}
|
||||
if (Object.keys(params).length && typeof window.openFamilyCard === 'function') {
|
||||
window.openFamilyCard(params);
|
||||
return;
|
||||
}
|
||||
if (type === 'student') {
|
||||
window.location.href = '<?= site_url('family') ?>' + '?student_id=' + encodeURIComponent(id);
|
||||
} else if (type === 'guardian') {
|
||||
window.location.href = '<?= site_url('family') ?>' + '?guardian_id=' + encodeURIComponent(id);
|
||||
}
|
||||
};
|
||||
|
||||
// Preloaded datasets for suggestions (students + guardians)
|
||||
const STATIC_ITEMS = [
|
||||
@@ -368,12 +385,7 @@
|
||||
btn.className = 'list-group-item list-group-item-action';
|
||||
btn.innerHTML = `<div class="d-flex justify-content-between"><span>${(it.label||'').replace(/</g,'<')}</span><span class="text-muted small">${(it.sub||'').replace(/</g,'<')}</span></div>`;
|
||||
btn.addEventListener('click', () => {
|
||||
// Redirect to show only the selected family
|
||||
if (it.type === 'student') {
|
||||
window.location.href = '<?= site_url('family') ?>' + '?student_id=' + encodeURIComponent(it.id);
|
||||
} else if (it.type === 'guardian') {
|
||||
window.location.href = '<?= site_url('family') ?>' + '?guardian_id=' + encodeURIComponent(it.id);
|
||||
}
|
||||
openFamilyResult(it.type, it.id);
|
||||
});
|
||||
suggest.appendChild(btn);
|
||||
});
|
||||
@@ -455,7 +467,7 @@
|
||||
}
|
||||
if (best) {
|
||||
e.preventDefault();
|
||||
window.location.href = '<?= site_url('family') ?>' + '?student_id=' + encodeURIComponent(best.value);
|
||||
openFamilyResult('student', best.value);
|
||||
}
|
||||
});
|
||||
// Hide suggestions on outside click
|
||||
|
||||
@@ -153,6 +153,13 @@
|
||||
/* Prevent horizontal scrollbars from stray overflows */
|
||||
html, body { overflow-x: hidden; }
|
||||
|
||||
#familyCardModal .family-card-modal-dialog {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
#familyCardModal .modal-content {
|
||||
max-height: calc(100vh - 2rem);
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
@@ -237,7 +244,7 @@ html, body { overflow-x: hidden; }
|
||||
|
||||
<!-- Family Card Modal -->
|
||||
<div class="modal fade" id="familyCardModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-xl modal-dialog-scrollable">
|
||||
<div class="modal-dialog modal-xl modal-dialog-scrollable family-card-modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Family</h5>
|
||||
@@ -312,33 +319,60 @@ html, body { overflow-x: hidden; }
|
||||
}
|
||||
window.openFamilyCard = loadFamilyCard;
|
||||
|
||||
document.addEventListener('click', function(e){
|
||||
const link = e.target.closest('[data-family-student-id], [data-family-guardian-id], [data-family-id]');
|
||||
if (!link) return;
|
||||
e.preventDefault();
|
||||
const sid = link.getAttribute('data-family-student-id');
|
||||
const gid = link.getAttribute('data-family-guardian-id');
|
||||
const fid = link.getAttribute('data-family-id');
|
||||
function familyParamsFromTarget(target) {
|
||||
const link = target.closest('[data-family-student-id], [data-family-guardian-id], [data-family-id], a[href]');
|
||||
if (!link) return null;
|
||||
let sid = link.getAttribute('data-family-student-id');
|
||||
let gid = link.getAttribute('data-family-guardian-id');
|
||||
let fid = link.getAttribute('data-family-id');
|
||||
if (!sid && !gid && !fid && link.matches('a[href]')) {
|
||||
try {
|
||||
const url = new URL(link.getAttribute('href'), window.location.origin);
|
||||
const familyPath = new URL('<?= site_url('family') ?>', window.location.origin).pathname.replace(/\/+$/, '');
|
||||
const linkPath = url.pathname.replace(/\/+$/, '');
|
||||
if (url.origin !== window.location.origin || linkPath !== familyPath) return null;
|
||||
sid = url.searchParams.get('student_id');
|
||||
gid = url.searchParams.get('guardian_id');
|
||||
fid = url.searchParams.get('family_id');
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
const params = {};
|
||||
if (fid) params.family_id = fid;
|
||||
else if (sid) params.student_id = sid;
|
||||
else if (gid) params.guardian_id = gid;
|
||||
if (Object.keys(params).length) loadFamilyCard(params);
|
||||
});
|
||||
return Object.keys(params).length ? params : null;
|
||||
}
|
||||
|
||||
document.addEventListener('click', function(e){
|
||||
const link = e.target.closest('[data-family-student-id], [data-family-guardian-id], [data-family-id]');
|
||||
if (!link) return;
|
||||
function handleFamilyCardClick(e) {
|
||||
const params = familyParamsFromTarget(e.target);
|
||||
if (!params) return;
|
||||
if (e.familyCardHandled) return;
|
||||
e.familyCardHandled = true;
|
||||
e.preventDefault();
|
||||
const sid = link.getAttribute('data-family-student-id');
|
||||
const gid = link.getAttribute('data-family-guardian-id');
|
||||
const fid = link.getAttribute('data-family-id');
|
||||
const params = {};
|
||||
if (fid) params.family_id = fid;
|
||||
else if (sid) params.student_id = sid;
|
||||
else if (gid) params.guardian_id = gid;
|
||||
if (Object.keys(params).length) loadFamilyCard(params);
|
||||
}, true);
|
||||
loadFamilyCard(params);
|
||||
}
|
||||
|
||||
document.addEventListener('click', handleFamilyCardClick);
|
||||
document.addEventListener('click', handleFamilyCardClick, true);
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function(){
|
||||
try {
|
||||
const current = new URL(window.location.href);
|
||||
const familyPath = new URL('<?= site_url('family') ?>', window.location.origin).pathname.replace(/\/+$/, '');
|
||||
const currentPath = current.pathname.replace(/\/+$/, '');
|
||||
if (currentPath !== familyPath) return;
|
||||
const sid = current.searchParams.get('student_id');
|
||||
const gid = current.searchParams.get('guardian_id');
|
||||
const fid = current.searchParams.get('family_id');
|
||||
const params = {};
|
||||
if (fid) params.family_id = fid;
|
||||
else if (sid) params.student_id = sid;
|
||||
else if (gid) params.guardian_id = gid;
|
||||
if (Object.keys(params).length) loadFamilyCard(params);
|
||||
} catch (_) {}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
|
||||
@@ -274,6 +274,12 @@
|
||||
}
|
||||
.card-header { background-color: #f0f7ff; }
|
||||
.form-text { color: var(--mgmt-muted); }
|
||||
#familyCardModal .family-card-modal-dialog {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
#familyCardModal .modal-content {
|
||||
max-height: calc(100vh - 2rem);
|
||||
}
|
||||
</style>
|
||||
<?= $this->renderSection('styles') ?>
|
||||
</head>
|
||||
@@ -295,7 +301,7 @@
|
||||
|
||||
<!-- Family Card Modal -->
|
||||
<div class="modal fade" id="familyCardModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-xl modal-dialog-scrollable">
|
||||
<div class="modal-dialog modal-xl modal-dialog-scrollable family-card-modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Family</h5>
|
||||
@@ -594,36 +600,63 @@
|
||||
// Expose for programmatic usage
|
||||
window.openFamilyCard = loadFamilyCard;
|
||||
|
||||
// Bubble-phase handler (general)
|
||||
document.addEventListener('click', function(e){
|
||||
const link = e.target.closest('[data-family-student-id], [data-family-guardian-id], [data-family-id]');
|
||||
if (!link) return;
|
||||
e.preventDefault();
|
||||
const sid = link.getAttribute('data-family-student-id');
|
||||
const gid = link.getAttribute('data-family-guardian-id');
|
||||
const fid = link.getAttribute('data-family-id');
|
||||
function familyParamsFromTarget(target) {
|
||||
const link = target.closest('[data-family-student-id], [data-family-guardian-id], [data-family-id], a[href]');
|
||||
if (!link) return null;
|
||||
let sid = link.getAttribute('data-family-student-id');
|
||||
let gid = link.getAttribute('data-family-guardian-id');
|
||||
let fid = link.getAttribute('data-family-id');
|
||||
if (!sid && !gid && !fid && link.matches('a[href]')) {
|
||||
try {
|
||||
const url = new URL(link.getAttribute('href'), window.location.origin);
|
||||
const familyPath = new URL('<?= site_url('family') ?>', window.location.origin).pathname.replace(/\/+$/, '');
|
||||
const linkPath = url.pathname.replace(/\/+$/, '');
|
||||
if (url.origin !== window.location.origin || linkPath !== familyPath) return null;
|
||||
sid = url.searchParams.get('student_id');
|
||||
gid = url.searchParams.get('guardian_id');
|
||||
fid = url.searchParams.get('family_id');
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
const params = {};
|
||||
if (fid) params.family_id = fid;
|
||||
else if (sid) params.student_id = sid;
|
||||
else if (gid) params.guardian_id = gid;
|
||||
if (Object.keys(params).length) loadFamilyCard(params);
|
||||
});
|
||||
return Object.keys(params).length ? params : null;
|
||||
}
|
||||
|
||||
function handleFamilyCardClick(e) {
|
||||
const params = familyParamsFromTarget(e.target);
|
||||
if (!params) return;
|
||||
if (e.familyCardHandled) return;
|
||||
e.familyCardHandled = true;
|
||||
e.preventDefault();
|
||||
loadFamilyCard(params);
|
||||
}
|
||||
|
||||
// Bubble-phase handler (general)
|
||||
document.addEventListener('click', handleFamilyCardClick);
|
||||
|
||||
// Capture-phase safety net so components that stop propagation (e.g., DataTables) don't block us
|
||||
document.addEventListener('click', function(e){
|
||||
const link = e.target.closest('[data-family-student-id], [data-family-guardian-id], [data-family-id]');
|
||||
if (!link) return;
|
||||
// If already prevented by other handler, still proceed
|
||||
e.preventDefault();
|
||||
const sid = link.getAttribute('data-family-student-id');
|
||||
const gid = link.getAttribute('data-family-guardian-id');
|
||||
const fid = link.getAttribute('data-family-id');
|
||||
const params = {};
|
||||
if (fid) params.family_id = fid;
|
||||
else if (sid) params.student_id = sid;
|
||||
else if (gid) params.guardian_id = gid;
|
||||
if (Object.keys(params).length) loadFamilyCard(params);
|
||||
}, true);
|
||||
document.addEventListener('click', handleFamilyCardClick, true);
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function(){
|
||||
try {
|
||||
const current = new URL(window.location.href);
|
||||
const familyPath = new URL('<?= site_url('family') ?>', window.location.origin).pathname.replace(/\/+$/, '');
|
||||
const currentPath = current.pathname.replace(/\/+$/, '');
|
||||
if (currentPath !== familyPath) return;
|
||||
const sid = current.searchParams.get('student_id');
|
||||
const gid = current.searchParams.get('guardian_id');
|
||||
const fid = current.searchParams.get('family_id');
|
||||
const params = {};
|
||||
if (fid) params.family_id = fid;
|
||||
else if (sid) params.student_id = sid;
|
||||
else if (gid) params.guardian_id = gid;
|
||||
if (Object.keys(params).length) loadFamilyCard(params);
|
||||
} catch (_) {}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user