76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassYUI.add('history-hash-ie', function(Y) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass/**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Improves IE6/7 support in history-hash by using a hidden iframe to create
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * entries in IE's browser history. This module is only needed if IE6/7 support
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * is necessary; it's not needed for any other browser.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass *
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @module history
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @submodule history-hash-ie
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @since 3.2.0
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass */
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass// Combination of a UA sniff to ensure this is IE (or a browser that wants us to
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass// treat it like IE) and feature detection for native hashchange support (false
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass// for IE < 8 or IE8/9 in IE7 mode).
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glassif (Y.UA.ie && !Y.HistoryBase.nativeHashChange) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass var Do = Y.Do,
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass GlobalEnv = YUI.namespace('Env.HistoryHash'),
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass HistoryHash = Y.HistoryHash,
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
4106577eb9389768607e9d9a51f614faa6bdb8bcEric Ferraiuolo iframe = GlobalEnv._iframe,
4106577eb9389768607e9d9a51f614faa6bdb8bcEric Ferraiuolo win = Y.config.win;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Gets the raw (not decoded) current location hash from the IE iframe,
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * minus the preceding '#' character and the hashPrefix (if one is set).
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass *
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @method getIframeHash
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @return {String} current iframe hash
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @static
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass */
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass HistoryHash.getIframeHash = function () {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (!iframe || !iframe.contentWindow) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return '';
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass var prefix = HistoryHash.hashPrefix,
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass hash = iframe.contentWindow.location.hash.substr(1);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return prefix && hash.indexOf(prefix) === 0 ?
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass hash.replace(prefix, '') : hash;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass };
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Updates the history iframe with the specified hash.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass *
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @method _updateIframe
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param {String} hash location hash
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param {Boolean} replace (optional) if <code>true</code>, the current
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * history state will be replaced without adding a new history entry
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @protected
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @static
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @for HistoryHash
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass */
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass HistoryHash._updateIframe = function (hash, replace) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass var iframeDoc = iframe && iframe.contentWindow && iframe.contentWindow.document,
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass iframeLocation = iframeDoc && iframeDoc.location;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (!iframeDoc || !iframeLocation) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
c0d83403b13f02bc6fdcf62a712de150a7f974e2Dav Glass Y.log('updating history iframe: ' + hash + ', replace: ' + !!replace, 'info', 'history');
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (replace) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass iframeLocation.replace(hash.charAt(0) === '#' ? hash : '#' + hash);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass } else {
c0d83403b13f02bc6fdcf62a712de150a7f974e2Dav Glass iframeDoc.open().close();
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass iframeLocation.hash = hash;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass };
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
c0d83403b13f02bc6fdcf62a712de150a7f974e2Dav Glass Do.before(HistoryHash._updateIframe, HistoryHash, 'replaceHash', HistoryHash, true);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (!iframe) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Y.on('domready', function () {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass var lastUrlHash = HistoryHash.getHash();
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // Create a hidden iframe to store history state, following the
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // iframe-hiding recommendations from
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // http://www.paciellogroup.com/blog/?p=604.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass //
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // This iframe will allow history navigation within the current page
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // context. After navigating to another page, all but the most
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // recent history state will be lost.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass //
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // Earlier versions of the YUI History Utility attempted to work
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // around this limitation by having the iframe load a static
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // resource. This workaround was extremely fragile and tended to
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // break frequently (and silently) since it was entirely dependent
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // on IE's inconsistent handling of iframe history.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass //
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // Since this workaround didn't work much of the time anyway and
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // added significant complexity, it has been removed, and IE6 and 7
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // now get slightly degraded history support.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Y.log('creating dynamic history iframe', 'info', 'history');
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass iframe = GlobalEnv._iframe = Y.Node.getDOMNode(Y.Node.create(
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass '<iframe src="javascript:0" style="display:none" height="0" width="0" tabindex="-1" title="empty"/>'
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass ));
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // Append the iframe to the documentElement rather than the body.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // Keeping it outside the body prevents scrolling on the initial
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // page load (hat tip to Ben Alman and jQuery BBQ for this
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // technique).
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Y.config.doc.documentElement.appendChild(iframe);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // Update the iframe with the initial location hash, if any. This
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // will create an initial history entry that the user can return to
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // after the state has changed.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass HistoryHash._updateIframe(lastUrlHash || '#');
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // Listen for hashchange events and keep the iframe's hash in sync
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // with the parent frame's hash.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Y.on('hashchange', function (e) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass lastUrlHash = e.newHash;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (HistoryHash.getIframeHash() !== lastUrlHash) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Y.log('updating iframe hash to match URL hash', 'info', 'history');
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass HistoryHash._updateIframe(lastUrlHash);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }, win);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // Watch the iframe hash in order to detect back/forward navigation.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Y.later(50, null, function () {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass var iframeHash = HistoryHash.getIframeHash();
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (iframeHash !== lastUrlHash) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Y.log('updating URL hash to match iframe hash', 'info', 'history');
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass HistoryHash.setHash(iframeHash);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }, null, true);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass });
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass}
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass}, '@VERSION@' ,{requires:['history-hash', 'node-base']});