补充主题静态资源与归档模板

This commit is contained in:
kate522 committed 2026-07-03 23:15:11 +08:00
1 parent 1268a55dd0
commit 3247db7ed1
265 files changed
+59174

No files matched your search

+213
View File
@@ -0,0 +1,213 @@
/**
* AKSRT Archive AJAX Filter
*/
(function () {
"use strict";
function initArchiveFilter() {
var bar = document.querySelector(".archive-filter-bar--ajax[data-ajax-archive]");
if (!bar) return;
var archiveType = bar.dataset.ajaxArchive || "category";
var termId = parseInt(bar.dataset.termId, 10) || 0;
var wrap = document.querySelector("[data-ajax-wrap]");
if (!wrap) return;
var loading = wrap.querySelector(".archive__ajax-loading");
var REST_BASE = "/wp-json/aksrt/v1/archive/posts";
var state = {
filter_cat: "",
filter_tag: "",
sort: "latest",
page: 1,
cf: {}
};
// Read initial state from active chips
var activeCat = bar.querySelector("[data-filter-cat].is-active");
if (activeCat) state.filter_cat = activeCat.dataset.filterCat || "";
var activeTag = bar.querySelector("[data-filter-tag].is-active");
if (activeTag) state.filter_tag = activeTag.dataset.filterTag || "";
var activeSort = bar.querySelector("[data-filter-sort].is-active");
if (activeSort) state.sort = activeSort.dataset.filterSort || "latest";
// custom_filter: read initial cf state from active chips
bar.querySelectorAll("[data-filter-cf].is-active").forEach(function (el) {
var dimKey = el.dataset.filterCf || "";
var dimVal = el.dataset.filterCfVal || "";
if (dimKey) state.cf[dimKey] = dimVal;
});
function buildUrl() {
var params = new URLSearchParams();
params.set("archive_type", archiveType);
params.set("term_id", String(termId));
if (state.filter_cat) params.set("filter_cat", state.filter_cat);
if (state.filter_tag) params.set("filter_tag", state.filter_tag);
var sortMap = { oldest: { orderby: "date", order: "ASC" }, popular: { orderby: "comment_count", order: "DESC" } };
var s = sortMap[state.sort];
params.set("sort", s ? s.orderby : "date");
params.set("order", s ? s.order : "DESC");
params.set("page", String(state.page));
// custom_filter: pass active dimensions as JSON
var cfActive = {};
var hasCf = false;
for (var cfK in state.cf) {
if (state.cf[cfK]) { cfActive[cfK] = state.cf[cfK]; hasCf = true; }
}
if (hasCf) params.set("custom_filters", JSON.stringify(cfActive));
return REST_BASE + "?" + params.toString();
}
function updateActiveChips() {
bar.querySelectorAll("[data-filter-cat]").forEach(function (el) {
el.classList.toggle("is-active", (el.dataset.filterCat || "") === state.filter_cat);
});
bar.querySelectorAll("[data-filter-tag]").forEach(function (el) {
el.classList.toggle("is-active", (el.dataset.filterTag || "") === state.filter_tag);
});
bar.querySelectorAll("[data-filter-sort]").forEach(function (el) {
el.classList.toggle("is-active", (el.dataset.filterSort || "latest") === state.sort);
});
// custom_filter: update cf chip active state
bar.querySelectorAll("[data-filter-cf]").forEach(function (el) {
var dimKey = el.dataset.filterCf || "";
var dimVal = el.dataset.filterCfVal || "";
var isActive = dimKey && (state.cf[dimKey] || "") === dimVal;
el.classList.toggle("is-active", isActive);
});
}
function showLoading() {
if (loading) loading.classList.add("is-loading");
wrap.classList.add("is-loading");
}
function hideLoading() {
if (loading) loading.classList.remove("is-loading");
wrap.classList.remove("is-loading");
}
function fetchPosts(pushState) {
showLoading();
fetch(buildUrl(), {
method: "GET",
headers: { Accept: "application/json" },
credentials: "same-origin"
})
.then(function (r) {
if (!r.ok) throw new Error("HTTP " + r.status);
return r.json();
})
.then(function (data) {
hideLoading();
if (data.html !== undefined) {
// Keep the loading element, replace the rest
var children = Array.from(wrap.children);
children.forEach(function (child) {
if (child !== loading) wrap.removeChild(child);
});
if (data.html) {
var temp = document.createElement("div");
temp.innerHTML = data.html;
while (temp.firstChild) wrap.appendChild(temp.firstChild);
} else {
var noResults = document.createElement("div");
noResults.className = "no-results";
noResults.innerHTML = "<p>暂无文章</p>";
wrap.appendChild(noResults);
}
// Re-init rehydratable modules for new content
if (window.AksrtFrontend) AksrtFrontend.rehydrate(wrap, 'ajax');
}
if (pushState !== false) {
var url = new URL(window.location.href);
url.searchParams.delete("orderby");
url.searchParams.delete("order");
url.searchParams.delete("paged");
url.searchParams.delete("aksrt_filter_cat");
url.searchParams.delete("aksrt_filter_tag");
// custom_filter: clean cf params
url.searchParams.forEach(function (v, k) {
if (k.indexOf("aksrt_cf_") === 0) url.searchParams.delete(k);
});
if (state.filter_cat) url.searchParams.set("aksrt_filter_cat", state.filter_cat);
if (state.filter_tag) url.searchParams.set("aksrt_filter_tag", state.filter_tag);
// custom_filter: set cf URL params
for (var cfK2 in state.cf) {
if (state.cf[cfK2]) url.searchParams.set("aksrt_cf_" + cfK2, state.cf[cfK2]);
}
if (state.sort === "oldest") { url.searchParams.set("orderby", "date"); url.searchParams.set("order", "asc"); }
else if (state.sort === "popular") { url.searchParams.set("orderby", "comment_count"); url.searchParams.set("order", "desc"); }
if (state.page > 1) url.searchParams.set("paged", String(state.page));
history.pushState({ aksrtArchive: true, state: Object.assign({}, state) }, "", url.toString());
}
})
.catch(function () {
hideLoading();
});
}
bar.addEventListener("click", function (e) {
var chip = e.target.closest("[data-filter-cat], [data-filter-tag], [data-filter-sort], [data-filter-cf]");
if (!chip) return;
e.preventDefault();
var changed = false;
if (chip.dataset.filterCat !== undefined) {
var newCat = chip.dataset.filterCat;
if (newCat !== state.filter_cat) { state.filter_cat = newCat; changed = true; }
}
if (chip.dataset.filterTag !== undefined) {
var newTag = chip.dataset.filterTag;
if (newTag !== state.filter_tag) { state.filter_tag = newTag; changed = true; }
}
if (chip.dataset.filterSort !== undefined) {
var newSort = chip.dataset.filterSort || "latest";
if (newSort !== state.sort) { state.sort = newSort; changed = true; }
}
// custom_filter: handle cf chip clicks
if (chip.dataset.filterCf !== undefined) {
var cfKey = chip.dataset.filterCf;
var cfVal = chip.dataset.filterCfVal || "";
if ((state.cf[cfKey] || "") !== cfVal) {
state.cf[cfKey] = cfVal;
changed = true;
}
}
if (changed) {
state.page = 1;
updateActiveChips();
fetchPosts(true);
}
});
// Pagination within AJAX wrap
wrap.addEventListener("click", function (e) {
var pageLink = e.target.closest(".pagination a, .nav-links a, a.page-numbers");
if (!pageLink || !wrap.contains(pageLink)) return;
var href = pageLink.getAttribute("href");
if (!href) return;
var match = href.match(/[?&]paged=(\d+)/);
if (match) {
e.preventDefault();
state.page = parseInt(match[1], 10) || 1;
fetchPosts(true);
}
});
// Handle browser back/forward
window.addEventListener("popstate", function (e) {
if (e.state && e.state.aksrtArchive) {
state = Object.assign(state, e.state.state);
updateActiveChips();
fetchPosts(false);
}
});
}
window.AksrtFrontend.register("aksrt-archive-filter", function () { initArchiveFilter(); });
})();
+226
View File
@@ -0,0 +1,226 @@
/**
* AKSRT Article Tools — password toggles, search clear, article actions, interaction bar
*/
(function () {
"use strict";
function initPasswordToggles(root) {
(root || document).querySelectorAll(".toggle-pwd").forEach(function (btn) {
if (btn.dataset.pwdToggleBound) return;
btn.dataset.pwdToggleBound = "1";
btn.addEventListener("click", function () {
var id = btn.getAttribute("data-target");
var input = id ? document.getElementById(id) : null;
if (!input) return;
var show = input.getAttribute("type") === "password";
input.setAttribute("type", show ? "text" : "password");
btn.setAttribute("aria-label", show ? "隐藏密码" : "显示密码");
});
});
}
function initSearchClear() {
var btn = document.getElementById("search-clear-btn");
var input = document.getElementById("search-page-input");
if (btn && input) {
var syncClearButton = function () {
var hasValue = input.value.trim().length > 0;
btn.classList.toggle("is-visible", hasValue);
btn.hidden = !hasValue;
};
btn.addEventListener("click", function () {
input.value = "";
input.focus();
syncClearButton();
});
input.addEventListener("input", syncClearButton);
syncClearButton();
}
var categorySelect = document.getElementById("search-category-filter");
if (categorySelect) {
categorySelect.addEventListener("change", function () {
var url = new URL(window.location.href);
if (this.value) {
url.searchParams.set("aksrt_category", this.value);
} else {
url.searchParams.delete("aksrt_category");
}
url.searchParams.delete("paged");
window.location.href = url.toString();
});
}
}
function showToast(msg, type) {
if (window.aksrt && aksrt.notyf) {
aksrt.notyf(msg, { type: type || "info", duration: 2200 });
} else {
console.log("[AKSRT Toast]", type, msg);
}
}
function initArticleTools() {
var buttons = document.querySelectorAll("[data-article-tool]");
if (!buttons.length) return;
buttons.forEach(function (button) {
button.addEventListener("click", function () {
var tool = button.getAttribute("data-article-tool");
if (tool === "print") {
window.print();
return;
}
if (tool === "pdf") {
window.print();
if (typeof showToast === "function") {
showToast("请在打印对话框中选择“另存为 PDF”", "info");
}
}
});
});
}
function getBaseStatCount(statName) {
var statEl = document.querySelector('[data-stat-count="' + statName + '"][data-base-count]');
return statEl ? (parseInt(statEl.dataset.baseCount, 10) || 0) : 0;
}
function updateStatCounts(statName, count) {
var safeCount = Math.max(0, count);
document.querySelectorAll('[data-stat-count="' + statName + '"]').forEach(function (statEl) {
statEl.textContent = String(safeCount);
});
}
function setBaseStatCount(statName, count) {
var safeCount = Math.max(0, count);
document.querySelectorAll('[data-stat-count="' + statName + '"][data-base-count]').forEach(function (statEl) {
statEl.dataset.baseCount = String(safeCount);
});
updateStatCounts(statName, safeCount);
}
function requestInteraction(actionName, postId, active) {
if (!window.aksrtData || !aksrtData.ajaxUrl || !aksrtData.nonce) {
return Promise.reject(new Error("互动服务未配置"));
}
var body = new URLSearchParams();
body.set("action", actionName);
body.set("nonce", aksrtData.nonce);
body.set("postId", String(postId));
body.set("active", active ? "1" : "0");
return fetch(aksrtData.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().catch(function () {
throw new Error("服务器返回无效响应");
});
}).then(function (payload) {
if (!payload || !payload.success) {
var message = payload && payload.data && payload.data.message ? payload.data.message : "请求失败";
throw new Error(message);
}
return payload.data || {};
});
}
function setButtonBusy(button, busy) {
button.disabled = !!busy;
button.classList.toggle("is-loading", !!busy);
}
function initInteractionBar(root) {
var scope = root || document;
var likeBtn = scope.getElementById("action-like");
var favBtn = scope.getElementById("action-favorite");
if (likeBtn && likeBtn.dataset.aksrtInteractionBound) return;
if (favBtn && favBtn.dataset.aksrtInteractionBound) return;
if (likeBtn) {
var likePostId = likeBtn.dataset.postId ? String(likeBtn.dataset.postId) : "";
function applyLikeState(isActive, count) {
likeBtn.dataset.initialActive = isActive ? "1" : "0";
likeBtn.classList.toggle("is-active", isActive);
var likeIcon = likeBtn.querySelector("i");
if (likeIcon) {
likeIcon.className = isActive ? "fas fa-heart" : "far fa-heart";
}
if ("number" === typeof count && !isNaN(count)) {
setBaseStatCount("likes", count);
} else {
updateStatCounts("likes", getBaseStatCount("likes"));
}
}
applyLikeState(likeBtn.dataset.initialActive === "1", getBaseStatCount("likes"));
likeBtn.addEventListener("click", function () {
if (!likePostId || likeBtn.disabled) return;
var nextState = likeBtn.dataset.initialActive !== "1";
setButtonBusy(likeBtn, true);
requestInteraction("aksrt_toggle_like", likePostId, nextState).then(function (data) {
applyLikeState(!!data.active, parseInt(data.count, 10) || 0);
showToast(data.active ? "感谢你的点赞" : "已取消点赞", "success");
}).catch(function (error) {
showToast(error && error.message ? error.message : "点赞失败", "error");
}).finally(function () {
setButtonBusy(likeBtn, false);
});
});
}
if (favBtn) {
var favoritePostId = favBtn.dataset.postId ? String(favBtn.dataset.postId) : "";
function applyFavoriteState(isActive, count) {
favBtn.dataset.initialActive = isActive ? "1" : "0";
favBtn.classList.toggle("is-active", isActive);
var favoriteIcon = favBtn.querySelector("i");
if (favoriteIcon) {
favoriteIcon.className = isActive ? "fas fa-star" : "far fa-star";
}
if ("number" === typeof count && !isNaN(count)) {
setBaseStatCount("favorites", count);
} else {
updateStatCounts("favorites", getBaseStatCount("favorites"));
}
}
applyFavoriteState(favBtn.dataset.initialActive === "1", getBaseStatCount("favorites"));
favBtn.addEventListener("click", function () {
if (!favoritePostId || favBtn.disabled) return;
var nextState = favBtn.dataset.initialActive !== "1";
setButtonBusy(favBtn, true);
requestInteraction("aksrt_toggle_favorite", favoritePostId, nextState).then(function (data) {
applyFavoriteState(!!data.active, parseInt(data.count, 10) || 0);
showToast(data.active ? "收藏成功" : "已取消收藏", "success");
}).catch(function (error) {
showToast(error && error.message ? error.message : "收藏失败", "error");
}).finally(function () {
setButtonBusy(favBtn, false);
});
});
}
if (likeBtn) likeBtn.dataset.aksrtInteractionBound = "1";
if (favBtn) favBtn.dataset.aksrtInteractionBound = "1";
}
window.AksrtFrontend.register("aksrt-search-clear", function () { initSearchClear(); });
window.AksrtFrontend.register("aksrt-article-tools", function () { initArticleTools(); });
window.AksrtFrontend.register("aksrt-password-toggles", function (root) { initPasswordToggles(root); });
window.AksrtFrontend.register("aksrt-interaction-bar", function (root) { initInteractionBar(root); });
})();
+622
View File
@@ -0,0 +1,622 @@
/**
* AKSRT Comment System — AJAX submit, captcha, ordering, author filter
*/
(function () {
"use strict";
function showToast(msg, type) {
if (window.aksrt && aksrt.notyf) {
aksrt.notyf(msg, { type: type || "info", duration: 2200 });
} else {
console.log("[AKSRT Toast]", type, msg);
}
}
function initCommentSystem() {
var form = document.querySelector("#commentform");
if (!form) return;
// 修复:同时匹配 button 和 input 元素
var submitBtn = form.querySelector('[type="submit"]');
if (!submitBtn) return;
var isInputSubmit = submitBtn.tagName === 'INPUT';
// 保存原始按钮内容(用于恢复)
var originalBtnHTML = isInputSubmit ? submitBtn.value : submitBtn.innerHTML;
function setSubmitBtnContent(html, textFallback) {
if (isInputSubmit) {
submitBtn.value = textFallback;
} else {
submitBtn.innerHTML = html;
}
}
// 状态管理
var isSubmitting = false;
var countdownTimer = null;
// 显示/隐藏加载状态
function setLoading(loading) {
if (loading) {
isSubmitting = true;
submitBtn.classList.add("is-loading");
submitBtn.disabled = true;
var loadingText = (window.aksrtData && aksrtData.commentSubmittingText) || '发送中...';
setSubmitBtnContent('<i class="fas fa-circle-notch fa-spin"></i> ' + loadingText, loadingText);
} else {
isSubmitting = false;
submitBtn.classList.remove("is-loading");
submitBtn.classList.remove('countdown-active');
submitBtn.disabled = false;
setSubmitBtnContent(originalBtnHTML, originalBtnHTML);
}
}
// 收集表单数据(包含验证码字段)
function collectFormData() {
var formData = new FormData(form);
// 确保包含必要的隐藏字段
var postId = document.querySelector('input[name="comment_post_ID"]');
if (postId && !formData.get('comment_post_ID')) {
formData.append('comment_post_ID', postId.value);
}
return formData;
}
// 从 wp_die() HTML 中提取错误信息
function extractErrorMessage(html) {
// WordPress wp_die() 输出格式: <p>错误信息</p>
var match = html.match(/<p[^>]*>([^<]+)<\/p>/i);
return match ? match[1].trim() : '未知错误';
}
// 从错误消息中提取等待时间(秒)
function extractWaitTime(msg) {
var match = msg.match(/(\d+)\s*秒/);
return match ? parseInt(match[1]) : 0;
}
// 启动倒计时(用于频率限制)
function startCountdown(seconds) {
if (countdownTimer) clearInterval(countdownTimer);
submitBtn.classList.add('countdown-active');
submitBtn.disabled = true;
var remaining = seconds;
countdownTimer = setInterval(function () {
setSubmitBtnContent(
'<i class="fas fa-clock"></i> 请等待 ' + remaining + 's',
'请等待 ' + remaining + 's'
);
if (--remaining <= 0) {
clearInterval(countdownTimer);
countdownTimer = null;
submitBtn.classList.remove('countdown-active', 'is-loading');
submitBtn.disabled = false;
setSubmitBtnContent(originalBtnHTML, originalBtnHTML);
isSubmitting = false;
}
}, 1000);
}
function updateCommentCount(delta) {
var countEl = document.querySelector('.comments-count');
if (!countEl) return;
var text = countEl.textContent || '';
var match = text.match(/(\d+)/);
if (!match) return;
var nextCount = Math.max(0, parseInt(match[1], 10) + delta);
countEl.textContent = '共 ' + nextCount + ' 条';
}
function handleResponse(responseText, statusCode) {
try {
// 情况1: 成功提交 - 包含评论ID或成功标记
if (statusCode === 200 || statusCode === 201) {
if (responseText.includes('comment-submitted') ||
responseText.indexOf('id="comment-') !== -1 ||
responseText.indexOf('awaiting-moderation') !== -1) {
// 区分是否需要审核
if (responseText.indexOf('审核') !== -1 ||
responseText.indexOf('moderation') !== -1 ||
responseText.includes('awaiting-moderation')) {
showToast('评论已提交,等待管理员审核', 'info');
} else {
showToast('评论发布成功', 'success');
}
// 清空文本框
var textarea = form.querySelector('#comment');
if (textarea) textarea.value = '';
// 重置回复状态
var replyInfo = document.getElementById('comment-reply-info');
if (replyInfo) replyInfo.style.display = 'none';
// 刷新评论列表(延迟执行,确保后端处理完成)
setTimeout(function () {
reloadCommentList();
}, 500);
setLoading(false);
return true;
}
}
// 情况2: HTTP 429 频率限制
if (statusCode === 429) {
var errorMsg = extractErrorMessage(responseText);
var waitSeconds = extractWaitTime(errorMsg);
showToast(errorMsg, 'warning');
if (waitSeconds > 0) {
startCountdown(waitSeconds);
} else {
setLoading(false); // 无具体等待时间时恢复按钮
}
return false;
}
// 情况3: HTTP 403 权限不足(地区/IP/关键词等)
if (statusCode === 403) {
var forbiddenMsg = extractErrorMessage(responseText);
showToast(forbiddenMsg, 'error');
setLoading(false);
return false;
}
// 情况4: 包含WordPress错误信息
var errorMatch = responseText.match(/<p[^>]*>([^<]*(?:错误|失败|error|Error)[^<]*)<\/p>/i);
if (errorMatch) {
showToast(errorMatch[1].trim(), 'error');
setLoading(false);
return false;
}
// 默认情况:可能是成功或其他
showToast('评论已提交', 'success');
var textarea2 = form.querySelector('#comment');
if (textarea2) textarea2.value = '';
// 局部刷新评论列表(不再整页 reload)
setTimeout(function () {
reloadCommentList();
}, 500);
setLoading(false);
return true;
} catch (e) {
console.error('[AKSRT Comment] 解析响应失败:', e);
showToast('响应解析异常,请重试', 'error');
setLoading(false);
return false;
}
}
// 执行实际的 AJAX 请求 — local insert instead of full-page re-fetch
function performSubmit() {
setLoading(true);
var formData = collectFormData();
var restBase = '/wp-json/aksrt/v1/comment/submit';
// Try REST endpoint for local-insert HTML response
var restBody = {};
formData.forEach(function (v, k) { restBody[k] = v; });
fetch(restBase, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': (window.aksrtData && aksrtData.restNonce) || ''
},
credentials: 'same-origin',
body: JSON.stringify(restBody)
})
.then(function (r) { return r.json(); })
.then(function (json) {
if (json && json.success && json.html) {
// Local insert: prepend new comment HTML
localInsertComment(json.html, json.is_reply, json.parent_id, json.needs_moderation);
var textarea = form.querySelector('#comment');
if (textarea) textarea.value = '';
var replyInfo = document.getElementById('comment-reply-info');
if (replyInfo) replyInfo.style.display = 'none';
// Reset captcha
var captchaImg = form.querySelector('.imagecaptcha img');
if (captchaImg) captchaImg.click();
// Wait time countdown
if (json.wait_time && json.wait_time > 0) {
startCountdown(json.wait_time);
} else {
setLoading(false);
}
// Move respond back to original position
restoreRespondPosition();
return;
}
if (json && json.code) {
showToast(json.message || '评论提交失败', 'error');
if (json.wait_time) startCountdown(json.wait_time);
else setLoading(false);
return;
}
showToast('评论已提交', 'success');
setLoading(false);
setTimeout(function () { reloadCommentList(); }, 500);
})
.catch(function () {
// Fallback: submit to wp-comments-post.php directly
performLegacySubmit();
});
}
function localInsertComment(html, isReply, parentId, needsModeration) {
var temp = document.createElement('div');
temp.innerHTML = html;
var newComment = temp.firstElementChild;
if (!newComment) { reloadCommentList(); return; }
newComment.style.overflow = 'hidden';
newComment.style.maxHeight = '0';
newComment.style.opacity = '0';
newComment.style.transition = 'max-height 0.4s ease, opacity 0.3s ease';
if (isReply && parentId) {
var parentComment = document.querySelector('#comment-' + parentId + ', [data-comment-id="' + parentId + '"]');
if (parentComment) {
var children = parentComment.querySelector('.children');
if (!children) {
children = document.createElement('ol');
children.className = 'children';
parentComment.appendChild(children);
}
children.insertBefore(newComment, children.firstChild);
} else {
prependToCommentList(newComment);
}
} else {
prependToCommentList(newComment);
}
// slideDown animation
requestAnimationFrame(function () {
newComment.style.maxHeight = newComment.scrollHeight + 100 + 'px';
newComment.style.opacity = '1';
setTimeout(function () {
newComment.style.maxHeight = '';
newComment.style.overflow = '';
newComment.style.transition = '';
}, 500);
});
if (needsModeration) {
showToast('评论已提交,等待管理员审核', 'info');
} else {
showToast('评论发布成功', 'success');
}
if (window.AksrtFrontend) AksrtFrontend.rehydrate(newComment, 'ajax');
updateCommentCount(1);
}
function prependToCommentList(el) {
var list = document.querySelector('.commentlist, #comment-list > ol, #comment-list');
if (list) list.insertBefore(el, list.firstChild);
}
function restoreRespondPosition() {
var respond = document.getElementById('respond');
var placeholder = document.getElementById('wp-temp-form-div');
if (respond && placeholder && placeholder.parentNode) {
placeholder.parentNode.insertBefore(respond, placeholder);
placeholder.remove();
}
}
// Legacy fallback: POST to wp-comments-post.php
function performLegacySubmit() {
var formData = collectFormData();
var actionUrl = form.getAttribute('action') || '/wp-comments-post.php';
fetch(actionUrl, {
method: 'POST',
body: formData,
credentials: 'same-origin',
headers: { 'X-Requested-With': 'XMLHttpRequest' }
})
.then(function (response) {
return response.text().then(function (text) {
return { status: response.status, text: text, ok: response.ok };
});
})
.then(function (result) {
handleResponse(result.text, result.status);
})
.catch(function (error) {
console.error('[AKSRT Comment] 提交失败:', error);
if (error.message === 'Failed to fetch' || error.name === 'TypeError') {
showToast('网络连接失败,请检查网络后重试', 'error');
} else {
showToast(error.message || '评论提交失败,请重试', 'error');
}
setLoading(false);
})
.finally(function () {
// 兜底:避免异常分支漏掉状态恢复导致按钮卡在"发送中"
if (!countdownTimer && isSubmitting) {
setLoading(false);
}
});
}
// 核心表单提交事件处理器
function handleSubmit(e) {
// 如果已经在提交中或倒计时中,防止重复提交
if (isSubmitting || countdownTimer) {
e.preventDefault();
e.stopImmediatePropagation();
return false;
}
// 阻止默认表单提交
e.preventDefault();
e.stopImmediatePropagation();
// 检查验证码状态(如果有验证码组件)
var captchaScene = window.AKSRTCaptchaState &&
window.AKSRTCaptchaState.scenes &&
window.AKSRTCaptchaState.scenes.comment;
if (captchaScene && typeof captchaScene.verify === 'function') {
// 有验证码:先触发验证流程
setLoading(true);
captchaScene.verify(function (verified) {
if (verified !== false) {
// 验证通过,执行 AJAX 提交
performSubmit();
} else {
// 验证失败
showToast('人机验证未通过,请重试', 'warning');
setLoading(false);
}
});
} else {
// 无验证码或已经验证过:直接提交
performSubmit();
}
return false;
}
// 绑定表单提交事件(使用捕获阶段,高优先级)
form.addEventListener('submit', handleSubmit, true);
}
/* ====== 评论列表动态刷新 ====== */
function reloadCommentList() {
var listContainer = document.getElementById('comment-list');
if (!listContainer) {
// 降级:整页刷新
window.location.reload();
return;
}
var postIdInput = document.querySelector('input[name="comment_post_ID"]');
if (!postIdInput) return;
// 显示骨架屏加载效果
listContainer.innerHTML = '<li class="comment-loading-skeleton">' +
'<div class="aksrt-comment"><div class="aksrt-comment__body">' +
'<div style="height:60px;background:#f0f0f0;border-radius:8px;margin-bottom:10px;animation:pulse 1.5s ease-in-out infinite;"></div>' +
'<div style="height:20px;width:70%;background:#f0f0f0;border-radius:4px;animation:pulse 1.5s ease-in-out infinite;"></div>' +
'</div></div></li>';
// 获取当前页面 URL(带时间戳避免缓存)
var currentUrl = window.location.href.split('#')[0];
var bustUrl = currentUrl + (currentUrl.indexOf('?') === -1 ? '?' : '&') + '_cache_bust=' + Date.now();
fetch(bustUrl, {
method: 'GET',
credentials: 'same-origin'
})
.then(function (response) { return response.text(); })
.then(function (html) {
// 从新页面提取评论列表
var parser = new DOMParser();
var doc = parser.parseFromString(html, 'text/html');
var newList = doc.getElementById('comment-list');
if (newList && newList.innerHTML.trim()) {
listContainer.innerHTML = newList.innerHTML;
// 更新评论计数
var countEl = document.querySelector('.comments-count');
var newCountEl = doc.querySelector('.comments-count');
if (countEl && newCountEl) {
countEl.textContent = newCountEl.textContent;
}
} else {
listContainer.innerHTML = '';
}
})
.catch(function (error) {
console.error('[AKSRT Comment] 刷新评论列表失败:', error);
// 失败时降级为整页刷新
window.location.reload();
});
}
/* ====== 评论排序(最新 / 最早) ====== */
function initCommentOrder(root) {
var scope = root || document;
var commentsArea = scope.getElementById("comments");
if (!commentsArea) return;
if (commentsArea.dataset.orderInit === "1") return;
commentsArea.dataset.orderInit = "1";
function getPaginationEl(root) {
if (!root) return null;
return root.querySelector(".aksrt-comment-pagination, .comment-navigation");
}
function renderLoadingState() {
var listContainer = commentsArea.querySelector("#comment-list");
if (!listContainer) return;
listContainer.innerHTML = '<li class="comment-loading-skeleton">' +
'<div class="aksrt-comment"><div class="aksrt-comment__body">' +
'<div style="height:60px;background:#f0f0f0;border-radius:8px;margin-bottom:10px;animation:pulse 1.5s ease-in-out infinite;"></div>' +
'<div style="height:20px;width:70%;background:#f0f0f0;border-radius:4px;animation:pulse 1.5s ease-in-out infinite;"></div>' +
'</div></div></li>';
}
function applyCommentOrder(order) {
if (order !== "newest" && order !== "oldest" && order !== "hottest") {
order = "newest";
}
renderLoadingState();
var url = new URL(window.location.href);
url.searchParams.set("aksrt_comment_order", order);
url.searchParams.delete("cpage");
var fetchUrl = new URL(url.toString());
fetchUrl.searchParams.set("_cache_bust", Date.now().toString());
fetch(fetchUrl.toString(), {
method: "GET",
credentials: "same-origin"
})
.then(function (response) { return response.text(); })
.then(function (html) {
var parser = new DOMParser();
var doc = parser.parseFromString(html, "text/html");
var newComments = doc.getElementById("comments");
if (!newComments) {
throw new Error("new comments area not found");
}
var currentFilter = commentsArea.querySelector(".comment-filter");
var newFilter = newComments.querySelector(".comment-filter");
if (currentFilter && newFilter) {
currentFilter.replaceWith(newFilter.cloneNode(true));
}
var currentList = commentsArea.querySelector("#comment-list");
var newList = newComments.querySelector("#comment-list");
if (currentList && newList) {
currentList.replaceWith(newList.cloneNode(true));
}
var currentPagination = getPaginationEl(commentsArea);
var newPagination = getPaginationEl(newComments);
if (currentPagination && newPagination) {
currentPagination.replaceWith(newPagination.cloneNode(true));
} else if (currentPagination && !newPagination) {
currentPagination.remove();
} else if (!currentPagination && newPagination) {
var list = commentsArea.querySelector("#comment-list");
if (list && list.parentNode) {
list.parentNode.insertBefore(newPagination.cloneNode(true), list.nextSibling);
}
}
var currentCount = commentsArea.querySelector(".comments-count");
var newCount = newComments.querySelector(".comments-count");
if (currentCount && newCount) {
currentCount.textContent = newCount.textContent;
}
if (window.history && typeof window.history.replaceState === "function") {
window.history.replaceState(null, "", url.toString());
}
if (window.AksrtFrontend) AksrtFrontend.rehydrate(commentsArea, 'ajax');
})
.catch(function (error) {
console.error("[AKSRT Comment] 排序刷新失败:", error);
window.location.href = url.toString();
});
}
commentsArea.addEventListener("click", function (e) {
var link = e.target.closest(".comment-orderby");
if (link && commentsArea.contains(link)) {
e.preventDefault();
var order = (link.dataset && link.dataset.order) ? link.dataset.order : "newest";
applyCommentOrder(order);
return;
}
var authorLink = e.target.closest(".comment-author-filter");
if (authorLink && commentsArea.contains(authorLink)) {
e.preventDefault();
var authorOnly = (authorLink.dataset && authorLink.dataset.authorOnly) ? authorLink.dataset.authorOnly : "1";
applyAuthorFilter(authorOnly);
}
});
function applyAuthorFilter(authorOnly) {
renderLoadingState();
var url = new URL(window.location.href);
if (authorOnly === "1") {
url.searchParams.set("aksrt_author_only", "1");
} else {
url.searchParams.delete("aksrt_author_only");
}
url.searchParams.delete("cpage");
var fetchUrl = new URL(url.toString());
fetchUrl.searchParams.set("_cache_bust", Date.now().toString());
fetch(fetchUrl.toString(), {
method: "GET",
credentials: "same-origin"
})
.then(function (response) { return response.text(); })
.then(function (html) {
var parser = new DOMParser();
var doc = parser.parseFromString(html, "text/html");
var newComments = doc.getElementById("comments");
if (!newComments) {
throw new Error("new comments area not found");
}
var currentFilter = commentsArea.querySelector(".comment-filter");
var newFilter = newComments.querySelector(".comment-filter");
if (currentFilter && newFilter) {
currentFilter.replaceWith(newFilter.cloneNode(true));
}
var currentList = commentsArea.querySelector("#comment-list");
var newList = newComments.querySelector("#comment-list");
if (currentList && newList) {
currentList.replaceWith(newList.cloneNode(true));
}
if (window.history && typeof window.history.replaceState === "function") {
window.history.replaceState(null, "", url.toString());
}
if (window.AksrtFrontend) AksrtFrontend.rehydrate(commentsArea, 'ajax');
})
.catch(function (error) {
console.error("[AKSRT Comment] Author filter failed:", error);
window.location.href = url.toString();
});
}
}
window.AksrtFrontend.register("aksrt-comment-system", function () { initCommentSystem(); });
window.AksrtFrontend.register("aksrt-comment-order", function (root) { initCommentOrder(root); });
})();
+109
View File
@@ -0,0 +1,109 @@
/**
* AKSRT Dropdown Menus — user, auth, post-meta
*/
(function () {
"use strict";
function initUserDropdown() {
var toggle = document.getElementById("user-menu-toggle");
var menu = document.getElementById("user-dropdown");
if (!toggle || !menu) return;
function close() {
menu.classList.remove("is-open");
toggle.setAttribute("aria-expanded", "false");
}
toggle.addEventListener("click", function (e) {
e.stopPropagation();
var open = !menu.classList.contains("is-open");
menu.classList.toggle("is-open", open);
toggle.setAttribute("aria-expanded", open ? "true" : "false");
});
document.addEventListener("click", function (e) {
if (!menu.contains(e.target) && e.target !== toggle) close();
});
document.addEventListener("touchstart", function (e) {
if (!menu.contains(e.target) && e.target !== toggle) close();
}, { passive: true });
document.addEventListener("keydown", function (e) {
if (e.key === "Escape") close();
});
}
function initAuthDropdown() {
var trigger = document.getElementById("nav-auth-trigger");
var container = document.getElementById("nav-auth-dropdown");
if (!trigger || !container) return;
function close() {
container.classList.remove("is-open");
trigger.setAttribute("aria-expanded", "false");
}
trigger.addEventListener("click", function (e) {
e.stopPropagation();
var open = !container.classList.contains("is-open");
container.classList.toggle("is-open", open);
trigger.setAttribute("aria-expanded", open ? "true" : "false");
});
document.addEventListener("click", function (e) {
if (!container.contains(e.target) && e.target !== trigger) close();
});
document.addEventListener("touchstart", function (e) {
if (!container.contains(e.target) && e.target !== trigger) close();
}, { passive: true });
document.addEventListener("keydown", function (e) {
if (e.key === "Escape") close();
});
}
function initPostDropMeta() {
document.querySelectorAll('.post-drop-meta').forEach(function (wrap) {
if (!wrap || wrap.dataset.aksrtDropMetaBound === '1') return;
var trigger = wrap.querySelector('.post-drop-meta__toggle');
var menu = wrap.querySelector('.post-drop-meta__menu');
if (!trigger || !menu) return;
wrap.dataset.aksrtDropMetaBound = '1';
function close() {
wrap.classList.remove('is-open');
trigger.setAttribute('aria-expanded', 'false');
menu.setAttribute('aria-hidden', 'true');
}
trigger.addEventListener('click', function (e) {
e.stopPropagation();
var open = !wrap.classList.contains('is-open');
document.querySelectorAll('.post-drop-meta.is-open').forEach(function (other) {
if (other !== wrap) {
other.classList.remove('is-open');
var otherTrigger = other.querySelector('.post-drop-meta__toggle');
var otherMenu = other.querySelector('.post-drop-meta__menu');
if (otherTrigger) otherTrigger.setAttribute('aria-expanded', 'false');
if (otherMenu) otherMenu.setAttribute('aria-hidden', 'true');
}
});
wrap.classList.toggle('is-open', open);
trigger.setAttribute('aria-expanded', open ? 'true' : 'false');
menu.setAttribute('aria-hidden', open ? 'false' : 'true');
});
document.addEventListener('click', function (e) {
if (!wrap.contains(e.target)) close();
});
document.addEventListener('touchstart', function (e) {
if (!wrap.contains(e.target)) close();
}, { passive: true });
document.addEventListener('keydown', function (e) {
if (e.key === 'Escape') close();
});
});
}
window.AksrtFrontend.register("aksrt-user-dropdown", function () { initUserDropdown(); });
window.AksrtFrontend.register("aksrt-auth-dropdown", function () { initAuthDropdown(); });
window.AksrtFrontend.register("aksrt-post-drop-meta", function () { initPostDropMeta(); });
})();
+140
View File
@@ -0,0 +1,140 @@
/**
* AKSRT Footer Tabbar
*/
(function () {
"use strict";
function initFooterTabbar() {
var tabbar = document.getElementById("footer-tabbar");
if (!tabbar) return;
var addBackdrop = document.getElementById("tabbar-add-backdrop");
var ticking = false;
var scrollThreshold = 100;
var isHidden = false;
// Use body scroll bus classes from aksrt-runtime.js
function handleScrollDownHide() {
var body = document.body;
var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
if (scrollTop > scrollThreshold) {
if (body.classList.contains("scroll-down") && !isHidden) {
// 向下滚动 - 隐藏
tabbar.classList.add("is-hidden");
isHidden = true;
} else if (body.classList.contains("scroll-up") && isHidden) {
tabbar.classList.remove("is-hidden");
isHidden = false;
}
} else {
tabbar.classList.remove("is-hidden");
isHidden = false;
}
}
// 返回顶部按钮切换
function handleOntopWrap() {
var ontopWraps = tabbar.querySelectorAll(".tabbar-ontop-wrap");
var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
ontopWraps.forEach(function (wrap) {
if (scrollTop > scrollThreshold) {
wrap.classList.add("is-scrolled");
} else {
wrap.classList.remove("is-scrolled");
}
});
}
// 滚动事件处理
function onScroll() {
if (!ticking) {
requestAnimationFrame(function () {
if (tabbar.classList.contains("scroll-down-hide")) {
handleScrollDownHide();
}
handleOntopWrap();
ticking = false;
});
ticking = true;
}
}
window.addEventListener("scroll", onScroll, { passive: true });
function closeAddPanels() {
document.querySelectorAll(".tabbar-add-panel").forEach(function (panel) {
panel.setAttribute("hidden", "");
});
if (addBackdrop) addBackdrop.setAttribute("hidden", "");
document.body.classList.remove("tabbar-add-open");
}
function openAddPanel(panelId) {
closeAddPanels();
var panel = document.getElementById(panelId);
if (!panel) return;
panel.removeAttribute("hidden");
if (addBackdrop) addBackdrop.removeAttribute("hidden");
document.body.classList.add("tabbar-add-open");
}
if (addBackdrop) {
addBackdrop.addEventListener("click", closeAddPanels);
}
document.addEventListener("keydown", function (e) {
if (e.key === "Escape") closeAddPanels();
});
// 返回顶部点击事件 + 双击首页刷新
var homeClickTimer = null;
tabbar.addEventListener("click", function (e) {
var addBtn = e.target.closest('.tabbar-item[data-type="add"]');
if (addBtn) {
e.preventDefault();
openAddPanel(addBtn.getAttribute("data-panel-id"));
return;
}
var searchBtn = e.target.closest('.tabbar-item[data-type="search"]');
if (searchBtn) {
e.preventDefault();
if (typeof window.__aksrtOpenSearchPanel === "function") {
window.__aksrtOpenSearchPanel();
}
return;
}
var ontopBtn = e.target.closest(".tabbar-ontop-btn");
if (ontopBtn) {
e.preventDefault();
window.scrollTo({ top: 0, behavior: "smooth" });
return;
}
// 双击首页Tab刷新页面
var homeBtn = e.target.closest('.tabbar-item[data-type="home"]');
if (homeBtn && tabbar.classList.contains("has-animation")) {
if (homeClickTimer) {
clearTimeout(homeClickTimer);
homeClickTimer = null;
window.location.reload();
return;
}
homeClickTimer = setTimeout(function () {
homeClickTimer = null;
}, 350);
}
});
document.addEventListener("click", function (e) {
if (e.target.closest("[data-close-tabbar-add-panel]")) {
closeAddPanels();
}
});
}
window.AksrtFrontend.register("aksrt-footer-tabbar", function () { initFooterTabbar(); });
})();
+144
View File
@@ -0,0 +1,144 @@
/**
* AKSRT Misc — related swiper, slide covers, hidden content
*/
(function () {
"use strict";
function initRelatedSwiper() {
var el = document.querySelector(".related-swiper[data-swiper-config]");
if (!el || typeof Swiper === "undefined") return;
var config = {};
try { config = JSON.parse(el.dataset.swiperConfig || "{}"); } catch (e) {}
new Swiper(el, Object.assign({
slidesPerView: "auto",
spaceBetween: 12,
freeMode: true,
navigation: {
nextEl: ".related-swiper-next",
prevEl: ".related-swiper-prev",
},
}, config));
}
window.AksrtFrontend.register("aksrt-related-swiper", function () { initRelatedSwiper(); });
})();
(function () {
"use strict";
function initSlideCovers() {
var covers = document.querySelectorAll(".single-cover--slide");
covers.forEach(function (cover) {
var slides = cover.querySelectorAll(".single-cover__slide");
var dots = cover.querySelectorAll(".single-cover__dot");
if (slides.length < 2) return;
var current = 0;
var interval = 5000;
function goTo(idx) {
slides[current].classList.remove("is-active");
if (dots[current]) dots[current].classList.remove("is-active");
current = idx;
slides[current].classList.add("is-active");
if (dots[current]) dots[current].classList.add("is-active");
}
var timer = setInterval(function () {
goTo((current + 1) % slides.length);
}, interval);
dots.forEach(function (dot, i) {
dot.addEventListener("click", function () {
clearInterval(timer);
goTo(i);
timer = setInterval(function () {
goTo((current + 1) % slides.length);
}, interval);
});
});
});
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initSlideCovers);
} else {
initSlideCovers();
}
})();
(function () {
"use strict";
function initHiddenContent() {
document.addEventListener("click", function (e) {
var btn = e.target.closest(".aksrt-hidden-content__submit-btn");
if (!btn) return;
e.preventDefault();
var wrapper = btn.closest(".aksrt-hidden-content--locked");
if (!wrapper) return;
var mode = wrapper.getAttribute("data-aksrt-visibility-mode");
var pid = wrapper.getAttribute("data-aksrt-visibility-pid");
var input = wrapper.querySelector(".aksrt-hidden-content__password-input");
var password = input ? input.value.trim() : "";
if (mode === "password" && !password) {
if (input) input.focus();
return;
}
var formData = new FormData();
formData.append("action", "aksrt_check_visibility");
formData.append("_nonce", (window.aksrtData && aksrtData.visibilityNonce) || "");
formData.append("mode", mode);
formData.append("pid", pid);
if (password) formData.append("password", password);
btn.disabled = true;
btn.textContent = "...";
fetch((window.aksrtData && aksrtData.ajaxUrl) || "/wp-admin/admin-ajax.php", {
method: "POST",
body: formData,
credentials: "same-origin",
})
.then(function (res) { return res.json(); })
.then(function (data) {
if (data.success) {
window.location.reload();
} else {
var msg = (data.data && data.data.message) ? data.data.message : "验证失败";
alert(msg);
btn.disabled = false;
btn.textContent = "验证";
}
})
.catch(function () {
alert("网络错误,请重试");
btn.disabled = false;
btn.textContent = "验证";
});
});
// Handle Enter key on password input
document.addEventListener("keydown", function (e) {
if (e.key === "Enter" && e.target.classList.contains("aksrt-hidden-content__password-input")) {
e.preventDefault();
var wrapper = e.target.closest(".aksrt-hidden-content--locked");
if (wrapper) {
var btn = wrapper.querySelector(".aksrt-hidden-content__submit-btn");
if (btn) btn.click();
}
}
});
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initHiddenContent);
} else {
initHiddenContent();
}
})();
+54
View File
@@ -0,0 +1,54 @@
/**
* AKSRT Navigation Drawer
*/
(function () {
"use strict";
function initNavDrawer() {
var toggle = document.getElementById("nav-toggle");
var drawer = document.getElementById("nav-drawer");
var backdrop = document.getElementById("nav-drawer-backdrop");
var closeBtn = document.getElementById("nav-drawer-close");
if (!toggle || !drawer || !backdrop) return;
var openIcon = toggle.querySelector(".nav-toggle-open");
var closeIcon = toggle.querySelector(".nav-toggle-close");
function setOpen(open) {
toggle.setAttribute("aria-expanded", open ? "true" : "false");
drawer.classList.toggle("is-open", open);
backdrop.classList.toggle("is-open", open);
drawer.setAttribute("aria-hidden", open ? "false" : "true");
backdrop.setAttribute("aria-hidden", open ? "false" : "true");
document.body.style.overflow = open ? "hidden" : "";
if (openIcon && closeIcon) {
openIcon.style.display = open ? "none" : "";
closeIcon.style.display = open ? "" : "none";
}
if (open && typeof window.__aksrtCloseSearchPanel === "function") {
window.__aksrtCloseSearchPanel();
}
}
setOpen(false);
toggle.addEventListener("click", function () {
setOpen(!drawer.classList.contains("is-open"));
});
backdrop.addEventListener("click", function () {
setOpen(false);
});
if (closeBtn) closeBtn.addEventListener("click", function () {
setOpen(false);
});
document.addEventListener("keydown", function (e) {
if (e.key === "Escape" && drawer.classList.contains("is-open")) {
setOpen(false);
toggle.focus();
}
});
}
window.AksrtFrontend.register("aksrt-nav-drawer", function () { initNavDrawer(); });
})();
+270
View File
@@ -0,0 +1,270 @@
/**
* AKSRT AJAX Pagination & Lazy Load
*/
(function () {
"use strict";
function initAjaxPagination(root) {
var containers = (root || document).querySelectorAll(".aksrt-pagination-ajax, .ajax-pagination");
if (!containers.length) return;
var triggerText = (window.aksrtData && aksrtData.ajaxTrigger) || "加载更多";
var nomoreText = (window.aksrtData && aksrtData.ajaxNomore) || "没有更多了";
var loadingText = (window.aksrtData && aksrtData.ajaxLoading) || "正在加载...";
containers.forEach(function (container) {
if (container.dataset.aksrtPaginationBound === "1") return;
container.dataset.aksrtPaginationBound = "1";
var mode = container.dataset.mode || "load_more";
var nextPage = parseInt(container.dataset.nextPage, 10) || 2;
var maxPages = parseInt(container.dataset.maxPages, 10) || 1;
var isComment = container.classList.contains("aksrt-comment-pagination");
var postId = container.dataset.postId || "";
var commentOrder = container.dataset.commentOrder || "newest";
var loading = false;
var loadMoreBtn = container.querySelector(".aksrt-load-more-btn, .ajax-next");
var indicator = container.querySelector(".aksrt-loading-indicator");
// 目标容器:文章列表取 .post-grid,评论取 .comment-list
var target = container.previousElementSibling;
function showSkeleton() {
if (!target) return;
var loader = target.querySelector(".post-ajax-loader");
if (loader) {
loader.classList.add("is-loading");
}
}
function hideSkeleton() {
if (!target) return;
var loader = target.querySelector(".post-ajax-loader");
if (loader) {
loader.classList.remove("is-loading");
}
}
function loadNextPage() {
if (loading || nextPage > maxPages || !target) return;
loading = true;
if (indicator) indicator.style.display = "flex";
if (loadMoreBtn) {
loadMoreBtn.classList.add("is-loading");
loadMoreBtn.textContent = loadingText;
}
showSkeleton();
var action = isComment ? "aksrt_load_more_comments" : "aksrt_load_more_posts";
var queryContext = container.dataset.queryContext || "";
var queryVars = container.dataset.queryVars || "";
var renderConfig = container.dataset.renderConfig || "";
var body = new URLSearchParams();
body.set("action", action);
body.set("nonce", aksrtData.nonce);
body.set("page", String(nextPage));
if (queryContext) {
body.set("query_context", queryContext);
}
if (!isComment && queryVars) {
body.set("query_vars", queryVars);
}
if (!isComment && renderConfig) {
body.set("render_config", renderConfig);
}
if (isComment && postId) {
body.set("post_id", postId);
body.set("comment_order", commentOrder);
}
fetch(aksrtData.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.success && res.data && res.data.html) {
var temp = document.createElement("div");
temp.innerHTML = res.data.html;
var newItems = temp.children;
while (newItems.length > 0) {
target.appendChild(newItems[0]);
}
nextPage++;
container.dataset.nextPage = String(nextPage);
// 重新初始化懒加载(新加载的图片)
if (typeof initLazyLoad === "function") initLazyLoad();
// 如果没有更多页
if (nextPage > maxPages || !res.data.has_more) {
if (loadMoreBtn) {
loadMoreBtn.textContent = nomoreText;
loadMoreBtn.classList.remove("is-loading");
loadMoreBtn.classList.add("ajax-nomore");
loadMoreBtn.style.pointerEvents = "none";
} else {
container.innerHTML = '<span class="ajax-nomore">' + nomoreText + '</span>';
}
}
}
})
.catch(function () {})
.finally(function () {
loading = false;
hideSkeleton();
if (indicator) indicator.style.display = "none";
if (loadMoreBtn && !loadMoreBtn.classList.contains("ajax-nomore")) {
loadMoreBtn.classList.remove("is-loading");
loadMoreBtn.textContent = triggerText;
}
});
}
// 加载更多按钮点击
if (loadMoreBtn) {
loadMoreBtn.addEventListener("click", function(e) {
e.preventDefault();
if (loadMoreBtn.dataset.jumpComments === "1") {
var jumpInput = container.querySelector(".jump-input");
if (!jumpInput) return;
var targetPage = parseInt(jumpInput.value, 10) || 1;
var max = parseInt(jumpInput.dataset.maxPages || String(maxPages), 10) || maxPages;
targetPage = Math.max(1, Math.min(max, targetPage));
var url = new URL(window.location.href);
url.searchParams.set("cpage", String(targetPage));
window.location.href = url.toString();
return;
}
if (loadMoreBtn.dataset.jumpArchive === "1") {
var archiveJumpInput = container.querySelector(".jump-input");
if (!archiveJumpInput) return;
var archiveTargetPage = parseInt(archiveJumpInput.value, 10) || 1;
var archiveMax = parseInt(archiveJumpInput.dataset.maxPages || String(maxPages), 10) || maxPages;
archiveTargetPage = Math.max(1, Math.min(archiveMax, archiveTargetPage));
var archiveUrl = new URL(window.location.href);
archiveUrl.searchParams.set("paged", String(archiveTargetPage));
window.location.href = archiveUrl.toString();
return;
}
loadNextPage();
});
}
// 无限滚动:IntersectionObserver
if (mode === "infinite" && "IntersectionObserver" in window) {
// Comment containers respect commentIasAuto; if disabled, fall back to click-to-load
if (isComment && window.aksrtData && aksrtData.commentIasAuto === false) {
// Skip IntersectionObserver — load_more button already present
} else {
var sentinel = document.createElement("div");
sentinel.className = "aksrt-scroll-sentinel";
container.appendChild(sentinel);
var lazyloadAction = container.dataset.lazyloadAction || "";
var iasMax = isComment
? ((window.aksrtData && typeof aksrtData.commentIasMax !== "undefined") ? parseInt(aksrtData.commentIasMax, 10) : 0)
: ((window.aksrtData && typeof aksrtData.iasMax !== "undefined") ? parseInt(aksrtData.iasMax, 10) : 0);
var initialPage = nextPage - 1; // page at init time
var observer = new IntersectionObserver(
function (entries) {
if (entries[0].isIntersecting && !loading) {
// iasMax = 0 means unlimited, otherwise limit additional pages
if (iasMax > 0 && (nextPage - initialPage) >= iasMax) {
// Reached ias max, show nomore and disconnect
observer.disconnect();
if (loadMoreBtn) {
loadMoreBtn.textContent = nomoreText;
loadMoreBtn.classList.add("ajax-nomore");
loadMoreBtn.style.pointerEvents = "none";
}
return;
}
loadNextPage();
}
},
{ rootMargin: "400px" }
);
if (lazyloadAction === "ias") {
container.classList.add("ias-pending");
}
observer.observe(sentinel);
}
}
});
}
/* ====== 图片懒加载 ====== */
function initLazyLoad(root) {
var scope = root || document;
var lazyImages = scope.querySelectorAll("img.aksrt-lazy");
if (!lazyImages.length) return;
// 不支持 IntersectionObserver 时直接加载所有图片
if (!("IntersectionObserver" in window)) {
lazyImages.forEach(function (img) {
var src = img.dataset.src;
if (src) {
img.src = src;
img.classList.remove("aksrt-lazy");
img.classList.add("aksrt-loaded");
}
var skeleton = img.previousElementSibling;
if (skeleton && skeleton.classList.contains("aksrt-skeleton")) {
skeleton.remove();
}
});
return;
}
var observer = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (!entry.isIntersecting) return;
var img = entry.target;
var src = img.dataset.src;
if (!src) {
observer.unobserve(img);
return;
}
// 创建新图片预加载
var tempImg = new Image();
tempImg.onload = function () {
img.src = src;
img.classList.remove("aksrt-lazy");
img.classList.add("aksrt-loaded");
// 移除骨架
var skeleton = img.previousElementSibling;
if (skeleton && skeleton.classList.contains("aksrt-skeleton")) {
skeleton.remove();
}
};
tempImg.onerror = function () {
img.classList.remove("aksrt-lazy");
img.classList.add("aksrt-error");
// 移除骨架
var skeleton = img.previousElementSibling;
if (skeleton && skeleton.classList.contains("aksrt-skeleton")) {
skeleton.remove();
}
};
tempImg.src = src;
observer.unobserve(img);
});
}, {
rootMargin: "200px 0px",
threshold: 0.01
});
lazyImages.forEach(function (img) {
observer.observe(img);
});
}
window.AksrtFrontend.register("aksrt-ajax-pagination", function (root) { initAjaxPagination(root); });
window.AksrtFrontend.register("aksrt-lazy-load", function (root) { initLazyLoad(root); });
})();
+180
View File
@@ -0,0 +1,180 @@
/**
* AKSRT Scroll Behaviors — back-to-top, floating buttons, reading progress, nav scroll
*/
(function () {
"use strict";
function initBackToTop() {
var el = document.getElementById("float-back-to-top") || document.getElementById("back-to-top");
if (!el) return;
function onScroll() {
if (window.scrollY > 400) {
el.classList.add("is-visible");
} else {
el.classList.remove("is-visible");
}
}
window.addEventListener("scroll", onScroll, { passive: true });
onScroll();
el.addEventListener("click", function (e) {
e.preventDefault();
if (window.aksrt && aksrt.scrollTopTo) {
aksrt.scrollTopTo(0);
} else {
window.scrollTo({ top: 0, behavior: "smooth" });
}
});
}
function initFloatingButtons() {
var wrap = document.getElementById("float-right-btns");
if (!wrap) return;
function debugEnabled() {
return !!(window.aksrtData && aksrtData.debug);
}
function debugLog(message, context, level) {
if (!debugEnabled()) return;
var method = level === "error" ? "error" : (level === "warn" ? "warn" : "log");
console[method]("[AKSRT FloatingButtons] " + message, context || {});
}
function reportDebug(eventName, payload) {
if (!(window.aksrtData && aksrtData.debugLog && aksrtData.ajaxUrl && aksrtData.nonce)) {
return;
}
var body = new URLSearchParams();
body.set("action", "aksrt_frontend_debug");
body.set("nonce", aksrtData.nonce);
body.set("source", "floating_buttons");
body.set("event", eventName);
body.set("page", window.location.href);
if (payload && payload.text) body.set("text", String(payload.text));
if (payload && payload.size) body.set("size", String(payload.size));
if (payload && payload.error) body.set("error", String(payload.error));
fetch(aksrtData.ajaxUrl, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" },
credentials: "same-origin",
body: body.toString()
}).catch(function () {});
}
var scrollTimer = null;
function setHidden(hidden) {
wrap.classList.toggle("is-hidden", !!hidden);
}
function syncFromScrollBus() {
var body = document.body;
if (wrap.classList.contains("scroll-down-hide")) {
setHidden(body.classList.contains("scroll-down"));
}
if (wrap.classList.contains("scrolling-hide")) {
setHidden(true);
window.clearTimeout(scrollTimer);
scrollTimer = window.setTimeout(function () {
if (!body.classList.contains("scroll-down")) setHidden(false);
}, 160);
}
}
window.addEventListener("scroll", function () {
requestAnimationFrame(syncFromScrollBus);
}, { passive: true });
wrap.addEventListener("click", function (event) {
var btn = event.target.closest(".float-btn");
if (!btn) return;
if (btn.getAttribute("href") === "#") {
event.preventDefault();
}
if (btn.hasAttribute("data-action") && btn.getAttribute("data-action") === "toggle-theme") {
event.preventDefault();
if (window.aksrt && typeof aksrt.toggleTheme === "function") {
aksrt.toggleTheme();
} else {
document.documentElement.classList.toggle("dark");
document.body.classList.toggle("dark-theme");
}
}
btn.classList.remove("is-rippling");
window.requestAnimationFrame(function () {
btn.classList.add("is-rippling");
window.setTimeout(function () {
btn.classList.remove("is-rippling");
}, 600);
});
});
}
function initReadingProgress() {
var bar = document.getElementById("reading-progress-global");
if (!bar) return;
function update() {
var doc = document.documentElement;
var scrollable = doc.scrollHeight - window.innerHeight;
var pct = scrollable <= 0 ? 100 : Math.min(100, Math.max(0, (window.scrollY / scrollable) * 100));
bar.style.width = pct + "%";
bar.setAttribute("aria-valuenow", String(Math.round(pct)));
}
window.addEventListener("scroll", update, { passive: true });
window.addEventListener("resize", update, { passive: true });
update();
}
function initNavScrollState() {
var nav = document.querySelector(".site-nav");
var sliderContainer = document.querySelector(".header-components-container");
if (nav && sliderContainer) {
nav.classList.add("nav-transparent");
}
var scrollDownHide = document.body.classList.contains("scroll-down-hide");
var ticking = false;
function update() {
ticking = false;
var body = document.body;
if (nav) {
nav.classList.toggle("is-scrolled", body.classList.contains("body-scroll"));
}
if (nav && scrollDownHide) {
if (body.classList.contains("scroll-down")) {
nav.classList.add("is-hidden");
} else {
nav.classList.remove("is-hidden");
}
}
}
function onScroll() {
if (!ticking) {
window.requestAnimationFrame(update);
ticking = true;
}
}
window.addEventListener("scroll", onScroll, { passive: true });
window.addEventListener("resize", onScroll, { passive: true });
update();
}
window.AksrtFrontend.register("aksrt-floating-buttons", function () { initFloatingButtons(); });
window.AksrtFrontend.register("aksrt-back-to-top", function () { initBackToTop(); });
window.AksrtFrontend.register("aksrt-reading-progress", function () { initReadingProgress(); });
window.AksrtFrontend.register("aksrt-nav-scroll-state", function () { initNavScrollState(); });
})();
+340
View File
@@ -0,0 +1,340 @@
/**
* AKSRT Search Panel — desktop panel, mobile overlay, history, suggestions
*/
(function () {
"use strict";
function initSearchPanel() {
var btn = document.getElementById("search-toggle");
var panel = document.getElementById("nav-search-panel");
var mobileOverlay = document.getElementById("tabbar-search-overlay");
var mobileInput = document.getElementById("tabbar-search-input");
var mobileClose = document.getElementById("tabbar-search-close");
var mobileForm = mobileOverlay ? mobileOverlay.querySelector("form") : null;
var mobileTypeInput = document.getElementById("tabbar-search-type");
var mobileTypeButtons = document.querySelectorAll("#tabbar-search-types [data-search-type]");
var historyWrap = document.getElementById("tabbar-search-history");
var historySection = document.getElementById("tabbar-search-history-section");
var historyClear = document.getElementById("tabbar-search-history-clear");
var suggestionsWrap = document.getElementById("tabbar-search-suggestions");
var suggestionsSection = document.getElementById("tabbar-search-suggestions-section");
if (!btn || !panel) return;
var HISTORY_KEY = "aksrt-mobile-search-history";
var suggestTimer = null;
var searchConfig = (window.aksrtData && aksrtData.search) || {};
var historyEnabled = searchConfig.historyEnabled !== false;
var suggestionsEnabled = !!searchConfig.suggestionsEnabled;
if (historySection && !historyEnabled) {
historySection.hidden = true;
}
if (suggestionsSection && !suggestionsEnabled) {
suggestionsSection.hidden = true;
}
function getSearchType() {
return mobileTypeInput ? (mobileTypeInput.value || "post") : "post";
}
function setSearchType(type) {
if (!mobileTypeInput) return;
mobileTypeInput.value = type;
mobileTypeButtons.forEach(function (button) {
button.classList.toggle("is-active", button.getAttribute("data-search-type") === type);
});
requestSuggestions();
}
function readHistory() {
if (!historyEnabled) return [];
if (aksrtData.isLoggedIn) return [];
try {
var raw = localStorage.getItem(HISTORY_KEY);
var list = raw ? JSON.parse(raw) : [];
return Array.isArray(list) ? list : [];
} catch (e) {
return [];
}
}
function writeHistory(items) {
if (!historyEnabled) return;
if (aksrtData.isLoggedIn) return;
try {
localStorage.setItem(HISTORY_KEY, JSON.stringify(items.slice(0, 8)));
} catch (e) {}
}
function requestHistorySync(mode, items, callback) {
if (!historyEnabled) {
if (historySection) historySection.hidden = true;
if (typeof callback === "function") callback([]);
return;
}
if (!aksrtData.isLoggedIn) {
if (typeof callback === "function") callback(mode === "save" ? (items || []) : readHistory());
return;
}
var xhr = new XMLHttpRequest();
xhr.open("POST", aksrtData.ajaxUrl, true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
xhr.onload = function () {
if (typeof callback !== "function") return;
if (xhr.status < 200 || xhr.status >= 300) {
callback([]);
return;
}
try {
var json = JSON.parse(xhr.responseText);
callback(json.success && json.data && Array.isArray(json.data.items) ? json.data.items : []);
} catch (e) {
callback([]);
}
};
var body = "action=aksrt_search_history&nonce=" + encodeURIComponent(aksrtData.nonce) + "&mode=" + encodeURIComponent(mode);
if (mode === "save") {
body += "&items=" + encodeURIComponent(JSON.stringify(items || []));
}
xhr.send(body);
}
function pushHistory(keyword, type) {
if (!historyEnabled) return;
if (!keyword) return;
if (aksrtData.isLoggedIn) {
requestHistorySync("get", null, function (remoteItems) {
var nextRemote = (remoteItems || []).filter(function (item) {
return !(item && item.keyword === keyword && item.type === type);
});
nextRemote.unshift({ keyword: keyword, type: type });
requestHistorySync("save", nextRemote.slice(0, 8), function (savedItems) {
renderHistory(savedItems);
});
});
return;
}
var next = readHistory().filter(function (item) {
return !(item && item.keyword === keyword && item.type === type);
});
next.unshift({ keyword: keyword, type: type });
writeHistory(next);
renderHistory();
}
function renderHistory(providedItems) {
if (!historyWrap) return;
if (!historyEnabled) {
if (historySection) historySection.hidden = true;
historyWrap.innerHTML = "";
return;
}
if (historySection) {
historySection.hidden = false;
}
var items = Array.isArray(providedItems) ? providedItems : readHistory();
if (!items.length) {
historyWrap.innerHTML = '<div class="tabbar-search-overlay__empty">暂无搜索历史</div>';
if (historyClear) historyClear.style.display = "none";
return;
}
if (historyClear) historyClear.style.display = "inline-flex";
historyWrap.innerHTML = items.map(function (item) {
return '<button type="button" class="tabbar-search-overlay__history-item" data-history-keyword="' + encodeURIComponent(item.keyword) + '" data-history-type="' + encodeURIComponent(item.type || 'post') + '">' +
'<i class="fas fa-history"></i><span>' + item.keyword + '</span>' +
'</button>';
}).join("");
}
function renderSuggestions(items) {
if (!suggestionsWrap || !suggestionsSection) return;
if (!suggestionsEnabled) {
suggestionsSection.hidden = true;
suggestionsWrap.innerHTML = "";
return;
}
if (!items || !items.length) {
suggestionsWrap.innerHTML = '<div class="tabbar-search-overlay__empty">暂无匹配结果</div>';
suggestionsSection.hidden = false;
return;
}
suggestionsWrap.innerHTML = items.map(function (item) {
var meta = item.meta ? '<small>' + item.meta + '</small>' : '';
return '<a href="' + item.url + '" class="tabbar-search-overlay__suggestion-item">' +
'<span>' + item.title + '</span>' + meta +
'</a>';
}).join("");
suggestionsSection.hidden = false;
}
function requestSuggestions() {
if (!mobileInput || !suggestionsWrap || !suggestionsSection) return;
if (!suggestionsEnabled) {
suggestionsSection.hidden = true;
return;
}
var keyword = (mobileInput.value || "").trim();
if (suggestTimer) clearTimeout(suggestTimer);
if (keyword.length < 2) {
suggestionsSection.hidden = true;
return;
}
suggestTimer = setTimeout(function () {
var xhr = new XMLHttpRequest();
xhr.open("POST", aksrtData.ajaxUrl, true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
xhr.onload = function () {
if (xhr.status < 200 || xhr.status >= 300) return;
try {
var json = JSON.parse(xhr.responseText);
if (json.success && json.data && json.data.items) {
renderSuggestions(json.data.items);
}
} catch (e) {}
};
xhr.send(
"action=aksrt_search_suggestions&nonce=" + encodeURIComponent(aksrtData.nonce) +
"&q=" + encodeURIComponent(keyword) +
"&type=" + encodeURIComponent(getSearchType())
);
}, 180);
}
function isMobileSearchMode() {
return window.innerWidth < 768 && !!mobileOverlay;
}
function setOpen(open) {
if (isMobileSearchMode()) {
if (open) {
mobileOverlay.removeAttribute("hidden");
document.body.classList.add("tabbar-search-open");
if (mobileInput) mobileInput.focus();
if (historyEnabled) renderHistory();
if (suggestionsEnabled) requestSuggestions();
} else {
mobileOverlay.setAttribute("hidden", "");
document.body.classList.remove("tabbar-search-open");
if (suggestionsSection) suggestionsSection.hidden = true;
}
btn.setAttribute("aria-expanded", open ? "true" : "false");
return;
}
panel.classList.toggle("is-open", open);
btn.setAttribute("aria-expanded", open ? "true" : "false");
if (open) {
var input = panel.querySelector('input[type="search"]');
if (input) input.focus();
}
}
btn.addEventListener("click", function (e) {
e.stopPropagation();
if (isMobileSearchMode()) {
setOpen(!mobileOverlay || mobileOverlay.hasAttribute("hidden"));
return;
}
setOpen(!panel.classList.contains("is-open"));
});
document.addEventListener("click", function (e) {
if (isMobileSearchMode()) return;
if (!panel.classList.contains("is-open")) return;
if (panel.contains(e.target) || btn.contains(e.target)) return;
setOpen(false);
});
if (mobileOverlay) {
mobileOverlay.addEventListener("click", function (e) {
if (e.target === mobileOverlay) setOpen(false);
});
}
if (mobileClose) {
mobileClose.addEventListener("click", function () {
setOpen(false);
});
}
if (historyClear) {
historyClear.addEventListener("click", function () {
if (aksrtData.isLoggedIn) {
requestHistorySync("save", [], function (savedItems) {
renderHistory(savedItems);
});
return;
}
writeHistory([]);
renderHistory();
});
}
if (historyWrap) {
historyWrap.addEventListener("click", function (e) {
var item = e.target.closest("[data-history-keyword]");
if (!item || !mobileInput) return;
mobileInput.value = decodeURIComponent(item.getAttribute("data-history-keyword") || "");
setSearchType(decodeURIComponent(item.getAttribute("data-history-type") || "post"));
requestSuggestions();
});
}
mobileTypeButtons.forEach(function (button) {
button.addEventListener("click", function () {
setSearchType(button.getAttribute("data-search-type") || "post");
});
});
if (mobileInput) {
mobileInput.addEventListener("input", requestSuggestions);
}
if (mobileForm) {
mobileForm.addEventListener("submit", function () {
if (mobileInput) {
pushHistory((mobileInput.value || "").trim(), getSearchType());
}
});
}
document.querySelectorAll("[data-aksrt-search-form]").forEach(function (form) {
if (form === mobileForm) return;
form.addEventListener("submit", function () {
if (!historyEnabled) return;
var input = form.querySelector('input[name="s"]');
var typeInput = form.querySelector('input[name="aksrt_search_type"]');
var keyword = input ? (input.value || "").trim() : "";
var type = typeInput ? (typeInput.value || "post") : "post";
pushHistory(keyword, type);
});
});
setSearchType(getSearchType());
if (historyEnabled && aksrtData.isLoggedIn) {
requestHistorySync("get", null, function (items) {
renderHistory(items);
});
}
document.addEventListener("keydown", function (e) {
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
e.preventDefault();
setOpen(true);
}
if (e.key === "Escape" && panel.classList.contains("is-open")) {
setOpen(false);
btn.focus();
}
if (e.key === "Escape" && isMobileSearchMode() && mobileOverlay && !mobileOverlay.hasAttribute("hidden")) {
setOpen(false);
btn.focus();
}
});
window.__aksrtOpenSearchPanel = function () { setOpen(true); };
window.__aksrtCloseSearchPanel = function () { setOpen(false); };
}
window.AksrtFrontend.register("aksrt-search-panel", function () { initSearchPanel(); });
})();
+295
View File
@@ -0,0 +1,295 @@
/**
* AKSRT Hero & Swiper Initialization
*/
(function () {
"use strict";
window.AksrtSwipers = { new: [], scroll: [], tab: [] };
function initHeroSlider() {
if (typeof Swiper === "undefined") return;
// ===== Type A: .swiper-scroll =====
document.querySelectorAll(".swiper-scroll:not(.swiper-initialized)").forEach(function (el, index) {
var c_w = el.offsetWidth;
var firstSlide = el.querySelector(".swiper-wrapper > *");
var i_w = firstSlide ? firstSlide.offsetWidth : 200;
var slidesPerGroup = Math.max(1, Math.floor(c_w / i_w));
var option = {
slidesPerView: "auto",
freeMode: true,
freeModeSticky: true,
mousewheel: { forceToAxis: true },
slidesPerGroup: slidesPerGroup,
autoplay: el.dataset.autoplay ? {
delay: parseInt(el.dataset.interval || "4000", 10),
disableOnInteraction: false,
} : false,
loop: !!el.dataset.loop,
navigation: {
nextEl: el.querySelector(".swiper-button-next"),
prevEl: el.querySelector(".swiper-button-prev"),
},
};
el.classList.add("swiper-scroll-eq-" + index);
el.setAttribute("swiper-scroll-index", String(index));
window.AksrtSwipers.scroll[index] = new Swiper(el, option);
});
// ===== Type B: .swiper-tab =====
document.querySelectorAll(".swiper-tab:not(.swiper-initialized)").forEach(function (el, index) {
var speed = parseInt(el.dataset.speed || "0", 10) || Math.floor((el.offsetWidth + 1200) / 170) * 50;
speed = Math.max(300, speed);
var initialSlide = parseInt(el.getAttribute("active-index") || "0", 10);
var option = {
loop: false,
initialSlide: initialSlide,
autoHeight: true,
spaceBetween: 20,
autoplay: false,
speed: speed,
pagination: {
el: el.querySelector(".swiper-pagination"),
clickable: true,
},
};
var tabId = el.getAttribute("swiper-tab");
if (tabId) {
var tabNav = document.querySelector('[swiper-tab-nav="' + tabId + '"]');
if (tabNav && tabNav.swiper) {
option.thumbs = {
swiper: tabNav.swiper,
autoScrollOffset: 2,
};
}
}
el.classList.add("swiper-tab-eq-" + index);
el.setAttribute("swiper-tab-index", String(index));
window.AksrtSwipers.tab[index] = new Swiper(el, option);
});
// ===== Type C: .new-swiper =====
document.querySelectorAll(".new-swiper:not(.swiper-initialized)").forEach(function (el, index) {
var delay = parseInt(el.dataset.interval || "6000", 10);
var autoplay = el.dataset.autoplay !== undefined ? {
delay: delay,
disableOnInteraction: false,
} : false;
var speed = parseInt(el.dataset.speed || "0", 10) || Math.floor((el.offsetWidth + 1000) / 22) * 10;
speed = Math.max(400, speed);
if (!autoplay) speed = Math.floor(speed / 1.6);
var loop = !!el.dataset.loop;
var parallax = !!el.querySelector("[data-swiper-parallax],[data-swiper-parallax-scale]");
var effect = el.dataset.effect || "slide";
var direction = el.dataset.direction || "horizontal";
var spaceBetween = parseInt(el.dataset.spaceBetween || "0", 10);
var paginationType = el.dataset.paginationType || "bullets";
var autoHeight = el.hasAttribute("auto-height");
el.classList.add("swiper-new-eq-" + index);
el.setAttribute("swiper-new-index", String(index));
var swiperArgs = {
loop: loop,
autoHeight: autoHeight,
direction: direction,
spaceBetween: spaceBetween,
parallax: parallax,
effect: effect,
lazy: { loadPrevNext: true },
autoplay: autoplay,
speed: speed,
pagination: {
el: el.querySelector(".swiper-pagination"),
type: paginationType,
clickable: true,
},
navigation: {
nextEl: el.querySelector(".swiper-button-next"),
prevEl: el.querySelector(".swiper-button-prev"),
},
keyboard: { enabled: true },
a11y: { prevSlideMessage: "上一张", nextSlideMessage: "下一张" },
on: {
lazyImageReady: function (slideEl, imageEl) {
if (imageEl) imageEl.classList.add("lazyloaded");
},
slideChange: function () {
el.querySelectorAll(".aksrt-dplayer, video").forEach(function (media) {
if (media.pause) media.pause();
var dp = media.closest("[data-dplayer]");
if (dp && dp._dplayer) dp._dplayer.pause();
});
},
init: function () {
if (loop) {
el.querySelectorAll(".swiper-slide-duplicate img").forEach(function (img) {
img.classList.add("no-imgbox");
});
}
},
},
};
if (paginationType === "thumbnail") {
swiperArgs.pagination.type = "bullets";
swiperArgs.pagination.bulletClass = "pagination-thumbnail-item";
swiperArgs.pagination.bulletActiveClass = "pagination-thumbnail-item-active";
swiperArgs.pagination.renderBullet = function (idx, className) {
var slide = this.slides[idx];
if (!slide) return "";
var img = slide.querySelector("img");
var src = img ? (img.dataset.src || img.src) : "";
if (src) {
return '<div class="' + className + '"><img class="aksrt-tilt-thumb" src="' + src + '"></div>';
}
return "";
};
}
var swiperInstance = new Swiper(el, swiperArgs);
window.AksrtSwipers.new[index] = swiperInstance;
if (el.classList.contains("banner-module__swiper")) {
var prevBtn = el.querySelector(".swiper-button-prev");
var nextBtn = el.querySelector(".swiper-button-next");
if (prevBtn) {
prevBtn.addEventListener("click", function (e) {
e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation();
if (swiperInstance && !swiperInstance.destroyed) swiperInstance.slidePrev();
}, true);
}
if (nextBtn) {
nextBtn.addEventListener("click", function (e) {
e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation();
if (swiperInstance && !swiperInstance.destroyed) swiperInstance.slideNext();
}, true);
}
}
});
// ===== Compat: data-swiper-config JSON =====
document.querySelectorAll("[data-swiper-config]:not(.swiper-initialized):not(.new-swiper):not(.swiper-scroll):not(.swiper-tab)").forEach(function (el) {
var config = {};
try { config = JSON.parse(el.dataset.swiperConfig || "{}"); } catch (e) {}
var paginationEl = el.querySelector(".swiper-pagination, .header-components__pagination");
var prevBtn = el.querySelector(".swiper-button-prev");
var nextBtn = el.querySelector(".swiper-button-next");
var defaults = {
effect: "fade",
fadeEffect: { crossFade: true },
loop: true,
speed: 600,
autoplay: { delay: 5000, disableOnInteraction: false },
pagination: paginationEl ? { el: paginationEl, type: "progressbar" } : false,
navigation: (prevBtn && nextBtn) ? { prevEl: prevBtn, nextEl: nextBtn } : false,
keyboard: { enabled: true },
a11y: { prevSlideMessage: "上一张", nextSlideMessage: "下一张" },
};
var finalConfig = Object.assign({}, defaults, config);
if (config.pagination && typeof config.pagination === "object") {
if (!config.pagination.el && paginationEl) config.pagination.el = paginationEl;
finalConfig.pagination = Object.assign({}, defaults.pagination || {}, config.pagination);
} else if (config.pagination === false) {
finalConfig.pagination = false;
}
if (config.navigation === true && prevBtn && nextBtn) {
finalConfig.navigation = { prevEl: prevBtn, nextEl: nextBtn };
}
new Swiper(el, finalConfig);
});
// Clickable slides
document.querySelectorAll(".swiper-slide[data-link]").forEach(function (slide) {
var link = slide.dataset.link;
if (link && link !== "#") {
slide.style.cursor = "pointer";
slide.addEventListener("click", function (e) {
if (e.target.closest(".header-components-search, .header-components-card, .hero__btn, .swiper-button-prev, .swiper-button-next, .swiper-pagination, .hero-search, a, button, input")) return;
window.location.href = link;
});
}
});
// Legacy hero__slides fallback
document.querySelectorAll(".hero__slides:not(.swiper-wrapper)").forEach(function (slider) {
var slides = slider.querySelectorAll(".hero__slide");
var dots = slider.querySelectorAll(".hero__dot");
var prevBtn = slider.closest("section")?.querySelector(".hero__btn--prev");
var nextBtn = slider.closest("section")?.querySelector(".hero__btn--next");
if (!slides.length || slides.length <= 1) return;
var autoplayInterval = parseInt(slider.dataset.autoplay || "5000", 10) || 5000;
var pauseOnHover = slider.dataset.pauseOnHover === "true";
var current = 0;
var timer = null;
var paused = false;
function show(index) {
index = ((index % slides.length) + slides.length) % slides.length;
slides[current].classList.remove("active");
if (dots[current]) dots[current].setAttribute("aria-selected", "false");
current = index;
slides[current].classList.add("active");
if (dots[current]) dots[current].setAttribute("aria-selected", "true");
}
function next() { show(current + 1); }
function prev() { show(current - 1); }
function startAutoplay() { stopAutoplay(); timer = setInterval(next, autoplayInterval); }
function stopAutoplay() { if (timer) clearInterval(timer); timer = null; }
function restart() { if (!paused) { stopAutoplay(); startAutoplay(); } }
show(0);
if (nextBtn) nextBtn.addEventListener("click", function () { next(); restart(); });
if (prevBtn) prevBtn.addEventListener("click", function () { prev(); restart(); });
dots.forEach(function (dot, i) { dot.addEventListener("click", function () { show(i); restart(); }); });
slider.setAttribute("tabindex", "-1");
slider.addEventListener("keydown", function (e) {
if (e.key === "ArrowRight") { next(); restart(); }
else if (e.key === "ArrowLeft") { prev(); restart(); }
});
if (pauseOnHover) {
slider.addEventListener("mouseenter", function () { paused = true; stopAutoplay(); });
slider.addEventListener("mouseleave", function () { paused = false; startAutoplay(); });
}
slides.forEach(function (slide) {
var link = slide.dataset.link;
if (link && link !== "#") {
slide.style.cursor = "pointer";
slide.addEventListener("click", function () { window.location.href = link; });
}
});
var touchStartX = 0;
slider.addEventListener("touchstart", function (e) { touchStartX = e.changedTouches[0].screenX; stopAutoplay(); }, { passive: true });
slider.addEventListener("touchend", function (e) {
var diff = touchStartX - e.changedTouches[0].screenX;
if (Math.abs(diff) > 50) { if (diff > 0) next(); else prev(); }
startAutoplay();
}, { passive: true });
startAutoplay();
document.addEventListener("visibilitychange", function () {
if (document.hidden) stopAutoplay();
else if (!paused) startAutoplay();
});
});
}
window.AksrtFrontend.register("aksrt-hero-slider", function () { initHeroSlider(); });
})();
+269
View File
@@ -0,0 +1,269 @@
/**
* AKSRT Theme Toggle — dark/light mode switching with transitions
*/
(function () {
"use strict";
var THEME_KEY = "aksrt-theme";
var THEME_COOKIE_KEY = "theme_mode";
function normalizeStoredTheme(value) {
if (value === "dark" || value === "dark-theme") return "dark";
if (value === "light" || value === "white-theme") return "light";
return null;
}
function toCookieTheme(value) {
return value === "dark" ? "dark-theme" : "white-theme";
}
function getCookie(name) {
var parts = document.cookie ? document.cookie.split("; ") : [];
for (var i = 0; i < parts.length; i++) {
var pair = parts[i].split("=");
if (decodeURIComponent(pair[0]) === name) {
return decodeURIComponent(pair.slice(1).join("="));
}
}
return "";
}
function setCookie(name, value, days) {
var maxAge = days ? "; max-age=" + (days * 24 * 60 * 60) : "";
var secure = window.location && window.location.protocol === "https:" ? "; Secure" : "";
document.cookie = encodeURIComponent(name) + "=" + encodeURIComponent(value) + maxAge + "; path=/; SameSite=Lax" + secure;
}
function getStoredTheme() {
var localTheme = null;
try {
localTheme = normalizeStoredTheme(localStorage.getItem(THEME_KEY));
} catch (e) {
localTheme = null;
}
var theme = normalizeStoredTheme(getCookie(THEME_COOKIE_KEY)) || localTheme;
if (theme) {
setStoredTheme(theme);
}
return theme;
}
function setStoredTheme(value) {
var theme = normalizeStoredTheme(value);
if (!theme) return;
try {
localStorage.setItem(THEME_KEY, theme);
} catch (e) {}
setCookie(THEME_COOKIE_KEY, toCookieTheme(theme), 365);
}
function getTimeAutoTheme() {
var hour = (new Date()).getHours();
return hour >= 20 || hour < 8 ? "dark" : "light";
}
function resolveConfiguredTheme(mode) {
var normalized = normalizeStoredTheme(mode);
if (normalized) return normalized;
if (mode === "time-auto" || mode === "auto") {
return getTimeAutoTheme();
}
return "light";
}
function syncBrandLogos(isDark) {
document.querySelectorAll("[data-logo-light]").forEach(function (img) {
var lightSrc = img.getAttribute("data-logo-light") || "";
var darkSrc = img.getAttribute("data-logo-dark") || "";
if (!lightSrc) return;
img.setAttribute("src", isDark && darkSrc ? darkSrc : lightSrc);
});
}
function syncThemeColorMeta(isDark) {
var meta = document.querySelector('meta[name="theme-color"]');
if (!meta) {
meta = document.createElement("meta");
meta.setAttribute("name", "theme-color");
document.head.appendChild(meta);
}
meta.setAttribute("content", isDark ? "#2F3135" : "#FDFCFE");
}
function getThemeImageAttr(img, name) {
return img.getAttribute(name) || img.getAttribute("data-" + name) || "";
}
function setThemeImageSource(img, src) {
if (!src || img.getAttribute("src") === src) return;
img.setAttribute("src", src);
}
function syncThemeImages(isDark) {
document.querySelectorAll("img[switch-src], img[data-switch-src]").forEach(function (img) {
var darkSrc = getThemeImageAttr(img, "switch-src");
if (!img.dataset.aksrtThemeLightSrc) {
img.dataset.aksrtThemeLightSrc = img.getAttribute("src") || "";
}
setThemeImageSource(img, isDark && darkSrc ? darkSrc : img.dataset.aksrtThemeLightSrc);
});
document.querySelectorAll("img[white-src], img[dark-src], img[data-white-src], img[data-dark-src]").forEach(function (img) {
var lightSrc = getThemeImageAttr(img, "white-src") || img.dataset.aksrtThemeLightSrc || img.getAttribute("src") || "";
var darkSrc = getThemeImageAttr(img, "dark-src");
if (!img.dataset.aksrtThemeLightSrc && lightSrc) {
img.dataset.aksrtThemeLightSrc = lightSrc;
}
setThemeImageSource(img, isDark && darkSrc ? darkSrc : lightSrc);
});
}
function syncCodeHighlightTheme(isDark) {
if (typeof window.AksrtPrecodeApplyTheme === "function") {
window.AksrtPrecodeApplyTheme(isDark);
return;
}
var settings = (window.aksrtData && window.aksrtData.codeHighlight) || {};
var theme = isDark ? (settings.darkTheme || "monokai") : (settings.lightTheme || "enlighter");
document.querySelectorAll(".enlighter-default").forEach(function (el) {
el.className = el.className.replace(/\benlighter-t-[\w-]+\b/g, "").replace(/\s+/g, " ").trim();
el.classList.add("enlighter-t-" + theme);
});
}
function dispatchThemeChange(isDark) {
try {
document.dispatchEvent(new CustomEvent("aksrt:theme-change", {
detail: {
theme: isDark ? "dark" : "light",
isDark: isDark
}
}));
} catch (e) {}
}
function applyTheme(mode) {
var isDark = mode === "dark";
document.documentElement.classList.toggle("dark", isDark);
document.documentElement.setAttribute("data-theme", isDark ? "dark" : "light");
document.body.classList.toggle("theme-dark", isDark);
document.body.classList.toggle("dark-theme", isDark);
document.body.classList.toggle("white-theme", !isDark);
document.body.setAttribute("data-theme", isDark ? "dark" : "light");
syncBrandLogos(isDark);
syncThemeColorMeta(isDark);
syncThemeImages(isDark);
syncCodeHighlightTheme(isDark);
dispatchThemeChange(isDark);
var btn = document.getElementById("theme-toggle");
if (btn) {
btn.setAttribute("aria-pressed", isDark ? "true" : "false");
btn.classList.toggle("is-dark", isDark);
var moon = btn.querySelector(".theme-icon-moon");
var sun = btn.querySelector(".theme-icon-sun");
if (moon && sun) {
moon.style.display = isDark ? "none" : "";
sun.style.display = isDark ? "" : "none";
}
}
var floatBtn = document.getElementById("float-theme-toggle");
if (floatBtn) {
floatBtn.setAttribute("aria-pressed", isDark ? "true" : "false");
var moonIcon = floatBtn.querySelector(".float-btn__icon-moon");
var sunIcon = floatBtn.querySelector(".float-btn__icon-sun");
if (moonIcon && sunIcon) {
moonIcon.style.display = isDark ? "" : "none";
sunIcon.style.display = isDark ? "none" : "";
}
}
var ddBtn = document.getElementById("dropdown-theme-toggle");
if (ddBtn) ddBtn.setAttribute("aria-pressed", isDark ? "true" : "false");
}
function initTheme() {
var stored = getStoredTheme();
var configuredMode = (window.aksrtData && aksrtData.themeMode) || "light";
if (stored === "dark" || stored === "light") {
applyTheme(stored);
} else {
applyTheme(resolveConfiguredTheme(configuredMode));
}
function prefersReducedMotion() {
return window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
}
function getThemeTransitionPoint(event) {
if (event && typeof event.clientX === "number" && typeof event.clientY === "number") {
return { x: event.clientX, y: event.clientY };
}
return { x: window.innerWidth / 2, y: window.innerHeight / 2 };
}
function runThemeTransition(next, event) {
if (!document.startViewTransition || prefersReducedMotion()) {
applyTheme(next);
return;
}
var point = getThemeTransitionPoint(event);
var endRadius = Math.hypot(
Math.max(point.x, window.innerWidth - point.x),
Math.max(point.y, window.innerHeight - point.y)
);
var clipPath = [
"circle(0px at " + point.x + "px " + point.y + "px)",
"circle(" + endRadius + "px at " + point.x + "px " + point.y + "px)"
];
var enteringDark = next === "dark";
try {
var transition = document.startViewTransition(function () {
applyTheme(next);
});
transition.ready.then(function () {
try {
document.documentElement.animate(
{ clipPath: enteringDark ? clipPath : clipPath.slice().reverse() },
{
duration: 500,
easing: enteringDark ? "ease-in" : "ease-out",
fill: "both",
pseudoElement: enteringDark ? "::view-transition-new(root)" : "::view-transition-old(root)"
}
);
} catch (e) {}
}).catch(function () {});
} catch (e) {
applyTheme(next);
}
}
function bindToggle(id) {
var el = document.getElementById(id);
if (!el) return;
el.addEventListener("click", function (event) {
var next = document.body.classList.contains("theme-dark") ? "light" : "dark";
setStoredTheme(next);
runThemeTransition(next, event);
});
}
bindToggle("theme-toggle");
bindToggle("theme-toggle-desktop");
bindToggle("dropdown-theme-toggle");
bindToggle("float-theme-toggle");
bindToggle("theme-toggle-mobile");
aksrt.toggleTheme = function (event) {
var next = document.body.classList.contains("theme-dark") ? "light" : "dark";
setStoredTheme(next);
runThemeTransition(next, event);
};
}
window.AksrtFrontend.register("aksrt-theme", function () { initTheme(); });
})();