./lib/assets/javascripts/pjax/jquery_pjax.js in pjax_rails-0.1.8 vs ./lib/assets/javascripts/pjax/jquery_pjax.js in pjax_rails-0.1.9
- old
+ new
@@ -1,9 +1,11 @@
-// jquery_pjax.js
+// jquery.pjax.js
// copyright chris wanstrath
-// https://github.com/defunkt/pjax
+// https://github.com/defunkt/jquery-pjax
+(function($){
+
// When called on a link, fetches the href with ajax into the
// container specified as the first parameter or with the data-pjax
// attribute on the link itself.
//
// Tries to make sure the back button and ctrl+click work the way
@@ -25,19 +27,28 @@
if ( options )
options.container = container
else
options = $.isPlainObject(container) ? container : {container:container}
+ // We can't persist $objects using the history API so we must use
+ // a String selector. Bail if we got anything else.
+ if ( options.container && typeof options.container !== 'string' ) {
+ throw "pjax container must be a string selector!"
+ return false
+ }
+
return this.live('click', function(event){
// Middle click, cmd click, and ctrl click should open
// links in a new tab as normal.
if ( event.which > 1 || event.metaKey )
return true
var defaults = {
url: this.href,
- container: $(this).attr('data-pjax')
+ container: $(this).attr('data-pjax'),
+ clickedElement: $(this),
+ fragment: null
}
$.pjax($.extend({}, defaults, options))
event.preventDefault()
@@ -51,143 +62,168 @@
// Works just like $.ajax in that it accepts a jQuery ajax
// settings object (with keys like url, type, data, etc).
//
// Accepts these extra keys:
//
-// container - Where to stick the response body.
+// container - Where to stick the response body. Must be a String.
// $(container).html(xhr.responseBody)
// push - Whether to pushState the URL. Defaults to true (of course).
// replace - Want to use replaceState instead? That's cool.
//
// Use it just like $.ajax:
//
// var xhr = $.pjax({ url: this.href, container: '#main' })
// console.log( xhr.readyState )
//
// Returns whatever $.ajax returns.
-$.pjax = function( options ) {
+var pjax = $.pjax = function( options ) {
var $container = $(options.container),
success = options.success || $.noop
// We don't want to let anyone override our success handler.
delete options.success
- var defaults = {
- timeout: 1500,
- push: true,
- replace: false,
- // We want the browser to maintain two separate internal caches: one for
- // pjax'd partial page loads and one for normal page loads. Without
- // adding this secret parameter, some browsers will often confuse the two.
- data: { _pjax: true },
- type: 'GET',
- dataType: 'html',
- beforeSend: function(xhr){
- $(document).trigger('start.pjax')
- xhr.setRequestHeader('X-PJAX', 'true')
- },
- error: function(){
- window.location = options.url
- },
- complete: function(){
- $(document).trigger('end.pjax')
- },
- success: function(data){
- // If we got no data or an entire web page, go directly
- // to the page and let normal error handling happen.
- if ( !$.trim(data) || /<html/i.test(data) )
- return window.location = options.url
+ // We can't persist $objects using the history API so we must use
+ // a String selector. Bail if we got anything else.
+ if ( typeof options.container !== 'string' )
+ throw "pjax container must be a string selector!"
- // Make it happen.
- $container.html(data)
+ options = $.extend(true, {}, pjax.defaults, options)
- // If there's a <title> tag in the response, use it as
- // the page's title.
- var oldTitle = document.title,
- title = $.trim( $container.find('title').remove().text() )
- if ( title ) document.title = title
+ if ( $.isFunction(options.url) ) {
+ options.url = options.url()
+ }
- var state = {
- pjax: options.container,
- timeout: options.timeout
- }
+ options.context = $container
- // We can't persist $objects using the history API so we need to store
- // the string selector.
- if ( $.isPlainObject(state.pjax) )
- state.pjax = state.pjax.selector
+ options.success = function(data){
+ if ( options.fragment ) {
+ // If they specified a fragment, look for it in the response
+ // and pull it out.
+ var $fragment = $(data).find(options.fragment)
+ if ( $fragment.length )
+ data = $fragment.children()
+ else
+ return window.location = options.url
+ } else {
+ // If we got no data or an entire web page, go directly
+ // to the page and let normal error handling happen.
+ if ( !$.trim(data) || /<html/i.test(data) )
+ return window.location = options.url
+ }
- // If there are extra params, save the complete URL in the state object
- var query = $.param(options.data)
- if ( query != "_pjax=true" )
- state.url = options.url + (/\?/.test(options.url) ? "&" : "?") + query
+ // Make it happen.
+ this.html(data)
- if ( options.replace ) {
- window.history.replaceState(state, document.title, options.url)
- } else if ( options.push ) {
- // this extra replaceState before first push ensures good back
- // button behavior
- if ( !$.pjax.active ) {
- window.history.replaceState($.extend({}, state, {url:null}), oldTitle)
- $.pjax.active = true
- }
+ // If there's a <title> tag in the response, use it as
+ // the page's title.
+ var oldTitle = document.title,
+ title = $.trim( this.find('title').remove().text() )
+ if ( title ) document.title = title
- window.history.pushState(state, document.title, options.url)
- }
+ var state = {
+ pjax: options.container,
+ fragment: options.fragment,
+ timeout: options.timeout
+ }
- // Google Analytics support
- if ( (options.replace || options.push) && window._gaq )
- _gaq.push(['_trackPageview'])
+ // If there are extra params, save the complete URL in the state object
+ var query = $.param(options.data)
+ if ( query != "_pjax=true" )
+ state.url = options.url + (/\?/.test(options.url) ? "&" : "?") + query
- // Invoke their success handler if they gave us one.
- success.apply(this, arguments)
+ if ( options.replace ) {
+ window.history.replaceState(state, document.title, options.url)
+ } else if ( options.push ) {
+ // this extra replaceState before first push ensures good back
+ // button behavior
+ if ( !pjax.active ) {
+ window.history.replaceState($.extend({}, state, {url:null}), oldTitle)
+ pjax.active = true
+ }
+
+ window.history.pushState(state, document.title, options.url)
}
- }
- options = $.extend(true, {}, defaults, options)
+ // Google Analytics support
+ if ( (options.replace || options.push) && window._gaq )
+ _gaq.push(['_trackPageview'])
- if ( $.isFunction(options.url) ) {
- options.url = options.url()
+ // If the URL has a hash in it, make sure the browser
+ // knows to navigate to the hash.
+ var hash = window.location.hash.toString()
+ if ( hash !== '' ) {
+ window.location.href = hash
+ }
+
+ // Invoke their success handler if they gave us one.
+ success.apply(this, arguments)
}
// Cancel the current request if we're already pjaxing
- var xhr = $.pjax.xhr
+ var xhr = pjax.xhr
if ( xhr && xhr.readyState < 4) {
xhr.onreadystatechange = $.noop
xhr.abort()
}
- $.pjax.xhr = $.ajax(options)
- $(document).trigger('pjax', $.pjax.xhr, options)
+ pjax.options = options
+ pjax.xhr = $.ajax(options)
+ $(document).trigger('pjax', [pjax.xhr, options])
- return $.pjax.xhr
+ return pjax.xhr
}
+pjax.defaults = {
+ timeout: 650,
+ push: true,
+ replace: false,
+ // We want the browser to maintain two separate internal caches: one for
+ // pjax'd partial page loads and one for normal page loads. Without
+ // adding this secret parameter, some browsers will often confuse the two.
+ data: { _pjax: true },
+ type: 'GET',
+ dataType: 'html',
+ beforeSend: function(xhr){
+ this.trigger('start.pjax', [xhr, pjax.options])
+ xhr.setRequestHeader('X-PJAX', 'true')
+ },
+ error: function(xhr, textStatus, errorThrown){
+ if ( textStatus !== 'abort' )
+ window.location = pjax.options.url
+ },
+ complete: function(xhr){
+ this.trigger('end.pjax', [xhr, pjax.options])
+ }
+}
+
+
// Used to detect initial (useless) popstate.
// If history.state exists, assume browser isn't going to fire initial popstate.
var popped = ('state' in window.history), initialURL = location.href
// popstate handler takes care of the back and forward buttons
//
// You probably shouldn't use pjax on pages with other pushState
// stuff yet.
-$(window).bind('popstate', function(event) {
+$(window).bind('popstate', function(event){
// Ignore inital popstate that some browsers fire on page load
var initialPop = !popped && location.href == initialURL
popped = true
if ( initialPop ) return
var state = event.state
if ( state && state.pjax ) {
- var $container = $(state.pjax+'')
- if ( $container.length )
+ var container = state.pjax
+ if ( $(container+'').length )
$.pjax({
url: state.url || location.href,
- container: $container,
+ fragment: state.fragment,
+ container: container,
push: false,
timeout: state.timeout
})
else
window.location = location.href
@@ -195,14 +231,25 @@
})
// Add the state property to jQuery's event object so we can use it in
// $(window).bind('popstate')
-if ( $.event.props.indexOf('state') < 0 )
+if ( $.inArray('state', $.event.props) < 0 )
$.event.props.push('state')
+// Is pjax supported by this browser?
+$.support.pjax =
+ window.history && window.history.pushState && window.history.replaceState
+ // pushState isn't reliable on iOS yet.
+ && !navigator.userAgent.match(/(iPod|iPhone|iPad|WebApps\/.+CFNetwork)/)
+
+
// Fall back to normalcy for older browsers.
-if ( !window.history || !window.history.pushState ) {
- $.pjax = $.noop
+if ( !$.support.pjax ) {
+ $.pjax = function( options ) {
+ window.location = $.isFunction(options.url) ? options.url() : options.url
+ }
$.fn.pjax = function() { return this }
-}
+}
+
+})(jQuery);
\ No newline at end of file