Permalink
Browse files

Changes to hopefully simplify and synchronize transitions and scrolling.

- Added $.mobile.scrollTo() which synchronously scrolls the page, and is aware of any pending silentScroll() requests.

- Removed the silentScroll() call in the orientationchange and resize callback in jquery.mobile.media.js.

- Modified transition code to use $.mobile.scrollTo() so that we can synchronously scroll the window. Changed where we call the focus and scroll code to account for timing.

- Removed setTimeout() wrap around transitionPages() in the ajax callback.
  • Loading branch information...
1 parent b464b1b commit a0fa3d477b73c6b480d0fbfad46820c94e54d7c7 @jblas jblas committed Feb 2, 2011
Showing with 47 additions and 19 deletions.
  1. +15 −8 js/jquery.mobile.core.js
  2. +0 −2 js/jquery.mobile.media.js
  3. +32 −9 js/jquery.mobile.navigation.js
View
@@ -134,6 +134,8 @@
$.mobile.metaViewportContent ? $( "<meta>", { name: "viewport", content: $.mobile.metaViewportContent}).prependTo( $head ) : undefined;
+ var silentScrollTimer = 0;
+
//expose some core utilities
$.extend($.mobile, {
@@ -158,20 +160,25 @@
}
},
+ scrollTo: function(x, y) {
+ if (silentScrollTimer)
+ clearTimeout(silentScrollTimer);
+ silentScrollTimer = 0;
+ window.scrollTo(x || 0, y || 0);
+ },
+
//scroll page vertically: scroll to 0 to hide iOS address bar, or pass a Y value
silentScroll: function( ypos ) {
ypos = ypos || 0;
// prevent scrollstart and scrollstop events
$.event.special.scrollstart.enabled = false;
-
- setTimeout(function() {
- window.scrollTo( 0, ypos );
+ if (silentScrollTimer)
+ clearTimeout(silentScrollTimer);
+ silentScrollTimer = setTimeout(function() {
+ $.mobile.scrollTo( 0, ypos );
+ $.event.special.scrollstart.enabled = true;
$(document).trigger( "silentscroll", { x: 0, y: ypos });
},20);
-
- setTimeout(function() {
- $.event.special.scrollstart.enabled = true;
- }, 150 );
},
// find and enhance the pages in the dom and transition to the first page.
@@ -212,6 +219,6 @@
//window load event
//hide iOS browser chrome on load
- $window.load( $.mobile.silentScroll );
+ $window.load( function(){$.mobile.silentScroll();} );
})( jQuery, this );
@@ -111,8 +111,6 @@ $(document).bind("mobileinit.htmlclass", function(){
} else {
$( '.ui-page' ).css( 'minHeight', ( screen.availHeight <= screen.availWidth ) ? screen.availHeight : screen.availWidth);
}
-
- $.mobile.silentScroll();
}
//add classes to HTML element for min/max breakpoints
detectResolutionBreakpoints();
@@ -345,8 +345,6 @@
//function for transitioning between two existing pages
function transitionPages() {
- $.mobile.silentScroll();
-
//get current scroll distance
var currScroll = $window.scrollTop(),
perspectiveTransitions = [ "flip" ],
@@ -381,11 +379,6 @@
removeActiveLinkClass();
- //jump to top or prev scroll, sometimes on iOS the page has not rendered yet. I could only get by this with a setTimeout, but would like to avoid that.
- $.mobile.silentScroll( to.data( "lastScroll" ) );
-
- reFocus( to );
-
//trigger show/hide events
if( from ){
from.data( "page" )._trigger( "hide", null, { nextPage: to } );
@@ -423,7 +416,7 @@
pageContainerClasses = [];
};
-
+ $.mobile.scrollTo(0, 0);
if(transition && (transition !== 'none')){
$.mobile.pageLoading( true );
@@ -446,7 +439,31 @@
from.removeClass( $.mobile.activePageClass );
}
loadComplete();
+
+ // The ordering of the operations below is important for the following reasons:
+ //
+ // - The classes that are set on the viewport during a transition causes
+ // ui-page elements to have a height that exactly matches the viewport
+ // height. When removeContainerClasses() is called, these classes are removed,
+ // but the reflow necessary to calculate the new document height may not have
+ // happened yet. This means we need to delay the code that sets any previous
+ // scroll offset for some time so that the browser can calculate the height,
+ // allowing us to scroll to the proper offset.
+ //
+ // - We need to set the focus *AFTER* the classes have been removed so that we
+ // don't trigger the browser's auto-offset-rendering which kicks in for overflow:hidden
+ // elements. We also need to make sure we set it *BEFORE* we scroll so that it doesn't
+ // cause the browser to scroll the focused element into view after we've set our desired
+ // scroll position.
+ //
+ // - Finally, we set the scroll position *AFTER* the classes are unset and focus has
+ // been set.
removeContainerClasses();
+ reFocus( to );
+ setTimeout(function(){
+ reFocus( to );
+ $.mobile.scrollTo( 0, to.data( "lastScroll" ) );
+ }, 10);
});
}
else{
@@ -456,6 +473,12 @@
}
to.addClass( $.mobile.activePageClass );
loadComplete();
+
+ // The order of the code below matters. We need make sure we focus first,
+ // and then scroll to our desired offset since some browsers will auto scroll
+ // whatever gets focused programatically into view.
+ reFocus( to );
+ $.mobile.scrollTo( 0, to.data( "lastScroll" ) );
}
};
@@ -557,7 +580,7 @@
.appendTo( $.mobile.pageContainer );
enhancePage();
- setTimeout(function() { transitionPages() }, 0);
+ transitionPages();
},
error: function() {
$.mobile.pageLoading( true );

0 comments on commit a0fa3d4

Please sign in to comment.