~openerp-dev/openerp-web/trunk-jquery1.9-ppa

« back to all changes in this revision

Viewing changes to addons/web/static/lib/jquery.ba-bbq/jquery.ba-bbq.js

  • Committer: Prashant Panchal(OpenERP)
  • Date: 2014-04-16 09:24:51 UTC
  • Revision ID: ppa@tinyerp.com-20140416092451-outv36dahgip1860
[IMP] add jquery-migrate-1.1.1.j & jquery-1.9.1.js & change in web

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*!
2
 
 * jQuery BBQ: Back Button & Query Library - v1.2.1 - 2/17/2010
 
2
 * jQuery BBQ: Back Button & Query Library - v1.4pre - 1/15/2013
3
3
 * http://benalman.com/projects/jquery-bbq-plugin/
4
4
 * 
5
 
 * Copyright (c) 2010 "Cowboy" Ben Alman
 
5
 * Copyright (c) 2010-2013 "Cowboy" Ben Alman
6
6
 * Dual licensed under the MIT and GPL licenses.
7
7
 * http://benalman.com/about/license/
8
8
 */
9
9
 
10
10
// Script: jQuery BBQ: Back Button & Query Library
11
11
//
12
 
// *Version: 1.2.1, Last updated: 2/17/2010*
 
12
// *Version: 1.4pre, Last updated: 1/15/2013*
13
13
// 
14
14
// Project Home - http://benalman.com/projects/jquery-bbq-plugin/
15
15
// GitHub       - http://github.com/cowboy/jquery-bbq/
16
16
// Source       - http://github.com/cowboy/jquery-bbq/raw/master/jquery.ba-bbq.js
17
 
// (Minified)   - http://github.com/cowboy/jquery-bbq/raw/master/jquery.ba-bbq.min.js (4.0kb)
 
17
// (Minified)   - http://github.com/cowboy/jquery-bbq/raw/master/jquery.ba-bbq.min.js (2.2kb gzipped)
18
18
// 
19
19
// About: License
20
20
// 
21
 
// Copyright (c) 2010 "Cowboy" Ben Alman,
 
21
// Copyright (c) 2010-2013 "Cowboy" Ben Alman,
22
22
// Dual licensed under the MIT and GPL licenses.
23
23
// http://benalman.com/about/license/
24
24
// 
38
38
// tested with, what browsers it has been tested in, and where the unit tests
39
39
// reside (so you can test it yourself).
40
40
// 
41
 
// jQuery Versions - 1.3.2, 1.4.1, 1.4.2
42
 
// Browsers Tested - Internet Explorer 6-8, Firefox 2-3.7, Safari 3-4,
43
 
//                   Chrome 4-5, Opera 9.6-10.1.
 
41
// jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
 
42
// Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5,
 
43
//                   Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5.
44
44
// Unit Tests      - http://benalman.com/code/projects/jquery-bbq/unit/
45
45
// 
46
46
// About: Release History
47
47
// 
 
48
// 1.4pre - (1/15/2013) Removed $.browser reference to work with jQuery 1.9
 
49
// 1.3pre - (8/26/2010) Integrated <jQuery hashchange event> v1.3, which adds
 
50
//         document.title and document.domain support in IE6/7, BlackBerry
 
51
//         support, better Iframe hiding for accessibility reasons, and the new
 
52
//         <jQuery.fn.hashchange> "shortcut" method. Added the
 
53
//         <jQuery.param.sorted> method which reduces the possibility of
 
54
//         extraneous hashchange event triggering. Added the
 
55
//         <jQuery.param.fragment.ajaxCrawlable> method which can be used to
 
56
//         enable Google "AJAX Crawlable mode."
48
57
// 1.2.1 - (2/17/2010) Actually fixed the stale window.location Safari bug from
49
58
//         <jQuery hashchange event> in BBQ, which was the main reason for the
50
59
//         previous release!
87
96
    
88
97
    // Method / object references.
89
98
    jq_param = $.param,
 
99
    jq_param_sorted,
90
100
    jq_param_fragment,
91
101
    jq_deparam,
92
102
    jq_deparam_fragment,
94
104
    jq_bbq_pushState,
95
105
    jq_bbq_getState,
96
106
    jq_elemUrlAttr,
97
 
    jq_event_special = $.event.special,
 
107
    special = $.event.special,
98
108
    
99
109
    // Reused strings.
100
110
    str_hashchange = 'hashchange',
101
111
    str_querystring = 'querystring',
102
112
    str_fragment = 'fragment',
103
113
    str_elemUrlAttr = 'elemUrlAttr',
104
 
    str_location = 'location',
105
114
    str_href = 'href',
106
115
    str_src = 'src',
107
116
    
108
117
    // Reused RegExp.
109
 
    re_trim_querystring = /^.*\?|#.*$/g,
110
 
    re_trim_fragment = /^.*\#/,
 
118
    re_params_querystring = /^.*\?|#.*$/g,
 
119
    re_params_fragment,
 
120
    re_fragment,
111
121
    re_no_escape,
112
122
    
 
123
    ajax_crawlable,
 
124
    fragment_prefix,
 
125
    
113
126
    // Used by jQuery.elemUrlAttr.
