Files
wordpress-theme-aksrt/assets/js/messages.js
T
kate522 1f4a39d8f8 feat(runtime): 全站前端脚本统一接入 AksrtFrontend 全局 DOM 生命周期
- rehydrate.js 新增 boot()/aksrt:ready 事件,支持 boot 后晚注册立即以 init 触发
- aksrt-runtime.js 初始加载改走 AksrtFrontend.boot,tooltip/倒计时注册为组件
- 约 30 个前端脚本(首页、评论、支付、路由、页面叶子、widgets)
  从直接 DOMContentLoaded 迁移为 AksrtFrontend.register,并加幂等标记
- section-navs 依赖改为 aksrt-runtime,保证注册时序
- 清理死代码:删除孤儿 loader.js/main.js 及 runtime/page-navs 遗留副本
- loader.js 移除已迁移模块的 tbquire 路径映射,main.js 相应瘦身
- build-public-assets.mjs 增加 runtime/main.min.js 自动压缩步骤
- 新增 4 个契约测试(homepage-dom/rehydrate-runtime/global-dom-init/
  public-bundle-parity),3 个既有 harness 适配注册表初始化方式
2026-09-02 21:48:56 +08:00

235 lines
8.6 KiB
JavaScript

/**
* AKSRT message center DOM navigation.
*
* @package AKSRT
*/
(function () {
'use strict';
function init(scope) {
scope = scope || document;
var root = scope.nodeType === 1 && scope.matches('[data-message-center]') ? scope : scope.querySelector('[data-message-center]');
if (!root || root.dataset.aksrtMessagesBound === '1') return;
root.dataset.aksrtMessagesBound = '1';
var nonce = typeof aksrtData !== 'undefined' ? aksrtData.nonce : '';
var ajaxUrl = typeof aksrtData !== 'undefined' ? aksrtData.ajaxUrl : '/wp-admin/admin-ajax.php';
var content = root.querySelector('[data-message-content]');
var nav = root.querySelector('[data-message-nav]');
var state = {
view: root.dataset.view || 'unread',
page: 1,
detail: 0,
paginateType: root.dataset.paginateType || 'ajax_lists',
};
var pollInterval = 60000;
function post(action, data) {
var body = new URLSearchParams({ action: action, nonce: nonce });
Object.keys(data || {}).forEach(function (key) {
var value = data[key];
if (Array.isArray(value)) {
value.forEach(function (item) { body.append(key + '[]', item); });
} else {
body.append(key, value);
}
});
return fetch(ajaxUrl, { method: 'POST', body: body, credentials: 'same-origin' })
.then(function (response) { return response.json(); });
}
function routeFor(view) {
var link = nav.querySelector('[data-message-view="' + view + '"]');
return link ? link.href : window.location.href;
}
function updateHeaderBadge(unread) {
var count = Math.max(0, Number(unread) || 0);
var headerBadge = document.querySelector('.aksrt-notification-badge');
var avatarDot = document.querySelector('.nav-user__dot');
if (headerBadge) {
headerBadge.textContent = String(count);
headerBadge.style.display = count > 0 ? '' : 'none';
}
if (avatarDot) avatarDot.style.display = count > 0 ? '' : 'none';
}
function renderError(message) {
content.innerHTML = '<div class="messages-empty"><span class="messages-empty__icon"><i class="fa fas fa-exclamation-circle"></i></span><p class="messages-empty__text"></p></div>';
content.querySelector('.messages-empty__text').textContent = message || '加载失败,请稍后重试';
}
function appendMessagePage(markup) {
var incoming = document.createElement('div');
incoming.innerHTML = markup;
var currentList = content.querySelector('.messages-list');
var incomingList = incoming.querySelector('.messages-list');
if (!currentList || !incomingList) {
content.innerHTML = markup;
return null;
}
var existingIds = new Set();
currentList.querySelectorAll('[data-notification-id]').forEach(function (item) {
existingIds.add(item.dataset.notificationId);
});
var firstAdded = null;
incomingList.querySelectorAll('.message-item').forEach(function (item) {
if (existingIds.has(item.dataset.notificationId)) return;
if (!firstAdded) firstAdded = item;
currentList.appendChild(item);
});
var currentPagination = content.querySelector('.messages-pagination');
var incomingPagination = incoming.querySelector('.messages-pagination');
if (currentPagination) currentPagination.remove();
if (incomingPagination) content.appendChild(incomingPagination);
return firstAdded;
}
function load(next, options) {
var requested = {
view: next.view || state.view,
page: next.page || 1,
detail: next.detail || 0,
};
var settings = options || {};
root.classList.add('is-loading');
content.setAttribute('aria-busy', 'true');
return post('aksrt_load_message_center', {
view: requested.view,
page: requested.page,
notification_id: requested.detail,
}).then(function (result) {
if (!result.success || !result.data) {
throw new Error(result.data && result.data.message ? result.data.message : '加载失败,请稍后重试');
}
requested.paginateType = result.data.paginate_type || state.paginateType;
state = requested;
root.dataset.view = state.view;
root.dataset.paginateType = state.paginateType;
nav.innerHTML = result.data.nav;
var firstAdded = null;
if (settings.append && state.paginateType === 'ajax_lists') {
firstAdded = appendMessagePage(result.data.content);
} else {
content.innerHTML = result.data.content;
}
updateHeaderBadge(result.data.unread);
if (settings.history === 'push') {
window.history.pushState(state, '', routeFor(state.view));
} else if (settings.history === 'replace') {
window.history.replaceState(state, '', routeFor(state.view));
}
if (firstAdded) {
firstAdded.setAttribute('tabindex', '-1');
firstAdded.focus({ preventScroll: true });
} else {
content.focus({ preventScroll: true });
}
}).catch(function (error) {
renderError(error.message);
}).finally(function () {
root.classList.remove('is-loading');
content.removeAttribute('aria-busy');
});
}
function reloadList() {
return load({ view: state.view, page: state.page, detail: 0 });
}
document.addEventListener('click', function (event) {
var tab = event.target.closest('[data-message-view]');
if (!tab || !root.contains(tab) || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
event.preventDefault();
load({ view: tab.dataset.messageView, page: 1, detail: 0 }, { history: 'push' });
});
document.addEventListener('click', function (event) {
var button = event.target.closest('.js-msg-detail');
if (!button || !root.contains(button)) return;
event.preventDefault();
load({ view: button.dataset.view || state.view, page: state.page, detail: button.dataset.id });
});
document.addEventListener('click', function (event) {
var button = event.target.closest('[data-message-back]');
if (!button || !root.contains(button)) return;
load({ view: button.dataset.view || state.view, page: state.page, detail: 0 });
});
document.addEventListener('click', function (event) {
var button = event.target.closest('[data-message-page]');
if (!button || !root.contains(button)) return;
event.preventDefault();
load({ view: state.view, page: button.dataset.messagePage, detail: 0 });
});
document.addEventListener('click', function (event) {
var button = event.target.closest('[data-message-next-page]');
if (!button || !root.contains(button)) return;
event.preventDefault();
load(
{ view: state.view, page: button.dataset.messageNextPage, detail: 0 },
{ append: true }
);
});
document.addEventListener('click', function (event) {
var button = event.target.closest('.js-msg-mark-read');
if (!button || !root.contains(button)) return;
post('aksrt_mark_notification_read', { notification_id: button.dataset.id }).then(function (result) {
if (result.success) reloadList();
});
});
document.addEventListener('click', function (event) {
var button = event.target.closest('.js-msg-delete');
if (!button || !root.contains(button)) return;
post('aksrt_delete_notification', { notification_id: button.dataset.id }).then(function (result) {
if (result.success) reloadList();
});
});
document.addEventListener('click', function (event) {
var button = event.target.closest('.js-msg-mark-all-read');
if (!button || !root.contains(button)) return;
post('aksrt_mark_notification_read', { mark_all: '1' }).then(function (result) {
if (result.success) reloadList();
});
});
document.addEventListener('click', function (event) {
var button = event.target.closest('.js-msg-clear-read');
if (!button || !root.contains(button)) return;
var ids = [];
root.querySelectorAll('.message-item:not(.is-unread)[data-notification-id]').forEach(function (item) {
if (/^\d+$/.test(item.dataset.notificationId)) ids.push(item.dataset.notificationId);
});
if (!ids.length) return;
post('aksrt_delete_notifications', { notification_ids: ids }).then(function (result) {
if (result.success) reloadList();
});
});
window.addEventListener('popstate', function (event) {
var previous = event.state;
if (previous && previous.view) {
load(previous);
}
});
window.history.replaceState(state, '', routeFor(state.view));
window.setInterval(function () {
post('aksrt_check_new_notifications', {}).then(function (result) {
if (result.success && result.data) updateHeaderBadge(result.data.unread);
}).catch(function () {});
}, pollInterval);
}
window.AksrtFrontend.register('aksrt-messages', init);
})();