2 * @class Ext.util.History
4 History management component that allows you to register arbitrary tokens that signify application
5 history state on navigation actions. You can then handle the history {@link #change} event in order
6 to reset your application UI to the appropriate state when the user navigates forward or backward through
7 the browser history stack.
10 The {@link #init} method of the History object must be called before using History. This sets up the internal
11 state and must be the first thing called before using History.
14 The History objects requires elements on the page to keep track of the browser history. For older versions of IE,
15 an IFrame is required to do the tracking. For other browsers, a hidden field can be used. The history objects expects
16 these to be on the page before the {@link #init} method is called. The following markup is suggested in order
17 to support all browsers:
19 <form id="history-form" class="x-hide-display">
20 <input type="hidden" id="x-history-field" />
21 <iframe id="x-history-frame"></iframe>
27 Ext.define('Ext.util.History', {
29 alternateClassName: 'Ext.History',
31 observable: 'Ext.util.Observable'
34 constructor: function() {
36 me.oldIEMode = Ext.isIE6 || Ext.isIE7 || !Ext.isStrict && Ext.isIE8;
38 me.hiddenField = null;
40 me.currentToken = null;
44 var href = window.location.href,
45 i = href.indexOf("#");
47 return i >= 0 ? href.substr(i + 1) : null;
51 this.hiddenField.value = this.currentToken;
55 handleStateChange: function(token) {
56 this.currentToken = token;
57 this.fireEvent('change', token);
60 updateIFrame: function(token) {
61 var html = '<html><body><div id="state">' +
62 Ext.util.Format.htmlEncode(token) +
63 '</div></body></html>';
66 var doc = this.iframe.contentWindow.document;
76 checkIFrame: function () {
78 contentWindow = me.iframe.contentWindow;
80 if (!contentWindow || !contentWindow.document) {
81 Ext.Function.defer(this.checkIFrame, 10, this);
85 var doc = contentWindow.document,
86 elem = doc.getElementById("state"),
87 oldToken = elem ? elem.innerText : null,
88 oldHash = me.getHash();
90 Ext.TaskManager.start({
92 var doc = contentWindow.document,
93 elem = doc.getElementById("state"),
94 newToken = elem ? elem.innerText : null,
95 newHash = me.getHash();
97 if (newToken !== oldToken) {
99 me.handleStateChange(newToken);
100 window.top.location.hash = newToken;
103 } else if (newHash !== oldHash) {
105 me.updateIFrame(newHash);
112 me.fireEvent('ready', me);
115 startUp: function () {
118 me.currentToken = me.hiddenField.value || this.getHash();
123 var hash = me.getHash();
124 Ext.TaskManager.start({
126 var newHash = me.getHash();
127 if (newHash !== hash) {
129 me.handleStateChange(hash);
137 me.fireEvent('ready', me);
143 * The id of the hidden field required for storing the current history token.
147 fieldId: Ext.baseCSSPrefix + 'history-field',
149 * The id of the iframe required by IE to manage the history stack.
153 iframeId: Ext.baseCSSPrefix + 'history-frame',
156 * Initialize the global History instance.
157 * @param {Boolean} onReady (optional) A callback function that will be called once the history
158 * component is fully initialized.
159 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to the browser window.
161 init: function (onReady, scope) {
165 Ext.callback(onReady, scope, [me]);
170 Ext.onReady(function() {
171 me.init(onReady, scope);
176 me.hiddenField = Ext.getDom(me.fieldId);
179 me.iframe = Ext.getDom(me.iframeId);
185 * Fires when the Ext.util.History singleton has been initialized and is ready for use.
186 * @param {Ext.util.History} The Ext.util.History singleton.
191 * Fires when navigation back or forwards within the local page's history occurs.
192 * @param {String} token An identifier associated with the page state at that point in its history.
198 me.on('ready', onReady, scope, {single: true});
204 * Add a new token to the history stack. This can be any arbitrary value, although it would
205 * commonly be the concatenation of a component id and another id marking the specifc history
206 * state of that component. Example usage:
208 // Handle tab changes on a TabPanel
209 tabPanel.on('tabchange', function(tabPanel, tab){
210 Ext.History.add(tabPanel.id + ':' + tab.id);
213 * @param {String} token The value that defines a particular application-specific history state
214 * @param {Boolean} preventDuplicates When true, if the passed token matches the current token
215 * it will not save a new history step. Set to false if the same state can be saved more than once
216 * at the same history stack location (defaults to true).
218 add: function (token, preventDup) {
221 if (preventDup !== false) {
222 if (me.getToken() === token) {
228 return me.updateIFrame(token);
230 window.top.location.hash = token;
236 * Programmatically steps back one step in browser history (equivalent to the user pressing the Back button).
239 window.history.go(-1);
243 * Programmatically steps forward one step in browser history (equivalent to the user pressing the Forward button).
246 window.history.go(1);
250 * Retrieves the currently-active history token.
251 * @return {String} The token
253 getToken: function() {
254 return this.ready ? this.currentToken : this.getHash();