OpenNIT

Quelltext des aktuellen Standes

Fassung 1.1.1

confirm_modal.php

4 KB
<?php
/**
 * Wiederverwendbares Bestätigungs-Modal (ersetzt natives confirm()).
 *
 * Nutzung im Template:
 *   <?php $this->insert('partials/confirm_modal'); ?>   – oder per include
 *
 * Aufruf aus JS:
 *   itConfirm({ title, text, confirmLabel, confirmClass, onConfirm })
 *   itConfirmSubmit(buttonEl, title, text)   // sendet das umschließende <form>
 */
if (defined('IT_CONFIRM_MODAL_RENDERED')) {
    return;
}
define('IT_CONFIRM_MODAL_RENDERED', true);
?>
<div class="it-confirm-overlay" id="itConfirmOverlay" aria-hidden="true">
    <div class="it-confirm" role="dialog" aria-modal="true" aria-labelledby="itConfirmTitle">
        <div class="it-confirm-body">
            <p class="it-confirm-title" id="itConfirmTitle"><?= $this->te('Bestätigen') ?></p>
            <p class="it-confirm-text" id="itConfirmText"></p>
        </div>
        <div class="it-confirm-actions">
            <button type="button" class="btn btn-default btn-sm" id="itConfirmCancel"><?= $this->te('Abbrechen') ?></button>
            <button type="button" class="btn btn-danger btn-sm" id="itConfirmOk"><?= $this->te('Bestätigen') ?></button>
        </div>
    </div>
</div>
<style>
.it-confirm-overlay { position:fixed; inset:0; background:rgba(15,23,42,0.45); z-index:1090;
    display:none; align-items:center; justify-content:center; padding:1rem; }
.it-confirm-overlay.open { display:flex; }
.it-confirm { background:var(--color-bg); border-radius:0.5rem; max-width:430px; width:100%; overflow:hidden;
    box-shadow:0 20px 50px rgba(0,0,0,.3); animation:itConfirmPop .15s ease; }
@keyframes itConfirmPop { from { transform:scale(.96); opacity:0; } to { transform:scale(1); opacity:1; } }
.it-confirm-body { padding:1.4rem 1.4rem 1rem; }
.it-confirm-title { font-size:1.02rem; font-weight:700; color:var(--gray-900); margin:0 0 0.4rem; }
.it-confirm-text { font-size:0.88rem; color:var(--gray-500); margin:0; line-height:1.5; }
.it-confirm-actions { display:flex; justify-content:flex-end; gap:0.6rem; padding:0.9rem 1.4rem;
    background:var(--gray-50); border-top:1px solid var(--gray-100); }
</style>
<script>
(function () {
    var overlay = document.getElementById('itConfirmOverlay');
    var titleEl = document.getElementById('itConfirmTitle');
    var textEl  = document.getElementById('itConfirmText');
    var okBtn   = document.getElementById('itConfirmOk');
    var noBtn   = document.getElementById('itConfirmCancel');
    var onOk    = null;

    function close() { overlay.classList.remove('open'); overlay.setAttribute('aria-hidden', 'true'); onOk = null; }

    window.itConfirm = function (opts) {
        opts = opts || {};
        titleEl.textContent = opts.title || 'Bestätigen';
        textEl.textContent  = opts.text  || '';
        okBtn.textContent   = opts.confirmLabel || 'Bestätigen';
        okBtn.className     = 'btn btn-sm ' + (opts.confirmClass || 'btn-danger');
        onOk = typeof opts.onConfirm === 'function' ? opts.onConfirm : null;
        overlay.classList.add('open');
        overlay.setAttribute('aria-hidden', 'false');
        okBtn.focus();
    };

    window.itConfirmSubmit = function (btn, title, text, confirmLabel) {
        var form = btn.closest('form');
        if (!form) return;
        window.itConfirm({
            title: title, text: text, confirmLabel: confirmLabel || 'Löschen',
            onConfirm: function () { form.submit(); }
        });
    };

    okBtn.addEventListener('click', function () { var f = onOk; close(); if (f) f(); });
    noBtn.addEventListener('click', close);
    overlay.addEventListener('click', function (e) { if (e.target === overlay) close(); });
    document.addEventListener('keydown', function (e) {
        if (e.key === 'Escape' && overlay.classList.contains('open')) close();
    });
})();
</script>