2568df48f2c0875d0b24a63e48a75d8cae041f76
[platform/framework/web/web-ui-fw.git] / libs / js / jquery-mobile-1.0.1pre / js / jquery.mobile.navigation.pushstate.js
1 /*
2 * history.pushState support, layered on top of hashchange
3 */
4
5 ( function( $, window ) {
6         // For now, let's Monkeypatch this onto the end of $.mobile._registerInternalEvents
7         // Scope self to pushStateHandler so we can reference it sanely within the
8         // methods handed off as event handlers
9         var     pushStateHandler = {},
10                 self = pushStateHandler,
11                 $win = $( window ),
12                 url = $.mobile.path.parseUrl( location.href );
13
14         $.extend( pushStateHandler, {
15                 // TODO move to a path helper, this is rather common functionality
16                 initialFilePath: (function() {
17                         return url.pathname + url.search;
18                 })(),
19
20                 initialHref: url.hrefNoHash,
21
22                 // Flag for tracking if a Hashchange naturally occurs after each popstate + replace
23                 hashchangeFired: false,
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                 // TODO sort out a single barrier to hashchange functionality
50                 nextHashChangePrevented: function( value ) {
51                         $.mobile.urlHistory.ignoreNextHashChange = value;
52                         self.onHashChangeDisabled = value;
53                 },
54
55                 // on hash change we want to clean up the url
56                 // NOTE this takes place *after* the vanilla navigation hash change
57                 // handling has taken place and set the state of the DOM
58                 onHashChange: function( e ) {
59                         // disable this hash change
60                         if( self.onHashChangeDisabled ){
61                                 return;
62                         }
63                         
64                         var href, state,
65                                 hash = location.hash,
66                                 isPath = $.mobile.path.isPath( hash ),
67                                 resolutionUrl = isPath ? location.href : $.mobile.getDocumentUrl();
68                         hash = isPath ? hash.replace( "#", "" ) : hash;
69
70                         // propulate the hash when its not available
71                         state = self.state();
72
73                         // make the hash abolute with the current href
74                         href = $.mobile.path.makeUrlAbsolute( hash, resolutionUrl );
75
76                         if ( isPath ) {
77                                 href = self.resetUIKeys( href );
78                         }
79
80                         // replace the current url with the new href and store the state
81                         // Note that in some cases we might be replacing an url with the
82                         // same url. We do this anyways because we need to make sure that
83                         // all of our history entries have a state object associated with
84                         // them. This allows us to work around the case where window.history.back()
85                         // is called to transition from an external page to an embedded page.
86                         // In that particular case, a hashchange event is *NOT* generated by the browser.
87                         // Ensuring each history entry has a state object means that onPopState()
88                         // will always trigger our hashchange callback even when a hashchange event
89                         // is not fired.
90                         history.replaceState( state, document.title, href );
91                 },
92
93                 // on popstate (ie back or forward) we need to replace the hash that was there previously
94                 // cleaned up by the additional hash handling
95                 onPopState: function( e ) {
96                         var poppedState = e.originalEvent.state, holdnexthashchange = false;
97
98                         // if there's no state its not a popstate we care about, ie chrome's initial popstate
99                         // or forward popstate
100                         if( poppedState ) {
101                                 // disable any hashchange triggered by the browser
102                                 self.nextHashChangePrevented( true );
103
104                                 // defer our manual hashchange until after the browser fired
105                                 // version has come and gone
106                                 setTimeout(function() {
107                                         // make sure that the manual hash handling takes place
108                                         self.nextHashChangePrevented( false );
109
110                                         // change the page based on the hash
111                                         $.mobile._handleHashChange( poppedState.hash );
112                                 }, 100);
113                         }
114                 },
115
116                 init: function() {
117                         $win.bind( "hashchange", self.onHashChange );
118
119                         // Handle popstate events the occur through history changes
120                         $win.bind( "popstate", self.onPopState );
121
122                         // if there's no hash, we need to replacestate for returning to home
123                         if ( location.hash === "" ) {
124                                 history.replaceState( self.state(), document.title, location.href );
125                         }
126                 }
127         });
128
129         $( function() {
130                 if( $.mobile.pushStateEnabled && $.support.pushState ){
131                         pushStateHandler.init();
132                 }
133         });
134 })( jQuery, this );