API Docs for: 3.8.0
Show:

File: history/js/history-hash-ie.js

  1. /**
  2.  * Improves IE6/7 support in history-hash by using a hidden iframe to create
  3.  * entries in IE's browser history. This module is only needed if IE6/7 support
  4.  * is necessary; it's not needed for any other browser.
  5.  *
  6.  * @module history
  7.  * @submodule history-hash-ie
  8.  * @since 3.2.0
  9.  */

  10. // Combination of a UA sniff to ensure this is IE (or a browser that wants us to
  11. // treat it like IE) and feature detection for native hashchange support (false
  12. // for IE < 8 or IE8/9 in IE7 mode).
  13. if (Y.UA.ie && !Y.HistoryBase.nativeHashChange) {
  14.     var Do          = Y.Do,
  15.         GlobalEnv   = YUI.namespace('Env.HistoryHash'),
  16.         HistoryHash = Y.HistoryHash,

  17.         iframe = GlobalEnv._iframe,
  18.         win    = Y.config.win;

  19.     /**
  20.      * Gets the raw (not decoded) current location hash from the IE iframe,
  21.      * minus the preceding '#' character and the hashPrefix (if one is set).
  22.      *
  23.      * @method getIframeHash
  24.      * @return {String} current iframe hash
  25.      * @static
  26.      */
  27.     HistoryHash.getIframeHash = function () {
  28.         if (!iframe || !iframe.contentWindow) {
  29.             return '';
  30.         }

  31.         var prefix = HistoryHash.hashPrefix,
  32.             hash   = iframe.contentWindow.location.hash.substr(1);

  33.         return prefix && hash.indexOf(prefix) === 0 ?
  34.                     hash.replace(prefix, '') : hash;
  35.     };

  36.     /**
  37.      * Updates the history iframe with the specified hash.
  38.      *
  39.      * @method _updateIframe
  40.      * @param {String} hash location hash
  41.      * @param {Boolean} replace (optional) if <code>true</code>, the current
  42.      *   history state will be replaced without adding a new history entry
  43.      * @protected
  44.      * @static
  45.      * @for HistoryHash
  46.      */
  47.     HistoryHash._updateIframe = function (hash, replace) {
  48.         var iframeDoc      = iframe && iframe.contentWindow && iframe.contentWindow.document,
  49.             iframeLocation = iframeDoc && iframeDoc.location;

  50.         if (!iframeDoc || !iframeLocation) {
  51.             return;
  52.         }

  53.         Y.log('updating history iframe: ' + hash + ', replace: ' + !!replace, 'info', 'history');

  54.         if (replace) {
  55.             iframeLocation.replace(hash.charAt(0) === '#' ? hash : '#' + hash);
  56.         } else {
  57.             iframeDoc.open().close();
  58.             iframeLocation.hash = hash;
  59.         }
  60.     };

  61.     Do.before(HistoryHash._updateIframe, HistoryHash, 'replaceHash', HistoryHash, true);

  62.     if (!iframe) {
  63.         Y.on('domready', function () {
  64.             var lastUrlHash = HistoryHash.getHash();

  65.             // Create a hidden iframe to store history state, following the
  66.             // iframe-hiding recommendations from
  67.             // http://www.paciellogroup.com/blog/?p=604.
  68.             //
  69.             // This iframe will allow history navigation within the current page
  70.             // context. After navigating to another page, all but the most
  71.             // recent history state will be lost.
  72.             //
  73.             // Earlier versions of the YUI History Utility attempted to work
  74.             // around this limitation by having the iframe load a static
  75.             // resource. This workaround was extremely fragile and tended to
  76.             // break frequently (and silently) since it was entirely dependent
  77.             // on IE's inconsistent handling of iframe history.
  78.             //
  79.             // Since this workaround didn't work much of the time anyway and
  80.             // added significant complexity, it has been removed, and IE6 and 7
  81.             // now get slightly degraded history support.
  82.             Y.log('creating dynamic history iframe', 'info', 'history');

  83.             iframe = GlobalEnv._iframe = Y.Node.getDOMNode(Y.Node.create(
  84.                 '<iframe src="javascript:0" style="display:none" height="0" width="0" tabindex="-1" title="empty"/>'
  85.             ));

  86.             // Append the iframe to the documentElement rather than the body.
  87.             // Keeping it outside the body prevents scrolling on the initial
  88.             // page load (hat tip to Ben Alman and jQuery BBQ for this
  89.             // technique).
  90.             Y.config.doc.documentElement.appendChild(iframe);

  91.             // Update the iframe with the initial location hash, if any. This
  92.             // will create an initial history entry that the user can return to
  93.             // after the state has changed.
  94.             HistoryHash._updateIframe(lastUrlHash || '#');

  95.             // Listen for hashchange events and keep the iframe's hash in sync
  96.             // with the parent frame's hash.
  97.             Y.on('hashchange', function (e) {
  98.                 lastUrlHash = e.newHash;

  99.                 if (HistoryHash.getIframeHash() !== lastUrlHash) {
  100.                     Y.log('updating iframe hash to match URL hash', 'info', 'history');
  101.                     HistoryHash._updateIframe(lastUrlHash);
  102.                 }
  103.             }, win);

  104.             // Watch the iframe hash in order to detect back/forward navigation.
  105.             Y.later(50, null, function () {
  106.                 var iframeHash = HistoryHash.getIframeHash();

  107.                 if (iframeHash !== lastUrlHash) {
  108.                     Y.log('updating URL hash to match iframe hash', 'info', 'history');
  109.                     HistoryHash.setHash(iframeHash);
  110.                 }
  111.             }, null, true);
  112.         });
  113.     }
  114. }

  115.