PageRenderTime 72ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/public/jquery/event/hashchange/hashchange.js

https://github.com/retro/HibreedCMS
JavaScript | 245 lines | 75 code | 34 blank | 136 comment | 16 complexity | 2301f87f8c7b59142a16cc142e957f84 MD5 | raw file
  1. /*!
  2. * jQuery hashchange event - v1.2 - 2/11/2010
  3. * http://benalman.com/projects/jquery-hashchange-plugin/
  4. *
  5. * Copyright (c) 2010 "Cowboy" Ben Alman
  6. * Dual licensed under the MIT and GPL licenses.
  7. * http://benalman.com/about/license/
  8. */
  9. // Script: jQuery hashchange event
  10. //
  11. // *Version: 1.2, Last updated: 2/11/2010*
  12. //
  13. // Project Home - http://benalman.com/projects/jquery-hashchange-plugin/
  14. // GitHub - http://github.com/cowboy/jquery-hashchange/
  15. // Source - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js
  16. // (Minified) - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (1.1kb)
  17. //
  18. // About: License
  19. //
  20. // Copyright (c) 2010 "Cowboy" Ben Alman,
  21. // Dual licensed under the MIT and GPL licenses.
  22. // http://benalman.com/about/license/
  23. //
  24. // About: Examples
  25. //
  26. // This working example, complete with fully commented code, illustrate one way
  27. // in which this plugin can be used.
  28. //
  29. // hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/
  30. //
  31. // About: Support and Testing
  32. //
  33. // Information about what version or versions of jQuery this plugin has been
  34. // tested with, what browsers it has been tested in, and where the unit tests
  35. // reside (so you can test it yourself).
  36. //
  37. // jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
  38. // Browsers Tested - Internet Explorer 6-8, Firefox 2-3.7, Safari 3-4, Chrome, Opera 9.6-10.1.
  39. // Unit Tests - http://benalman.com/code/projects/jquery-hashchange/unit/
  40. //
  41. // About: Known issues
  42. //
  43. // While this jQuery hashchange event implementation is quite stable and robust,
  44. // there are a few unfortunate browser bugs surrounding expected hashchange
  45. // event-based behaviors, independent of any JavaScript window.onhashchange
  46. // abstraction. See the following examples for more information:
  47. //
  48. // Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/
  49. // Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/
  50. // WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/
  51. // Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/
  52. //
  53. // About: Release History
  54. //
  55. // 1.2 - (2/11/2010) Fixed a bug where coming back to a page using this plugin
  56. // from a page on another domain would cause an error in Safari 4. Also,
  57. // IE6/7 Iframe is now inserted after the body (this actually works),
  58. // which prevents the page from scrolling when the event is first bound.
  59. // Event can also now be bound before DOM ready, but it won't be usable
  60. // before then in IE6/7.
  61. // 1.1 - (1/21/2010) Incorporated document.documentMode test to fix IE8 bug
  62. // where browser version is incorrectly reported as 8.0, despite
  63. // inclusion of the X-UA-Compatible IE=EmulateIE7 meta tag.
  64. // 1.0 - (1/9/2010) Initial Release. Broke out the jQuery BBQ event.special
  65. // window.onhashchange functionality into a separate plugin for users
  66. // who want just the basic event & back button support, without all the
  67. // extra awesomeness that BBQ provides. This plugin will be included as
  68. // part of jQuery BBQ, but also be available separately.
  69. (function($,window,undefined){
  70. '$:nomunge'; // Used by YUI compressor.
  71. // Method / object references.
  72. var fake_onhashchange,
  73. jq_event_special = $.event.special,
  74. // Reused strings.
  75. str_location = 'location',
  76. str_hashchange = 'hashchange',
  77. str_href = 'href',
  78. // IE6/7 specifically need some special love when it comes to back-button
  79. // support, so let's do a little browser sniffing..
  80. browser = $.browser,
  81. mode = document.documentMode,
  82. is_old_ie = browser.msie && ( mode === undefined || mode < 8 ),
  83. // Does the browser support window.onhashchange? Test for IE version, since
  84. // IE8 incorrectly reports this when in "IE7" or "IE8 Compatibility View"!
  85. supports_onhashchange = 'on' + str_hashchange in window && !is_old_ie;
  86. // Get location.hash (or what you'd expect location.hash to be) sans any
  87. // leading #. Thanks for making this necessary, Firefox!
  88. function get_fragment( url ) {
  89. url = url || window[ str_location ][ str_href ];
  90. return url.replace( /^[^#]*#?(.*)$/, '$1' );
  91. };
  92. // Property: jQuery.hashchangeDelay
  93. //
  94. // The numeric interval (in milliseconds) at which the <hashchange event>
  95. // polling loop executes. Defaults to 100.
  96. $[ str_hashchange + 'Delay' ] = 100;
  97. // Event: hashchange event
  98. //
  99. // Fired when location.hash changes. In browsers that support it, the native
  100. // window.onhashchange event is used (IE8, FF3.6), otherwise a polling loop is
  101. // initialized, running every <jQuery.hashchangeDelay> milliseconds to see if
  102. // the hash has changed. In IE 6 and 7, a hidden Iframe is created to allow
  103. // the back button and hash-based history to work.
  104. //
  105. // Usage:
  106. //
  107. // > $(window).bind( 'hashchange', function(e) {
  108. // > var hash = location.hash;
  109. // > ...
  110. // > });
  111. //
  112. // Additional Notes:
  113. //
  114. // * The polling loop and Iframe are not created until at least one callback
  115. // is actually bound to 'hashchange'.
  116. // * If you need the bound callback(s) to execute immediately, in cases where
  117. // the page 'state' exists on page load (via bookmark or page refresh, for
  118. // example) use $(window).trigger( 'hashchange' );
  119. // * The event can be bound before DOM ready, but since it won't be usable
  120. // before then in IE6/7 (due to the necessary Iframe), recommended usage is
  121. // to bind it inside a $(document).ready() callback.
  122. jq_event_special[ str_hashchange ] = $.extend( jq_event_special[ str_hashchange ], {
  123. // Called only when the first 'hashchange' event is bound to window.
  124. setup: function() {
  125. // If window.onhashchange is supported natively, there's nothing to do..
  126. if ( supports_onhashchange ) { return false; }
  127. // Otherwise, we need to create our own. And we don't want to call this
  128. // until the user binds to the event, just in case they never do, since it
  129. // will create a polling loop and possibly even a hidden Iframe.
  130. $( fake_onhashchange.start );
  131. },
  132. // Called only when the last 'hashchange' event is unbound from window.
  133. teardown: function() {
  134. // If window.onhashchange is supported natively, there's nothing to do..
  135. if ( supports_onhashchange ) { return false; }
  136. // Otherwise, we need to stop ours (if possible).
  137. $( fake_onhashchange.stop );
  138. }
  139. });
  140. // fake_onhashchange does all the work of triggering the window.onhashchange
  141. // event for browsers that don't natively support it, including creating a
  142. // polling loop to watch for hash changes and in IE 6/7 creating a hidden
  143. // Iframe to enable back and forward.
  144. fake_onhashchange = (function(){
  145. var self = {},
  146. timeout_id,
  147. iframe,
  148. set_history,
  149. get_history;
  150. // Initialize. In IE 6/7, creates a hidden Iframe for history handling.
  151. function init(){
  152. // Most browsers don't need special methods here..
  153. set_history = get_history = function(val){ return val; };
  154. // But IE6/7 do!
  155. if ( is_old_ie ) {
  156. // Create hidden Iframe after the end of the body to prevent initial
  157. // page load from scrolling unnecessarily.
  158. iframe = $('<iframe src="javascript:0"/>').hide().insertAfter( 'body' )[0].contentWindow;
  159. // Get history by looking at the hidden Iframe's location.hash.
  160. get_history = function() {
  161. return get_fragment( iframe.document[ str_location ][ str_href ] );
  162. };
  163. // Set a new history item by opening and then closing the Iframe
  164. // document, *then* setting its location.hash.
  165. set_history = function( hash, history_hash ) {
  166. if ( hash !== history_hash ) {
  167. var doc = iframe.document;
  168. doc.open().close();
  169. doc[ str_location ].hash = '#' + hash;
  170. }
  171. };
  172. // Set initial history.
  173. set_history( get_fragment() );
  174. }
  175. };
  176. // Start the polling loop.
  177. self.start = function() {
  178. // Polling loop is already running!
  179. if ( timeout_id ) { return; }
  180. // Remember the initial hash so it doesn't get triggered immediately.
  181. var last_hash = get_fragment();
  182. // Initialize if not yet initialized.
  183. set_history || init();
  184. // This polling loop checks every $.hashchangeDelay milliseconds to see if
  185. // location.hash has changed, and triggers the 'hashchange' event on
  186. // window when necessary.
  187. if(!navigator.userAgent.match(/Rhino/))
  188. (function loopy(){
  189. var hash = get_fragment(),
  190. history_hash = get_history( last_hash );
  191. if ( hash !== last_hash ) {
  192. set_history( last_hash = hash, history_hash );
  193. $(window).trigger( str_hashchange );
  194. } else if ( history_hash !== last_hash ) {
  195. window[ str_location ][ str_href ] = window[ str_location ][ str_href ].replace( /#.*/, '' ) + '#' + history_hash;
  196. }
  197. timeout_id = setTimeout( loopy, $[ str_hashchange + 'Delay' ] );
  198. })();
  199. };
  200. // Stop the polling loop, but only if an IE6/7 Iframe wasn't created. In
  201. // that case, even if there are no longer any bound event handlers, the
  202. // polling loop is still necessary for back/next to work at all!
  203. self.stop = function() {
  204. if ( !iframe ) {
  205. timeout_id && clearTimeout( timeout_id );
  206. timeout_id = 0;
  207. }
  208. };
  209. return self;
  210. })();
  211. })(jQuery,this);