N°6359 - ⬆️ Update jQuery BBQ (from https://github.com/cee-chen/jquery-bbq)

This commit is contained in:
Eric Espie
2023-06-08 14:30:09 +02:00
parent ea49c0a87c
commit 4f999de844
2 changed files with 404 additions and 152 deletions

View File

@@ -1,5 +1,5 @@
/*!
* jQuery BBQ: Back Button & Query Library - v1.2.1 - 2/17/2010
* jQuery BBQ: Back Button & Query Library - v1.3pre - 8/26/2010
* http://benalman.com/projects/jquery-bbq-plugin/
*
* Copyright (c) 2010 "Cowboy" Ben Alman
@@ -9,12 +9,12 @@
// Script: jQuery BBQ: Back Button & Query Library
//
// *Version: 1.2.1, Last updated: 2/17/2010*
// *Version: 1.3pre, Last updated: 8/26/2010*
//
// Project Home - http://benalman.com/projects/jquery-bbq-plugin/
// GitHub - http://github.com/cowboy/jquery-bbq/
// Source - http://github.com/cowboy/jquery-bbq/raw/master/jquery.ba-bbq.js
// (Minified) - http://github.com/cowboy/jquery-bbq/raw/master/jquery.ba-bbq.min.js (4.0kb)
// (Minified) - http://github.com/cowboy/jquery-bbq/raw/master/jquery.ba-bbq.min.js (2.2kb gzipped)
//
// About: License
//
@@ -38,13 +38,21 @@
// tested with, what browsers it has been tested in, and where the unit tests
// reside (so you can test it yourself).
//
// jQuery Versions - 1.3.2, 1.4.1, 1.4.2
// Browsers Tested - Internet Explorer 6-8, Firefox 2-3.7, Safari 3-4,
// Chrome 4-5, Opera 9.6-10.1.
// jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
// Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5,
// Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5.
// Unit Tests - http://benalman.com/code/projects/jquery-bbq/unit/
//
// About: Release History
//
// 1.3pre - (8/26/2010) Integrated <jQuery hashchange event> v1.3, which adds
// document.title and document.domain support in IE6/7, BlackBerry
// support, better Iframe hiding for accessibility reasons, and the new
// <jQuery.fn.hashchange> "shortcut" method. Added the
// <jQuery.param.sorted> method which reduces the possibility of
// extraneous hashchange event triggering. Added the
// <jQuery.param.fragment.ajaxCrawlable> method which can be used to
// enable Google "AJAX Crawlable mode."
// 1.2.1 - (2/17/2010) Actually fixed the stale window.location Safari bug from
// <jQuery hashchange event> in BBQ, which was the main reason for the
// previous release!
@@ -87,6 +95,7 @@
// Method / object references.
jq_param = $.param,
jq_param_sorted,
jq_param_fragment,
jq_deparam,
jq_deparam_fragment,
@@ -94,22 +103,25 @@
jq_bbq_pushState,
jq_bbq_getState,
jq_elemUrlAttr,
jq_event_special = $.event.special,
special = $.event.special,
// Reused strings.
str_hashchange = 'hashchange',
str_querystring = 'querystring',
str_fragment = 'fragment',
str_elemUrlAttr = 'elemUrlAttr',
str_location = 'location',
str_href = 'href',
str_src = 'src',
// Reused RegExp.
re_trim_querystring = /^.*\?|#.*$/g,
re_trim_fragment = /^.*\#/,
re_params_querystring = /^.*\?|#.*$/g,
re_params_fragment,
re_fragment,
re_no_escape,
ajax_crawlable,
fragment_prefix,
// Used by jQuery.elemUrlAttr.
elemUrlAttr_cache = {};
@@ -132,7 +144,7 @@
// Get location.hash (or what you'd expect location.hash to be) sans any
// leading #. Thanks for making this necessary, Firefox!
function get_fragment( url ) {
return url.replace( /^[^#]*#?(.*)$/, '$1' );
return url.replace( re_fragment, '$2' );
};
// Get location.search (or what you'd expect location.search to be) sans any
@@ -146,7 +158,7 @@
// Method: jQuery.param.querystring
//
// Retrieve the query string from a URL or if no arguments are passed, the
// current window.location.
// current window.location.href.
//
// Usage:
//
@@ -155,7 +167,7 @@
// Arguments:
//
// url - (String) A URL containing query string params to be parsed. If url
// is not passed, the current window.location is used.
// is not passed, the current window.location.href is used.
//
// Returns:
//
@@ -189,13 +201,12 @@
//
// Returns:
//
// (String) Either a params string with urlencoded data or a URL with a
// urlencoded query string in the format 'a=b&c=d&e=f'.
// (String) A URL with a urlencoded query string in the format '?a=b&c=d&e=f'.
// Method: jQuery.param.fragment
//
// Retrieve the fragment (hash) from a URL or if no arguments are passed, the
// current window.location.
// current window.location.href.
//
// Usage:
//
@@ -204,7 +215,7 @@
// Arguments:
//
// url - (String) A URL containing fragment (hash) params to be parsed. If
// url is not passed, the current window.location is used.
// url is not passed, the current window.location.href is used.
//
// Returns:
//
@@ -238,8 +249,7 @@
//
// Returns:
//
// (String) Either a params string with urlencoded data or a URL with a
// urlencoded fragment (hash) in the format 'a=b&c=d&e=f'.
// (String) A URL with a urlencoded fragment (hash) in the format '#a=b&c=d&e=f'.
function jq_param_sub( is_fragment, get_func, url, params, merge_mode ) {
var result,
@@ -254,7 +264,7 @@
// matches[1] = url part that precedes params, not including trailing ?/#
// matches[2] = params, not including leading ?/#
// matches[3] = if in 'querystring' mode, hash including leading #, otherwise ''
matches = url.match( is_fragment ? /^([^#]*)\#?(.*)$/ : /^([^#?]*)\??([^#]*)(#?.*)/ );
matches = url.match( is_fragment ? re_fragment : /^([^#?]*)\??([^#]*)(#?.*)/ );
// Get the hash if in 'querystring' mode, and it exists.
hash = matches[3] || '';
@@ -262,7 +272,7 @@
if ( merge_mode === 2 && is_string( params ) ) {
// If merge_mode is 2 and params is a string, merge the fragment / query
// string into the URL wholesale, without converting it into an object.
qs = params.replace( is_fragment ? re_trim_fragment : re_trim_querystring, '' );
qs = params.replace( is_fragment ? re_params_fragment : re_params_querystring, '' );
} else {
// Convert relevant params in url to object.
@@ -280,8 +290,8 @@
: merge_mode === 1 ? $.extend( {}, params, url_params ) // url params override passed params
: $.extend( {}, url_params, params ); // passed params override url params
// Convert params object to a string.
qs = jq_param( qs );
// Convert params object into a sorted params string.
qs = jq_param_sorted( qs );
// Unescape characters specified via $.param.noEscape. Since only hash-
// history users have requested this feature, it's only enabled for
@@ -294,12 +304,12 @@
// Build URL from the base url, querystring and hash. In 'querystring'
// mode, ? is only added if a query string exists. In 'fragment' mode, #
// is always added.
result = matches[1] + ( is_fragment ? '#' : qs || !matches[1] ? '?' : '' ) + qs + hash;
result = matches[1] + ( is_fragment ? fragment_prefix : qs || !matches[1] ? '?' : '' ) + qs + hash;
} else {
// If URL was passed in, parse params from URL string, otherwise parse
// params from window.location.
result = get_func( url !== undefined ? url : window[ str_location ][ str_href ] );
// params from window.location.href.
result = get_func( url !== undefined ? url : location.href );
}
return result;
@@ -308,6 +318,56 @@
jq_param[ str_querystring ] = curry( jq_param_sub, 0, get_querystring );
jq_param[ str_fragment ] = jq_param_fragment = curry( jq_param_sub, 1, get_fragment );
// Method: jQuery.param.sorted
//
// Returns a params string equivalent to that returned by the internal
// jQuery.param method, but sorted, which makes it suitable for use as a
// cache key.
//
// For example, in most browsers jQuery.param({z:1,a:2}) returns "z=1&a=2"
// and jQuery.param({a:2,z:1}) returns "a=2&z=1". Even though both the
// objects being serialized and the resulting params strings are equivalent,
// if these params strings were set into the location.hash fragment
// sequentially, the hashchange event would be triggered unnecessarily, since
// the strings are different (even though the data described by them is the
// same). By sorting the params string, unecessary hashchange event triggering
// can be avoided.
//
// Usage:
//
// > jQuery.param.sorted( obj [, traditional ] );
//
// Arguments:
//
// obj - (Object) An object to be serialized.
// traditional - (Boolean) Params deep/shallow serialization mode. See the
// documentation at http://api.jquery.com/jQuery.param/ for more detail.
//
// Returns:
//
// (String) A sorted params string.
jq_param.sorted = jq_param_sorted = function( a, traditional ) {
var arr = [],
obj = {};
$.each( jq_param( a, traditional ).split( '&' ), function(i,v){
var key = v.replace( /(?:%5B|=).*$/, '' ),
key_obj = obj[ key ];
if ( !key_obj ) {
key_obj = obj[ key ] = [];
arr.push( key );
}
key_obj.push( v );
});
return $.map( arr.sort(), function(v){
return obj[ v ];
}).join( '&' );
};
// Method: jQuery.param.fragment.noEscape
//
// Specify characters that will be left unescaped when fragments are created
@@ -346,6 +406,41 @@
// "uglifying up the URL" the most.
jq_param_fragment.noEscape( ',/' );
// Method: jQuery.param.fragment.ajaxCrawlable
//
// TODO: DESCRIBE
//
// Usage:
//
// > jQuery.param.fragment.ajaxCrawlable( [ state ] );
//
// Arguments:
//
// state - (Boolean) TODO: DESCRIBE
//
// Returns:
//
// (Boolean) The current ajaxCrawlable state.
jq_param_fragment.ajaxCrawlable = function( state ) {
if ( state !== undefined ) {
if ( state ) {
re_params_fragment = /^.*(?:#!|#)/;
re_fragment = /^([^#]*)(?:#!|#)?(.*)$/;
fragment_prefix = '#!';
} else {
re_params_fragment = /^.*#/;
re_fragment = /^([^#]*)#?(.*)$/;
fragment_prefix = '#';
}
ajax_crawlable = !!state;
}
return ajax_crawlable;
};
jq_param_fragment.ajaxCrawlable( 0 );
// Section: Deparam (from string)
//
// Method: jQuery.deparam
@@ -369,7 +464,7 @@
// (Object) An object representing the deserialized params string.
$.deparam = jq_deparam = function( params, coerce ) {
var obj = {},
var obj = Object.create(null),
coerce_types = { 'true': !0, 'false': !1, 'null': null };
// Iterate over all name=value pairs.
@@ -426,7 +521,7 @@
for ( ; i <= keys_last; i++ ) {
key = keys[i] === '' ? cur.length : keys[i];
cur = cur[key] = i < keys_last
? cur[key] || ( keys[i+1] && isNaN( keys[i+1] ) ? {} : [] )
? cur[key] || ( keys[i+1] && isNaN( keys[i+1] ) ? Object.create(null) : [] )
: val;
}
@@ -462,7 +557,7 @@
// Method: jQuery.deparam.querystring
//
// Parse the query string from a URL or the current window.location,
// Parse the query string from a URL or the current window.location.href,
// deserializing it into an object, optionally coercing numbers, booleans,
// null and undefined values.
//
@@ -473,8 +568,8 @@
// Arguments:
//
// url - (String) An optional params string or URL containing query string
// params to be parsed. If url is omitted, the current window.location
// is used.
// params to be parsed. If url is omitted, the current
// window.location.href is used.
// coerce - (Boolean) If true, coerces any numbers or true, false, null, and
// undefined to their actual value. Defaults to false if omitted.
//
@@ -484,7 +579,7 @@
// Method: jQuery.deparam.fragment
//
// Parse the fragment (hash) from a URL or the current window.location,
// Parse the fragment (hash) from a URL or the current window.location.href,
// deserializing it into an object, optionally coercing numbers, booleans,
// null and undefined values.
//
@@ -495,7 +590,7 @@
// Arguments:
//
// url - (String) An optional params string or URL containing fragment (hash)
// params to be parsed. If url is omitted, the current window.location
// params to be parsed. If url is omitted, the current window.location.href
// is used.
// coerce - (Boolean) If true, coerces any numbers or true, false, null, and
// undefined to their actual value. Defaults to false if omitted.
@@ -511,7 +606,7 @@
url_or_params = jq_param[ is_fragment ? str_fragment : str_querystring ]();
} else {
url_or_params = is_string( url_or_params )
? url_or_params.replace( is_fragment ? re_trim_fragment : re_trim_querystring, '' )
? url_or_params.replace( is_fragment ? re_params_fragment : re_params_querystring, '' )
: url_or_params;
}
@@ -715,13 +810,12 @@
var has_args = params !== undefined,
// Merge params into window.location using $.param.fragment.
url = jq_param_fragment( window[ str_location ][ str_href ],
url = jq_param_fragment( location.href,
has_args ? params : {}, has_args ? merge_mode : 2 );
// Set new window.location.href. If hash is empty, use just # to prevent
// browser from reloading the page. Note that Safari 3 & Chrome barf on
// location.hash = '#'.
window[ str_location ][ str_href ] = url + ( /#/.test( url ) ? '' : '#' );
// Set new window.location.href. Note that Safari 3 & Chrome barf on
// location.hash = '#' so the entire URL is set.
location.href = url;
};
// Method: jQuery.bbq.getState
@@ -850,7 +944,7 @@
// required to enable the augmented event object in jQuery 1.4.2 and newer.
// * See <jQuery hashchange event> for more detailed information.
jq_event_special[ str_hashchange ] = $.extend( jq_event_special[ str_hashchange ], {
special[ str_hashchange ] = $.extend( special[ str_hashchange ], {
// Augmenting the event object with the .fragment property and .getState
// method requires jQuery 1.4 or newer. Note: with 1.3.2, everything will
@@ -892,7 +986,7 @@
})(jQuery,this);
/*!
* jQuery hashchange event - v1.2 - 2/11/2010
* jQuery hashchange event - v1.3 - 7/21/2010
* http://benalman.com/projects/jquery-hashchange-plugin/
*
* Copyright (c) 2010 "Cowboy" Ben Alman
@@ -902,12 +996,12 @@
// Script: jQuery hashchange event
//
// *Version: 1.2, Last updated: 2/11/2010*
// *Version: 1.3, Last updated: 7/21/2010*
//
// Project Home - http://benalman.com/projects/jquery-hashchange-plugin/
// GitHub - http://github.com/cowboy/jquery-hashchange/
// Source - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js
// (Minified) - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (1.1kb)
// (Minified) - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (0.8kb gzipped)
//
// About: License
//
@@ -917,10 +1011,11 @@
//
// About: Examples
//
// This working example, complete with fully commented code, illustrate one way
// in which this plugin can be used.
// These working examples, complete with fully commented code, illustrate a few
// ways in which this plugin can be used.
//
// hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/
// document.domain - http://benalman.com/code/projects/jquery-hashchange/examples/document_domain/
//
// About: Support and Testing
//
@@ -928,24 +1023,40 @@
// tested with, what browsers it has been tested in, and where the unit tests
// reside (so you can test it yourself).
//
// jQuery Versions - 1.3.2, 1.4.1, 1.4.2
// Browsers Tested - Internet Explorer 6-8, Firefox 2-3.7, Safari 3-4, Chrome, Opera 9.6-10.1.
// jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
// Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5,
// Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5.
// Unit Tests - http://benalman.com/code/projects/jquery-hashchange/unit/
//
// About: Known issues
//
// While this jQuery hashchange event implementation is quite stable and robust,
// there are a few unfortunate browser bugs surrounding expected hashchange
// event-based behaviors, independent of any JavaScript window.onhashchange
// abstraction. See the following examples for more information:
// While this jQuery hashchange event implementation is quite stable and
// robust, there are a few unfortunate browser bugs surrounding expected
// hashchange event-based behaviors, independent of any JavaScript
// window.onhashchange abstraction. See the following examples for more
// information:
//
// Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/
// Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/
// WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/
// Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/
//
// Also note that should a browser natively support the window.onhashchange
// event, but not report that it does, the fallback polling loop will be used.
//
// About: Release History
//
// 1.3 - (7/21/2010) Reorganized IE6/7 Iframe code to make it more
// "removable" for mobile-only development. Added IE6/7 document.title
// support. Attempted to make Iframe as hidden as possible by using
// techniques from http://www.paciellogroup.com/blog/?p=604. Added
// support for the "shortcut" format $(window).hashchange( fn ) and
// $(window).hashchange() like jQuery provides for built-in events.
// Renamed jQuery.hashchangeDelay to <jQuery.fn.hashchange.delay> and
// lowered its default value to 50. Added <jQuery.fn.hashchange.domain>
// and <jQuery.fn.hashchange.src> properties plus document-domain.html
// file to address access denied issues when setting document.domain in
// IE6/7.
// 1.2 - (2/11/2010) Fixed a bug where coming back to a page using this plugin
// from a page on another domain would cause an error in Safari 4. Also,
// IE6/7 Iframe is now inserted after the body (this actually works),
@@ -964,63 +1075,144 @@
(function($,window,undefined){
'$:nomunge'; // Used by YUI compressor.
// Method / object references.
var fake_onhashchange,
jq_event_special = $.event.special,
// Reused string.
var str_hashchange = 'hashchange',
// Reused strings.
str_location = 'location',
str_hashchange = 'hashchange',
str_href = 'href',
// Method / object references.
doc = document,
fake_onhashchange,
special = $.event.special,
mode = document.documentMode,
is_old_ie = false,
// Does the browser support window.onhashchange? Test for IE version, since
// IE8 incorrectly reports this when in "IE7" or "IE8 Compatibility View"!
supports_onhashchange = 'on' + str_hashchange in window && !is_old_ie;
// Does the browser support window.onhashchange? Note that IE8 running in
// IE7 compatibility mode reports true for 'onhashchange' in window, even
// though the event isn't supported, so also test document.documentMode.
doc_mode = doc.documentMode,
supports_onhashchange = 'on' + str_hashchange in window && ( doc_mode === undefined || doc_mode > 7 );
// Get location.hash (or what you'd expect location.hash to be) sans any
// leading #. Thanks for making this necessary, Firefox!
function get_fragment( url ) {
url = url || window[ str_location ][ str_href ];
return url.replace( /^[^#]*#?(.*)$/, '$1' );
url = url || location.href;
return '#' + url.replace( /^[^#]*#?(.*)$/, '$1' );
};
// Property: jQuery.hashchangeDelay
// Method: jQuery.fn.hashchange
//
// Bind a handler to the window.onhashchange event or trigger all bound
// window.onhashchange event handlers. This behavior is consistent with
// jQuery's built-in event handlers.
//
// Usage:
//
// > jQuery(window).hashchange( [ handler ] );
//
// Arguments:
//
// handler - (Function) Optional handler to be bound to the hashchange
// event. This is a "shortcut" for the more verbose form:
// jQuery(window).bind( 'hashchange', handler ). If handler is omitted,
// all bound window.onhashchange event handlers will be triggered. This
// is a shortcut for the more verbose
// jQuery(window).trigger( 'hashchange' ). These forms are described in
// the <hashchange event> section.
//
// Returns:
//
// (jQuery) The initial jQuery collection of elements.
// Allow the "shortcut" format $(elem).hashchange( fn ) for binding and
// $(elem).hashchange() for triggering, like jQuery does for built-in events.
$.fn[ str_hashchange ] = function( fn ) {
return fn ? this.bind( str_hashchange, fn ) : this.trigger( str_hashchange );
};
// Property: jQuery.fn.hashchange.delay
//
// The numeric interval (in milliseconds) at which the <hashchange event>
// polling loop executes. Defaults to 100.
// polling loop executes. Defaults to 50.
$[ str_hashchange + 'Delay' ] = 100;
// Property: jQuery.fn.hashchange.domain
//
// If you're setting document.domain in your JavaScript, and you want hash
// history to work in IE6/7, not only must this property be set, but you must
// also set document.domain BEFORE jQuery is loaded into the page. This
// property is only applicable if you are supporting IE6/7 (or IE8 operating
// in "IE7 compatibility" mode).
//
// In addition, the <jQuery.fn.hashchange.src> property must be set to the
// path of the included "document-domain.html" file, which can be renamed or
// modified if necessary (note that the document.domain specified must be the
// same in both your main JavaScript as well as in this file).
//
// Usage:
//
// jQuery.fn.hashchange.domain = document.domain;
// Property: jQuery.fn.hashchange.src
//
// If, for some reason, you need to specify an Iframe src file (for example,
// when setting document.domain as in <jQuery.fn.hashchange.domain>), you can
// do so using this property. Note that when using this property, history
// won't be recorded in IE6/7 until the Iframe src file loads. This property
// is only applicable if you are supporting IE6/7 (or IE8 operating in "IE7
// compatibility" mode).
//
// Usage:
//
// jQuery.fn.hashchange.src = 'path/to/file.html';
$.fn[ str_hashchange ].delay = 50;
/*
$.fn[ str_hashchange ].domain = null;
$.fn[ str_hashchange ].src = null;
*/
// Event: hashchange event
//
// Fired when location.hash changes. In browsers that support it, the native
// window.onhashchange event is used (IE8, FF3.6), otherwise a polling loop is
// initialized, running every <jQuery.hashchangeDelay> milliseconds to see if
// the hash has changed. In IE 6 and 7, a hidden Iframe is created to allow
// the back button and hash-based history to work.
// HTML5 window.onhashchange event is used, otherwise a polling loop is
// initialized, running every <jQuery.fn.hashchange.delay> milliseconds to
// see if the hash has changed. In IE6/7 (and IE8 operating in "IE7
// compatibility" mode), a hidden Iframe is created to allow the back button
// and hash-based history to work.
//
// Usage:
// Usage as described in <jQuery.fn.hashchange>:
//
// > $(window).bind( 'hashchange', function(e) {
// > // Bind an event handler.
// > jQuery(window).hashchange( function(e) {
// > var hash = location.hash;
// > ...
// > });
// >
// > // Manually trigger the event handler.
// > jQuery(window).hashchange();
//
// A more verbose usage that allows for event namespacing:
//
// > // Bind an event handler.
// > jQuery(window).bind( 'hashchange', function(e) {
// > var hash = location.hash;
// > ...
// > });
// >
// > // Manually trigger the event handler.
// > jQuery(window).trigger( 'hashchange' );
//
// Additional Notes:
//
// * The polling loop and Iframe are not created until at least one callback
// is actually bound to 'hashchange'.
// * If you need the bound callback(s) to execute immediately, in cases where
// the page 'state' exists on page load (via bookmark or page refresh, for
// example) use $(window).trigger( 'hashchange' );
// * The polling loop and Iframe are not created until at least one handler
// is actually bound to the 'hashchange' event.
// * If you need the bound handler(s) to execute immediately, in cases where
// a location.hash exists on page load, via bookmark or page refresh for
// example, use jQuery(window).hashchange() or the more verbose
// jQuery(window).trigger( 'hashchange' ).
// * The event can be bound before DOM ready, but since it won't be usable
// before then in IE6/7 (due to the necessary Iframe), recommended usage is
// to bind it inside a $(document).ready() callback.
// to bind it inside a DOM ready handler.
jq_event_special[ str_hashchange ] = $.extend( jq_event_special[ str_hashchange ], {
// Override existing $.event.special.hashchange methods (allowing this plugin
// to be defined after jQuery BBQ in BBQ's source code).
special[ str_hashchange ] = $.extend( special[ str_hashchange ], {
// Called only when the first 'hashchange' event is bound to window.
setup: function() {
@@ -1051,83 +1243,134 @@
fake_onhashchange = (function(){
var self = {},
timeout_id,
iframe,
set_history,
get_history;
// Initialize. In IE 6/7, creates a hidden Iframe for history handling.
function init(){
// Most browsers don't need special methods here..
set_history = get_history = function(val){ return val; };
// But IE6/7 do!
if ( is_old_ie ) {
// Create hidden Iframe after the end of the body to prevent initial
// page load from scrolling unnecessarily.
iframe = $('<iframe src="javascript:0"/>').hide().insertAfter( 'body' )[0].contentWindow;
// Get history by looking at the hidden Iframe's location.hash.
get_history = function() {
return get_fragment( iframe.document[ str_location ][ str_href ] );
};
// Set a new history item by opening and then closing the Iframe
// document, *then* setting its location.hash.
set_history = function( hash, history_hash ) {
if ( hash !== history_hash ) {
var doc = iframe.document;
doc.open().close();
doc[ str_location ].hash = '#' + hash;
}
};
// Set initial history.
set_history( get_fragment() );
}
};
// Remember the initial hash so it doesn't get triggered immediately.
last_hash = get_fragment(),
fn_retval = function(val){ return val; },
history_set = fn_retval,
history_get = fn_retval;
// Start the polling loop.
self.start = function() {
// Polling loop is already running!
if ( timeout_id ) { return; }
// Remember the initial hash so it doesn't get triggered immediately.
var last_hash = get_fragment();
// Initialize if not yet initialized.
set_history || init();
// This polling loop checks every $.hashchangeDelay milliseconds to see if
// location.hash has changed, and triggers the 'hashchange' event on
// window when necessary.
(function loopy(){
var hash = get_fragment(),
history_hash = get_history( last_hash );
if ( hash !== last_hash ) {
set_history( last_hash = hash, history_hash );
$(window).trigger( str_hashchange );
} else if ( history_hash !== last_hash ) {
window[ str_location ][ str_href ] = window[ str_location ][ str_href ].replace( /#.*/, '' ) + '#' + history_hash;
}
timeout_id = setTimeout( loopy, $[ str_hashchange + 'Delay' ] );
})();
timeout_id || poll();
};
// Stop the polling loop, but only if an IE6/7 Iframe wasn't created. In
// that case, even if there are no longer any bound event handlers, the
// polling loop is still necessary for back/next to work at all!
// Stop the polling loop.
self.stop = function() {
if ( !iframe ) {
timeout_id && clearTimeout( timeout_id );
timeout_id = 0;
}
timeout_id && clearTimeout( timeout_id );
timeout_id = undefined;
};
// This polling loop checks every $.fn.hashchange.delay milliseconds to see
// if location.hash has changed, and triggers the 'hashchange' event on
// window when necessary.
function poll() {
var hash = get_fragment(),
history_hash = history_get( last_hash );
if ( hash !== last_hash ) {
history_set( last_hash = hash, history_hash );
$(window).trigger( str_hashchange );
} else if ( history_hash !== last_hash ) {
location.href = location.href.replace( /#.*/, '' ) + history_hash;
}
timeout_id = setTimeout( poll, $.fn[ str_hashchange ].delay );
};
// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
// vvvvvvvvvvvvvvvvvvv REMOVE IF NOT SUPPORTING IE6/7/8 vvvvvvvvvvvvvvvvvvv
// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
$.browser.msie && !supports_onhashchange && (function(){
// Not only do IE6/7 need the "magical" Iframe treatment, but so does IE8
// when running in "IE7 compatibility" mode.
var iframe,
iframe_src;
// When the event is bound and polling starts in IE 6/7, create a hidden
// Iframe for history handling.
self.start = function(){
if ( !iframe ) {
iframe_src = $.fn[ str_hashchange ].src;
iframe_src = iframe_src && iframe_src + get_fragment();
// Create hidden Iframe. Attempt to make Iframe as hidden as possible
// by using techniques from http://www.paciellogroup.com/blog/?p=604.
iframe = $('<iframe tabindex="-1" title="empty"/>').hide()
// When Iframe has completely loaded, initialize the history and
// start polling.
.one( 'load', function(){
iframe_src || history_set( get_fragment() );
poll();
})
// Load Iframe src if specified, otherwise nothing.
.attr( 'src', iframe_src || 'javascript:0' )
// Append Iframe after the end of the body to prevent unnecessary
// initial page scrolling (yes, this works).
.insertAfter( 'body' )[0].contentWindow;
// Whenever `document.title` changes, update the Iframe's title to
// prettify the back/next history menu entries. Since IE sometimes
// errors with "Unspecified error" the very first time this is set
// (yes, very useful) wrap this with a try/catch block.
doc.onpropertychange = function(){
try {
if ( event.propertyName === 'title' ) {
iframe.document.title = doc.title;
}
} catch(e) {}
};
}
};
// Override the "stop" method since an IE6/7 Iframe was created. Even
// if there are no longer any bound event handlers, the polling loop
// is still necessary for back/next to work at all!
self.stop = fn_retval;
// Get history by looking at the hidden Iframe's location.hash.
history_get = function() {
return get_fragment( iframe.location.href );
};
// Set a new history item by opening and then closing the Iframe
// document, *then* setting its location.hash. If document.domain has
// been set, update that as well.
history_set = function( hash, history_hash ) {
var iframe_doc = iframe.document,
domain = $.fn[ str_hashchange ].domain;
if ( hash !== history_hash ) {
// Update Iframe with any initial `document.title` that might be set.
iframe_doc.title = doc.title;
// Opening the Iframe's document after it has been closed is what
// actually adds a history entry.
iframe_doc.open();
// Set document.domain for the Iframe document as well, if necessary.
domain && iframe_doc.write( '<script>document.domain="' + domain + '"</script>' );
iframe_doc.close();
// Update the Iframe's hash, for great justice.
iframe.location.hash = hash;
}
};
})();
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// ^^^^^^^^^^^^^^^^^^^ REMOVE IF NOT SUPPORTING IE6/7/8 ^^^^^^^^^^^^^^^^^^^
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
return self;
})();

View File

@@ -1,9 +1,18 @@
/*
* jQuery BBQ: Back Button & Query Library - v1.2.1 - 2/17/2010
* jQuery BBQ: Back Button & Query Library - v1.3pre - 8/26/2010
* http://benalman.com/projects/jquery-bbq-plugin/
*
* Copyright (c) 2010 "Cowboy" Ben Alman
* Dual licensed under the MIT and GPL licenses.
* http://benalman.com/about/license/
*/
(function(e,t){"$:nomunge";function N(e){return typeof e==="string"}function C(e){var t=r.call(arguments,1);return function(){return e.apply(this,t.concat(r.call(arguments)))}}function k(e){return e.replace(/^[^#]*#?(.*)$/,"$1")}function L(e){return e.replace(/(?:^[^?#]*\?([^#]*).*$)?.*/,"$1")}function A(r,o,a,f,l){var c,h,p,d,g;if(f!==n){p=a.match(r?/^([^#]*)\#?(.*)$/:/^([^#?]*)\??([^#]*)(#?.*)/);g=p[3]||"";if(l===2&&N(f)){h=f.replace(r?S:E,"")}else{d=u(p[2]);f=N(f)?u[r?m:v](f):f;h=l===2?f:l===1?e.extend({},f,d):e.extend({},d,f);h=s(h);if(r){h=h.replace(x,i)}}c=p[1]+(r?"#":h||!p[1]?"?":"")+h+g}else{c=o(a!==n?a:t[y][b])}return c}function O(e,t,r){if(t===n||typeof t==="boolean"){r=t;t=s[e?m:v]()}else{t=N(t)?t.replace(e?S:E,""):t}return u(t,r)}function M(t,r,i,o){if(!N(i)&&typeof i!=="object"){o=i;i=r;r=n}return this.each(function(){var n=e(this),u=r||h()[(this.nodeName||"").toLowerCase()]||"",a=u&&n.attr(u)||"";n.attr(u,s[t](a,i,o))})}var n,r=Array.prototype.slice,i=decodeURIComponent,s=e.param,o,u,a,f=e.bbq=e.bbq||{},l,c,h,p=e.event.special,d="hashchange",v="querystring",m="fragment",g="elemUrlAttr",y="location",b="href",w="src",E=/^.*\?|#.*$/g,S=/^.*\#/,x,T={};s[v]=C(A,0,L);s[m]=o=C(A,1,k);o.noEscape=function(t){t=t||"";var n=e.map(t.split(""),encodeURIComponent);x=new RegExp(n.join("|"),"g")};o.noEscape(",/");e.deparam=u=function(t,r){var s={},o={"true":!0,"false":!1,"null":null};e.each(t.replace(/\+/g," ").split("&"),function(t,u){var a=u.split("="),f=i(a[0]),l,c=s,h=0,p=f.split("]["),d=p.length-1;if(/\[/.test(p[0])&&/\]$/.test(p[d])){p[d]=p[d].replace(/\]$/,"");p=p.shift().split("[").concat(p);d=p.length-1}else{d=0}if(a.length===2){l=i(a[1]);if(r){l=l&&!isNaN(l)?+l:l==="undefined"?n:o[l]!==n?o[l]:l}if(d){for(;h<=d;h++){f=p[h]===""?c.length:p[h];c=c[f]=h<d?c[f]||(p[h+1]&&isNaN(p[h+1])?{}:[]):l}}else{if(e.isArray(s[f])){s[f].push(l)}else if(s[f]!==n){s[f]=[s[f],l]}else{s[f]=l}}}else if(f){s[f]=r?n:""}});return s};u[v]=C(O,0);u[m]=a=C(O,1);e[g]||(e[g]=function(t){return e.extend(T,t)})({a:b,base:b,iframe:w,img:w,input:w,form:"action",link:b,script:w});h=e[g];e.fn[v]=C(M,v);e.fn[m]=C(M,m);f.pushState=l=function(e,r){if(N(e)&&/^#/.test(e)&&r===n){r=2}var i=e!==n,s=o(t[y][b],i?e:{},i?r:2);t[y][b]=s+(/#/.test(s)?"":"#")};f.getState=c=function(e,t){return e===n||typeof e==="boolean"?a(e):a(t)[e]};f.removeState=function(t){var r={};if(t!==n){r=c();e.each(e.isArray(t)?t:arguments,function(e,t){delete r[t]})}l(r,2)};p[d]=e.extend(p[d],{add:function(t){function i(e){var t=e[m]=o();e.getState=function(e,r){return e===n||typeof e==="boolean"?u(t,e):u(t,r)[e]};r.apply(this,arguments)}var r;if(e.isFunction(t)){r=t;return i}else{r=t.handler;t.handler=i}}})})(jQuery,this);(function(e,t,n){"$:nomunge";function c(e){e=e||t[s][u];return e.replace(/^[^#]*#?(.*)$/,"$1")}var r,i=e.event.special,s="location",o="hashchange",u="href",a=document.documentMode,f=false,l="on"+o in t&&!f;e[o+"Delay"]=100;i[o]=e.extend(i[o],{setup:function(){if(l){return false}e(r.start)},teardown:function(){if(l){return false}e(r.stop)}});r=function(){function h(){a=l=function(e){return e};if(f){i=e('<iframe src="javascript:0"/>').hide().insertAfter("body")[0].contentWindow;l=function(){return c(i.document[s][u])};a=function(e,t){if(e!==t){var n=i.document;n.open().close();n[s].hash="#"+e}};a(c())}}var n={},r,i,a,l;n.start=function(){if(r){return}var n=c();a||h();(function i(){var f=c(),h=l(n);if(f!==n){a(n=f,h);e(t).trigger(o)}else if(h!==n){t[s][u]=t[s][u].replace(/#.*/,"")+"#"+h}r=setTimeout(i,e[o+"Delay"])})()};n.stop=function(){if(!i){r&&clearTimeout(r);r=0}};return n}()})(jQuery,this)
(function($,r){var h,n=Array.prototype.slice,t=decodeURIComponent,a=$.param,j,c,m,y,b=$.bbq=$.bbq||{},s,x,k,e=$.event.special,d="hashchange",B="querystring",F="fragment",z="elemUrlAttr",l="href",w="src",p=/^.*\?|#.*$/g,u,H,g,i,C,E={};function G(I){return typeof I==="string"}function D(J){var I=n.call(arguments,1);return function(){return J.apply(this,I.concat(n.call(arguments)))}}function o(I){return I.replace(H,"$2")}function q(I){return I.replace(/(?:^[^?#]*\?([^#]*).*$)?.*/,"$1")}function f(K,P,I,L,J){var R,O,N,Q,M;if(L!==h){N=I.match(K?H:/^([^#?]*)\??([^#]*)(#?.*)/);M=N[3]||"";if(J===2&&G(L)){O=L.replace(K?u:p,"")}else{Q=m(N[2]);L=G(L)?m[K?F:B](L):L;O=J===2?L:J===1?$.extend({},L,Q):$.extend({},Q,L);O=j(O);if(K){O=O.replace(g,t)}}R=N[1]+(K?C:O||!N[1]?"?":"")+O+M}else{R=P(I!==h?I:location.href)}return R}a[B]=D(f,0,q);a[F]=c=D(f,1,o);a.sorted=j=function(J,K){var I=[],L={};$.each(a(J,K).split("&"),function(P,M){var O=M.replace(/(?:%5B|=).*$/,""),N=L[O];if(!N){N=L[O]=[];I.push(O)}N.push(M)});return $.map(I.sort(),function(M){return L[M]}).join("&")};c.noEscape=function(J){J=J||"";var I=$.map(J.split(""),encodeURIComponent);g=new RegExp(I.join("|"),"g")};c.noEscape(",/");c.ajaxCrawlable=function(I){if(I!==h){if(I){u=/^.*(?:#!|#)/;H=/^([^#]*)(?:#!|#)?(.*)$/;C="#!"}else{u=/^.*#/;H=/^([^#]*)#?(.*)$/;C="#"}i=!!I}return i};c.ajaxCrawlable(0);$.deparam=m=function(L,I){var K=Object.create(null),J={"true":!0,"false":!1,"null":null};$.each(L.replace(/\+/g," ").split("&"),function(O,T){var N=T.split("="),S=t(N[0]),M,R=K,P=0,U=S.split("]["),Q=U.length-1;if(/\[/.test(U[0])&&/\]$/.test(U[Q])){U[Q]=U[Q].replace(/\]$/,"");U=U.shift().split("[").concat(U);Q=U.length-1}else{Q=0}if(N.length===2){M=t(N[1]);if(I){M=M&&!isNaN(M)?+M:M==="undefined"?h:J[M]!==h?J[M]:M}if(Q){for(;P<=Q;P++){S=U[P]===""?R.length:U[P];R=R[S]=P<Q?R[S]||(U[P+1]&&isNaN(U[P+1])?Object.create(null):[]):M}}else{if($.isArray(K[S])){K[S].push(M)}else{if(K[S]!==h){K[S]=[K[S],M]}else{K[S]=M}}}}else{if(S){K[S]=I?h:""}}});return K};function A(K,I,J){if(I===h||typeof I==="boolean"){J=I;I=a[K?F:B]()}else{I=G(I)?I.replace(K?u:p,""):I}return m(I,J)}m[B]=D(A,0);m[F]=y=D(A,1);$[z]||($[z]=function(I){return $.extend(E,I)})({a:l,base:l,iframe:w,img:w,input:w,form:"action",link:l,script:w});k=$[z];function v(L,J,K,I){if(!G(K)&&typeof K!=="object"){I=K;K=J;J=h}return this.each(function(){var O=$(this),M=J||k()[(this.nodeName||"").toLowerCase()]||"",N=M&&O.attr(M)||"";O.attr(M,a[L](N,K,I))})}$.fn[B]=D(v,B);$.fn[F]=D(v,F);b.pushState=s=function(L,I){if(G(L)&&/^#/.test(L)&&I===h){I=2}var K=L!==h,J=c(location.href,K?L:{},K?I:2);location.href=J};b.getState=x=function(I,J){return I===h||typeof I==="boolean"?y(I):y(J)[I]};b.removeState=function(I){var J={};if(I!==h){J=x();$.each($.isArray(I)?I:arguments,function(L,K){delete J[K]})}s(J,2)};e[d]=$.extend(e[d],{add:function(I){var K;function J(M){var L=M[F]=c();M.getState=function(N,O){return N===h||typeof N==="boolean"?m(L,N):m(L,O)[N]};K.apply(this,arguments)}if($.isFunction(I)){K=I;return J}else{K=I.handler;I.handler=J}}})})(jQuery,this);
/*
* jQuery hashchange event - v1.3 - 7/21/2010
* http://benalman.com/projects/jquery-hashchange-plugin/
*
* Copyright (c) 2010 "Cowboy" Ben Alman
* Dual licensed under the MIT and GPL licenses.
* http://benalman.com/about/license/
*/
(function($,e,b){var c="hashchange",h=document,f,g=$.event.special,i=h.documentMode,d="on"+c in e&&(i===b||i>7);function a(j){j=j||location.href;return"#"+j.replace(/^[^#]*#?(.*)$/,"$1")}$.fn[c]=function(j){return j?this.bind(c,j):this.trigger(c)};$.fn[c].delay=50;g[c]=$.extend(g[c],{setup:function(){if(d){return false}$(f.start)},teardown:function(){if(d){return false}$(f.stop)}});f=(function(){var j={},p,m=a(),k=function(q){return q},l=k,o=k;j.start=function(){p||n()};j.stop=function(){p&&clearTimeout(p);p=b};function n(){var r=a(),q=o(m);if(r!==m){l(m=r,q);$(e).trigger(c)}else{if(q!==m){location.href=location.href.replace(/#.*/,"")+q}}p=setTimeout(n,$.fn[c].delay)}$.browser.msie&&!d&&(function(){var q,r;j.start=function(){if(!q){r=$.fn[c].src;r=r&&r+a();q=$('<iframe tabindex="-1" title="empty"/>').hide().one("load",function(){r||l(a());n()}).attr("src",r||"javascript:0").insertAfter("body")[0].contentWindow;h.onpropertychange=function(){try{if(event.propertyName==="title"){q.document.title=h.title}}catch(s){}}}};j.stop=k;o=function(){return a(q.location.href)};l=function(v,s){var u=q.document,t=$.fn[c].domain;if(v!==s){u.title=h.title;u.open();t&&u.write('<script>document.domain="'+t+'"<\/script>');u.close();q.location.hash=v}}})();return j})()})(jQuery,this);