@qooxdoo/framework
Version:
The JS Framework for Coders
233 lines (188 loc) • 5.62 kB
JavaScript
/* ************************************************************************
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;
}
});