363 lines
13 KiB
JavaScript
363 lines
13 KiB
JavaScript
/**
|
|
* AKSRT Search Panel — desktop panel, mobile overlay, history, suggestions
|
|
*/
|
|
(function () {
|
|
"use strict";
|
|
|
|
function initSearchPanel() {
|
|
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");
|
|
var searchForms = Array.prototype.slice.call(document.querySelectorAll("[data-aksrt-search-form]"));
|
|
if (!searchForms.length && !mobileForm) 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 getDesktopSearchType() {
|
|
if (!searchForms.length) return searchConfig.defaultType || "post";
|
|
var input = searchForms[0].querySelector('input[name="aksrt_search_type"]');
|
|
var value = input ? (input.value || "") : "";
|
|
return value || searchConfig.defaultType || "post";
|
|
}
|
|
|
|
function getDesktopCategory() {
|
|
if (!searchForms.length) return "0";
|
|
var input = searchForms[0].querySelector('input[name="aksrt_category"]');
|
|
return input ? (input.value || "0") : "0";
|
|
}
|
|
|
|
function syncSearchForms(type, category) {
|
|
searchForms.forEach(function (form) {
|
|
var typeInput = form.querySelector('input[name="aksrt_search_type"]');
|
|
if (typeInput) {
|
|
typeInput.value = type || searchConfig.defaultType || "post";
|
|
}
|
|
var categoryInput = form.querySelector('input[name="aksrt_category"]');
|
|
if (categoryInput) {
|
|
if ((type || searchConfig.defaultType || "post") === "post" && category && category !== "0") {
|
|
categoryInput.value = category;
|
|
} else {
|
|
categoryInput.value = "";
|
|
}
|
|
}
|
|
form.querySelectorAll("[data-search-type]").forEach(function (button) {
|
|
button.classList.toggle("is-active", button.getAttribute("data-search-type") === (type || searchConfig.defaultType || "post"));
|
|
});
|
|
});
|
|
}
|
|
|
|
function syncCategorySelectors(type, category) {
|
|
document.querySelectorAll("[data-search-category-select]").forEach(function (select) {
|
|
select.value = category && category !== "" ? category : "0";
|
|
select.disabled = (type || searchConfig.defaultType || "post") !== "post";
|
|
});
|
|
}
|
|
|
|
|
|
function getSearchType() {
|
|
if (mobileTypeInput) {
|
|
return mobileTypeInput.value || getDesktopSearchType();
|
|
}
|
|
return getDesktopSearchType();
|
|
}
|
|
|
|
function setSearchType(type) {
|
|
var nextType = type || searchConfig.defaultType || getDesktopSearchType();
|
|
if (mobileTypeInput) {
|
|
mobileTypeInput.value = nextType;
|
|
}
|
|
mobileTypeButtons.forEach(function (button) {
|
|
button.classList.toggle("is-active", button.getAttribute("data-search-type") === nextType);
|
|
});
|
|
syncSearchForms(nextType, getDesktopCategory());
|
|
syncCategorySelectors(nextType, getDesktopCategory());
|
|
requestSuggestions();
|
|
}
|
|
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;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
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();
|
|
});
|
|
}
|
|
|
|
document.querySelectorAll("[data-search-category-select]").forEach(function (select) {
|
|
select.addEventListener("change", function () {
|
|
var nextCategory = this.value || "0";
|
|
syncSearchForms(getSearchType(), nextCategory);
|
|
syncCategorySelectors(getSearchType(), nextCategory);
|
|
});
|
|
});
|
|
|
|
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());
|
|
}
|
|
});
|
|
}
|
|
|
|
searchForms.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 || searchConfig.defaultType || "post") : (searchConfig.defaultType || "post");
|
|
pushHistory(keyword, type);
|
|
});
|
|
});
|
|
|
|
syncSearchForms(getSearchType(), getDesktopCategory());
|
|
syncCategorySelectors(getSearchType(), getDesktopCategory());
|
|
setSearchType(getSearchType());
|
|
if (historyEnabled && aksrtData.isLoggedIn) {
|
|
requestHistorySync("get", null, function (items) {
|
|
renderHistory(items);
|
|
});
|
|
}
|
|
|
|
document.addEventListener("keydown", function (e) {
|
|
if (e.key === "Escape" && isMobileSearchMode() && mobileOverlay && !mobileOverlay.hasAttribute("hidden")) {
|
|
setOpen(false);
|
|
}
|
|
});
|
|
|
|
window.__aksrtOpenSearchPanel = function () { setOpen(true); };
|
|
window.__aksrtCloseSearchPanel = function () { setOpen(false); };
|
|
}
|
|
|
|
window.AksrtFrontend.register("aksrt-search-panel", function () { initSearchPanel(); });
|
|
})();
|