mirror of
https://github.com/MarijnDoeve/TijdVoorDeTest.git
synced 2026-07-06 23:50:16 +02:00
4a87ac574d
- Add question in question bank now opens a modal instead of navigating to a full-page form, consistent with the edit modal pattern - Modal closes are blocked by static backdrop once the user has made any change (input, checkbox, drag-reorder, sort, randomize, remove answer) - Dirty state resets when the modal is fully hidden
77 lines
2.4 KiB
JavaScript
77 lines
2.4 KiB
JavaScript
import {Controller} from '@hotwired/stimulus';
|
|
import {Modal} from 'bootstrap';
|
|
|
|
export default class extends Controller {
|
|
static targets = ['modal', 'modalBody', 'modalFooter'];
|
|
|
|
async open(event) {
|
|
event.preventDefault();
|
|
const url = event.currentTarget.dataset.url;
|
|
const title = event.currentTarget.dataset.modalTitle;
|
|
if (title) {
|
|
const titleEl = this.modalTarget.querySelector('.modal-title');
|
|
if (titleEl) titleEl.textContent = title;
|
|
}
|
|
const modal = Modal.getOrCreateInstance(this.modalTarget);
|
|
this.modalBodyTarget.innerHTML = '<div class="text-center py-4"><div class="spinner-border" role="status"></div></div>';
|
|
if (this.hasModalFooterTarget) this.modalFooterTarget.innerHTML = '';
|
|
modal.show();
|
|
await this._loadForm(url);
|
|
}
|
|
|
|
async _loadForm(url) {
|
|
const res = await fetch(url, {headers: {'X-Modal-Request': '1'}});
|
|
this.modalBodyTarget.innerHTML = await res.text();
|
|
this._moveFooter();
|
|
this._bindDirty();
|
|
this._bindForm(url);
|
|
}
|
|
|
|
_bindDirty() {
|
|
const modal = Modal.getOrCreateInstance(this.modalTarget);
|
|
modal._config.backdrop = true;
|
|
modal._config.keyboard = true;
|
|
|
|
const markDirty = () => {
|
|
modal._config.backdrop = 'static';
|
|
modal._config.keyboard = false;
|
|
};
|
|
|
|
this.modalBodyTarget.addEventListener('input', markDirty, {once: true});
|
|
this.modalBodyTarget.addEventListener('change', markDirty, {once: true});
|
|
|
|
this.modalTarget.addEventListener('hidden.bs.modal', () => {
|
|
modal._config.backdrop = true;
|
|
modal._config.keyboard = true;
|
|
}, {once: true});
|
|
}
|
|
|
|
_moveFooter() {
|
|
if (!this.hasModalFooterTarget) return;
|
|
const template = this.modalBodyTarget.querySelector('template[data-modal-footer]');
|
|
this.modalFooterTarget.innerHTML = template ? template.innerHTML : '';
|
|
if (template) template.remove();
|
|
}
|
|
|
|
_bindForm(url) {
|
|
const form = this.modalBodyTarget.querySelector('form');
|
|
if (!form) return;
|
|
form.addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
const res = await fetch(url, {
|
|
method: 'POST',
|
|
headers: {'X-Modal-Request': '1'},
|
|
body: new FormData(form),
|
|
});
|
|
if (res.status === 204) {
|
|
Modal.getOrCreateInstance(this.modalTarget).hide();
|
|
window.location.reload();
|
|
} else {
|
|
this.modalBodyTarget.innerHTML = await res.text();
|
|
this._moveFooter();
|
|
this._bindForm(url);
|
|
}
|
|
}, {once: true});
|
|
}
|
|
}
|