Upgrade to ExtJS 3.0.0 - Released 07/06/2009
[extjs.git] / pkgs / pkg-history-debug.js
1 /*!
2  * Ext JS Library 3.0.0
3  * Copyright(c) 2006-2009 Ext JS, LLC
4  * licensing@extjs.com
5  * http://www.extjs.com/license
6  */
7 /**\r
8  * @class Ext.History\r
9  * @extends Ext.util.Observable\r
10  * History management component that allows you to register arbitrary tokens that signify application\r
11  * history state on navigation actions.  You can then handle the history {@link #change} event in order\r
12  * to reset your application UI to the appropriate state when the user navigates forward or backward through\r
13  * the browser history stack.\r
14  * @singleton\r
15  */\r
16 Ext.History = (function () {\r
17     var iframe, hiddenField;\r
18     var ready = false;\r
19     var currentToken;\r
20 \r
21     function getHash() {\r
22         var href = top.location.href, i = href.indexOf("#");\r
23         return i >= 0 ? href.substr(i + 1) : null;\r
24     }\r
25 \r
26     function doSave() {\r
27         hiddenField.value = currentToken;\r
28     }\r
29 \r
30     function handleStateChange(token) {\r
31         currentToken = token;\r
32         Ext.History.fireEvent('change', token);\r
33     }\r
34 \r
35     function updateIFrame (token) {\r
36         var html = ['<html><body><div id="state">',token,'</div></body></html>'].join('');\r
37         try {\r
38             var doc = iframe.contentWindow.document;\r
39             doc.open();\r
40             doc.write(html);\r
41             doc.close();\r
42             return true;\r
43         } catch (e) {\r
44             return false;\r
45         }\r
46     }\r
47 \r
48     function checkIFrame() {\r
49         if (!iframe.contentWindow || !iframe.contentWindow.document) {\r
50             setTimeout(checkIFrame, 10);\r
51             return;\r
52         }\r
53 \r
54         var doc = iframe.contentWindow.document;\r
55         var elem = doc.getElementById("state");\r
56         var token = elem ? elem.innerText : null;\r
57 \r
58         var hash = getHash();\r
59 \r
60         setInterval(function () {\r
61 \r
62             doc = iframe.contentWindow.document;\r
63             elem = doc.getElementById("state");\r
64 \r
65             var newtoken = elem ? elem.innerText : null;\r
66 \r
67             var newHash = getHash();\r
68 \r
69             if (newtoken !== token) {\r
70                 token = newtoken;\r
71                 handleStateChange(token);\r
72                 top.location.hash = token;\r
73                 hash = token;\r
74                 doSave();\r
75             } else if (newHash !== hash) {\r
76                 hash = newHash;\r
77                 updateIFrame(newHash);\r
78             }\r
79 \r
80         }, 50);\r
81 \r
82         ready = true;\r
83 \r
84         Ext.History.fireEvent('ready', Ext.History);\r
85     }\r
86 \r
87     function startUp() {\r
88         currentToken = hiddenField.value ? hiddenField.value : getHash();\r
89 \r
90         if (Ext.isIE) {\r
91             checkIFrame();\r
92         } else {\r
93             var hash = getHash();\r
94             setInterval(function () {\r
95                 var newHash = getHash();\r
96                 if (newHash !== hash) {\r
97                     hash = newHash;\r
98                     handleStateChange(hash);\r
99                     doSave();\r
100                 }\r
101             }, 50);\r
102             ready = true;\r
103             Ext.History.fireEvent('ready', Ext.History);\r
104         }\r
105     }\r
106 \r
107     return {\r
108         /**\r
109          * The id of the hidden field required for storing the current history token.\r
110          * @type String\r
111          * @property\r
112          */\r
113         fieldId: 'x-history-field',\r
114         /**\r
115          * The id of the iframe required by IE to manage the history stack.\r
116          * @type String\r
117          * @property\r
118          */\r
119         iframeId: 'x-history-frame',\r
120         \r
121         events:{},\r
122 \r
123         /**\r
124          * Initialize the global History instance.\r
125          * @param {Boolean} onReady (optional) A callback function that will be called once the history\r
126          * component is fully initialized.\r
127          * @param {Object} scope (optional) The callback scope\r
128          */\r
129         init: function (onReady, scope) {\r
130             if(ready) {\r
131                 Ext.callback(onReady, scope, [this]);\r
132                 return;\r
133             }\r
134             if(!Ext.isReady){\r
135                 Ext.onReady(function(){\r
136                     Ext.History.init(onReady, scope);\r
137                 });\r
138                 return;\r
139             }\r
140             hiddenField = Ext.getDom(Ext.History.fieldId);\r
141             if (Ext.isIE) {\r
142                 iframe = Ext.getDom(Ext.History.iframeId);\r
143             }\r
144             this.addEvents('ready', 'change');\r
145             if(onReady){\r
146                 this.on('ready', onReady, scope, {single:true});\r
147             }\r
148             startUp();\r
149         },\r
150 \r
151         /**\r
152          * Add a new token to the history stack. This can be any arbitrary value, although it would\r
153          * commonly be the concatenation of a component id and another id marking the specifc history\r
154          * state of that component.  Example usage:\r
155          * <pre><code>\r
156 // Handle tab changes on a TabPanel\r
157 tabPanel.on('tabchange', function(tabPanel, tab){\r
158     Ext.History.add(tabPanel.id + ':' + tab.id);\r
159 });\r
160 </code></pre>\r
161          * @param {String} token The value that defines a particular application-specific history state\r
162          * @param {Boolean} preventDuplicates When true, if the passed token matches the current token\r
163          * it will not save a new history step. Set to false if the same state can be saved more than once\r
164          * at the same history stack location (defaults to true).\r
165          */\r
166         add: function (token, preventDup) {\r
167             if(preventDup !== false){\r
168                 if(this.getToken() == token){\r
169                     return true;\r
170                 }\r
171             }\r
172             if (Ext.isIE) {\r
173                 return updateIFrame(token);\r
174             } else {\r
175                 top.location.hash = token;\r
176                 return true;\r
177             }\r
178         },\r
179 \r
180         /**\r
181          * Programmatically steps back one step in browser history (equivalent to the user pressing the Back button).\r
182          */\r
183         back: function(){\r
184             history.go(-1);\r
185         },\r
186 \r
187         /**\r
188          * Programmatically steps forward one step in browser history (equivalent to the user pressing the Forward button).\r
189          */\r
190         forward: function(){\r
191             history.go(1);\r
192         },\r
193 \r
194         /**\r
195          * Retrieves the currently-active history token.\r
196          * @return {String} The token\r
197          */\r
198         getToken: function() {\r
199             return ready ? currentToken : getHash();\r
200         }\r
201     };\r
202 })();\r
203 Ext.apply(Ext.History, new Ext.util.Observable());