fix(profile): align account dialogs and contracts
This commit is contained in:
@@ -167,7 +167,7 @@
|
||||
var submitLabel = button ? button.innerHTML : '';
|
||||
if (button) {
|
||||
button.disabled = true;
|
||||
button.innerHTML = '<i class="fa fa-spinner fa-spin mr6" aria-hidden="true"></i>正在提交…';
|
||||
button.innerHTML = '<i class="fa fas fa-spinner fa-spin mr6" aria-hidden="true"></i>正在提交…';
|
||||
}
|
||||
toast('正在提交申请…', 'load', '', 'aksrt_identity_submit');
|
||||
window.AksrtRequest.request(config.restBase, {
|
||||
|
||||
+323
-363
@@ -349,7 +349,7 @@
|
||||
}
|
||||
|
||||
/* ==================== 个人信息保存 ==================== */
|
||||
|
||||
|
||||
|
||||
function initProfileForm(root) {
|
||||
root = root || document;
|
||||
@@ -718,7 +718,6 @@
|
||||
var runtime = window.AksrtModalRuntime;
|
||||
var template = document.querySelector('template[data-aksrt-settings-modal-template="' + kind + '"]');
|
||||
if (!runtime || typeof runtime.open !== 'function' || !template) return;
|
||||
var title = kind === 'password' ? '修改密码' : (kind === 'email' ? '更改邮箱' : '绑定手机');
|
||||
runtime.open({
|
||||
html: template.innerHTML,
|
||||
kind: 'account-settings',
|
||||
@@ -727,252 +726,349 @@
|
||||
onContent: function (_, session) {
|
||||
var shell = session && session.shell;
|
||||
if (!shell) return;
|
||||
shell.setAttribute('aria-label', title);
|
||||
var dialog = shell.querySelector('[data-account-dialog]');
|
||||
var title = dialog && dialog.querySelector('[data-account-password-title], .modal-colorful-header .text-center > div:last-child');
|
||||
if (title && title.textContent.trim()) shell.setAttribute('aria-label', title.textContent.trim());
|
||||
var firstInput = shell.querySelector('input:not([type="hidden"]), textarea, select');
|
||||
if (firstInput) firstInput.focus();
|
||||
bindModalFields(shell);
|
||||
initBindPhone(shell);
|
||||
bindDialog(shell);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function bindModalFields(scope) {
|
||||
if (!scope) return;
|
||||
scope.querySelectorAll('.toggle-pwd').forEach(function(btn) {
|
||||
if (btn.dataset.aksrtSettingsInitialized === 'true') return;
|
||||
btn.dataset.aksrtSettingsInitialized = 'true';
|
||||
btn.addEventListener('click', function() {
|
||||
var inp = scope.querySelector('#' + this.getAttribute('data-target'));
|
||||
if (!inp) return;
|
||||
inp.type = inp.type === 'password' ? 'text' : 'password';
|
||||
this.classList.toggle('is-visible');
|
||||
var icon = this.querySelector('i');
|
||||
if (icon) {
|
||||
icon.classList.toggle('fa-eye', inp.type === 'password');
|
||||
icon.classList.toggle('fa-eye-slash', inp.type === 'text');
|
||||
}
|
||||
function setStep(dialog, key) {
|
||||
dialog.querySelectorAll('[data-account-step]').forEach(function (panel) {
|
||||
panel.classList.toggle('is-active', panel.getAttribute('data-account-step') === key);
|
||||
});
|
||||
var panels = Array.prototype.slice.call(dialog.querySelectorAll('[data-account-step]'));
|
||||
var index = Math.max(0, panels.findIndex(function (panel) { return panel.getAttribute('data-account-step') === key; }));
|
||||
dialog.querySelectorAll('.account-step-list li').forEach(function (item, itemIndex) {
|
||||
item.classList.toggle('active', itemIndex === index);
|
||||
item.classList.toggle('done', itemIndex < index);
|
||||
});
|
||||
}
|
||||
|
||||
function resetCountdown(button) {
|
||||
if (!button) return;
|
||||
if (button.__aksrtCountdownTimer) window.clearInterval(button.__aksrtCountdownTimer);
|
||||
button.__aksrtCountdownTimer = null;
|
||||
button.disabled = false;
|
||||
button.classList.remove('is-counting');
|
||||
button.textContent = button.getAttribute('data-idle-label') || '发送验证码';
|
||||
}
|
||||
|
||||
function startCountdown(button, seconds) {
|
||||
var idleText = button.textContent;
|
||||
var left = Number(seconds || 60);
|
||||
if (button.__aksrtCountdownTimer) window.clearInterval(button.__aksrtCountdownTimer);
|
||||
button.disabled = true;
|
||||
button.classList.add('is-counting');
|
||||
button.setAttribute('data-idle-label', idleText);
|
||||
button.textContent = left + 's';
|
||||
button.__aksrtCountdownTimer = window.setInterval(function () {
|
||||
left -= 1;
|
||||
if (left <= 0) { resetCountdown(button); return; }
|
||||
button.textContent = left + 's';
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function settingsRestRoot() {
|
||||
return String((window.aksrtData && (window.aksrtData.restUrl || window.aksrtData.apiUrl)) || cfg.restUrl || '/wp-json/aksrt/v1').replace(/\/$/, '');
|
||||
}
|
||||
|
||||
function settingsRestNonce() {
|
||||
return (window.aksrtData && (window.aksrtData.restNonce || window.aksrtData.nonce)) || cfg.restNonce || '';
|
||||
}
|
||||
|
||||
function formHasRequiredValues(form) {
|
||||
var required = form.querySelectorAll('[required]');
|
||||
for (var i = 0; i < required.length; i++) {
|
||||
if (required[i].type === 'checkbox' && !required[i].checked) {
|
||||
required[i].focus();
|
||||
notyf(i18n.agreeTerms || '请先同意相关协议', 'warning');
|
||||
return false;
|
||||
}
|
||||
if (required[i].type !== 'checkbox' && !String(required[i].value || '').trim()) {
|
||||
required[i].focus();
|
||||
notyf(i18n.fillRequired || '请填写必填项', 'warning');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function sendEmailCode(button, form, scene) {
|
||||
if (!form || button.disabled) return;
|
||||
if (scene === 'change_email' && !String((form.querySelector('[name="new_email"]') || {}).value || '').trim()) {
|
||||
notyf('请输入邮箱', 'warning');
|
||||
return;
|
||||
}
|
||||
runCaptcha('change_email', form).then(function (captchaPayload) {
|
||||
if (captchaPayload === null) return null;
|
||||
var data = new URLSearchParams();
|
||||
data.set('action', 'aksrt_send_account_email_code');
|
||||
data.set('_settings_nonce', settingsNonce);
|
||||
data.set('scene', scene);
|
||||
new FormData(form).forEach(function (value, key) { if (value !== '' && !data.has(key)) data.set(key, value); });
|
||||
Object.keys(captchaPayload || {}).forEach(function (key) { data.set(key, captchaPayload[key]); });
|
||||
button.disabled = true;
|
||||
return fetch(ajaxUrl, { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: data.toString() });
|
||||
}).then(function (response) { return response ? response.json() : null; }).then(function (payload) {
|
||||
if (!payload) return;
|
||||
if (!payload.success) throw new Error((payload.data && payload.data.message) || '发送失败');
|
||||
notyf((payload.data && payload.data.message) || '验证码已发送', 'success');
|
||||
startCountdown(button, payload.data && payload.data.countdown);
|
||||
}).catch(function (error) {
|
||||
resetCountdown(button);
|
||||
notyf(error.message || '发送失败', 'danger');
|
||||
}).finally(function () { resetCaptcha('change_email', form); });
|
||||
}
|
||||
|
||||
function sendPhoneCode(button, form, stage) {
|
||||
if (!form || button.disabled) return;
|
||||
var phone = String((form.querySelector('[name="phone"]') || {}).value || '').trim();
|
||||
if (!phone) { notyf('请输入手机号', 'warning'); return; }
|
||||
runCaptcha('bind_phone', form).then(function (captchaPayload) {
|
||||
if (captchaPayload === null) return null;
|
||||
var restRoot = settingsRestRoot();
|
||||
var nonce = settingsRestNonce();
|
||||
var request = fetch(restRoot + '/user/phone-code', {
|
||||
method: 'POST', credentials: 'same-origin',
|
||||
headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': nonce },
|
||||
body: JSON.stringify(Object.assign({ phone: phone, stage: stage }, captchaPayload || {}))
|
||||
});
|
||||
button.disabled = true;
|
||||
return request;
|
||||
}).then(function (response) { return response ? response.json().then(function (payload) { return { ok: response.ok, payload: payload }; }) : null; }).then(function (result) {
|
||||
if (!result) return;
|
||||
if (!result.ok || !result.payload.success) throw new Error(result.payload.message || '发送失败');
|
||||
notyf(result.payload.message || '验证码已发送', 'success');
|
||||
startCountdown(button, result.payload.data && result.payload.data.countdown);
|
||||
}).catch(function (error) {
|
||||
resetCountdown(button);
|
||||
notyf(error.message || '发送失败', 'danger');
|
||||
}).finally(function () { resetCaptcha('bind_phone', form); });
|
||||
}
|
||||
|
||||
function postAjaxForm(form, action, scene, success) {
|
||||
if (!formHasRequiredValues(form)) return;
|
||||
var button = form.querySelector('[type="submit"]');
|
||||
var label = button && button.querySelector('[data-aksrt-settings-submit-label]');
|
||||
var original = label ? label.textContent : '';
|
||||
if (button) { button.disabled = true; setSettingsSubmitLabel(button, i18n.submitting || '提交中...'); }
|
||||
runCaptcha(scene, form).then(function (captchaPayload) {
|
||||
if (captchaPayload === null) {
|
||||
if (button) { button.disabled = false; setSettingsSubmitLabel(button, original); }
|
||||
return null;
|
||||
}
|
||||
var data = new FormData(form);
|
||||
data.set('action', action);
|
||||
data.set('_settings_nonce', settingsNonce);
|
||||
Object.keys(captchaPayload || {}).forEach(function (key) { data.set(key, captchaPayload[key]); });
|
||||
return fetch(ajaxUrl, { method: 'POST', credentials: 'same-origin', body: data });
|
||||
}).then(function (response) { return response ? response.json() : null; }).then(function (payload) {
|
||||
if (!payload) return;
|
||||
if (button) { button.disabled = false; setSettingsSubmitLabel(button, original); }
|
||||
if (!payload.success) throw new Error((payload.data && payload.data.message) || '操作失败');
|
||||
notyf((payload.data && payload.data.message) || '操作成功', 'success');
|
||||
if (typeof success === 'function') success(payload);
|
||||
}).catch(function (error) {
|
||||
if (button) { button.disabled = false; setSettingsSubmitLabel(button, original); }
|
||||
notyf(error.message || '操作失败', 'danger');
|
||||
}).finally(function () { resetCaptcha(scene, form); });
|
||||
}
|
||||
|
||||
function postPhoneForm(form, endpoint, success) {
|
||||
if (!formHasRequiredValues(form)) return;
|
||||
var button = form.querySelector('[type="submit"]');
|
||||
var label = button && button.querySelector('[data-aksrt-settings-submit-label]');
|
||||
var original = label ? label.textContent : '';
|
||||
runCaptcha('bind_phone', form).then(function (captchaPayload) {
|
||||
if (captchaPayload === null) return null;
|
||||
var restRoot = settingsRestRoot();
|
||||
var nonce = settingsRestNonce();
|
||||
if (button) { button.disabled = true; setSettingsSubmitLabel(button, i18n.submitting || '提交中...'); }
|
||||
var payload = {};
|
||||
new FormData(form).forEach(function (value, key) { payload[key] = value; });
|
||||
Object.keys(captchaPayload || {}).forEach(function (key) { payload[key] = captchaPayload[key]; });
|
||||
return fetch(restRoot + endpoint, { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': nonce }, body: JSON.stringify(payload) });
|
||||
}).then(function (response) { return response ? response.json().then(function (payload) { return { ok: response.ok, payload: payload }; }) : null; }).then(function (result) {
|
||||
if (!result) return;
|
||||
if (!result.ok || !result.payload.success) throw new Error(result.payload.message || '操作失败');
|
||||
if (button) { button.disabled = false; setSettingsSubmitLabel(button, original); }
|
||||
notyf(result.payload.message || '操作成功', 'success');
|
||||
if (typeof success === 'function') success(result.payload);
|
||||
}).catch(function (error) {
|
||||
if (button) { button.disabled = false; setSettingsSubmitLabel(button, original); }
|
||||
notyf(error.message || '操作失败', 'danger');
|
||||
}).finally(function () { resetCaptcha('bind_phone', form); });
|
||||
}
|
||||
|
||||
function sendRecoveryCode(button, form) {
|
||||
if (!form || button.disabled) return;
|
||||
var target = String((form.querySelector('[name="target"]') || {}).value || '').trim();
|
||||
if (!target) { notyf('请输入邮箱或手机号', 'warning'); return; }
|
||||
var dialog = form.closest('[data-account-dialog="password"]');
|
||||
button.disabled = true;
|
||||
runCaptcha('lostpassword', form).then(function (captchaPayload) {
|
||||
if (captchaPayload === null) { notyf('请先完成人机验证', 'warning'); resetCountdown(button); return null; }
|
||||
var payload = { scene: 'resetpassword', target: target, channel: dialog ? (dialog.getAttribute('data-recovery-channel') || '') : '' };
|
||||
Object.keys(captchaPayload || {}).forEach(function (key) { payload[key] = captchaPayload[key]; });
|
||||
return fetch(settingsRestRoot() + '/auth/code', {
|
||||
method: 'POST', credentials: 'same-origin',
|
||||
headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': settingsRestNonce() },
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
}).then(function (response) { return response ? response.json().then(function (payload) { return { ok: response.ok, payload: payload }; }) : null; }).then(function (result) {
|
||||
if (!result) return;
|
||||
if (!result.ok || !result.payload.success) throw new Error(result.payload.message || '发送失败');
|
||||
notyf((result.payload.data && result.payload.data.message) || result.payload.message || '验证码已发送', 'success');
|
||||
startCountdown(button, (result.payload.data && result.payload.data.countdown) || result.payload.countdown);
|
||||
}).catch(function (error) {
|
||||
resetCountdown(button);
|
||||
notyf(error.message || '发送失败', 'danger');
|
||||
}).finally(function () { resetCaptcha('lostpassword', form); });
|
||||
}
|
||||
|
||||
function postRecoveryForm(form) {
|
||||
if (!formHasRequiredValues(form)) return;
|
||||
var password = form.querySelector('[name="password"]');
|
||||
var confirm = form.querySelector('[name="password_confirm"]');
|
||||
if (password && confirm && password.value !== confirm.value) { notyf('两次密码输入不一致', 'warning'); confirm.focus(); return; }
|
||||
var button = form.querySelector('[type="submit"]');
|
||||
var label = button && button.querySelector('[data-aksrt-settings-submit-label]');
|
||||
var original = label ? label.textContent : '';
|
||||
var dialog = form.closest('[data-account-dialog="password"]');
|
||||
if (button) { button.disabled = true; setSettingsSubmitLabel(button, i18n.submitting || '提交中...'); }
|
||||
runCaptcha('lostpassword', form).then(function (captchaPayload) {
|
||||
if (captchaPayload === null) {
|
||||
if (button) { button.disabled = false; setSettingsSubmitLabel(button, original); }
|
||||
return null;
|
||||
}
|
||||
var payload = {};
|
||||
new FormData(form).forEach(function (value, key) { payload[key] = value; });
|
||||
payload.channel = dialog ? (dialog.getAttribute('data-recovery-channel') || '') : '';
|
||||
Object.keys(captchaPayload || {}).forEach(function (key) { payload[key] = captchaPayload[key]; });
|
||||
return fetch(settingsRestRoot() + '/auth/reset-password', {
|
||||
method: 'POST', credentials: 'same-origin',
|
||||
headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': settingsRestNonce() },
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
}).then(function (response) { return response ? response.json().then(function (payload) { return { ok: response.ok, payload: payload }; }) : null; }).then(function (result) {
|
||||
if (!result) return;
|
||||
if (!result.ok || !result.payload.success) throw new Error(result.payload.message || '重设密码失败');
|
||||
if (button) { button.disabled = false; setSettingsSubmitLabel(button, original); }
|
||||
notyf(result.payload.message || (result.payload.data && result.payload.data.message) || '密码已重置', 'success');
|
||||
window.setTimeout(function () {
|
||||
var redirect = result.payload.redirect || (result.payload.data && result.payload.data.redirect);
|
||||
if (redirect) window.location.assign(redirect);
|
||||
else window.location.reload();
|
||||
}, 700);
|
||||
}).catch(function (error) {
|
||||
if (button) { button.disabled = false; setSettingsSubmitLabel(button, original); }
|
||||
notyf(error.message || '重设密码失败', 'danger');
|
||||
}).finally(function () { resetCaptcha('lostpassword', form); });
|
||||
}
|
||||
|
||||
function bindDialog(shell) {
|
||||
var dialog = shell.querySelector('[data-account-dialog]');
|
||||
if (!dialog || dialog.dataset.aksrtBound === 'true') return;
|
||||
dialog.dataset.aksrtBound = 'true';
|
||||
dialog.querySelectorAll('.toggle-pwd').forEach(function (button) {
|
||||
button.addEventListener('click', function () {
|
||||
var input = dialog.querySelector('#' + button.getAttribute('data-target'));
|
||||
if (!input) return;
|
||||
input.type = input.type === 'password' ? 'text' : 'password';
|
||||
var icon = button.querySelector('i');
|
||||
if (icon) { icon.classList.toggle('fa-eye', input.type === 'password'); icon.classList.toggle('fa-eye-slash', input.type === 'text'); }
|
||||
});
|
||||
});
|
||||
|
||||
var pInput = scope.querySelector('#pwd-new');
|
||||
var sBar = scope.querySelector('#pwd-strength-bar');
|
||||
var sTxt = scope.querySelector('#pwd-strength-text');
|
||||
if (pInput && sBar && sTxt) {
|
||||
pInput.addEventListener('input', function() {
|
||||
var v = this.value;
|
||||
var fill = sBar.querySelector('.pwd-strength__fill');
|
||||
if (!v) { fill.className = 'pwd-strength__fill'; sTxt.className = 'pwd-strength__text'; sTxt.textContent = ''; return; }
|
||||
var score = 0;
|
||||
if (v.length >= 6) score++;
|
||||
if (v.length >= 10) score++;
|
||||
if (/[a-z]/.test(v) && /[A-Z]/.test(v)) score++;
|
||||
if (/\d/.test(v)) score++;
|
||||
if (/[^a-zA-Z0-9]/.test(v)) score++;
|
||||
var level = score <= 1 ? 'weak' : (score <= 3 ? 'medium' : 'strong');
|
||||
var label = score <= 1 ? '弱' : (score <= 3 ? '中' : '强');
|
||||
fill.className = 'pwd-strength__fill level-' + level;
|
||||
sTxt.className = 'pwd-strength__text level-' + level;
|
||||
sTxt.textContent = '密码强度: ' + label;
|
||||
var type = dialog.getAttribute('data-account-dialog');
|
||||
if (type === 'password') {
|
||||
var recoveryTarget = dialog.querySelector('#pwd-recovery-target');
|
||||
if (recoveryTarget && dialog.dataset.recoveryTarget) recoveryTarget.value = dialog.dataset.recoveryTarget;
|
||||
dialog.querySelectorAll('[data-account-recovery-open],[data-account-recovery-back]').forEach(function (button) {
|
||||
button.addEventListener('click', function () {
|
||||
var showRecovery = button.hasAttribute('data-account-recovery-open');
|
||||
dialog.querySelectorAll('[data-account-password-pane]').forEach(function (pane) {
|
||||
pane.hidden = pane.getAttribute('data-account-password-pane') === 'recovery' ? !showRecovery : showRecovery;
|
||||
});
|
||||
var title = dialog.querySelector('[data-account-password-title]');
|
||||
if (title) {
|
||||
title.textContent = title.getAttribute(showRecovery ? 'data-recovery-label' : 'data-change-label') || title.textContent;
|
||||
var shell = dialog.closest('.aksrt-user-settings-modal');
|
||||
if (shell) shell.setAttribute('aria-label', title.textContent);
|
||||
}
|
||||
var input = dialog.querySelector(showRecovery ? '#pwd-recovery-target' : '#pwd-old');
|
||||
if (input) input.focus();
|
||||
});
|
||||
});
|
||||
var passwordForm = dialog.querySelector('#pwd-form');
|
||||
if (passwordForm) passwordForm.addEventListener('submit', function (event) {
|
||||
event.preventDefault();
|
||||
var password = passwordForm.querySelector('[name="password"]');
|
||||
var confirm = passwordForm.querySelector('[name="password2"]');
|
||||
if (password && confirm && password.value !== confirm.value) { notyf('两次密码输入不一致', 'warning'); confirm.focus(); return; }
|
||||
postAjaxForm(passwordForm, 'aksrt_change_password', 'change_password', function () { window.setTimeout(function () { window.location.reload(); }, 700); });
|
||||
});
|
||||
var recoveryForm = dialog.querySelector('#pwd-recovery-form');
|
||||
var recoveryCodeButton = dialog.querySelector('[data-account-recovery-send]');
|
||||
if (recoveryCodeButton && recoveryForm) recoveryCodeButton.addEventListener('click', function () { sendRecoveryCode(recoveryCodeButton, recoveryForm); });
|
||||
if (recoveryForm) recoveryForm.addEventListener('submit', function (event) { event.preventDefault(); postRecoveryForm(recoveryForm); });
|
||||
} else if (type === 'email') {
|
||||
dialog.querySelectorAll('.account-code-send').forEach(function (button) {
|
||||
button.addEventListener('click', function () { sendEmailCode(button, button.closest('form'), button.getAttribute('data-account-code-scene')); });
|
||||
});
|
||||
var oldForm = dialog.querySelector('#email-old-verify-form');
|
||||
var newForm = dialog.querySelector('#email-new-form');
|
||||
if (oldForm) oldForm.addEventListener('submit', function (event) {
|
||||
event.preventDefault();
|
||||
postAjaxForm(oldForm, 'aksrt_verify_account_email', 'change_email', function () { setStep(dialog, 'email-new'); });
|
||||
});
|
||||
if (newForm) newForm.addEventListener('submit', function (event) {
|
||||
event.preventDefault();
|
||||
postAjaxForm(newForm, 'aksrt_change_email', 'change_email', function () {
|
||||
if (dialog.querySelector('[data-account-step="email-success"]')) setStep(dialog, 'email-success');
|
||||
window.setTimeout(function () { window.location.reload(); }, 700);
|
||||
});
|
||||
});
|
||||
} else if (type === 'phone') {
|
||||
dialog.querySelectorAll('[data-aksrt-sms-trigger]').forEach(function (button) {
|
||||
button.addEventListener('click', function () { sendPhoneCode(button, button.closest('form'), button.getAttribute('data-aksrt-sms-scene')); });
|
||||
});
|
||||
var phoneOldForm = dialog.querySelector('#phone-old-verify-form');
|
||||
var phoneNewForm = dialog.querySelector('#aksrt-bind-phone-form');
|
||||
if (phoneOldForm) phoneOldForm.addEventListener('submit', function (event) {
|
||||
event.preventDefault();
|
||||
postPhoneForm(phoneOldForm, '/user/phone-verify', function () { setStep(dialog, 'phone-new'); });
|
||||
});
|
||||
if (phoneNewForm) phoneNewForm.addEventListener('submit', function (event) {
|
||||
event.preventDefault();
|
||||
postPhoneForm(phoneNewForm, '/user/phone', function () {
|
||||
if (dialog.querySelector('[data-account-step="phone-success"]')) setStep(dialog, 'phone-success');
|
||||
window.setTimeout(function () { window.location.reload(); }, 700);
|
||||
});
|
||||
});
|
||||
}
|
||||
bindSend('pwd-send-code', 'pwd-form', 'change_password', scope);
|
||||
bindSend('email-send-code', 'email-form', 'change_email', scope);
|
||||
submitForm('pwd-form', 'aksrt_change_password', scope);
|
||||
submitForm('email-form', 'aksrt_change_email', scope);
|
||||
}
|
||||
|
||||
function resetSettingsModal(shell) {
|
||||
if (!shell || !shell.classList.contains('aksrt-user-settings-modal')) return;
|
||||
shell.dataset.aksrtSettingsModalClosed = 'true';
|
||||
var forms = shell.querySelectorAll('form');
|
||||
var sceneMap = { 'pwd-form': 'change_password', 'email-form': 'change_email', 'aksrt-bind-phone-form': 'bind_phone' };
|
||||
forms.forEach(function(form) {
|
||||
form.reset();
|
||||
var scene = sceneMap[form.id];
|
||||
if (scene) resetCaptcha(scene, form);
|
||||
form.querySelectorAll('[data-aksrt-countdown]').forEach(function(button) {
|
||||
if (button.__aksrtCountdownTimer) window.clearInterval(button.__aksrtCountdownTimer);
|
||||
button.__aksrtCountdownTimer = null;
|
||||
button.disabled = false;
|
||||
button.classList.remove('is-counting');
|
||||
button.textContent = button.getAttribute('data-idle-label') || button.textContent;
|
||||
});
|
||||
});
|
||||
var bar = shell.querySelector('#pwd-strength-bar');
|
||||
var fill = bar && bar.querySelector('.pwd-strength__fill');
|
||||
var text = shell.querySelector('#pwd-strength-text');
|
||||
if (fill) fill.className = 'pwd-strength__fill';
|
||||
if (text) { text.textContent = ''; text.className = 'pwd-strength__text'; }
|
||||
shell.querySelectorAll('.account-code-send,[data-aksrt-sms-trigger],[data-account-recovery-send]').forEach(resetCountdown);
|
||||
shell.querySelectorAll('form').forEach(function (form) { form.reset(); });
|
||||
}
|
||||
|
||||
if (document.documentElement.dataset.aksrtSettingsModalCleanupInitialized !== 'true') {
|
||||
document.documentElement.dataset.aksrtSettingsModalCleanupInitialized = 'true';
|
||||
document.addEventListener('aksrt:modal:close', function(event) {
|
||||
var shell = event.detail && event.detail.shell;
|
||||
resetSettingsModal(shell);
|
||||
});
|
||||
document.addEventListener('aksrt:modal:close', function (event) { resetSettingsModal(event.detail && event.detail.shell); });
|
||||
}
|
||||
|
||||
root.querySelectorAll('[data-aksrt-settings-modal]').forEach(function(btn) {
|
||||
if (btn.dataset.aksrtSettingsInitialized === 'true') return;
|
||||
btn.dataset.aksrtSettingsInitialized = 'true';
|
||||
btn.addEventListener('click', function() {
|
||||
openSettingsModal(this.getAttribute('data-aksrt-settings-modal'));
|
||||
});
|
||||
root.querySelectorAll('[data-aksrt-settings-modal]').forEach(function (button) {
|
||||
if (button.dataset.aksrtSettingsInitialized === 'true') return;
|
||||
button.dataset.aksrtSettingsInitialized = 'true';
|
||||
button.addEventListener('click', function () { openSettingsModal(button.getAttribute('data-aksrt-settings-modal')); });
|
||||
});
|
||||
|
||||
// 验证码发送
|
||||
function getSendBtnIdleText(btnId) {
|
||||
if (btnId === 'pwd-send-code') return i18n.sendToCurrentEmail || '发送到当前邮箱';
|
||||
if (btnId === 'email-send-code') return i18n.sendToNewEmail || '发送到新邮箱';
|
||||
return i18n.sendCode || '发送验证码';
|
||||
}
|
||||
|
||||
function bindSend(btnId, formId, scene, scope) {
|
||||
var container = scope || document;
|
||||
var b = container.querySelector ? container.querySelector('#' + btnId) : document.getElementById(btnId);
|
||||
if (!b) return;
|
||||
if (b.dataset.aksrtSettingsInitialized === 'true') return;
|
||||
b.dataset.aksrtSettingsInitialized = 'true';
|
||||
b.addEventListener('click', function() {
|
||||
if (this.classList.contains('is-counting')) return;
|
||||
var self = this;
|
||||
var form = container.querySelector ? container.querySelector('#' + formId) : document.getElementById(formId);
|
||||
var toastId = scene === 'change_password'
|
||||
? 'aksrt-settings-password-code-toast'
|
||||
: 'aksrt-settings-email-code-toast';
|
||||
runCaptcha(scene, form).then(function(captchaPayload) {
|
||||
if (captchaPayload === null) return;
|
||||
if (container.dataset && container.dataset.aksrtSettingsModalClosed === 'true') return;
|
||||
self.disabled = true;
|
||||
self.textContent = i18n.sending || '发送中...';
|
||||
notyf(i18n.sending || '正在发送验证码…', 'load', '', toastId);
|
||||
var data = new URLSearchParams();
|
||||
data.set('action', 'aksrt_send_email_code');
|
||||
data.set('_settings_nonce', settingsNonce);
|
||||
data.set('scene', scene || '');
|
||||
if (form) {
|
||||
new FormData(form).forEach(function(value, key) {
|
||||
if (data.has(key) || value === '' || value == null) return;
|
||||
data.set(key, value);
|
||||
});
|
||||
}
|
||||
Object.keys(captchaPayload || {}).forEach(function(key) { data.set(key, captchaPayload[key]); });
|
||||
fetch(ajaxUrl, { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: data.toString() })
|
||||
.then(function(r) { return r.json(); }).then(function(res) {
|
||||
if (res.success) {
|
||||
notyf((res.data && res.data.message) || i18n.codeSent || '验证码已发送', 'success', 5, toastId);
|
||||
if (container.dataset && container.dataset.aksrtSettingsModalClosed === 'true') return;
|
||||
var sec = 60;
|
||||
self.classList.add('is-counting');
|
||||
self.textContent = sec + 's 后重发';
|
||||
self.setAttribute('data-aksrt-countdown', '');
|
||||
self.setAttribute('data-idle-label', getSendBtnIdleText(btnId));
|
||||
var t = setInterval(function() {
|
||||
sec--;
|
||||
if (sec <= 0) {
|
||||
clearInterval(t);
|
||||
self.__aksrtCountdownTimer = null;
|
||||
self.disabled = false;
|
||||
self.classList.remove('is-counting');
|
||||
self.textContent = getSendBtnIdleText(btnId);
|
||||
} else {
|
||||
self.textContent = sec + 's 后重发';
|
||||
}
|
||||
}, 1000);
|
||||
self.__aksrtCountdownTimer = t;
|
||||
} else {
|
||||
notyf((res.data && res.data.message) || i18n.sendFailed || '发送失败', 'danger', 5, toastId);
|
||||
self.disabled = false;
|
||||
self.textContent = getSendBtnIdleText(btnId);
|
||||
}
|
||||
})
|
||||
.catch(function() {
|
||||
notyf(i18n.networkError || '网络错误', 'danger', 5, toastId);
|
||||
self.disabled = false;
|
||||
self.textContent = getSendBtnIdleText(btnId);
|
||||
})
|
||||
.finally(function() {
|
||||
resetCaptcha(scene, form);
|
||||
});
|
||||
}).catch(function() {
|
||||
resetCaptcha(scene, form);
|
||||
notyf('人机验证失败,请重试', 'danger', 5, toastId);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 表单提交
|
||||
function submitForm(fid, act, scope) {
|
||||
var container = scope || document;
|
||||
var fm = container.querySelector ? container.querySelector('#' + fid) : document.getElementById(fid);
|
||||
if (!fm) return;
|
||||
if (fm.dataset.aksrtSettingsInitialized === 'true') return;
|
||||
fm.dataset.aksrtSettingsInitialized = 'true';
|
||||
fm.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
var btn = fm.querySelector('[type=submit]');
|
||||
var submitLabel = btn && btn.querySelector('[data-aksrt-settings-submit-label]');
|
||||
var orig = submitLabel ? submitLabel.textContent : '';
|
||||
var toastId = fid === 'pwd-form'
|
||||
? 'aksrt-settings-password-toast'
|
||||
: 'aksrt-settings-email-toast';
|
||||
var reqs = fm.querySelectorAll('[required]');
|
||||
for (var i = 0; i < reqs.length; i++) {
|
||||
if (!reqs[i].value.trim()) { reqs[i].focus(); notyf(i18n.fillRequired || '请填写必填项', 'warning'); return; }
|
||||
}
|
||||
if (fid === 'pwd-form') {
|
||||
var pwdNew = fm.querySelector('#pwd-new');
|
||||
var pwdConfirm = fm.querySelector('#pwd-new-confirm');
|
||||
if (pwdNew && pwdConfirm && pwdNew.value !== pwdConfirm.value) {
|
||||
pwdConfirm.focus();
|
||||
notyf(i18n.passwordMismatch || '两次输入的新密码不一致', 'warning');
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (btn) { btn.disabled = true; setSettingsSubmitLabel(btn, i18n.submitting || '提交中...'); }
|
||||
notyf(i18n.submitting || '正在提交…', 'load', '', toastId);
|
||||
var scene = fid === 'pwd-form' ? 'change_password' : 'change_email';
|
||||
runCaptcha(scene, fm).then(function(captchaPayload) {
|
||||
if (captchaPayload === null) {
|
||||
if (btn) { btn.disabled = false; setSettingsSubmitLabel(btn, orig); }
|
||||
return null;
|
||||
}
|
||||
if (container.dataset && container.dataset.aksrtSettingsModalClosed === 'true') return null;
|
||||
var modalShell = fm.closest('.aksrt-user-settings-modal');
|
||||
if (modalShell && modalShell.dataset.aksrtSettingsModalClosed === 'true') return null;
|
||||
var d = new FormData(fm);
|
||||
d.set('action', act);
|
||||
d.set('_settings_nonce', settingsNonce);
|
||||
Object.keys(captchaPayload || {}).forEach(function(key) { d.set(key, captchaPayload[key]); });
|
||||
return fetch(ajaxUrl, { method: 'POST', credentials: 'same-origin', body: d });
|
||||
})
|
||||
.then(function(r) { return r ? r.json() : null; })
|
||||
.then(function(r) {
|
||||
if (!r) return;
|
||||
if (btn) { btn.disabled = false; setSettingsSubmitLabel(btn, orig); }
|
||||
if (r.success) {
|
||||
notyf((r.data && r.data.message) || '操作成功', 'success', 5, toastId);
|
||||
var activeModal = window.AksrtModalRuntime && window.AksrtModalRuntime.getActive();
|
||||
if (activeModal && activeModal.classList.contains('aksrt-user-settings-modal') && activeModal.contains(fm)) {
|
||||
window.AksrtModalRuntime.close('settings-submit');
|
||||
}
|
||||
if (r.data && r.data.redirect_to) setTimeout(function() { window.location.href = r.data.redirect_to; }, 2500);
|
||||
} else {
|
||||
notyf((r.data && r.data.message) || i18n.operationFailed || '操作失败', 'danger', 5, toastId);
|
||||
}
|
||||
})
|
||||
.catch(function() {
|
||||
if (btn) { btn.disabled = false; setSettingsSubmitLabel(btn, orig); }
|
||||
notyf(i18n.networkError || '网络错误', 'danger', 5, toastId);
|
||||
})
|
||||
.finally(function() {
|
||||
resetCaptcha(scene, fm);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
root.querySelectorAll('.binding-item--linkable').forEach(function(link) {
|
||||
root.querySelectorAll('.binding-item--linkable').forEach(function(link) {
|
||||
if (link.dataset.aksrtBindCaptchaInitialized === 'true') return;
|
||||
link.dataset.aksrtBindCaptchaInitialized = 'true';
|
||||
link.addEventListener('click', function(event) {
|
||||
@@ -1134,145 +1230,9 @@
|
||||
initNotifications();
|
||||
initNotificationPreferences();
|
||||
initSettings();
|
||||
initBindPhone();
|
||||
initSettingsCallbackToast();
|
||||
});
|
||||
|
||||
|
||||
// 绑定手机
|
||||
function initBindPhone(root) {
|
||||
root = root || document;
|
||||
var form = root.id === 'aksrt-bind-phone-form' ? root : root.querySelector('#aksrt-bind-phone-form');
|
||||
if (!form) return;
|
||||
if (form.dataset.aksrtSettingsInitialized === 'true') return;
|
||||
form.dataset.aksrtSettingsInitialized = 'true';
|
||||
function isValidSmsPhone(phone) {
|
||||
if (!window.aksrtData || aksrtData.smsNumberLimitCh !== false) {
|
||||
return /^1[3-9]\d{9}$/.test(phone);
|
||||
}
|
||||
return /^(?:\d{5,}|\+\d{6,}|\+?\d{2,}[-\s]\d{2,}[0-9\-\s]{0,15})$/.test(phone);
|
||||
}
|
||||
var sendButton = form.querySelector('[data-aksrt-sms-trigger]');
|
||||
if (sendButton) sendButton.addEventListener('click', function () {
|
||||
var phone = String((form.querySelector('[name="phone"]') || {}).value || '').trim();
|
||||
if (!isValidSmsPhone(phone)) { notyf('请输入正确的手机号', 'warning'); return; }
|
||||
var toastId = 'aksrt-settings-phone-code-toast';
|
||||
var restRoot = (window.aksrtData && aksrtData.apiUrl) || '/wp-json/aksrt/v1';
|
||||
var nonce = (window.aksrtData && aksrtData.restNonce) || '';
|
||||
sendButton.disabled = true;
|
||||
notyf('正在发送验证码…', 'load', '', toastId);
|
||||
runCaptcha('bind_phone', form).then(function(captchaPayload) {
|
||||
if (captchaPayload === null) {
|
||||
sendButton.disabled = false;
|
||||
return null;
|
||||
}
|
||||
var modalShell = form.closest('.aksrt-user-settings-modal');
|
||||
if (modalShell && modalShell.dataset.aksrtSettingsModalClosed === 'true') return null;
|
||||
return fetch(String(restRoot).replace(/\/$/, '') + '/user/phone-code', {
|
||||
method: 'POST', credentials: 'same-origin',
|
||||
headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': nonce },
|
||||
body: JSON.stringify(Object.assign({ phone: phone }, captchaPayload || {}))
|
||||
});
|
||||
}).then(function (r) { return r ? r.json().then(function (j) { return { ok: r.ok, json: j }; }) : null; }).then(function (res) {
|
||||
if (!res) return;
|
||||
if (!res.ok || !res.json.success) throw new Error(res.json.message || '发送失败');
|
||||
notyf(res.json.message || '验证码已发送', 'success', 5, toastId);
|
||||
var modalShell = form.closest('.aksrt-user-settings-modal');
|
||||
if (modalShell && modalShell.dataset.aksrtSettingsModalClosed === 'true') return;
|
||||
var left = Number((res.json.data && res.json.data.countdown) || 60);
|
||||
sendButton.setAttribute('data-aksrt-countdown', '');
|
||||
sendButton.setAttribute('data-idle-label', '获取验证码');
|
||||
sendButton.classList.add('is-counting');
|
||||
var timer = setInterval(function () {
|
||||
left -= 1;
|
||||
sendButton.textContent = left + 's';
|
||||
if (left <= 0) {
|
||||
clearInterval(timer);
|
||||
sendButton.__aksrtCountdownTimer = null;
|
||||
sendButton.disabled = false;
|
||||
sendButton.classList.remove('is-counting');
|
||||
sendButton.textContent = sendButton.getAttribute('data-idle-label');
|
||||
}
|
||||
}, 1000);
|
||||
sendButton.__aksrtCountdownTimer = timer;
|
||||
}).catch(function (error) { sendButton.disabled = false; notyf(error.message || '发送失败', 'danger', 5, toastId); })
|
||||
.finally(function () { resetCaptcha('bind_phone', form); });
|
||||
});
|
||||
form.addEventListener('submit', function (e) {
|
||||
e.preventDefault();
|
||||
var phoneEl = form.querySelector('[name="phone"]');
|
||||
var codeEl = form.querySelector('[name="code"]');
|
||||
var phone = phoneEl ? String(phoneEl.value || '').trim() : '';
|
||||
var code = codeEl ? String(codeEl.value || '').trim() : '';
|
||||
if (!isValidSmsPhone(phone)) {
|
||||
notyf('请输入正确的手机号', 'warning');
|
||||
return;
|
||||
}
|
||||
if (!/^\d{6}$/.test(code)) {
|
||||
notyf('请输入短信验证码', 'warning');
|
||||
return;
|
||||
}
|
||||
var submitBtn = form.querySelector('[type="submit"]');
|
||||
var submitLabel = submitBtn && submitBtn.querySelector('[data-aksrt-settings-submit-label]');
|
||||
var submitIdleText = submitLabel ? submitLabel.textContent : '';
|
||||
if (submitBtn) {
|
||||
submitBtn.disabled = true;
|
||||
setSettingsSubmitLabel(submitBtn, '绑定中...');
|
||||
}
|
||||
function doBind(captcha) {
|
||||
var toastId = 'aksrt-settings-phone-bind-toast';
|
||||
notyf('正在绑定手机…', 'load', '', toastId);
|
||||
var restRoot = (window.aksrtData && aksrtData.apiUrl) || '/wp-json/aksrt/v1';
|
||||
var nonce = (window.aksrtData && aksrtData.restNonce) || '';
|
||||
return fetch(String(restRoot).replace(/\/$/, '') + '/user/phone', {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-WP-Nonce': nonce
|
||||
},
|
||||
body: JSON.stringify(Object.assign({ phone: phone, code: code }, captcha))
|
||||
})
|
||||
.then(function (r) { return r.json().then(function (j) { return { ok: r.ok, json: j }; }); })
|
||||
.then(function (res) {
|
||||
if (res.ok && res.json && res.json.success) {
|
||||
notyf(res.json.message || '绑定成功', 'success', 5, toastId);
|
||||
var activeModal = window.AksrtModalRuntime && window.AksrtModalRuntime.getActive();
|
||||
if (activeModal && activeModal.classList.contains('aksrt-user-settings-modal') && activeModal.contains(form)) {
|
||||
window.AksrtModalRuntime.close('settings-submit');
|
||||
}
|
||||
setTimeout(function () { window.location.reload(); }, 600);
|
||||
return;
|
||||
}
|
||||
notyf((res.json && (res.json.message || res.json.error)) || '绑定失败', 'danger', 5, toastId);
|
||||
if (submitBtn) {
|
||||
submitBtn.disabled = false;
|
||||
setSettingsSubmitLabel(submitBtn, submitIdleText);
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
notyf('网络错误', 'danger', 5, toastId);
|
||||
if (submitBtn) {
|
||||
submitBtn.disabled = false;
|
||||
setSettingsSubmitLabel(submitBtn, submitIdleText);
|
||||
}
|
||||
});
|
||||
}
|
||||
runCaptcha('bind_phone', form).then(function(captchaPayload) {
|
||||
if (captchaPayload === null) {
|
||||
if (submitBtn) {
|
||||
submitBtn.disabled = false;
|
||||
setSettingsSubmitLabel(submitBtn, submitIdleText);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
var modalShell = form.closest('.aksrt-user-settings-modal');
|
||||
if (modalShell && modalShell.dataset.aksrtSettingsModalClosed === 'true') return null;
|
||||
return doBind(captchaPayload);
|
||||
}).finally(function() {
|
||||
resetCaptcha('bind_phone', form);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user