@qooxdoo/framework
Version:
The JS Framework for Coders
227 lines (195 loc) • 5.58 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() {
super();
this._baseUrl = null;
this.__initIframe();
},
members: {
__checkOnHashChange: null,
__iframe: null,
__iframeReady: false,
//overridden
addToHistory(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() {
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() {
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(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() {
qx.event.Idle.getInstance().addListener(
"interval",
this.__onHashChange,
this
);
},
/**
* Remove hash change listeners
*/
__detatchListeners() {
qx.event.Idle.getInstance().removeListener(
"interval",
this.__onHashChange,
this
);
},
/**
* hash change event handler
*/
__onHashChange() {
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() {
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() {
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(state) {
this._setHash(this._encode(state));
},
/**
* Sets the fragment identifier of the window URL
*
* @param value {String} the fragment identifier
*/
_setHash(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() {
this.__detatchListeners();
this.__iframe = null;
}
});