70 lines
2.9 KiB
JavaScript
70 lines
2.9 KiB
JavaScript
(() => {
|
|
const dialog = document.querySelector('[data-guide-dialog]');
|
|
if (!dialog) return;
|
|
const trigger = document.querySelector('[data-guide-open]');
|
|
const steps = Array.from(dialog.querySelectorAll('[data-guide-step]'));
|
|
const back = dialog.querySelector('[data-guide-back]');
|
|
const next = dialog.querySelector('[data-guide-next]');
|
|
const close = dialog.querySelector('[data-guide-close]');
|
|
const error = dialog.querySelector('[data-guide-error]');
|
|
const unsaved = dialog.querySelector('[data-guide-unsaved]');
|
|
let index = 0;
|
|
let saving = false;
|
|
|
|
function showStep() {
|
|
steps.forEach((step, number) => { step.hidden = number !== index; });
|
|
dialog.querySelector('[data-guide-progress]').textContent = `Шаг ${index + 1} из ${steps.length}`;
|
|
back.disabled = index === 0;
|
|
next.textContent = index === steps.length - 1 ? 'Завершить подсказки' : 'Далее';
|
|
steps[index].scrollTop = 0;
|
|
steps[index].querySelector('h3').focus({preventScroll: true});
|
|
}
|
|
function open() {
|
|
index = 0;
|
|
error.hidden = true;
|
|
unsaved.hidden = true;
|
|
dialog.showModal();
|
|
showStep();
|
|
}
|
|
async function finish() {
|
|
if (saving) return;
|
|
if (dialog.dataset.guidePending !== 'true') {
|
|
dialog.close();
|
|
return;
|
|
}
|
|
saving = true;
|
|
dialog.setAttribute('aria-busy', 'true');
|
|
close.disabled = next.disabled = back.disabled = true;
|
|
error.hidden = true;
|
|
try {
|
|
const response = await fetch('/admin/guide/dismiss', {
|
|
method: 'POST', credentials: 'same-origin', redirect: 'error',
|
|
headers: {'X-CSRF-Token': dialog.dataset.guideCsrf, 'Accept': 'application/json'}, signal: AbortSignal.timeout(15000),
|
|
});
|
|
if (!response.ok) throw new Error();
|
|
dialog.dataset.guidePending = 'false';
|
|
dialog.close();
|
|
} catch (_failure) {
|
|
error.textContent = 'Не удалось сохранить закрытие подсказок. Попробуйте ещё раз или продолжите без сохранения: при следующем открытии страницы подсказки могут появиться снова.';
|
|
error.hidden = false;
|
|
unsaved.hidden = false;
|
|
} finally {
|
|
saving = false;
|
|
dialog.removeAttribute('aria-busy');
|
|
close.disabled = next.disabled = false;
|
|
back.disabled = index === 0;
|
|
}
|
|
}
|
|
trigger?.addEventListener('click', event => { event.preventDefault(); open(); });
|
|
back.addEventListener('click', () => { index -= 1; showStep(); });
|
|
next.addEventListener('click', () => {
|
|
if (index === steps.length - 1) finish();
|
|
else { index += 1; showStep(); }
|
|
});
|
|
close.addEventListener('click', finish);
|
|
unsaved.addEventListener('click', () => { if (!saving) dialog.close(); });
|
|
dialog.addEventListener('cancel', event => { event.preventDefault(); finish(); });
|
|
dialog.addEventListener('close', () => trigger?.focus());
|
|
if (dialog.dataset.guidePending === 'true') open();
|
|
})();
|