/** Shared authentication state machine for modal and /sign/. */ (function () { 'use strict'; var config = window.aksrtData || {}; var apiRoot = String(config.apiUrl || config.restUrl || '/wp-json/aksrt/v1').replace(/\/$/, ''); var nonce = config.restNonce || ''; var modal = null; var lastModalTrigger = null; var qrStates = []; var oauthErrorMessages = { access_denied: '已取消第三方授权', cancelled: '已取消第三方授权', canceled: '已取消第三方授权', invalid_state: '授权状态已失效,请重新尝试', state_invalid: '授权状态已失效,请重新尝试', state_mismatch: '授权状态已失效,请重新尝试', state_user_mismatch: '当前账号与授权发起账号不一致,请重新尝试', provider_disabled: '该登录方式暂未启用', provider_unavailable: '该登录方式暂时不可用', provider_cancelled: '已取消第三方授权', provider_error: '第三方授权失败,请稍后重试', callback_failed: '第三方授权失败,请稍后重试', code_missing: '授权回调缺少必要信息,请重新尝试', proxy_config: '代理登录配置不可用,请联系管理员', account_match_failed: '第三方账号匹配失败,请重试', login_failed: '第三方登录失败,请重试', bind_failed: '第三方账号绑定失败,请重试', bind_verification_required: '请先完成人机验证后再绑定', binding_conflict: '该第三方账号已绑定其他账号', account_conflict: '该第三方账号无法绑定到当前账号', already_bound: '该第三方账号已绑定其他账号', timeout: '第三方授权已超时,请重试', }; var oauthProviderLabels = { github: 'GitHub', gitee: 'Gitee', qq: 'QQ', google: 'Google', weibo: '微博', weixin: '微信', weixingzh: '微信公众号', }; function request(path, data, options) { options = options || {}; return fetch(apiRoot + '/auth/' + path, { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': nonce }, body: JSON.stringify(data), signal: options.signal, }).then(function (response) { return response.json().catch(function () { return {}; }).then(function (body) { if (!response.ok || body.success === false) { throw new Error(body.message || (body.data && body.data.message) || '请求失败,请稍后再试'); } return body.data || body; }); }); } function formData(form) { var data = {}; new FormData(form).forEach(function (value, key) { data[key] = value; }); return data; } function escapeHtml(value) { return String(value || '').replace(/[&<>"']/g, function (char) { return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[char]; }); } function notify(text, type) { if (!text || typeof window.notyf !== 'function') return; window.notyf(escapeHtml(text), type || 'info'); } function cleanOAuthResult(url) { ['oauth_action', 'oauth_provider', 'oauth_error', 'oauth_bound'].forEach(function (key) { url.searchParams.delete(key); }); if (window.history && window.history.replaceState) { window.history.replaceState({}, '', url.pathname + url.search + url.hash); } } function showOAuthResultToast() { if (!window.URL || document.documentElement.dataset.aksrtOauthResultHandled === 'true') return; var url = new URL(window.location.href); var action = url.searchParams.get('oauth_action'); if (['login', 'bind', 'error'].indexOf(action) === -1) return; var userCenterOwnsBind = action === 'bind' && /\/user(?:\/settings)?\/?$/.test(url.pathname) && document.querySelector('[data-identity-root], [data-aksrt-settings-root]'); if (userCenterOwnsBind) return; document.documentElement.dataset.aksrtOauthResultHandled = 'true'; var provider = url.searchParams.get('oauth_provider') || ''; var providerLabel = oauthProviderLabels[provider] || ''; var message = ''; var type = 'success'; if (action === 'login') message = providerLabel ? providerLabel + '登录成功' : '登录成功'; if (action === 'bind') message = providerLabel ? providerLabel + '绑定成功' : '第三方账号绑定成功'; if (action === 'error') { type = 'danger'; message = oauthErrorMessages[url.searchParams.get('oauth_error') || ''] || '第三方授权失败,请重试'; } notify(message, type); cleanOAuthResult(url); } function qrState(root) { if (root._aksrtQrState) return root._aksrtQrState; root._aksrtQrState = { root: root, timer: null, timeout: null, controller: null, inFlight: false, sequence: 0, token: '', startedAt: 0, backoff: 0, terminal: false, }; qrStates.push(root._aksrtQrState); return root._aksrtQrState; } function qrNodes(root) { var box = root.querySelector('[data-auth-qrcode]'); return { box: box, content: box && box.querySelector('[data-auth-qr-content]'), status: box && box.querySelector('[data-auth-qr-status]'), }; } function setQrStatus(root, message) { var nodes = qrNodes(root); if (nodes.status) nodes.status.textContent = message || ''; } function setQrRefresh(root, message) { var nodes = qrNodes(root); if (!nodes.box) return; nodes.box.dataset.loading = '0'; nodes.box.dataset.loaded = '0'; if (nodes.content) nodes.content.innerHTML = ''; setQrStatus(root, message); } function isRootActive(root) { if (!root || root.dataset.activeTab !== 'oauth' || document.visibilityState !== 'visible') return false; if (root.dataset.surface !== 'modal') return document.documentElement.contains(root); return !!modal && modal.classList.contains('is-open') && modal.contains(root); } function stopQr(root) { var state = qrState(root); state.sequence += 1; if (state.timer) window.clearTimeout(state.timer); if (state.timeout) window.clearTimeout(state.timeout); state.timer = null; state.timeout = null; if (state.controller) { try { state.controller.abort(); } catch (_) {} } state.controller = null; state.inFlight = false; } function finishQr(root, status, message) { var state = qrState(root); stopQr(root); state.terminal = true; state.token = ''; setQrRefresh(root, message || (status === 'expired' ? '二维码已过期,点击刷新' : '二维码登录已结束,点击刷新')); } function qrRequest(root, path, payload) { var state = qrState(root); if (state.inFlight) return Promise.resolve(null); state.inFlight = true; var controller = window.AbortController ? new window.AbortController() : null; var timedOut = false; state.controller = controller; state.timeout = window.setTimeout(function () { timedOut = true; if (controller) controller.abort(); }, 15000); return request(path, payload, { signal: controller ? controller.signal : undefined }).catch(function (error) { if (timedOut) { var timeoutError = new Error('二维码请求超时'); timeoutError.code = 'QR_TIMEOUT'; throw timeoutError; } throw error; }).finally(function () { if (state.controller !== controller) return; if (state.timeout) window.clearTimeout(state.timeout); state.timeout = null; state.controller = null; state.inFlight = false; }); } function scheduleQrPoll(root, delay) { var state = qrState(root); if (!state.token || state.terminal || !isRootActive(root)) return; if (state.startedAt && Date.now() - state.startedAt >= 300000) { finishQr(root, 'timeout', '二维码登录已超时,点击刷新'); return; } if (state.timer) window.clearTimeout(state.timer); var wait = delay === 0 ? 0 : Math.min(30000, Math.max(3000, Number(delay) || 3000) * Math.pow(2, Math.min(3, state.backoff))); state.timer = window.setTimeout(function () { state.timer = null; pollQr(root); }, wait); } function pollQr(root) { var state = qrState(root); if (!state.token || state.terminal || state.inFlight || !isRootActive(root)) return; qrRequest(root, 'check-qrcode-login', { token: state.token, action: root.dataset.oauthIntent || 'login', redirect_to: root.dataset.redirectTo || window.location.href, }).then(function (result) { if (!result || !isRootActive(root)) return; if (result.needs_binding && result.redirect) { stopQr(root); setQrStatus(root, '需要绑定本地账号,正在跳转'); notify('请绑定已有账号或注册新账号', 'info'); window.location.assign(result.redirect); return; } if (result.bound && result.redirect) { stopQr(root); setQrStatus(root, '绑定成功,正在跳转'); notify('微信公众号绑定成功', 'success'); window.location.assign(result.redirect); return; } if (result.logged_in || result.status === 'logged_in') { stopQr(root); setQrStatus(root, '登录成功,正在跳转'); notify('登录成功', 'success'); window.location.assign(result.redirect || window.location.href); return; } if (result.status === 'expired') { finishQr(root, 'expired', '二维码已过期,点击刷新'); notify('二维码已过期,请刷新后重试', 'warning'); return; } if (['denied', 'cancelled', 'canceled', 'failed', 'error'].indexOf(result.status) !== -1) { finishQr(root, result.status, '二维码登录未完成,点击刷新'); notify('二维码登录未完成,请刷新后重试', 'danger'); return; } state.backoff = 0; setQrStatus(root, result.message || (result.status === 'scanned' ? '已扫码,请在微信中确认' : '等待扫码确认')); scheduleQrPoll(root, result.poll_interval ? Number(result.poll_interval) * 1000 : 3000); }).catch(function (error) { if (!isRootActive(root) || (error && error.name === 'AbortError')) return; state.backoff = Math.min(3, state.backoff + 1); setQrStatus(root, error && error.code === 'QR_TIMEOUT' ? '状态检查超时,正在重试' : '状态检查失败,正在重试'); scheduleQrPoll(root, 3000); }); } function loadQr(root, force) { var nodes = qrNodes(root); if (!nodes.box) return; var state = qrState(root); if (force) { stopQr(root); state.token = ''; state.startedAt = 0; state.backoff = 0; state.terminal = false; nodes.box.dataset.loaded = '0'; } if (state.inFlight || nodes.box.dataset.loading === '1') return; if (state.token && !state.terminal) { scheduleQrPoll(root, 0); return; } if (nodes.box.dataset.loaded === '1' && state.terminal) return; nodes.box.dataset.loading = '1'; setQrStatus(root, '正在获取二维码'); var qrPayload = { action: root.dataset.oauthIntent || 'login', redirect_to: root.dataset.redirectTo || window.location.href, }; if (root.dataset.bindPass) qrPayload.bind_pass = root.dataset.bindPass; qrRequest(root, 'qrcode-login', qrPayload).then(function (result) { if (!result || !isRootActive(root)) return; nodes.box.dataset.loading = '0'; nodes.box.dataset.loaded = '1'; if (nodes.content) nodes.content.innerHTML = result.qr_html || ''; state.token = result.token || ''; state.startedAt = Date.now(); state.backoff = 0; state.terminal = result.mode !== 'scan' || !state.token; setQrStatus(root, state.terminal ? '请按页面提示完成登录' : '请使用微信扫描二维码'); if (!state.terminal) scheduleQrPoll(root, result.poll_interval ? Number(result.poll_interval) * 1000 : 3000); }).catch(function (error) { if (!isRootActive(root) || (error && error.name === 'AbortError')) return; state.terminal = true; setQrRefresh(root, '二维码加载失败,点击重试'); notify(error.message, 'danger'); }); } function activate(root, tab, updateUrl) { var panel = root.querySelector('[data-auth-panel="' + tab + '"]'); if (!panel) return; if (root.dataset.activeTab === 'oauth' && tab !== 'oauth') stopQr(root); root.querySelectorAll('[data-auth-panel]').forEach(function (item) { var active = item === panel; item.hidden = !active; item.setAttribute('aria-hidden', active ? 'false' : 'true'); }); root.querySelectorAll('[data-auth-tab]').forEach(function (item) { item.setAttribute('aria-selected', item.dataset.authTab === tab ? 'true' : 'false'); }); root.dataset.activeTab = tab; if (updateUrl && root.dataset.surface === 'page' && window.history && window.URL) { var url = new URL(window.location.href); url.searchParams.set('tab', tab); window.history.replaceState({}, '', url.toString()); } var focus = panel.querySelector('input:not([type="hidden"]), button, a[href], [tabindex]:not([tabindex="-1"])'); if (focus) window.setTimeout(function () { focus.focus(); }, 30); if (tab === 'oauth') loadQr(root, false); } function submitQrCode(form) { var data = formData(form); var root = form.closest('[data-aksrt-auth]'); data.action = root ? (root.dataset.oauthIntent || 'login') : 'login'; data.redirect_to = root ? (root.dataset.redirectTo || window.location.href) : window.location.href; if (root && root.dataset.bindPass) data.bind_pass = root.dataset.bindPass; var button = form.querySelector('button[type="submit"]'); if (button) button.disabled = true; request('weixingzh-code', data).then(function (result) { if (result.needs_binding) { notify('请绑定已有账号或注册新账号', 'info'); } else if (result.bound) { notify('微信公众号绑定成功', 'success'); } else { notify('登录成功', 'success'); } window.location.assign(result.redirect || window.location.href); }).catch(function (error) { if (button) button.disabled = false; notify(error.message, 'danger'); }); } function setBusy(form, busy) { var button = form.querySelector('.sign-submit'); if (!button) return; button.disabled = busy; var spinner = button.querySelector('.fa-spinner'); if (spinner) spinner.hidden = !busy; } function startCountdown(button, seconds) { var original = button.dataset.label || button.textContent; button.dataset.label = original; button.disabled = true; var left = Math.max(1, Number(seconds) || 60); button.textContent = left + 's'; var timer = window.setInterval(function () { left -= 1; if (left <= 0) { window.clearInterval(timer); button.disabled = false; button.textContent = original; } else { button.textContent = left + 's'; } }, 1000); } function captchaScene(scene) { return scene === 'resetpassword' || scene === 'reset-password' ? 'lostpassword' : scene; } function captchaFormScene(form, fallback) { var mount = form && form.querySelector ? form.querySelector('[data-aksrt-captcha-config][data-scene]') : null; return mount ? (mount.getAttribute('data-scene') || captchaScene(fallback)) : captchaScene(fallback); } function captchaScope(form) { return form || document; } function resetCaptcha(scene, scope) { if (window.AKSRTCaptcha) window.AKSRTCaptcha.reset(captchaScene(scene), captchaScope(scope)); } function sendCode(button) { var form = button.closest('form'); var target = form && form.querySelector('[name="target"]'); if (!target || !target.value.trim()) { notify('请先填写邮箱或手机号', 'warning'); return; } button.disabled = true; var payload = formData(form); payload.scene = button.dataset.sendCode; payload.target = target.value.trim(); payload.channel = (form.querySelector('[name="channel"]') || {}).value || ''; var scene = captchaFormScene(form, payload.scene); var captcha = window.AKSRTCaptcha; var ticket = captcha ? captcha.run(captchaScene(scene), captchaScope(form)) : Promise.resolve({}); ticket.then(function (captchaPayload) { if (captchaPayload === null) { button.disabled = false; notify('请先完成人机验证', 'warning'); return null; } payload = formData(form); payload.scene = button.dataset.sendCode; payload.target = target.value.trim(); payload.channel = (form.querySelector('[name="channel"]') || {}).value || ''; Object.assign(payload, captchaPayload || {}); return request('code', payload).then(function (result) { notify(result.message || '验证码已发送', 'success'); startCountdown(button, result.countdown || 60); }).catch(function (error) { button.disabled = false; notify(error.message, 'danger'); }).finally(function () { resetCaptcha(scene, form); }); }).catch(function (error) { button.disabled = false; resetCaptcha(scene, form); notify(error.message || '人机验证失败,请重试', 'danger'); }); } function submit(form) { var action = form.dataset.authForm; var scene = captchaFormScene(form, action); var captcha = window.AKSRTCaptcha; setBusy(form, true); (captcha ? captcha.run(scene, captchaScope(form)) : Promise.resolve({})).then(function (captchaPayload) { if (captchaPayload === null) { setBusy(form, false); notify('请先完成人机验证', 'warning'); return null; } var payload = formData(form); if (action === 'register' && payload.channel !== 'phone') payload.user_email = payload.target; Object.assign(payload, captchaPayload || {}); return request(action, payload).then(function (result) { notify(result.message || '操作成功', 'success'); if (result.redirect) window.setTimeout(function () { window.location.assign(result.redirect); }, 350); }).catch(function (error) { notify(error.message, 'danger'); setBusy(form, false); }).finally(function () { resetCaptcha(scene, form); }); }).catch(function (error) { setBusy(form, false); resetCaptcha(scene, form); notify(error.message || '人机验证失败,请重试', 'danger'); }); } function toggleLoginMode(root, button) { var password = root.querySelector('[data-auth-password-fields]'); var code = root.querySelector('[data-auth-code-fields]'); if (!password || !code) return; var showCode = code.hidden; code.hidden = !showCode; password.hidden = showCode; button.textContent = showCode ? '使用账号密码登录' : '使用验证码登录'; } function setOAuthRedirect(root, redirect) { if (!redirect || !window.URL) return; root.querySelectorAll('a[data-provider][href]').forEach(function (link) { var url; try { url = new URL(link.href, window.location.href); } catch (_) { return; } if (url.origin !== window.location.origin) return; if (!link.dataset.oauthStartHref) link.dataset.oauthStartHref = url.toString(); url = new URL(link.dataset.oauthStartHref, window.location.href); url.searchParams.set('redirect_to', redirect); link.href = url.toString(); }); } // 邀请码输入实时校验(公开只读接口;提交时服务端仍是硬门禁)。 function initInviteVerify(root) { root.querySelectorAll('input[data-invite-verify]').forEach(function (input) { if (input.dataset.inviteVerifyBound === '1') return; input.dataset.inviteVerifyBound = '1'; var feedback = root.querySelector('[data-invite-feedback]'); var timer = null; function setFeedback(text, isError) { if (!feedback) return; if (!text) { feedback.hidden = true; feedback.textContent = ''; feedback.classList.remove('is-error'); return; } feedback.hidden = false; feedback.textContent = text; feedback.classList.toggle('is-error', !!isError); } input.addEventListener('input', function () { if (timer) window.clearTimeout(timer); var code = input.value.trim(); if (!code) { setFeedback(''); return; } timer = window.setTimeout(function () { window.fetch('/wp-json/aksrt/v1/invite-code/verify?code=' + encodeURIComponent(code), { credentials: 'same-origin' }) .then(function (response) { return response.ok ? response.json() : null; }) .then(function (payload) { if (!payload) { setFeedback(''); return; } setFeedback(payload.valid ? '邀请码有效。' : '邀请码无效或已用完。', !payload.valid); }) .catch(function () { setFeedback(''); }); }, 400); }); }); } function initRoot(root) { root.querySelectorAll('input').forEach(function (input) { if (!input.hasAttribute('placeholder')) input.setAttribute('placeholder', ' '); }); root.querySelectorAll('form').forEach(function (form) { form.noValidate = true; }); root.querySelectorAll('[data-auth-tab]').forEach(function (tab) { tab.setAttribute('role', 'tab'); var panel = root.querySelector('[data-auth-panel="' + tab.dataset.authTab + '"]'); if (panel && panel.id) tab.setAttribute('aria-controls', panel.id); }); root.querySelectorAll('[data-password-show]').forEach(function (button) { button.setAttribute('aria-pressed', 'false'); if (!button.getAttribute('aria-label')) button.setAttribute('aria-label', '显示密码'); }); setOAuthRedirect(root, root.dataset.redirectTo || ''); initInviteVerify(root); var initial = root.dataset.initialTab || 'signin'; if (initial === 'oauth' && window.matchMedia && window.matchMedia('(max-width: 767px)').matches) initial = 'signin'; var mayActivateQr = initial !== 'oauth' || document.visibilityState === 'visible'; if (root.dataset.surface === 'modal' && (!modal || !modal.classList.contains('is-open'))) mayActivateQr = false; if (!mayActivateQr) initial = 'signin'; activate(root, initial, false); root.addEventListener('click', function (event) { var tab = event.target.closest('[data-auth-tab]'); if (tab) { event.preventDefault(); activate(root, tab.dataset.authTab, true); return; } var password = event.target.closest('[data-password-show]'); if (password) { var input = password.closest('.floating-input').querySelector('input'); var visible = input.type === 'password'; input.type = visible ? 'text' : 'password'; password.setAttribute('aria-label', visible ? '隐藏密码' : '显示密码'); password.setAttribute('aria-pressed', visible ? 'true' : 'false'); password.querySelector('i').className = visible ? 'fa fas fa-eye-slash' : 'fa fas fa-eye'; return; } var send = event.target.closest('[data-send-code]'); if (send) { event.preventDefault(); sendCode(send); return; } var mode = event.target.closest('[data-login-mode]'); if (mode) { event.preventDefault(); toggleLoginMode(root, mode); return; } var refreshQr = event.target.closest('[data-auth-refresh-qr]'); if (refreshQr) { event.preventDefault(); loadQr(root, true); } }); root.addEventListener('submit', function (event) { var qrForm = event.target.closest('[data-aksrt-weixingzh-code]'); if (qrForm) { event.preventDefault(); if (validateForm(qrForm)) submitQrCode(qrForm); return; } var form = event.target.closest('[data-auth-form]'); if (!form) return; event.preventDefault(); if (!validateForm(form)) return; submit(form); }); } function validateForm(form) { if (!form.checkValidity || form.checkValidity()) return true; var field = form.querySelector(':invalid'); notify((field && field.validationMessage) || '请完整填写表单', 'warning'); if (field && typeof field.focus === 'function') field.focus(); return false; } function authPageUrl(tab, redirect) { var routes = config.routes || {}; var base = tab === 'signup' ? routes.register : routes.login; var url = new URL(base || '/sign/', window.location.href); url.searchParams.set('tab', tab || 'signin'); if (redirect) url.searchParams.set('redirect_to', redirect); return url.toString(); } function focusableModalItems() { if (!modal) return []; return Array.prototype.filter.call(modal.querySelectorAll('a[href], button:not([disabled]), input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'), function (item) { return item.offsetParent !== null && !item.closest('[hidden]'); }); } function openModal(tab, redirect, trigger) { if (!modal) { window.location.assign(authPageUrl(tab, redirect)); return; } lastModalTrigger = trigger || document.activeElement; modal.classList.add('is-open'); modal.setAttribute('aria-hidden', 'false'); document.body.classList.add('auth-modal-open'); var root = modal.querySelector('[data-aksrt-auth]'); if (root) { var targetRedirect = redirect || window.location.href; root.dataset.redirectTo = targetRedirect; root.dataset.oauthIntent = tab === 'oauth' && trigger && trigger.dataset.oauthIntent === 'bind' ? 'bind' : 'login'; root.querySelectorAll('[name="redirect_to"]').forEach(function (input) { input.value = targetRedirect; }); setOAuthRedirect(root, targetRedirect); activate(root, tab || 'signin', false); } } function closeModal(storeDismissal) { if (!modal || !modal.classList.contains('is-open')) return; var root = modal.querySelector('[data-aksrt-auth]'); if (root) stopQr(root); modal.classList.remove('is-open'); modal.setAttribute('aria-hidden', 'true'); document.body.classList.remove('auth-modal-open'); if (storeDismissal && Number(modal.dataset.autoExpires) > 0) { var until = Date.now() + Number(modal.dataset.autoExpires) * 3600000; window.localStorage.setItem('aksrtAuthAutoUntil', String(until)); } var restore = lastModalTrigger; lastModalTrigger = null; if (restore && document.documentElement.contains(restore) && typeof restore.focus === 'function') restore.focus(); } function handleModalKeydown(event) { if (!modal || !modal.classList.contains('is-open')) return; if (event.key === 'Escape') { event.preventDefault(); closeModal(true); return; } if (event.key !== 'Tab') return; var items = focusableModalItems(); if (!items.length) { event.preventDefault(); modal.focus(); return; } var first = items[0]; var last = items[items.length - 1]; if (event.shiftKey && (document.activeElement === first || !modal.contains(document.activeElement))) { event.preventDefault(); last.focus(); } else if (!event.shiftKey && document.activeElement === last) { event.preventDefault(); first.focus(); } } function init() { if (document.documentElement.dataset.aksrtAuthInitialized === '1') return; document.documentElement.dataset.aksrtAuthInitialized = '1'; showOAuthResultToast(); document.querySelectorAll('[data-aksrt-auth]').forEach(initRoot); modal = document.querySelector('[data-auth-modal]'); document.addEventListener('click', function (event) { var trigger = event.target.closest('[data-aksrt-auth-required], .aksrt-login-trigger, #nav-login-btn, .signin-loader, .signup-loader, .qrcode-signin'); if (!trigger) return; event.preventDefault(); var tab = trigger.classList.contains('signup-loader') ? 'signup' : (trigger.classList.contains('qrcode-signin') ? 'oauth' : 'signin'); openModal(tab, trigger.dataset.authRedirect || window.location.href, trigger); }); if (modal) { modal.addEventListener('click', function (event) { if (event.target.closest('[data-auth-close]')) closeModal(true); }); document.addEventListener('keydown', handleModalKeydown); if (modal.dataset.auto === '1' && Number(window.localStorage.getItem('aksrtAuthAutoUntil') || 0) < Date.now()) { window.setTimeout(function () { openModal(modal.querySelector('[data-aksrt-auth]').dataset.initialTab || 'signin', window.location.href, null); }, Math.max(1, Number(modal.dataset.autoWait) || 5) * 1000); } } document.addEventListener('visibilitychange', function () { qrStates.forEach(function (state) { if (document.visibilityState !== 'visible') stopQr(state.root); else if (isRootActive(state.root)) loadQr(state.root, false); }); }); } jQuery(document).off('auto_fun.aksrt-auth').on('auto_fun.aksrt-auth', init); }());