1(function () { 2 'use strict'; 3 4 if (typeof marqAjax === 'undefined') return; 5 6 var sections = document.querySelectorAll('.case-studies-section'); 7 if (!sections.length) return; 8 9 sections.forEach(initSection); 10 11 function initSection(section) { 12 var action = section.dataset.ajaxAction || 'marq_filter_posts'; 13 var perPage = parseInt(section.dataset.perPage, 10) || 6; 14 var allowedCats = (section.dataset.allowedCats || '') 15 .split(',').map(function (n) { return parseInt(n, 10); }).filter(Boolean); 16 var byCategory = section.dataset.byCategory === '1'; 17 18 var grid = section.querySelector('.posts-grid, .case-studies-grid'); 19 var noPostsMsg = section.querySelector('.no-posts-message'); 20 var loadMoreRow = section.querySelector('.load-more-row'); 21 var loadMoreBtn = section.querySelector('.load-more-posts, .load-more-case-studies'); 22 var filterBtns = section.querySelectorAll('.filter-btn'); 23 var searchForm = section.querySelector('.search-form'); 24 var searchInput = section.querySelector('.search-input'); 25 var searchClear = section.querySelector('.search-clear'); 26 27 if (!grid) return; 28 29 var state = { 30 category: 'all', 31 search: '', 32 page: 1, 33 loading: false 34 }; 35 36 // Filter button clicks 37 filterBtns.forEach(function (btn) { 38 btn.addEventListener('click', function () { 39 if (state.loading) return; 40 var cat = btn.dataset.category;
41 setActiveFilter(btn); 42 if (searchInput) searchInput.value = ''; 43 toggleClearBtn(false); 44 state.category = cat; 45 state.search = ''; 46 state.page = 1; 47 fetchPosts({ append: false }); 48 }); 49 }); 50 51 // Search submit (Enter or magnifying glass click) 52 if (searchForm) { 53 searchForm.addEventListener('submit', function (e) { 54 e.preventDefault(); 55 if (state.loading) return; 56 state.search = searchInput ? searchInput.value.trim() : ''; 57 state.page = 1; 58 toggleClearBtn(state.search !== ''); 59 fetchPosts({ append: false }); 60 }); 61 } 62 63 // Clear search (X button) 64 if (searchClear) { 65 searchClear.addEventListener('click', function () { 66 if (state.loading) return; 67 if (searchInput) searchInput.value = ''; 68 state.search = ''; 69 state.page = 1; 70 toggleClearBtn(false); 71 fetchPosts({ append: false }); 72 }); 73 } 74 75 // Load more 76 if (loadMoreBtn) { 77 loadMoreBtn.addEventListener('click', function () { 78 if (state.loading) return; 79 state.page = parseInt(loadMoreBtn.dataset.page, 10) + 1; 80 fetchPosts({ append: true }); 81 }); 82 } 83 84 function toggleClearBtn(show) { 85 if (!searchClear) return; 86 if (show) { 87 searchClear.removeAttribute('hidden'); 88 } else { 89 searchClear.setAttribute('hidden', ''); 90 } 91 } 92 93 function setActiveFilter(activeBtn) { 94 filterBtns.forEach(function (b) { 95 b.classList.remove('active'); 96 if (!b.classList.contains('black_outline')) { 97 b.classList.add('black_outline'); 98 } 99 }); 100 activeBtn.classList.add('active'); 101 activeBtn.classList.remove('black_outline'); 102 } 103 104 function fetchPosts(opts) { 105 state.loading = true; 106 grid.classList.add('is-loading'); 107 108 var formData = new FormData(); 109 formData.append('action', action); 110 formData.append('nonce', marqAjax.nonce); 111 formData.append('category', state.category); 112 formData.append('search', state.search); 113 formData.append('page', state.page); 114 formData.append('per_page', perPage); 115 formData.append('by_category', byCategory ? '1' : '0'); 116 formData.append('allowed_cats', allowedCats.join(',')); 117 118 fetch(marqAjax.ajax_url, { 119 method: 'POST', 120 credentials: 'same-origin', 121 body: formData 122 }) 123 .then(function (r) { return r.json(); }) 124 .then(function (res) { 125 if (!res || !res.success) { 126 throw new Error('AJAX error'); 127 } 128 renderResponse(res.data, opts.append); 129 }) 130 .catch(function (err) { 131 console.error('marq AJAX:', err); 132 }) 133 .finally(function () { 134 state.loading = false; 135 grid.classList.remove('is-loading'); 136 }); 137 } 138 139 function renderResponse(data, append) { 140 var html = data.html || ''; 141 var hasMore = !!data.has_more; 142 var found = parseInt(data.found, 10) || 0; 143 var maxPages = parseInt(data.max_pages, 10) || 1; 144 145 if (append) { 146 grid.insertAdjacentHTML('beforeend', html); 147 } else { 148 grid.innerHTML = html; 149 } 150 151 // Toggle grid visibility + no-posts message 152 if (found === 0 && !append) { 153 grid.style.display = 'none'; 154 if (noPostsMsg) noPostsMsg.style.display = ''; 155 } else { 156 grid.style.display = ''; 157 if (noPostsMsg) noPostsMsg.style.display = 'none'; 158 } 159 160 // Load More button state
161 if (loadMoreBtn && loadMoreRow) { 162 loadMoreBtn.dataset.page = state.page; 163 loadMoreBtn.dataset.maxPages = maxPages; 164 loadMoreRow.style.display = hasMore ? '' : 'none'; 165 } 166 } 167 } 168})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.