recreate project

This commit is contained in:
root
2026-02-10 22:11:06 -05:00
commit 663c0cdbda
10149 changed files with 1379710 additions and 0 deletions
@@ -0,0 +1,670 @@
<?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() ?>