114
127
    elemUrlAttr_cache = {};
115
128
  
132
145
  // Get location.hash (or what you'd expect location.hash to be) sans any
133
146
  // leading #. Thanks for making this necessary, Firefox!
134
147
  function get_fragment( url ) {
135
 
    return url.replace( /^[^#]*#?(.*)$/, '$1' );
 
148
    return url.replace( re_fragment, '$2' );
136
149
  };
137
150
  
138
151
  // Get location.search (or what you'd expect location.search to be) sans any
146
159
  // Method: jQuery.param.querystring
147
160
  // 
148
161
  // Retrieve the query string from a URL or if no arguments are passed, the
149
 
  // current window.location.
 
162
  // current window.location.href.
150
163
  // 
151
164
  // Usage:
152
165
  // 
155
168
  // Arguments:
156
169
  // 
157
170
  //  url - (String) A URL containing query string params to be parsed. If url
158
 
  //    is not passed, the current window.location is used.
 
171
  //    is not passed, the current window.location.href is used.
159
172
  // 
160
173
  // Returns:
161
174
  // 
189
202
  // 
190
203
  // Returns:
191
204
  // 
192
 
  //  (String) Either a params string with urlencoded data or a URL with a
193
 
  //    urlencoded query string in the format 'a=b&c=d&e=f'.
 
205
  //  (String) A URL with a urlencoded query string in the format '?a=b&c=d&e=f'.
194
206
  
195
207
  // Method: jQuery.param.fragment
196
208
  // 
197
209
  // Retrieve the fragment (hash) from a URL or if no arguments are passed, the
198
 
  // current window.location.
 
210
  // current window.location.href.
199
211
  // 
200
212
  // Usage:
201
213
  // 
204
216
  // Arguments:
205
217
  // 
206
218
  //  url - (String) A URL containing fragment (hash) params to be parsed. If
207
 
  //    url is not passed, the current window.location is used.
 
219
  //    url is not passed, the current window.location.href is used.
208
220
  // 
209
221
  // Returns:
210
222
  // 
238
250
  // 
239
251
  // Returns:
240
252
  // 
241
 
  //  (String) Either a params string with urlencoded data or a URL with a
242
 
  //    urlencoded fragment (hash) in the format 'a=b&c=d&e=f'.
 
253
  //  (String) A URL with a urlencoded fragment (hash) in the format '#a=b&c=d&e=f'.
243
254
  
244
255
  function jq_param_sub( is_fragment, get_func, url, params, merge_mode ) {
245
256
    var result,
254
265
      // matches[1] = url part that precedes params, not including trailing ?/#
255
266
      // matches[2] = params, not including leading ?/#
256
267
      // matches[3] = if in 'querystring' mode, hash including leading #, otherwise ''
257
 
      matches = url.match( is_fragment ? /^([^#]*)\#?(.*)$/ : /^([^#?]*)\??([^#]*)(#?.*)/ );
 
268
      matches = url.match( is_fragment ? re_fragment : /^([^#?]*)\??([^#]*)(#?.*)/ );
258
269
      
259
270
      // Get the hash if in 'querystring' mode, and it exists.
260
271
      hash = matches[3] || '';
262
273
      if ( merge_mode === 2 && is_string( params ) ) {
263
274
        // If merge_mode is 2 and params is a string, merge the fragment / query
264
275
        // string into the URL wholesale, without converting it into an object.
265
 
        qs = params.replace( is_fragment ? re_trim_fragment : re_trim_querystring, '' );
 
276
        qs = params.replace( is_fragment ? re_params_fragment : re_params_querystring, '' );
266
277
        
267
278
      } else {
268
279
        // Convert relevant params in url to object.
280
291
          : merge_mode === 1  ? $.extend( {}, params, url_params )  // url params override passed params
281
292
          : $.extend( {}, url_params, params );                     // passed params override url params
282
293
        
283
 
        // Convert params object to a string.
284
 
        qs = jq_param( qs );
 
294
        // Convert params object into a sorted params string.
 
295
        qs = jq_param_sorted( qs );
285
296
        
286
297
        // Unescape characters specified via $.param.noEscape. Since only hash-
287
298
        // history users have requested this feature, it's only enabled for
294
305
      // Build URL from the base url, querystring and hash. In 'querystring'
295
306
      // mode, ? is only added if a query string exists. In 'fragment' mode, #
296
307
      // is always added.
297
 
      result = matches[1] + ( is_fragment ? '#' : qs || !matches[1] ? '?' : '' ) + qs + hash;
 
308
      result = matches[1] + ( is_fragment ? fragment_prefix : qs || !matches[1] ? '?' : '' ) + qs + hash;
298
309
      
299
310
    } else {
300
311
      // If URL was passed in, parse params from URL string, otherwise parse
301
 
      // params from window.location.
302
 
      result = get_func( url !== undefined ? url : window[ str_location ][ str_href ] );
 
312
      // params from window.location.href.
 
313
      result = get_func( url !== undefined ? url : location.href );
303
314
    }
304
315
    
305
316
    return result;
308
319
  jq_param[ str_querystring ]                  = curry( jq_param_sub, 0, get_querystring );
309
320
  jq_param[ str_fragment ] = jq_param_fragment = curry( jq_param_sub, 1, get_fragment );
310
321
  
 
322
  // Method: jQuery.param.sorted
 
323
  // 
 
324
  // Returns a params string equivalent to that returned by the internal
 
325
  // jQuery.param method, but sorted, which makes it suitable for use as a
 
326
  // cache key.
 
327
  // 
 
328
  // For example, in most browsers jQuery.param({z:1,a:2}) returns "z=1&a=2"
 
329
  // and jQuery.param({a:2,z:1}) returns "a=2&z=1". Even though both the
 
330
  // objects being serialized and the resulting params strings are equivalent,
 
331
  // if these params strings were set into the location.hash fragment
 
332
  // sequentially, the hashchange event would be triggered unnecessarily, since
 
333
  // the strings are different (even though the data described by them is the
 
334
  // same). By sorting the params string, unecessary hashchange event triggering
 
335
  // can be avoided.
 
336
  // 
 
337
  // Usage:
 
338
  // 
 
339
  // > jQuery.param.sorted( obj [, traditional ] );
 
340
  // 
 
341
  // Arguments:
 
342
  // 
 
343
  //  obj - (Object) An object to be serialized.
 
344
  //  traditional - (Boolean) Params deep/shallow serialization mode. See the
 
345
  //    documentation at http://api.jquery.com/jQuery.param/ for more detail.
 
346
  // 
 
347
  // Returns:
 
348
  // 
 
349
  //  (String) A sorted params string.
 
350
  
 
351
  jq_param.sorted = jq_param_sorted = function( a, traditional ) {
 
352
    var arr = [],
 
353
      obj = {};
 
354
    
 
355
    $.each( jq_param( a, traditional ).split( '&' ), function(i,v){
 
356
      var key = v.replace( /(?:%5B|=).*$/, '' ),
 
357
        key_obj = obj[ key ];
 
358
      
 
359
      if ( !key_obj ) {
 
360
        key_obj = obj[ key ] = [];
 
361
        arr.push( key );
 
362
      }
 
363
      
 
364
      key_obj.push( v );
 
365
    });
 
366
    
 
367
    return $.map( arr.sort(), function(v){
 
368
      return obj[ v ];
 
369
    }).join( '&' );
 
370
  };
 
371
  
311
372
  // Method: jQuery.param.fragment.noEscape
312
373
  // 
313
374
  // Specify characters that will be left unescaped when fragments are created
346
407
  // "uglifying up the URL" the most.
347
408
  jq_param_fragment.noEscape( ',/' );
348
409
  
 
410
  // Method: jQuery.param.fragment.ajaxCrawlable
 
411
  // 
 
412
  // TODO: DESCRIBE
 
413
  // 
 
414
  // Usage:
 
415
  // 
 
416
  // > jQuery.param.fragment.ajaxCrawlable( [ state ] );
 
417
  // 
 
418
  // Arguments:
 
419
  // 
 
420
  //  state - (Boolean) TODO: DESCRIBE
 
421
  // 
 
422
  // Returns:
 
423
  // 
 
424
  //  (Boolean) The current ajaxCrawlable state.
 
425
  
 
426
  jq_param_fragment.ajaxCrawlable = function( state ) {
 
427
    if ( state !== undefined ) {
 
428
      if ( state ) {
 
429
        re_params_fragment = /^.*(?:#!|#)/;
 
430
        re_fragment = /^([^#]*)(?:#!|#)?(.*)$/;
 
431
        fragment_prefix = '#!';
 
432
      } else {
 
433
        re_params_fragment = /^.*#/;
 
434
        re_fragment = /^([^#]*)#?(.*)$/;
 
435
        fragment_prefix = '#';
 
436
      }
 
437
      ajax_crawlable = !!state;
 
438
    }
 
439
    
 
440
    return ajax_crawlable;
 
441
  };
 
442
  
 
443
  jq_param_fragment.ajaxCrawlable( 0 );
 
444
  
349
445
  // Section: Deparam (from string)
350
446
  // 
351
447
  // Method: jQuery.deparam
462
558
  
463
559
  // Method: jQuery.deparam.querystring
464
560
  // 
465
 
  // Parse the query string from a URL or the current window.location,
 
561
  // Parse the query string from a URL or the current window.location.href,
466
562
  // deserializing it into an object, optionally coercing numbers, booleans,
467
563
  // null and undefined values.
468
564
  // 
473
569
  // Arguments:
474
570
  // 
475
571
  //  url - (String) An optional params string or URL containing query string
476
 
  //    params to be parsed. If url is omitted, the current window.location
477
 
  //    is used.
 
572
  //    params to be parsed. If url is omitted, the current
 
573
  //    window.location.href is used.
478
574
  //  coerce - (Boolean) If true, coerces any numbers or true, false, null, and
479
575
  //    undefined to their actual value. Defaults to false if omitted.
480
576
  // 
484
580
  
485
581
  // Method: jQuery.deparam.fragment
486
582
  // 
487
 
  // Parse the fragment (hash) from a URL or the current window.location,
 
583
  // Parse the fragment (hash) from a URL or the current window.location.href,
488
584
  // deserializing it into an object, optionally coercing numbers, booleans,
489
585
  // null and undefined values.
490
586
  // 
495
591
  // Arguments:
496
592
  // 
497
593
  //  url - (String) An optional params string or URL containing fragment (hash)
498
 
  //    params to be parsed. If url is omitted, the current window.location
 
594
  //    params to be parsed. If url is omitted, the current window.location.href
499
595
  //    is used.
500
596
  //  coerce - (Boolean) If true, coerces any numbers or true, false, null, and
501
597
  //    undefined to their actual value. Defaults to false if omitted.
511
607
      url_or_params = jq_param[ is_fragment ? str_fragment : str_querystring ]();
512
608
    } else {
513
609
      url_or_params = is_string( url_or_params )
514
 
        ? url_or_params.replace( is_fragment ? re_trim_fragment : re_trim_querystring, '' )
 
610
        ? url_or_params.replace( is_fragment ? re_params_fragment : re_params_querystring, '' )
515
611
        : url_or_params;
516
612
    }
517
613
    
715
811
    
716
812
    var has_args = params !== undefined,
717
813
      // Merge params into window.location using $.param.fragment.
718
 
      url = jq_param_fragment( window[ str_location ][ str_href ],
 
814
      url = jq_param_fragment( location.href,
719
815
        has_args ? params : {}, has_args ? merge_mode : 2 );
720
816
    
721
 
    // Set new window.location.href. If hash is empty, use just # to prevent
722
 
    // browser from reloading the page. Note that Safari 3 & Chrome barf on
723
 
    // location.hash = '#'.
724
 
    window[ str_location ][ str_href ] = url + ( /#/.test( url ) ? '' : '#' );
 
817
    // Set new window.location.href. Note that Safari 3 & Chrome barf on
 
818
    // location.hash = '#' so the entire URL is set.
 
819
    location.href = url;
725
820
  };
726
821
  
727
822
  // Method: jQuery.bbq.getState
850
945
  //   required to enable the augmented event object in jQuery 1.4.2 and newer.
851
946
  // * See <jQuery hashchange event> for more detailed information.
852
947
  
853
 
  jq_event_special[ str_hashchange ] = $.extend( jq_event_special[ str_hashchange ], {
 
948
  special[ str_hashchange ] = $.extend( special[ str_hashchange ], {
854
949
    
855
950
    // Augmenting the event object with the .fragment property and .getState
856
951
    // method requires jQuery 1.4 or newer. Note: with 1.3.2, everything will
892
987
})(jQuery,this);
893
988
 
894
989
/*!
895
 
 * jQuery hashchange event - v1.2 - 2/11/2010
 
990
 * jQuery hashchange event - v1.3 - 7/21/2010
896
991
 * http://benalman.com/projects/jquery-hashchange-plugin/
897
992
 * 
898
993
 * Copyright (c) 2010 "Cowboy" Ben Alman
902
997
 
903
998
// Script: jQuery hashchange event
904
999
//
905
 
// *Version: 1.2, Last updated: 2/11/2010*
 
1000
// *Version: 1.3, Last updated: 7/21/2010*
906
1001
// 
907
1002
// Project Home - http://benalman.com/projects/jquery-hashchange-plugin/
908
1003
// GitHub       - http://github.com/cowboy/jquery-hashchange/
909
1004
// Source       - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js
910
 
// (Minified)   - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (1.1kb)
 
1005
// (Minified)   - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (0.8kb gzipped)
911
1006
// 
912
1007
// About: License
913
1008
// 
917
1012
// 
918
1013
// About: Examples
919
1014
// 
920
 
// This working example, complete with fully commented code, illustrate one way
921
 
// in which this plugin can be used.
 
1015
// These working examples, complete with fully commented code, illustrate a few
 
1016
// ways in which this plugin can be used.
922
1017
// 
923
1018
// hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/
 
1019
// document.domain - http://benalman.com/code/projects/jquery-hashchange/examples/document_domain/
924
1020
// 
925
1021
// About: Support and Testing
926
1022
// 
928
1024
// tested with, what browsers it has been tested in, and where the unit tests
929
1025
// reside (so you can test it yourself).
930
1026
// 
931
 
// jQuery Versions - 1.3.2, 1.4.1, 1.4.2
932
 
// Browsers Tested - Internet Explorer 6-8, Firefox 2-3.7, Safari 3-4, Chrome, Opera 9.6-10.1.
 
1027
// jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
 
1028
// Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5,
 
1029
//                   Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5.
933
1030
// Unit Tests      - http://benalman.com/code/projects/jquery-hashchange/unit/
934
1031
// 
935
1032
// About: Known issues
936
1033
// 
937
 
// While this jQuery hashchange event implementation is quite stable and robust,
938
 
// there are a few unfortunate browser bugs surrounding expected hashchange
939
 
// event-based behaviors, independent of any JavaScript window.onhashchange
940
 
// abstraction. See the following examples for more information:
 
1034
// While this jQuery hashchange event implementation is quite stable and
 
1035
// robust, there are a few unfortunate browser bugs surrounding expected
 
1036
// hashchange event-based behaviors, independent of any JavaScript
 
1037
// window.onhashchange abstraction. See the following examples for more
 
1038
// information:
941
1039
// 
942
1040
// Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/
943
1041
// Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/
944
1042
// WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/
945
1043
// Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/
946
1044
// 
 
1045
// Also note that should a browser natively support the window.onhashchange 
 
1046
// event, but not report that it does, the fallback polling loop will be used.
 
1047
// 
947
1048
// About: Release History
948
1049
// 
 
1050
// 1.3   - (7/21/2010) Reorganized IE6/7 Iframe code to make it more
 
1051
//         "removable" for mobile-only development. Added IE6/7 document.title
 
1052
//         support. Attempted to make Iframe as hidden as possible by using
 
1053
//         techniques from http://www.paciellogroup.com/blog/?p=604. Added 
 
1054
//         support for the "shortcut" format $(window).hashchange( fn ) and
 
1055
//         $(window).hashchange() like jQuery provides for built-in events.
 
1056
//         Renamed jQuery.hashchangeDelay to <jQuery.fn.hashchange.delay> and
 
1057
//         lowered its default value to 50. Added <jQuery.fn.hashchange.domain>
 
1058
//         and <jQuery.fn.hashchange.src> properties plus document-domain.html
 
1059
//         file to address access denied issues when setting document.domain in
 
1060
//         IE6/7.
949
1061
// 1.2   - (2/11/2010) Fixed a bug where coming back to a page using this plugin
950
1062
//         from a page on another domain would cause an error in Safari 4. Also,
951
1063
//         IE6/7 Iframe is now inserted after the body (this actually works),
964
1076
(function($,window,undefined){
965
1077
  '$:nomunge'; // Used by YUI compressor.
966
1078
  
967
 
  // Method / object references.
968
 
  var fake_onhashchange,
969
 
    jq_event_special = $.event.special,
970
 
    
971
 
    // Reused strings.
972
 
    str_location = 'location',
973
 
    str_hashchange = 'hashchange',
974
 
    str_href = 'href',
975
 
    
976
 
    // IE6/7 specifically need some special love when it comes to back-button
977
 
    // support, so let's do a little browser sniffing..
978
 
    browser = $.browser,
979
 
    mode = document.documentMode,
980
 
    is_old_ie = browser.msie && ( mode === undefined || mode < 8 ),
981
 
    
982
 
    // Does the browser support window.onhashchange? Test for IE version, since
983
 
    // IE8 incorrectly reports this when in "IE7" or "IE8 Compatibility View"!
984
 
    supports_onhashchange = 'on' + str_hashchange in window && !is_old_ie;
 
1079
  // Reused string.
 
1080
  var str_hashchange = 'hashchange',
 
1081
    
 
1082
    // Method / object references.
 
1083
    doc = document,
 
1084
    fake_onhashchange,
 
1085
    special = $.event.special,
 
1086
    
 
1087
    // Does the browser support window.onhashchange? Note that IE8 running in
 
1088
    // IE7 compatibility mode reports true for 'onhashchange' in window, even
 
1089
    // though the event isn't supported, so also test document.documentMode.
 
1090
    doc_mode = doc.documentMode,
 
1091
    supports_onhashchange = 'on' + str_hashchange in window && ( doc_mode === undefined || doc_mode > 7 );
985
1092
  
986
1093
  // Get location.hash (or what you'd expect location.hash to be) sans any
987
1094
  // leading #. Thanks for making this necessary, Firefox!
988
1095
  function get_fragment( url ) {
989
 
    url = url || window[ str_location ][ str_href ];
990
 
    return url.replace( /^[^#]*#?(.*)$/, '$1' );
991
 
  };
992
 
  
993
 
  // Property: jQuery.hashchangeDelay
 
1096
    url = url || location.href;
 
1097
    return '#' + url.replace( /^[^#]*#?(.*)$/, '$1' );
 
1098
  };
 
1099
  
 
1100
  // Method: jQuery.fn.hashchange
 
1101
  // 
 
1102
  // Bind a handler to the window.onhashchange event or trigger all bound
 
1103
  // window.onhashchange event handlers. This behavior is consistent with
 
1104
  // jQuery's built-in event handlers.
 
1105
  // 
 
1106
  // Usage:
 
1107
  // 
 
1108
  // > jQuery(window).hashchange( [ handler ] );
 
1109
  // 
 
1110
  // Arguments:
 
1111
  // 
 
1112
  //  handler - (Function) Optional handler to be bound to the hashchange
 
1113
  //    event. This is a "shortcut" for the more verbose form:
 
1114
  //    jQuery(window).bind( 'hashchange', handler ). If handler is omitted,
 
1115
  //    all bound window.onhashchange event handlers will be triggered. This
 
1116
  //    is a shortcut for the more verbose
 
1117
  //    jQuery(window).trigger( 'hashchange' ). These forms are described in
 
1118
  //    the <hashchange event> section.
 
1119
  // 
 
1120
  // Returns:
 
1121
  // 
 
1122
  //  (jQuery) The initial jQuery collection of elements.
 
1123
  
 
1124
  // Allow the "shortcut" format $(elem).hashchange( fn ) for binding and
 
1125
  // $(elem).hashchange() for triggering, like jQuery does for built-in events.
 
1126
  $.fn[ str_hashchange ] = function( fn ) {
 
1127
    return fn ? this.bind( str_hashchange, fn ) : this.trigger( str_hashchange );
 
1128
  };
 
1129
  
 
1130
  // Property: jQuery.fn.hashchange.delay
994
1131
  // 
995
1132
  // The numeric interval (in milliseconds) at which the <hashchange event>
996
 
  // polling loop executes. Defaults to 100.
997
 
  
998
 
  $[ str_hashchange + 'Delay' ] = 100;
 
1133
  // polling loop executes. Defaults to 50.
 
1134
  
 
1135
  // Property: jQuery.fn.hashchange.domain
 
1136
  // 
 
1137
  // If you're setting document.domain in your JavaScript, and you want hash
 
1138
  // history to work in IE6/7, not only must this property be set, but you must
 
1139
  // also set document.domain BEFORE jQuery is loaded into the page. This
 
1140
  // property is only applicable if you are supporting IE6/7 (or IE8 operating
 
1141
  // in "IE7 compatibility" mode).
 
1142
  // 
 
1143
  // In addition, the <jQuery.fn.hashchange.src> property must be set to the
 
1144
  // path of the included "document-domain.html" file, which can be renamed or
 
1145
  // modified if necessary (note that the document.domain specified must be the
 
1146
  // same in both your main JavaScript as well as in this file).
 
1147
  // 
 
1148
  // Usage:
 
1149
  // 
 
1150
  // jQuery.fn.hashchange.domain = document.domain;
 
1151
  
 
1152
  // Property: jQuery.fn.hashchange.src
 
1153
  // 
 
1154
  // If, for some reason, you need to specify an Iframe src file (for example,
 
1155
  // when setting document.domain as in <jQuery.fn.hashchange.domain>), you can
 
1156
  // do so using this property. Note that when using this property, history
 
1157
  // won't be recorded in IE6/7 until the Iframe src file loads. This property
 
1158
  // is only applicable if you are supporting IE6/7 (or IE8 operating in "IE7
 
1159
  // compatibility" mode).
 
1160
  // 
 
1161
  // Usage:
 
1162
  // 
 
1163
  // jQuery.fn.hashchange.src = 'path/to/file.html';
 
1164
  
 
1165
  $.fn[ str_hashchange ].delay = 50;
 
1166
  /*
 
1167
  $.fn[ str_hashchange ].domain = null;
 
1168
  $.fn[ str_hashchange ].src = null;
 
1169
  */
999
1170
  
1000
1171
  // Event: hashchange event
1001
1172
  // 
1002
1173
  // Fired when location.hash changes. In browsers that support it, the native
1003
 
  // window.onhashchange event is used (IE8, FF3.6), otherwise a polling loop is
1004
 
  // initialized, running every <jQuery.hashchangeDelay> milliseconds to see if
1005
 
  // the hash has changed. In IE 6 and 7, a hidden Iframe is created to allow
1006
 
  // the back button and hash-based history to work.
1007
 
  // 
1008
 
  // Usage:
1009
 
  // 
1010
 
  // > $(window).bind( 'hashchange', function(e) {
1011
 
  // >   var hash = location.hash;
1012
 
  // >   ...
1013
 
  // > });
 
1174
  // HTML5 window.onhashchange event is used, otherwise a polling loop is
 
1175
  // initialized, running every <jQuery.fn.hashchange.delay> milliseconds to
 
1176
  // see if the hash has changed. In IE6/7 (and IE8 operating in "IE7
 
1177
  // compatibility" mode), a hidden Iframe is created to allow the back button
 
1178
  // and hash-based history to work.
 
1179
  // 
 
1180
  // Usage as described in <jQuery.fn.hashchange>:
 
1181
  // 
 
1182
  // > // Bind an event handler.
 
1183
  // > jQuery(window).hashchange( function(e) {
 
1184
  // >   var hash = location.hash;
 
1185
  // >   ...
 
1186
  // > });
 
1187
  // > 
 
1188
  // > // Manually trigger the event handler.
 
1189
  // > jQuery(window).hashchange();
 
1190
  // 
 
1191
  // A more verbose usage that allows for event namespacing:
 
1192
  // 
 
1193
  // > // Bind an event handler.
 
1194
  // > jQuery(window).bind( 'hashchange', function(e) {
 
1195
  // >   var hash = location.hash;
 
1196
  // >   ...
 
1197
  // > });
 
1198
  // > 
 
1199
  // > // Manually trigger the event handler.
 
1200
  // > jQuery(window).trigger( 'hashchange' );
1014
1201
  // 
1015
1202
  // Additional Notes:
1016
1203
  // 
1017
 
  // * The polling loop and Iframe are not created until at least one callback
1018
 
  //   is actually bound to 'hashchange'.
1019
 
  // * If you need the bound callback(s) to execute immediately, in cases where
1020
 
  //   the page 'state' exists on page load (via bookmark or page refresh, for
1021
 
  //   example) use $(window).trigger( 'hashchange' );
 
1204
  // * The polling loop and Iframe are not created until at least one handler
 
1205
  //   is actually bound to the 'hashchange' event.
 
1206
  // * If you need the bound handler(s) to execute immediately, in cases where
 
1207
  //   a location.hash exists on page load, via bookmark or page refresh for
 
1208
  //   example, use jQuery(window).hashchange() or the more verbose 
 
1209
  //   jQuery(window).trigger( 'hashchange' ).
1022
1210
  // * The event can be bound before DOM ready, but since it won't be usable
1023
1211
  //   before then in IE6/7 (due to the necessary Iframe), recommended usage is
1024
 
  //   to bind it inside a $(document).ready() callback.
 
1212
  //   to bind it inside a DOM ready handler.
1025
1213
  
1026
 
  jq_event_special[ str_hashchange ] = $.extend( jq_event_special[ str_hashchange ], {
 
1214
  // Override existing $.event.special.hashchange methods (allowing this plugin
 
1215
  // to be defined after jQuery BBQ in BBQ's source code).
 
1216
  special[ str_hashchange ] = $.extend( special[ str_hashchange ], {
1027
1217
    
1028
1218
    // Called only when the first 'hashchange' event is bound to window.
1029
1219
    setup: function() {
1054
1244
  fake_onhashchange = (function(){
1055
1245
    var self = {},
1056
1246
      timeout_id,
1057
 
      iframe,
1058
 
      set_history,
1059
 
      get_history;
1060
 
    
1061
 
    // Initialize. In IE 6/7, creates a hidden Iframe for history handling.
1062
 
    function init(){
1063
 
      // Most browsers don't need special methods here..
1064
 
      set_history = get_history = function(val){ return val; };
1065
 
      
1066
 
      // But IE6/7 do!
1067
 
      if ( is_old_ie ) {
1068
 
        
1069
 
        // Create hidden Iframe after the end of the body to prevent initial
1070
 
        // page load from scrolling unnecessarily.
1071
 
        iframe = $('<iframe src="javascript:0"/>').hide().insertAfter( 'body' )[0].contentWindow;
1072
 
        
1073
 
        // Get history by looking at the hidden Iframe's location.hash.
1074
 
        get_history = function() {
1075
 
          return get_fragment( iframe.document[ str_location ][ str_href ] );
1076
 
        };
1077
 
        
1078
 
        // Set a new history item by opening and then closing the Iframe
1079
 
        // document, *then* setting its location.hash.
1080
 
        set_history = function( hash, history_hash ) {
1081
 
          if ( hash !== history_hash ) {
1082
 
            var doc = iframe.document;
1083
 
            doc.open().close();
1084
 
            doc[ str_location ].hash = '#' + hash;
1085
 
          }
1086
 
        };
1087
 
        
1088
 
        // Set initial history.
1089
 
        set_history( get_fragment() );
1090
 
      }
1091
 
    };
 
1247
      
 
1248
      // Remember the initial hash so it doesn't get triggered immediately.
 
1249
      last_hash = get_fragment(),
 
1250
      
 
1251
      fn_retval = function(val){ return val; },
 
1252
      history_set = fn_retval,
 
1253
      history_get = fn_retval;
1092
1254
    
1093
1255
    // Start the polling loop.
1094
1256
    self.start = function() {
1095
 
      // Polling loop is already running!
1096
 
      if ( timeout_id ) { return; }
1097
 
      
1098
 
      // Remember the initial hash so it doesn't get triggered immediately.
1099
 
      var last_hash = get_fragment();
1100
 
      
1101
 
      // Initialize if not yet initialized.
1102
 
      set_history || init();
1103
 
      
1104
 
      // This polling loop checks every $.hashchangeDelay milliseconds to see if
1105
 
      // location.hash has changed, and triggers the 'hashchange' event on
1106
 
      // window when necessary.
1107
 
      (function loopy(){
1108
 
        var hash = get_fragment(),
1109
 
          history_hash = get_history( last_hash );
1110
 
        
1111
 
        if ( hash !== last_hash ) {
1112
 
          set_history( last_hash = hash, history_hash );
1113
 
          
1114
 
          $(window).trigger( str_hashchange );
1115
 
          
1116
 
        } else if ( history_hash !== last_hash ) {
1117
 
          window[ str_location ][ str_href ] = window[ str_location ][ str_href ].replace( /#.*/, '' ) + '#' + history_hash;
1118
 
        }
1119
 
        
1120
 
        timeout_id = setTimeout( loopy, $[ str_hashchange + 'Delay' ] );
1121
 
      })();
 
1257
      timeout_id || poll();
1122
1258
    };
1123
1259
    
1124
 
    // Stop the polling loop, but only if an IE6/7 Iframe wasn't created. In
1125
 
    // that case, even if there are no longer any bound event handlers, the
1126
 
    // polling loop is still necessary for back/next to work at all!
 
1260
    // Stop the polling loop.
1127
1261
    self.stop = function() {
1128
 
      if ( !iframe ) {
1129
 
        timeout_id && clearTimeout( timeout_id );
1130
 
        timeout_id = 0;
 
1262
      timeout_id && clearTimeout( timeout_id );
 
1263
      timeout_id = undefined;
 
1264
    };
 
1265
    
 
1266
    // This polling loop checks every $.fn.hashchange.delay milliseconds to see
 
1267
    // if location.hash has changed, and triggers the 'hashchange' event on
 
1268
    // window when necessary.
 
1269
    function poll() {
 
1270
      var hash = get_fragment(),
 
1271
        history_hash = history_get( last_hash );
 
1272
      
 
1273
      if ( hash !== last_hash ) {
 
1274
        history_set( last_hash = hash, history_hash );
 
1275
        
 
1276
        $(window).trigger( str_hashchange );
 
1277
        
 
1278
      } else if ( history_hash !== last_hash ) {
 
1279
        location.href = location.href.replace( /#.*/, '' ) + history_hash;
1131
1280
      }
 
1281
      
 
1282
      timeout_id = setTimeout( poll, $.fn[ str_hashchange ].delay );
1132
1283
    };
1133
1284
    
 
1285
    // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
 
1286
    // vvvvvvvvvvvvvvvvvvv REMOVE IF NOT SUPPORTING IE6/7/8 vvvvvvvvvvvvvvvvvvv
 
1287
    // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
 
1288
    (navigator.userAgent.match(/MSIE/i) !== null) && !supports_onhashchange && (function(){
 
1289
      // Not only do IE6/7 need the "magical" Iframe treatment, but so does IE8
 
1290
      // when running in "IE7 compatibility" mode.
 
1291
      
 
1292
      var iframe,
 
1293
        iframe_src;
 
1294
      
 
1295
      // When the event is bound and polling starts in IE 6/7, create a hidden
 
1296
      // Iframe for history handling.
 
1297
      self.start = function(){
 
1298
        if ( !iframe ) {
 
1299
          iframe_src = $.fn[ str_hashchange ].src;
 
1300
          iframe_src = iframe_src && iframe_src + get_fragment();
 
1301
          
 
1302
          // Create hidden Iframe. Attempt to make Iframe as hidden as possible
 
1303
          // by using techniques from http://www.paciellogroup.com/blog/?p=604.
 
1304
          iframe = $('<iframe tabindex="-1" title="empty"/>').hide()
 
1305
            
 
1306
            // When Iframe has completely loaded, initialize the history and
 
1307
            // start polling.
 
1308
            .one( 'load', function(){
 
1309
              iframe_src || history_set( get_fragment() );
 
1310
              poll();
 
1311
            })
 
1312
            
 
1313
            // Load Iframe src if specified, otherwise nothing.
 
1314
            .attr( 'src', iframe_src || 'javascript:0' )
 
1315
            
 
1316
            // Append Iframe after the end of the body to prevent unnecessary
 
1317
            // initial page scrolling (yes, this works).
 
1318
            .insertAfter( 'body' )[0].contentWindow;
 
1319
          
 
1320
          // Whenever `document.title` changes, update the Iframe's title to
 
1321
          // prettify the back/next history menu entries. Since IE sometimes
 
1322
          // errors with "Unspecified error" the very first time this is set
 
1323
          // (yes, very useful) wrap this with a try/catch block.
 
1324
          doc.onpropertychange = function(){
 
1325
            try {
 
1326
              if ( event.propertyName === 'title' ) {
 
1327
                iframe.document.title = doc.title;
 
1328
              }
 
1329
            } catch(e) {}
 
1330
          };
 
1331
          
 
1332
        }
 
1333
      };
 
1334
      
 
1335
      // Override the "stop" method since an IE6/7 Iframe was created. Even
 
1336
      // if there are no longer any bound event handlers, the polling loop
 
1337
      // is still necessary for back/next to work at all!
 
1338
      self.stop = fn_retval;
 
1339
      
 
1340
      // Get history by looking at the hidden Iframe's location.hash.
 
1341
      history_get = function() {
 
1342
        return get_fragment( iframe.location.href );
 
1343
      };
 
1344
      
 
1345
      // Set a new history item by opening and then closing the Iframe
 
1346
      // document, *then* setting its location.hash. If document.domain has
 
1347
      // been set, update that as well.
 
1348
      history_set = function( hash, history_hash ) {
 
1349
        var iframe_doc = iframe.document,
 
1350
          domain = $.fn[ str_hashchange ].domain;
 
1351
        
 
1352
        if ( hash !== history_hash ) {
 
1353
          // Update Iframe with any initial `document.title` that might be set.
 
1354
          iframe_doc.title = doc.title;
 
1355
          
 
1356
          // Opening the Iframe's document after it has been closed is what
 
1357
          // actually adds a history entry.
 
1358
          iframe_doc.open();
 
1359
          
 
1360
          // Set document.domain for the Iframe document as well, if necessary.
 
1361
          domain && iframe_doc.write( '<script>document.domain="' + domain + '"</script>' );
 
1362
          
 
1363
          iframe_doc.close();
 
1364
          
 
1365
          // Update the Iframe's hash, for great justice.
 
1366
          iframe.location.hash = hash;
 
1367
        }
 
1368
      };
 
1369
      
 
1370
    })();
 
1371
    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
1372
    // ^^^^^^^^^^^^^^^^^^^ REMOVE IF NOT SUPPORTING IE6/7/8 ^^^^^^^^^^^^^^^^^^^
 
1373
    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
1374
    
1134
1375
    return self;
1135
1376
  })();
1136
1377