/* Главная: общий вход, выбор феша и демонстрация с учебными данными. */ (function (window, document) { 'use strict'; var page = document.getElementById('feis-home'); if (!page || page.getAttribute('data-initialized') === '1') { return; } page.setAttribute('data-initialized', '1'); var $ = window.jQuery; var destination = '/'; var allowedDestinations = ['/', '/personal/', '/teacher/', '/organizer/', '/dancer/']; var competitionDestinations = ['/teacher/', '/organizer/', '/dancer/']; var intentKey = 'feisinfo.home.competition-intent'; var status = page.querySelector('#status'); var loginForm = page.querySelector('#home-login'); document.documentElement.lang = document.body.lang; var menuToggle = page.querySelector('[data-home-menu-toggle]'); var quickMenu = page.querySelector('#home-quick-menu'); function closeQuickMenu(restoreFocus) { quickMenu.hidden = true; menuToggle.setAttribute('aria-expanded', 'false'); if (restoreFocus) { menuToggle.focus(); } } menuToggle.addEventListener('click', function (event) { quickMenu.hidden = !quickMenu.hidden; menuToggle.setAttribute('aria-expanded', quickMenu.hidden ? 'false' : 'true'); if (!quickMenu.hidden && event.detail === 0) { quickMenu.querySelector('a, button').focus(); } }); quickMenu.addEventListener('click', function (event) { if (event.target.closest('a, button')) { closeQuickMenu(false); } }); document.addEventListener('click', function (event) { if (!quickMenu.hidden && !quickMenu.contains(event.target) && !menuToggle.contains(event.target)) { closeQuickMenu(false); } }); document.addEventListener('keydown', function (event) { if (event.key === 'Escape' && !quickMenu.hidden) { closeQuickMenu(true); } }); window.addEventListener('resize', function () { if (window.matchMedia && window.matchMedia('(min-width: 721px)').matches) { closeQuickMenu(false); } }); function cookieValue(name) { var prefix = name + '='; var parts = document.cookie.split(';'); for (var index = 0; index < parts.length; index++) { var part = parts[index].trim(); if (part.indexOf(prefix) === 0) { try { return decodeURIComponent(part.slice(prefix.length)); } catch (error) { return part.slice(prefix.length); } } } return ''; } function refreshContext() { if (document.hidden) { return; } var marker = page.getAttribute('data-context-marker'); var currentMarker = cookieValue('session_id'); // Это обновление контекста навигации, а не проверка доступа к аккаунту. if (marker && currentMarker && currentMarker !== marker) { window.location.reload(); } } window.addEventListener('pageshow', function (event) { if (event.persisted) { window.location.reload(); } else { refreshContext(); } }); document.addEventListener('visibilitychange', refreshContext); function showStatus(element, message, failed) { if (element) { element.textContent = message; element.classList.toggle('is-error', failed); } } function busy(form, enabled) { form.setAttribute('aria-busy', enabled ? 'true' : 'false'); Array.prototype.forEach.call(form.querySelectorAll('input, button, select'), function (input) { input.disabled = enabled; }); } Array.prototype.forEach.call(page.querySelectorAll('[data-home-login]'), function (button) { button.addEventListener('click', function () { destination = allowedDestinations.indexOf(button.getAttribute('data-next')) !== -1 ? button.getAttribute('data-next') : '/'; var reducedMotion = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches; document.getElementById('home-account').scrollIntoView({ behavior: reducedMotion ? 'auto' : 'smooth', block: 'center' }); if (loginForm) { loginForm.querySelector('#email').focus({ preventScroll: true }); } }); }); if (loginForm && $) { loginForm.addEventListener('submit', function (event) { event.preventDefault(); if (!loginForm.checkValidity() || loginForm.getAttribute('aria-busy') === 'true') { return; } var credentials = { action: 'login', login: loginForm.querySelector('#email').value, password: loginForm.querySelector('#password').value }; busy(loginForm, true); showStatus(status, '', false); $.ajax({ url: '/general_includings/login_actions.php', type: 'POST', data: credentials, success: function (response) { if (String(response).trim() === '1') { var eventId = Number(page.getAttribute('data-feis-id')); if (competitionDestinations.indexOf(destination) !== -1 && eventId > 0) { try { window.sessionStorage.setItem(intentKey, JSON.stringify({ route: destination, feisId: eventId, expiresAt: Date.now() + 5 * 60 * 1000 })); } catch (error) { // При недоступном хранилище открываем главную, а не другой феш. } window.location.assign('/'); } else { window.location.assign(destination); } return; } // Сообщение старого обработчика показываем текстом, без выполнения HTML/JS. var messageTemplate = document.createElement('template'); messageTemplate.innerHTML = String(response); Array.prototype.forEach.call(messageTemplate.content.querySelectorAll('script, style'), function (element) { element.remove(); }); var message = messageTemplate.content.textContent.trim(); showStatus(status, message && message !== '0' ? message : page.getAttribute('data-login-error'), true); }, error: function () { showStatus(status, page.getAttribute('data-login-error'), true); }, complete: function () { busy(loginForm, false); } }); }); } Array.prototype.forEach.call(page.querySelectorAll('[data-home-logout]'), function (button) { button.addEventListener('click', function () { if (!$ || button.disabled) { return; } button.disabled = true; $.ajax({ url: '/general_includings/login_actions.php', type: 'POST', data: { action: 'logout' }, success: function (response) { if (String(response).trim() === '1') { window.location.assign('/'); } else { showStatus(status, page.getAttribute('data-login-error'), true); } }, error: function () { showStatus(status, page.getAttribute('data-login-error'), true); }, complete: function () { button.disabled = false; } }); }); }); function normalize(value) { value = String(value).toLocaleLowerCase().replace(/ё/g, 'е'); return value.normalize ? value.normalize('NFD').replace(/[\u0300-\u036f]/g, '') : value; } function resumeCompetitionIntent() { if (Number(page.getAttribute('data-user-id')) <= 0 || !$) { return; } var intent; try { intent = JSON.parse(window.sessionStorage.getItem(intentKey)); if (!intent) { return; } if (competitionDestinations.indexOf(intent.route) === -1 || !Number.isInteger(intent.feisId) || intent.feisId <= 0 || !(intent.expiresAt > Date.now())) { window.sessionStorage.removeItem(intentKey); return; } } catch (error) { return; } if (intent.feisId === Number(page.getAttribute('data-feis-id'))) { window.sessionStorage.removeItem(intentKey); var attributes = { '/teacher/': 'data-can-register', '/organizer/': 'data-can-organize', '/dancer/': 'data-has-entries' }; if (page.getAttribute(attributes[intent.route]) === '1') { window.location.assign(intent.route); } else { showStatus(status, page.getAttribute(intent.route === '/organizer/' ? 'data-organizer-access' : 'data-registration-access'), true); } return; } var form = page.querySelector('[data-home-event-form]'); var eventStatus = page.querySelector('[data-home-event-status]'); busy(form, true); showStatus(eventStatus, page.getAttribute('data-saving'), false); $.ajax({ url: '/home/select_feis.php', type: 'POST', dataType: 'json', data: { feis_id: String(intent.feisId), token: page.getAttribute('data-selection-token') }, success: function (response) { if (response && response.status === 'ok' && Number(response.feis_id) === intent.feisId) { // Новая загрузка проверит права на выбранный феш перед переходом. window.location.assign('/'); } else { window.sessionStorage.removeItem(intentKey); showStatus(eventStatus, page.getAttribute('data-selection-error'), true); } }, error: function () { window.sessionStorage.removeItem(intentKey); showStatus(eventStatus, page.getAttribute('data-selection-error'), true); }, complete: function () { busy(form, false); } }); } function setupEventPicker() { var form = page.querySelector('[data-home-event-form]'); var select = form ? form.querySelector('select') : null; if (!select || select.disabled || !$) { return; } var field = form.querySelector('.home-event-control'); var eventStatus = page.querySelector('[data-home-event-status]'); var entries = Array.prototype.map.call(select.options, function (option) { return { value: option.value, name: option.textContent.trim(), city: option.getAttribute('data-city') || '', date: option.getAttribute('data-date') || '', tokens: normalize(option.textContent + ' ' + (option.getAttribute('data-city') || '')) .split(/[\s,./()–—-]+/) }; }); var selected = select.value; var input = document.createElement('input'); var toggle = document.createElement('button'); var list = document.createElement('ul'); var visible = []; var active = -1; input.id = 'home-feis-input'; input.className = 'home-event-input'; input.type = 'text'; input.autocomplete = 'off'; input.placeholder = page.getAttribute('data-search-placeholder'); input.setAttribute('role', 'combobox'); input.setAttribute('aria-autocomplete', 'list'); input.setAttribute('aria-expanded', 'false'); input.setAttribute('aria-controls', 'home-feis-options'); toggle.type = 'button'; toggle.className = 'home-event-toggle'; toggle.textContent = '⌄'; toggle.setAttribute('aria-label', form.querySelector('[data-home-event-label]').textContent); toggle.setAttribute('aria-controls', 'home-feis-options'); toggle.setAttribute('aria-expanded', 'false'); list.id = 'home-feis-options'; list.className = 'home-event-options'; list.setAttribute('role', 'listbox'); list.hidden = true; select.hidden = true; form.querySelector('.home-native-select').hidden = true; form.querySelector('[data-home-event-label]').htmlFor = input.id; field.appendChild(input); field.appendChild(toggle); field.appendChild(list); function selectedName() { var entry = entries.filter(function (item) { return item.value === selected; })[0]; return entry && entry.value !== '0' ? entry.name : ''; } function close() { list.hidden = true; input.setAttribute('aria-expanded', 'false'); toggle.setAttribute('aria-expanded', 'false'); input.removeAttribute('aria-activedescendant'); input.value = selectedName(); } function highlight(index) { active = index; Array.prototype.forEach.call(list.querySelectorAll('[role="option"]'), function (item, position) { item.classList.toggle('is-active', position === active); }); var option = list.querySelectorAll('[role="option"]')[active]; if (option) { input.setAttribute('aria-activedescendant', option.id); option.scrollIntoView({ block: 'nearest' }); } } function save(value) { if (value === selected || form.getAttribute('aria-busy') === 'true') { close(); return; } close(); busy(form, true); showStatus(eventStatus, page.getAttribute('data-saving'), false); $.ajax({ url: '/home/select_feis.php', timeout: 15000, type: 'POST', dataType: 'json', data: { feis_id: value, token: page.getAttribute('data-selection-token') }, success: function (response) { if (response && response.status === 'ok' && String(response.feis_id) === value) { window.location.hash = 'home-competition'; window.location.reload(); } else { showStatus(eventStatus, page.getAttribute('data-selection-error'), true); } }, error: function () { showStatus(eventStatus, page.getAttribute('data-selection-error'), true); }, complete: function () { busy(form, false); } }); } function open(query) { var words = normalize(query).trim().split(/\s+/).filter(Boolean); visible = entries.filter(function (entry) { return words.every(function (word) { return entry.tokens.some(function (token) { return token.indexOf(word) === 0; }); }); }); list.textContent = ''; active = -1; input.removeAttribute('aria-activedescendant'); visible.forEach(function (entry, index) { var item = document.createElement('li'); var title = document.createElement('span'); item.id = 'home-feis-option-' + index; item.className = 'home-event-option'; item.setAttribute('role', 'option'); item.setAttribute('aria-selected', entry.value === selected ? 'true' : 'false'); title.textContent = entry.name; item.appendChild(title); if (entry.city || entry.date) { var meta = document.createElement('small'); meta.textContent = [entry.city, entry.date].filter(Boolean).join(' · '); item.appendChild(meta); } item.addEventListener('mousedown', function (event) { event.preventDefault(); }); item.addEventListener('click', function () { save(entry.value); }); list.appendChild(item); }); if (!visible.length) { var empty = document.createElement('li'); empty.className = 'home-event-option'; empty.textContent = page.getAttribute('data-no-matches'); list.appendChild(empty); } list.hidden = false; input.setAttribute('aria-expanded', 'true'); toggle.setAttribute('aria-expanded', 'true'); } input.value = selectedName(); input.addEventListener('focus', function () { open(''); }); input.addEventListener('click', function () { input.select(); open(input.value === selectedName() ? '' : input.value); }); input.addEventListener('input', function () { open(input.value); }); input.addEventListener('keydown', function (event) { if (event.key === 'ArrowDown' || event.key === 'ArrowUp') { event.preventDefault(); if (list.hidden) { open(''); } if (visible.length) { var direction = event.key === 'ArrowDown' ? 1 : -1; highlight(active < 0 ? (direction > 0 ? 0 : visible.length - 1) : (active + direction + visible.length) % visible.length); } } else if (event.key === 'Enter') { event.preventDefault(); if (!list.hidden && visible[active]) { save(visible[active].value); } } else if (event.key === 'Escape' || event.key === 'Tab') { close(); } }); toggle.addEventListener('click', function () { if (!list.hidden) { close(); } else { input.focus(); open(''); } }); select.addEventListener('change', function () { save(select.value); }); form.addEventListener('submit', function (event) { event.preventDefault(); }); document.addEventListener('click', function (event) { if (!field.contains(event.target)) { close(); } }); field.addEventListener('focusout', function () { window.setTimeout(function () { if (!field.contains(document.activeElement)) { close(); } }, 0); }); } setupEventPicker(); resumeCompetitionIntent(); })(window, document);