85 lines
4.0 KiB
JavaScript
85 lines
4.0 KiB
JavaScript
// The panel's own question and input dialogs in place of the browser's
|
|
// confirm() and prompt(): UI.confirm(text, {ok, danger}) and
|
|
// UI.prompt(text, value) answer with promises. A form with data-confirm asks
|
|
// first and is sent only on «да».
|
|
(function () {
|
|
'use strict';
|
|
let dlg = null;
|
|
function make() {
|
|
dlg = document.createElement('dialog');
|
|
dlg.className = 'uidlg';
|
|
dlg.innerHTML = '<form method="dialog"><p class="ui-text"></p><input class="ui-input" autocomplete="off" spellcheck="false">' +
|
|
'<div class="row end"><button type="button" class="btn ghost close ui-no">Отмена</button><button type="submit" class="ui-yes">OK</button></div></form>';
|
|
document.body.appendChild(dlg);
|
|
}
|
|
function ask(text, o) {
|
|
if (!dlg) make();
|
|
if (dlg.open) dlg.close('');
|
|
const input = dlg.querySelector('.ui-input'), yes = dlg.querySelector('.ui-yes');
|
|
// Long words (a file name) stay on one line, cut with "…"; the window
|
|
// is as wide as its words, up to the screen's room.
|
|
const t = dlg.querySelector('.ui-text');
|
|
t.textContent = '';
|
|
// "{chip}" in the text: the chip stands there, inside the sentence.
|
|
const parts = String(text).split('{chip}');
|
|
text = parts.shift();
|
|
String(text).split(/(\s+)/).forEach(w => {
|
|
if (w.length > 28 && !/\s/.test(w)) {
|
|
const s = document.createElement('span');
|
|
s.className = 'ui-long'; s.textContent = w; s.title = w;
|
|
t.appendChild(s);
|
|
} else t.appendChild(document.createTextNode(w));
|
|
});
|
|
// Extras of a question about an action: where (a chip), the command in
|
|
// mono, a note under it.
|
|
if (parts.length && o.chip) {
|
|
const c = document.createElement('span'); c.className = 'ui-chip'; c.textContent = o.chip; c.title = o.chip;
|
|
t.append(c, parts.join(''));
|
|
o = Object.assign({}, o, {chip: ''});
|
|
}
|
|
dlg.querySelectorAll('.ui-extra').forEach(e => e.remove());
|
|
if (o.chip || o.code || o.note) {
|
|
const box = document.createElement('div');
|
|
box.className = 'ui-extra';
|
|
if (o.chip) { const c = document.createElement('div'); c.className = 'ui-chip'; c.textContent = o.chip; c.title = o.chip; box.appendChild(c); }
|
|
if (o.code) { const p = document.createElement('pre'); p.className = 'ui-code'; p.textContent = o.code; box.appendChild(p); }
|
|
if (o.note) { const n = document.createElement('p'); n.className = 'ui-note'; n.textContent = o.note; box.appendChild(n); }
|
|
t.after(box);
|
|
}
|
|
input.hidden = !o.input;
|
|
input.value = o.value || '';
|
|
yes.textContent = o.ok || 'OK';
|
|
yes.className = 'ui-yes' + (o.danger ? ' btn danger' : '');
|
|
// «Отмена» red, unless «да» is the red one (a delete): never two reds.
|
|
dlg.querySelector('.ui-no').classList.toggle('close', !o.danger);
|
|
return new Promise(done => {
|
|
const end = v => { dlg.onclose = null; done(v); };
|
|
dlg.querySelector('.ui-no').onclick = () => dlg.close('');
|
|
dlg.querySelector('form').onsubmit = ev => { ev.preventDefault(); dlg.close('ok'); };
|
|
dlg.onclose = () => end(dlg.returnValue === 'ok' ? (o.input ? input.value : true) : (o.input ? null : false));
|
|
dlg.returnValue = '';
|
|
dlg.showModal();
|
|
if (o.input) { input.focus(); input.select(); } else yes.focus();
|
|
});
|
|
}
|
|
const UI = {
|
|
confirm: (text, o) => ask(text, Object.assign({ok: 'Да'}, o)),
|
|
prompt: (text, value) => ask(text, {input: true, value, ok: 'OK'})
|
|
};
|
|
window.UI = UI;
|
|
// Forms that ask first: data-confirm, and data-danger for a red «да».
|
|
document.addEventListener('submit', ev => {
|
|
const f = ev.target;
|
|
if (!f.dataset || !f.dataset.confirm) return;
|
|
if (f.dataset.confirmed) { delete f.dataset.confirmed; return; }
|
|
ev.preventDefault();
|
|
ev.stopImmediatePropagation();
|
|
const by = ev.submitter;
|
|
UI.confirm(f.dataset.confirm, {ok: f.dataset.ok || 'Да', danger: 'danger' in f.dataset}).then(ok => {
|
|
if (!ok) return;
|
|
f.dataset.confirmed = '1';
|
|
f.requestSubmit(by && f.contains(by) ? by : undefined);
|
|
});
|
|
}, true);
|
|
})();
|