Drupal 7 ajax page navigation with history

Many clients these days ask for ajax enabled sites for smooth navigation between pages (here's an example http://debbievinick.com). To achieve such behaviour and maintain backwards compatibility with non-javascript browsing (of most interest in that category are search spiders, e.g. Googlebot) the fundamental problem is that for each page you must serve two versions: 1 full page for when you land on the url directly, and 1 ajax version which just returns the content to be updated.

...or do you?

The speed benefits from having ajax navigation don't really come from serving fewer bytes to load page, but from not having to re-render the entire page, and re-parse all your JavaScript and CSS. A simple solution when using a CMS is just to fetch the entire page you want to update the content for, and then extract the section you need.

The following implementation is based on a simple Drupal installation with the Zen theme: http://drupal.org/project/zen

Consider we have 3 pages (/home, /contact, /about) with this basic structure:

<html>
	<head><title><title />...</head>
	<body>
		<div id="header">...</div>
		<div id="mainwrapper">
			<div id="main">
				<div id="content"></div>
				<div id="navigation"></div>
			</div>
		</div>
		<div id="footer">...</div>
	</body>
</html>

The only content changes from page to page is div#main and title

Using jQuery's ajax load function we can specific a part of the HTML tree from the result we want to use by adding a selector:

$('#main-wrapper').load('/about #main');

If run from /home this would fetch the contents of /about, extract the HTML from div#main and overwrite the current contents of div#wrapper with it. This is the bulk of the functionality we require but there are still a few improvements.

Firstly the title of the page is outside div#main and is not updated. This can fixed fairly simply:

var loadPage = function(path) {
	$('#main-wrapper').load(path + ' #main', function(response) {
		var title = response.match(/<title>([^<]+)<\/title>/)[1];
		try {
			$('title').html(title);
		} catch(e) {
			var titleText = $('<div/>').html(title).text();
			document.title = titleText;
		}
	});
};

Setting the title is a little complex because of they way different browsers expect plain text or HTML. You can use whichever technique you prefer.

The other major issue is page state. Click the link to navigate to /about from /home, and then reloading the page would take you back to /home. This is where the history.js library comes in. If you are using Drupal you can drop in the library using this module: http://drupal.org/project/history_js (NB history.js is incompatible with the Overlay module, so you'll have to disable it)

Now we need to do two things: set up the ajax navigation on the main menu links, and pass the state change events through to our loadPage function:

var initMenu = function() {
	$('#main-menu a').each(function() {
		var path = ($(this).attr('pathname').substr(0, 1) != '/') ?
			'/' + $(this).attr('pathname') :
			$(this).attr('pathname');
		$(this).click(function() {
			History.pushState(null, null, path);
			return false;
		});
	});
};
$(document).ready(function() {
	initMenu();
	History.Adapter.bind(window, 'statechange', function() {
		var State = History.getState();
		loadPage(State.url);
	});
});

In older browsers history.js will use hash links to store the page state. If you were to reload a page at /home#./about we can add a bit of code to redirect you to /about :

if(location.hash.substr(0, 3) == '#./') {
	location.href = location.hash.substr(3);
}

We can further optimise by storing loaded page data and titles in memory, so if a page is navigated back to we don't even need to perform an ajax request:

var pageCache = {};
 
var loadPage = function(path) {
	if(pageCache[path]) {
		$('#main-wrapper').html(pageCache[path].body);
		writePage(pageCache[path].title, path);
	} else {
		$('#main-wrapper').load(path + ' #main', function(response) {
			var title = response.match(/<title>([^<]+)<\/title>/)[1];
			pageCache[path] = {
				body: $(this).html(),
				title: title
			}
			writePage(title, path);
		});
	}
};
 
var writePage = function(title, path) {
	initMenu();
	try {
		$('title').html(title);
	} catch(e) {
		var titleText = $('<div/>').html(title).text();
		document.title = titleText;
	}
};

In the final script we add Google Analytics tracking (if you have it) and an option to fade content in and out:

(function($) {
 
	var History = window.History;
	if ( !History.enabled ) {
		return false;
	}
 
	if(location.hash.substr(0, 3) == '#./') {
		location.href = location.hash.substr(3);
	}
 
	var _wrapper = '#main-wrapper';
	var _contents = '#main';
	var _menu = '#main-menu a';
	// set _fade to a selector you want to fade-in/out
	// on page change, e.g. '#content .content'
	var _fade = null;
 
	var initMenu = function() {
		$(_menu).each(function() {
			var path = ($(this).attr('pathname').substr(0, 1) != '/') ?
				'/' + $(this).attr('pathname') :
				$(this).attr('pathname');
			$(this).click(function() {
				History.pushState(null, null, path);
				return false;
			});
		});
	};
 
	var pageCache = {};
 
	var loadPage = function(path) {
		if(_fade) $(_fade).fadeOut('fast');
		if(pageCache[path]) {
			$(_wrapper).html(pageCache[path].body);
			writePage(pageCache[path].title, path);
		} else {
			$(_wrapper).load(path + ' ' + _contents, function(response) {
				var title = response.match(/<title>([^<]+)<\/title>/)[1];
				pageCache[path] = {
					body: $(this).html(),
					title: title
				};
				writePage(title, path);
			});
		}
	};
 
	var writePage = function(title, path) {
		if(_fade) $(_fade).hide().fadeIn('fast');
		initMenu();
		try {
			$('title').html(title);
		} catch(e) {
			var titleText = $('<div/>').html(title).text();
			document.title = titleText;
		}
		if(typeof _gaq != 'undefined') _gaq.push(['_trackPageview', path]);
	};
 
	$(document).ready(function() {
		initMenu();
		History.Adapter.bind(window, 'statechange', function() {
			var State = History.getState();
			loadPage(State.url);
		});
		pageCache[History.getState().url] = {
			body: $(_wrapper).html(),
			title: $('title').html()
		};
	});
 
})(jQuery);

Download here: https://github.com/edg2s/drupal-ajax-navigation

Comments

Any ideas to implement this to views infinite scroll as opposed to menu items?

Thanks a lot for this nice peace of code well documented. I just had to change line 16 of nav.js : 'wrapper': '#main-wrapper', by 'wrapper': '#main', to make to loading works.

Thanks for sharing. Nicolas

You shouldn't need to edit the code file directly, you can pass in a configurations object to init(). See the usage notes on GitHub.

roulette doc free - roulette games
roulette free play free roulette
https://roulettecas.com/

roulette doc free - roulette games
roulette free play free roulette
https://roulettecas.com/

веселая обезьянка играть онлайн
жетоны для игровых автоматов
https://cazinovulkan777.ru/14995-igrovye-avtomaty-onlajn-igrat-besplatno... игровые автоматы онлайн играть бесплатно и без регистрации свиньи
а

веселая обезьянка играть онлайн
жетоны для игровых автоматов
https://cazinovulkan777.ru/14995-igrovye-avtomaty-onlajn-igrat-besplatno... игровые автоматы онлайн играть бесплатно и без регистрации свиньи
а

amoxicillin suspension cost, buy benadryl original, generic wellbutrin xl cost, buy ventolin online cheap, cost of warfarin therapy, cost of phenazopyridine, order prednisolone 5mg online, motrin wholesale, can i buy celebrex in mexico, amoxil buy, buy generic lipitor india, can you buy viagra over the counter in bahrain, no rx lasix, can viagra be purchased over the counter in usa, ketoconazole cream where to buy, buy metformin online in uk, respiratory solution buy ventolin, alli uk order, benadryl bulk buy, how much does advair diskus cost, can you still buy nizoral shampoo

amoxicillin suspension cost, buy benadryl original, generic wellbutrin xl cost, buy ventolin online cheap, cost of warfarin therapy, cost of phenazopyridine, order prednisolone 5mg online, motrin wholesale, can i buy celebrex in mexico, amoxil buy, buy generic lipitor india, can you buy viagra over the counter in bahrain, no rx lasix, can viagra be purchased over the counter in usa, ketoconazole cream where to buy, buy metformin online in uk, respiratory solution buy ventolin, alli uk order, benadryl bulk buy, how much does advair diskus cost, can you still buy nizoral shampoo

cialis brand cheap, how do i cancel my acai berry order colon cleanse, buy zithromax overnight shipping, buy acai berry weight loss, linezolid buy online, where to buy cheap clomid online, amoxicillin over the counter uk, buy cheap viagra online with prescription, retin-a micro buy, abilify cost 5mg, proscar order online benign prostatic hyperplasia, dilantin purchase online, where can i buy misoprostol in johannesburg, buy differin 0.1 gel, how much does allegra cost over the counter, pravachol cost generic, oxcarbazepine generic cost, order furosemide prescription, buy lamisil liquid spray, kamagra us cheap, cost of atorvastatin calcium

how much does estrace pills cost, over the counter medicine similar to acyclovir, mail order avodart, purchase atorvastatin calcium, prilosec contraindications no prescription needed, vs buy generic nexium, buy cialis online in usa drugs, purchase metronidazole online without prescription, can you buy benadryl in the uk, buying viagra online is it safe, can you order zithromax online, cost of isotretinoin with insurance, yasmin pill buy ortho tri cyclen, hydroxyurea 500 mg cost, clomid order buy, buying amoxicillin without prescription, buy celecoxib online, erythromycin benzoyl peroxide topical gel buy, new over the counter weight loss drug uk xenical, why does flovent cost so much, online buy prednisone

how much does estrace pills cost, over the counter medicine similar to acyclovir, mail order avodart, purchase atorvastatin calcium, prilosec contraindications no prescription needed, vs buy generic nexium, buy cialis online in usa drugs, purchase metronidazole online without prescription, can you buy benadryl in the uk, buying viagra online is it safe, can you order zithromax online, cost of isotretinoin with insurance, yasmin pill buy ortho tri cyclen, hydroxyurea 500 mg cost, clomid order buy, buying amoxicillin without prescription, buy celecoxib online, erythromycin benzoyl peroxide topical gel buy, new over the counter weight loss drug uk xenical, why does flovent cost so much, online buy prednisone

cost gabapentin 300 mg, kamagra cheapest price, buy letrozole femara online, where can i buy xenical in ireland, protonix without a prescription, prednisolone for sale uk, purchase terramycin, where to buy orlistat 120mg uk, prevacid as needed no prescription required, differin gel purchase, viagra to buy, advair cost rite aid, metoclopramide codeine over the counter, viagra online without a prescription generic drugs, cyproheptadine for sale, purchase valtrex no prescription, buying viagra on broadband, prednisone epocrates search buy, order vicodin no prescription no membership generic viagra online, buy online lithium carbonate, do i need prescription to buy zovirax

wellbutrin xl 150 mg cost, where to buy cialis in india, houses for sale in montrose artane, buy tamoxifen citrate research chemicals, buy whole acai berry products, zithromax suspension cost, how much does abilify cost, cheap propranolol no prescription, codeine cough syrup buy promethazine, vs cipro buy zithromax, zyrtec d buy nasal decongestant, buy best hoodia, where can i buy permethrin 5, hyaluronic acid cost source naturals, azithromycin to order, cheap lasix for dogs, what is the cost of flonase, buy reminyl online, buy viagra legally, misoprostol cost in canada, buy acai farms

sales buy januvia, baclofen cost in india, synthroid to buy, how much does sotalol cost, order advil ibuprofen, betamethasone cream buy online uk, warning buy acai, buy strattera without prescription, injection buy mestinon online, during pregnancy zithromax without prescription, buy levoxyl uk, voli low cost roma cipro, where to buy ketoconazole oral, extreme acai berry where to buy, where can i buy prilosec otc, purchase nexium medications, wisconsin ginseng for sale, metronidazole buy over the counter, cheap januvia, order real viagra online, order brand viagra generic medications

sales buy januvia, baclofen cost in india, synthroid to buy, how much does sotalol cost, order advil ibuprofen, betamethasone cream buy online uk, warning buy acai, buy strattera without prescription, injection buy mestinon online, during pregnancy zithromax without prescription, buy levoxyl uk, voli low cost roma cipro, where to buy ketoconazole oral, extreme acai berry where to buy, where can i buy prilosec otc, purchase nexium medications, wisconsin ginseng for sale, metronidazole buy over the counter, cheap januvia, order real viagra online, order brand viagra generic medications

buy baclofen in canada, viagra nei sexy shop cheap, losartan hctz 100-25 cost, zantac 150 cost acid indigestion, cost keflex, buy root korean ginseng tea, mail order casodex, omeprazole 40 mg buy, samantha luvox cheap, buying real viagra online, buy nolvadex clomid uk, can you buy permethrin 5 cream over the counter, viagra online for sale, uk viagra paypal, buy propecia china, buy cipro without prescription urinary tract infections, fosamax no prescription online pharmacy, how much does pantoprazole cost, buy nizoral in canada, buy carbatrol carbamazepine extended release, canadian cialis no prescription

buy baclofen in canada, viagra nei sexy shop cheap, losartan hctz 100-25 cost, zantac 150 cost acid indigestion, cost keflex, buy root korean ginseng tea, mail order casodex, omeprazole 40 mg buy, samantha luvox cheap, buying real viagra online, buy nolvadex clomid uk, can you buy permethrin 5 cream over the counter, viagra online for sale, uk viagra paypal, buy propecia china, buy cipro without prescription urinary tract infections, fosamax no prescription online pharmacy, how much does pantoprazole cost, buy nizoral in canada, buy carbatrol carbamazepine extended release, canadian cialis no prescription

Pages

Add new comment