User login

Load new content via AJAX and change the URL

Agaric wanted to know how to have a photo album where pictures would load when selected, without re-loading the rest of the page. The goal is to have the chosen picture load (with JQuery effects and any other coolness without a full page refresh) but to also have the URL in the address bar updates so people have a unique link back to the image.

Facebook does this, and the next time I was catching up on my friends' new album additions at 4 a.m. on a Sunday morning, I had to view source and see what was going on.

What looks like the key javascript code is copied below.

Indeed, the whole album page in the first place is loaded by AJAX– viewing source shows not the name of the album, or the Photo X of XX text, nor the Back to Album link, nor the Previous and Next buttons.

I'm pretty sure the code we care most about is the Javascript href.replace function, that it is where the URI is updated to match the AJAX-loaded page content.

<script type="text/javascript">
//<![CDATA[
(function(href) { var uri_re = /^(?:(?:[^:\/?#]+):)?(?:\/\/(?:[^\/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?/; href.replace(uri_re, function(all, path, query, frag) { if (frag) { var dst, src = path + (query ? '?' + query : ''); if (frag.charAt(0) == '/') { dst = frag.replace(/^\/+/, '/'); } else if (/&|=/.test(frag)) { var q = {}; var m = frag.match(/([^#]*)(#.*)?/); var arr = (query||'').split('&').concat((m[1]||'').split('&')); for (var i=0, length=arr.length; i<length; i++) { var t = arr[i].split('='); if (t.length && t[0] != '') { q[t[0]] = t[1]; } } var s = []; for (var i in q) { s.push(i+ (q[i]?'='+q[i]:'')); } dst = path+'?'+s.join('&')+(m[2]||''); } if (dst && dst != src) { window.location.replace(dst); } } }); })(window.location.href);Env={quickling_inactive_page_regex:"^\\\/(election08\\\/|logout\\.php|help\\.php|photos\\\/|ac\\.php|ajax\\\/emu\\\/h\\.php|ext\\\/|ads\\\/create\\\/|feeds\\\/|.+(\\?|&)fb95_opt_(in|out)|intern\\\/(?!example\\\/quickling))",method:"GET",dev:0,start:(new Date()).getTime(),ps_limit:5,ps_ratio:4,svn_rev:134874,static_base:"http:\/\/static.ak.fbcdn.net\/",ecdc_page_regex:"^\\\/(safe_image\\.php|ajax\\\/perf\\.php|profile\\.php|home\\.php|photo\\.php|album\\.php|photo_search\\.php|photos\\.php|wall\\.php|friends\\\/ajax\\\/filters\\.php|friends\\\/ajax\\\/friends\\.php|friends\\\/ajax\\\/selector\\.php|group\\.php|groups\\.php|friends\\\/$)"}; var onloadRegister = window.onloadRegister || function(h) { onloadhooks.push(h); }; var onloadhooks = window.onloadhooks || []; var onafterloadRegister = window.onafterloadRegister || function(h) { onafterloadhooks.push(h); }; var onafterloadhooks = window.onafterloadhooks || []; function wait_for_load(element, e, f) { f = bind(element, f, e); if (window.loaded) { return f(); } switch ((e || event).type) { case 'load': onloadRegister(f); return; case 'click': if (element.original_cursor === undefined) { element.original_cursor = element.style.cursor; } if (document.body.original_cursor === undefined) { document.body.original_cursor = document.body.style.cursor; } element.style.cursor = document.body.style.cursor = 'progress'; onafterloadRegister(function() { element.style.cursor = element.original_cursor; document.body.style.cursor = document.body.original_cursor; element.original_cursor = document.body.original_cursor = undefined; if (element.tagName.toLowerCase() == 'a') { var original_event = window.event; window.event = e; var ret_value = element.onclick.call(element, e); window.event = original_event; if (ret_value !== false && element.href) { window.location.href = element.href; } } else if (element.click) { element.click(); } }); break; } return false; }; function bind(obj, method ) { var args = []; for (var ii = 2; ii < arguments.length; ii++) { args.push(arguments[ii]); } var fn = function() { var _obj = obj || (this == window ? false : this); var _args = args.slice(); for (var jj = 0; jj < arguments.length; jj++) { _args.push(arguments[jj]); } if (typeof(method) == "string") { if (_obj[method]) { return _obj[method].apply(_obj, _args); } } else { return method.apply(_obj, _args); } }; if (typeof method == 'string') { fn.name = method; } else if (method) { if (method.name) { fn.name = method.name; } fn.toString = function() { return 'bound<'+method.toString()+'>'; } } return fn; }; function goURI(uri) { uri = uri.toString(); if (window.PageTransitions && PageTransitions.isInitialized()) { PageTransitions.go(uri); } else if (window.location.href == uri) { window.location.reload(); } else { window.location.href = uri; } } var PrimordialBootloader = window.PrimordialBootloader || { loaded : [], done : function(names) { PrimordialBootloader.loaded.push(names); } }; var Bootloader = window.Bootloader || { done : PrimordialBootloader.done };document.cookie = "cavalry_transit_start_time=; expires=Mon, 26 Jul 1997 05:00:00 GMT; path=\/; domain=.facebook.com";
//]]>
</script>

Resolution

Searched words: 
autoload AJAX-changing content with new unique URL URI change browser bar address while browsing photo album

Comments

Post new comment

The content of this field is kept private and will not be shown publicly.
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.
  • You can use Markdown syntax to format and style the text. Also see Markdown Extra for tables, footnotes, and more.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <img> <blockquote> <small> <h2> <h3> <h4> <h5> <h6> <sub> <sup> <p> <br> <strike> <table> <tr> <td> <thead> <th> <tbody> <tt> <output>
  • Lines and paragraphs break automatically.

More information about formatting options

By submitting this form, you accept the Mollom privacy policy.