2 Copyright (c) 2007 Brian Dillard and Brad Neuberg:
3 Brian Dillard | Project Lead | bdillard@pathf.com | http://blogs.pathf.com/agileajax/
4 Brad Neuberg | Original Project Creator | http://codinginparadise.org
6 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files
7 (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge,
8 publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do
9 so, subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15 FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
16 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18 window.dhtmlHistory={isIE:false,isOpera:false,isSafari:false,isSafari3:false,isKonquerer:false,isGecko:false,isSupported:false,create:function(_1){
20 var UA=navigator.userAgent.toLowerCase();
21 var _4=navigator.platform.toLowerCase();
22 var _5=navigator.vendor||"";
23 var _6=(UA.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[])[1];
25 this.isKonqueror=true;
26 this.isSupported=false;
28 if(typeof window.opera!=="undefined"){
30 this.isSupported=true;
32 if(typeof document.all!=="undefined"){
34 this.isSupported=true;
36 if(_5.indexOf("Apple Computer, Inc.")>-1){
37 if(parseInt(_6,10)<420){
42 this.isSupported=(_4.indexOf("mac")>-1);
44 if(UA.indexOf("gecko")!=-1){
46 this.isSupported=true;
52 window.historyStorage.setup(_1);
60 var _7=this.getCurrentLocation();
61 this.currentLocation=_7;
68 this.addEventListener(window,"unload",_8);
70 this.ignoreLocationChange=true;
72 if(!historyStorage.hasKey(this.PAGELOADEDSTRING)){
73 this.ignoreLocationChange=true;
75 historyStorage.put(this.PAGELOADEDSTRING,true);
77 this.ignoreLocationChange=false;
78 this.fireOnNewListener=true;
85 },initialize:function(){
87 if(!historyStorage.hasKey(this.PAGELOADEDSTRING)){
88 this.fireOnNewListener=false;
90 historyStorage.put(this.PAGELOADEDSTRING,true);
92 this.fireOnNewListener=true;
96 },addListener:function(_a){
98 if(this.fireOnNewListener){
99 this.fireHistoryEvent(this.currentLocation);
100 this.fireOnNewListener=false;
102 },addEventListener:function(o,e,l){
103 if(o.addEventListener){
104 o.addEventListener(e,l,false);
107 o.attachEvent("on"+e,function(){
112 },add:function(_e,_f){
114 _e=this.removeHash(_e);
115 historyStorage.put(_e,_f);
116 this.currentLocation=_e;
117 window.location.hash=_e;
118 this.putSafariState(_e);
122 if(_10.currentWaitTime>0){
123 _10.currentWaitTime=_10.currentWaitTime-_10.waitTime;
125 _e=_10.removeHash(_e);
126 if(document.getElementById(_e)&&_10.debugMode){
127 var e="Exception: History locations can not have the same value as _any_ IDs that might be in the document,"+" due to a bug in IE; please ask the developer to choose a history location that does not match any HTML"+" IDs in this document. The following ID is already taken and cannot be a location: "+_e;
130 historyStorage.put(_e,_f);
131 _10.ignoreLocationChange=true;
132 _10.ieAtomicLocationChange=true;
133 _10.currentLocation=_e;
134 window.location.hash=_e;
136 _10.iframe.src="blank.html?"+_e;
138 _10.ieAtomicLocationChange=false;
140 window.setTimeout(_11,this.currentWaitTime);
141 this.currentWaitTime=this.currentWaitTime+this.waitTime;
143 },isFirstLoad:function(){
144 return this.firstLoad;
145 },getVersion:function(){
147 },getCurrentLocation:function(){
148 var r=(this.isSafari?this.getSafariState():this.getCurrentHash());
150 },getCurrentHash:function(){
151 var r=window.location.href;
152 var i=r.indexOf("#");
153 return (i>=0?r.substr(i+1):"");
154 },PAGELOADEDSTRING:"DhtmlHistory_pageLoaded",listener:null,waitTime:200,currentWaitTime:0,currentLocation:null,iframe:null,safariHistoryStartPoint:null,safariStack:null,safariLength:null,ignoreLocationChange:null,fireOnNewListener:null,firstLoad:null,ieAtomicLocationChange:null,createIE:function(_16){
156 var _17=(historyStorage.debugMode?"width: 800px;height:80px;border:1px solid black;":historyStorage.hideStyles);
157 var _18="rshHistoryFrame";
158 var _19="<iframe frameborder=\"0\" id=\""+_18+"\" style=\""+_17+"\" src=\"blank.html?"+_16+"\"></iframe>";
160 this.iframe=document.getElementById(_18);
161 },createOpera:function(){
163 var _1a="<img src=\"javascript:location.href='javascript:dhtmlHistory.checkLocation();';\" style=\""+historyStorage.hideStyles+"\" />";
165 },createSafari:function(){
166 var _1b="rshSafariForm";
167 var _1c="rshSafariStack";
168 var _1d="rshSafariLength";
169 var _1e=historyStorage.debugMode?historyStorage.showStyles:historyStorage.hideStyles;
170 var _1f=(historyStorage.debugMode?"width:800px;height:20px;border:1px solid black;margin:0;padding:0;":historyStorage.hideStyles);
171 var _20="<form id=\""+_1b+"\" style=\""+_1e+"\">"+"<input type=\"text\" style=\""+_1f+"\" id=\""+_1c+"\" value=\"[]\"/>"+"<input type=\"text\" style=\""+_1f+"\" id=\""+_1d+"\" value=\"\"/>"+"</form>";
173 this.safariStack=document.getElementById(_1c);
174 this.safariLength=document.getElementById(_1d);
175 if(!historyStorage.hasKey(this.PAGELOADEDSTRING)){
176 this.safariHistoryStartPoint=history.length;
177 this.safariLength.value=this.safariHistoryStartPoint;
179 this.safariHistoryStartPoint=this.safariLength.value;
181 },getSafariStack:function(){
182 var r=this.safariStack.value;
183 return historyStorage.fromJSON(r);
184 },getSafariState:function(){
185 var _22=this.getSafariStack();
186 var _23=_22[history.length-this.safariHistoryStartPoint-1];
188 },putSafariState:function(_24){
189 var _25=this.getSafariStack();
190 _25[history.length-this.safariHistoryStartPoint]=_24;
191 this.safariStack.value=historyStorage.toJSON(_25);
192 },fireHistoryEvent:function(_26){
193 var _27=historyStorage.get(_26);
194 this.listener.call(null,_26,_27);
195 },checkLocation:function(){
196 if(!this.isIE&&this.ignoreLocationChange){
197 this.ignoreLocationChange=false;
200 if(!this.isIE&&this.ieAtomicLocationChange){
203 var _28=this.getCurrentLocation();
204 if(_28==this.currentLocation){
207 this.ieAtomicLocationChange=true;
208 if(this.isIE&&this.getIframeHash()!=_28){
209 this.iframe.src="blank.html?"+_28;
215 this.currentLocation=_28;
216 this.ieAtomicLocationChange=false;
217 this.fireHistoryEvent(_28);
218 },getIframeHash:function(){
219 var doc=this.iframe.contentWindow.document;
220 var _2a=String(doc.location.search);
221 if(_2a.length==1&&_2a.charAt(0)=="?"){
224 if(_2a.length>=2&&_2a.charAt(0)=="?"){
225 _2a=_2a.substring(1);
229 },removeHash:function(_2b){
231 if(_2b===null||_2b===undefined){
237 if(_2b.length==1&&_2b.charAt(0)=="#"){
240 if(_2b.length>1&&_2b.charAt(0)=="#"){
249 },iframeLoaded:function(_2d){
250 if(this.ignoreLocationChange){
251 this.ignoreLocationChange=false;
254 var _2e=String(_2d.search);
255 if(_2e.length==1&&_2e.charAt(0)=="?"){
258 if(_2e.length>=2&&_2e.charAt(0)=="?"){
259 _2e=_2e.substring(1);
262 window.location.hash=_2e;
263 this.fireHistoryEvent(_2e);
265 window.historyStorage={setup:function(_2f){
266 if(typeof _2f!=="undefined"){
268 this.debugMode=_2f.debugMode;
271 this.toJSON=_2f.toJSON;
274 this.fromJSON=_2f.fromJSON;
277 var _30="rshStorageForm";
278 var _31="rshStorageField";
279 var _32=this.debugMode?historyStorage.showStyles:historyStorage.hideStyles;
280 var _33=(historyStorage.debugMode?"width: 800px;height:80px;border:1px solid black;":historyStorage.hideStyles);
281 var _34="<form id=\""+_30+"\" style=\""+_32+"\">"+"<textarea id=\""+_31+"\" style=\""+_33+"\"></textarea>"+"</form>";
283 this.storageField=document.getElementById(_31);
284 if(typeof window.opera!=="undefined"){
285 this.storageField.focus();
287 },put:function(key,_36){
288 this.assertValidKey(key);
289 if(this.hasKey(key)){
292 this.storageHash[key]=_36;
293 this.saveHashTable();
295 this.assertValidKey(key);
296 this.loadHashTable();
297 var _38=this.storageHash[key];
302 },remove:function(key){
303 this.assertValidKey(key);
304 this.loadHashTable();
305 delete this.storageHash[key];
306 this.saveHashTable();
308 this.storageField.value="";
310 },hasKey:function(key){
311 this.assertValidKey(key);
312 this.loadHashTable();
313 return (typeof this.storageHash[key]!=="undefined");
314 },isValidKey:function(key){
315 return (typeof key==="string");
316 },showStyles:"border:0;margin:0;padding:0;",hideStyles:"left:-1000px;top:-1000px;width:1px;height:1px;border:0;position:absolute;",debugMode:false,storageHash:{},hashLoaded:false,storageField:null,assertValidKey:function(key){
317 var _3d=this.isValidKey(key);
318 if(!_3d&&this.debugMode){
319 throw new Error("Please provide a valid key for window.historyStorage. Invalid key = "+key+".");
321 },loadHashTable:function(){
322 if(!this.hashLoaded){
323 var _3e=this.storageField.value;
324 if(_3e!==""&&_3e!==null){
325 this.storageHash=this.fromJSON(_3e);
326 this.hashLoaded=true;
329 },saveHashTable:function(){
330 this.loadHashTable();
331 var _3f=this.toJSON(this.storageHash);
332 this.storageField.value=_3f;
333 },toJSON:function(o){
334 return o.toJSONString();
335 },fromJSON:function(s){
336 return s.parseJSON();