@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
1414limitations under the License.
1515*/
1616
17- import React , { createRef , ReactNode , SyntheticEvent } from 'react' ;
17+ import React , { createRef , ReactNode } from 'react' ;
1818import ReactDOM from "react-dom" ;
1919import { NotificationCountType , Room , RoomEvent } from "matrix-js-sdk/src/models/room" ;
2020import { MatrixEvent , MatrixEventEvent } from "matrix-js-sdk/src/models/event" ;
@@ -91,6 +91,9 @@ interface IProps {
9191 // id of an event to jump to. If not given, will go to the end of the live timeline.
9292 eventId ?: string ;
9393
94+ // whether we should scroll the event into view
95+ eventScrollIntoView ?: boolean ;
96+
9497 // where to position the event given by eventId, in pixels from the bottom of the viewport.
9598 // If not given, will try to put the event half way down the viewport.
9699 eventPixelOffset ?: number ;
@@ -124,8 +127,7 @@ interface IProps {
124127 // callback which is called when the panel is scrolled.
125128 onScroll ?( event : Event ) : void ;
126129
127- // callback which is called when the user interacts with the room timeline
128- onUserScroll ?( event : SyntheticEvent ) : void ;
130+ onEventScrolledIntoView ?( eventId ?: string ) : void ;
129131
130132 // callback which is called when the read-up-to mark is updated.
131133 onReadMarkerUpdated ?( ) : void ;
@@ -327,9 +329,11 @@ class TimelinePanel extends React.Component<IProps, IState> {
327329
328330 const differentEventId = newProps . eventId != this . props . eventId ;
329331 const differentHighlightedEventId = newProps . highlightedEventId != this . props . highlightedEventId ;
330- if ( differentEventId || differentHighlightedEventId ) {
331- logger . log ( "TimelinePanel switching to eventId " + newProps . eventId +
332- " (was " + this . props . eventId + ")" ) ;
332+ const differentAvoidJump = newProps . eventScrollIntoView && ! this . props . eventScrollIntoView ;
333+ if ( differentEventId || differentHighlightedEventId || differentAvoidJump ) {
334+ logger . log ( "TimelinePanel switching to " +
335+ "eventId " + newProps . eventId + " (was " + this . props . eventId + "), " +
336+ "scrollIntoView: " + newProps . eventScrollIntoView + " (was " + this . props . eventScrollIntoView + ")" ) ;
333337 return this . initTimeline ( newProps ) ;
334338 }
335339 }
@@ -1123,7 +1127,41 @@ class TimelinePanel extends React.Component<IProps, IState> {
11231127 offsetBase = 0.5 ;
11241128 }
11251129
1126- return this . loadTimeline ( initialEvent , pixelOffset , offsetBase ) ;
1130+ return this . loadTimeline ( initialEvent , pixelOffset , offsetBase , props . eventScrollIntoView ) ;
1131+ }
1132+
1133+ private scrollIntoView ( eventId ?: string , pixelOffset ?: number , offsetBase ?: number ) : void {
1134+ const doScroll = ( ) => {
1135+ if ( eventId ) {
1136+ debuglog ( "TimelinePanel scrolling to eventId " + eventId +
1137+ " at position " + ( offsetBase * 100 ) + "% + " + pixelOffset ) ;
1138+ this . messagePanel . current . scrollToEvent (
1139+ eventId ,
1140+ pixelOffset ,
1141+ offsetBase ,
1142+ ) ;
1143+ } else {
1144+ debuglog ( "TimelinePanel scrolling to bottom" ) ;
1145+ this . messagePanel . current . scrollToBottom ( ) ;
1146+ }
1147+ } ;
1148+
1149+ debuglog ( "TimelinePanel scheduling scroll to event" ) ;
1150+ this . props . onEventScrolledIntoView ?.( eventId ) ;
1151+ // Ensure the correct scroll position pre render, if the messages have already been loaded to DOM,
1152+ // to avoid it jumping around
1153+ doScroll ( ) ;
1154+
1155+ // Ensure the correct scroll position post render for correct behaviour.
1156+ //
1157+ // requestAnimationFrame runs our code immediately after the DOM update but before the next repaint.
1158+ //
1159+ // If the messages have just been loaded for the first time, this ensures we'll repeat setting the
1160+ // correct scroll position after React has re-rendered the TimelinePanel and MessagePanel and
1161+ // updated the DOM.
1162+ window . requestAnimationFrame ( ( ) => {
1163+ doScroll ( ) ;
1164+ } ) ;
11271165 }
11281166
11291167 /**
@@ -1139,8 +1177,10 @@ class TimelinePanel extends React.Component<IProps, IState> {
11391177 * @param {number? } offsetBase the reference point for the pixelOffset. 0
11401178 * means the top of the container, 1 means the bottom, and fractional
11411179 * values mean somewhere in the middle. If omitted, it defaults to 0.
1180+ *
1181+ * @param {boolean? } scrollIntoView whether to scroll the event into view.
11421182 */
1143- private loadTimeline ( eventId ?: string , pixelOffset ?: number , offsetBase ?: number ) : void {
1183+ private loadTimeline ( eventId ?: string , pixelOffset ?: number , offsetBase ?: number , scrollIntoView = true ) : void {
11441184 this . timelineWindow = new TimelineWindow (
11451185 MatrixClientPeg . get ( ) , this . props . timelineSet ,
11461186 { windowLimit : this . props . timelineCap } ) ;
@@ -1176,32 +1216,9 @@ class TimelinePanel extends React.Component<IProps, IState> {
11761216 return ;
11771217 }
11781218
1179- const doScroll = ( ) => {
1180- if ( eventId ) {
1181- debuglog ( "TimelinePanel scrolling to eventId " + eventId ) ;
1182- this . messagePanel . current . scrollToEvent (
1183- eventId ,
1184- pixelOffset ,
1185- offsetBase ,
1186- ) ;
1187- } else {
1188- debuglog ( "TimelinePanel scrolling to bottom" ) ;
1189- this . messagePanel . current . scrollToBottom ( ) ;
1190- }
1191- } ;
1192-
1193- // Ensure the correct scroll position pre render, if the messages have already been loaded to DOM, to
1194- // avoid it jumping around
1195- doScroll ( ) ;
1196-
1197- // Ensure the correct scroll position post render for correct behaviour.
1198- //
1199- // requestAnimationFrame runs our code immediately after the DOM update but before the next repaint.
1200- //
1201- // If the messages have just been loaded for the first time, this ensures we'll repeat setting the
1202- // correct scroll position after React has re-rendered the TimelinePanel and MessagePanel and updated
1203- // the DOM.
1204- window . requestAnimationFrame ( doScroll ) ;
1219+ if ( scrollIntoView ) {
1220+ this . scrollIntoView ( eventId , pixelOffset , offsetBase ) ;
1221+ }
12051222
12061223 if ( this . props . sendReadReceiptOnLoad ) {
12071224 this . sendReadReceipt ( ) ;
@@ -1651,7 +1668,6 @@ class TimelinePanel extends React.Component<IProps, IState> {
16511668 ourUserId = { MatrixClientPeg . get ( ) . credentials . userId }
16521669 stickyBottom = { stickyBottom }
16531670 onScroll = { this . onMessageListScroll }
1654- onUserScroll = { this . props . onUserScroll }
16551671 onFillRequest = { this . onMessageListFillRequest }
16561672 onUnfillRequest = { this . onMessageListUnfillRequest }
16571673 isTwelveHour = { this . context ?. showTwelveHourTimestamps ?? this . state . isTwelveHour }
0 commit comments