1(function (){ 2 3 var queryParams = null; 4 var container = document.querySelector('.js-container-async'); 5 if (container) { 6 var filterTogglers = container.getElementsByClassName('js-toggle-filters'); 7 var content = container.querySelector('.ajax-posts__posts'); 8 var status = container.querySelector('.ajax-posts__status'); 9 } 10 11 function init() { 12 if (container) { 13 addEventListeners(); 14 setDefaults(); 15 } 16 } 17 18 /** 19 * Add event listeners 20 */ 21 function addEventListeners() { 22 // Add event listeners with event propagination 23 on(container,'click', 'a[data-filter]', function(event) { 24 handleFilterEvent(event.target); 25 event.preventDefault(); 26 return true; 27 }); 28 29 on(container, 'click', '.js-collapse-filterlist', function(event) { 30 toggleFilterListCollapse(event); 31 event.preventDefault(); 32 return true; 33 }); 34 35 on(container, 'click', '.js-reset-filters', function(event) { 36 resetFilters(); 37 event.preventDefault(); 38 return true; 39 }); 40 41 on(container, 'click', '.js-load-more', function(event) { 42 handleLoadMoreEvent(event.target); 43 event.preventDefault(); 44 return true; 45 }); 46 47 // Add event listner on all filter toggle buttons 48 [].slice.call(filterTogglers).forEach(function(button){ 49 button.addEventListener('click', toggleFilters) 50 }); 51 } 52 53 /** 54 * Set default query variables 55 */ 56 function setDefaults() { 57 queryParams = { 58 'id' : container.dataset.id || null, 59 'page' : null, 60 'tax' : {}, 61 'quantity': parseInt(container.dataset.quantity, 10) || 0, 62 'postType': container.dataset.postType || 'post', 63 'postStatus': container.dataset.postStatus || 'publish', 64 'orderby': container.dataset.orderby || 'date', 65 'order': container.dataset.order || 'DESC', 66 'multiselect': container.dataset.multiselect === 'true', 67 }; 68 } 69 70 /** 71 * Update query and get posts after filter change 72 * 73 * @param NodeElement filter Clicked filter 74 */ 75 function handleFilterEvent(filter) { 76 if (!filter.classList.contains('is-active')) { 77 // If we only allow one select per filter, deselect the other filter 78 if (!queryParams.multiselect) { 79 deSelectSiblingFilters(filter); 80 } 81 filter.classList.add('is-active'); 82 updateQueryParams({ 83 page: 1, 84 filter: filter.dataset.filter, 85 term: filter.dataset.term, 86 }); 87 } else { 88 filter.classList.remove('is-active'); 89 removeQueryParam(filter.dataset.filter, filter.dataset.term); 90 } 91 getAJAXPosts({reset: true}); 92 93 var t = $(".ajax-posts__posts"); 94 window.addEventListener( 95 "orientationchange", 96 function () { 97 t.isotope("layout"); 98 }, 99 !1 100 ); 101 setTimeout(function () { 102 t.isotope("layout"); 103 }, 500) 104 } 105 106 /** 107 * Deselect siblings filters when only one term per taxoomy is allowed 108 * 109 * @param NodeElement filter Clicked filter 110 */ 111 function deSelectSiblingFilters(filter) { 112 var selector = '.ajax-posts__filter.is-active[data-filter=' + filter.dataset.filter + ']'; 113 var activeSiblingFilters = container.querySelectorAll(selector); 114 activeSiblingFilters.forEach(function(siblingFilter) { 115 siblingFilter.classList.remove('is-active'); 116 removeQueryParam(siblingFilter.dataset.filter, siblingFilter.dataset.term); 117 }); 118 } 119 120 /** 121 * Get next page of posts 122 * 123 * @param NodeElement button Clicked load more button 124 */ 125 function handleLoadMoreEvent(button){ 126 updateQueryParams({ page: parseInt(button.dataset.page, 10) }) 127 getAJAXPosts({reset: false}); 128 } 129 130 /** 131 * Reset filters to empty values 132 */ 133 function resetFilters() { 134 // Convert nodeList to array to prevent fail on for each 135 var activeFilters = Array.prototype.slice.call(container.querySelectorAll('a[data-filter].is-active')); 136 137 // Remove active classes
138 activeFilters.forEach(function(filter){ 139 filter.classList.remove('is-active'); 140 }); 141 142 // Empty taxonomy from query 143 queryParams.tax = {}; 144 queryParams.page = 1; 145 getAJAXPosts({reset: true}); 146 } 147 148 /** 149 * Toggle the filter class. 150 * Called via event listeners 151 */ 152 function toggleFilters() { 153 container.classList.toggle('is-expanded-filters'); 154 155 } 156 157 function toggleFilterListCollapse(event) { 158 event.target.parentNode.parentNode.classList.toggle('is-collapsed'); 159 } 160 161 /** 162 * Update te query parameters based on the filter change 163 * 164 * @param Array params params that will be changed 165 */ 166 function updateQueryParams(params) { 167 queryParams.page = params.page; 168 169 // If we're also updating the taxonomy 170 if (params.filter) { 171 if (queryParams.tax.hasOwnProperty(params.filter)) { 172 queryParams.tax[params.filter].push(params.term); 173 } else { 174 queryParams.tax[params.filter] = [params.term]; 175 } 176 } 177 } 178 179 /** 180 * Remove a term from the set of query params 181 * 182 * @param string tax taxonomy of the term to remove 183 * @param {string term term to remove 184 */ 185 function removeQueryParam(tax, term) { 186 if (queryParams.tax.hasOwnProperty(tax)) { 187 if (queryParams.tax[tax].indexOf(term) > -1) { 188 queryParams.tax[tax].splice( queryParams.tax[tax].indexOf(term) , 1 ); 189 } 190 } 191 } 192 193 /** 194 * Show the Error Reponse div 195 */ 196 function showResponseMessage() { 197 status.style.display = 'block'; 198 status.scrollIntoView({behavior: "smooth"}); 199 } 200 201 /** 202 * Show the Error Reponse div 203 */ 204 function hideResponseMessage() { 205 status.style.display = 'none'; 206 } 207 208 /** 209 * Get new posts via Ajax 210 * 211 * Retrieve a new set of posts based on the created query 212 * 213 * @return string server side generated HTML 214 */ 215 function getAJAXPosts(args) { 216 217 // Set status to querying 218 container.classList.add('is-waiting'); 219 220 var request = new XMLHttpRequest(); 221 request.open('POST', filterPosts.ajaxUrl, true); 222 request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 223 request.timeout = 4000; // time in milliseconds 224 225 request.onload = function() { 226 227 //remove load more button 228 var loadMoreButton = content.querySelector('.js-load-more'); 229 if (loadMoreButton) { 230 content.removeChild(loadMoreButton.parentNode); 231 } 232 var response = JSON.parse(this.response); 233 if (this.status === 200) { 234 // If we have a succesfull query 235 if (response.success) { 236 // Hide error status button 237 hideResponseMessage(); 238 // If we have to remove the show more button 239 if (args.reset) { 240 content.innerHTML = response.data.content; 241 } else { 242 content.innerHTML += response.data.content; 243 } 244 } else { 245 status.innerHTML = response.data; 246 showResponseMessage(); 247 } 248 } else { 249 status.innerHTML = filterPosts.serverErrorMessage; 250 showResponseMessage(); 251 } 252 // Resolve status 253 container.classList.remove('is-waiting'); 254 }; 255 256 request.ontimeout = function() { 257 status.innerHTML = filterPosts.timeoutMessage; 258 showResponseMessage(); 259 container.classList.remove('is-waiting'); 260 } 261 262 request.send(objectToQueryString({ 263 action: 'process_filter_change', 264 nonce: filterPosts.nonce, 265 params: queryParams, 266 })); 267 } 268 269 /** 270 * Helper function for event delegation 271 * 272 * To add event listeners on dynamic content, you can add a listener 273 * on thewrapping container, find the dom-node that triggered 274 * the event and check if that node mach our 275 * 276 * @param NodeElement el wrapping element for the dynamic content 277 * @param string eventName type of event, e.g. click, mouseenter, etc 278 * @param string selector selector criteria of the element where the action should be on 279 * @param Function fn callback funciton 280 * @return Function The callback 281 */ 282 function on(el, eventName, selector, fn) { 283 var element = el; 284 285 element.addEventListener(eventName, function(event) { 286 var possibleTargets = element.querySelectorAll(selector); 287 288 var target = event.target; 289 290 for (var i = 0, l = possibleTargets.length; i < l; i++) { 291 var el = target; 292 var p = possibleTargets[i]; 293 294 while(el && el !== element) { 295 if (el === p) {
296 return fn.call(p, event); 297 } 298 299 el = el.parentNode; 300 } 301 } 302 }); 303 } 304 305 /** 306 * Convert an deep object to a url parameter list 307 * 308 * Boiled down from jQuery 309 * 310 * WordPress Ajax post request doesn't accept JSON, only form-urlencoded! 311 * Took me a while to get... 312 * 313 * Although seems not to be totally true: 314 * http://wordpress.stackexchange.com/questions/177554/allowing-admin-ajax-php-to-receive-application-json-instead-of-x-www-form-url 315 * 316 * But in this case we just convert the params object to a url encoded string, like our friend and foe jQuery does. 317 * 318 */ 319 function objectToQueryString(a) { 320 var prefix, s, add, name, r20, output; 321 s = []; 322 r20 = /%20/g; 323 add = function (key, value) { 324 // If value is a function, invoke it and return its value 325 value = ( typeof value == 'function' ) ? value() : ( value == null ? "" : value ); 326 s[ s.length ] = encodeURIComponent(key) + "=" + encodeURIComponent(value); 327 }; 328 if (a instanceof Array) { 329 for (name in a) { 330 add(name, a[name]); 331 } 332 } else { 333 for (prefix in a) { 334 buildParams(prefix, a[ prefix ], add); 335 } 336 } 337 output = s.join("&").replace(r20, "+"); 338 return output; 339 }; 340 341 /** 342 * Helper function to create URL parameters of deep object 343 * 344 * Boiled down from jQuery 345 */ 346 function buildParams(prefix, obj, add) { 347 var name, i, l, rbracket; 348 rbracket = /\[\]$/; 349 if (obj instanceof Array) { 350 for (i = 0, l = obj.length; i < l; i++) { 351 if (rbracket.test(prefix)) { 352 add(prefix, obj[i]); 353 } else { 354 buildParams(prefix + "[" + ( typeof obj[i] === "object" ? i : "" ) + "]", obj[i], add); 355 } 356 } 357 } else if (typeof obj == "object") { 358 // Serialize object item. 359 for (name in obj) { 360 buildParams(prefix + "[" + name + "]", obj[ name ], add); 361 } 362 } else { 363 // Serialize scalar item. 364 add(prefix, obj); 365 } 366 } 367 368 init(); 369 370}()); 371 372jQuery(document).ready(function($){ 373$(".ajax-post__filter-category li").click(function() { 374 375 $(this).addClass("is-active-m"); 376 $(this).siblings().removeClass("is-active-m"); 377 378 379}); 380 381});
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.