328 lines
9.2 KiB
JavaScript
Executable File
328 lines
9.2 KiB
JavaScript
Executable File
(function (){
|
|
|
|
var queryParams = null;
|
|
var container = document.querySelector('.js-container-async');
|
|
if (container) {
|
|
var filterTogglers = container.getElementsByClassName('js-toggle-filters');
|
|
var content = container.querySelector('.ajax-posts__posts');
|
|
var status = container.querySelector('.ajax-posts__status');
|
|
}
|
|
|
|
function init() {
|
|
if (container) {
|
|
addEventListeners();
|
|
setDefaults();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add event listeners
|
|
*/
|
|
function addEventListeners() {
|
|
// Add event listeners with event propagination
|
|
on(container,'click', 'a[data-filter]', function(event) {
|
|
handleFilterEvent(event.target);
|
|
event.preventDefault();
|
|
return true;
|
|
});
|
|
|
|
on(container, 'click', '.js-load-more', function(event) {
|
|
handleLoadMoreEvent(event.target);
|
|
event.preventDefault();
|
|
return true;
|
|
});
|
|
|
|
on(container, 'click', '.js-reset-filters', function() {
|
|
resetFilters();
|
|
event.preventDefault();
|
|
return true;
|
|
});
|
|
|
|
// Add event listner on all filter toggle buttons
|
|
[].slice.call(filterTogglers).forEach(function(button){
|
|
button.addEventListener('click', toggleFilters)
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Set default query variables
|
|
*/
|
|
function setDefaults() {
|
|
queryParams = {
|
|
'page' : null,
|
|
'tax' : {},
|
|
'quantity': parseInt(container.dataset.quantity, 10) || 0,
|
|
'postType': container.dataset.postType || 'post',
|
|
'language': filterPosts.language || null,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Update query and get posts after filter change
|
|
*
|
|
* @param NodeElement filter Clicked filter
|
|
*/
|
|
function handleFilterEvent(filter) {
|
|
|
|
if (!filter.classList.contains('is-active')) {
|
|
filter.classList.add('is-active');
|
|
updateQueryParams({
|
|
page: 1,
|
|
filter: filter.dataset.filter,
|
|
term: filter.dataset.term,
|
|
});
|
|
} else {
|
|
filter.classList.remove('is-active');
|
|
removeQueryParam(filter.dataset.filter, filter.dataset.term);
|
|
}
|
|
getAJAXPosts({reset: true});
|
|
}
|
|
|
|
/**
|
|
* Get next page of posts
|
|
*
|
|
* @param NodeElement button Clicked load more button
|
|
*/
|
|
function handleLoadMoreEvent(button){
|
|
updateQueryParams({ page: parseInt(button.dataset.page, 10) })
|
|
getAJAXPosts({reset: false});
|
|
}
|
|
|
|
/**
|
|
* Reset filters to empty values
|
|
*/
|
|
function resetFilters() {
|
|
// Convert nodeList to array to prevent fail on for each
|
|
var activeFilters = Array.prototype.slice.call(container.querySelectorAll('a[data-filter].is-active'));
|
|
|
|
// Remove active classes
|
|
activeFilters.forEach(function(filter){
|
|
filter.classList.remove('is-active');
|
|
});
|
|
|
|
// Empty taxonomy from query
|
|
queryParams.tax = {};
|
|
queryParams.page = 1;
|
|
getAJAXPosts({reset: true});
|
|
}
|
|
|
|
/**
|
|
* Toggle the filter class.
|
|
* Called via event listeners
|
|
*/
|
|
function toggleFilters() {
|
|
container.classList.toggle('is-expanded-filters');
|
|
}
|
|
|
|
/**
|
|
* Update te query parameters based on the filter change
|
|
*
|
|
* @param Array params params that will be changed
|
|
*/
|
|
function updateQueryParams(params) {
|
|
queryParams.page = params.page;
|
|
|
|
// If we're also updating the taxonomy
|
|
if (params.filter) {
|
|
if (queryParams.tax.hasOwnProperty(params.filter)) {
|
|
queryParams.tax[params.filter].push(params.term);
|
|
} else {
|
|
queryParams.tax[params.filter] = [params.term];
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove a term from the set of query params
|
|
*
|
|
* @param string tax taxonomy of the term to remove
|
|
* @param {tring term term to remove
|
|
*/
|
|
function removeQueryParam(tax, term) {
|
|
if (queryParams.tax.hasOwnProperty(tax)) {
|
|
if (queryParams.tax[tax].indexOf(term) > -1) {
|
|
queryParams.tax[tax].splice( queryParams.tax[tax].indexOf(term) , 1 );
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Show the Error Reponse div
|
|
*/
|
|
function showResponseMessage() {
|
|
status.style.display = 'block';
|
|
status.scrollIntoView({behavior: "smooth"});
|
|
}
|
|
|
|
/**
|
|
* Show the Error Reponse div
|
|
*/
|
|
function hideResponseMessage() {
|
|
status.style.display = 'none';
|
|
}
|
|
|
|
/**
|
|
* Get new posts via Ajax
|
|
*
|
|
* Retrieve a new set of posts based on the created query
|
|
*
|
|
* @return string server side generated HTML
|
|
*/
|
|
function getAJAXPosts(args) {
|
|
|
|
// Set status to querying
|
|
container.classList.add('is-waiting');
|
|
|
|
var request = new XMLHttpRequest();
|
|
request.open('POST', filterPosts.ajaxUrl, true);
|
|
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
|
request.timeout = 4000; // time in milliseconds
|
|
|
|
request.onload = function() {
|
|
|
|
console.log(this.response);
|
|
|
|
//remove load more button
|
|
var loadMoreButton = content.querySelector('.js-load-more');
|
|
if (loadMoreButton) {
|
|
content.removeChild(loadMoreButton.parentNode);
|
|
}
|
|
var response = JSON.parse(this.response);
|
|
if (this.status === 200) {
|
|
// If we have a succesfull query
|
|
if (response.success) {
|
|
// Hide error status button
|
|
hideResponseMessage();
|
|
// If we have to remove the show more button
|
|
if (args.reset) {
|
|
content.innerHTML = response.data.content;
|
|
} else {
|
|
content.innerHTML += response.data.content;
|
|
}
|
|
} else {
|
|
status.innerHTML = response.data;
|
|
showResponseMessage();
|
|
}
|
|
} else {
|
|
status.innerHTML = filterPosts.serverErrorMessage;
|
|
showResponseMessage();
|
|
}
|
|
// Resolve status
|
|
container.classList.remove('is-waiting');
|
|
};
|
|
|
|
request.ontimeout = function() {
|
|
status.innerHTML = filterPosts.timeoutMessage;
|
|
showResponseMessage();
|
|
container.classList.remove('is-waiting');
|
|
}
|
|
|
|
request.send(objectToQueryString({
|
|
action: 'process_filter_change',
|
|
nonce: filterPosts.nonce,
|
|
params: queryParams,
|
|
}));
|
|
}
|
|
|
|
/**
|
|
* Helper function for event delegation
|
|
*
|
|
* To add event listeners on dynamic content, you can add a listener
|
|
* on thewrapping container, find the dom-node that triggered
|
|
* the event and check if that node mach our
|
|
*
|
|
* @param NodeElement el wrapping element for the dynamic content
|
|
* @param string eventName type of event, e.g. click, mouseenter, etc
|
|
* @param string selector selector criteria of the element where the action should be on
|
|
* @param Function fn callback funciton
|
|
* @return Function The callback
|
|
*/
|
|
function on(el, eventName, selector, fn) {
|
|
var element = el;
|
|
|
|
element.addEventListener(eventName, function(event) {
|
|
var possibleTargets = element.querySelectorAll(selector);
|
|
|
|
var target = event.target;
|
|
|
|
for (var i = 0, l = possibleTargets.length; i < l; i++) {
|
|
var el = target;
|
|
var p = possibleTargets[i];
|
|
|
|
while(el && el !== element) {
|
|
if (el === p) {
|
|
return fn.call(p, event);
|
|
}
|
|
|
|
el = el.parentNode;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Convert an deep object to a url parameter list
|
|
*
|
|
* Boiled down from jQuery
|
|
*
|
|
* WordPress Ajax post request doesn't accept JSON, only form-urlencoded!
|
|
* Took me a while to get...
|
|
*
|
|
* Although seems not to be totally true:
|
|
* http://wordpress.stackexchange.com/questions/177554/allowing-admin-ajax-php-to-receive-application-json-instead-of-x-www-form-url
|
|
*
|
|
* But in this case we just convert the params object to a url encoded string, like our friend and foe jQuery does.
|
|
*
|
|
*/
|
|
function objectToQueryString(a) {
|
|
var prefix, s, add, name, r20, output;
|
|
s = [];
|
|
r20 = /%20/g;
|
|
add = function (key, value) {
|
|
// If value is a function, invoke it and return its value
|
|
value = ( typeof value == 'function' ) ? value() : ( value == null ? "" : value );
|
|
s[ s.length ] = encodeURIComponent(key) + "=" + encodeURIComponent(value);
|
|
};
|
|
if (a instanceof Array) {
|
|
for (name in a) {
|
|
add(name, a[name]);
|
|
}
|
|
} else {
|
|
for (prefix in a) {
|
|
buildParams(prefix, a[ prefix ], add);
|
|
}
|
|
}
|
|
output = s.join("&").replace(r20, "+");
|
|
return output;
|
|
};
|
|
|
|
/**
|
|
* Helper function to create URL parameters of deep object
|
|
*
|
|
* Boiled down from jQuery
|
|
*/
|
|
function buildParams(prefix, obj, add) {
|
|
var name, i, l, rbracket;
|
|
rbracket = /\[\]$/;
|
|
if (obj instanceof Array) {
|
|
for (i = 0, l = obj.length; i < l; i++) {
|
|
if (rbracket.test(prefix)) {
|
|
add(prefix, obj[i]);
|
|
} else {
|
|
buildParams(prefix + "[" + ( typeof obj[i] === "object" ? i : "" ) + "]", obj[i], add);
|
|
}
|
|
}
|
|
} else if (typeof obj == "object") {
|
|
// Serialize object item.
|
|
for (name in obj) {
|
|
buildParams(prefix + "[" + name + "]", obj[ name ], add);
|
|
}
|
|
} else {
|
|
// Serialize scalar item.
|
|
add(prefix, obj);
|
|
}
|
|
}
|
|
|
|
init();
|
|
|
|
}()); |