6
6
* Dual licensed under the MIT and GPL licenses.
7
7
* http://benalman.com/about/license/
9
(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);
b'\\ No newline at end of file'
10
// Script: jQuery hashchange event
12
// *Version: 1.3, Last updated: 7/21/2010*
14
// Project Home - http://benalman.com/projects/jquery-hashchange-plugin/
15
// GitHub - http://github.com/cowboy/jquery-hashchange/
16
// Source - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js
17
// (Minified) - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (0.8kb gzipped)
21
// Copyright (c) 2010 "Cowboy" Ben Alman,
22
// Dual licensed under the MIT and GPL licenses.
23
// http://benalman.com/about/license/
27
// These working examples, complete with fully commented code, illustrate a few
28
// ways in which this plugin can be used.
30
// hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/
31
// document.domain - http://benalman.com/code/projects/jquery-hashchange/examples/document_domain/
33
// About: Support and Testing
35
// Information about what version or versions of jQuery this plugin has been
36
// tested with, what browsers it has been tested in, and where the unit tests
37
// reside (so you can test it yourself).
39
// jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
40
// Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5,
41
// Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5.
42
// Unit Tests - http://benalman.com/code/projects/jquery-hashchange/unit/
44
// About: Known issues
46
// While this jQuery hashchange event implementation is quite stable and
47
// robust, there are a few unfortunate browser bugs surrounding expected
48
// hashchange event-based behaviors, independent of any JavaScript
49
// window.onhashchange abstraction. See the following examples for more
52
// Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/
53
// Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/
54
// WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/
55
// Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/
57
// Also note that should a browser natively support the window.onhashchange
58
// event, but not report that it does, the fallback polling loop will be used.
60
// About: Release History
62
// 1.3 - (7/21/2010) Reorganized IE6/7 Iframe code to make it more
63
// "removable" for mobile-only development. Added IE6/7 document.title
64
// support. Attempted to make Iframe as hidden as possible by using
65
// techniques from http://www.paciellogroup.com/blog/?p=604. Added
66
// support for the "shortcut" format $(window).hashchange( fn ) and
67
// $(window).hashchange() like jQuery provides for built-in events.
68
// Renamed jQuery.hashchangeDelay to <jQuery.fn.hashchange.delay> and
69
// lowered its default value to 50. Added <jQuery.fn.hashchange.domain>
70
// and <jQuery.fn.hashchange.src> properties plus document-domain.html
71
// file to address access denied issues when setting document.domain in
73
// 1.2 - (2/11/2010) Fixed a bug where coming back to a page using this plugin
74
// from a page on another domain would cause an error in Safari 4. Also,
75
// IE6/7 Iframe is now inserted after the body (this actually works),
76
// which prevents the page from scrolling when the event is first bound.
77
// Event can also now be bound before DOM ready, but it won't be usable
78
// before then in IE6/7.
79
// 1.1 - (1/21/2010) Incorporated document.documentMode test to fix IE8 bug
80
// where browser version is incorrectly reported as 8.0, despite
81
// inclusion of the X-UA-Compatible IE=EmulateIE7 meta tag.
82
// 1.0 - (1/9/2010) Initial Release. Broke out the jQuery BBQ event.special
83
// window.onhashchange functionality into a separate plugin for users
84
// who want just the basic event & back button support, without all the
85
// extra awesomeness that BBQ provides. This plugin will be included as
86
// part of jQuery BBQ, but also be available separately.
88
(function($,window,undefined){
89
'$:nomunge'; // Used by YUI compressor.
92
var str_hashchange = 'hashchange',
94
// Method / object references.
97
special = $.event.special,
99
// Does the browser support window.onhashchange? Note that IE8 running in
100
// IE7 compatibility mode reports true for 'onhashchange' in window, even
101
// though the event isn't supported, so also test document.documentMode.
102
doc_mode = doc.documentMode,
103
supports_onhashchange = 'on' + str_hashchange in window && ( doc_mode === undefined || doc_mode > 7 );
105
// Get location.hash (or what you'd expect location.hash to be) sans any
106
// leading #. Thanks for making this necessary, Firefox!
107
function get_fragment( url ) {
108
url = url || location.href;
109
return '#' + url.replace( /^[^#]*#?(.*)$/, '$1' );
112
// Method: jQuery.fn.hashchange
114
// Bind a handler to the window.onhashchange event or trigger all bound
115
// window.onhashchange event handlers. This behavior is consistent with
116
// jQuery's built-in event handlers.
120
// > jQuery(window).hashchange( [ handler ] );
124
// handler - (Function) Optional handler to be bound to the hashchange
125
// event. This is a "shortcut" for the more verbose form:
126
// jQuery(window).bind( 'hashchange', handler ). If handler is omitted,
127
// all bound window.onhashchange event handlers will be triggered. This
128
// is a shortcut for the more verbose
129
// jQuery(window).trigger( 'hashchange' ). These forms are described in
130
// the <hashchange event> section.
134
// (jQuery) The initial jQuery collection of elements.
136
// Allow the "shortcut" format $(elem).hashchange( fn ) for binding and
137
// $(elem).hashchange() for triggering, like jQuery does for built-in events.
138
$.fn[ str_hashchange ] = function( fn ) {
139
return fn ? this.bind( str_hashchange, fn ) : this.trigger( str_hashchange );
142
// Property: jQuery.fn.hashchange.delay
144
// The numeric interval (in milliseconds) at which the <hashchange event>
145
// polling loop executes. Defaults to 50.
147
// Property: jQuery.fn.hashchange.domain
149
// If you're setting document.domain in your JavaScript, and you want hash
150
// history to work in IE6/7, not only must this property be set, but you must
151
// also set document.domain BEFORE jQuery is loaded into the page. This
152
// property is only applicable if you are supporting IE6/7 (or IE8 operating
153
// in "IE7 compatibility" mode).
155
// In addition, the <jQuery.fn.hashchange.src> property must be set to the
156
// path of the included "document-domain.html" file, which can be renamed or
157
// modified if necessary (note that the document.domain specified must be the
158
// same in both your main JavaScript as well as in this file).
162
// jQuery.fn.hashchange.domain = document.domain;
164
// Property: jQuery.fn.hashchange.src
166
// If, for some reason, you need to specify an Iframe src file (for example,
167
// when setting document.domain as in <jQuery.fn.hashchange.domain>), you can
168
// do so using this property. Note that when using this property, history
169
// won't be recorded in IE6/7 until the Iframe src file loads. This property
170
// is only applicable if you are supporting IE6/7 (or IE8 operating in "IE7
171
// compatibility" mode).
175
// jQuery.fn.hashchange.src = 'path/to/file.html';
177
$.fn[ str_hashchange ].delay = 50;
179
$.fn[ str_hashchange ].domain = null;
180
$.fn[ str_hashchange ].src = null;
183
// Event: hashchange event
185
// Fired when location.hash changes. In browsers that support it, the native
186
// HTML5 window.onhashchange event is used, otherwise a polling loop is
187
// initialized, running every <jQuery.fn.hashchange.delay> milliseconds to
188
// see if the hash has changed. In IE6/7 (and IE8 operating in "IE7
189
// compatibility" mode), a hidden Iframe is created to allow the back button
190
// and hash-based history to work.
192
// Usage as described in <jQuery.fn.hashchange>:
194
// > // Bind an event handler.
195
// > jQuery(window).hashchange( function(e) {
196
// > var hash = location.hash;
200
// > // Manually trigger the event handler.
201
// > jQuery(window).hashchange();
203
// A more verbose usage that allows for event namespacing:
205
// > // Bind an event handler.
206
// > jQuery(window).bind( 'hashchange', function(e) {
207
// > var hash = location.hash;
211
// > // Manually trigger the event handler.
212
// > jQuery(window).trigger( 'hashchange' );
216
// * The polling loop and Iframe are not created until at least one handler
217
// is actually bound to the 'hashchange' event.
218
// * If you need the bound handler(s) to execute immediately, in cases where
219
// a location.hash exists on page load, via bookmark or page refresh for
220
// example, use jQuery(window).hashchange() or the more verbose
221
// jQuery(window).trigger( 'hashchange' ).
222
// * The event can be bound before DOM ready, but since it won't be usable
223
// before then in IE6/7 (due to the necessary Iframe), recommended usage is
224
// to bind it inside a DOM ready handler.
226
// Override existing $.event.special.hashchange methods (allowing this plugin
227
// to be defined after jQuery BBQ in BBQ's source code).
228
special[ str_hashchange ] = $.extend( special[ str_hashchange ], {
230
// Called only when the first 'hashchange' event is bound to window.
232
// If window.onhashchange is supported natively, there's nothing to do..
233
if ( supports_onhashchange ) { return false; }
235
// Otherwise, we need to create our own. And we don't want to call this
236
// until the user binds to the event, just in case they never do, since it
237
// will create a polling loop and possibly even a hidden Iframe.
238
$( fake_onhashchange.start );
241
// Called only when the last 'hashchange' event is unbound from window.
242
teardown: function() {
243
// If window.onhashchange is supported natively, there's nothing to do..
244
if ( supports_onhashchange ) { return false; }
246
// Otherwise, we need to stop ours (if possible).
247
$( fake_onhashchange.stop );
252
// fake_onhashchange does all the work of triggering the window.onhashchange
253
// event for browsers that don't natively support it, including creating a
254
// polling loop to watch for hash changes and in IE 6/7 creating a hidden
255
// Iframe to enable back and forward.
256
fake_onhashchange = (function(){
260
// Remember the initial hash so it doesn't get triggered immediately.
261
last_hash = get_fragment(),
263
fn_retval = function(val){ return val; },
264
history_set = fn_retval,
265
history_get = fn_retval;
267
// Start the polling loop.
268
self.start = function() {
269
timeout_id || poll();
272
// Stop the polling loop.
273
self.stop = function() {
274
timeout_id && clearTimeout( timeout_id );
275
timeout_id = undefined;
278
// This polling loop checks every $.fn.hashchange.delay milliseconds to see
279
// if location.hash has changed, and triggers the 'hashchange' event on
280
// window when necessary.
282
var hash = get_fragment(),
283
history_hash = history_get( last_hash );
285
if ( hash !== last_hash ) {
286
history_set( last_hash = hash, history_hash );
288
$(window).trigger( str_hashchange );
290
} else if ( history_hash !== last_hash ) {
291
location.href = location.href.replace( /#.*/, '' ) + history_hash;
294
timeout_id = setTimeout( poll, $.fn[ str_hashchange ].delay );
297
// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
298
// vvvvvvvvvvvvvvvvvvv REMOVE IF NOT SUPPORTING IE6/7/8 vvvvvvvvvvvvvvvvvvv
299
// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
300
$.browser.msie && !supports_onhashchange && (function(){
301
// Not only do IE6/7 need the "magical" Iframe treatment, but so does IE8
302
// when running in "IE7 compatibility" mode.
307
// When the event is bound and polling starts in IE 6/7, create a hidden
308
// Iframe for history handling.
309
self.start = function(){
311
iframe_src = $.fn[ str_hashchange ].src;
312
iframe_src = iframe_src && iframe_src + get_fragment();
314
// Create hidden Iframe. Attempt to make Iframe as hidden as possible
315
// by using techniques from http://www.paciellogroup.com/blog/?p=604.
316
iframe = $('<iframe tabindex="-1" title="empty"/>').hide()
318
// When Iframe has completely loaded, initialize the history and
320
.one( 'load', function(){
321
iframe_src || history_set( get_fragment() );
325
// Load Iframe src if specified, otherwise nothing.
326
.attr( 'src', iframe_src || 'javascript:0' )
328
// Append Iframe after the end of the body to prevent unnecessary
329
// initial page scrolling (yes, this works).
330
.insertAfter( 'body' )[0].contentWindow;
332
// Whenever `document.title` changes, update the Iframe's title to
333
// prettify the back/next history menu entries. Since IE sometimes
334
// errors with "Unspecified error" the very first time this is set
335
// (yes, very useful) wrap this with a try/catch block.
336
doc.onpropertychange = function(){
338
if ( event.propertyName === 'title' ) {
339
iframe.document.title = doc.title;
347
// Override the "stop" method since an IE6/7 Iframe was created. Even
348
// if there are no longer any bound event handlers, the polling loop
349
// is still necessary for back/next to work at all!
350
self.stop = fn_retval;
352
// Get history by looking at the hidden Iframe's location.hash.
353
history_get = function() {
354
return get_fragment( iframe.location.href );
357
// Set a new history item by opening and then closing the Iframe
358
// document, *then* setting its location.hash. If document.domain has
359
// been set, update that as well.
360
history_set = function( hash, history_hash ) {
361
var iframe_doc = iframe.document,
362
domain = $.fn[ str_hashchange ].domain;
364
if ( hash !== history_hash ) {
365
// Update Iframe with any initial `document.title` that might be set.
366
iframe_doc.title = doc.title;
368
// Opening the Iframe's document after it has been closed is what
369
// actually adds a history entry.
372
// Set document.domain for the Iframe document as well, if necessary.
373
domain && iframe_doc.write( '<script>document.domain="' + domain + '"</script>' );
377
// Update the Iframe's hash, for great justice.
378
iframe.location.hash = hash;
383
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
384
// ^^^^^^^^^^^^^^^^^^^ REMOVE IF NOT SUPPORTING IE6/7/8 ^^^^^^^^^^^^^^^^^^^
385
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^