feat(auth): rebuild the sign-in surfaces on the shared sign-card contract

The login/register page and the auth modal had drifted into a parallel
system: floating-input fields, a sign-page-card shell and a bespoke
jio-auth-modal wrapper that none of the theme's own sign CSS targeted.
The reference card rules (.sign, .sign-img, .sign-content, .line-form-input,
.scale-placeholder, .social_loginbar, .title-h-left, #u_sign .modal-dialog,
.qrcode-signin-container) have been in main.css all along, so the fix is to
render the reference DOM instead of re-styling a second one.

auth-content.php now emits one .sign.jio-panel.blur-bg.relative card with a
.tab-content of #tab-sign-in / #tab-sign-up / #tab-resetpassword /
#tab-qrcode-signin / #tab-bind panes. Each pane opens with a
.title-h-left.fa-2x heading plus a .muted-color.px12 link, fields are
.relative.line-form.mb10 > .line-form-input + .scale-placeholder +
.line-form-line, the verification trigger is the .yztx.abs-right captchsubmit
button, and submits are .but.radius.jb-blue|jb-green.padding-lg.btn-block.
Social entries come from the shared render_social_buttons() separator +
.social_loginbar, and the OAuth bind pane uses the oauth-data-box avatar card.

The modal shell is #u_sign.modal > .modal-dialog > .sign-content >
.sign-img.absolute.hide-sm + .sign, and the page shell is the reference
.container.sign-page > .row.sign-row.gutters-5 > .col-md-6(.col-md-offset-6/
.col-md-offset-3).sign-col with a .fixed.lazyload background and a blurred
fixed footer. auth.js drives .in instead of .is-open, toggles the new
password/signin-mode/invite-gate controls and no longer touches the retired
markup. The page also drops two footer-hook removals that targeted functions
which no longer exist, and opts out of the fixed-nav offset.

The sign page's custom theme setting now actually applies: Router answers
jio_forced_theme_mode, jioData.themeForced wins over the stored cookie in
theme.js, theme-toggle positions are suppressed, and the page marks html/body
dark or white accordingly.

sign.css shrinks from ~114 lines of bespoke component styling to a thin
positioning layer, and the retired classes are gone rather than kept.

Verification: php -l on every changed PHP file, node --check on both JS files,
node --test across widget-system, navigation and front-submit (873 passing),
and tools/audit-psr4-paths.php / audit-admin-contracts.php both at 0 errors.
assets/js/runtime/main.min.js was rebuilt because theme.js gained the forced
theme branch.
This commit is contained in:
kate522 committed 2026-11-04 16:04:24 +08:00
1 parent d40906b4a3
commit 41366e7fc4
15 files changed
+664 -281

No files matched your search

