@@ -914,28 +914,50 @@ this.wheelDelta = function(e) {
914914 return delta ;
915915} ;
916916
917- this . scrollIntoView = function ( id ) {
918- setTimeout ( function ( ) {
919- var hashI = id . indexOf ( '#' ) ;
920- if ( hashI != - 1 )
921- id = id . substr ( hashI + 1 ) ;
922-
923- var obj = document . getElementById ( id ) ;
924- if ( obj ) {
925- /* Locate a suitable ancestor to scroll */
926- var p ;
927- for ( p = obj . parentNode ; p != document . body ; p = p . parentNode ) {
928- if ( p . scrollHeight > p . clientHeight &&
929- WT . css ( p , 'overflow-y' ) == 'auto' ) {
930- var xy = WT . widgetPageCoordinates ( obj , p ) ;
931- p . scrollTop += xy . y ;
932- return ;
933- }
934- }
917+ this . scrollHistory = function ( ) {
918+ // after any hash change event (forward/backward, or user clicks
919+ // on an achor with internal path), the server calls this function
920+ // to update the scroll position of the main window
921+ try {
922+ if ( window . history . state ) {
923+ if ( typeof window . history . state . pageXOffset !== UNDEFINED ) {
924+ // scroll to a historic position where we have been before
925+ //console.log("scrollHistory: " + JSON.stringify(window.history.state));
926+ window . scrollTo ( window . history . state . pageXOffset , window . history . state . pageYOffset ) ;
927+ } else {
928+ // we went to a new hash (following an anchor, we assume some equivalence
929+ // with 'new page') that hasn't been scrolled yet.
930+ // Scroll to the top, which may be overriden by scrollIntoView (if the hash
931+ // exists somewhere as an object ID)
932+ //console.log("scrollHistory: new page scroll strategy");
933+ // window.scrollTo(0, 0);
934+ WT . scrollIntoView ( window . history . state . state ) ;
935+ }
936+ }
937+ } catch ( error ) {
938+ console . log ( error ) ;
939+ }
940+ }
935941
936- obj . scrollIntoView ( true ) ;
942+ this . scrollIntoView = function ( id ) {
943+ var hashI = id . indexOf ( '#' ) ;
944+ if ( hashI != - 1 )
945+ id = id . substr ( hashI + 1 ) ;
946+
947+ var obj = document . getElementById ( id ) ;
948+ if ( obj ) {
949+ /* Locate a suitable ancestor to scroll */
950+ var p ;
951+ for ( p = obj . parentNode ; p != document . body ; p = p . parentNode ) {
952+ if ( p . scrollHeight > p . clientHeight &&
953+ WT . css ( p , 'overflow-y' ) == 'auto' ) {
954+ var xy = WT . widgetPageCoordinates ( obj , p ) ;
955+ p . scrollTop += xy . y ;
956+ return ;
937957 }
938- } , 100 ) ;
958+ }
959+ obj . scrollIntoView ( true ) ;
960+ }
939961} ;
940962
941963function isHighSurrogate ( chr ) {
@@ -1905,6 +1927,37 @@ function gentleURIEncode(s) {
19051927}
19061928
19071929if ( html5History ) {
1930+ // we need to update the scroll position at the scroll event,
1931+ // because we don't have the chance to update the html5history
1932+ // state anymore at the moment that onPopState() is called.
1933+ // For navigation, when pushState() is called, the scroll
1934+ // history can be updated before the pushState() call.
1935+ function updateScrollHistory ( ) {
1936+ //console.log("updateScrollHistory");
1937+ try {
1938+ var newState = window . history . state ;
1939+ if ( window . history . state == null ) {
1940+ // freshly initiated session, no state present yet
1941+ newState = { } ;
1942+ newState . state = "" ;
1943+ newState . title = window . document . title ;
1944+ }
1945+ newState . pageXOffset = window . pageXOffset ;
1946+ newState . pageYOffset = window . pageYOffset ;
1947+ window . history . replaceState ( newState , newState . title ) ;
1948+ } catch ( error ) {
1949+ // shouldn't happen
1950+ console . log ( error . toString ( ) ) ;
1951+ }
1952+ }
1953+ window . addEventListener ( 'scroll' , updateScrollHistory ) ;
1954+
1955+ // the 'auto' scrollRestoration gives too much flicker, since it
1956+ // updates the scroll state before the page is updated
1957+ // Browsers not supporting manual scrollRestoration, the flicker
1958+ // should not be worse than what it was.
1959+ window . history . scrollRestoration = 'manual' ;
1960+
19081961 this . history = ( function ( )
19091962{
19101963 var currentState = null , baseUrl = null , ugly = false , cb = null ,
@@ -1925,7 +1978,9 @@ if (html5History) {
19251978 saveState ( initialState ) ;
19261979
19271980 function onPopState ( event ) {
1928- var newState = event . state ;
1981+ var newState = null ;
1982+ if ( event . state && event . state . state )
1983+ newState = event . state . state ;
19291984
19301985 if ( newState == null )
19311986 newState = stateMap [ w . location . pathname + w . location . search ] ;
@@ -1945,6 +2000,7 @@ if (html5History) {
19452000 currentState = newState ;
19462001 onStateChange ( currentState != "" ? currentState : "/" ) ;
19472002 }
2003+ //console.log("onPopState: " + JSON.stringify(window.history.state));
19482004 }
19492005
19502006 w . addEventListener ( "popstate" , onPopState , false ) ;
@@ -1965,6 +2021,7 @@ _$_$endif_$_();
19652021 } ,
19662022
19672023 navigate : function ( state , generateEvent ) {
2024+ //console.log("navigate: " + state);
19682025 WT . resolveRelativeAnchors ( ) ;
19692026
19702027 currentState = state ;
@@ -2004,7 +2061,18 @@ _$_$endif_$_();
20042061 }
20052062
20062063 try {
2007- window . history . pushState ( state ? state : "" , document . title , url ) ;
2064+ var historyState = { } ;
2065+ historyState . state = state ? state : "" ;
2066+ // By not setting historyState.page[XY]Offset, we indicate that
2067+ // this state change was made by navigation rather than by
2068+ // the back/forward button
2069+ // keep title for call to replaceState when page offset is updated
2070+ historyState . title = document . title ;
2071+ // update scroll position of stack top with the position at the time of leaving the page
2072+ updateScrollHistory ( ) ;
2073+ //console.log("pushState before: " + JSON.stringify(window.history.state));
2074+ window . history . pushState ( historyState , document . title , url ) ;
2075+ //console.log("pushState after: " + JSON.stringify(window.history.state));
20082076 } catch ( error ) {
20092077 /*
20102078 * In case we are wrong about our baseUrl or base href
@@ -2013,7 +2081,12 @@ _$_$endif_$_();
20132081 console . log ( error . toString ( ) ) ;
20142082 }
20152083
2016- WT . scrollIntoView ( state ) ;
2084+ // We used to call scrollIntoView here. We modified this to have
2085+ // scrollIntoView called after the server round-trip, so that the
2086+ // new content is certainly visible before we scroll. This avoids
2087+ // flicker. If the rendering result was pre-learned client-side,
2088+ // the page will scroll to the right position only after a server
2089+ // round-trip, which is not ideal.
20172090
20182091 if ( generateEvent )
20192092 cb ( state ) ;
@@ -2056,8 +2129,6 @@ _$_$endif_$_();
20562129
20572130 w . location . hash = state ;
20582131
2059- WT . scrollIntoView ( state ) ;
2060-
20612132 if ( generateEvent )
20622133 cb ( state ) ;
20632134 } ,
0 commit comments