2019-11-28 01:03:51 +01:00
/ * *
* Copyright 2019 Google Inc . All rights reserved .
* Modifications copyright ( c ) Microsoft Corporation .
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* /
2019-11-19 03:18:28 +01:00
import { helper , RegisteredListener } from '../helper' ;
2019-11-27 21:38:26 +01:00
import { JugglerSessionEvents } from './Connection' ;
2019-11-28 01:03:51 +01:00
import { FrameManagerEvents , FrameManager } from './FrameManager' ;
2019-11-19 03:18:28 +01:00
import { NetworkManager , NetworkManagerEvents } from './NetworkManager' ;
2019-11-28 01:03:51 +01:00
import * as frames from '../frames' ;
2019-11-19 03:18:28 +01:00
export class NextNavigationWatchdog {
2019-11-27 21:38:26 +01:00
private _frameManager : FrameManager ;
2019-11-28 01:03:51 +01:00
private _navigatedFrame : frames.Frame ;
2019-11-19 03:18:28 +01:00
private _promise : Promise < unknown > ;
private _resolveCallback : ( value? : unknown ) = > void ;
private _navigation : { navigationId : number | null , url? : string } = null ;
private _eventListeners : RegisteredListener [ ] ;
2019-11-27 21:38:26 +01:00
2019-11-28 01:03:51 +01:00
constructor ( frameManager : FrameManager , navigatedFrame : frames.Frame ) {
2019-11-27 21:38:26 +01:00
this . _frameManager = frameManager ;
2019-11-19 03:18:28 +01:00
this . _navigatedFrame = navigatedFrame ;
this . _promise = new Promise ( x = > this . _resolveCallback = x ) ;
this . _eventListeners = [
2019-11-27 21:38:26 +01:00
helper . addEventListener ( frameManager . _session , 'Page.navigationStarted' , this . _onNavigationStarted . bind ( this ) ) ,
helper . addEventListener ( frameManager . _session , 'Page.sameDocumentNavigation' , this . _onSameDocumentNavigation . bind ( this ) ) ,
2019-11-19 03:18:28 +01:00
] ;
}
promise() {
return this . _promise ;
}
navigation() {
return this . _navigation ;
}
_onNavigationStarted ( params ) {
2019-11-27 21:38:26 +01:00
if ( params . frameId === this . _frameManager . _frameData ( this . _navigatedFrame ) . frameId ) {
2019-11-19 03:18:28 +01:00
this . _navigation = {
navigationId : params.navigationId ,
url : params.url ,
} ;
this . _resolveCallback ( ) ;
}
}
_onSameDocumentNavigation ( params ) {
2019-11-27 21:38:26 +01:00
if ( params . frameId === this . _frameManager . _frameData ( this . _navigatedFrame ) . frameId ) {
2019-11-19 03:18:28 +01:00
this . _navigation = {
navigationId : null ,
} ;
this . _resolveCallback ( ) ;
}
}
dispose() {
helper . removeEventListeners ( this . _eventListeners ) ;
}
}
export class NavigationWatchdog {
2019-11-27 21:38:26 +01:00
private _frameManager : FrameManager ;
2019-11-28 01:03:51 +01:00
private _navigatedFrame : frames.Frame ;
2019-11-19 03:18:28 +01:00
private _targetNavigationId : any ;
private _firedEvents : any ;
private _targetURL : any ;
private _promise : Promise < unknown > ;
private _resolveCallback : ( value? : unknown ) = > void ;
private _navigationRequest : any ;
private _eventListeners : RegisteredListener [ ] ;
2019-11-27 21:38:26 +01:00
2019-11-28 01:03:51 +01:00
constructor ( frameManager : FrameManager , navigatedFrame : frames.Frame , networkManager : NetworkManager , targetNavigationId , targetURL , firedEvents ) {
2019-11-27 21:38:26 +01:00
this . _frameManager = frameManager ;
2019-11-19 03:18:28 +01:00
this . _navigatedFrame = navigatedFrame ;
this . _targetNavigationId = targetNavigationId ;
this . _firedEvents = firedEvents ;
this . _targetURL = targetURL ;
this . _promise = new Promise ( x = > this . _resolveCallback = x ) ;
this . _navigationRequest = null ;
const check = this . _checkNavigationComplete . bind ( this ) ;
this . _eventListeners = [
2019-11-27 21:38:26 +01:00
helper . addEventListener ( frameManager . _session , JugglerSessionEvents . Disconnected , ( ) = > this . _resolveCallback ( new Error ( 'Navigation failed because browser has disconnected!' ) ) ) ,
helper . addEventListener ( frameManager . _session , 'Page.eventFired' , check ) ,
helper . addEventListener ( frameManager . _session , 'Page.frameAttached' , check ) ,
helper . addEventListener ( frameManager . _session , 'Page.frameDetached' , check ) ,
helper . addEventListener ( frameManager . _session , 'Page.navigationStarted' , check ) ,
helper . addEventListener ( frameManager . _session , 'Page.navigationCommitted' , check ) ,
helper . addEventListener ( frameManager . _session , 'Page.navigationAborted' , this . _onNavigationAborted . bind ( this ) ) ,
2019-11-19 03:18:28 +01:00
helper . addEventListener ( networkManager , NetworkManagerEvents . Request , this . _onRequest . bind ( this ) ) ,
2019-11-27 21:38:26 +01:00
helper . addEventListener ( frameManager , FrameManagerEvents . FrameDetached , check ) ,
2019-11-19 03:18:28 +01:00
] ;
check ( ) ;
}
_onRequest ( request ) {
if ( request . frame ( ) !== this . _navigatedFrame || ! request . isNavigationRequest ( ) )
return ;
this . _navigationRequest = request ;
}
navigationResponse() {
return this . _navigationRequest ? this . _navigationRequest . response ( ) : null ;
}
_checkNavigationComplete() {
2019-11-28 01:03:51 +01:00
const checkFiredEvents = ( frame : frames.Frame , firedEvents ) = > {
2019-11-27 21:38:26 +01:00
for ( const subframe of frame . childFrames ( ) ) {
if ( ! checkFiredEvents ( subframe , firedEvents ) )
return false ;
}
return firedEvents . every ( event = > this . _frameManager . _frameData ( frame ) . firedEvents . has ( event ) ) ;
} ;
2019-11-19 03:18:28 +01:00
if ( this . _navigatedFrame . isDetached ( ) )
this . _resolveCallback ( new Error ( 'Navigating frame was detached' ) ) ;
2019-11-27 21:38:26 +01:00
else if ( this . _frameManager . _frameData ( this . _navigatedFrame ) . lastCommittedNavigationId === this . _targetNavigationId
2019-11-19 03:18:28 +01:00
&& checkFiredEvents ( this . _navigatedFrame , this . _firedEvents ) )
this . _resolveCallback ( null ) ;
}
_onNavigationAborted ( params ) {
2019-11-27 21:38:26 +01:00
if ( params . frameId === this . _frameManager . _frameData ( this . _navigatedFrame ) . frameId && params . navigationId === this . _targetNavigationId )
2019-11-19 03:18:28 +01:00
this . _resolveCallback ( new Error ( 'Navigation to ' + this . _targetURL + ' failed: ' + params . errorText ) ) ;
}
promise() {
return this . _promise ;
}
dispose() {
helper . removeEventListeners ( this . _eventListeners ) ;
}
}