- Rewrite post_list/filter schema (PHP + JS) with the reference theme's
field set, order, defaults and dependencies; topics fields excluded
(no topics taxonomy), AKSRT private filter_* toggles dropped
- Support dynamic checkbox options in AksField (options as formData key)
so cat_custom_filter.custom_filters lists the custom_filter dimensions
- Map PostDisplay filter settings to the new keys without legacy fallback;
cat_custom_filter now carries lists/dropdown fieldsets and array filters
- Wire the archive chain to reference semantics: cat_custom_filter
overrides per-category filter projects, custom_filter_show gates the
default display, dimension chip groups render on category/tag archives
- Filter archive queries (main query + AJAX endpoint) by _aksrt_cf_{key}
meta with exact-quoted LIKE matching
- Add advanced-filter settings reference contract test
229 lines
8.2 KiB
JavaScript
229 lines
8.2 KiB
JavaScript
/**
|
|
* AKSRT Archive AJAX Filter
|
|
*/
|
|
(function () {
|
|
"use strict";
|
|
|
|
function initArchiveFilter(root) {
|
|
var scope = root || document;
|
|
var bar = scope.querySelector(".archive-filter-bar--ajax[data-ajax-archive]");
|
|
if (!bar || bar.dataset.aksrtArchiveInit === "1") return;
|
|
bar.dataset.aksrtArchiveInit = "1";
|
|
|
|
var archiveType = bar.dataset.ajaxArchive || "category";
|
|
var termId = parseInt(bar.dataset.termId, 10) || 0;
|
|
var wrap = scope.querySelector("[data-ajax-wrap]");
|
|
if (!wrap) return;
|
|
|
|
var loading = wrap.querySelector(".archive__ajax-loading");
|
|
var REST_BASE = "/wp-json/aksrt/v1/archive/posts";
|
|
var emptyText = archiveType === "tag" ? "该标签下暂无文章" : "该分类下暂无文章";
|
|
|
|
var state = {
|
|
filter_cat: "",
|
|
filter_tag: "",
|
|
custom: {},
|
|
sort: "date",
|
|
page: 1
|
|
};
|
|
|
|
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 || "date";
|
|
// 自定义高级筛选维度:以当前 URL 参数为准(SSR active 状态与 URL 一致)。
|
|
if (bar.querySelector("[data-filter-dim]")) {
|
|
new URLSearchParams(window.location.search).forEach(function (value, key) {
|
|
if (bar.querySelector('[data-filter-dim="' + key + '"]')) {
|
|
state.custom[key] = value;
|
|
}
|
|
});
|
|
}
|
|
|
|
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);
|
|
if (Object.keys(state.custom).length) params.set("custom_filter", JSON.stringify(state.custom));
|
|
|
|
params.set("sort", state.sort || "date");
|
|
params.set("page", String(state.page));
|
|
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 || "date") === state.sort);
|
|
});
|
|
bar.querySelectorAll("[data-filter-dim]").forEach(function (el) {
|
|
var current = state.custom[el.dataset.filterDim] || "";
|
|
el.classList.toggle("is-active", (el.dataset.filterDimValue || "") !== "" && (el.dataset.filterDimValue || "") === current);
|
|
});
|
|
}
|
|
|
|
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 rebuildEmptyState() {
|
|
var noResults = document.createElement("div");
|
|
noResults.className = "no-results content-stream__empty";
|
|
noResults.innerHTML = "<p>" + emptyText + "</p>";
|
|
wrap.appendChild(noResults);
|
|
}
|
|
|
|
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) {
|
|
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 {
|
|
rebuildEmptyState();
|
|
}
|
|
// legacy 事件顺序:先 post_ajax.ed,再全局 auto_fun 重扫
|
|
wrap.dispatchEvent(new CustomEvent("post_ajax.ed", { bubbles: true }));
|
|
if (typeof window.auto_fun === "function") window.auto_fun();
|
|
}
|
|
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");
|
|
bar.querySelectorAll("[data-filter-dim]").forEach(function (el) {
|
|
url.searchParams.delete(el.dataset.filterDim);
|
|
});
|
|
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);
|
|
Object.keys(state.custom).forEach(function (key) {
|
|
url.searchParams.set(key, state.custom[key]);
|
|
});
|
|
if (state.sort) url.searchParams.set("orderby", state.sort);
|
|
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-dim]");
|
|
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 || "date";
|
|
if (newSort !== state.sort) {
|
|
state.sort = newSort;
|
|
changed = true;
|
|
}
|
|
}
|
|
if (chip.dataset.filterDim !== undefined) {
|
|
var dimKey = chip.dataset.filterDim;
|
|
var dimValue = chip.dataset.filterDimValue || "";
|
|
if (dimValue !== (state.custom[dimKey] || "")) {
|
|
if (dimValue === "") {
|
|
delete state.custom[dimKey];
|
|
} else {
|
|
state.custom[dimKey] = dimValue;
|
|
}
|
|
changed = true;
|
|
}
|
|
}
|
|
|
|
if (changed) {
|
|
state.page = 1;
|
|
updateActiveChips();
|
|
fetchPosts(true);
|
|
}
|
|
});
|
|
|
|
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);
|
|
}
|
|
});
|
|
|
|
window.addEventListener("popstate", function (e) {
|
|
if (e.state && e.state.aksrtArchive) {
|
|
state = Object.assign(state, e.state.state);
|
|
updateActiveChips();
|
|
fetchPosts(false);
|
|
}
|
|
});
|
|
}
|
|
|
|
function init(root) {
|
|
initArchiveFilter(root);
|
|
}
|
|
|
|
if (document.readyState === "loading") {
|
|
document.addEventListener("DOMContentLoaded", function () { init(); });
|
|
} else {
|
|
init();
|
|
}
|
|
// AJAX 注入新内容后由 auto_fun 重扫(bar 级 data 标记保证幂等)。
|
|
if (window.jQuery) {
|
|
window.jQuery(document).on("auto_fun", function () { init(); });
|
|
}
|
|
})();
|