@@ -74,6 +74,8 @@ export default class PageContext extends ContentFeature {
7474 mutationObserver = null ;
7575 lastSentContent = null ;
7676 listenForUrlChanges = true ;
77+ /** @type {ReturnType<typeof setTimeout> | null } */
78+ #delayedRecheckTimer = null ;
7779
7880 init ( ) {
7981 if ( ! this . shouldActivate ( ) ) {
@@ -95,7 +97,11 @@ export default class PageContext extends ContentFeature {
9597 } ) ;
9698 if ( this . getFeatureSettingEnabled ( 'subscribeToHashChange' , 'enabled' ) ) {
9799 window . addEventListener ( 'hashchange' , ( ) => {
100+ // Immediate collection
98101 this . handleContentCollectionRequest ( ) ;
102+
103+ // Schedule delayed recheck after DOM settles
104+ this . scheduleDelayedRecheck ( ) ;
99105 } ) ;
100106 }
101107 if ( this . getFeatureSettingEnabled ( 'subscribeToPageShow' , 'enabled' ) ) {
@@ -145,7 +151,11 @@ export default class PageContext extends ContentFeature {
145151 if ( ! this . shouldActivate ( ) ) {
146152 return ;
147153 }
154+ // Immediate collection
148155 this . handleContentCollectionRequest ( ) ;
156+
157+ // Schedule delayed recheck after DOM settles
158+ this . scheduleDelayedRecheck ( ) ;
149159 }
150160
151161 setup ( ) {
@@ -169,6 +179,17 @@ export default class PageContext extends ContentFeature {
169179 this . #cachedContent = undefined ;
170180 this . #cachedTimestamp = 0 ;
171181 this . stopObserving ( ) ;
182+ this . clearTimers ( ) ;
183+ }
184+
185+ /**
186+ * Clear all pending timers
187+ */
188+ clearTimers ( ) {
189+ if ( this . #delayedRecheckTimer) {
190+ clearTimeout ( this . #delayedRecheckTimer) ;
191+ this . #delayedRecheckTimer = null ;
192+ }
172193 }
173194
174195 set cachedContent ( content ) {
@@ -198,6 +219,69 @@ export default class PageContext extends ContentFeature {
198219 }
199220 }
200221
222+ /**
223+ * Schedule a delayed recheck after navigation events
224+ */
225+ scheduleDelayedRecheck ( ) {
226+ // Clear any existing delayed recheck
227+ if ( this . #delayedRecheckTimer) {
228+ clearTimeout ( this . #delayedRecheckTimer) ;
229+ }
230+
231+ const delayMs = this . getFeatureSetting ( 'navigationRecheckDelayMs' ) || 1500 ;
232+
233+ this . log . info ( 'Scheduling delayed recheck' , { delayMs } ) ;
234+ this . #delayedRecheckTimer = setTimeout ( ( ) => {
235+ this . log . info ( 'Performing delayed recheck after navigation' ) ;
236+
237+ // Store the previous content for comparison
238+ const previousContent = this . cachedContent ;
239+
240+ // Force fresh collection by invalidating cache
241+ this . invalidateCache ( ) ;
242+
243+ // Collect fresh content
244+ const freshContent = this . collectPageContent ( ) ;
245+
246+ // Only send if content has meaningfully changed
247+ if ( this . hasContentChanged ( previousContent , freshContent ) ) {
248+ this . log . info ( 'Content changed after navigation delay - sending update' ) ;
249+ this . sendContentResponse ( freshContent ) ;
250+ } else {
251+ this . log . info ( 'No significant content change after navigation delay' ) ;
252+ }
253+
254+ this . #delayedRecheckTimer = null ;
255+ } , delayMs ) ;
256+ }
257+
258+ /**
259+ * Check if content has meaningfully changed
260+ * @param {any } oldContent
261+ * @param {any } newContent
262+ * @returns {boolean }
263+ */
264+ hasContentChanged ( oldContent , newContent ) {
265+ if ( ! oldContent || ! newContent ) {
266+ return true ;
267+ }
268+
269+ // Compare key content fields
270+ const fieldsToCompare = [ 'title' , 'content' , 'headings' ] ;
271+
272+ for ( const field of fieldsToCompare ) {
273+ const oldValue = JSON . stringify ( oldContent [ field ] || '' ) ;
274+ const newValue = JSON . stringify ( newContent [ field ] || '' ) ;
275+
276+ if ( oldValue !== newValue ) {
277+ this . log . info ( 'Content changed in field' , field ) ;
278+ return true ;
279+ }
280+ }
281+
282+ return false ;
283+ }
284+
201285 startObserving ( ) {
202286 this . log . info ( 'Starting observing' , this . mutationObserver , this . #cachedContent) ;
203287 if ( this . mutationObserver && this . #cachedContent && ! this . isObserving ) {
0 commit comments