UNPKG

@qooxdoo/framework

Version:

The JS Framework for Coders

233 lines (188 loc) 5.62 kB
/* ************************************************************************ qooxdoo - the new era of web development http://qooxdoo.org Copyright: 2004-2012 1&1 Internet AG, Germany, http://www.1und1.de License: MIT: https://opensource.org/licenses/MIT See the LICENSE file in the project's top-level directory for details. Authors: * Sebastian Werner (wpbasti) * Andreas Ecker (ecker) * Fabian Jakobs (fjakobs) * Mustafa Sak (msak) ************************************************************************ */ /** * History manager implementation for IE greater 7. IE reloads iframe * content on history actions even just hash value changed. This * implementation forwards history states (hashes) to a helper iframe. * * This class must be disposed of after use * * @internal */ qx.Class.define("qx.bom.HashHistory", { extend : qx.bom.History, implement: [ qx.core.IDisposable ], construct : function() { this.base(arguments); this._baseUrl = null; this.__initIframe(); }, members : { __checkOnHashChange : null, __iframe : null, __iframeReady : false, //overridden addToHistory : function(state, newTitle) { if (!qx.lang.Type.isString(state)) { state = state + ""; } if (qx.lang.Type.isString(newTitle)) { this.setTitle(newTitle); this._titles[state] = newTitle; } if (this.getState() !== state) { this._writeState(state); } }, /** * Initializes the iframe * */ __initIframe : function() { this.__iframe = this.__createIframe(); document.body.appendChild(this.__iframe); this.__waitForIFrame(function() { this._baseUrl = this.__iframe.contentWindow.document.location.href; this.__attachListeners(); }, this); }, /** * IMPORTANT NOTE FOR IE: * Setting the source before adding the iframe to the document. * Otherwise IE will bring up a "Unsecure items ..." warning in SSL mode * * @return {Element} */ __createIframe : function () { var iframe = qx.bom.Iframe.create({ src : qx.util.ResourceManager.getInstance().toUri(qx.core.Environment.get("qx.blankpage")) + "#" }); iframe.style.visibility = "hidden"; iframe.style.position = "absolute"; iframe.style.left = "-1000px"; iframe.style.top = "-1000px"; return iframe; }, /** * Waits for the IFrame being loaded. Once the IFrame is loaded * the callback is called with the provided context. * * @param callback {Function} This function will be called once the iframe is loaded * @param context {Object?window} The context for the callback. * @param retry {Integer} number of tries to initialize the iframe */ __waitForIFrame : function(callback, context, retry) { if (typeof retry === "undefined") { retry = 0; } if ( !this.__iframe.contentWindow || !this.__iframe.contentWindow.document ) { if (retry > 20) { throw new Error("can't initialize iframe"); } qx.event.Timer.once(function() { this.__waitForIFrame(callback, context, ++retry); }, this, 10); return; } this.__iframeReady = true; callback.call(context || window); }, /** * Attach hash change listeners */ __attachListeners : function() { qx.event.Idle.getInstance().addListener("interval", this.__onHashChange, this); }, /** * Remove hash change listeners */ __detatchListeners : function() { qx.event.Idle.getInstance().removeListener("interval", this.__onHashChange, this); }, /** * hash change event handler */ __onHashChange : function() { var currentState = this._readState(); if (qx.lang.Type.isString(currentState) && currentState != this.getState()) { this._onHistoryLoad(currentState); } }, /** * Browser dependent function to read the current state of the history * * @return {String} current state of the browser history */ _readState : function() { var hash = !this._getHash() ? "" : this._getHash().substr(1); return this._decode(hash); }, /** * Returns the fragment identifier of the top window URL. For gecko browsers we * have to use a regular expression to avoid encoding problems. * * @return {String|null} the fragment identifier or <code>null</code> if the * iframe isn't ready yet */ _getHash : function() { if (!this.__iframeReady){ return null; } return this.__iframe.contentWindow.document.location.hash; }, /** * Save a state into the browser history. * * @param state {String} state to save */ _writeState : function(state) { this._setHash(this._encode(state)); }, /** * Sets the fragment identifier of the window URL * * @param value {String} the fragment identifier */ _setHash : function (value) { if (!this.__iframe || !this._baseUrl){ return; } var hash = !this.__iframe.contentWindow.document.location.hash ? "" : this.__iframe.contentWindow.document.location.hash.substr(1); if (value != hash) { this.__iframe.contentWindow.document.location.hash = value; } } }, destruct : function() { this.__detatchListeners(); this.__iframe = null; } });