Files
2026-05-16 13:44:12 -04:00

671 lines
44 KiB
PHP
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
// Options (can be moved to config or controller)
$medicalOptions = $medicalOptions ?? [
"None",
"ADHD (Attention-Deficit/Hyperactivity Disorder)",
"Anxiety or Emotional Disorders",
"Asthma",
"Autism Spectrum Disorder (ASD)",
"Behavioral or Conduct Disorders",
"Blindness / Vision Impairment",
"Celiac Disease (Gluten Intolerance)",
"Cerebral Palsy",
"Cystic Fibrosis",
"Depression",
"Diabetes (Type 1 or Type 2)",
"Down Syndrome",
"Dyslexia or Learning Disabilities",
"Eating Disorders",
"Eczema / Severe Skin Conditions",
"Epilepsy / Seizure Disorders",
"Hearing Impairments / Deafness",
"Heart Conditions (congenital or acquired)",
"Hemophilia / Bleeding Disorders",
"Kidney Disease",
"Migraines / Chronic Headaches",
"Obsessive-Compulsive Disorder (OCD)",
"Physical Disabilities / Mobility Impairments",
"PTSD (Post-Traumatic Stress Disorder)",
"Sickle Cell Anemia",
"Speech and Language Disorders",
"Thyroid Disorders",
"Tourette Syndrome",
"Traumatic Brain Injury (TBI)",
"Rheumatic diseases",
"Ulcerative Colitis / Crohns Disease",
"Other"
];
$allergyOptions = $allergyOptions ?? [
"None",
"Animal Dander (cats, dogs, etc.)",
"Antibiotics",
"Bee stings",
"Cockroach",
"Corn",
"Dust Mites",
"Egg",
"Fire ant stings",
"Fish",
"Fragrances / Perfumes",
"Latex",
"Milk / Dairy",
"Mold",
"Mosquito bites",
"Peanut",
"Pollen (grass, tree, weed)",
"Sesame",
"Shellfish (shrimp, crab, lobster, etc.)",
"Soy",
"Tree Nuts (almond, cashew, walnut, etc.)",
"Wasp stings",
"Wheat / Gluten",
"Other"
];
$gradeOptions = $gradeOptions ?? ['KG', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', 'Youth'];
?>
<?= $this->extend('layout/management_layout') ?>
<?= $this->section('content') ?>
<div class="container-fluid">
<div class="wrapper">
<div class="content">
<h2 class="text-center mt-4 mb-3">Student Profiles</h2>
<div class="table-responsive">
<table id="myTable" class="table table-striped table-hover align-middle">
<thead class="table-dark">
<tr>
<th>School ID</th>
<th>First Name</th>
<th>Last Name</th>
<th>DOB</th>
<th>Age</th>
<th>Gender</th>
<th>Assigned Grade</th>
<th>Active</th>
<th>Medical Conditions</th>
<th>Allergies</th>
<th>Photo Consent</th>
<th>Registration Date</th>
<th style="min-width: 220px;">Action</th>
</tr>
</thead>
<tbody>
<?php if (!empty($students)): ?>
<?php foreach ($students as $student): ?>
<?php
$modalIdContact = 'contactModal' . (int)$student['id'];
$modalIdEdit = 'editStudentModal' . (int)$student['id'];
$updateUrl = base_url('administrator/students/update'); // POST target
// Format DOB for display
$dobDisp = '';
if (!empty($student['dob'])) {
try {
$dobDisp = (new DateTime($student['dob']))->format('m-d-Y');
} catch (\Throwable $e) {
$dobDisp = esc($student['dob']);
}
}
// Format Reg Date for display (as local mm-dd-YYYY)
$regDisp = '';
if (!empty($student['registration_date'])) {
try {
$dt = new \DateTime($student['registration_date'], new \DateTimeZone('UTC'));
$dt->setTimezone(new \DateTimeZone(user_timezone()));
$regDisp = local_datetime($student['registration_date'], 'm-d-Y H:i');
} catch (\Throwable $e) {
$regDisp = esc($student['registration_date']);
}
}
// Input-safe values
$dobVal = $dobDisp;
$regDateLocal = '';
if (!empty($student['registration_date'])) {
try {
$dt2 = new \DateTime($student['registration_date'], new \DateTimeZone('UTC'));
$dt2->setTimezone(new \DateTimeZone(user_timezone()));
$regDateLocal = local_datetime($student['registration_date'], 'Y-m-d\TH:i');
} catch (\Throwable $e) {
$regDateLocal = '';
}
}
$isActive = (int)($student['is_active'] ?? 1);
// Preselected lists (server-computed strings or joined lists)
$medSelected = array_filter(array_map('trim', preg_split('/[,\n;]+/', (string)($student['medical_conditions'] ?? ''), -1, PREG_SPLIT_NO_EMPTY)));
$allSelected = array_filter(array_map('trim', preg_split('/[,\n;]+/', (string)($student['allergies'] ?? ''), -1, PREG_SPLIT_NO_EMPTY)));
$medOther = implode(', ', array_diff($medSelected, $medicalOptions));
$allOther = implode(', ', array_diff($allSelected, $allergyOptions));
$medId = 'medical_conditions_' . (int)$student['id'];
$allId = 'allergies_' . (int)$student['id'];
$medOtherId = 'medical_other_' . (int)$student['id'];
$allOtherId = 'allergy_other_' . (int)$student['id'];
?>
<tr>
<td><?= esc($student['school_id']) ?></td>
<td>
<a href="#" class="text-decoration-none" data-family-student-id="<?= (int)($student['id'] ?? 0) ?>">
<?= esc($student['firstname']) ?>
</a>
</td>
<td>
<a href="#" class="text-decoration-none" data-family-student-id="<?= (int)($student['id'] ?? 0) ?>">
<?= esc($student['lastname']) ?>
</a>
</td>
<td><?= esc($dobDisp) ?></td>
<td><?= esc((string)($student['age'] ?? '')) ?></td>
<td><?= esc($student['gender']) ?></td>
<td><?= esc($student['class_section_name']) ?></td>
<td><?= $isActive ? 'Yes' : 'No' ?></td>
<td><?= esc($student['medical_conditions'] ?? '') ?></td>
<td><?= esc($student['allergies'] ?? '') ?></td>
<td><?= !empty($student['photo_consent']) ? 'Yes' : 'No' ?></td>
<td><?= esc($regDisp) ?></td>
<td class="d-flex flex-wrap gap-2">
<!-- Contact Modal Trigger -->
<button class="btn btn-warning btn-sm" data-bs-toggle="modal" data-bs-target="#<?= $modalIdContact ?>">
Contact Information
</button>
<!-- Edit Modal Trigger -->
<button class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#<?= $modalIdEdit ?>">
Edit Student
</button>
<!-- Contact Modal -->
<div class="modal fade" id="<?= $modalIdContact ?>" tabindex="-1" aria-labelledby="<?= $modalIdContact ?>Label" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content shadow">
<div class="modal-header bg-primary text-white">
<h5 class="modal-title" id="<?= $modalIdContact ?>Label">
Contact Info - <?= esc($student['firstname']) ?> <?= esc($student['lastname']) ?>
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<h5 class="mb-3 border-bottom pb-1">👨‍👩‍👧 Parent Information</h5>
<div class="row mb-3">
<div class="col-md-6">
<p><strong>Name:</strong> <?= esc(($student['parent_firstname'] ?? '') . ' ' . ($student['parent_lastname'] ?? '')) ?></p>
<p><strong>Phone:</strong> <?= esc($student['parent_phone'] ?? 'N/A') ?></p>
</div>
<div class="col-md-6">
<p><strong>Email:</strong> <?= esc($student['parent_email'] ?? 'N/A') ?></p>
</div>
</div>
<h5 class="mb-3 border-bottom pb-1">🚨 Emergency Contact</h5>
<div class="row">
<div class="col-md-6">
<p><strong>Name:</strong> <?= esc($student['emergency_name'] ?? 'N/A') ?></p>
<p><strong>Relationship:</strong> <?= esc($student['emergency_relationship'] ?? 'N/A') ?></p>
<p><strong>Phone:</strong> <?= esc($student['emergency_phone'] ?? 'N/A') ?></p>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<!-- Edit Student Modal -->
<div class="modal fade" id="<?= $modalIdEdit ?>" tabindex="-1" aria-labelledby="<?= $modalIdEdit ?>Label" aria-hidden="true">
<div class="modal-dialog modal-xl">
<div class="modal-content shadow">
<div class="modal-header bg-success text-white">
<h5 class="modal-title" id="<?= $modalIdEdit ?>Label">
Edit Student - <?= esc($student['firstname']) ?> <?= esc($student['lastname']) ?>
</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form method="post" action="<?= $updateUrl ?>" class="needs-validation" novalidate>
<?= csrf_field() ?>
<input type="hidden" name="id" value="<?= (int)$student['id'] ?>">
<div class="modal-body">
<div class="row g-3">
<!-- school_id -->
<div class="col-md-3">
<label class="form-label">School ID</label>
<input type="text" name="school_id" class="form-control" value="<?= esc($student['school_id'] ?? '') ?>" maxlength="100">
</div>
<!-- firstname -->
<div class="col-md-3">
<label class="form-label">First Name</label>
<input type="text" name="firstname" class="form-control"
value="<?= esc($student['firstname'] ?? '') ?>"
pattern="^[A-Za-z\s\-]{2,30}$" required>
<div class="invalid-feedback">Only letters, spaces, or dashes (230 chars).</div>
</div>
<!-- lastname -->
<div class="col-md-3">
<label class="form-label">Last Name</label>
<input type="text" name="lastname" class="form-control"
value="<?= esc($student['lastname'] ?? '') ?>"
pattern="^[A-Za-z\s\-]{2,30}$" required>
<div class="invalid-feedback">Only letters, spaces, or dashes (230 chars).</div>
</div>
<!-- gender -->
<div class="col-md-3">
<label class="form-label">Gender</label>
<select name="gender" class="form-select" required>
<option value="" disabled <?= empty($student['gender']) ? 'selected' : '' ?>>Select…</option>
<option value="Male" <?= (strcasecmp($student['gender'] ?? '', 'Male') === 0) ? 'selected' : '' ?>>Male</option>
<option value="Female" <?= (strcasecmp($student['gender'] ?? '', 'Female') === 0) ? 'selected' : '' ?>>Female</option>
</select>
<div class="invalid-feedback">Please choose a gender.</div>
</div>
<!-- dob -->
<div class="col-md-3">
<label class="form-label">DOB</label>
<input type="date" name="dob" class="form-control js-dob" value="<?= esc($dobVal) ?>" required>
<div class="invalid-feedback">Please provide a valid date of birth.</div>
</div>
<!-- age (readonly) -->
<div class="col-md-3">
<label class="form-label">Age</label>
<input type="number" name="age" class="form-control js-age" value="<?= (int)($student['age'] ?? 0) ?>" min="0" step="1" readonly>
<div class="form-text">Auto-calculated from DOB.</div>
</div>
<!-- registration_grade -->
<div class="col-md-3">
<label class="form-label">Grade</label>
<select name="registration_grade" class="form-select" required>
<option value="" disabled <?= empty($student['registration_grade']) ? 'selected' : '' ?>>Select…</option>
<?php foreach ($gradeOptions as $opt): ?>
<option value="<?= esc($opt) ?>" <?= (strcasecmp((string)($student['registration_grade'] ?? ''), (string)$opt) === 0) ? 'selected' : '' ?>>
<?= esc($opt) ?>
</option>
<?php endforeach; ?>
</select>
<div class="invalid-feedback">Please choose a grade.</div>
</div>
<!-- registration_date (datetime-local) -->
<div class="col-md-3">
<label class="form-label">Registration Date & Time</label>
<input type="datetime-local" name="registration_date" class="form-control" value="<?= esc($regDateLocal) ?>">
<div class="form-text">Local time (<?= esc(user_timezone()) ?>).</div>
</div>
<!-- parent_id -->
<div class="col-md-3">
<label class="form-label">Parent ID</label>
<input type="number" name="parent_id" class="form-control" value="<?= (int)($student['parent_id'] ?? 0) ?>" min="1" step="1" required>
<div class="invalid-feedback">Parent ID is required.</div>
</div>
<!-- year_of_registration -->
<div class="col-md-3">
<label class="form-label">Year of Registration</label>
<input type="text" name="year_of_registration" class="form-control"
value="<?= esc($student['year_of_registration'] ?? '') ?>"
pattern="^\d{4}(-\d{4})?$" maxlength="25" placeholder="e.g., 2025 or 2025-2026">
<div class="invalid-feedback">Use YYYY or YYYY-YYYY.</div>
</div>
<!-- school_year -->
<?php
$syDatalistId = 'datalist-school-years-' . (int)$student['id'];
$nowY = (int)date('Y');
$syOptions = [];
for ($y = $nowY - 2; $y <= $nowY + 3; $y++) {
$syOptions[] = $y . '-' . ($y + 1);
}
?>
<div class="col-md-3">
<label class="form-label">School Year</label>
<input list="<?= $syDatalistId ?>" name="school_year" class="form-control"
value="<?= esc($student['school_year'] ?? '') ?>"
pattern="^\d{4}-\d{4}$" maxlength="9" placeholder="YYYY-YYYY">
<datalist id="<?= $syDatalistId ?>">
<?php foreach ($syOptions as $sy): ?>
<option value="<?= esc($sy) ?>"></option>
<?php endforeach; ?>
</datalist>
<div class="invalid-feedback">Format: YYYY-YYYY.</div>
</div>
<!-- rfid_tag -->
<div class="col-md-3">
<label class="form-label">RFID Tag</label>
<input type="text" name="rfid_tag" class="form-control" value="<?= esc($student['rfid_tag'] ?? '') ?>" maxlength="100" placeholder="Optional">
</div>
<!-- semester -->
<div class="col-md-3">
<label class="form-label">Semester</label>
<?php $sem = trim((string)($student['semester'] ?? '')); ?>
<select name="semester" class="form-select">
<option value="" <?= $sem === '' ? 'selected' : '' ?>>—</option>
<option value="Fall" <?= strcasecmp($sem, 'Fall') === 0 ? 'selected' : '' ?>>Fall</option>
<option value="Spring" <?= strcasecmp($sem, 'Spring') === 0 ? 'selected' : '' ?>>Spring</option>
<option value="Summer" <?= strcasecmp($sem, 'Summer') === 0 ? 'selected' : '' ?>>Summer</option>
</select>
</div>
<!-- tuition_paid -->
<div class="col-md-3">
<label class="form-label d-block">Tuition Paid</label>
<input type="hidden" name="tuition_paid" value="0">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" value="1" id="tuition_paid_<?= (int)$student['id'] ?>" name="tuition_paid" <?= !empty($student['tuition_paid']) ? 'checked' : '' ?>>
<label class="form-check-label" for="tuition_paid_<?= (int)$student['id'] ?>">Mark as paid</label>
</div>
</div>
<!-- is_new -->
<div class="col-md-3">
<label class="form-label">Is New Student?</label>
<?php $isNewVal = (string)($student['is_new'] ?? '1'); ?>
<select name="is_new" class="form-select" required>
<option value="1" <?= $isNewVal === '1' ? 'selected' : '' ?>>Yes (New)</option>
<option value="0" <?= $isNewVal === '0' ? 'selected' : '' ?>>No (Returning)</option>
</select>
</div>
<!-- is_active -->
<div class="col-md-3">
<label class="form-label d-block">Active Status</label>
<input type="hidden" name="is_active" value="0">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" value="1" id="is_active_<?= (int)$student['id'] ?>" name="is_active" <?= $isActive ? 'checked' : '' ?>>
<label class="form-check-label" for="is_active_<?= (int)$student['id'] ?>">Show in classes/attendance</label>
</div>
</div>
<!-- photo_consent -->
<div class="col-md-12">
<div class="form-check mt-2">
<input type="hidden" name="photo_consent" value="0">
<input class="form-check-input" type="checkbox" value="1" id="photo_consent_<?= (int)$student['id'] ?>" name="photo_consent" <?= !empty($student['photo_consent']) ? 'checked' : '' ?>>
<label class="form-check-label" for="photo_consent_<?= (int)$student['id'] ?>">Photo Consent</label>
</div>
</div>
<!-- Medical Conditions -->
<div class="col-md-6">
<label class="form-label">Medical Conditions</label>
<!-- Hidden payload + touched flag -->
<input type="hidden" name="medical_conditions" id="<?= $medId ?>_hidden">
<input type="hidden" name="medical_touched" id="<?= $medId ?>_touched" value="0">
<select class="form-select js-multi"
id="<?= $medId ?>"
multiple
data-none="None"
data-hidden="#<?= $medId ?>_hidden"
data-other="#<?= $medOtherId ?>"
data-touched="#<?= $medId ?>_touched">
<?php foreach ($medicalOptions as $opt): ?>
<option value="<?= esc($opt) ?>" <?= in_array($opt, $medSelected, true) ? 'selected' : '' ?>>
<?= esc($opt) ?>
</option>
<?php endforeach; ?>
</select>
<div class="form-text">Hold Ctrl/⌘ to select multiple. Choose <b>None</b> if no conditions.</div>
<label class="form-label mt-2">Other (free text, comma-separated)</label>
<input type="text" class="form-control" id="<?= $medOtherId ?>" placeholder="e.g., Seasonal rhinitis" value="<?= esc($medOther) ?>">
</div>
<!-- Allergies -->
<div class="col-md-6">
<label class="form-label">Allergies</label>
<!-- Hidden payload + touched flag -->
<input type="hidden" name="allergies" id="<?= $allId ?>_hidden">
<input type="hidden" name="allergies_touched" id="<?= $allId ?>_touched" value="0">
<select class="form-select js-multi"
id="<?= $allId ?>"
multiple
data-none="None"
data-hidden="#<?= $allId ?>_hidden"
data-other="#<?= $allOtherId ?>"
data-touched="#<?= $allId ?>_touched">
<?php foreach ($allergyOptions as $opt): ?>
<option value="<?= esc($opt) ?>" <?= in_array($opt, $allSelected, true) ? 'selected' : '' ?>>
<?= esc($opt) ?>
</option>
<?php endforeach; ?>
</select>
<div class="form-text">Hold Ctrl/⌘ to select multiple. Choose <b>None</b> if no allergies.</div>
<label class="form-label mt-2">Other (free text, comma-separated)</label>
<input type="text" class="form-control" id="<?= $allOtherId ?>" placeholder="e.g., Penicillin" value="<?= esc($allOther) ?>">
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-success">Save Changes</button>
</div>
</form>
</div>
</div>
</div>
<!-- /Edit Student Modal -->
</td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr>
<td colspan="13" class="text-center">No students found.</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<?= $this->endSection() ?>
<?= $this->section('scripts') ?>
<script>
document.addEventListener('DOMContentLoaded', () => {
/* ============== DataTables (guarded) ============== */
if (window.jQuery && typeof jQuery.fn.DataTable === 'function' && document.getElementById('myTable')) {
jQuery('#myTable').DataTable(); // Use your own options if needed
}
/* ============== Bootstrap 5 validation ============== */
(function() {
const forms = document.querySelectorAll('.needs-validation');
Array.prototype.forEach.call(forms, (form) => {
form.addEventListener('submit', (evt) => {
if (!form.checkValidity()) {
evt.preventDefault();
evt.stopPropagation();
}
form.classList.add('was-validated');
}, false);
});
})();
/* ============== Helpers ============== */
function splitCSV(s) {
if (!s) return [];
return s.split(',').map(x => x.trim()).filter(Boolean);
}
function uniq(arr) {
const seen = new Set();
const out = [];
for (const v of arr) {
const k = v.toLowerCase();
if (!seen.has(k)) {
seen.add(k);
out.push(v);
}
}
return out;
}
function setTouched(sel) {
const tSel = sel.dataset.touched ? document.querySelector(sel.dataset.touched) : null;
if (tSel) tSel.value = '1';
}
function updateHiddenFromSelect(sel) {
const hiddenSel = sel.dataset.hidden ? document.querySelector(sel.dataset.hidden) : null;
if (!hiddenSel) return;
const noneLabel = (sel.dataset.none || 'None').toLowerCase();
const otherInp = sel.dataset.other ? document.querySelector(sel.dataset.other) : null;
const selected = Array.from(sel.selectedOptions).map(o => o.value).filter(Boolean);
const others = otherInp && !otherInp.disabled ? splitCSV(otherInp.value) : [];
let final = uniq([...selected, ...others]);
// Remove "None" token from payload; exclusivity handled elsewhere
final = final.filter(v => v.toLowerCase() !== noneLabel);
hiddenSel.value = final.length ? final.join(', ') : '';
}
function enforceNone(sel) {
const noneLabel = sel.dataset.none || 'None';
const values = Array.from(sel.selectedOptions).map(o => o.value);
const otherInp = sel.dataset.other ? document.querySelector(sel.dataset.other) : null;
if (values.includes(noneLabel)) {
// Deselect everything except "None"
Array.from(sel.options).forEach(opt => {
if (opt.value !== noneLabel) opt.selected = false;
});
if (otherInp) {
otherInp.value = '';
otherInp.disabled = true;
}
} else {
// Ensure "None" is off if other items chosen
Array.from(sel.options).forEach(opt => {
if (opt.value === noneLabel) opt.selected = false;
});
if (otherInp) {
otherInp.disabled = false;
}
}
updateHiddenFromSelect(sel);
}
function bindSelect(sel) {
if (sel.__bound) return;
sel.__bound = true;
// Initial normalize + pack based on server preselects
enforceNone(sel);
sel.addEventListener('change', () => {
enforceNone(sel);
setTouched(sel);
});
const otherInp = sel.dataset.other ? document.querySelector(sel.dataset.other) : null;
if (otherInp) {
otherInp.addEventListener('input', () => {
updateHiddenFromSelect(sel);
setTouched(sel);
});
}
}
// Bind all multi-selects present on the page (all modals rendered server-side)
document.querySelectorAll('select.js-multi').forEach(bindSelect);
// Modal lifecycle: wire age + (re)bind selects inside shown modal
document.querySelectorAll('.modal').forEach((modal) => {
modal.addEventListener('shown.bs.modal', () => {
// Age from DOB
const dob = modal.querySelector('.js-dob');
const age = modal.querySelector('.js-age');
if (dob && age) {
const update = () => {
if (!dob.value) {
age.value = '';
return;
}
const d = new Date(dob.value + 'T00:00:00');
if (isNaN(d.getTime())) {
age.value = '';
return;
}
const t = new Date();
let a = t.getFullYear() - d.getFullYear();
const m = t.getMonth() - d.getMonth();
if (m < 0 || (m === 0 && t.getDate() < d.getDate())) a--;
age.value = a >= 0 ? a : '';
};
update();
dob.addEventListener('change', update);
dob.addEventListener('input', update);
}
modal.querySelectorAll('select.js-multi').forEach(bindSelect);
// Ensure hidden fields packed and flags set on submit
modal.querySelectorAll('form').forEach((form) => {
if (form.__syncBound) return;
form.__syncBound = true;
form.addEventListener('submit', () => {
form.querySelectorAll('select.js-multi').forEach((sel) => {
enforceNone(sel);
updateHiddenFromSelect(sel);
setTouched(sel);
});
});
});
});
});
// --- CSRF sync: ensure latest token is sent on submit ---
(function attachCsrfSync() {
const TOKEN_NAME = '<?= csrf_token() ?>';
const COOKIE_NAME = <?= json_encode(config('Security')->csrfCookieName ?? (config('Security')->cookieName ?? 'csrf_cookie_name')) ?>;
function getCookie(name) {
const parts = document.cookie.split(';');
for (let i = 0; i < parts.length; i++) {
const p = parts[i].trim();
if (p.startsWith(name + '=')) return decodeURIComponent(p.substring(name.length + 1));
}
return '';
}
function syncFormToken(form) {
try {
const cookieVal = getCookie(COOKIE_NAME);
if (!cookieVal) return; // nothing to sync
const hidden = form.querySelector('input[name="' + TOKEN_NAME + '"]');
if (hidden) hidden.value = cookieVal;
} catch (_) {
// no-op
}
}
// Bind to all edit forms on this page
document.querySelectorAll('form').forEach((form) => {
if (form.__csrfSyncBound) return;
form.__csrfSyncBound = true;
form.addEventListener('submit', () => syncFormToken(form));
});
})();
});
</script>
<?= $this->endSection() ?>