source.js
import 'promise-polyfill';
import 'whatwg-fetch';
if (!window.Promise) {
window.Promise = Promise;
}
export default class Ajaxload {
constructor(link, wrapper, options) {
this.link = document.querySelectorAll(link);
this.wrapper = document.querySelector(wrapper);
this.config = {
ajaxContent: '.js-content',
animationOut: 200,
animationIn: 200,
prefetch: false,
gsap: false,
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
};
Object.assign(this.config, options);
this.init();
}
init() {
Array.from(this.link).forEach(link => {
link.addEventListener('mouseover', e => this.fetchData(e));
link.addEventListener('click', e => this.isSessionReady(e));
});
window.addEventListener('popstate', () => {
const initPageJSON = sessionStorage.getItem('initPage');
const initPage = JSON.parse(initPageJSON);
event.state === null ? this.switchContent(initPage.title, initPage.content) : this.changeState();
});
document.addEventListener('DOMContentLoaded', () => {
sessionStorage.setItem('initPage', JSON.stringify({
content: this.wrapper.innerHTML,
title: document.title,
}));
});
}
fetchData(e) {
if ((e.target.dataset.ajaxnavprefetch === 'disabled') || (!this.config.prefetch === true)) return false;
const url = e.target.href;
if (sessionStorage.getItem(url) === null) {
fetch(url, {
headers: new Headers(this.config.headers),
})
.then((response) => {
if (!response.ok) {
throw Error(response.statusText);
}
return response;
})
.then(response => response.text())
.then(content => sessionStorage.setItem(url, JSON.stringify(content)))
.catch(error => console.log(error));
}
}
isSessionReady(e) {
e.preventDefault();
if (e.target.href === document.location.href) return false;
const source = e.target.href;
const content = sessionStorage.getItem(source);
sessionStorage[source] ? this.prepareContent(e, content) : this.refetchData(e, source);
}
prepareContent(e, content) {
let newDiv;
this.isJson(content) ? newDiv = JSON.parse(content) : newDiv = content;
if (this.config.gsap === false) {
return new Promise((resolve, reject) => {
this.fadeOut(this.wrapper, this.config.animationOut, () => resolve());
}).then(() => {
this.wrapper.firstChild.remove();
this.wrapper.innerHTML = newDiv;
this.setTitle();
this.setHistory(e, newDiv);
}).then(() => this.fadeIn(this.wrapper, this.config.animationIn))
.catch(error => console.warn(error));
} else {
console.log('gsap');
}
}
refetchData(e, source) {
fetch(source, {
headers: new Headers(this.config.headers),
})
.then((response) => {
if (!response.ok) {
throw Error(response.statusText);
}
return response;
})
.then(response => response.text())
.then(content => this.prepareContent(e, content))
.then(() => console.log('loaded fresh'))
.catch(error => console.log(error));
}
setHistory(e, newDiv) {
const stateObj = {
content: {
content: newDiv,
title: document.title,
},
url: e.target.href,
};
window.history.pushState(stateObj.content, '', stateObj.url);
}
changeState() {
if (event.state) {
const state = {
content: event.state.content,
title: event.state.title,
};
this.switchContent(state.title, state.content);
}
}
switchContent(title, content) {
if (this.config.gsap === false) {
return new Promise((resolve, reject) => {
this.fadeOut(this.wrapper, this.config.animationOut, () => resolve());
}).then(() => {
this.wrapper.firstChild.remove();
this.wrapper.innerHTML = content;
document.title = title;
}).then(() => this.fadeIn(this.wrapper, this.config.animationIn));
} else {
console.log('gsap');
}
}
//Helper
fadeOut(el, duration, cb) {
let s = el.style;
let step = 25 / (duration || 300);
s.opacity = s.opacity || 1;
(function fade() {
if ((s.opacity -= step) < 0) {
s.display = "block";
return cb();
}
return setTimeout(fade, 25);
})();
}
fadeIn(el, duration, display) {
let s = el.style,
step = 25 / (duration || 300);
s.opacity = s.opacity || 0;
s.display = display || "block";
(function fade() {
(s.opacity = parseFloat(s.opacity) + step) > 1 ? s.opacity = 1 : setTimeout(fade, 25);
})();
}
setTitle() {
if (document.querySelector(this.config.ajaxContent) === null) {
throw Error('Please check your ajaxContent Class');
return false;
}
const title = document.querySelector(this.config.ajaxContent).dataset.ajaxnavtitle;
document.title = title;
}
isJson(str) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}
}