mirror of
https://github.com/itflow-org/itflow
synced 2026-08-15 20:15:12 +00:00
Migrated confirm modal to sweetalert2 lib
This commit is contained in:
@@ -75,7 +75,7 @@ $remember_token_count = mysqli_num_rows($sql_remember_tokens);
|
||||
|
||||
// Show the error alert if it exists:
|
||||
if (!empty($_SESSION['alert_type']) && $_SESSION['alert_type'] == 'error') {
|
||||
echo "<div class='alert alert-danger'>{$_SESSION['alert_message']}</div>";
|
||||
echo "<div class='alert alert-danger'>" . alertMessageHtml($_SESSION['alert_message']) . "</div>";
|
||||
// Clear it so it doesn't persist on refresh
|
||||
unset($_SESSION['alert_type']);
|
||||
unset($_SESSION['alert_message']);
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
</p>
|
||||
|
||||
|
||||
<?php require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/inc_confirm_modal.php'; ?>
|
||||
|
||||
<!-- jQuery -->
|
||||
|
||||
@@ -66,6 +65,7 @@
|
||||
|
||||
<script src="/js/pretty_content.js"></script>
|
||||
|
||||
<script src="/libs/sweetalert2/js/sweetalert2.min.js"></script>
|
||||
<script src="/js/confirm_modal.js"></script>
|
||||
|
||||
<script src="/js/keepalive.js"></script>
|
||||
|
||||
@@ -28,6 +28,7 @@ header("X-Frame-Options: DENY"); // Legacy
|
||||
|
||||
<!-- Theme style -->
|
||||
<link rel="stylesheet" href="/libs/adminlte/css/adminlte.min.css">
|
||||
<link rel="stylesheet" href="/libs/sweetalert2/css/sweetalert2.min.css">
|
||||
|
||||
</head>
|
||||
|
||||
@@ -155,7 +156,7 @@ header("X-Frame-Options: DENY"); // Legacy
|
||||
}
|
||||
?>
|
||||
<div class="alert alert-<?= $_SESSION['alert_type'] ?>" id="alert">
|
||||
<?= escapeHtml($_SESSION['alert_message']) ?>
|
||||
<?= alertMessageHtml($_SESSION['alert_message']) ?>
|
||||
<button class='close' data-bs-dismiss='alert'>×</button>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
@@ -150,3 +150,41 @@ function escapeCsvFormula($value) {
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a flash alert message for output.
|
||||
*
|
||||
* flashAlert() messages deliberately carry a little formatting markup - roughly
|
||||
* 480 of the ~653 call sites wrap a value in <strong> - while 429 of them also
|
||||
* interpolate PHP variables that are user controlled (custom link names, ticket
|
||||
* status names, saved payment descriptions and so on). Escaping the lot would
|
||||
* print the tags; printing the lot raw is an XSS hole.
|
||||
*
|
||||
* So: escape everything, then restore a fixed allowlist of formatting tags that
|
||||
* carry no attributes and cannot execute. Attribute injection, </script>, event
|
||||
* handlers and <a href> are all neutralised because the escaped forms are never
|
||||
* put back.
|
||||
*
|
||||
* Every place that displays $_SESSION['alert_message'] must use this. Before it
|
||||
* existed there were four separate implementations and one of them interpolated
|
||||
* raw.
|
||||
*/
|
||||
function alertMessageHtml($message) {
|
||||
|
||||
$allowed_tags = [
|
||||
'<strong>', '</strong>',
|
||||
'<b>', '</b>',
|
||||
'<em>', '</em>',
|
||||
'<i>', '</i>',
|
||||
'<code>', '</code>',
|
||||
'<br>', '<br/>', '<br />',
|
||||
];
|
||||
|
||||
$safe = htmlspecialchars((string) $message, ENT_QUOTES, 'UTF-8');
|
||||
|
||||
foreach ($allowed_tags as $tag) {
|
||||
$safe = str_replace(htmlspecialchars($tag, ENT_QUOTES, 'UTF-8'), $tag, $safe);
|
||||
}
|
||||
|
||||
return $safe;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<?php
|
||||
require_once "inc_confirm_modal.php";
|
||||
?>
|
||||
|
||||
<?php
|
||||
@@ -45,6 +44,7 @@ if (basename(dirname($_SERVER['REQUEST_URI'])) === 'guest') { ?>
|
||||
|
||||
<!-- AdminLTE App -->
|
||||
<script src="/libs/adminlte/js/adminlte.min.js"></script>
|
||||
<script src="/libs/sweetalert2/js/sweetalert2.min.js"></script>
|
||||
<script src="/js/autocomplete.js"></script>
|
||||
<script src="/js/app.js"></script>
|
||||
<script src="/js/ajax_modal.js"></script>
|
||||
|
||||
@@ -29,6 +29,7 @@ header("X-Frame-Options: DENY");
|
||||
<!-- Custom Styles -->
|
||||
<link rel="stylesheet" href="/libs/flatpickr/css/flatpickr.min.css">
|
||||
<link rel="stylesheet" href="/libs/tom-select/css/tom-select.bootstrap5.min.css">
|
||||
<link rel="stylesheet" href="/libs/sweetalert2/css/sweetalert2.min.css">
|
||||
<link rel="stylesheet" href="/libs/DataTables/datatables.min.css">
|
||||
<link rel="stylesheet" href="/libs/intl-tel-input/css/intlTelInput.min.css">
|
||||
<link rel="stylesheet" href="/libs/adminlte/css/adminlte.min.css">
|
||||
|
||||
@@ -36,23 +36,8 @@ if (!empty($_SESSION['alert_message'])) {
|
||||
$alert_style = $alert_styles[$alert_type] ?? 'text-bg-secondary';
|
||||
$alert_dark_text = in_array($alert_type, ['warning', 'alert', 'info'], true);
|
||||
|
||||
// Escape everything, then put back only these formatting tags.
|
||||
$alert_allowed_tags = [
|
||||
'<strong>', '</strong>',
|
||||
'<b>', '</b>',
|
||||
'<em>', '</em>',
|
||||
'<i>', '</i>',
|
||||
'<code>', '</code>',
|
||||
'<br>', '<br/>', '<br />',
|
||||
];
|
||||
$alert_safe_message = htmlspecialchars($_SESSION['alert_message'], ENT_QUOTES, 'UTF-8');
|
||||
foreach ($alert_allowed_tags as $alert_tag) {
|
||||
$alert_safe_message = str_replace(
|
||||
htmlspecialchars($alert_tag, ENT_QUOTES, 'UTF-8'),
|
||||
$alert_tag,
|
||||
$alert_safe_message
|
||||
);
|
||||
}
|
||||
// Escaping lives in one place now - see alertMessageHtml() in functions/sanitize.php
|
||||
$alert_safe_message = alertMessageHtml($_SESSION['alert_message']);
|
||||
|
||||
?>
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
<div class="modal fade" id="confirmationModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="confirmationModalLabel">Confirm</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
Are you sure?
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" id="confirmSubmitBtn">Yes</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,25 +1,45 @@
|
||||
// Delegated on document rather than bound to the links present at page load, so
|
||||
// that confirm-link also works on markup injected by an ajax modal
|
||||
/**
|
||||
* Confirmation dialogs, on SweetAlert2.
|
||||
*
|
||||
* Delegated on document rather than bound to the links present at page load, so
|
||||
* that confirm-link also works on markup injected by an ajax modal.
|
||||
*
|
||||
* Per-link copy comes from data attributes, all optional:
|
||||
* data-confirm-title heading (default: "Are you sure?")
|
||||
* data-confirm-text body (default: none)
|
||||
* data-confirm-button confirm label (default: "Yes")
|
||||
* data-confirm-icon warning|error|question|info|success
|
||||
*
|
||||
* A link whose classes mark it destructive (text-danger) defaults to a red
|
||||
* confirm button and a warning icon, so the 92 delete links read as dangerous
|
||||
* without touching any of them.
|
||||
*/
|
||||
document.addEventListener('click', function (e) {
|
||||
const link = e.target.closest('a.confirm-link');
|
||||
if (!link) {
|
||||
if (!link || typeof Swal === 'undefined') {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
|
||||
const modalEl = document.getElementById('confirmationModal');
|
||||
const confirmBtn = document.getElementById('confirmSubmitBtn');
|
||||
if (!modalEl || !confirmBtn) {
|
||||
return;
|
||||
}
|
||||
const destructive = link.classList.contains('text-danger');
|
||||
|
||||
// Replacing the node drops any handler left over from a previous link,
|
||||
// which is what .off('click') used to do here.
|
||||
const freshBtn = confirmBtn.cloneNode(true);
|
||||
confirmBtn.replaceWith(freshBtn);
|
||||
freshBtn.addEventListener('click', function () {
|
||||
window.location.href = link.getAttribute('href');
|
||||
Swal.fire({
|
||||
title: link.dataset.confirmTitle || 'Are you sure?',
|
||||
text: link.dataset.confirmText || '',
|
||||
icon: link.dataset.confirmIcon || (destructive ? 'warning' : 'question'),
|
||||
showCancelButton: true,
|
||||
confirmButtonText: link.dataset.confirmButton || 'Yes',
|
||||
cancelButtonText: 'Cancel',
|
||||
reverseButtons: true,
|
||||
focusCancel: destructive,
|
||||
buttonsStyling: false,
|
||||
customClass: {
|
||||
confirmButton: destructive ? 'btn btn-danger mx-1' : 'btn btn-primary mx-1',
|
||||
cancelButton: 'btn btn-secondary mx-1'
|
||||
}
|
||||
}).then(function (result) {
|
||||
if (result.isConfirmed) {
|
||||
window.location.href = link.getAttribute('href');
|
||||
}
|
||||
});
|
||||
|
||||
bootstrap.Modal.getOrCreateInstance(modalEl).show();
|
||||
});
|
||||
|
||||
1
libs/sweetalert2/css/sweetalert2.min.css
vendored
Normal file
1
libs/sweetalert2/css/sweetalert2.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
5
libs/sweetalert2/js/sweetalert2.min.js
vendored
Normal file
5
libs/sweetalert2/js/sweetalert2.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -655,7 +655,7 @@ if (isset($_POST['add_telemetry'])) {
|
||||
if (!empty($_SESSION['alert_message'])) {
|
||||
?>
|
||||
<div class="alert alert-info" id="alert">
|
||||
<?= escapeHtml($_SESSION['alert_message']) ?>
|
||||
<?= alertMessageHtml($_SESSION['alert_message']) ?>
|
||||
<button class='close' data-bs-dismiss='alert'>×</button>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
Reference in New Issue
Block a user