@@ -13,10 +13,13 @@ import { IMouseEvent, IScrollRecord } from '~shared/interfaces/ISaSession';
1313const domReplayerScript = require . resolve ( '../../injected-scripts/domReplayerSubscribe' ) ;
1414
1515export default class ReplayView extends ViewBackend {
16+ public static MESSAGE_HANG_ID = 'script-hang' ;
1617 public replayApi : ReplayApi ;
1718 public tabState : ReplayTabState ;
1819 public readonly playbarView : PlaybarView ;
1920
21+ private lastInactivityMillis = 0 ;
22+
2023 public constructor ( window : Window ) {
2124 super ( window , {
2225 preload : domReplayerScript ,
@@ -25,6 +28,7 @@ export default class ReplayView extends ViewBackend {
2528 contextIsolation : true ,
2629 javascript : false ,
2730 } ) ;
31+
2832 this . interceptHttpRequests ( ) ;
2933 this . playbarView = new PlaybarView ( window ) ;
3034 this . checkResponsive = this . checkResponsive . bind ( this ) ;
@@ -102,10 +106,22 @@ export default class ReplayView extends ViewBackend {
102106 await this . publishTickChanges ( events ) ;
103107 }
104108
109+ public async gotoNextTick ( ) {
110+ const offset = await this . nextTick ( ) ;
111+ this . playbarView . changeTickOffset ( offset ) ;
112+ }
113+
114+ public async gotoPreviousTick ( ) {
115+ const state = this . tabState . gotoPreviousTick ( ) ;
116+ await this . publishTickChanges ( state ) ;
117+ this . playbarView . changeTickOffset ( this . tabState . currentPlaybarOffsetPct ) ;
118+ }
119+
105120 public async nextTick ( ) {
106121 if ( ! this . isAttached || ! this . tabState ) return 0 ;
107122 const events = this . tabState . gotoNextTick ( ) ;
108123 await this . publishTickChanges ( events ) ;
124+ setImmediate ( ( ) => this . checkResponsive ( ) ) ;
109125
110126 return this . tabState . currentPlaybarOffsetPct ;
111127 }
@@ -123,9 +139,13 @@ export default class ReplayView extends ViewBackend {
123139 const [ domChanges ] = events ;
124140 if ( domChanges ?. length ) {
125141 if ( domChanges [ 0 ] . action === 'newDocument' ) {
126- const nav = domChanges . shift ( ) ;
127- console . log ( 'Re-navigating' , nav . textContent ) ;
128- await this . webContents . loadURL ( nav . textContent ) ;
142+ const url = new URL ( domChanges [ 0 ] . textContent ) ;
143+ const currentUrl = new URL ( this . webContents . getURL ( ) ) ;
144+ if ( url . origin !== currentUrl . origin ) {
145+ console . log ( 'Re-navigating' , url . href ) ;
146+ domChanges . shift ( ) ;
147+ await this . webContents . loadURL ( url . href ) ;
148+ }
129149 }
130150 }
131151 this . webContents . send ( 'dom:apply' , ...events ) ;
@@ -142,14 +162,30 @@ export default class ReplayView extends ViewBackend {
142162 }
143163
144164 private checkResponsive ( ) {
145- if ( this . replayApi . unresponsiveSeconds >= 5 ) {
165+ const lastActivityMillis =
166+ new Date ( ) . getTime ( ) - ( this . replayApi . lastActivityDate ?? new Date ( ) ) . getTime ( ) ;
167+
168+ if ( lastActivityMillis < this . lastInactivityMillis ) {
169+ this . lastInactivityMillis = lastActivityMillis ;
170+ return ;
171+ }
172+ if ( lastActivityMillis - this . lastInactivityMillis < 500 ) return ;
173+ this . lastInactivityMillis = lastActivityMillis ;
174+
175+ if (
176+ lastActivityMillis >= 5e3 &&
177+ this . replayApi . lastCommandName !== 'waitForMillis' &&
178+ this . replayApi . showUnresponsiveMessage
179+ ) {
180+ const lastActivitySecs = Math . floor ( lastActivityMillis / 1e3 ) ;
146181 Application . instance . overlayManager . show (
147182 'message-overlay' ,
148183 this . window . browserWindow ,
149184 this . window . browserWindow . getContentBounds ( ) ,
150185 {
151186 title : 'Did your script hang?' ,
152- message : `The last update was ${ this . replayApi . unresponsiveSeconds } seconds ago.` ,
187+ message : `The last update was ${ lastActivitySecs } seconds ago.` ,
188+ id : ReplayView . MESSAGE_HANG_ID ,
153189 } ,
154190 ) ;
155191 } else {
0 commit comments