147 lines
4.5 KiB
JavaScript
147 lines
4.5 KiB
JavaScript
(function () {
|
|
var backdrop = null;
|
|
var modal = null;
|
|
var titleEl = null;
|
|
var bodyEl = null;
|
|
var cancelBtn = null;
|
|
var confirmBtn = null;
|
|
var footerEl = null;
|
|
var prevFocus = null;
|
|
var currentOpts = null;
|
|
var onKeydown = null;
|
|
|
|
function build() {
|
|
backdrop = document.createElement('div');
|
|
backdrop.className = 'modal-backdrop';
|
|
|
|
modal = document.createElement('div');
|
|
modal.className = 'modal';
|
|
modal.setAttribute('role', 'dialog');
|
|
modal.setAttribute('aria-modal', 'true');
|
|
|
|
var header = document.createElement('div');
|
|
header.className = 'modal-header';
|
|
titleEl = document.createElement('span');
|
|
header.appendChild(titleEl);
|
|
|
|
bodyEl = document.createElement('div');
|
|
bodyEl.className = 'modal-body';
|
|
|
|
footerEl = document.createElement('div');
|
|
footerEl.className = 'modal-footer';
|
|
|
|
cancelBtn = document.createElement('button');
|
|
cancelBtn.type = 'button';
|
|
confirmBtn = document.createElement('button');
|
|
confirmBtn.type = 'button';
|
|
|
|
modal.appendChild(header);
|
|
modal.appendChild(bodyEl);
|
|
modal.appendChild(footerEl);
|
|
backdrop.appendChild(modal);
|
|
|
|
backdrop.addEventListener('mousedown', function (e) {
|
|
if (e.target === backdrop) close();
|
|
});
|
|
cancelBtn.addEventListener('click', close);
|
|
confirmBtn.addEventListener('click', function () {
|
|
if (confirmBtn.disabled) return;
|
|
if (currentOpts && currentOpts.confirm && currentOpts.confirm.onConfirm) {
|
|
currentOpts.confirm.onConfirm();
|
|
}
|
|
});
|
|
}
|
|
|
|
function open(opts) {
|
|
if (backdrop && backdrop.parentNode) close();
|
|
if (!backdrop) build();
|
|
|
|
currentOpts = opts;
|
|
prevFocus = document.activeElement;
|
|
|
|
titleEl.textContent = opts.title || '';
|
|
|
|
bodyEl.textContent = '';
|
|
if (opts.body instanceof Node) {
|
|
bodyEl.appendChild(opts.body);
|
|
} else if (typeof opts.body === 'string') {
|
|
bodyEl.textContent = opts.body;
|
|
}
|
|
|
|
var confirmOpts = opts.confirm || {};
|
|
var cancelOpts = opts.cancel || {};
|
|
|
|
confirmBtn.textContent = confirmOpts.label || 'OK';
|
|
confirmBtn.className = 'btn' + (confirmOpts.danger ? ' danger' : '');
|
|
confirmBtn.disabled = !!confirmOpts.initiallyDisabled;
|
|
|
|
cancelBtn.textContent = cancelOpts.label || 'CANCEL';
|
|
cancelBtn.className = 'btn';
|
|
|
|
footerEl.textContent = '';
|
|
if (opts.swapButtons) {
|
|
footerEl.appendChild(confirmBtn);
|
|
footerEl.appendChild(cancelBtn);
|
|
} else {
|
|
footerEl.appendChild(cancelBtn);
|
|
footerEl.appendChild(confirmBtn);
|
|
}
|
|
|
|
document.body.appendChild(backdrop);
|
|
|
|
setTimeout(function () {
|
|
if (cancelOpts.autofocus) {
|
|
cancelBtn.focus();
|
|
return;
|
|
}
|
|
var firstInput = bodyEl.querySelector('input, textarea, select');
|
|
if (firstInput) {
|
|
firstInput.focus();
|
|
if (firstInput.select) firstInput.select();
|
|
} else {
|
|
confirmBtn.focus();
|
|
}
|
|
}, 0);
|
|
|
|
var enterConfirms = confirmOpts.enterConfirms !== false;
|
|
onKeydown = function (e) {
|
|
if (e.key === 'Escape') {
|
|
e.preventDefault();
|
|
close();
|
|
return;
|
|
}
|
|
if (e.key === 'Enter' && enterConfirms) {
|
|
var tag = (e.target && e.target.tagName) || '';
|
|
if (tag === 'TEXTAREA') return;
|
|
e.preventDefault();
|
|
if (!confirmBtn.disabled) confirmBtn.click();
|
|
}
|
|
};
|
|
document.addEventListener('keydown', onKeydown);
|
|
|
|
return {
|
|
close: close,
|
|
setConfirmDisabled: function (d) { confirmBtn.disabled = !!d; },
|
|
confirmButton: confirmBtn
|
|
};
|
|
}
|
|
|
|
function close() {
|
|
if (!backdrop || !backdrop.parentNode) return;
|
|
if (onKeydown) {
|
|
document.removeEventListener('keydown', onKeydown);
|
|
onKeydown = null;
|
|
}
|
|
backdrop.parentNode.removeChild(backdrop);
|
|
currentOpts = null;
|
|
var toRestore = prevFocus;
|
|
prevFocus = null;
|
|
if (toRestore && toRestore.focus) {
|
|
try { toRestore.focus(); } catch (e) {}
|
|
}
|
|
}
|
|
|
|
window.openModal = open;
|
|
window.closeModal = close;
|
|
})();
|