3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
16 * @class Ext.util.History
18 * History management component that allows you to register arbitrary tokens that signify application
19 * history state on navigation actions. You can then handle the history {@link #change} event in order
20 * to reset your application UI to the appropriate state when the user navigates forward or backward through
21 * the browser history stack.
24 * The {@link #init} method of the History object must be called before using History. This sets up the internal
25 * state and must be the first thing called before using History.
28 * The History objects requires elements on the page to keep track of the browser history. For older versions of IE,
29 * an IFrame is required to do the tracking. For other browsers, a hidden field can be used. The history objects expects
30 * these to be on the page before the {@link #init} method is called. The following markup is suggested in order
31 * to support all browsers:
33 * <form id="history-form" class="x-hide-display">
34 * <input type="hidden" id="x-history-field" />
35 * <iframe id="x-history-frame"></iframe>
40 Ext.define('Ext.util.History', {
42 alternateClassName: 'Ext.History',
44 observable: 'Ext.util.Observable'
47 constructor: function() {
49 me.oldIEMode = Ext.isIE6 || Ext.isIE7 || !Ext.isStrict && Ext.isIE8;
51 me.hiddenField = null;
53 me.currentToken = null;
57 var href = window.location.href,
58 i = href.indexOf("#");
60 return i >= 0 ? href.substr(i + 1) : null;
64 this.hiddenField.value = this.currentToken;
68 handleStateChange: function(token) {
69 this.currentToken = token;
70 this.fireEvent('change', token);
73 updateIFrame: function(token) {
74 var html = '<html><body><div id="state">' +
75 Ext.util.Format.htmlEncode(token) +
76 '</div></body></html>';
79 var doc = this.iframe.contentWindow.document;
89 checkIFrame: function () {
91 contentWindow = me.iframe.contentWindow;
93 if (!contentWindow || !contentWindow.document) {
94 Ext.Function.defer(this.checkIFrame, 10, this);
98 var doc = contentWindow.document,
99 elem = doc.getElementById("state"),
100 oldToken = elem ? elem.innerText : null,
101 oldHash = me.getHash();
103 Ext.TaskManager.start({
105 var doc = contentWindow.document,
106 elem = doc.getElementById("state"),
107 newToken = elem ? elem.innerText : null,
108 newHash = me.getHash();
110 if (newToken !== oldToken) {
112 me.handleStateChange(newToken);
113 window.top.location.hash = newToken;
116 } else if (newHash !== oldHash) {
118 me.updateIFrame(newHash);
125 me.fireEvent('ready', me);
128 startUp: function () {
131 me.currentToken = me.hiddenField.value || this.getHash();
136 var hash = me.getHash();
137 Ext.TaskManager.start({
139 var newHash = me.getHash();
140 if (newHash !== hash) {
142 me.handleStateChange(hash);
150 me.fireEvent('ready', me);
156 * The id of the hidden field required for storing the current history token.
160 fieldId: Ext.baseCSSPrefix + 'history-field',
162 * The id of the iframe required by IE to manage the history stack.
166 iframeId: Ext.baseCSSPrefix + 'history-frame',
169 * Initialize the global History instance.
170 * @param {Boolean} onReady (optional) A callback function that will be called once the history
171 * component is fully initialized.
172 * @param {Object} scope (optional) The scope (`this` reference) in which the callback is executed. Defaults to the browser window.
174 init: function (onReady, scope) {
178 Ext.callback(onReady, scope, [me]);
183 Ext.onReady(function() {
184 me.init(onReady, scope);
189 me.hiddenField = Ext.getDom(me.fieldId);
192 me.iframe = Ext.getDom(me.iframeId);
198 * Fires when the Ext.util.History singleton has been initialized and is ready for use.
199 * @param {Ext.util.History} The Ext.util.History singleton.
204 * Fires when navigation back or forwards within the local page's history occurs.
205 * @param {String} token An identifier associated with the page state at that point in its history.
211 me.on('ready', onReady, scope, {single: true});
217 * Add a new token to the history stack. This can be any arbitrary value, although it would
218 * commonly be the concatenation of a component id and another id marking the specific history
219 * state of that component. Example usage:
221 * // Handle tab changes on a TabPanel
222 * tabPanel.on('tabchange', function(tabPanel, tab){
223 * Ext.History.add(tabPanel.id + ':' + tab.id);
226 * @param {String} token The value that defines a particular application-specific history state
227 * @param {Boolean} [preventDuplicates=true] When true, if the passed token matches the current token
228 * it will not save a new history step. Set to false if the same state can be saved more than once
229 * at the same history stack location.
231 add: function (token, preventDup) {
234 if (preventDup !== false) {
235 if (me.getToken() === token) {
241 return me.updateIFrame(token);
243 window.top.location.hash = token;
249 * Programmatically steps back one step in browser history (equivalent to the user pressing the Back button).
252 window.history.go(-1);
256 * Programmatically steps forward one step in browser history (equivalent to the user pressing the Forward button).
259 window.history.go(1);
263 * Retrieves the currently-active history token.
264 * @return {String} The token
266 getToken: function() {
267 return this.ready ? this.currentToken : this.getHash();