Skip to content

Instantly share code, notes, and snippets.

@cyrusbeer
Created September 13, 2012 11:29
Show Gist options
  • Save cyrusbeer/3713706 to your computer and use it in GitHub Desktop.
Save cyrusbeer/3713706 to your computer and use it in GitHub Desktop.
$(function( $ ) {
$(document).ready(function() {
$(".ajax-intercept").ajaxInterceptor({
pageElementToUpdateSelector: "div#content",
showLoadingMessage: true,
showLoadingDelayMillis: 600,
loadingMessage: 'Loading...',
loadingMessageSelector: 'div.loading-message'
});
});
});
/*
* Author: Cyrus Beer
* 9/13/2012
* Requires: history.js, history.adapter.jquery.js, json2.js
*/
(function($) {
var settings = {
'pageElementToUpdateSelector' : undefined, // The selector for the page element that will be updated
'showLoadingMessage' : true,
'loadingMessageDelay': 600, // with these defaults, if the ajax call takes > .6 seconds, a loading message will show until the ajax call completes.
'loadingMessage': 'Loading...',
'loadingMessageSelector': 'div.loading-message'
};
var History = null;
var selector = '';
var lastUrlLoaded;
var methods = {
init : function(options) { // Initializes the plugin
selector = this.selector;
if (options) {
$.extend(settings, options);
}
if (settings.pageElementToUpdateSelector === null) {
$.error('Missing required parameter pageElementToUpdateSelector on jQuery.ajaxInterceptor');
return;
}
if (methods.supported()) {
methods.bindEvents.call($(this));
}
return $(this);
},
// If the browser does not support HTML 5, the ajax interceptor does not get called
// so it degrades nicely.
supported: function() {
History = window.History;
return History.enabled;
},
bindEvents: function() {
$(selector).off('click').on('click', function(e) {
e.preventDefault();
// allow a link to override the pageElementToUpdateSelector if need be.
if ($(this).attr('pageElementToUpdateSelector')) {
settings.pageElementToUpdateSelector = $(this).attr('pageElementToUpdateSelector');
}
var url = $(this).attr('href');
History.pushState({url:url}, '', url);
return false;
});
// Bind state change for preserving back/forwards browser button functionality when loading ajax
History.Adapter.bind(window, 'statechange', function(e) {
var state = History.getState();
if (state !== null && state.url != lastUrlLoaded) {
methods.loadContent(state.url);
lastUrlLoaded = state.url;
}
});
},
// Loads the ajax content
loadContent: function(url) {
var destination = $(settings.pageElementToUpdateSelector);
$.ajax({
url:url,
data: {'page_element_to_update_selector':settings.pageElementToUpdateSelector},
method:'GET',
beforeSend: function(xhr) {
if (settings.showLoadingMessage === true) {
$.showLoadingMessage({
delay:settings.loadingMessageDelay,
message:settings.loadingMessage,
selector:settings.loadingMessageSelector
});
}
},
complete: function(xhr, status) {
if (settings.showLoadingMessage === true) {
$.hideLoadingMessage({selector:settings.loadingMessageSelector});
}
},
success: function(ajaxHtml) {
destination.html(ajaxHtml);
document.title = $(ajaxHtml).filter("div#page_title").text();
if (typeof settings.ready == 'function') { // Fire the callback
settings.ready.call($(this), url);
}
},
// on error, send the url to the browser, so the error will be clearly visible
error: function(jqXHR, textStatus, errorThrown) {
window.location = url;
}
});
}
};
$.fn.ajaxInterceptor = function(method) {
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
}
else if (typeof method === 'object' || !method) {
return methods.init.apply(this, arguments);
}
else {
$.error('Method ' + method + ' does not exist on jQuery.ajaxInterceptor');
}
};
$.showLoadingMessage = function(optionsOverride){
var options = {
message:'Loading...',
delay: 0,
selector: undefined
};
$.extend(options, optionsOverride);
if (options.delay > 0) {
$(document).data("_loading_timeout", setTimeout(function() { $.showLoadingMessageNow(options)}, options.delay));
} else {
$.showLoadingMessageNow(options);
}
};
$.showLoadingMessageNow = function(options){
//if this element has delayed mask scheduled then remove it and display the new one
if ($(document).data("_loading_timeout") !== undefined) {
clearTimeout($(document).data("_loading_timeout"));
$(document).removeData("_loading_timeout");
}
$(options.selector)
.html(options.message)
.show();
};
$.hideLoadingMessage = function(options){
//if this element has delayed mask scheduled then remove it
if ($(document).data("_loading_timeout") !== undefined) {
clearTimeout($(document).data("_loading_timeout"));
$(document).removeData("_loading_timeout");
}
$(options.selector).hide();
};
})(jQuery);
#{if (!params.page_element_to_update_selector)}
<!DOCTYPE html>
<html>
<head>
<title>#{get 'title' /}</title>
<meta charset="${_response_encoding}">
#{stylesheet 'main.css' /}
#{stylesheet 'bootstrap.min.css' /}
#{/if}
#{get 'moreStyles' /}
#{if (!params.page_element_to_update_selector)}
<link rel="shortcut icon" type="image/png" href="@{'/public/images/favicon.png'}">
#{script 'jquery-1.8.1.min.js' /}
#{script 'history.js' /}
#{script 'history.adapter.jquery.js' /}
#{script 'json2.js' /}
#{script 'jquery.ajax.interceptor.js' /}
#{script 'application.js' /}
#{/if}
#{get 'moreScripts' /}
#{if (!params.page_element_to_update_selector)}
</head>
<body>
<div class="navbar">
<div class="navbar-inner">
<a class="brand" href="#">Company XYZ</a>
<ul class="nav">
<li name="heading1" class="active"><a href="/" class="ajax-intercept">Heading 1</a></li>
<li name="heading2"><a href="/page2" class="ajax-intercept">Heading 2</a></li>
</ul>
</div>
</div>
<div class="loading-message"></div>
<div class="container" id="content">
#{/if}
<div style="display:none" id="page_title">#{get 'title' /}</div>
#{doLayout /}
#{if (!params.page_element_to_update_selector)}
</div>
</body>
</html>
#{/if}
#{extends 'main.html' /}
#{set title:'Page 2' /}
#{set 'moreScripts'}
#{script 'script-to-load-only-on-this-page.js' /}
#{/set}
<script type="text/javascript">
$(document).ready(function() {
$("div.navbar-inner li.active").removeClass("active");
$("div.navbar-inner li[name='heading2']").addClass("active");
});
</script>
<h2>Page 2</h2>
<br/><br/>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment