补充主题静态资源与归档模板
This commit is contained in:
1 parent
1268a55dd0
commit
3247db7ed1
265 files changed
+59174
No files matched your search
@@ -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(); });
|
||||
})();
|
||||
@@ -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); });
|
||||
})();
|
||||
@@ -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); });
|
||||
})();
|
||||
@@ -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(); });
|
||||
})();
|
||||
@@ -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(); });
|
||||
})();
|
||||
@@ -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();
|
||||
}
|
||||
})();
|
||||
@@ -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(); });
|
||||
})();
|
||||
@@ -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); });
|
||||
})();
|
||||
@@ -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(); });
|
||||
})();
|
||||
@@ -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(); });
|
||||
})();
|
||||
@@ -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(); });
|
||||
})();
|
||||
@@ -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(); });
|
||||
})();
|
||||
Reference in new issue
Block a user