-
-
Save balupton/854622 to your computer and use it in GitHub Desktop.
// History.js It! | |
// v1.0.1 - 30 September, 2012 | |
// https://gist.github.com/854622 | |
(function(window,undefined){ | |
// Prepare our Variables | |
var | |
History = window.History, | |
$ = window.jQuery, | |
document = window.document; | |
// Check to see if History.js is enabled for our Browser | |
if ( !History.enabled ) { | |
return false; | |
} | |
// Wait for Document | |
$(function(){ | |
// Prepare Variables | |
var | |
/* Application Specific Variables */ | |
contentSelector = '#content,article:first,.article:first,.post:first', | |
$content = $(contentSelector).filter(':first'), | |
contentNode = $content.get(0), | |
$menu = $('#menu,#nav,nav:first,.nav:first').filter(':first'), | |
activeClass = 'active selected current youarehere', | |
activeSelector = '.active,.selected,.current,.youarehere', | |
menuChildrenSelector = '> li,> ul > li', | |
completedEventName = 'statechangecomplete', | |
/* Application Generic Variables */ | |
$window = $(window), | |
$body = $(document.body), | |
rootUrl = History.getRootUrl(), | |
scrollOptions = { | |
duration: 800, | |
easing:'swing' | |
}; | |
// Ensure Content | |
if ( $content.length === 0 ) { | |
$content = $body; | |
} | |
// Internal Helper | |
$.expr[':'].internal = function(obj, index, meta, stack){ | |
// Prepare | |
var | |
$this = $(obj), | |
url = $this.attr('href')||'', | |
isInternalLink; | |
// Check link | |
isInternalLink = url.substring(0,rootUrl.length) === rootUrl || url.indexOf(':') === -1; | |
// Ignore or Keep | |
return isInternalLink; | |
}; | |
// HTML Helper | |
var documentHtml = function(html){ | |
// Prepare | |
var result = String(html) | |
.replace(/<\!DOCTYPE[^>]*>/i, '') | |
.replace(/<(html|head|body|title|meta|script)([\s\>])/gi,'<div class="document-$1"$2') | |
.replace(/<\/(html|head|body|title|meta|script)\>/gi,'</div>') | |
; | |
// Return | |
return result; | |
}; | |
// Ajaxify Helper | |
$.fn.ajaxify = function(){ | |
// Prepare | |
var $this = $(this); | |
// Ajaxify | |
$this.find('a:internal:not(.no-ajaxy)').click(function(event){ | |
// Prepare | |
var | |
$this = $(this), | |
url = $this.attr('href'), | |
title = $this.attr('title')||null; | |
// Continue as normal for cmd clicks etc | |
if ( event.which == 2 || event.metaKey ) { return true; } | |
// Ajaxify this link | |
History.pushState(null,title,url); | |
event.preventDefault(); | |
return false; | |
}); | |
// Chain | |
return $this; | |
}; | |
// Ajaxify our Internal Links | |
$body.ajaxify(); | |
// Hook into State Changes | |
$window.bind('statechange',function(){ | |
// Prepare Variables | |
var | |
State = History.getState(), | |
url = State.url, | |
relativeUrl = url.replace(rootUrl,''); | |
// Set Loading | |
$body.addClass('loading'); | |
// Start Fade Out | |
// Animating to opacity to 0 still keeps the element's height intact | |
// Which prevents that annoying pop bang issue when loading in new content | |
$content.animate({opacity:0},800); | |
// Ajax Request the Traditional Page | |
$.ajax({ | |
url: url, | |
success: function(data, textStatus, jqXHR){ | |
// Prepare | |
var | |
$data = $(documentHtml(data)), | |
$dataBody = $data.find('.document-body:first'), | |
$dataContent = $dataBody.find(contentSelector).filter(':first'), | |
$menuChildren, contentHtml, $scripts; | |
// Fetch the scripts | |
$scripts = $dataContent.find('.document-script'); | |
if ( $scripts.length ) { | |
$scripts.detach(); | |
} | |
// Fetch the content | |
contentHtml = $dataContent.html()||$data.html(); | |
if ( !contentHtml ) { | |
document.location.href = url; | |
return false; | |
} | |
// Update the menu | |
$menuChildren = $menu.find(menuChildrenSelector); | |
$menuChildren.filter(activeSelector).removeClass(activeClass); | |
$menuChildren = $menuChildren.has('a[href^="'+relativeUrl+'"],a[href^="/'+relativeUrl+'"],a[href^="'+url+'"]'); | |
if ( $menuChildren.length === 1 ) { $menuChildren.addClass(activeClass); } | |
// Update the content | |
$content.stop(true,true); | |
$content.html(contentHtml).ajaxify().css('opacity',100).show(); /* you could fade in here if you'd like */ | |
// Update the title | |
document.title = $data.find('.document-title:first').text(); | |
try { | |
document.getElementsByTagName('title')[0].innerHTML = document.title.replace('<','<').replace('>','>').replace(' & ',' & '); | |
} | |
catch ( Exception ) { } | |
// Add the scripts | |
$scripts.each(function(){ | |
var $script = $(this), scriptText = $script.text(), scriptNode = document.createElement('script'); | |
scriptNode.appendChild(document.createTextNode(scriptText)); | |
contentNode.appendChild(scriptNode); | |
}); | |
// Complete the change | |
if ( $body.ScrollTo||false ) { $body.ScrollTo(scrollOptions); } /* http://balupton.com/projects/jquery-scrollto */ | |
$body.removeClass('loading'); | |
$window.trigger(completedEventName); | |
// Inform Google Analytics of the change | |
if ( typeof window._gaq !== 'undefined' ) { | |
window._gaq.push(['_trackPageview', relativeUrl]); | |
} | |
// Inform ReInvigorate of a state change | |
if ( typeof window.reinvigorate !== 'undefined' && typeof window.reinvigorate.ajax_track !== 'undefined' ) { | |
reinvigorate.ajax_track(url); | |
// ^ we use the full url here as that is what reinvigorate supports | |
} | |
}, | |
error: function(jqXHR, textStatus, errorThrown){ | |
document.location.href = url; | |
return false; | |
} | |
}); // end ajax | |
}); // end onStateChange | |
}); // end onDomLoad | |
})(window); // end closure |
Great script! I have a problem with my home page though that is loading in the container if i hit the back button. What i want is every page except my home page to load inside the container. Is this possible to exclude a page from loading in the container div?
Is it possible to exclude specific strings like wp-admin.php, wp-login.php, index.php etc? How can i add a function that when i visit the home page (including with browser's back button) will just hide the $content div?
Help anyone i desperately need a solution on this. Please!
should note that this script throws an error if using jquery v1.9.0(latest version)
Error under jquery 1.9.0 is on
Sizzle.error = function( msg ) {
throw new Error( "Syntax error, unrecognized expression: " + msg );
};
In the jQuery 1.9 change log there is this: http://jquery.com/upgrade-guide/1.9/#jquery-htmlstring-versus-jquery-selectorstring
In my case, the response returned from documentHtml(data) doesn't start with a < (in my case it is a conditional for modernizr) is rejected by the new jquery selector parser.
changing the var documentHtml = function(html) to return $.parseHtml seems to work for me, though I haven't explored any follow on effects or issues.
// Return
return $.parseHTML(result);
You can also use Davis.js to Ajaxify/hijax you webpage:
see: http://78.47.126.11:3000
As far as I can see; the script makes an ajax call for the browser back-button and previously clicked links. Can you update this gist to show how to ensure that saved states/pages are retrieved from history instead of making a new ajax request?
The fix from genereddick works but ScrollTo is still broken with new versions of jQuery, since
Why already loaded javascript is not applied to new content in content div?
Zeokat you saved my day! thanks. Nice piece of code.
I am facing an issue. I want to run jaquery on the loaded page but it not working because the page is not loaded and jquery not hit i want to show an alert when the page is loaded but not work:
jQuery(document).ready(function() { alert("hello world"); )};
i put this code in footer file but not working
This a great script! Love it!
I did run into an issue when implemented with the new Google Tag Manager (GTM) with Google Analytics. If using GTM the _gaq.push event still fires but there is no link to an account id. You will see the event fire but it's posting to UA-XXXXX-XX. To quickly work around this, in GTM, I created a rule based on {event} that equals a value of 'pageView'. Then in the ajaxify-html5.js script I changed the following starting at 172:
Change to:
Pageviews are executing normally now. For more info on Google Tag Manager -- check out http://support.google.com/tagmanager/