Created
December 10, 2015 16:36
-
-
Save adamduncan/15659b15182e36a8aec5 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//---------------------------------------------------------------------- | |
// HISTORY API | |
// Base Package | |
//---------------------------------------------------------------------- | |
var HistoryAPI = { | |
contentId: 'content', | |
content: document.getElementById('content'), | |
animateClass: 'history-content--animate-out', | |
rootLoadingClass: 'html--page-loading', | |
animationDuration: 300, | |
init: function () { | |
// exit early if no support | |
if (!Modernizr.history) return; | |
// loop over local links, and pass callback to bind clicks | |
this.localLinksLoop(this.bindClickEvent); | |
// bind popstate event | |
this.bindPopstate(); | |
}, | |
bindPopstate: function () { | |
// set timeout (? check Dive into HTML5 as to why this is needed) | |
window.setTimeout(function () { | |
// add event listener event to window | |
window.addEventListener("popstate", function (e) { | |
// don't pop content for hashchanges - may need removing hash improvements | |
if (!window.location.hash) { | |
// use same loadEvents method as pushState, passing new pop'd href | |
HistoryAPI.loadEvents(window.location.href); | |
} | |
}, false); | |
}, 1); | |
}, | |
localLinksLoop: function (callback) { | |
// store all link elements and localhost value | |
var allLinks = document.querySelectorAll('a'), | |
localHost = window.location.host; | |
// loop over all links on page | |
for (var i = 0; i < allLinks.length; i++) { | |
var thisLink = allLinks[i]; | |
// if internal link and not hashed and target isn't _blank | |
if (thisLink.host === localHost && !thisLink.hash && thisLink.target !== '_blank') { | |
// run callback to, passing link | |
callback(thisLink); | |
} | |
} | |
}, | |
bindClickEvent: function (link) { | |
// add click event listener | |
link.addEventListener('click', function (e) { | |
// store link href and normalized trailing slash version (no querystring, no slash, no extension) | |
var linkHref = link.href, | |
hasQuery = (linkHref.indexOf('?') > -1), | |
hasSlash = linkHref.substr(-1) === '/', | |
hasExtension = linkHref.split('/')[linkHref.split('/').length - 1].indexOf('.') > -1, | |
slashedHref = (!hasQuery && !hasSlash && !hasExtension) ? linkHref + '/' : linkHref; | |
// prevent default for all | |
e.preventDefault(); | |
// if current page, do nothing further | |
if (window.location.href === linkHref) { | |
return; | |
// otherwise call to get content and push state | |
} else { | |
// call to get content, passing callback | |
HistoryAPI.loadEvents(slashedHref); | |
// call to push history | |
HistoryAPI.historyPush(slashedHref); | |
}; | |
}, false); | |
}, | |
loadEvents: function (href) { | |
// call to run unload state | |
HistoryAPI.pageUnload(); | |
// call to get content, passing href and callback | |
HistoryAPI.getContent(href, HistoryAPI.pageLoad); | |
}, | |
getContent: function (href, callback) { | |
// construct new request | |
var request = new XMLHttpRequest(); | |
// open request, passing method, url and async boolean | |
request.open('GET', href, true); | |
// set up ready event handler | |
request.onreadystatechange = function () { | |
// test response codes | |
if (this.readyState === 4) { | |
if (this.status >= 200 && this.status < 400) { | |
// success | |
// run callback, passing response | |
callback(this.responseText); | |
} else { | |
// error handling TBD | |
console.log('Error: ' + this.statusText); | |
// potentially force-send user to target page? | |
window.location.href = href; | |
} | |
} | |
}; | |
// send the request and clear | |
request.send(); | |
request = null; | |
}, | |
pageUnload: function () { | |
// add class to root for any loading-related styles | |
Constants.root.classList.add(HistoryAPI.rootLoadingClass); | |
// add class to animate content out with CSS3 | |
HistoryAPI.content.classList.add(HistoryAPI.animateClass); | |
}, | |
pageLoad: function (response) { | |
// set timeout to allow animation delay play out | |
var animateTimeout = setTimeout(function () { | |
// create element to parse response as html | |
var newElement = document.createElement('div'); | |
// populate new element | |
newElement.innerHTML = response; | |
// update content in page | |
HistoryAPI.content.innerHTML = newElement.querySelector('#content').innerHTML; | |
// remove class to root for any loading-related styles | |
Constants.root.classList.remove(HistoryAPI.rootLoadingClass); | |
// remove animation classes to show | |
HistoryAPI.content.classList.remove(HistoryAPI.animateClass); | |
// loop over local links, and pass callback to bind clicks | |
HistoryAPI.localLinksLoop(HistoryAPI.bindClickEvent); | |
}, HistoryAPI.animationDuration); | |
}, | |
historyPush: function (link) { | |
// push state via history api | |
history.pushState(null, null, link); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment