855 lines
32 KiB
JavaScript
855 lines
32 KiB
JavaScript
/**
|
|
* AKSRT User Center — 本人中心专属脚本
|
|
*
|
|
* 从 page-profile.php 内联 JS 迁移而来。
|
|
* 依赖全局 aksrtUserCenter 配置对象(由模板注入)。
|
|
*
|
|
* @package AKSRT
|
|
*/
|
|
|
|
/* global aksrtUserCenter, showToast */
|
|
|
|
(function() {
|
|
'use strict';
|
|
|
|
var cfg = window.aksrtUserCenter || {};
|
|
var ajaxUrl = cfg.ajaxUrl || '';
|
|
var publicNonce = cfg.publicNonce || '';
|
|
var settingsNonce = cfg.settingsNonce || '';
|
|
var submitNonce = cfg.submitNonce || '';
|
|
var userId = cfg.userId || 0;
|
|
var i18n = cfg.i18n || {};
|
|
var tabAliases = cfg.tabAliases || {};
|
|
var tabUrls = cfg.tabUrls || {};
|
|
|
|
/* ==================== Dashboard 导航 ==================== */
|
|
function initDashboardNavigation() {
|
|
var tabContainer = document.querySelector('.uc-mobile-tabs');
|
|
if (!tabContainer) return;
|
|
|
|
var tabs = tabContainer.querySelectorAll('[data-tab]');
|
|
var sidebarBtns = document.querySelectorAll('.uc-sidebar [data-tab]');
|
|
var panels = {};
|
|
var defaultTab = cfg.defaultTab || 'profile';
|
|
var drawerTrigger = document.getElementById('uc-drawer-trigger');
|
|
var drawerOverlay = document.getElementById('uc-drawer-overlay');
|
|
var sidebar = document.querySelector('.uc-sidebar');
|
|
|
|
tabs.forEach(function(tab) {
|
|
var name = tab.getAttribute('data-tab');
|
|
var panel = document.getElementById('panel-' + name);
|
|
if (panel) {
|
|
panels[name] = { tab: tab, panel: panel };
|
|
}
|
|
});
|
|
|
|
function openDrawer() {
|
|
if (sidebar) sidebar.classList.add('is-open');
|
|
if (drawerOverlay) drawerOverlay.classList.add('is-visible');
|
|
document.body.style.overflow = 'hidden';
|
|
}
|
|
|
|
function closeDrawer() {
|
|
if (sidebar) sidebar.classList.remove('is-open');
|
|
if (drawerOverlay) drawerOverlay.classList.remove('is-visible');
|
|
document.body.style.overflow = '';
|
|
}
|
|
|
|
function switchTo(name) {
|
|
if (!panels[name]) name = defaultTab;
|
|
Object.keys(panels).forEach(function(key) {
|
|
var active = key === name;
|
|
panels[key].tab.classList.toggle('is-active', active);
|
|
panels[key].tab.setAttribute('aria-selected', active ? 'true' : 'false');
|
|
panels[key].panel.classList.toggle('is-active', active);
|
|
panels[key].panel.hidden = !active;
|
|
});
|
|
sidebarBtns.forEach(function(btn) {
|
|
btn.classList.toggle('is-active', btn.getAttribute('data-tab') === name);
|
|
});
|
|
closeDrawer();
|
|
}
|
|
|
|
function loadPanel(name, forceLoad, queryParams) {
|
|
if (!panels[name]) return Promise.reject(new Error('panel-not-found'));
|
|
var target = panels[name].panel;
|
|
if (!forceLoad && target.dataset.panelLoaded === 'true') return Promise.resolve();
|
|
if (target._aksrtPanelRequest) return target._aksrtPanelRequest;
|
|
var restUrl = (window.aksrtData && (window.aksrtData.restUrl || window.aksrtData.apiUrl)) || cfg.restUrl || '';
|
|
if (!restUrl) return Promise.reject(new Error('rest-unavailable'));
|
|
if (name === 'orders' && (!window.AKSRTOrderCenter || typeof window.AKSRTOrderCenter.init !== 'function')) {
|
|
return Promise.reject(new Error('orders-initializer-unavailable'));
|
|
}
|
|
target.classList.add('is-loading');
|
|
var url = restUrl.replace(/\/$/, '') + '/user-center/panel/' + encodeURIComponent(name);
|
|
if (name === 'creator' || name === 'promotion' || name === 'posts' || name === 'follow') {
|
|
var params = queryParams || new URLSearchParams(window.location.search);
|
|
var allowedParams = name === 'creator' ? ['income_page'] :
|
|
(name === 'promotion' ? ['reward_tab', 'commission_page', 'invite_page'] :
|
|
(name === 'posts' ? ['post_status', 'posts_page'] : ['follow_list', 'follow_page']));
|
|
allowedParams.forEach(function(key) {
|
|
if (params.get(key)) url += (url.indexOf('?') === -1 ? '?' : '&') + key + '=' + encodeURIComponent(params.get(key));
|
|
});
|
|
}
|
|
target._aksrtPanelRequest = fetch(url, {
|
|
credentials: 'same-origin',
|
|
headers: { 'X-WP-Nonce': (window.aksrtData && (window.aksrtData.restNonce || window.aksrtData.nonce)) || '' }
|
|
}).then(function(response) {
|
|
return response.json().then(function(payload) {
|
|
if (!response.ok || !payload || !payload.success || !payload.data || typeof payload.data.html !== 'string') throw new Error('panel-load-failed');
|
|
if (name === 'orders' && window.AKSRTOrderCenter && typeof window.AKSRTOrderCenter.destroy === 'function') {
|
|
window.AKSRTOrderCenter.destroy(target);
|
|
}
|
|
target.innerHTML = payload.data.html;
|
|
if (window.AksrtFrontend && typeof window.AksrtFrontend.rehydrate === 'function') {
|
|
window.AksrtFrontend.rehydrate(target, 'ajax');
|
|
}
|
|
target.dataset.panelLoaded = 'true';
|
|
});
|
|
}).finally(function() {
|
|
target._aksrtPanelRequest = null;
|
|
target.classList.remove('is-loading');
|
|
});
|
|
return target._aksrtPanelRequest;
|
|
}
|
|
|
|
function activate(name, updateHistory, forceLoad, queryParams) {
|
|
if (!panels[name]) name = defaultTab;
|
|
// VIP membership may change outside this page, so never reuse stale HTML.
|
|
if (name === 'vip' && !forceLoad) forceLoad = true;
|
|
return loadPanel(name, forceLoad, queryParams).then(function() {
|
|
switchTo(name);
|
|
if (updateHistory) updateUrl(name);
|
|
if (name === 'promotion' && typeof window.AKSRTRevenueCenterInit === 'function') window.AKSRTRevenueCenterInit(panels[name].panel);
|
|
if (name === 'promotion' && typeof window.AKSRTAffiliatePromotionInit === 'function') window.AKSRTAffiliatePromotionInit();
|
|
}).catch(function() {
|
|
if (typeof showToast === 'function') showToast(i18n.networkError || '加载失败,请重试');
|
|
});
|
|
}
|
|
|
|
function tabFromUrl() {
|
|
var pathParts = window.location.pathname.replace(/\/+$/, '').split('/');
|
|
var pathTab = pathParts.length > 2 && pathParts[pathParts.length - 2] === 'user' ? pathParts[pathParts.length - 1] : '';
|
|
var name = pathTab || (cfg.activeTab || defaultTab);
|
|
if (name === 'balance') name = 'credits';
|
|
return tabAliases[name] || name;
|
|
}
|
|
|
|
function updateUrl(name, sourceUrl) {
|
|
if (!window.history.replaceState) return;
|
|
var pathTab = name === 'credits' ? 'balance' : name;
|
|
var u = new URL('/user/' + pathTab + '/', window.location.origin);
|
|
if (sourceUrl) {
|
|
var source = new URL(sourceUrl, window.location.href);
|
|
source.searchParams.forEach(function(value, key) { u.searchParams.set(key, value); });
|
|
}
|
|
window.history.pushState({}, '', u);
|
|
}
|
|
|
|
// Delegate every internal user-center link. This also covers markup injected
|
|
// after a REST panel refresh, so panel navigation never falls back to a full load.
|
|
document.addEventListener('click', function(e) {
|
|
var link = e.target && e.target.closest ? e.target.closest('a[href]') : null;
|
|
if (!link || e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || link.target === '_blank') return;
|
|
var url;
|
|
try { url = new URL(link.href, window.location.href); } catch (_) { return; }
|
|
if (url.origin !== window.location.origin) return;
|
|
var parts = url.pathname.replace(/\/+$/, '').split('/');
|
|
var pathTab = parts.length > 2 && parts[parts.length - 2] === 'user' ? parts[parts.length - 1] : '';
|
|
var name = link.getAttribute('data-tab') || pathTab;
|
|
if (name === 'balance') name = 'credits';
|
|
name = tabAliases[name] || name;
|
|
if (!name || !panels[name]) return;
|
|
e.preventDefault();
|
|
var hasQuery = url.search !== '';
|
|
activate(name, false, hasQuery, url.searchParams).then(function() { updateUrl(name, url.href); });
|
|
});
|
|
var creatorPanel = panels.creator ? panels.creator.panel : null;
|
|
if (creatorPanel) {
|
|
creatorPanel.addEventListener('click', function(e) {
|
|
var link = e.target && e.target.closest ? e.target.closest('.creator-income__pagination a') : null;
|
|
if (!link || e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
|
|
e.preventDefault();
|
|
var pageUrl = new URL(link.href, window.location.href);
|
|
loadPanel('creator', true, pageUrl.searchParams).then(function() {
|
|
switchTo('creator');
|
|
if (window.history.pushState) window.history.pushState({}, '', pageUrl.toString());
|
|
if (typeof window.AKSRTRevenueCenterInit === 'function') window.AKSRTRevenueCenterInit(creatorPanel);
|
|
}).catch(function() {
|
|
if (typeof showToast === 'function') showToast(i18n.networkError || '加载失败,请重试');
|
|
});
|
|
});
|
|
}
|
|
window.addEventListener('popstate', function() {
|
|
activate(tabFromUrl(), false, window.location.search !== '', new URLSearchParams(window.location.search));
|
|
});
|
|
if (drawerTrigger) drawerTrigger.addEventListener('click', openDrawer);
|
|
if (drawerOverlay) drawerOverlay.addEventListener('click', closeDrawer);
|
|
activate(tabFromUrl(), false);
|
|
}
|
|
|
|
/* ==================== 个人信息保存 ==================== */
|
|
|
|
|
|
function initProfileForm() {
|
|
var form = document.getElementById('profile-form');
|
|
if (!form) return;
|
|
|
|
form.addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
var btn = document.getElementById('profile-save-btn');
|
|
var msg = document.getElementById('profile-save-msg');
|
|
btn.disabled = true;
|
|
btn.textContent = i18n.saving || '保存中…';
|
|
msg.className = 'profile-form__submit-msg';
|
|
msg.textContent = '';
|
|
|
|
var data = new FormData(form);
|
|
data.append('user_id', String(userId));
|
|
|
|
fetch(ajaxUrl, { method: 'POST', body: data })
|
|
.then(function(r) { return r.json(); })
|
|
.then(function(res) {
|
|
btn.disabled = false;
|
|
btn.textContent = i18n.saveBtn || '保存修改';
|
|
if (res.success) {
|
|
showToast(i18n.saved || '已保存');
|
|
} else {
|
|
msg.className = 'profile-form__submit-msg is-error';
|
|
msg.textContent = res.data.message || (i18n.saveFailed || '保存失败');
|
|
}
|
|
})
|
|
.catch(function() {
|
|
btn.disabled = false;
|
|
btn.textContent = i18n.saveBtn || '保存修改';
|
|
msg.className = 'profile-form__submit-msg is-error';
|
|
msg.textContent = i18n.networkError || '网络错误,请重试';
|
|
});
|
|
});
|
|
}
|
|
|
|
function initAuthForm() {
|
|
var root = document.querySelector('[data-identity-root]');
|
|
if (root && window.AKSRTUserCenterAuth && typeof window.AKSRTUserCenterAuth.init === 'function') {
|
|
window.AKSRTUserCenterAuth.init(root);
|
|
}
|
|
}
|
|
|
|
/* ==================== 列表内取消收藏 ==================== */
|
|
function initUnfavorite() {
|
|
var list = document.querySelector('.profile-list[data-list="favorites"]');
|
|
if (!list) return;
|
|
|
|
list.addEventListener('click', function(e) {
|
|
var btn = e.target.closest('[data-action="unfavorite"]');
|
|
if (!btn) return;
|
|
e.preventDefault();
|
|
var postId = btn.getAttribute('data-post-id');
|
|
if (!postId || btn.disabled) return;
|
|
if (!confirm(i18n.confirmUnfavorite || '确定取消收藏这篇文章?')) return;
|
|
|
|
btn.disabled = true;
|
|
btn.classList.add('is-loading');
|
|
|
|
var body = new URLSearchParams();
|
|
body.set('action', 'aksrt_toggle_favorite');
|
|
body.set('postId', postId);
|
|
body.set('nonce', publicNonce);
|
|
body.set('active', '0');
|
|
|
|
fetch(ajaxUrl, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
|
|
credentials: 'same-origin',
|
|
body: body.toString()
|
|
})
|
|
.then(function(r) { return r.json(); })
|
|
.then(function(res) {
|
|
if (res && res.success) {
|
|
var item = btn.closest('.profile-list-item');
|
|
if (item) {
|
|
item.classList.add('is-removing');
|
|
setTimeout(function() {
|
|
if (item.parentNode) item.parentNode.removeChild(item);
|
|
if (!list.querySelector('.profile-list-item')) {
|
|
// Show empty state instead of reloading
|
|
var empty = document.createElement('div');
|
|
empty.className = 'profile-empty';
|
|
empty.innerHTML = '<div class="profile-empty__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" width="30" height="30"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg></div><p class="profile-empty__title">暂无收藏</p><p class="profile-empty__desc">你还没有收藏任何文章。</p>';
|
|
list.parentNode.replaceChild(empty, list);
|
|
}
|
|
}, 220);
|
|
}
|
|
showToast(i18n.unfavorited || '已取消收藏');
|
|
} else {
|
|
btn.disabled = false;
|
|
btn.classList.remove('is-loading');
|
|
showToast((res && res.data && res.data.message) || (i18n.operationFailed || '操作失败'));
|
|
}
|
|
})
|
|
.catch(function() {
|
|
btn.disabled = false;
|
|
btn.classList.remove('is-loading');
|
|
showToast(i18n.networkError || '网络错误');
|
|
});
|
|
});
|
|
}
|
|
|
|
function initPostDeletion() {
|
|
if (document.documentElement.dataset.aksrtPostDeletionBound === 'true') return;
|
|
document.documentElement.dataset.aksrtPostDeletionBound = 'true';
|
|
document.addEventListener('click', function(e) {
|
|
var btn = e.target && e.target.closest ? e.target.closest('[data-action="delete-post"]') : null;
|
|
if (!btn || btn.disabled || !confirm('确定删除这篇文章?')) return;
|
|
e.preventDefault();
|
|
btn.disabled = true;
|
|
var body = new URLSearchParams();
|
|
body.set('action', 'aksrt_delete_post');
|
|
body.set('post_id', btn.getAttribute('data-post-id') || '');
|
|
body.set('nonce', btn.getAttribute('data-nonce') || submitNonce);
|
|
fetch(ajaxUrl, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, credentials: 'same-origin', body: body.toString() })
|
|
.then(function(response) { return response.json(); })
|
|
.then(function(response) {
|
|
if (!response || !response.success) throw new Error('delete-failed');
|
|
var item = btn.closest('.profile-list-item');
|
|
if (item) item.remove();
|
|
if (typeof showToast === 'function') showToast('文章已删除');
|
|
})
|
|
.catch(function() {
|
|
btn.disabled = false;
|
|
if (typeof showToast === 'function') showToast(i18n.operationFailed || '操作失败');
|
|
});
|
|
});
|
|
}
|
|
|
|
/* ==================== 通知中心 ==================== */
|
|
function initNotifications() {
|
|
var list = document.getElementById('aksrt-notification-list');
|
|
var markAllBtn = document.getElementById('aksrt-mark-all-notifications-read');
|
|
var markSelectedBtn = document.getElementById('aksrt-mark-selected-notifications-read');
|
|
var deleteSelectedBtn = document.getElementById('aksrt-delete-selected-notifications');
|
|
if (!list) return;
|
|
|
|
function markRead(notificationId, markAll) {
|
|
var body = new URLSearchParams();
|
|
body.set('action', 'aksrt_mark_notification_read');
|
|
body.set('nonce', publicNonce);
|
|
if (markAll) {
|
|
body.set('mark_all', '1');
|
|
} else {
|
|
body.set('notification_id', notificationId);
|
|
}
|
|
return fetch(ajaxUrl, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
|
|
credentials: 'same-origin',
|
|
body: body.toString()
|
|
}).then(function(r) { return r.json(); });
|
|
}
|
|
|
|
// 单条标记已读 / 删除
|
|
list.addEventListener('click', function(e) {
|
|
var btn = e.target.closest('.aksrt-notification-read-btn');
|
|
if (btn) {
|
|
var id = btn.getAttribute('data-notification-id');
|
|
if (!id || btn.disabled) return;
|
|
btn.disabled = true;
|
|
markRead(id, false).then(function(res) {
|
|
if (res && res.success) {
|
|
var row = btn.closest('[data-notification-id]');
|
|
if (row) row.classList.add('is-read');
|
|
btn.remove();
|
|
showToast(i18n.markedRead || '已标记为已读');
|
|
} else {
|
|
btn.disabled = false;
|
|
showToast((res && res.data && res.data.message) || (i18n.operationFailed || '操作失败'));
|
|
}
|
|
}).catch(function() {
|
|
btn.disabled = false;
|
|
showToast(i18n.networkError || '网络错误');
|
|
});
|
|
return;
|
|
}
|
|
|
|
var delBtn = e.target.closest('.aksrt-notification-delete-btn');
|
|
if (!delBtn) return;
|
|
var delId = delBtn.getAttribute('data-notification-id');
|
|
if (!delId || delBtn.disabled) return;
|
|
if (!confirm(i18n.confirmDeleteNotification || '确定删除这条通知?')) return;
|
|
delBtn.disabled = true;
|
|
var body = new URLSearchParams();
|
|
body.set('action', 'aksrt_delete_notification');
|
|
body.set('nonce', publicNonce);
|
|
body.set('notification_id', delId);
|
|
fetch(ajaxUrl, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
|
|
credentials: 'same-origin',
|
|
body: body.toString()
|
|
}).then(function(r) { return r.json(); }).then(function(res) {
|
|
if (res && res.success) {
|
|
var delRow = delBtn.closest('[data-notification-id]');
|
|
if (delRow) delRow.remove();
|
|
showToast(i18n.notificationDeleted || '已删除通知');
|
|
} else {
|
|
delBtn.disabled = false;
|
|
showToast((res && res.data && res.data.message) || (i18n.operationFailed || '操作失败'));
|
|
}
|
|
}).catch(function() {
|
|
delBtn.disabled = false;
|
|
showToast(i18n.networkError || '网络错误');
|
|
});
|
|
});
|
|
|
|
// 全部已读
|
|
if (markAllBtn) {
|
|
markAllBtn.addEventListener('click', function() {
|
|
if (markAllBtn.disabled) return;
|
|
markAllBtn.disabled = true;
|
|
markRead('', true).then(function(res) {
|
|
if (res && res.success) {
|
|
list.querySelectorAll('[data-notification-id]').forEach(function(row) {
|
|
row.classList.add('is-read');
|
|
});
|
|
list.querySelectorAll('.aksrt-notification-read-btn').forEach(function(b) { b.remove(); });
|
|
showToast(i18n.allMarkedRead || '已全部标记为已读');
|
|
} else {
|
|
markAllBtn.disabled = false;
|
|
showToast((res && res.data && res.data.message) || (i18n.operationFailed || '操作失败'));
|
|
}
|
|
}).catch(function() {
|
|
markAllBtn.disabled = false;
|
|
showToast(i18n.networkError || '网络错误');
|
|
});
|
|
});
|
|
}
|
|
|
|
// 批量已读
|
|
if (markSelectedBtn) {
|
|
markSelectedBtn.addEventListener('click', function() {
|
|
var checked = Array.prototype.slice.call(list.querySelectorAll('.aksrt-notification-check:checked')).map(function(input) {
|
|
return input.value;
|
|
});
|
|
if (!checked.length) {
|
|
showToast(i18n.selectNotifications || '请先选择要标记的通知');
|
|
return;
|
|
}
|
|
markSelectedBtn.disabled = true;
|
|
var chain = Promise.resolve();
|
|
checked.forEach(function(id) {
|
|
chain = chain.then(function() { return markRead(id, false); });
|
|
});
|
|
chain.then(function() {
|
|
checked.forEach(function(id) {
|
|
var row = list.querySelector('[data-notification-id="' + id + '"]');
|
|
if (row) row.classList.add('is-read');
|
|
var b = row ? row.querySelector('.aksrt-notification-read-btn') : null;
|
|
if (b) b.remove();
|
|
});
|
|
showToast(i18n.selectedMarkedRead || '已标记所选通知为已读');
|
|
markSelectedBtn.disabled = false;
|
|
}).catch(function() {
|
|
markSelectedBtn.disabled = false;
|
|
showToast(i18n.networkError || '网络错误');
|
|
});
|
|
});
|
|
}
|
|
|
|
// 批量删除
|
|
if (deleteSelectedBtn) {
|
|
deleteSelectedBtn.addEventListener('click', function() {
|
|
var checked = Array.prototype.slice.call(list.querySelectorAll('.aksrt-notification-check:checked')).map(function(input) {
|
|
return input.value;
|
|
});
|
|
if (!checked.length) {
|
|
showToast(i18n.selectNotifications || '请先选择要删除的通知');
|
|
return;
|
|
}
|
|
if (!confirm(i18n.confirmBatchDelete || '确定批量删除所选通知?')) return;
|
|
deleteSelectedBtn.disabled = true;
|
|
var body = new FormData();
|
|
body.append('action', 'aksrt_delete_notifications');
|
|
body.append('nonce', publicNonce);
|
|
checked.forEach(function(id) {
|
|
body.append('notification_ids[]', id);
|
|
});
|
|
fetch(ajaxUrl, { method: 'POST', body: body, credentials: 'same-origin' })
|
|
.then(function(r) { return r.json(); })
|
|
.then(function(res) {
|
|
if (res && res.success) {
|
|
checked.forEach(function(id) {
|
|
var row = list.querySelector('[data-notification-id="' + id + '"]');
|
|
if (row) row.remove();
|
|
});
|
|
showToast(i18n.batchDeleted || '已删除所选通知');
|
|
} else {
|
|
deleteSelectedBtn.disabled = false;
|
|
showToast((res && res.data && res.data.message) || (i18n.operationFailed || '操作失败'));
|
|
}
|
|
})
|
|
.catch(function() {
|
|
deleteSelectedBtn.disabled = false;
|
|
showToast(i18n.networkError || '网络错误');
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
/* ==================== 账号设置:弹窗 / 密码 / 邮箱 / 绑定 ==================== */
|
|
function initSettings() {
|
|
if (!ajaxUrl || !settingsNonce) return;
|
|
|
|
function openModal(id) {
|
|
var m = document.getElementById(id);
|
|
if (!m) return;
|
|
m.classList.add('is-open');
|
|
document.body.style.overflow = 'hidden';
|
|
var firstInput = m.querySelector('input:not([type=hidden])');
|
|
if (firstInput) setTimeout(function() { firstInput.focus(); }, 200);
|
|
}
|
|
|
|
function closeModal(m) {
|
|
if (typeof m === 'string') m = document.getElementById(m);
|
|
if (!m) return;
|
|
m.classList.remove('is-open');
|
|
document.body.style.overflow = '';
|
|
var f = m.querySelector('form');
|
|
var sceneMap = { 'pwd-modal': 'change_password', 'email-modal': 'change_email', 'phone-modal': 'bind_phone' };
|
|
var scene = m.id && sceneMap[m.id] ? sceneMap[m.id] : '';
|
|
var store = window.AKSRTCaptchaState && window.AKSRTCaptchaState.scenes ? window.AKSRTCaptchaState.scenes : null;
|
|
if (f) {
|
|
f.reset();
|
|
var bar = document.getElementById('pwd-strength-bar');
|
|
var txt = document.getElementById('pwd-strength-text');
|
|
if (bar && bar.firstChild) { bar.style.width = '0'; bar.firstChild.className = 'pwd-strength__fill'; }
|
|
if (txt) { txt.textContent = ''; txt.className = 'pwd-strength__text'; }
|
|
}
|
|
if (scene && store && store[scene] && typeof store[scene].reset === 'function') {
|
|
store[scene].reset();
|
|
}
|
|
}
|
|
|
|
document.querySelectorAll('.security-trigger').forEach(function(btn) {
|
|
btn.addEventListener('click', function() { openModal(this.getAttribute('data-modal')); });
|
|
});
|
|
document.querySelectorAll('[data-close-modal]').forEach(function(el) {
|
|
el.addEventListener('click', function() { closeModal(this.closest('.aksrt-modal')); });
|
|
});
|
|
document.addEventListener('keydown', function(e) {
|
|
if (e.key === 'Escape') {
|
|
var openM = document.querySelector('.aksrt-modal.is-open');
|
|
if (openM) closeModal(openM);
|
|
}
|
|
});
|
|
|
|
// 密码显隐切换
|
|
document.querySelectorAll('#pwd-modal .toggle-pwd, #email-modal .toggle-pwd').forEach(function(btn) {
|
|
btn.addEventListener('click', function() {
|
|
var inp = document.getElementById(this.getAttribute('data-target'));
|
|
if (!inp) return;
|
|
inp.type = (inp.type === 'password') ? 'text' : 'password';
|
|
this.classList.toggle('is-visible');
|
|
});
|
|
});
|
|
|
|
// 密码强度
|
|
var pInput = document.getElementById('pwd-new');
|
|
var sBar = document.getElementById('pwd-strength-bar');
|
|
var sTxt = document.getElementById('pwd-strength-text');
|
|
if (pInput && sBar && sTxt) {
|
|
pInput.addEventListener('input', function() {
|
|
var v = this.value;
|
|
var f = sBar.querySelector('.pwd-strength__fill');
|
|
if (!v) { f.className = 'pwd-strength__fill'; sTxt.className = 'pwd-strength__text'; sTxt.textContent = ''; return; }
|
|
var s = 0;
|
|
if (v.length >= 6) s++;
|
|
if (v.length >= 10) s++;
|
|
if (/[a-z]/.test(v) && /[A-Z]/.test(v)) s++;
|
|
if (/\d/.test(v)) s++;
|
|
if (/[^a-zA-Z0-9]/.test(v)) s++;
|
|
var lv = '', tx = '';
|
|
if (s <= 1) { lv = 'weak'; tx = '弱'; }
|
|
else if (s <= 3) { lv = 'medium'; tx = '中'; }
|
|
else { lv = 'strong'; tx = '强'; }
|
|
f.className = 'pwd-strength__fill level-' + lv;
|
|
sTxt.className = 'pwd-strength__text level-' + lv;
|
|
sTxt.textContent = '密码强度: ' + tx;
|
|
});
|
|
}
|
|
|
|
// 验证码发送
|
|
function triggerSceneCaptcha(scene, callback) {
|
|
var store = window.AKSRTCaptchaState && window.AKSRTCaptchaState.scenes ? window.AKSRTCaptchaState.scenes : null;
|
|
var instance = store && store[scene] ? store[scene] : null;
|
|
if (instance && typeof instance.verify === 'function') {
|
|
instance.verify(callback);
|
|
return;
|
|
}
|
|
callback();
|
|
}
|
|
|
|
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) {
|
|
var b = document.getElementById(btnId);
|
|
if (!b) return;
|
|
b.addEventListener('click', function() {
|
|
if (this.classList.contains('is-counting')) return;
|
|
var self = this;
|
|
var form = document.getElementById(formId);
|
|
triggerSceneCaptcha(scene, function() {
|
|
self.disabled = true;
|
|
self.textContent = i18n.sending || '发送中...';
|
|
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);
|
|
});
|
|
}
|
|
fetch(ajaxUrl, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: data.toString() })
|
|
.then(function(r) { return r.json(); }).then(function(res) {
|
|
if (res.success) {
|
|
showToast(res.data.message || (i18n.codeSent || '验证码已发送'));
|
|
var sec = 60;
|
|
self.classList.add('is-counting');
|
|
self.textContent = sec + 's 后重发';
|
|
var t = setInterval(function() {
|
|
sec--;
|
|
if (sec <= 0) {
|
|
clearInterval(t);
|
|
self.disabled = false;
|
|
self.classList.remove('is-counting');
|
|
self.textContent = getSendBtnIdleText(btnId);
|
|
} else {
|
|
self.textContent = sec + 's 后重发';
|
|
}
|
|
}, 1000);
|
|
} else {
|
|
showToast(res.data.message || (i18n.sendFailed || '发送失败'));
|
|
self.disabled = false;
|
|
self.textContent = getSendBtnIdleText(btnId);
|
|
}
|
|
})
|
|
.catch(function() {
|
|
showToast(i18n.networkError || '网络错误');
|
|
self.disabled = false;
|
|
self.textContent = getSendBtnIdleText(btnId);
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
bindSend('pwd-send-code', 'pwd-form', 'change_password');
|
|
bindSend('email-send-code', 'email-form', 'change_email');
|
|
|
|
// 表单提交
|
|
function submitForm(fid, act) {
|
|
var fm = document.getElementById(fid);
|
|
if (!fm) return;
|
|
fm.addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
var btn = fm.querySelector('[type=submit]');
|
|
var orig = btn ? btn.textContent : '';
|
|
var reqs = fm.querySelectorAll('[required]');
|
|
for (var i = 0; i < reqs.length; i++) {
|
|
if (!reqs[i].value.trim()) { reqs[i].focus(); showToast(i18n.fillRequired || '请填写必填项'); return; }
|
|
}
|
|
if (fid === 'pwd-form') {
|
|
var pwdNew = document.getElementById('pwd-new');
|
|
var pwdConfirm = document.getElementById('pwd-new-confirm');
|
|
if (pwdNew && pwdConfirm && pwdNew.value !== pwdConfirm.value) {
|
|
pwdConfirm.focus();
|
|
showToast(i18n.passwordMismatch || '两次输入的新密码不一致');
|
|
return;
|
|
}
|
|
}
|
|
if (btn) { btn.disabled = true; btn.textContent = i18n.submitting || '提交中...'; }
|
|
var d = new FormData(fm);
|
|
d.append('action', act);
|
|
d.append('_settings_nonce', settingsNonce);
|
|
fetch(ajaxUrl, { method: 'POST', body: d })
|
|
.then(function(r) { return r.json(); })
|
|
.then(function(r) {
|
|
if (btn) { btn.disabled = false; btn.textContent = orig; }
|
|
if (r.success) {
|
|
showToast(r.data.message || '');
|
|
closeModal(fm.closest('.aksrt-modal'));
|
|
if (r.data.redirect_to) setTimeout(function() { window.location.href = r.data.redirect_to; }, 2500);
|
|
} else {
|
|
showToast(r.data.message || (i18n.operationFailed || '操作失败'));
|
|
}
|
|
})
|
|
.catch(function() {
|
|
if (btn) { btn.disabled = false; btn.textContent = orig; }
|
|
showToast(i18n.networkError || '网络错误');
|
|
});
|
|
});
|
|
}
|
|
|
|
submitForm('pwd-form', 'aksrt_change_password');
|
|
submitForm('email-form', 'aksrt_change_email');
|
|
|
|
// 解绑
|
|
document.querySelectorAll('.binding-unbind-btn').forEach(function(b) {
|
|
b.addEventListener('click', function() {
|
|
var p = this.getAttribute('data-provider');
|
|
if (!p) return;
|
|
if (!confirm(i18n.confirmUnbind || '确定解除绑定?')) return;
|
|
var self = b;
|
|
self.disabled = true;
|
|
self.textContent = i18n.unbinding || '解除中...';
|
|
var unbindNonce = document.getElementById('aksrt-oauth-unbind-nonce');
|
|
var data = new URLSearchParams();
|
|
data.set('action', 'aksrt_oauth_unbind');
|
|
data.set('nonce', unbindNonce ? unbindNonce.value : '');
|
|
data.set('provider', p);
|
|
data.set('userId', String(userId));
|
|
fetch(ajaxUrl, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
body: data.toString()
|
|
})
|
|
.then(function(r) { return r.json(); })
|
|
.then(function(d) {
|
|
if (d.success) {
|
|
showToast(i18n.unbindSuccess || '解除成功');
|
|
setTimeout(function() {
|
|
var u = new URL(window.location);
|
|
u.searchParams.set('tab', 'settings');
|
|
u.searchParams.set('oauth_unbound', p);
|
|
window.location.href = u.toString();
|
|
}, 1000);
|
|
} else {
|
|
showToast(i18n.unbindFailed || '解除失败');
|
|
self.disabled = false;
|
|
self.textContent = i18n.unbind || '解除';
|
|
}
|
|
})
|
|
.catch(function() {
|
|
showToast(i18n.networkError || '网络错误');
|
|
self.disabled = false;
|
|
self.textContent = i18n.unbind || '解除';
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
initDashboardNavigation();
|
|
initProfileForm();
|
|
initAuthForm();
|
|
initUnfavorite();
|
|
initPostDeletion();
|
|
initNotifications();
|
|
initSettings();
|
|
});
|
|
} else {
|
|
initDashboardNavigation();
|
|
initProfileForm();
|
|
initAuthForm();
|
|
initUnfavorite();
|
|
initPostDeletion();
|
|
initNotifications();
|
|
initSettings();
|
|
}
|
|
|
|
// 绑定手机
|
|
(function initBindPhone() {
|
|
var form = document.getElementById('aksrt-bind-phone-form');
|
|
if (!form) return;
|
|
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 (!/^1[3-9]\d{9}$/.test(phone)) {
|
|
showToast('请输入正确的手机号');
|
|
return;
|
|
}
|
|
if (!code) {
|
|
showToast('请输入短信验证码');
|
|
return;
|
|
}
|
|
var submitBtn = form.querySelector('[type="submit"]');
|
|
if (submitBtn) {
|
|
submitBtn.disabled = true;
|
|
submitBtn.textContent = '绑定中...';
|
|
}
|
|
function collectCaptcha(formEl) {
|
|
var out = {};
|
|
[
|
|
'captcha_verified', 'tencent_ticket', 'tencent_randstr', 'tencent_sid',
|
|
'cf_turnstile_response', 'geetest_lot_number', 'geetest_captcha_output',
|
|
'geetest_pass_token', 'geetest_gen_time', 'aliyun_captcha_verify_param'
|
|
].forEach(function (name) {
|
|
var el = formEl.querySelector('[name="' + name + '"]');
|
|
if (el && el.value) out[name] = el.value;
|
|
});
|
|
return out;
|
|
}
|
|
function resetCaptcha() {
|
|
try {
|
|
var store = window.AKSRTCaptchaState && window.AKSRTCaptchaState.scenes;
|
|
if (store && store.bind_phone && typeof store.bind_phone.reset === 'function') {
|
|
store.bind_phone.reset();
|
|
}
|
|
} catch (err) {}
|
|
}
|
|
function doBind() {
|
|
var captcha = collectCaptcha(form);
|
|
var restRoot = (window.aksrtData && aksrtData.apiUrl) || '/wp-json/aksrt/v1';
|
|
var nonce = (window.aksrtData && aksrtData.restNonce) || '';
|
|
fetch(String(restRoot).replace(/\/$/, '') + '/auth/bind-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) {
|
|
showToast((res.json.message) || '绑定成功');
|
|
setTimeout(function () { window.location.reload(); }, 600);
|
|
return;
|
|
}
|
|
resetCaptcha();
|
|
showToast((res.json && (res.json.message || res.json.error)) || '绑定失败');
|
|
if (submitBtn) {
|
|
submitBtn.disabled = false;
|
|
submitBtn.textContent = '确认绑定';
|
|
}
|
|
})
|
|
.catch(function () {
|
|
resetCaptcha();
|
|
showToast('网络错误');
|
|
if (submitBtn) {
|
|
submitBtn.disabled = false;
|
|
submitBtn.textContent = '确认绑定';
|
|
}
|
|
});
|
|
}
|
|
var store = window.AKSRTCaptchaState && window.AKSRTCaptchaState.scenes;
|
|
if (store && store.bind_phone && typeof store.bind_phone.verify === 'function') {
|
|
store.bind_phone.verify(doBind);
|
|
} else {
|
|
doBind();
|
|
}
|
|
});
|
|
})();
|
|
|
|
})();
|