| 1 |
document.addEventListener("DOMContentLoaded", function () { |
| 2 |
const searchContainers = document.querySelectorAll( |
| 3 |
".sp-smart-post-search-wrapper" |
| 4 |
); |
| 5 |
function debounce(fn, delay) { |
| 6 |
let timer; |
| 7 |
return function (...args) { |
| 8 |
clearTimeout(timer); |
| 9 |
timer = setTimeout(() => fn.apply(this, args), delay); |
| 10 |
}; |
| 11 |
} |
| 12 |
const safeJSONParse = (str, fallback = {}) => { |
| 13 |
try { |
| 14 |
return JSON.parse(str) || fallback; |
| 15 |
} catch (e) { |
| 16 |
console.log("Failed to parse JSON:", str, e); |
| 17 |
return fallback; |
| 18 |
} |
| 19 |
}; |
| 20 |
const loadQueryData = (state) => { |
| 21 |
return fetch(sp_smart_search_block_localize.searchRestUrl, { |
| 22 |
method: "POST", |
| 23 |
headers: { "Content-Type": "application/json" }, |
| 24 |
body: JSON.stringify(state), |
| 25 |
}).then((res) => res.json()); |
| 26 |
}; |
| 27 |
function highlightSearchTerm(container, term) { |
| 28 |
if (!term) { |
| 29 |
return; |
| 30 |
} |
| 31 |
const regex = new RegExp( |
| 32 |
"(" + term.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + ")", |
| 33 |
"gi" |
| 34 |
); |
| 35 |
|
| 36 |
const walker = document.createTreeWalker( |
| 37 |
container, |
| 38 |
NodeFilter.SHOW_TEXT, |
| 39 |
null, |
| 40 |
false |
| 41 |
); |
| 42 |
const nodes = []; |
| 43 |
while (walker.nextNode()) { |
| 44 |
nodes.push(walker.currentNode); |
| 45 |
} |
| 46 |
|
| 47 |
nodes?.forEach(function (node) { |
| 48 |
const parent = node.parentNode; |
| 49 |
if (parent && parent.nodeName !== "MARK") { |
| 50 |
const newHTML = node.nodeValue.replace( |
| 51 |
regex, |
| 52 |
'<mark class="sp-smart-post-search-highlight">$1</mark>' |
| 53 |
); |
| 54 |
if (newHTML !== node.nodeValue) { |
| 55 |
const span = document.createElement("span"); |
| 56 |
span.innerHTML = newHTML; |
| 57 |
parent.replaceChild(span, node); |
| 58 |
} |
| 59 |
} |
| 60 |
}); |
| 61 |
} |
| 62 |
const eventHandler = async (e, container, query) => { |
| 63 |
e.preventDefault(); |
| 64 |
const target = e.target; |
| 65 |
const searchResults = container.querySelector( |
| 66 |
".sp-smart-post-search-results" |
| 67 |
); |
| 68 |
const searchInput = target.closest(".sp-smart-post-search-input"); |
| 69 |
const taxonomyField = container.querySelector( |
| 70 |
".sp-smart-post-search-cate-list" |
| 71 |
); |
| 72 |
|
| 73 |
if (taxonomyField) { |
| 74 |
const termId = taxonomyField.value; |
| 75 |
query.term = termId; |
| 76 |
} |
| 77 |
if (searchInput) { |
| 78 |
const searchTerm = searchInput.value.trim(); |
| 79 |
if (searchTerm.length > 0) { |
| 80 |
searchResults.classList.add( |
| 81 |
"sp-smart-post-search-results--show" |
| 82 |
); |
| 83 |
query.s = searchTerm; |
| 84 |
} else { |
| 85 |
searchResults.classList.remove( |
| 86 |
"sp-smart-post-search-results--show" |
| 87 |
); |
| 88 |
return; |
| 89 |
} |
| 90 |
} |
| 91 |
|
| 92 |
loadQueryData(query).then((data) => { |
| 93 |
const resultList = container.querySelector( |
| 94 |
".sp-smart-post-search-list" |
| 95 |
); |
| 96 |
if (resultList) { |
| 97 |
resultList.innerHTML = data.html; |
| 98 |
if (query.s && query?.hightLightSearchTerm) { |
| 99 |
highlightSearchTerm(resultList, query.s.trim()); |
| 100 |
} |
| 101 |
} |
| 102 |
const loadMore = container.querySelector( |
| 103 |
".sp-smart-post-search-load-more" |
| 104 |
); |
| 105 |
if (loadMore) { |
| 106 |
const showCount = query?.showResultsCount || true; |
| 107 |
const viewMoreText = |
| 108 |
loadMore.dataset.view_more_text ?? "View More"; |
| 109 |
if (data.remaining_posts > 0) { |
| 110 |
if (query?.moreResultClickAction === "expanded") { |
| 111 |
loadMore.innerHTML = `<button type="button" class="sp-smart-post-search-load-more-button"> ${viewMoreText}${ showCount ? (" " + data.remaining_posts + " + Posts") : ""}</button>`; |
| 112 |
const loadMoreBtn = loadMore.querySelector( |
| 113 |
".sp-smart-post-search-load-more-button" |
| 114 |
); |
| 115 |
loadMoreBtn?.addEventListener("click", () => { |
| 116 |
query.loadMore = true; |
| 117 |
eventHandler(e, container, query); |
| 118 |
}); |
| 119 |
} else { |
| 120 |
loadMore.innerHTML = `<a href="/?s=${query.s}" ${query?.moreResultClickAction === "new_tab" ? `target="_blank"` : ""} class="sp-smart-post-search-load-more-button"> |
| 121 |
${viewMoreText}${ showCount ? (" " + data.remaining_posts + " + Posts") : ""} </a>`; |
| 122 |
} |
| 123 |
} else { |
| 124 |
loadMore.innerHTML = ""; |
| 125 |
} |
| 126 |
} |
| 127 |
}); |
| 128 |
}; |
| 129 |
searchContainers?.forEach((container) => { |
| 130 |
const searchForm = container.querySelector( |
| 131 |
".sp-smart-post-search-form" |
| 132 |
); |
| 133 |
|
| 134 |
let searchSettings = searchForm?.dataset?.search_settings ?? "{}"; |
| 135 |
searchSettings = safeJSONParse(searchSettings, {}); |
| 136 |
const blockWrapper = container.closest(".sp-smart-post-wrapper"); |
| 137 |
if (blockWrapper) { |
| 138 |
searchSettings.block = blockWrapper.id; |
| 139 |
if (searchSettings?.displayType === "popup") { |
| 140 |
const searchTrigger = blockWrapper.querySelector( |
| 141 |
"button.sp-smart-post-search-trigger-button" |
| 142 |
); |
| 143 |
|
| 144 |
if (searchTrigger) { |
| 145 |
searchTrigger.addEventListener("click", () => { |
| 146 |
container.classList.toggle( |
| 147 |
"sp-smart-post-search-popup--active" |
| 148 |
); |
| 149 |
const searchOverlay = blockWrapper.querySelector( |
| 150 |
".sp-smart-post-search-overlay" |
| 151 |
); |
| 152 |
if(searchOverlay) { |
| 153 |
searchOverlay.classList.toggle("sp-d-block"); |
| 154 |
|
| 155 |
searchOverlay.addEventListener("click", () => { |
| 156 |
container.classList.remove( |
| 157 |
"sp-smart-post-search-popup--active" |
| 158 |
); |
| 159 |
searchOverlay.classList.remove("sp-d-block"); |
| 160 |
}); |
| 161 |
} |
| 162 |
// Close button functionality |
| 163 |
const popupCloseBtn = container.querySelector( |
| 164 |
".sp-smart-post-popup-close-icon" |
| 165 |
); |
| 166 |
if ( popupCloseBtn ) { |
| 167 |
popupCloseBtn.addEventListener( "click", () => { |
| 168 |
container.classList.remove( |
| 169 |
"sp-smart-post-search-popup--active" |
| 170 |
); |
| 171 |
if(searchOverlay) { |
| 172 |
searchOverlay.classList.remove("sp-d-block"); |
| 173 |
} |
| 174 |
}); |
| 175 |
} |
| 176 |
|
| 177 |
}); |
| 178 |
} |
| 179 |
|
| 180 |
} |
| 181 |
} |
| 182 |
|
| 183 |
if (searchSettings?.isAjaxSearch) { |
| 184 |
const filter_fields = |
| 185 |
container?.querySelectorAll( |
| 186 |
".sp-smart-post-search-form select[name], .sp-smart-post-search-form input[name]" |
| 187 |
) || []; |
| 188 |
filter_fields?.forEach((field) => { |
| 189 |
const isInput = field.tagName === "INPUT"; |
| 190 |
const eventName = isInput ? "input" : "change"; |
| 191 |
|
| 192 |
// Add event listener. |
| 193 |
field?.addEventListener( |
| 194 |
eventName, |
| 195 |
isInput |
| 196 |
? debounce( |
| 197 |
(e) => |
| 198 |
eventHandler(e, container, searchSettings), |
| 199 |
400 |
| 200 |
) |
| 201 |
: (e) => eventHandler(e, container, searchSettings) |
| 202 |
); |
| 203 |
}); |
| 204 |
} else { |
| 205 |
searchForm?.addEventListener("submit", (event) => { |
| 206 |
event.preventDefault(); |
| 207 |
}); |
| 208 |
} |
| 209 |
const resultDiv = container.querySelector(".sp-smart-post-search-results"); |
| 210 |
container.addEventListener( |
| 211 |
"blur", |
| 212 |
function (event) { |
| 213 |
// If focus moved *outside* the wrapper |
| 214 |
if (!container.contains(event.relatedTarget) && resultDiv ) { |
| 215 |
resultDiv.classList.remove("sp-smart-post-search-results--show"); // or your hide logic |
| 216 |
} |
| 217 |
}, |
| 218 |
true // IMPORTANT! useCapture to detect blur properly |
| 219 |
); |
| 220 |
}); |
| 221 |
}); |
| 222 |
|
| 223 |
document.addEventListener( "DOMContentLoaded", () => { |
| 224 |
// const popupSearchIcon = document.querySelectorAll(".sp-smart-post-wrapper .sp-smart-post-search-trigger"); |
| 225 |
const elements = document.querySelectorAll(".sp-smart-post-search-wrapper.sp-smart-post-search-popup"); |
| 226 |
if ( elements.length < 1 ) return; |
| 227 |
|
| 228 |
function adjustPosition() { |
| 229 |
elements.forEach( el => { |
| 230 |
const rect = el.getBoundingClientRect(); |
| 231 |
|
| 232 |
if ( (rect.width + rect.left) < window.innerWidth) { |
| 233 |
el.classList.remove("sp-popup-position-right"); |
| 234 |
el.classList.add("sp-popup-position-left"); |
| 235 |
} |
| 236 |
// If element goes past the right edge |
| 237 |
else if ( (rect.width + rect.left) > window.innerWidth) { |
| 238 |
el.classList.remove("sp-popup-position-left"); |
| 239 |
el.classList.add("sp-popup-position-right"); |
| 240 |
} |
| 241 |
}) |
| 242 |
} |
| 243 |
// Call when you show/move the element |
| 244 |
adjustPosition(); |
| 245 |
|
| 246 |
// Optional: also check on window resize |
| 247 |
window.addEventListener("resize", adjustPosition); |
| 248 |
}) |
| 249 |
|