jquery.history.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /*
  2. * jQuery history plugin
  3. *
  4. * sample page: http://www.mikage.to/jquery/jquery_history.html
  5. *
  6. * Copyright (c) 2006-2009 Taku Sano (Mikage Sawatari)
  7. * Licensed under the MIT License:
  8. * http://www.opensource.org/licenses/mit-license.php
  9. *
  10. * Modified by Lincoln Cooper to add Safari support and only call the callback once during initialization
  11. * for msie when no initial hash supplied.
  12. */
  13. jQuery.extend({
  14. historyCurrentHash: undefined,
  15. historyCallback: undefined,
  16. historyIframeSrc: undefined,
  17. historyInit: function(callback, src){
  18. jQuery.historyCallback = callback;
  19. if (src) jQuery.historyIframeSrc = src;
  20. var current_hash = location.hash.replace(/\?.*$/, '');
  21. jQuery.historyCurrentHash = current_hash;
  22. // if ((jQuery.browser.msie) && (jQuery.browser.version < 8)) {
  23. if (jQuery.browser.msie) {
  24. // To stop the callback firing twice during initilization if no hash present
  25. if (jQuery.historyCurrentHash == '') {
  26. jQuery.historyCurrentHash = '#';
  27. }
  28. // add hidden iframe for IE
  29. jQuery("body").prepend('<iframe id="jQuery_history" style="display: none;"'+
  30. (jQuery.historyIframeSrc ? ' src="'+jQuery.historyIframeSrc+'"' : '')
  31. +'></iframe>'
  32. );
  33. var ihistory = jQuery("#jQuery_history")[0];
  34. var iframe = ihistory.contentWindow.document;
  35. iframe.open();
  36. iframe.close();
  37. iframe.location.hash = current_hash;
  38. }
  39. else if (jQuery.browser.safari) {
  40. // etablish back/forward stacks
  41. jQuery.historyBackStack = [];
  42. jQuery.historyBackStack.length = history.length;
  43. jQuery.historyForwardStack = [];
  44. jQuery.lastHistoryLength = history.length;
  45. jQuery.isFirst = true;
  46. }
  47. if(current_hash)
  48. jQuery.historyCallback(current_hash.replace(/^#/, ''));
  49. setInterval(jQuery.historyCheck, 100);
  50. },
  51. historyAddHistory: function(hash) {
  52. // This makes the looping function do something
  53. jQuery.historyBackStack.push(hash);
  54. jQuery.historyForwardStack.length = 0; // clear forwardStack (true click occured)
  55. this.isFirst = true;
  56. },
  57. historyCheck: function(){
  58. // if ((jQuery.browser.msie) && (jQuery.browser.version < 8)) {
  59. if (jQuery.browser.msie) {
  60. // On IE, check for location.hash of iframe
  61. var ihistory = jQuery("#jQuery_history")[0];
  62. var iframe = ihistory.contentDocument || ihistory.contentWindow.document;
  63. var current_hash = iframe.location.hash.replace(/\?.*$/, '');
  64. if(current_hash != jQuery.historyCurrentHash) {
  65. location.hash = current_hash;
  66. jQuery.historyCurrentHash = current_hash;
  67. jQuery.historyCallback(current_hash.replace(/^#/, ''));
  68. }
  69. } else if (jQuery.browser.safari) {
  70. if(jQuery.lastHistoryLength == history.length && jQuery.historyBackStack.length > jQuery.lastHistoryLength) {
  71. jQuery.historyBackStack.shift();
  72. }
  73. if (!jQuery.dontCheck) {
  74. var historyDelta = history.length - jQuery.historyBackStack.length;
  75. jQuery.lastHistoryLength = history.length;
  76. if (historyDelta) { // back or forward button has been pushed
  77. jQuery.isFirst = false;
  78. if (historyDelta < 0) { // back button has been pushed
  79. // move items to forward stack
  80. for (var i = 0; i < Math.abs(historyDelta); i++) jQuery.historyForwardStack.unshift(jQuery.historyBackStack.pop());
  81. } else { // forward button has been pushed
  82. // move items to back stack
  83. for (var i = 0; i < historyDelta; i++) jQuery.historyBackStack.push(jQuery.historyForwardStack.shift());
  84. }
  85. var cachedHash = jQuery.historyBackStack[jQuery.historyBackStack.length - 1];
  86. if (cachedHash != undefined) {
  87. jQuery.historyCurrentHash = location.hash.replace(/\?.*$/, '');
  88. jQuery.historyCallback(cachedHash);
  89. }
  90. } else if (jQuery.historyBackStack[jQuery.historyBackStack.length - 1] == undefined && !jQuery.isFirst) {
  91. // back button has been pushed to beginning and URL already pointed to hash (e.g. a bookmark)
  92. // document.URL doesn't change in Safari
  93. if (location.hash) {
  94. var current_hash = location.hash;
  95. jQuery.historyCallback(location.hash.replace(/^#/, ''));
  96. } else {
  97. var current_hash = '';
  98. jQuery.historyCallback('');
  99. }
  100. jQuery.isFirst = true;
  101. }
  102. }
  103. } else {
  104. // otherwise, check for location.hash
  105. var current_hash = location.hash.replace(/\?.*$/, '');
  106. if(current_hash != jQuery.historyCurrentHash) {
  107. jQuery.historyCurrentHash = current_hash;
  108. jQuery.historyCallback(current_hash.replace(/^#/, ''));
  109. }
  110. }
  111. },
  112. historyLoad: function(hash){
  113. var newhash;
  114. hash = decodeURIComponent(hash.replace(/\?.*$/, ''));
  115. if (jQuery.browser.safari) {
  116. newhash = hash;
  117. }
  118. else {
  119. newhash = '#' + hash;
  120. location.hash = newhash;
  121. }
  122. jQuery.historyCurrentHash = newhash;
  123. // if ((jQuery.browser.msie) && (jQuery.browser.version < 8)) {
  124. if (jQuery.browser.msie) {
  125. var ihistory = jQuery("#jQuery_history")[0];
  126. var iframe = ihistory.contentWindow.document;
  127. iframe.open();
  128. iframe.close();
  129. iframe.location.hash = newhash;
  130. jQuery.lastHistoryLength = history.length;
  131. jQuery.historyCallback(hash);
  132. }
  133. else if (jQuery.browser.safari) {
  134. jQuery.dontCheck = true;
  135. // Manually keep track of the history values for Safari
  136. this.historyAddHistory(hash);
  137. // Wait a while before allowing checking so that Safari has time to update the "history" object
  138. // correctly (otherwise the check loop would detect a false change in hash).
  139. var fn = function() {jQuery.dontCheck = false;};
  140. window.setTimeout(fn, 200);
  141. jQuery.historyCallback(hash);
  142. // N.B. "location.hash=" must be the last line of code for Safari as execution stops afterwards.
  143. // By explicitly using the "location.hash" command (instead of using a variable set to "location.hash") the
  144. // URL in the browser and the "history" object are both updated correctly.
  145. location.hash = newhash;
  146. }
  147. else {
  148. jQuery.historyCallback(hash);
  149. }
  150. }
  151. });