+136 -102
View File
@@ -1,114 +1,148 @@
/* Shared authentication contract: modal and /sign/. */
.sign {
max-width: 330px;
margin: auto;
padding: 30px 0;
color: var(--main-color, #4e5358);
/* Authentication surfaces: modal (#u_sign) and the /sign/ page.
*
* Card, line inputs, tab panes, social bar and title rules come from the shared
* theme stylesheet; this file only positions the shells around them.
*/
#u_sign.jio-auth-modal {
z-index: 100050;
}
.sign [hidden] { display: none !important; }
.sign button { font: inherit; }
.sign-logo { margin-bottom: 24px; text-align: center; }
.sign-logo img { max-width: 180px; max-height: 70px; }
.sign-logo .sign-logo-dark { display: none; }
.dark-theme .sign-logo .sign-logo-light { display: none; }
.dark-theme .sign-logo .sign-logo-dark { display: inline-block; }
.sign-logo__text { font-size: 22px; font-weight: 700; color: inherit; }
.sign-panel { animation: auth-panel-in .24s ease both; }
@keyframes auth-panel-in {
from { opacity: 0; transform: translateY(5px); }
to { opacity: 1; transform: none; }
#u_sign.jio-auth-modal.in {
display: block;
overflow-x: hidden;
overflow-y: auto;
background: rgba(0, 0, 0, 0.4);
}
.sign-header { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 23px; }
.sign-header h2 { margin: 0; font-size: 22px; line-height: 1.4; color: var(--key-color, #333); }
.sign-header span { font-size: 12px; color: var(--muted-2-color, #999); }
.sign-header button,
.sign-options button,
.sign-mode-switch { padding: 0; border: 0; background: none; color: var(--focus-color, #f04494); cursor: pointer; }
.sign-form { display: grid; gap: 17px; }
#u_sign.jio-auth-modal .modal-dialog {
opacity: 0;
transform: translateY(-12px);
transition: opacity 0.2s ease, transform 0.25s ease;
}
.floating-input { position: relative; min-height: 42px; border-bottom: 1px solid var(--main-border-color, rgba(50, 50, 50, .12)); }
.floating-input::after { content: ""; position: absolute; right: 0; bottom: -1px; left: 0; height: 2px; background: var(--focus-color, #f04494); transform: scaleX(0); transition: transform .25s; }
.floating-input:focus-within::after { transform: scaleX(1); }
.floating-input input { width: 100%; height: 42px; padding: 13px 4px 2px; border: 0; outline: 0; background: transparent; color: inherit; font-size: 14px; box-shadow: none !important; }
.floating-input label { position: absolute; top: 12px; left: 4px; color: var(--muted-color, #777); font-size: 14px; font-weight: 400; pointer-events: none; transition: all .18s; }
.floating-input input:focus + label,
.floating-input input:not(:placeholder-shown) + label,
.floating-input.is-filled label { top: 0; font-size: 10px; color: var(--focus-color, #f04494); }
.floating-input.has-action input { padding-right: 94px; }
.floating-input .password-show,
.floating-input .send-code { position: absolute; right: 0; bottom: 6px; z-index: 2; border: 0; background: none; color: var(--muted-2-color, #999); cursor: pointer; }
.floating-input .send-code { color: var(--focus-color, #f04494); font-size: 12px; }
.floating-input .send-code:disabled { color: var(--muted-2-color, #999); cursor: default; }
#u_sign.jio-auth-modal.in .modal-dialog {
opacity: 1;
transform: none;
}
.sign-options { display: flex; align-items: center; justify-content: space-between; color: var(--muted-2-color, #999); font-size: 12px; }
.sign-options label { margin: 0; font-weight: 400; }
.sign-submit { width: 100%; min-height: 42px; padding: 10px 16px; border: 0; border-radius: 5px; color: #fff; cursor: pointer; transition: opacity .2s, transform .2s; }
.sign-submit:hover { opacity: .88; transform: translateY(-1px); }
.sign-submit:disabled { opacity: .55; cursor: wait; transform: none; }
.sign-submit.jb-blue { background: linear-gradient(135deg, #59c3ff, #2b70ff); }
.sign-submit.jb-green { background: linear-gradient(135deg, #50e3a4, #16a085); }
.sign-mode-switch { justify-self: center; font-size: 12px; }
.sign-notice { margin-bottom: 16px; padding: 10px 12px; border-radius: 5px; background: rgba(255, 86, 86, .08); color: #e55353; font-size: 12px; }
.sign-hint { margin-top: -10px; color: var(--muted-2-color, #999); font-size: 11px; }
.sign-agreement { display: flex; align-items: flex-start; gap: 6px; margin: 0; color: var(--muted-2-color, #999); font-size: 11px; font-weight: 400; }
.sign-agreement a { color: var(--focus-color, #f04494); }
.sign-agreement-implicit { justify-content: center; text-align: center; }
#u_sign .sign-img {
inset: 0;
overflow: hidden;
}
.social-login { margin-top: 24px; text-align: center; }
.social-login > span { display: flex; align-items: center; gap: 10px; color: var(--muted-2-color, #999); font-size: 11px; }
.social-login > span::before,
.social-login > span::after { content: ""; flex: 1; height: 1px; background: var(--main-border-color, rgba(50, 50, 50, .08)); }
.social-login-buttons { display: flex; flex-wrap: wrap; justify-content: center; gap: 13px; margin-top: 14px; }
.social-login-item { display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; padding: 0; border: 0; border-radius: 50px; background: var(--body-bg-color, #f5f6f7); color: #fff; text-decoration: none; cursor: pointer; }
.social-login-item:hover { transform: translateY(-2px); color: var(--focus-color, #f04494); }
.oauth-button-lg .social-login-item { width: auto; padding: 0 14px; }
.oauth-button-lg .social-login-item i,
.oauth-button-lg .social-login-item svg { margin-right: 6px; font-size: 1.2em; }
.social-login-item.weibo { background: #ea5d5c; }
.social-login-item.weixingzh,
.social-login-item.weixin { background: #24b76a; }
.social-login-item.qq { background: #1296db; }
.social-login-item.github { background: #505050; }
.social-login-item.gitee { background: #c2292f; }
.social-login-item.google { background: var(--main-shadow, rgba(116, 116, 116, .08)); color: var(--main-color, #4e5358); }
.auth-qrcode { display: grid; place-items: center; width: 180px; min-height: 180px; margin: 20px auto; background: #fff; color: #38b766; text-align: center; }
.auth-qrcode [data-auth-qr-content] { display: grid; place-items: center; width: 100%; min-height: 180px; }
.auth-qrcode i { font-size: 46px; }
.auth-qrcode span { color: #777; font-size: 12px; }
#u_sign .sign-img img {
display: block;
width: 100%;
height: 100%;
border-radius: var(--main-radius);
object-fit: cover;
}
.jio-auth-modal { position: fixed; inset: 0; z-index: 100050; display: none; place-items: center; padding: 18px; }
.jio-auth-modal.is-open { display: grid; }
.auth-modal-backdrop { position: absolute; inset: 0; background: rgba(14, 18, 24, .62); backdrop-filter: blur(2px); }
#u_sign .modal-dialog { position: relative; z-index: 1; width: 400px; max-width: calc(100vw - 30px); margin: 0; }
#u_sign.has-sign-img .modal-dialog { width: 800px; }
#u_sign .modal-content { position: relative; min-height: 300px; max-height: calc(100vh - 36px); overflow-x: hidden; overflow-y: auto; border: 0; border-radius: 8px; background: var(--main-bg-color, #fff); box-shadow: 0 12px 50px rgba(0, 0, 0, .22); }
.auth-modal-close { position: absolute; top: 13px; right: 15px; z-index: 4; width: 30px; height: 30px; border: 0; border-radius: 50%; background: rgba(0, 0, 0, .04); color: var(--muted-color, #777); cursor: pointer; }
#u_sign .sign-img { position: absolute; inset: 0 45% 0 0; overflow: hidden; padding: 0; }
#u_sign .sign-img img { display: block; width: 100%; height: 100%; border-radius: 8px 0 0 8px; object-fit: cover; }
#u_sign .sign-img + .sign { max-width: unset; margin-left: 55%; padding: 34px 44px; }
#u_sign .sign > .close {
position: absolute;
top: 10px;
right: 15px;
z-index: 3;
font-size: 18px;
}
.page-template-user-sign { min-height: 100vh; background: var(--body-bg-color, #f5f6f7); }
.sign-page-background { position: fixed; inset: 0; z-index: 0; background-position: center; background-size: cover; }
.sign-topbar { position: fixed; top: 0; right: 0; left: 0; z-index: 3; display: flex; justify-content: space-between; padding: 15px 24px; background: rgba(255, 255, 255, .75); backdrop-filter: blur(12px); }
.sign-page { position: relative; z-index: 1; display: flex; align-items: center; min-height: 100vh; padding: 76px max(5vw, 20px) 56px; }
.sign-page.sign-card-position-left { justify-content: flex-start; }
.sign-page.sign-card-position-center { justify-content: center; }
.sign-page.sign-card-position-right { justify-content: flex-end; }
.sign-page-card { width: 400px; max-width: 100%; padding: 0 35px; border-radius: 8px; background: var(--main-bg-color, #fff); box-shadow: 0 10px 40px rgba(0, 0, 0, .12); }
.sign-page-footer { position: fixed; right: 0; bottom: 12px; left: 0; z-index: 2; text-align: center; color: var(--muted-2-color, #999); font-size: 12px; }
.white-theme { --main-bg-color: #fff; --body-bg-color: #f5f6f7; --main-color: #4e5358; --key-color: #333; }
.dark-theme { --main-bg-color: #24272b; --body-bg-color: #17191c; --main-color: #d7d9dc; --key-color: #fff; --main-border-color: rgba(255, 255, 255, .12); }
body.auth-modal-open { overflow: hidden; }
body.auth-modal-open {
overflow: hidden;
}
/* ---- /sign/ page shell ---- */
.page-template-user-sign {
min-height: 500px;
}
.page-template-user-sign > .fixed {
z-index: 0;
}
.sign-page {
position: relative;
z-index: 1;
min-height: 500px;
padding-top: 70px;
padding-bottom: 60px;
}
.sign-row {
min-height: calc(100vh - 130px);
display: flex;
flex-wrap: wrap;
}
.sign-page .sign {
width: 350px;
}
.sign-col {
display: flex;
justify-content: center;
align-items: center;
}
.sign-page-footer {
top: auto;
height: auto;
padding: 10px;
z-index: 2;
}
.sign .sign-passw {
border: 0;
background: none;
padding: 0;
line-height: 1;
cursor: pointer;
}
.sign .oauth-data-box .muted-box {
margin-bottom: 10px;
}
.sign .oauth-data-box .avatar-img {
--this-size: 60px;
}
.sign [data-auth-qr-content] {
display: grid;
place-items: center;
min-height: 180px;
}
.sign .qrcode-signin-container button[data-auth-refresh-qr] {
border: 0;
background: none;
padding: 10px;
color: var(--focus-color);
cursor: pointer;
}
.sign [data-invite-feedback].is-error {
color: #ff5473;
}
@media (max-width: 991px) {
#u_sign .modal-dialog,
#u_sign.has-sign-img .modal-dialog {
width: auto;
margin: 30px;
}
}
@media (max-width: 767px) {
#u_sign .modal-dialog,
#u_sign.has-sign-img .modal-dialog { width: 400px; }
#u_sign .sign-img { display: none; }
#u_sign .sign-img + .sign { max-width: 340px; margin-left: auto; padding: 30px 0; }
#u_sign .modal-content { padding: 0 24px; }
.sign-page { justify-content: center !important; padding-right: 14px; padding-left: 14px; }
.sign-page-card { padding: 0 24px; }
.sign-page {
padding-top: 20px;
}
.sign-row {
min-height: calc(100vh - 110px);
}
.sign-page .sign {
width: 340px;
max-width: 100%;
}
}
+58 -26
View File
@@ -156,7 +156,7 @@
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);
return !!modal && modal.classList.contains('in') && modal.contains(root);
}
function stopQr(root) {
@@ -329,6 +329,8 @@
root.querySelectorAll('[data-auth-panel]').forEach(function (item) {
var active = item === panel;
item.hidden = !active;
item.classList.toggle('active', active);
item.classList.toggle('in', active);
item.setAttribute('aria-hidden', active ? 'false' : 'true');
});
root.querySelectorAll('[data-auth-tab]').forEach(function (item) {
@@ -340,8 +342,12 @@
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);
// Only prompt for input on a real user switch; the initial boot should not
// steal focus (and scroll) on the modal or the full page.
if (updateUrl) {
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);
}
@@ -369,11 +375,13 @@
}
function setBusy(form, busy) {
var button = form.querySelector('.sign-submit');
var button = form.querySelector('button[type="submit"]');
if (!button) return;
button.disabled = busy;
var spinner = button.querySelector('.fa-spinner');
if (spinner) spinner.hidden = !busy;
var label = button.querySelector('[data-submit-label]');
if (label) label.hidden = busy;
}
function startCountdown(button, seconds) {
@@ -483,14 +491,13 @@
});
}
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 switchSigninMode(root, mode) {
root.querySelectorAll('[data-signin-panel]').forEach(function (panel) {
var active = panel.dataset.signinPanel === mode;
panel.hidden = !active;
panel.classList.toggle('active', active);
panel.classList.toggle('in', active);
});
}
function setOAuthRedirect(root, redirect) {
@@ -538,9 +545,6 @@
}
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');
@@ -556,7 +560,7 @@
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 (root.dataset.surface === 'modal' && (!modal || !modal.classList.contains('in'))) mayActivateQr = false;
if (!mayActivateQr) initial = 'signin';
activate(root, initial, false);
root.addEventListener('click', function (event) {
@@ -568,12 +572,15 @@
}
var password = event.target.closest('[data-password-show]');
if (password) {
var input = password.closest('.floating-input').querySelector('input');
var field = password.closest('.line-form') || password.parentElement;
var input = field ? field.querySelector('input') : null;
if (!input) return;
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';
var glyph = password.querySelector('i');
if (glyph) glyph.className = visible ? 'fa fas fa-eye-slash' : 'fa fas fa-eye';
return;
}
var send = event.target.closest('[data-send-code]');
@@ -582,10 +589,33 @@
sendCode(send);
return;
}
var mode = event.target.closest('[data-login-mode]');
var mode = event.target.closest('[data-signin-mode]');
if (mode) {
event.preventDefault();
toggleLoginMode(root, mode);
switchSigninMode(root, mode.dataset.signinMode);
return;
}
var inviteGate = event.target.closest('[data-invite-gate]');
if (inviteGate) {
event.preventDefault();
var gateInput = root.querySelector('[data-invite-gate-input]');
var gatePanel = root.querySelector('[data-invite-gate-panel]');
var formPanel = root.querySelector('[data-invite-form-panel]');
if (!gateInput || !formPanel) return;
var code = gateInput.value.trim();
if (!code) {
gateInput.setAttribute('aria-invalid', 'true');
notify('请输入邀请码', 'warning');
return;
}
gateInput.setAttribute('aria-invalid', 'false');
var hiddenInvite = formPanel.querySelector('[data-invite-value]');
if (hiddenInvite) hiddenInvite.value = code;
if (gatePanel) { gatePanel.hidden = true; gatePanel.classList.remove('active', 'in'); }
formPanel.hidden = false;
formPanel.classList.add('active', 'in');
var focus = formPanel.querySelector('input:not([type="hidden"])');
if (focus) window.setTimeout(function () { focus.focus(); }, 30);
return;
}
var refreshQr = event.target.closest('[data-auth-refresh-qr]');
@@ -639,9 +669,10 @@
return;
}
lastModalTrigger = trigger || document.activeElement;
modal.classList.add('is-open');
modal.style.display = 'block';
modal.classList.add('in');
modal.setAttribute('aria-hidden', 'false');
document.body.classList.add('auth-modal-open');
document.body.classList.add('auth-modal-open', 'modal-open');
var root = modal.querySelector('[data-jio-auth]');
if (root) {
var targetRedirect = redirect || window.location.href;
@@ -654,12 +685,13 @@
}
function closeModal(storeDismissal) {
if (!modal || !modal.classList.contains('is-open')) return;
if (!modal || !modal.classList.contains('in')) return;
var root = modal.querySelector('[data-jio-auth]');
if (root) stopQr(root);
modal.classList.remove('is-open');
modal.classList.remove('in');
modal.style.display = '';
modal.setAttribute('aria-hidden', 'true');
document.body.classList.remove('auth-modal-open');
document.body.classList.remove('auth-modal-open', 'modal-open');
if (storeDismissal && Number(modal.dataset.autoExpires) > 0) {
var until = Date.now() + Number(modal.dataset.autoExpires) * 3600000;
window.localStorage.setItem('jioAuthAutoUntil', String(until));
@@ -670,7 +702,7 @@
}
function handleModalKeydown(event) {
if (!modal || !modal.classList.contains('is-open')) return;
if (!modal || !modal.classList.contains('in')) return;
if (event.key === 'Escape') {
event.preventDefault();
closeModal(true);
+6 -1
View File
@@ -165,9 +165,14 @@
if (themeInitialized) return;
themeInitialized = true;
var forced = window.jioData && window.jioData.themeForced;
var stored = getStoredTheme();
var configuredMode = (window.jioData && window.jioData.themeMode) || "light";
if (stored === "dark" || stored === "light") {
if (forced === "dark" || forced === "light") {
// A surface can pin the theme (the sign page's custom theme mode); a
// stored preference must not override it.
applyTheme(forced);
} else if (stored === "dark" || stored === "light") {
applyTheme(stored);
} else {
applyTheme(resolveConfiguredTheme(configuredMode));
+1 -1
View File
@@ -1 +1 @@
(function($,window2,document2){"use strict";function closeNotyf($element){$element.addClass("notyn-out"),window2.setTimeout(function(){$element.remove()},1e3)}function notyf2(message,type,time,id){var $body=jQuery(document2.body);jQuery(".notyn").length||$body.append('<div class="notyn"></div>'),type=type||"success",type==="error"&&(type="danger"),time=time||5e3,time=time<100?time*1e3:time;var idAttribute=id?' id="'+id+'"':"",$notification=jQuery('<div class="noty1"'+idAttribute+'><div class="notyf '+type+'">'+message+"</div></div>"),shouldClose=!id;id&&jQuery("#"+id).length?(jQuery("#"+id).find(".notyf").removeClass().addClass("notyf "+type).html(message),$notification=jQuery("#"+id),shouldClose=!0):jQuery(".notyn").append($notification),shouldClose&&window2.setTimeout(function(){closeNotyf($notification)},time)}jQuery(document2.body).on("click",".noty1",function(){closeNotyf(jQuery(this))}),window2.notyf=notyf2})(jQuery,window,document),(function(window2){"use strict";var allowedKinds={identity:!0,badges:!0,orders:!0,vip:!0},allowedEvents={click:!0,shell:!0,"first-content":!0,ready:!0,"action-start":!0,"action-end":!0,unauthorized:!0,error:!0},sessions=Object.create(null),sequence=0,maxSessions=100;function normalize(value,fallback){var normalized=String(value||fallback||"").toLowerCase().replace(/[^a-z0-9-]/g,"");return normalized||fallback}function now(){return window2.performance&&typeof window2.performance.now=="function"?window2.performance.now():0}function markName(session,event){return"jio-modal-"+session.kind+"-"+session.id+"-"+event}function emit(session,event){if(!(!window2.performance||typeof window2.performance.mark!="function")){var name=markName(session,event);if(window2.performance.mark(name),session.marks[event]=name,typeof window2.performance.measure=="function"&&session.marks.click&&event!=="click")try{window2.performance.measure("jio-modal-"+session.kind+"-"+session.id+"-click-to-"+event,session.marks.click,name)}catch{}}}function start(kind){var safeKind=normalize(kind,"unknown");allowedKinds[safeKind]||(safeKind="unknown"),sequence+=1;var id=String(sequence),session={id,kind:safeKind,startedAt:now(),marks:Object.create(null)};sessions[id]=session,emit(session,"click");for(var ids=Object.keys(sessions);ids.length>maxSessions;)delete sessions[ids.shift()];return id}function mark(id,event){var session=sessions[String(id||"")],safeEvent=normalize(event,"error");!session||!allowedEvents[safeEvent]||emit(session,safeEvent)}function finish(id){mark(id,"ready")}function fail(id){mark(id,"error")}window2.JioModalTelemetry={start,mark,finish,error:fail}})(window),(function(window2){"use strict";function data(){return window2.jioData||window2.jio||{}}function createIdempotencyKey(){if(window2.crypto&&typeof window2.crypto.randomUUID=="function")return window2.crypto.randomUUID();if(!window2.crypto||typeof window2.crypto.getRandomValues!="function")throw new Error("当前浏览器无法生成安全的操作标识");var bytes=new Uint8Array(16);window2.crypto.getRandomValues(bytes),bytes[6]=bytes[6]&15|64,bytes[8]=bytes[8]&63|128;var hex=Array.prototype.map.call(bytes,function(value){return value.toString(16).padStart(2,"0")}).join("");return hex.slice(0,8)+"-"+hex.slice(8,12)+"-"+hex.slice(12,16)+"-"+hex.slice(16,20)+"-"+hex.slice(20)}function restBase(){var config=data(),raw=config.restUrl||config.apiUrl||config.rest_url||"",siteUrl=config.siteUrl||config.homeUrl||window2.location.origin+"/";return window2.location.protocol==="https:"&&siteUrl.substring(0,5)==="http:"&&(siteUrl="https:"+siteUrl.substring(5)),raw?String(raw).replace(/\/$/,""):String(siteUrl).replace(/\/$/,"")+"/index.php?rest_route=/jio/v1"}function appendQuery(url2,query){if(!query)return url2;var parts=[];return typeof query=="string"?parts=query.replace(/^\?/,"").split("&").filter(Boolean):typeof query=="object"&&Object.keys(query).forEach(function(key){query[key]===void 0||query[key]===null||parts.push(encodeURIComponent(key)+"="+encodeURIComponent(String(query[key])))}),parts.length?url2+(url2.indexOf("?")>=0?"&":"?")+parts.join("&"):url2}function url(path,query){path=String(path||"");var inlineQuery="",queryIndex=path.indexOf("?");if(queryIndex>=0&&(inlineQuery=path.slice(queryIndex+1),path=path.slice(0,queryIndex)),/^https?:\/\//i.test(path))return appendQuery(path,query||inlineQuery);path.charAt(0)!=="/"&&(path="/"+path);var base=restBase(),result=(base.indexOf("rest_route=")>=0,base+path);return appendQuery(result,query||inlineQuery)}function headers(options){var config=data(),source=options&&options.headers||{},result={},nonce=config.restNonce||config.nonce||"";return Object.keys(source).forEach(function(key){result[key]=source[key]}),result.Accept||(result.Accept="application/json, text/html;q=0.9, */*;q=0.8"),nonce&&!result["X-WP-Nonce"]&&(result["X-WP-Nonce"]=nonce),options&&options.body!==void 0&&options.body!==null&&!(window2.FormData&&options.body instanceof window2.FormData)&&!result["Content-Type"]&&(result["CoLine truncated
(function($,window2,document2){"use strict";function closeNotyf($element){$element.addClass("notyn-out"),window2.setTimeout(function(){$element.remove()},1e3)}function notyf2(message,type,time,id){var $body=jQuery(document2.body);jQuery(".notyn").length||$body.append('<div class="notyn"></div>'),type=type||"success",type==="error"&&(type="danger"),time=time||5e3,time=time<100?time*1e3:time;var idAttribute=id?' id="'+id+'"':"",$notification=jQuery('<div class="noty1"'+idAttribute+'><div class="notyf '+type+'">'+message+"</div></div>"),shouldClose=!id;id&&jQuery("#"+id).length?(jQuery("#"+id).find(".notyf").removeClass().addClass("notyf "+type).html(message),$notification=jQuery("#"+id),shouldClose=!0):jQuery(".notyn").append($notification),shouldClose&&window2.setTimeout(function(){closeNotyf($notification)},time)}jQuery(document2.body).on("click",".noty1",function(){closeNotyf(jQuery(this))}),window2.notyf=notyf2})(jQuery,window,document),(function(window2){"use strict";var allowedKinds={identity:!0,badges:!0,orders:!0,vip:!0},allowedEvents={click:!0,shell:!0,"first-content":!0,ready:!0,"action-start":!0,"action-end":!0,unauthorized:!0,error:!0},sessions=Object.create(null),sequence=0,maxSessions=100;function normalize(value,fallback){var normalized=String(value||fallback||"").toLowerCase().replace(/[^a-z0-9-]/g,"");return normalized||fallback}function now(){return window2.performance&&typeof window2.performance.now=="function"?window2.performance.now():0}function markName(session,event){return"jio-modal-"+session.kind+"-"+session.id+"-"+event}function emit(session,event){if(!(!window2.performance||typeof window2.performance.mark!="function")){var name=markName(session,event);if(window2.performance.mark(name),session.marks[event]=name,typeof window2.performance.measure=="function"&&session.marks.click&&event!=="click")try{window2.performance.measure("jio-modal-"+session.kind+"-"+session.id+"-click-to-"+event,session.marks.click,name)}catch{}}}function start(kind){var safeKind=normalize(kind,"unknown");allowedKinds[safeKind]||(safeKind="unknown"),sequence+=1;var id=String(sequence),session={id,kind:safeKind,startedAt:now(),marks:Object.create(null)};sessions[id]=session,emit(session,"click");for(var ids=Object.keys(sessions);ids.length>maxSessions;)delete sessions[ids.shift()];return id}function mark(id,event){var session=sessions[String(id||"")],safeEvent=normalize(event,"error");!session||!allowedEvents[safeEvent]||emit(session,safeEvent)}function finish(id){mark(id,"ready")}function fail(id){mark(id,"error")}window2.JioModalTelemetry={start,mark,finish,error:fail}})(window),(function(window2){"use strict";function data(){return window2.jioData||window2.jio||{}}function createIdempotencyKey(){if(window2.crypto&&typeof window2.crypto.randomUUID=="function")return window2.crypto.randomUUID();if(!window2.crypto||typeof window2.crypto.getRandomValues!="function")throw new Error("当前浏览器无法生成安全的操作标识");var bytes=new Uint8Array(16);window2.crypto.getRandomValues(bytes),bytes[6]=bytes[6]&15|64,bytes[8]=bytes[8]&63|128;var hex=Array.prototype.map.call(bytes,function(value){return value.toString(16).padStart(2,"0")}).join("");return hex.slice(0,8)+"-"+hex.slice(8,12)+"-"+hex.slice(12,16)+"-"+hex.slice(16,20)+"-"+hex.slice(20)}function restBase(){var config=data(),raw=config.restUrl||config.apiUrl||config.rest_url||"",siteUrl=config.siteUrl||config.homeUrl||window2.location.origin+"/";return window2.location.protocol==="https:"&&siteUrl.substring(0,5)==="http:"&&(siteUrl="https:"+siteUrl.substring(5)),raw?String(raw).replace(/\/$/,""):String(siteUrl).replace(/\/$/,"")+"/index.php?rest_route=/jio/v1"}function appendQuery(url2,query){if(!query)return url2;var parts=[];return typeof query=="string"?parts=query.replace(/^\?/,"").split("&").filter(Boolean):typeof query=="object"&&Object.keys(query).forEach(function(key){query[key]===void 0||query[key]===null||parts.push(encodeURIComponent(key)+"="+encodeURIComponent(String(query[key])))}),parts.length?url2+(url2.indexOf("?")>=0?"&":"?")+parts.join("&"):url2}function url(path,query){path=String(path||"");var inlineQuery="",queryIndex=path.indexOf("?");if(queryIndex>=0&&(inlineQuery=path.slice(queryIndex+1),path=path.slice(0,queryIndex)),/^https?:\/\//i.test(path))return appendQuery(path,query||inlineQuery);path.charAt(0)!=="/"&&(path="/"+path);var base=restBase(),result=(base.indexOf("rest_route=")>=0,base+path);return appendQuery(result,query||inlineQuery)}function headers(options){var config=data(),source=options&&options.headers||{},result={},nonce=config.restNonce||config.nonce||"";return Object.keys(source).forEach(function(key){result[key]=source[key]}),result.Accept||(result.Accept="application/json, text/html;q=0.9, */*;q=0.8"),nonce&&!result["X-WP-Nonce"]&&(result["X-WP-Nonce"]=nonce),options&&options.body!==void 0&&options.body!==null&&!(window2.FormData&&options.body instanceof window2.FormData)&&!result["Content-Type"]&&(result["CoLine truncated
+6 -4
View File
@@ -25,15 +25,17 @@ if (!in_array($jio_mobile_align, ['top', 'left', 'right'], true)) {
$jio_initial_theme_mode = '';
if (class_exists('\Jio\Settings\Settings') && method_exists('\Jio\Settings\Settings', 'initial_theme_mode')) {
$jio_initial_theme_mode = \Jio\Settings\Settings::initial_theme_mode();
$jio_initial_theme_mode = (string) apply_filters('jio_initial_theme_mode', \Jio\Settings\Settings::initial_theme_mode());
}
$jio_has_initial_theme = in_array($jio_initial_theme_mode, ['dark', 'light'], true);
$jio_body_classes = [];
// legacy: body.nav-fixed drives top padding + hero pull-under-nav.
if (!isset($jio_header_settings['nav_fixed']) || !empty($jio_header_settings['nav_fixed'])) {
// legacy: body.nav-fixed drives top padding + hero pull-under-nav. The sign
// page lays out its own shell, so it opts out of the fixed-nav offset.
$jio_is_sign_page = function_exists('jio_is_auth_page_request') && jio_is_auth_page_request();
if (!$jio_is_sign_page && (!isset($jio_header_settings['nav_fixed']) || !empty($jio_header_settings['nav_fixed']))) {
$jio_body_classes[] = 'nav-fixed';
} else {
} elseif (!$jio_is_sign_page) {
$jio_body_classes[] = 'has-static-nav';
}
+11 -17
View File
@@ -47,16 +47,18 @@ if (!function_exists('jio_get_auth_agreement_view')) {
}
$links = [];
if ($enabled) {
$links[] = $url !== '' ? sprintf('<a href="%s" target="_blank" rel="noopener noreferrer">%s</a>', esc_url($url), esc_html__('用户协议', 'jio')) : esc_html__('用户协议', 'jio');
$links[] = $url !== '' ? sprintf('<a class="focus-color" href="%s" target="_blank" rel="noopener noreferrer">%s</a>', esc_url($url), esc_html__('用户协议', 'jio')) : esc_html__('用户协议', 'jio');
}
if ($privacy_enabled) {
$links[] = $privacy_url !== '' ? sprintf('<a href="%s" target="_blank" rel="noopener noreferrer">%s</a>', esc_url($privacy_url), esc_html__('隐私协议', 'jio')) : esc_html__('隐私协议', 'jio');
$links[] = $privacy_url !== '' ? sprintf('<a class="focus-color" href="%s" target="_blank" rel="noopener noreferrer">%s</a>', esc_url($privacy_url), esc_html__('隐私协议', 'jio')) : esc_html__('隐私协议', 'jio');
}
$links_html = implode(esc_html__('、', 'jio'), $links);
$label_html = esc_html__('我已阅读并同意', 'jio') . implode(esc_html__('和', 'jio'), $links);
return [
'enabled' => $enabled || $privacy_enabled,
'required' => $required,
'links_html' => $links_html,
'label_html' => $label_html,
'field_name' => 'agree_terms',
];
@@ -65,27 +67,19 @@ if (!function_exists('jio_get_auth_agreement_view')) {
if (!function_exists('jio_get_auth_sign_logo_html')) {
/**
* Shared logo block for full-page sign shell.
* Shared logo block for the sign card (modal and /sign/).
*/
function jio_get_auth_sign_logo_html(): string {
$logo_url = class_exists('\Jio\Settings\Settings') ? \Jio\Settings\Settings::user_logo_url() : '';
$logo_dark_url = class_exists('\Jio\Settings\Settings') ? \Jio\Settings\Settings::user_logo_dark_url() : $logo_url;
$logo_dark_url = class_exists('\Jio\Settings\Settings') ? \Jio\Settings\Settings::user_logo_dark_url() : $logo_url;
$home = home_url('/');
$name = get_bloginfo('name');
if ($logo_url) {
return sprintf(
'<a href="%s"><img class="sign-logo-light" src="%s" alt="%s"><img class="sign-logo-dark" src="%s" alt="%s"></a>',
esc_url($home),
esc_url($logo_url),
esc_attr($name),
esc_url($logo_dark_url),
esc_attr($name)
);
$img = function_exists('jio_get_adaptive_theme_img')
? jio_get_adaptive_theme_img($logo_url, $logo_dark_url, $name)
: '<img src="' . esc_url($logo_url) . '" alt="' . esc_attr($name) . '">';
return '<div class="text-center"><div class="sign-logo box-body"><a href="' . esc_url($home) . '">' . $img . '</a></div></div>';
}
return sprintf(
'<a href="%s" class="sign-logo__text">%s</a>',
esc_url($home),
esc_html(mb_substr((string) $name, 0, 2))
);
return '<div class="text-center"><div class="sign-logo box-body"><a href="' . esc_url($home) . '" class="sign-logo__text">' . esc_html(mb_substr((string) $name, 0, 2)) . '</a></div></div>';
}
}
+28
View File
@@ -25,6 +25,8 @@ final class Router {
add_action('init', [$this, 'register_rewrite_rules']);
add_filter('template_include', [$this, 'handle_template_include'], 99);
add_action('init', [$this, 'maybe_flush_rewrite_rules']);
add_filter('jio_forced_theme_mode', [$this, 'filter_sign_theme_mode']);
add_filter('jio_theme_mode_button_positions', [$this, 'filter_sign_theme_positions']);
add_filter('login_url', [$this, 'filter_login_url'], 10, 3);
add_filter('lostpassword_url', [$this, 'filter_lostpassword_url'], 10, 2);
@@ -75,6 +77,32 @@ final class Router {
return $template;
}
/** 登录页「自定义主题」:强制日间 / 夜间模式。 */
public function filter_sign_theme_mode(string $mode): string {
$override = $this->sign_theme_mode_override();
return $override !== '' ? $override : $mode;
}
/** 登录页强制主题时不显示主题切换按钮。 */
public function filter_sign_theme_positions(array $positions): array {
return $this->sign_theme_mode_override() !== '' ? [] : $positions;
}
private function sign_theme_mode_override(): string {
$is_sign = get_query_var('jio_sign') || (function_exists('jio_is_auth_page_request') && jio_is_auth_page_request());
if (!$is_sign || !class_exists('\Jio\Settings\Settings')) {
return '';
}
$mode = (string) (\Jio\Settings\Settings::sign_page_ui()['theme_mode'] ?? 'no');
if ($mode === 'dark-theme') {
return 'dark';
}
if ($mode === 'white-theme') {
return 'light';
}
return '';
}
public function maybe_flush_rewrite_rules(): void {
$rewrite_version = JIO_VERSION . ':sign-router-v3-single-route';
if (get_option('jio_auth_routes_flushed') !== $rewrite_version) {
+2
View File
@@ -463,6 +463,8 @@ trait ScriptsPart1c {
'siteUrl' => home_url('/'),
'themeUrl' => JIO_URI,
'themeMode' => class_exists('\Jio\Settings\Settings') ? \Jio\Settings\Settings::theme_mode_js_value() : 'auto',
// 登录页「自定义主题」:强制模式优先于用户保存的 cookie。
'themeForced' => (string) apply_filters('jio_forced_theme_mode', ''),
'debug' => defined('WP_DEBUG') && WP_DEBUG,
'debugLog' => defined('WP_DEBUG') && WP_DEBUG && defined('WP_DEBUG_LOG') && WP_DEBUG_LOG,
'postPaginationMode' => class_exists('\Jio\Settings\Settings') ? \Jio\Settings\Settings::get_post_pagination_mode() : 'load_more',
+5 -2
View File
@@ -394,7 +394,8 @@ class Settings {
/** 主题模式 → JS 可消费的简化值 (light / dark / time-auto) */
public static function theme_mode_js_value(): string {
return ThemeSearch::theme_mode_js_value();
$mode = (string) apply_filters('jio_theme_mode_js_value', ThemeSearch::theme_mode_js_value());
return in_array($mode, ['light', 'dark', 'time-auto'], true) ? $mode : 'time-auto';
}
@@ -429,7 +430,9 @@ class Settings {
/** 获取主题切换按钮显示位置列表 */
public static function get_theme_mode_button_positions(): array {
return ThemeSearch::get_theme_mode_button_positions();
$positions = ThemeSearch::get_theme_mode_button_positions();
$filtered = apply_filters('jio_theme_mode_button_positions', $positions);
return is_array($filtered) ? array_values(array_filter((array) $filtered)) : [];
}
+54 -13
View File
@@ -30,14 +30,46 @@ if ($tab === 'signup' && class_exists('\Jio\Settings\Settings') && !\Jio\Setting
$tab = 'signin';
}
remove_action('wp_footer', 'jio_render_footer_tabbar', 20);
remove_action('wp_footer', 'jio_render_float_buttons', 30);
$ui = class_exists('\Jio\Settings\Settings') ? \Jio\Settings\Settings::sign_page_ui() : [];
$images = $ui['background'] ?? [];
$background_id = $images ? (int) $images[array_rand($images)] : 0;
$background_url = $background_id > 0 ? (string) wp_get_attachment_image_url($background_id, 'full') : '';
// 主题模式由 Router 通过 jio_initial_theme_mode / jio_theme_mode_js_value 统一注入。
$theme_mode = (string) ($ui['theme_mode'] ?? 'no');
$position = (string) ($ui['card_position'] ?? 'right');
$show_header = !empty($ui['show_header']) && !$interim;
add_filter('document_title_parts', static function (array $parts): array {
$parts['title'] = __('登录 / 注册', 'jio');
unset($parts['tagline']);
return $parts;
});
$initial_theme_mode = '';
if ($theme_mode !== 'no' && class_exists('\Jio\Settings\Settings')) {
$initial_theme_mode = (string) apply_filters('jio_forced_theme_mode', '');
}
remove_action('wp_footer', 'jio_float_right');
$body_classes = ['page-template-user-sign', 'site-layout-1'];
if ($theme_mode !== 'no') {
$body_classes[] = $theme_mode;
}
if ($initial_theme_mode === 'dark') {
$body_classes[] = 'theme-dark';
$body_classes[] = 'dark-theme';
} elseif ($initial_theme_mode === 'light') {
$body_classes[] = 'white-theme';
}
$card_offset = ' col-md-offset-6';
if ($position === 'left') {
$card_offset = '';
} elseif ($position === 'center') {
$card_offset = ' col-md-offset-3';
}
$jio_auth_context = [
'surface' => 'page',
'tab' => $tab,
@@ -47,24 +79,33 @@ $jio_auth_context = [
];
?>
<!doctype html>
<html <?php language_attributes(); ?>>
<html <?php language_attributes(); ?><?php echo $initial_theme_mode === 'dark' ? ' class="dark"' : ''; ?><?php echo $initial_theme_mode !== '' ? ' data-theme="' . esc_attr($initial_theme_mode) . '"' : ''; ?>>
<head>
<meta charset="<?php bloginfo('charset'); ?>">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="robots" content="noindex,nofollow">
<title><?php echo esc_html__('登录 / 注册', 'jio') . ' - ' . esc_html(get_bloginfo('name')); ?></title>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0, viewport-fit=cover">
<meta name="robots" content="noindex, nofollow">
<?php wp_head(); ?>
</head>
<body <?php body_class('page-template-user-sign ' . ($theme_mode !== 'no' ? $theme_mode : '')); ?>>
<body <?php body_class($body_classes); ?><?php echo $initial_theme_mode !== '' ? ' data-theme="' . esc_attr($initial_theme_mode) . '"' : ''; ?>>
<?php wp_body_open(); ?>
<?php if ($background_url !== '') : ?><div class="sign-page-background" style="background-image:url('<?php echo esc_url($background_url); ?>')"></div><?php endif; ?>
<?php if (!empty($ui['show_header']) && !$interim) : ?><header class="sign-topbar"><a href="<?php echo esc_url(home_url('/')); ?>"><?php echo esc_html(get_bloginfo('name')); ?></a><a href="<?php echo esc_url(home_url('/')); ?>"><?php esc_html_e('返回首页', 'jio'); ?></a></header><?php endif; ?>
<main class="sign-page sign-card-position-<?php echo esc_attr($position); ?>">
<div class="sign-page-card">
<?php require get_template_directory() . '/templates/parts/auth-content.php'; ?>
<?php if ($background_url !== '') : ?>
<div class="fixed lazyload" data-bg="<?php echo esc_url($background_url); ?>" style="background-repeat:no-repeat;background-size:cover;background-position:center;"></div>
<?php endif; ?>
<?php if ($show_header && function_exists('jio_header')) { jio_header(); } ?>
<main role="main" class="container sign-page">
<div class="row sign-row gutters-5">
<div class="col-md-6<?php echo esc_attr($card_offset); ?> sign-col">
<div style="padding:20px 0 60px 0">
<?php require get_template_directory() . '/templates/parts/auth-content.php'; ?>
</div>
</div>
</div>
</main>
<?php if (!$interim) : ?><footer class="sign-page-footer"><?php echo !empty($ui['footer']) ? wp_kses_post((string) $ui['footer']) : '&copy; ' . esc_html(wp_date('Y')) . ' ' . esc_html(get_bloginfo('name')); ?></footer><?php endif; ?>
<?php if (!$interim) : ?>
<div class="sign-page-footer text-center blur-bg fixed px12 opacity8">
<?php echo !empty($ui['footer']) ? wp_kses_post((string) $ui['footer']) : '&copy; ' . esc_html(wp_date('Y')) . ' ' . esc_html(get_bloginfo('name')); ?>
</div>
<?php endif; ?>
<?php wp_footer(); ?>
</body>
</html>
+318 -82
View File
@@ -29,7 +29,7 @@ $signup_type = $settings ? $settings::signup_verification_type() : 'email';
$signup_type = $signup_verify ? $signup_type : 'email';
$reset_type = $settings ? $settings::reset_password_verification_type() : 'email';
$omit_confirm = $signup_verify && ($settings ? $settings::signup_omit_password_confirmation() : false);
$agreement = function_exists('jio_get_auth_agreement_view') ? jio_get_auth_agreement_view() : ['enabled' => false, 'required' => false, 'label_html' => '', 'field_name' => 'agree_terms'];
$agreement = function_exists('jio_get_auth_agreement_view') ? jio_get_auth_agreement_view() : ['enabled' => false, 'required' => false, 'links_html' => '', 'label_html' => '', 'field_name' => 'agree_terms'];
$referral = $settings ? $settings::get_referral_registration_settings() : ['enabled' => false, 'register_field' => 'hidden'];
$ref_mode = !empty($referral['enabled']) ? (string) ($referral['register_field'] ?? 'hidden') : 'hidden';
$ref_hint = $ref_mode === 'required' ? (string) ($referral['required_desc'] ?? '') : (string) ($referral['open_desc'] ?? '');
@@ -46,106 +46,342 @@ foreach ($oauth_providers as $provider) {
}
}
$show_logo = !empty($jio_auth_context['show_logo']);
$oauth_large = $settings ? (bool) $settings::get_value('oauth_button_lg', false) : false;
$redirect_to = esc_url_raw((string) ($jio_auth_context['redirect_to'] ?? home_url('/')));
$unique = $is_modal ? 'modal' : 'page';
$oauth_user_data = $is_oauth_bind && !empty($oauth_bind_data['user_data']) && is_array($oauth_bind_data['user_data']) ? $oauth_bind_data['user_data'] : [];
$oauth_name = sanitize_user((string) ($oauth_user_data['name'] ?? $oauth_user_data['nickname'] ?? $oauth_user_data['login'] ?? ''), true);
$oauth_email = sanitize_email((string) ($oauth_user_data['email'] ?? ''));
$oauth_avatar = esc_url_raw((string) ($oauth_user_data['avatar'] ?? ''));
if ($oauth_avatar === '' && function_exists('jio_get_default_avatar_url')) {
$oauth_avatar = jio_get_default_avatar_url();
}
$oauth_provider_name = $is_oauth_bind ? \Jio\Auth\Service::get_oauth_provider_name((string) ($oauth_bind_data['provider'] ?? '')) : '';
$oauth_intent = sanitize_key((string) ($jio_auth_context['oauth_intent'] ?? ($_GET['oauth_intent'] ?? 'login')));
$oauth_intent = $oauth_intent === 'bind' ? 'bind' : 'login';
$oauth_bind_pass = $oauth_intent === 'bind'
? sanitize_text_field((string) ($jio_auth_context['bind_pass'] ?? ($_GET['bind_pass'] ?? '')))
: '';
$initial_tab = $auth_tab;
if ($initial_tab === 'signin' && $close_signin && $registration_open) {
$initial_tab = 'signup';
}
if ($initial_tab === 'signup' && !$registration_open) {
$initial_tab = 'signin';
}
if ($initial_tab === 'oauth' && !$wechat_qr) {
$initial_tab = 'signin';
}
if ($initial_tab === 'bind' && !$is_oauth_bind) {
$initial_tab = 'signin';
}
$show_nopas = $passwordless;
$show_pas = !$passwordless || $passwordless_mode !== 'only_nopas';
$nopas_active = $show_nopas && $passwordless_mode !== 'pas';
$signin_user_hint = ($passwordless || $signin_phone) ? __('用户名/手机号/邮箱', 'jio') : __('用户名或邮箱', 'jio');
$social_html = '';
if (!$is_oauth_bind && !$close_signin && !empty($oauth_providers) && class_exists('\Jio\Auth\OAuth')) {
$social_html = \Jio\Auth\OAuth::get_instance()->render_social_buttons(__('社交账号登录', 'jio'));
}
$ref_tooltip = $ref_hint !== '' ? wp_strip_all_tags($ref_hint) : '';
$invite_tooltip = ($invite_mode === 'optional' && $invite_hint !== '') ? wp_strip_all_tags($invite_hint) : '';
?>
<div class="sign jio-auth<?php echo $oauth_large ? ' oauth-button-lg' : ''; ?>" data-jio-auth data-surface="<?php echo esc_attr($unique); ?>" data-initial-tab="<?php echo esc_attr($auth_tab); ?>" data-passwordless-mode="<?php echo esc_attr($passwordless_mode); ?>" data-redirect-to="<?php echo esc_attr($redirect_to); ?>" data-oauth-intent="<?php echo esc_attr($oauth_intent); ?>" data-bind-pass="<?php echo esc_attr($oauth_bind_pass); ?>">
<?php if ($show_logo) : ?>
<div class="sign-logo"><?php echo function_exists('jio_get_auth_sign_logo_html') ? jio_get_auth_sign_logo_html() : ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></div>
<div class="sign jio-panel blur-bg relative jio-auth" data-jio-auth data-surface="<?php echo esc_attr($unique); ?>" data-initial-tab="<?php echo esc_attr($initial_tab); ?>" data-redirect-to="<?php echo esc_attr($redirect_to); ?>" data-oauth-intent="<?php echo esc_attr($oauth_intent); ?>" data-bind-pass="<?php echo esc_attr($oauth_bind_pass); ?>">
<?php if ($is_modal) : ?>
<button type="button" class="close" data-auth-close aria-label="<?php esc_attr_e('关闭', 'jio'); ?>"><?php echo function_exists('jio_icon_markup') ? jio_icon_markup('jiosvg-close', 'ic-close') : '<i class="fa fas fa-times" aria-hidden="true"></i>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></button>
<?php endif; ?>
<?php if ($show_logo && function_exists('jio_get_auth_sign_logo_html')) : ?>
<?php echo jio_get_auth_sign_logo_html(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<?php endif; ?>
<section id="<?php echo esc_attr($unique); ?>-auth-panel-signin" class="sign-panel" role="tabpanel" data-auth-panel="signin" <?php echo $auth_tab !== 'signin' ? 'hidden' : ''; ?>>
<div class="sign-header"><h2><?php esc_html_e('登录', 'jio'); ?></h2><?php if ($registration_open) : ?><span><?php esc_html_e('没有账号?', 'jio'); ?> <button type="button" data-auth-tab="signup"><?php esc_html_e('立即注册', 'jio'); ?></button></span><?php endif; ?></div>
<div class="tab-content">
<?php if (!$close_signin) : ?>
<form class="sign-form" data-auth-form="login">
<div class="floating-input"><input name="target" id="<?php echo esc_attr($unique); ?>-login-target" autocomplete="username" required><label for="<?php echo esc_attr($unique); ?>-login-target"><?php echo ($passwordless || $signin_phone) ? esc_html__('邮箱 / 手机号 / 用户名', 'jio') : esc_html__('邮箱 / 用户名', 'jio'); ?></label></div>
<div data-auth-password-fields <?php echo $passwordless && $passwordless_mode !== 'pas' ? 'hidden' : ''; ?>>
<div class="floating-input has-action"><input type="password" name="password" id="<?php echo esc_attr($unique); ?>-login-password" autocomplete="current-password"><label for="<?php echo esc_attr($unique); ?>-login-password"><?php esc_html_e('密码', 'jio'); ?></label><button type="button" class="password-show" data-password-show aria-label="<?php esc_attr_e('显示密码', 'jio'); ?>" aria-pressed="false"><i class="fa fas fa-eye"></i></button></div>
<div class="tab-pane fade<?php echo $initial_tab === 'signin' ? ' active in' : ''; ?>" id="<?php echo esc_attr($unique); ?>-tab-sign-in" role="tabpanel" data-auth-panel="signin" <?php echo $initial_tab !== 'signin' ? 'hidden' : ''; ?>>
<div class="box-body">
<div class="title-h-left fa-2x"><?php esc_html_e('登录', 'jio'); ?></div>
<?php if ($registration_open) : ?><a class="muted-color px12" href="#<?php echo esc_attr($unique); ?>-tab-sign-up" data-auth-tab="signup"><?php esc_html_e('没有账号?立即注册', 'jio'); ?><i class="em12 ml3 fa fas fa-angle-right" aria-hidden="true"></i></a><?php endif; ?>
</div>
<?php if ($passwordless) : ?>
<div data-auth-code-fields <?php echo $passwordless_mode === 'pas' ? 'hidden' : ''; ?>>
<div class="floating-input has-action"><input name="code" inputmode="numeric" maxlength="6" id="<?php echo esc_attr($unique); ?>-login-code"><label for="<?php echo esc_attr($unique); ?>-login-code"><?php esc_html_e('验证码', 'jio'); ?></label><button type="button" class="send-code" data-send-code="login"><?php esc_html_e('发送验证码', 'jio'); ?></button></div>
<input type="hidden" name="channel" value="<?php echo esc_attr($passwordless_type === 'phone' ? 'phone' : ''); ?>">
<div id="sign-in">
<?php if ($show_nopas) : ?>
<div class="tab-content">
<div class="tab-pane fade<?php echo $nopas_active ? ' active in' : ''; ?>" id="<?php echo esc_attr($unique); ?>-tab-signin-nopas" data-signin-panel="nopas" <?php echo $nopas_active ? '' : 'hidden'; ?>>
<form data-auth-form="login">
<div class="relative line-form mb10">
<input type="text" name="target" id="<?php echo esc_attr($unique); ?>-nopas-target" class="line-form-input" autocomplete="username" tabindex="1" placeholder="" required>
<div class="scale-placeholder"><?php echo $passwordless_type === 'phone' ? esc_html__('手机号', 'jio') : ($passwordless_type === 'email_phone' ? esc_html__('手机号或邮箱', 'jio') : esc_html__('邮箱', 'jio')); ?></div>
<i class="line-form-line"></i>
</div>
<?php if (function_exists('jio_render_captcha')) { jio_render_captcha('login'); } ?>
<div class="relative line-form mb10">
<input type="text" name="code" id="<?php echo esc_attr($unique); ?>-nopas-code" class="line-form-input" inputmode="numeric" maxlength="6" autocomplete="one-time-code" tabindex="2" placeholder="" required>
<div class="scale-placeholder"><?php esc_html_e('验证码', 'jio'); ?></div>
<span class="yztx abs-right"><button type="button" form-action="login" class="but c-blue captchsubmit" data-send-code="login"><?php esc_html_e('发送验证码', 'jio'); ?></button></span>
<i class="line-form-line"></i>
</div>
<input type="hidden" name="channel" value="<?php echo esc_attr($passwordless_type === 'phone' ? 'phone' : ''); ?>">
<div class="relative line-form mb10 em09">
<span class="muted-color form-checkbox"><input type="checkbox" id="<?php echo esc_attr($unique); ?>-nopas-remember" name="rememberme" value="1" checked="checked"><label for="<?php echo esc_attr($unique); ?>-nopas-remember" class="ml3"><?php esc_html_e('记住登录', 'jio'); ?></label></span>
<span class="pull-right muted-2-color">
<?php if ($show_pas) : ?><a class="muted-2-color" href="#<?php echo esc_attr($unique); ?>-tab-signin-pas" data-signin-mode="pas"><?php esc_html_e('账号密码登录', 'jio'); ?></a><?php endif; ?>
</span>
</div>
<div class="box-body">
<input type="hidden" name="redirect_to" value="<?php echo esc_attr($redirect_to); ?>">
<button type="submit" class="but radius jb-blue padding-lg btn-block"><i class="fa fas fa-sign-in-alt mr10" aria-hidden="true"></i><span data-submit-label><?php esc_html_e('登录', 'jio'); ?></span><i class="fa fas fa-spinner fa-spin" hidden aria-hidden="true"></i></button>
</div>
</form>
</div>
<?php if ($show_pas) : ?>
<div class="tab-pane fade<?php echo $nopas_active ? '' : ' active in'; ?>" id="<?php echo esc_attr($unique); ?>-tab-signin-pas" data-signin-panel="pas" <?php echo $nopas_active ? 'hidden' : ''; ?>>
<form data-auth-form="login">
<div class="relative line-form mb10">
<input type="text" name="target" id="<?php echo esc_attr($unique); ?>-login-target" class="line-form-input" autocomplete="username" tabindex="1" placeholder="" required>
<div class="scale-placeholder"><?php echo esc_html($signin_user_hint); ?></div>
<i class="line-form-line"></i>
</div>
<div class="relative line-form mb10">
<input type="password" name="password" id="<?php echo esc_attr($unique); ?>-login-password" class="line-form-input" autocomplete="current-password" tabindex="2" placeholder="">
<div class="scale-placeholder"><?php esc_html_e('登录密码', 'jio'); ?></div>
<button type="button" class="abs-right sign-passw muted-2-color" data-password-show aria-label="<?php esc_attr_e('显示密码', 'jio'); ?>" aria-pressed="false"><i class="fa fas fa-eye" aria-hidden="true"></i></button>
<i class="line-form-line"></i>
</div>
<?php if (function_exists('jio_render_captcha')) { jio_render_captcha('login'); } ?>
<div class="relative line-form mb10 em09">
<span class="muted-color form-checkbox"><input type="checkbox" id="<?php echo esc_attr($unique); ?>-remember" name="rememberme" value="1" checked="checked"><label for="<?php echo esc_attr($unique); ?>-remember" class="ml3"><?php esc_html_e('记住登录', 'jio'); ?></label></span>
<span class="pull-right muted-2-color">
<a class="muted-2-color" href="#<?php echo esc_attr($unique); ?>-tab-resetpassword" data-auth-tab="resetpassword"><?php esc_html_e('找回密码', 'jio'); ?></a>
<?php if ($show_nopas) : ?><span class="opacity5"> | </span><a class="muted-2-color" href="#<?php echo esc_attr($unique); ?>-tab-signin-nopas" data-signin-mode="nopas"><?php esc_html_e('免密登录', 'jio'); ?></a><?php endif; ?>
</span>
</div>
<div class="box-body">
<input type="hidden" name="redirect_to" value="<?php echo esc_attr($redirect_to); ?>">
<button type="submit" class="but radius jb-blue padding-lg btn-block"><i class="fa fas fa-sign-in-alt mr10" aria-hidden="true"></i><span data-submit-label><?php esc_html_e('登录', 'jio'); ?></span><i class="fa fas fa-spinner fa-spin" hidden aria-hidden="true"></i></button>
</div>
</form>
</div>
<?php endif; ?>
</div>
<?php else : ?>
<form data-auth-form="login">
<div class="relative line-form mb10">
<input type="text" name="target" id="<?php echo esc_attr($unique); ?>-login-target" class="line-form-input" autocomplete="username" tabindex="1" placeholder="" required>
<div class="scale-placeholder"><?php echo esc_html($signin_user_hint); ?></div>
<i class="line-form-line"></i>
</div>
<div class="relative line-form mb10">
<input type="password" name="password" id="<?php echo esc_attr($unique); ?>-login-password" class="line-form-input" autocomplete="current-password" tabindex="2" placeholder="">
<div class="scale-placeholder"><?php esc_html_e('登录密码', 'jio'); ?></div>
<button type="button" class="abs-right sign-passw muted-2-color" data-password-show aria-label="<?php esc_attr_e('显示密码', 'jio'); ?>" aria-pressed="false"><i class="fa fas fa-eye" aria-hidden="true"></i></button>
<i class="line-form-line"></i>
</div>
<?php if (function_exists('jio_render_captcha')) { jio_render_captcha('login'); } ?>
<div class="relative line-form mb10 em09">
<span class="muted-color form-checkbox"><input type="checkbox" id="<?php echo esc_attr($unique); ?>-remember" name="rememberme" value="1" checked="checked"><label for="<?php echo esc_attr($unique); ?>-remember" class="ml3"><?php esc_html_e('记住登录', 'jio'); ?></label></span>
<span class="pull-right muted-2-color"><a class="muted-2-color" href="#<?php echo esc_attr($unique); ?>-tab-resetpassword" data-auth-tab="resetpassword"><?php esc_html_e('找回密码', 'jio'); ?></a></span>
</div>
<div class="box-body">
<input type="hidden" name="redirect_to" value="<?php echo esc_attr($redirect_to); ?>">
<button type="submit" class="but radius jb-blue padding-lg btn-block"><i class="fa fas fa-sign-in-alt mr10" aria-hidden="true"></i><span data-submit-label><?php esc_html_e('登录', 'jio'); ?></span><i class="fa fas fa-spinner fa-spin" hidden aria-hidden="true"></i></button>
</div>
</form>
<?php endif; ?>
<?php echo $social_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<?php if ($social_html !== '' && !empty($agreement['enabled'])) : ?><div class="muted-color mt10 text-center px12 opacity8"><?php esc_html_e('使用社交账号登录即表示同意', 'jio'); ?><?php echo $agreement['links_html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></div><?php endif; ?>
</div>
</div>
<?php endif; ?>
<?php if ($registration_open) : ?>
<div class="tab-pane fade<?php echo $initial_tab === 'signup' ? ' active in' : ''; ?>" id="<?php echo esc_attr($unique); ?>-tab-sign-up" role="tabpanel" data-auth-panel="signup" <?php echo $initial_tab !== 'signup' ? 'hidden' : ''; ?>>
<div class="box-body">
<div class="title-h-left fa-2x"><?php echo $is_oauth_bind ? esc_html__('创建新账号', 'jio') : esc_html__('注册', 'jio'); ?></div>
<a class="muted-color px12" href="#<?php echo esc_attr($unique); ?>-tab-sign-in" data-auth-tab="<?php echo $is_oauth_bind ? 'bind' : 'signin'; ?>"><?php esc_html_e('已有账号,立即登录', 'jio'); ?><i class="em12 ml3 fa fas fa-angle-right" aria-hidden="true"></i></a>
</div>
<?php
$register_fields = function () use ($unique, $oauth_name, $oauth_email, $signup_type, $signup_verify, $omit_confirm, $ref_mode, $ref_value, $ref_tooltip, $invite_mode, $invite_tooltip, $agreement, $is_oauth_bind, $obk) {
?>
<div class="relative line-form mb10">
<input type="text" name="user_login" id="<?php echo esc_attr($unique); ?>-register-name" class="line-form-input" value="<?php echo esc_attr($oauth_name); ?>" autocomplete="username" tabindex="1" placeholder="" required>
<div class="scale-placeholder"><?php esc_html_e('设置用户名', 'jio'); ?></div>
<i class="line-form-line"></i>
</div>
<div class="relative line-form mb10">
<input type="text" name="target" id="<?php echo esc_attr($unique); ?>-register-target" class="line-form-input" value="<?php echo esc_attr($oauth_email); ?>" autocomplete="<?php echo $signup_type === 'phone' ? 'tel' : 'email'; ?>" tabindex="2" placeholder="" required>
<div class="scale-placeholder"><?php echo $signup_type === 'phone' ? esc_html__('手机号', 'jio') : ($signup_type === 'email_phone' ? esc_html__('手机号或邮箱', 'jio') : esc_html__('邮箱', 'jio')); ?></div>
<i class="line-form-line"></i>
</div>
<?php if ($signup_verify) : ?>
<div class="relative line-form mb10">
<input type="text" name="code" id="<?php echo esc_attr($unique); ?>-register-code" class="line-form-input" inputmode="numeric" maxlength="6" autocomplete="one-time-code" tabindex="3" placeholder="" required>
<div class="scale-placeholder"><?php esc_html_e('验证码', 'jio'); ?></div>
<span class="yztx abs-right"><button type="button" form-action="register" class="but c-blue captchsubmit" data-send-code="register"><?php esc_html_e('发送验证码', 'jio'); ?></button></span>
<i class="line-form-line"></i>
</div>
<?php endif; ?>
<div class="relative line-form mb10">
<input type="password" name="password" id="<?php echo esc_attr($unique); ?>-register-password" class="line-form-input" autocomplete="new-password" minlength="6" tabindex="4" placeholder="" required>
<div class="scale-placeholder"><?php esc_html_e('设置密码', 'jio'); ?></div>
<button type="button" class="abs-right sign-passw muted-2-color" data-password-show aria-label="<?php esc_attr_e('显示密码', 'jio'); ?>" aria-pressed="false"><i class="fa fas fa-eye" aria-hidden="true"></i></button>
<i class="line-form-line"></i>
</div>
<?php if (!$omit_confirm) : ?>
<div class="relative line-form mb10">
<input type="password" name="password_confirm" id="<?php echo esc_attr($unique); ?>-register-confirm" class="line-form-input" autocomplete="new-password" minlength="6" tabindex="5" placeholder="" required>
<div class="scale-placeholder"><?php esc_html_e('重复密码', 'jio'); ?></div>
<button type="button" class="abs-right sign-passw muted-2-color" data-password-show aria-label="<?php esc_attr_e('显示密码', 'jio'); ?>" aria-pressed="false"><i class="fa fas fa-eye" aria-hidden="true"></i></button>
<i class="line-form-line"></i>
</div>
<?php endif; ?>
<?php if ($ref_mode !== 'hidden') : ?>
<div class="relative line-form mb10">
<input type="text" name="ref" id="<?php echo esc_attr($unique); ?>-register-ref" class="line-form-input" value="<?php echo esc_attr($ref_value); ?>" tabindex="6" placeholder="" <?php echo $ref_mode === 'required' ? 'required' : ''; ?>>
<div class="scale-placeholder"><?php echo $ref_mode === 'required' ? esc_html__('推广码', 'jio') : esc_html__('推广码(选填)', 'jio'); ?></div>
<?php if ($ref_tooltip !== '') : ?><div class="abs-right muted-2-color" data-toggle="tooltip" title="<?php echo esc_attr($ref_tooltip); ?>"><i class="fa fas fa-question-circle" aria-hidden="true"></i></div><?php endif; ?>
<i class="line-form-line"></i>
</div>
<?php endif; ?>
<?php if ($invite_mode === 'optional') : ?>
<div class="relative line-form mb10">
<input type="text" name="invite_code" id="<?php echo esc_attr($unique); ?>-register-invite" class="line-form-input" data-invite-verify tabindex="7" placeholder="">
<div class="scale-placeholder"><?php esc_html_e('邀请码(选填)', 'jio'); ?></div>
<?php if ($invite_tooltip !== '') : ?><div class="abs-right muted-2-color" data-toggle="tooltip" title="<?php echo esc_attr($invite_tooltip); ?>"><i class="fa fas fa-question-circle" aria-hidden="true"></i></div><?php endif; ?>
<i class="line-form-line"></i>
</div>
<small class="muted-2-color px12" data-invite-feedback role="status" aria-live="polite" hidden></small>
<?php elseif ($invite_mode === 'required') : ?>
<input type="hidden" name="invite_code" value="" data-invite-value>
<?php endif; ?>
<?php if (!empty($agreement['enabled'])) : ?>
<?php if (!empty($agreement['required'])) : ?>
<div class="form-checkbox muted-color mt10 text-center px12 opacity8"><input type="checkbox" name="agree_terms" value="1" id="<?php echo esc_attr($unique); ?>-register-agree" required><label for="<?php echo esc_attr($unique); ?>-register-agree" class="px12 ml6" style="font-weight:normal;"><?php echo $agreement['label_html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></label></div>
<?php else : ?>
<div class="muted-color mt10 text-center px12 opacity8"><?php esc_html_e('注册即表示同意', 'jio'); ?><?php echo $agreement['links_html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></div>
<?php endif; ?>
<?php endif; ?>
<?php if (function_exists('jio_render_captcha')) { jio_render_captcha('register'); } ?>
<input type="hidden" name="channel" value="<?php echo esc_attr($signup_type === 'phone' ? 'phone' : ''); ?>">
<input type="hidden" name="user_email" value="">
<?php if ($is_oauth_bind) : ?><input type="hidden" name="obk" value="<?php echo esc_attr($obk); ?>"><?php endif; ?>
<div class="box-body">
<button type="submit" class="but radius jb-green padding-lg btn-block"><?php echo function_exists('jio_icon_markup') ? jio_icon_markup('jiosvg-signup', 'icon mr10') : ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?><span data-submit-label><?php echo $is_oauth_bind ? esc_html__('绑定注册', 'jio') : esc_html__('注册', 'jio'); ?></span><i class="fa fas fa-spinner fa-spin" hidden aria-hidden="true"></i></button>
</div>
<?php
};
?>
<?php if ($invite_mode === 'required') : ?>
<div class="tab-content">
<div class="tab-pane fade active in" data-invite-gate-panel>
<div class="mb10 flex jc" style="min-height:72px;"><div class="text-center"><?php echo wp_kses_post($invite_hint); ?></div></div>
<div class="relative line-form mb10">
<input type="text" name="invite_code" id="<?php echo esc_attr($unique); ?>-invite-gate" class="line-form-input" data-invite-verify data-invite-gate-input autocomplete="off" tabindex="1" placeholder="">
<div class="scale-placeholder"><?php esc_html_e('请填写邀请码', 'jio'); ?></div>
<i class="line-form-line"></i>
</div>
<small class="muted-2-color px12" data-invite-feedback role="status" aria-live="polite" hidden></small>
<div class="box-body"><button type="button" class="but radius jb-blue padding-lg btn-block" data-invite-gate><?php esc_html_e('继续', 'jio'); ?><i class="em12 ml3 fa fas fa-angle-right" aria-hidden="true"></i></button></div>
</div>
<div class="tab-pane fade" data-invite-form-panel hidden>
<form id="sign-up" data-auth-form="register"><?php $register_fields(); ?></form>
</div>
</div>
<?php else : ?>
<form id="sign-up" data-auth-form="register"><?php $register_fields(); ?></form>
<?php endif; ?>
<div class="sign-options"><label><input type="checkbox" name="rememberme" value="1"> <?php esc_html_e('记住登录', 'jio'); ?></label><button type="button" data-auth-tab="resetpassword"><?php esc_html_e('忘记密码?', 'jio'); ?></button></div>
<?php if (function_exists('jio_render_captcha')) { jio_render_captcha('login'); } ?>
<input type="hidden" name="redirect_to" value="<?php echo esc_attr($redirect_to); ?>">
<button type="submit" class="sign-submit jb-blue"><span><?php esc_html_e('登录', 'jio'); ?></span><i class="fa fas fa-spinner fa-spin" hidden></i></button>
<?php if ($passwordless && $passwordless_mode !== 'only_nopas') : ?><button type="button" class="sign-mode-switch" data-login-mode><?php echo $passwordless_mode === 'pas' ? esc_html__('使用验证码登录', 'jio') : esc_html__('使用账号密码登录', 'jio'); ?></button><?php endif; ?>
</form>
<?php else : ?><div class="sign-notice"><?php esc_html_e('当前已关闭账号密码登录,请使用第三方登录。', 'jio'); ?></div><?php endif; ?>
</section>
</div>
<?php endif; ?>
<?php if ($registration_open) : ?>
<section id="<?php echo esc_attr($unique); ?>-auth-panel-signup" class="sign-panel" role="tabpanel" data-auth-panel="signup" <?php echo $auth_tab !== 'signup' ? 'hidden' : ''; ?>>
<div class="sign-header"><h2><?php echo $is_oauth_bind ? esc_html__('注册并绑定', 'jio') : esc_html__('注册', 'jio'); ?></h2><span><?php esc_html_e('已有账号?', 'jio'); ?> <button type="button" data-auth-tab="<?php echo $is_oauth_bind ? 'bind' : 'signin'; ?>"><?php esc_html_e('立即登录', 'jio'); ?></button></span></div>
<form class="sign-form" data-auth-form="register">
<div class="floating-input"><input name="user_login" value="<?php echo esc_attr($oauth_name); ?>" id="<?php echo esc_attr($unique); ?>-register-name" autocomplete="username" required><label for="<?php echo esc_attr($unique); ?>-register-name"><?php esc_html_e('用户名', 'jio'); ?></label></div>
<div class="floating-input"><input name="target" value="<?php echo esc_attr($oauth_email); ?>" id="<?php echo esc_attr($unique); ?>-register-target" autocomplete="<?php echo $signup_type === 'phone' ? 'tel' : 'email'; ?>" required><label for="<?php echo esc_attr($unique); ?>-register-target"><?php echo $signup_type === 'phone' ? esc_html__('手机号', 'jio') : ($signup_type === 'email_phone' ? esc_html__('邮箱 / 手机号', 'jio') : esc_html__('邮箱', 'jio')); ?></label></div>
<?php if ($signup_verify) : ?><div class="floating-input has-action"><input name="code" inputmode="numeric" maxlength="6" id="<?php echo esc_attr($unique); ?>-register-code" required><label for="<?php echo esc_attr($unique); ?>-register-code"><?php esc_html_e('验证码', 'jio'); ?></label><button type="button" class="send-code" data-send-code="register"><?php esc_html_e('发送验证码', 'jio'); ?></button></div><?php endif; ?>
<div class="floating-input has-action"><input type="password" name="password" id="<?php echo esc_attr($unique); ?>-register-password" autocomplete="new-password" minlength="6" required><label for="<?php echo esc_attr($unique); ?>-register-password"><?php esc_html_e('密码', 'jio'); ?></label><button type="button" class="password-show" data-password-show aria-label="<?php esc_attr_e('显示密码', 'jio'); ?>" aria-pressed="false"><i class="fa fas fa-eye"></i></button></div>
<?php if (!$omit_confirm) : ?><div class="floating-input has-action"><input type="password" name="password_confirm" id="<?php echo esc_attr($unique); ?>-register-confirm" autocomplete="new-password" minlength="6" required><label for="<?php echo esc_attr($unique); ?>-register-confirm"><?php esc_html_e('重复密码', 'jio'); ?></label><button type="button" class="password-show" data-password-show aria-label="<?php esc_attr_e('显示密码', 'jio'); ?>" aria-pressed="false"><i class="fa fas fa-eye"></i></button></div><?php endif; ?>
<?php if ($ref_mode !== 'hidden') : ?><div class="floating-input"><input name="ref" value="<?php echo esc_attr($ref_value); ?>" id="<?php echo esc_attr($unique); ?>-register-ref" <?php echo $ref_mode === 'required' ? 'required' : ''; ?>><label for="<?php echo esc_attr($unique); ?>-register-ref"><?php echo $ref_mode === 'required' ? esc_html__('推广码', 'jio') : esc_html__('推广码(选填)', 'jio'); ?></label></div><?php if ($ref_hint !== '') : ?><div class="sign-hint"><?php echo wp_kses_post($ref_hint); ?></div><?php endif; ?><?php endif; ?>
<?php if ($invite_mode !== 'hidden') : ?><div class="floating-input"><input name="invite_code" id="<?php echo esc_attr($unique); ?>-register-invite" data-invite-verify <?php echo $invite_mode === 'required' ? 'required' : ''; ?>><label for="<?php echo esc_attr($unique); ?>-register-invite"><?php echo $invite_mode === 'required' ? esc_html__('邀请码', 'jio') : esc_html__('邀请码(选填)', 'jio'); ?></label></div><small class="sign-hint" data-invite-feedback role="status" aria-live="polite" hidden></small><?php if ($invite_hint !== '') : ?><div class="sign-hint"><?php echo wp_kses_post($invite_hint); ?></div><?php endif; ?><?php endif; ?>
<?php if (!empty($agreement['enabled']) && !empty($agreement['required'])) : ?><label class="sign-agreement"><input type="checkbox" name="agree_terms" value="1" required><span><?php echo $agreement['label_html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></span></label><?php elseif (!empty($agreement['enabled'])) : ?><div class="sign-agreement sign-agreement-implicit"><?php esc_html_e('注册即表示', 'jio'); ?><?php echo $agreement['label_html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></div><?php endif; ?>
<?php if (function_exists('jio_render_captcha')) { jio_render_captcha('register'); } ?>
<input type="hidden" name="channel" value="<?php echo esc_attr($signup_type === 'phone' ? 'phone' : ''); ?>">
<input type="hidden" name="user_email" value="">
<?php if ($is_oauth_bind) : ?><input type="hidden" name="obk" value="<?php echo esc_attr($obk); ?>"><?php endif; ?>
<button type="submit" class="sign-submit jb-green"><span><?php esc_html_e('注册', 'jio'); ?></span><i class="fa fas fa-spinner fa-spin" hidden></i></button>
</form>
</section>
<?php endif; ?>
<div class="tab-pane fade<?php echo $initial_tab === 'resetpassword' ? ' active in' : ''; ?>" id="<?php echo esc_attr($unique); ?>-tab-resetpassword" role="tabpanel" data-auth-panel="resetpassword" <?php echo $initial_tab !== 'resetpassword' ? 'hidden' : ''; ?>>
<div class="box-body">
<div class="title-h-left fa-2x"><?php esc_html_e('找回密码', 'jio'); ?></div>
<a class="muted-color px12" href="#<?php echo esc_attr($unique); ?>-tab-sign-in" data-auth-tab="signin"><?php esc_html_e('登录', 'jio'); ?></a><i class="icon-spot"></i><?php if ($registration_open) : ?><a class="muted-color px12" href="#<?php echo esc_attr($unique); ?>-tab-sign-up" data-auth-tab="signup"><?php esc_html_e('注册', 'jio'); ?></a><?php endif; ?>
</div>
<form data-auth-form="reset-password">
<div class="relative line-form mb10">
<input type="text" name="target" id="<?php echo esc_attr($unique); ?>-reset-target" class="line-form-input" autocomplete="username" tabindex="1" placeholder="" required>
<div class="scale-placeholder"><?php echo $reset_type === 'phone' ? esc_html__('手机号', 'jio') : ($reset_type === 'email_phone' ? esc_html__('手机号或邮箱', 'jio') : esc_html__('邮箱', 'jio')); ?></div>
<i class="line-form-line"></i>
</div>
<?php if (function_exists('jio_render_captcha')) { jio_render_captcha('lostpassword'); } ?>
<div class="relative line-form mb10">
<input type="text" name="code" id="<?php echo esc_attr($unique); ?>-reset-code" class="line-form-input" inputmode="numeric" maxlength="6" autocomplete="one-time-code" tabindex="2" placeholder="" required>
<div class="scale-placeholder"><?php esc_html_e('验证码', 'jio'); ?></div>
<span class="yztx abs-right"><button type="button" form-action="resetpassword" class="but c-blue captchsubmit" data-send-code="resetpassword"><?php esc_html_e('发送验证码', 'jio'); ?></button></span>
<i class="line-form-line"></i>
</div>
<div class="relative line-form mb10">
<input type="password" name="password" id="<?php echo esc_attr($unique); ?>-reset-password" class="line-form-input" autocomplete="new-password" minlength="6" tabindex="3" placeholder="" required>
<div class="scale-placeholder"><?php esc_html_e('设置新密码', 'jio'); ?></div>
<button type="button" class="abs-right sign-passw muted-2-color" data-password-show aria-label="<?php esc_attr_e('显示密码', 'jio'); ?>" aria-pressed="false"><i class="fa fas fa-eye" aria-hidden="true"></i></button>
<i class="line-form-line"></i>
</div>
<div class="relative line-form mb10">
<input type="password" name="password_confirm" id="<?php echo esc_attr($unique); ?>-reset-confirm" class="line-form-input" autocomplete="new-password" minlength="6" tabindex="4" placeholder="" required>
<div class="scale-placeholder"><?php esc_html_e('重复密码', 'jio'); ?></div>
<button type="button" class="abs-right sign-passw muted-2-color" data-password-show aria-label="<?php esc_attr_e('显示密码', 'jio'); ?>" aria-pressed="false"><i class="fa fas fa-eye" aria-hidden="true"></i></button>
<i class="line-form-line"></i>
</div>
<input type="hidden" name="channel" value="<?php echo esc_attr($reset_type === 'phone' ? 'phone' : ''); ?>">
<div class="box-body">
<button type="submit" class="but radius jb-green padding-lg btn-block"><i class="fa fas fa-unlock-alt mr10" aria-hidden="true"></i><span data-submit-label><?php esc_html_e('确认提交', 'jio'); ?></span><i class="fa fas fa-spinner fa-spin" hidden aria-hidden="true"></i></button>
</div>
</form>
</div>
<section id="<?php echo esc_attr($unique); ?>-auth-panel-resetpassword" class="sign-panel" role="tabpanel" data-auth-panel="resetpassword" <?php echo $auth_tab !== 'resetpassword' ? 'hidden' : ''; ?>>
<div class="sign-header"><h2><?php esc_html_e('找回密码', 'jio'); ?></h2><span><button type="button" data-auth-tab="signin"><?php esc_html_e('返回登录', 'jio'); ?></button></span></div>
<form class="sign-form" data-auth-form="reset-password">
<div class="floating-input"><input name="target" id="<?php echo esc_attr($unique); ?>-reset-target" required><label for="<?php echo esc_attr($unique); ?>-reset-target"><?php echo $reset_type === 'phone' ? esc_html__('手机号', 'jio') : ($reset_type === 'email_phone' ? esc_html__('邮箱 / 手机号', 'jio') : esc_html__('邮箱', 'jio')); ?></label></div>
<div class="floating-input has-action"><input name="code" inputmode="numeric" maxlength="6" id="<?php echo esc_attr($unique); ?>-reset-code" required><label for="<?php echo esc_attr($unique); ?>-reset-code"><?php esc_html_e('验证码', 'jio'); ?></label><button type="button" class="send-code" data-send-code="resetpassword"><?php esc_html_e('发送验证码', 'jio'); ?></button></div>
<div class="floating-input has-action"><input type="password" name="password" id="<?php echo esc_attr($unique); ?>-reset-password" minlength="6" required><label for="<?php echo esc_attr($unique); ?>-reset-password"><?php esc_html_e('新密码', 'jio'); ?></label><button type="button" class="password-show" data-password-show aria-label="<?php esc_attr_e('显示密码', 'jio'); ?>" aria-pressed="false"><i class="fa fas fa-eye"></i></button></div>
<div class="floating-input has-action"><input type="password" name="password_confirm" id="<?php echo esc_attr($unique); ?>-reset-confirm" minlength="6" required><label for="<?php echo esc_attr($unique); ?>-reset-confirm"><?php esc_html_e('重复新密码', 'jio'); ?></label><button type="button" class="password-show" data-password-show aria-label="<?php esc_attr_e('显示密码', 'jio'); ?>" aria-pressed="false"><i class="fa fas fa-eye"></i></button></div>
<?php if (function_exists('jio_render_captcha')) { jio_render_captcha('lostpassword'); } ?>
<input type="hidden" name="channel" value="<?php echo esc_attr($reset_type === 'phone' ? 'phone' : ''); ?>">
<button type="submit" class="sign-submit jb-blue"><span><?php esc_html_e('重置密码', 'jio'); ?></span><i class="fa fas fa-spinner fa-spin" hidden></i></button>
</form>
</section>
<?php if ($wechat_qr) : ?>
<div class="tab-pane fade<?php echo $initial_tab === 'oauth' ? ' active in' : ''; ?>" id="<?php echo esc_attr($unique); ?>-tab-qrcode-signin" role="tabpanel" data-auth-panel="oauth" <?php echo $initial_tab !== 'oauth' ? 'hidden' : ''; ?>>
<div class="box-body">
<div class="title-h-left fa-2x"><?php esc_html_e('扫码登录', 'jio'); ?></div>
<span class="muted-3-color px12"><?php esc_html_e('使用', 'jio'); ?><a class="muted-color" href="#<?php echo esc_attr($unique); ?>-tab-sign-in" data-auth-tab="signin"><?php esc_html_e('其它方式登录', 'jio'); ?></a><?php echo $registration_open ? esc_html__('或', 'jio') . '<a class="muted-color" href="#' . esc_attr($unique) . '-tab-sign-up" data-auth-tab="signup">' . esc_html__('注册', 'jio') . '</a>' : ''; ?></span>
</div>
<div class="qrcode-signin-container box-body text-center" data-auth-qrcode>
<div data-auth-qr-content><p class="placeholder" style="height:180px;width:180px;margin:auto;"></p><p class="placeholder" style="height:27px;width:200px;margin:15px auto 0;"></p></div>
<p class="screen-reader-text" data-auth-qr-status role="status" aria-live="polite" aria-atomic="true"><?php esc_html_e('正在获取二维码', 'jio'); ?></p>
</div>
<?php if (!empty($agreement['enabled'])) : ?><div class="muted-color mt10 text-center px12 opacity8"><?php esc_html_e('扫码登录即表示同意', 'jio'); ?><?php echo $agreement['links_html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></div><?php endif; ?>
</div>
<?php endif; ?>
<section id="<?php echo esc_attr($unique); ?>-auth-panel-oauth" class="sign-panel" role="tabpanel" data-auth-panel="oauth" <?php echo $auth_tab !== 'oauth' ? 'hidden' : ''; ?>>
<div class="sign-header"><h2><?php esc_html_e('社交登录', 'jio'); ?></h2><span><button type="button" data-auth-tab="signin"><?php esc_html_e('返回登录', 'jio'); ?></button></span></div>
<?php if ($wechat_qr) : ?><div class="auth-qrcode" data-auth-qrcode><div data-auth-qr-content><i class="fa fab fa-weixin" aria-hidden="true"></i><span><?php esc_html_e('获取二维码中…', 'jio'); ?></span></div><p class="auth-qrcode-status screen-reader-text" data-auth-qr-status role="status" aria-live="polite" aria-atomic="true"><?php esc_html_e('正在获取二维码', 'jio'); ?></p></div><?php endif; ?>
</section>
<section id="<?php echo esc_attr($unique); ?>-auth-panel-bind" class="sign-panel" role="tabpanel" data-auth-panel="bind" <?php echo $auth_tab !== 'bind' ? 'hidden' : ''; ?>>
<div class="sign-header"><h2><?php esc_html_e('绑定账号', 'jio'); ?></h2><?php if ($is_oauth_bind && $registration_open) : ?><span><?php esc_html_e('没有账号?', 'jio'); ?> <button type="button" data-auth-tab="signup"><?php esc_html_e('立即注册', 'jio'); ?></button></span><?php endif; ?></div>
<?php if ($is_oauth_bind) : ?>
<div class="sign-notice"><?php printf(esc_html__('通过 %s 登录,请绑定已有账号。', 'jio'), esc_html($oauth_provider_name)); ?></div>
<form class="sign-form" data-auth-form="login">
<div class="floating-input"><input name="target" id="<?php echo esc_attr($unique); ?>-bind-target" autocomplete="username" required><label for="<?php echo esc_attr($unique); ?>-bind-target"><?php echo $signin_phone ? esc_html__('邮箱 / 手机号 / 用户名', 'jio') : esc_html__('邮箱 / 用户名', 'jio'); ?></label></div>
<div class="floating-input has-action"><input type="password" name="password" id="<?php echo esc_attr($unique); ?>-bind-password" autocomplete="current-password" required><label for="<?php echo esc_attr($unique); ?>-bind-password"><?php esc_html_e('密码', 'jio'); ?></label><button type="button" class="password-show" data-password-show aria-label="<?php esc_attr_e('显示密码', 'jio'); ?>" aria-pressed="false"><i class="fa fas fa-eye"></i></button></div>
<?php if (function_exists('jio_render_captcha')) { jio_render_captcha('bind'); } ?>
<input type="hidden" name="obk" value="<?php echo esc_attr($obk); ?>">
<input type="hidden" name="rememberme" value="1">
<input type="hidden" name="redirect_to" value="<?php echo esc_attr($redirect_to); ?>">
<button type="submit" class="sign-submit jb-blue"><span><?php esc_html_e('登录并绑定', 'jio'); ?></span><i class="fa fas fa-spinner fa-spin" hidden></i></button>
</form>
<?php else : ?><div class="sign-notice"><?php esc_html_e('绑定会话已过期,请重新使用第三方登录。', 'jio'); ?></div><?php endif; ?>
</section>
<?php if (!empty($oauth_providers) && !$is_oauth_bind) : ?>
<div class="social-login"><span><?php esc_html_e('其他登录方式', 'jio'); ?></span><div class="social-login-buttons">
<?php foreach ($oauth_providers as $provider) : ?><?php if (($provider['name'] ?? '') === 'weixingzh') continue; ?><?php $provider_label = (string) ($provider['label'] ?? $provider['name'] ?? ''); ?><a class="social-login-item <?php echo esc_attr((string) ($provider['name'] ?? '')); ?>" href="<?php echo esc_url((string) ($provider['url'] ?? '#')); ?>" data-provider="<?php echo esc_attr((string) ($provider['name'] ?? '')); ?>" aria-label="<?php echo esc_attr(sprintf(__('%s登录', 'jio'), $provider_label)); ?>" title="<?php echo esc_attr($provider_label); ?>"><?php echo $provider['icon'] ?? ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?><?php if ($oauth_large) : ?><span><?php printf(esc_html__('%s登录', 'jio'), esc_html($provider_label)); ?></span><?php endif; ?></a><?php endforeach; ?>
<?php if ($wechat_qr) : ?><button type="button" class="social-login-item weixingzh" data-auth-tab="oauth" aria-label="<?php esc_attr_e('微信扫码登录', 'jio'); ?>" title="<?php esc_attr_e('微信扫码登录', 'jio'); ?>"><i class="fa fab fa-weixin" aria-hidden="true"></i><?php if ($oauth_large) : ?><span><?php esc_html_e('微信登录', 'jio'); ?></span><?php endif; ?></button><?php endif; ?>
</div></div>
<?php endif; ?>
<div class="tab-pane fade<?php echo $initial_tab === 'bind' ? ' active in' : ''; ?>" id="<?php echo esc_attr($unique); ?>-tab-bind" role="tabpanel" data-auth-panel="bind" <?php echo $initial_tab !== 'bind' ? 'hidden' : ''; ?>>
<?php if ($is_oauth_bind) : ?>
<div class="oauth-data-box">
<div class="muted-box">
<div class="user-info flex ac relative">
<span class="avatar-img mr6"><img alt="<?php esc_attr_e('头像', 'jio'); ?>" src="<?php echo esc_url($oauth_avatar); ?>" class="avatar"></span>
<div class="flex1 ml10"><b><?php printf(esc_html__('您好!%s', 'jio'), esc_html($oauth_name !== '' ? $oauth_name : $oauth_provider_name)); ?></b><div class="mt6 px12 muted-2-color"><?php printf(esc_html__('您首次使用此%1$s账号登录', 'jio'), '<b class="badg badg-sm c-blue">' . esc_html($oauth_provider_name) . '</b>'); ?><br><?php esc_html_e('请先绑定已有账号或创建新账号', 'jio'); ?></div></div>
</div>
</div>
</div>
<div class="box-body">
<div class="title-h-left em14"><?php esc_html_e('绑定账号', 'jio'); ?></div>
<?php if ($registration_open) : ?><a class="muted-color px12" href="#<?php echo esc_attr($unique); ?>-tab-sign-up" data-auth-tab="signup"><?php esc_html_e('没有账号?创建新账号', 'jio'); ?><i class="em12 ml3 fa fas fa-angle-right" aria-hidden="true"></i></a><?php endif; ?>
</div>
<form data-auth-form="login">
<div class="relative line-form mb10">
<input type="text" name="target" id="<?php echo esc_attr($unique); ?>-bind-target" class="line-form-input" autocomplete="username" tabindex="1" placeholder="" required>
<div class="scale-placeholder"><?php echo esc_html($signin_user_hint); ?></div>
<i class="line-form-line"></i>
</div>
<div class="relative line-form mb10">
<input type="password" name="password" id="<?php echo esc_attr($unique); ?>-bind-password" class="line-form-input" autocomplete="current-password" tabindex="2" placeholder="" required>
<div class="scale-placeholder"><?php esc_html_e('登录密码', 'jio'); ?></div>
<button type="button" class="abs-right sign-passw muted-2-color" data-password-show aria-label="<?php esc_attr_e('显示密码', 'jio'); ?>" aria-pressed="false"><i class="fa fas fa-eye" aria-hidden="true"></i></button>
<i class="line-form-line"></i>
</div>
<?php if (function_exists('jio_render_captcha')) { jio_render_captcha('bind'); } ?>
<input type="hidden" name="obk" value="<?php echo esc_attr($obk); ?>">
<input type="hidden" name="rememberme" value="1">
<input type="hidden" name="redirect_to" value="<?php echo esc_attr($redirect_to); ?>">
<div class="box-body">
<button type="submit" class="but radius jb-blue padding-lg btn-block"><i class="fa fas fa-sign-in-alt mr10" aria-hidden="true"></i><span data-submit-label><?php esc_html_e('绑定登录', 'jio'); ?></span><i class="fa fas fa-spinner fa-spin" hidden aria-hidden="true"></i></button>
</div>
</form>
<?php else : ?>
<div class="box-body">
<div class="title-h-left fa-2x"><?php esc_html_e('绑定账号', 'jio'); ?></div>
</div>
<div class="box-body"><div class="c-red px12"><i class="fa fas fa-info-circle mr6" aria-hidden="true"></i><?php esc_html_e('绑定会话已过期,请重新使用第三方登录。', 'jio'); ?></div></div>
<?php endif; ?>
</div>
</div>
</div>
+5 -8
View File
@@ -17,7 +17,6 @@ $image_id = $images ? (int) $images[array_rand($images)] : 0;
$image_html = $image_id > 0 ? wp_get_attachment_image($image_id, 'full', false, [
'class' => 'fit-cover radius8',
'alt' => get_bloginfo('name'),
'loading' => 'lazy',
'decoding' => 'async',
]) : '';
$auto = class_exists('\Jio\Settings\Settings') ? \Jio\Settings\Settings::sign_modal_auto() : ['enabled' => false, 'waiting' => 5, 'expires' => 1];
@@ -30,13 +29,11 @@ $jio_auth_context = [
'redirect_to' => home_url('/'),
];
?>
<div id="u_sign" class="jio-auth-modal<?php echo $image_html !== '' ? ' has-sign-img' : ''; ?>" aria-hidden="true" role="dialog" aria-modal="true" aria-labelledby="jio-auth-modal-title" tabindex="-1" data-auth-modal data-auto="<?php echo !empty($auto['enabled']) ? '1' : '0'; ?>" data-auto-wait="<?php echo esc_attr((string) $auto['waiting']); ?>" data-auto-expires="<?php echo esc_attr((string) $auto['expires']); ?>">
<h2 id="jio-auth-modal-title" class="screen-reader-text"><?php esc_html_e('账户登录与注册', 'jio'); ?></h2>
<div class="auth-modal-backdrop" data-auth-close></div>
<div class="modal-dialog">
<div class="modal-content">
<button type="button" class="auth-modal-close" data-auth-close aria-label="<?php esc_attr_e('关闭', 'jio'); ?>"><i class="fa fas fa-times"></i></button>
<?php if ($image_html !== '') : ?><div class="sign-img"><?php echo $image_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></div><?php endif; ?>
<div id="u_sign" class="modal jio-auth-modal<?php echo $image_html !== '' ? ' has-sign-img' : ''; ?>" aria-hidden="true" role="dialog" aria-modal="true" aria-labelledby="jio-auth-modal-title" tabindex="-1" data-auth-modal data-auto="<?php echo !empty($auto['enabled']) ? '1' : '0'; ?>" data-auto-wait="<?php echo esc_attr((string) $auto['waiting']); ?>" data-auto-expires="<?php echo esc_attr((string) $auto['expires']); ?>">
<h2 id="jio-auth-modal-title" class="screen-reader-text"><?php esc_html_e('账户登录与注册', 'jio'); ?></h2>
<div class="modal-dialog" role="document">
<div class="sign-content">
<?php if ($image_html !== '') : ?><div class="sign-img absolute hide-sm"><?php echo $image_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></div><?php endif; ?>
<?php require get_template_directory() . '/templates/parts/auth-content.php'; ?>
</div>
</div>
@@ -28,15 +28,20 @@ test('modal and sign page use one renderer and one state machine', () => {
assert.doesNotMatch(loader, /sign-register/);
});
test('static authentication dimensions and responsive contract are retained', () => {
const css = read('assets/css/routes/sign.css');
assert.match(css, /\.sign\s*\{[\s\S]*?max-width:\s*330px/);
assert.match(css, /#u_sign\.has-sign-img \.modal-dialog\s*\{\s*width:\s*800px/);
assert.match(css, /#u_sign \.sign-img\s*\{[^}]*inset:\s*0 45% 0 0;[^}]*padding:\s*0/);
assert.match(css, /#u_sign \.sign-img \+ \.sign\s*\{[^}]*margin-left:\s*55%/);
assert.match(css, /\.social-login-item\s*\{[\s\S]*?width:\s*32px;[\s\S]*?height:\s*32px/);
assert.match(css, /\.auth-qrcode\s*\{[\s\S]*?width:\s*180px;[\s\S]*?min-height:\s*180px/);
assert.match(css, /@media \(max-width:\s*767px\)[\s\S]*?\.sign-img\s*\{\s*display:\s*none/);
test('authentication shell reuses the shared sign-card CSS contract', () => {
// Card width, the 800px split dialog, the 55% card offset, the 32px social
// items and the QR box all live in the shared theme stylesheet now.
const mainCss = read('assets/css/main.css');
const signCss = read('assets/css/routes/sign.css');
assert.match(mainCss, /\.sign\s*\{[\s\S]*?max-width:\s*330px/);
assert.match(mainCss, /#u_sign \.modal-dialog\s*\{\s*width:\s*800px;/);
assert.match(mainCss, /\.sign-img \+ \.sign\s*\{[\s\S]*?margin-left:\s*55%/);
assert.match(mainCss, /\.social-login-item\s*\{[\s\S]*?width:\s*32px !important;[\s\S]*?height:\s*32px !important/);
assert.match(mainCss, /\.qrcode-signin-container\s*\{[\s\S]*?min-height:\s*254px/);
assert.match(mainCss, /\.signin-qrcode-img\s*\{[\s\S]*?width:\s*180px/);
assert.match(mainCss, /#u_sign \.modal-dialog\s*\{\s*width:\s*800px;/);
assert.match(signCss, /\.sign-page \.sign\s*\{\s*width:\s*350px/);
assert.match(signCss, /@media \(max-width:\s*767px\)[\s\S]*?\.sign-page \.sign\s*\{[\s\S]*?width:\s*340px/);
});
test('authentication settings use reference defaults and canonical keys', () => {
@@ -72,10 +77,10 @@ test('authentication galleries save attachment IDs and are consumed by both surf
assert.match(reader, /auth_gallery_ids\('sign_modal_background'\)/);
assert.match(reader, /auth_gallery_ids\('sign_page_background'\)/);
assert.match(modal, /wp_get_attachment_image\(\$image_id, 'full'/);
assert.match(modal, /<div class="sign-img"><\?php echo \$image_html/);
assert.match(modal, /<div class="sign-img absolute hide-sm"><\?php echo \$image_html/);
assert.match(page, /wp_get_attachment_image_url\(\$background_id, 'full'\)/);
assert.match(page, /<div class="sign-page-background" style="background-image:url/);
assert.match(css, /\.sign-img img\s*\{[\s\S]*?object-fit:\s*cover/);
assert.match(page, /<div class="fixed lazyload" data-bg="<\?php echo esc_url\(\$background_url\)/);
assert.match(css, /#u_sign \.sign-img img\s*\{[\s\S]*?object-fit:\s*cover/);
assert.doesNotMatch(modal + page, /is_string\(\$images\)|explode\(',', \$images\)/);
});
@@ -163,18 +168,19 @@ test('shared renderer contracts every configured authentication state', () => {
const modal = read('templates/parts/modal-auth.php');
const client = read('assets/js/auth.js');
assert.match(shared, /data-auth-password-fields/);
assert.match(shared, /data-auth-code-fields/);
assert.match(shared, /data-login-mode/);
assert.match(shared, /data-signin-panel="nopas"/);
assert.match(shared, /data-signin-panel="pas"/);
assert.match(shared, /data-signin-mode="pas"/);
['login', 'register', 'resetpassword'].forEach((scene) => {
assert.match(shared, new RegExp(`data-send-code="${scene}"`));
});
assert.match(shared, /\$omit_confirm/);
assert.match(shared, /\$ref_mode !== 'hidden'/);
assert.match(shared, /\$ref_mode === 'required'/);
assert.match(shared, /sign-agreement-implicit/);
assert.match(shared, /data-invite-gate-panel/);
assert.match(shared, /data-invite-form-panel/);
assert.match(shared, /name="agree_terms"[\s\S]*?required/);
assert.match(shared, /oauth-button-lg/);
assert.match(shared, /render_social_buttons\(__\('社交账号登录'/);
assert.match(shared, /data-auth-qrcode/);
assert.match(modal, /data-auto=/);
assert.match(client, /jioAuthAutoUntil/);
@@ -220,8 +226,8 @@ test('OAuth frontend is accessible, redirect-aware, and removes retired provider
assert.match(client, /setAttribute\('aria-label', visible \? '隐藏密码' : '显示密码'\)/);
assert.match(client, /setAttribute\('aria-pressed', visible \? 'true' : 'false'\)/);
assert.match(shared, /data-auth-qr-status[^>]*role="status"[^>]*aria-live="polite"/);
assert.match(shared, /data-provider=/);
assert.match(shared, /aria-label="<\?php echo esc_attr\(sprintf/);
assert.match(read('src/Auth/OAuth.php'), /data-provider="' \. esc_attr\(\$name\)/);
assert.match(read('src/Auth/OAuth.php'), /aria-label="' \. esc_attr\(sprintf/);
assert.match(client, /searchParams\.set\('redirect_to', redirect\)/);
assert.match(client, /oauth_action/);
@@ -240,14 +246,15 @@ test('OAuth frontend is accessible, redirect-aware, and removes retired provider
assert.match(mainCss, /\.pay-box \.but\.baidu/);
});
test('the social-login area drops the implicit agreement line', () => {
test('agreement copy sits under each panel, not under the user card', () => {
const shared = read('templates/parts/auth-content.php');
const userRenderer = read('src/WidgetSystem/Renderers/UserRenderer.php');
// The reference shows no agreement copy under the social buttons; only the
// registration panel keeps its own, and it stays reachable.
assert.doesNotMatch(shared, /使用社交账号登录即表示/);
assert.match(shared, /注册即表示/);
// The sign-in column states the social agreement, the registration panel
// states its own, and the compact user card carries neither line.
assert.match(shared, /使用社交账号登录即表示同意/);
assert.match(shared, /扫码登录即表示同意/);
assert.match(shared, /注册即表示同意/);
assert.match(shared, /name="agree_terms"[\s\S]*?required/);
assert.doesNotMatch(userRenderer, /使用社交账号登录即表示|我已阅读并同意/);
});
@@ -308,7 +315,7 @@ test('provider URLs stay raw in the data layer and are escaped once per surface'
assert.match(oauth, /'url'\s*=>\s*\$url,/);
// Every consumer still escapes on output, so the rendered href is unchanged.
assert.match(shared, /esc_url\(\(string\) \(\$provider\['url'\] \?\? '#'\)\)/);
assert.match(oauth, /href="' \. esc_url\(\$url\) \. '" class="' \. esc_attr\(\$class\)/);
assert.match(userRenderer, /href="' \. esc_url\(\$url\)/);
assert.match(oauth, /'<a rel="nofollow" href="' \. esc_url\(\$url\)/);
assert.match(comments, /<a href="<\?php echo esc_url\(\$url\); \?\>" class="but hollow social-login-item ml10">/);
@@ -68,6 +68,7 @@ test('theme initializes when the removed jio namespace is absent', () => {
getElementById() { return null; },
createElement() { return { setAttribute() {} }; },
dispatchEvent() {},
addEventListener() {},
};
const window = {
document,
@@ -36,6 +36,7 @@ function is_user_logged_in(): bool { return false; }
function get_current_user_id(): int { return 0; }
function wp_max_upload_size(): int { return 1048576; }
function is_page_template(string $template = ''): bool { return false; }
function apply_filters(string $hook, $value) { return $value; }
function jio_is_lazy(string $scope): bool { return false; }
function jio_get_lazy_thumb(string $size = ''): string { return 'https://example.test/lazy.svg'; }
function jio_get_default_avatar_url(): string { return 'https://example.test/avatar.png'; }