0 directories, 46 files

util

Home / tinai / util
/**
 * Builds centered modal dialogs on the fly: a fieldset with a legend title,
 * a content element and a row of buttons, so new dialogs need no markup in
 * index.php and no positioning rules of their own.
 */

import { openModal } from './overlay-utils.js';

/**
 * Opens a centered modal dialog built on the fly. See confirm-dialog.js,
 * multi-choice-dialog.js and chat-renderer.js for the usage pattern.
 * @param {Object} options - Behaviour options.
 * @param {string} options.title - The legend title text.
 * @param {Node|null} [options.content=null] - The element placed above the buttons.
 * @param {Array<{caption: string, onclick?: Function}>} [options.buttons=[]] -
 *   The buttons in display order; each onclick receives the dialog's close()
 *   and decides whether to call it.
 * @param {Function|null} [options.on_escape=null] - Called on Escape; return
 *   false to keep the dialog open, true or undefined to close it.
 * @param {Function|null} [options.on_close=null] - Called once after the dialog
 *   is closed via any path.
 * @param {boolean} [options.click_outside=false] - Close when the overlay
 *   itself (not its content) is clicked.
 * @returns {Function} close() — closes the dialog idempotently.
 */
export function openDialog({ title, content = null, buttons = [], on_escape = null, on_close = null, click_outside = false }) {
	const overlay = document.createElement('div');
	overlay.className = 'div-structure-dialog-overlay div-dialog-overlay';

	const container = document.createElement('div');
	container.className = 'div-confirm-dialog-container';
	const fieldset = document.createElement('fieldset');
	const legend = document.createElement('legend');
	legend.textContent = title || '';
	fieldset.appendChild(legend);
	if (content) {
		fieldset.appendChild(content);
	}

	const button_row = document.createElement('div');
	button_row.className = 'div-confirm-buttons';
	for (const spec of buttons) {
		const button = document.createElement('button');
		button.type = 'button';
		button.className = 'as-icon';
		button.textContent = spec.caption || '';
		button.addEventListener('click', () => spec.onclick?.(close));
		button_row.appendChild(button);
	}
	if (buttons.length) {
		fieldset.appendChild(button_row);
	}

	container.appendChild(fieldset);
	overlay.appendChild(container);
	document.body.appendChild(overlay);

	const close = openModal(overlay, {
		click_outside,
		on_escape,
		on_close: () => {
			overlay.remove();
			on_close?.();
		}
	});

	button_row.querySelector('button')?.focus();
	return close;
}
🌐
dialog.js ×
Type: Web, text/x-java
2.50 Kilobytes
Last Modified 2026-11-04 09:48:28
⬇ Download File