]> git.wh0rd.org - 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 });