Revert "Export"
[framework/web/web-ui-fw.git] / libs / js / jquery-mobile-1.1.0 / js / jquery.mobile.navigation.pushstate.js
1 //>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
2 //>>description: history.pushState support, layered on top of hashchange.
3 //>>label: Pushstate Support
4 //>>group: Navigation
5
6 define( [ "jquery", "./jquery.mobile.navigation", "../external/requirejs/depend!./jquery.mobile.hashchange[jquery]" ], function( $ ) {
7 //>>excludeEnd("jqmBuildExclude");
8 ( function( $, window ) {
9         // For now, let's Monkeypatch this onto the end of $.mobile._registerInternalEvents
10         // Scope self to pushStateHandler so we can reference it sanely within the
11         // methods handed off as event handlers
12         var     pushStateHandler = {},
13                 self = pushStateHandler,
14                 $win = $( window ),
15                 url = $.mobile.path.parseUrl( location.href );
16
17         $.extend( pushStateHandler, {
18                 // TODO move to a path helper, this is rather common functionality
19                 initialFilePath: (function() {
20                         return url.pathname + url.search;
21                 })(),
22
23                 initialHref: url.hrefNoHash,
24
25                 state: function() {
26                         return {
27                                 hash: location.hash || "#" + self.initialFilePath,
28                                 title: document.title,
29
30                                 // persist across refresh
31                                 initialHref: self.initialHref
32                         };
33                 },
34
35                 resetUIKeys: function( url ) {
36                         var dialog = $.mobile.dialogHashKey,
37                                 subkey = "&" + $.mobile.subPageUrlKey,
38                                 dialogIndex = url.indexOf( dialog );
39
40                         if( dialogIndex > -1 ) {
41                                 url = url.slice( 0, dialogIndex ) + "#" + url.slice( dialogIndex );
42                         } else if( url.indexOf( subkey ) > -1 ) {
43                                 url = url.split( subkey ).join( "#" + subkey );
44                         }
45
46                         return url;
47                 },
48
49                 hashValueAfterReset: function( url ) {
50                         var resetUrl = self.resetUIKeys( url );
51                         return $.mobile.path.parseUrl( resetUrl ).hash;
52                 },
53
54                 // TODO sort out a single barrier to hashchange functionality
55                 nextHashChangePrevented: function( value ) {
56                         $.mobile.urlHistory.ignoreNextHashChange = value;
57                         self.onHashChangeDisabled = value;
58                 },
59
60                 // on hash change we want to clean up the url
61                 // NOTE this takes place *after* the vanilla navigation hash change
62                 // handling has taken place and set the state of the DOM
63                 onHashChange: function( e ) {
64                         // disable this hash change
65                         if( self.onHashChangeDisabled ){
66                                 return;
67                         }
68
69                         var href, state,
70                                 hash = location.hash,
71                                 isPath = $.mobile.path.isPath( hash ),
72                                 resolutionUrl = isPath ? location.href : $.mobile.getDocumentUrl();
73
74                         hash = isPath ? hash.replace( "#", "" ) : hash;
75
76
77                         // propulate the hash when its not available
78                         state = self.state();
79
80                         // make the hash abolute with the current href
81                         href = $.mobile.path.makeUrlAbsolute( hash, resolutionUrl );
82
83                         if ( isPath ) {
84                                 href = self.resetUIKeys( href );
85                         }
86
87                         // replace the current url with the new href and store the state
88                         // Note that in some cases we might be replacing an url with the
89                         // same url. We do this anyways because we need to make sure that
90                         // all of our history entries have a state object associated with
91                         // them. This allows us to work around the case where window.history.back()
92                         // is called to transition from an external page to an embedded page.
93                         // In that particular case, a hashchange event is *NOT* generated by the browser.
94                         // Ensuring each history entry has a state object means that onPopState()
95                         // will always trigger our hashchange callback even when a hashchange event
96                         // is not fired.
97                         history.replaceState( state, document.title, href );
98                 },
99
100                 // on popstate (ie back or forward) we need to replace the hash that was there previously
101                 // cleaned up by the additional hash handling
102                 onPopState: function( e ) {
103                         var poppedState = e.originalEvent.state,
104                                 timeout, fromHash, toHash, hashChanged;
105
106                         // if there's no state its not a popstate we care about, eg chrome's initial popstate
107                         if( poppedState ) {
108                                 // the active url in the history stack will still be from the previous state
109                                 // so we can use it to verify if a hashchange will be fired from the popstate
110                                 fromHash = self.hashValueAfterReset( $.mobile.urlHistory.getActive().url );
111
112                                 // the hash stored in the state popped off the stack will be our currenturl or
113                                 // the url to which we wish to navigate
114                                 toHash = self.hashValueAfterReset( poppedState.hash.replace("#", "") );
115
116                                 // if the hashes of the urls are different we must assume that the browser
117                                 // will fire a hashchange
118                                 hashChanged = fromHash !== toHash;
119
120                                 // unlock hash handling once the hashchange caused be the popstate has fired
121                                 if( hashChanged ) {
122                                         $win.one( "hashchange.pushstate", function() {
123                                                 self.nextHashChangePrevented( false );
124                                         });
125                                 }
126
127                                 // enable hash handling for the the _handleHashChange call
128                                 self.nextHashChangePrevented( false );
129
130                                 // change the page based on the hash
131                                 $.mobile._handleHashChange( poppedState.hash );
132
133                                 // only prevent another hash change handling if a hash change will be fired
134                                 // by the browser
135                                 if( hashChanged ) {
136                                         // disable hash handling until one of the above timers fires
137                                         self.nextHashChangePrevented( true );
138                                 }
139                         }
140                 },
141
142                 init: function() {
143                         $win.bind( "hashchange", self.onHashChange );
144
145                         // Handle popstate events the occur through history changes
146                         $win.bind( "popstate", self.onPopState );
147
148                         // if there's no hash, we need to replacestate for returning to home
149                         if ( location.hash === "" ) {
150                                 history.replaceState( self.state(), document.title, location.href );
151                         }
152                 }
153         });
154
155         $( function() {
156                 if( $.mobile.pushStateEnabled && $.support.pushState ){
157                         pushStateHandler.init();
158                 }
159         });
160 })( jQuery, this );
161 //>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
162 });
163 //>>excludeEnd("jqmBuildExclude");