]> git.wh0rd.org Git - tt-rss.git/blob - lib/dojo/hash.js.uncompressed.js
modify dojo rebuild script to remove uncompressed files
[tt-rss.git] / lib / dojo / hash.js.uncompressed.js
1 define("dojo/hash", ["./_base/kernel", "require", "./_base/config", "./_base/connect", "./_base/lang", "./ready", "./sniff"],
2         function(dojo, require, config, connect, lang, ready, has){
3
4         // module:
5         //              dojo/hash
6
7         dojo.hash = function(/* String? */ hash, /* Boolean? */ replace){
8                 // summary:
9                 //              Gets or sets the hash string in the browser URL.
10                 // description:
11                 //              Handles getting and setting of location.hash.
12                 //
13                 //               - If no arguments are passed, acts as a getter.
14                 //               - If a string is passed, acts as a setter.
15                 // hash:
16                 //              the hash is set - #string.
17                 // replace:
18                 //              If true, updates the hash value in the current history
19                 //              state instead of creating a new history state.
20                 // returns:
21                 //              when used as a getter, returns the current hash string.
22                 //              when used as a setter, returns the new hash string.
23                 // example:
24                 //      |       topic.subscribe("/dojo/hashchange", context, callback);
25                 //      |
26                 //      |       function callback (hashValue){
27                 //      |               // do something based on the hash value.
28                 //      |       }
29
30                 // getter
31                 if(!arguments.length){
32                         return _getHash();
33                 }
34                 // setter
35                 if(hash.charAt(0) == "#"){
36                         hash = hash.substring(1);
37                 }
38                 if(replace){
39                         _replace(hash);
40                 }else{
41                         location.href = "#" + hash;
42                 }
43                 return hash; // String
44         };
45
46         // Global vars
47         var _recentHash, _ieUriMonitor, _connect,
48                 _pollFrequency = config.hashPollFrequency || 100;
49
50         //Internal functions
51         function _getSegment(str, delimiter){
52                 var i = str.indexOf(delimiter);
53                 return (i >= 0) ? str.substring(i+1) : "";
54         }
55
56         function _getHash(){
57                 return _getSegment(location.href, "#");
58         }
59
60         function _dispatchEvent(){
61                 connect.publish("/dojo/hashchange", [_getHash()]);
62         }
63
64         function _pollLocation(){
65                 if(_getHash() === _recentHash){
66                         return;
67                 }
68                 _recentHash = _getHash();
69                 _dispatchEvent();
70         }
71
72         function _replace(hash){
73                 if(_ieUriMonitor){
74                         if(_ieUriMonitor.isTransitioning()){
75                                 setTimeout(lang.hitch(null,_replace,hash), _pollFrequency);
76                                 return;
77                         }
78                         var href = _ieUriMonitor.iframe.location.href;
79                         var index = href.indexOf('?');
80                         // main frame will detect and update itself
81                         _ieUriMonitor.iframe.location.replace(href.substring(0, index) + "?" + hash);
82                         return;
83                 }
84                 location.replace("#"+hash);
85                 !_connect && _pollLocation();
86         }
87
88         function IEUriMonitor(){
89                 // summary:
90                 //              Determine if the browser's URI has changed or if the user has pressed the
91                 //              back or forward button. If so, call _dispatchEvent.
92                 //
93                 // description:
94                 //              IE doesn't add changes to the URI's hash into the history unless the hash
95                 //              value corresponds to an actual named anchor in the document. To get around
96                 //              this IE difference, we use a background IFrame to maintain a back-forward
97                 //              history, by updating the IFrame's query string to correspond to the
98                 //              value of the main browser location's hash value.
99                 //
100                 //              E.g. if the value of the browser window's location changes to
101                 //
102                 //              #action=someAction
103                 //
104                 //              ... then we'd update the IFrame's source to:
105                 //
106                 //              ?action=someAction
107                 //
108                 //              This design leads to a somewhat complex state machine, which is
109                 //              described below:
110                 //
111                 //              ####s1
112                 //
113                 //              Stable state - neither the window's location has changed nor
114                 //              has the IFrame's location. Note that this is the 99.9% case, so
115                 //              we optimize for it.
116                 //
117                 //              Transitions: s1, s2, s3
118                 //
119                 //              ####s2
120                 //
121                 //              Window's location changed - when a user clicks a hyperlink or
122                 //              code programmatically changes the window's URI.
123                 //
124                 //              Transitions: s4
125                 //
126                 //              ####s3
127                 //
128                 //              Iframe's location changed as a result of user pressing back or
129                 //              forward - when the user presses back or forward, the location of
130                 //              the background's iframe changes to the previous or next value in
131                 //              its history.
132                 //
133                 //              Transitions: s1
134                 //
135                 //              ####s4
136                 //
137                 //              IEUriMonitor has programmatically changed the location of the
138                 //              background iframe, but it's location hasn't yet changed. In this
139                 //              case we do nothing because we need to wait for the iframe's
140                 //              location to reflect its actual state.
141                 //
142                 //              Transitions: s4, s5
143                 //
144                 //              ####s5
145                 //
146                 //              IEUriMonitor has programmatically changed the location of the
147                 //              background iframe, and the iframe's location has caught up with
148                 //              reality. In this case we need to transition to s1.
149                 //
150                 //              Transitions: s1
151                 //
152                 //              The hashchange event is always dispatched on the transition back to s1.
153
154
155                 // create and append iframe
156                 var ifr = document.createElement("iframe"),
157                         IFRAME_ID = "dojo-hash-iframe",
158                         ifrSrc = config.dojoBlankHtmlUrl || require.toUrl("./resources/blank.html");
159
160                 if(config.useXDomain && !config.dojoBlankHtmlUrl){
161                         console.warn("dojo.hash: When using cross-domain Dojo builds,"
162                                 + " please save dojo/resources/blank.html to your domain and set djConfig.dojoBlankHtmlUrl"
163                                 + " to the path on your domain to blank.html");
164                 }
165
166                 ifr.id = IFRAME_ID;
167                 ifr.src = ifrSrc + "?" + _getHash();
168                 ifr.style.display = "none";
169                 document.body.appendChild(ifr);
170
171                 this.iframe = dojo.global[IFRAME_ID];
172                 var recentIframeQuery, transitioning, expectedIFrameQuery, docTitle, ifrOffline,
173                         iframeLoc = this.iframe.location;
174
175                 function resetState(){
176                         _recentHash = _getHash();
177                         recentIframeQuery = ifrOffline ? _recentHash : _getSegment(iframeLoc.href, "?");
178                         transitioning = false;
179                         expectedIFrameQuery = null;
180                 }
181
182                 this.isTransitioning = function(){
183                         return transitioning;
184                 };
185
186                 this.pollLocation = function(){
187                         if(!ifrOffline){
188                                 try{
189                                         //see if we can access the iframe's location without a permission denied error
190                                         var iframeSearch = _getSegment(iframeLoc.href, "?");
191                                         //good, the iframe is same origin (no thrown exception)
192                                         if(document.title != docTitle){ //sync title of main window with title of iframe.
193                                                 docTitle = this.iframe.document.title = document.title;
194                                         }
195                                 }catch(e){
196                                         //permission denied - server cannot be reached.
197                                         ifrOffline = true;
198                                         console.error("dojo.hash: Error adding history entry. Server unreachable.");
199                                 }
200                         }
201                         var hash = _getHash();
202                         if(transitioning && _recentHash === hash){
203                                 // we're in an iframe transition (s4 or s5)
204                                 if(ifrOffline || iframeSearch === expectedIFrameQuery){
205                                         // s5 (iframe caught up to main window or iframe offline), transition back to s1
206                                         resetState();
207                                         _dispatchEvent();
208                                 }else{
209                                         // s4 (waiting for iframe to catch up to main window)
210                                         setTimeout(lang.hitch(this,this.pollLocation),0);
211                                         return;
212                                 }
213                         }else if(_recentHash === hash && (ifrOffline || recentIframeQuery === iframeSearch)){
214                                 // we're in stable state (s1, iframe query == main window hash), do nothing
215                         }else{
216                                 // the user has initiated a URL change somehow.
217                                 // sync iframe query <-> main window hash
218                                 if(_recentHash !== hash){
219                                         // s2 (main window location changed), set iframe url and transition to s4
220                                         _recentHash = hash;
221                                         transitioning = true;
222                                         expectedIFrameQuery = hash;
223                                         ifr.src = ifrSrc + "?" + expectedIFrameQuery;
224                                         ifrOffline = false; //we're updating the iframe src - set offline to false so we can check again on next poll.
225                                         setTimeout(lang.hitch(this,this.pollLocation),0); //yielded transition to s4 while iframe reloads.
226                                         return;
227                                 }else if(!ifrOffline){
228                                         // s3 (iframe location changed via back/forward button), set main window url and transition to s1.
229                                         location.href = "#" + iframeLoc.search.substring(1);
230                                         resetState();
231                                         _dispatchEvent();
232                                 }
233                         }
234                         setTimeout(lang.hitch(this,this.pollLocation), _pollFrequency);
235                 };
236                 resetState(); // initialize state (transition to s1)
237                 setTimeout(lang.hitch(this,this.pollLocation), _pollFrequency);
238         }
239         ready(function(){
240                 if("onhashchange" in dojo.global && (!has("ie") || (has("ie") >= 8 && document.compatMode != "BackCompat"))){   //need this IE browser test because "onhashchange" exists in IE8 in IE7 mode
241                         _connect = connect.connect(dojo.global,"onhashchange",_dispatchEvent);
242                 }else{
243                         if(document.addEventListener){ // Non-IE
244                                 _recentHash = _getHash();
245                                 setInterval(_pollLocation, _pollFrequency); //Poll the window location for changes
246                         }else if(document.attachEvent){ // IE7-
247                                 //Use hidden iframe in versions of IE that don't have onhashchange event
248                                 _ieUriMonitor = new IEUriMonitor();
249                         }
250                         // else non-supported browser, do nothing.
251                 }
252         });
253
254         return dojo.hash;
255
256 });