@@ -76,11 +76,22 @@ export class ActiveHTMLModel extends DOMWidgetModel {
7676 // constructor() {
7777 // super();
7878 // }
79+ _is_ready = false ;
7980 initialize ( attributes : any , options : { model_id : string ; comm ?: any ; widget_manager : any } ) {
8081 super . initialize ( attributes , options ) ;
8182 // this._ihandlers= {};
82- this . _updateHandlers ( ) ;
83- this . on ( 'change:jsHandlers' , this . _updateHandlers , this ) ;
83+ this . ready ( )
84+ }
85+ ready ( ) :Promise < ActiveHTMLModel > {
86+ if ( ! this . _is_ready ) {
87+ return this . _updateHandlers ( ) . then ( ( ) => {
88+ this . on ( 'change:jsHandlers' , this . _updateHandlers , this ) ;
89+ this . _is_ready = true ;
90+ return this
91+ } )
92+ } else {
93+ return Promise . resolve ( this )
94+ }
8495 }
8596
8697 defaults ( ) {
@@ -160,12 +171,11 @@ export class ActiveHTMLModel extends DOMWidgetModel {
160171 }
161172 return hash ;
162173 }
163- _updateHandlers ( ) : void {
164- let handlers = this . get ( 'jsHandlers' ) as Record < string , string > ;
165- let debug = this . get ( '_debugPrint' ) ;
174+ _setHandlers ( handlers :Record < string , string > ) {
166175 let _ihandlers = this . get ( '_ihandlers' ) ;
176+ let debug = this . get ( '_debugPrint' ) ;
167177 for ( let h in handlers ) {
168- if ( handlers . hasOwnProperty ( h ) ) {
178+ if ( h != "src" && handlers . hasOwnProperty ( h ) ) {
169179 let hash = this . _stringHash ( handlers [ h ] ) ;
170180 if (
171181 ( ! _ihandlers . hasOwnProperty ( h ) ) ||
@@ -179,6 +189,52 @@ export class ActiveHTMLModel extends DOMWidgetModel {
179189 }
180190 }
181191 }
192+ _apiMod :string | null = null ;
193+ static _needsAPILoad ( curMod :string | null , handlers :Record < string , any > , _ihandlers :Record < string , any > ) :boolean {
194+ return (
195+ handlers . hasOwnProperty ( "src" ) &&
196+ curMod !== handlers [ "src" ] &&
197+ ( ! _ihandlers . hasOwnProperty ( "src" ) || _ihandlers [ "src" ] != handlers [ "src" ] )
198+ )
199+ }
200+ _apiLoader :Promise < Record < string , any > > | null = null ;
201+ _updateHandlers ( ) : Promise < Record < string , any > > {
202+ let handlers = this . get ( 'jsHandlers' ) as Record < string , string > ;
203+ let debug = this . get ( '_debugPrint' ) ;
204+ let _ihandlers = this . get ( '_ihandlers' ) as Record < string , any > ;
205+ let imp = null ;
206+ if ( ActiveHTMLModel . _needsAPILoad ( this . _apiMod , handlers , _ihandlers ) ) {
207+ if ( debug ) {
208+ console . log ( 'loading API from source' , handlers [ "src" ] ) ;
209+ }
210+ // Ugly TypeScript hack to keep the dynamic import semantics we need
211+ // for reliable loading
212+ imp = eval ( "import(\"" + handlers [ "src" ] + "\")" ) ;
213+ }
214+ if ( imp !== null ) {
215+ this . _apiLoader = imp . then (
216+ ( mod : Record < string , any > ) => {
217+ for ( let m in mod ) {
218+ if ( mod [ m ] instanceof Function ) {
219+ _ihandlers [ m ] = [ null , mod [ m ] ] ;
220+ }
221+ }
222+ this . _apiMod = handlers [ "src" ] ;
223+ _ihandlers [ "src" ] = handlers [ "src" ] ;
224+ }
225+ ) . then ( ( ) => {
226+ this . _setHandlers ( handlers ) ;
227+ this . _apiLoader = null ;
228+ return _ihandlers
229+ } )
230+ }
231+ if ( this . _apiLoader !== null && typeof this . _apiLoader !== "undefined" ) {
232+ return this . _apiLoader as Promise < Record < string , any > > ;
233+ } else {
234+ this . _setHandlers ( handlers )
235+ return Promise . resolve ( _ihandlers )
236+ }
237+ }
182238
183239 _handle_comm_msg ( msg : KernelMessage . ICommMsgMsg ) : Promise < void > {
184240 const data = msg . content . data as any ;
@@ -209,27 +265,40 @@ export class ActiveHTMLModel extends DOMWidgetModel {
209265 ...ops
210266 } as unknown as Event ; // a hack only so we can use the same interface for custom events
211267 }
212- callHandler ( method :string , event :Event ) {
213- let handlers = this . get ( '_ihandlers' ) as Record < string , any > ;
214- let fn : ( ( event :Event , widget :WidgetModel , context :object ) => void ) | null = null ;
268+ callHandler ( method :string , event :Event ) : Promise < any > {
269+ return ActiveHTMLModel . callModelHandler ( method , event , this , this ) ;
270+ }
271+ static callModelHandler ( method : string , event : Event , model :WidgetModel , target :any ) : Promise < any > {
272+ let handlers = model . get ( '_ihandlers' ) as Record < string , any > ;
273+ let fn : ( ( event :Event , widget :WidgetModel , context :object ) => any ) | null = null ;
274+
215275 if ( handlers . hasOwnProperty ( method ) ) {
216276 fn = handlers [ method ] [ 1 ] ;
277+ if ( fn !== null ) {
278+ let val = fn . call ( target , event , target , ActiveHTMLView . handlerContext ) ;
279+ return Promise . resolve ( val ) ;
280+ } else {
281+ throw new Error ( "handler " + method + " is null" ) ;
282+ }
217283 } else {
218- let api = this . get ( 'jsAPI' ) ;
284+ let api = model . get ( 'jsAPI' ) as ActiveHTMLModel | null ;
219285 if ( api !== null ) {
220- handlers = api . get ( "_ihandlers" ) ;
221- if ( handlers . hasOwnProperty ( method ) ) {
222- fn = handlers [ method ] [ 1 ] ;
223- }
286+ return api . ready ( ) . then ( ( api ) => {
287+ handlers = api . get ( '_ihandlers' ) as Record < string , any >
288+ if ( handlers . hasOwnProperty ( method ) ) {
289+ fn = handlers [ method ] [ 1 ] ;
290+ }
291+ if ( fn !== null ) {
292+ return fn . call ( target , event , target , ActiveHTMLView . handlerContext ) ;
293+ } else {
294+ throw new Error ( "couldn't find API method " + method ) ;
295+ }
296+ } )
297+ } else {
298+ throw new Error ( "couldn't find handler or API method " + method ) ;
224299 }
225300 }
226- if ( fn !== null ) {
227- fn . call ( this , event , this , ActiveHTMLView . handlerContext ) ;
228- } else {
229- throw new Error ( "couldn't find handler " + method ) ;
230- }
231301 }
232-
233302}
234303
235304export class ActiveHTMLView extends DOMWidgetView {
@@ -699,7 +768,7 @@ export class ActiveHTMLView extends DOMWidgetView {
699768 }
700769 updateEvents ( ) :Promise < any > {
701770 return this . setEvents ( ) . then (
702- ( ) => this . removeEvents
771+ ( ) => this . removeEvents ( )
703772 )
704773 }
705774
@@ -754,7 +823,7 @@ export class ActiveHTMLView extends DOMWidgetView {
754823 }
755824 updateOnHandlers ( ) :Promise < any > {
756825 return this . setOnHandlers ( ) . then (
757- ( ) => this . removeOnHandlers
826+ ( ) => this . removeOnHandlers ( )
758827 )
759828 }
760829
@@ -950,25 +1019,8 @@ export class ActiveHTMLView extends DOMWidgetView {
9501019 this . sendEventMessage ( e , this . constructEventMessage ( e , props , eventName ) ) ;
9511020 }
9521021 }
953- callHandler ( method :string , event :Event ) {
954- let handlers = this . model . get ( '_ihandlers' ) as Record < string , any > ;
955- let fn : ( ( event :Event , widget :WidgetView , context :object ) => void ) | null = null ;
956- if ( handlers . hasOwnProperty ( method ) ) {
957- fn = handlers [ method ] [ 1 ] ;
958- } else {
959- let api = this . model . get ( 'jsAPI' ) ;
960- if ( api !== null ) {
961- handlers = api . get ( "_ihandlers" ) ;
962- if ( handlers . hasOwnProperty ( method ) ) {
963- fn = handlers [ method ] [ 1 ] ;
964- }
965- }
966- }
967- if ( fn !== null ) {
968- fn . call ( this , event , this , ActiveHTMLView . handlerContext ) ;
969- } else {
970- throw new Error ( "couldn't find handler " + method ) ;
971- }
1022+ callHandler ( method :string , event :Event ) :Promise < any > {
1023+ return ActiveHTMLModel . callModelHandler ( method , event , this . model , this ) ;
9721024 }
9731025 dummyEvent ( name :string , ops :object = { } ) :Event {
9741026 return {
0 commit comments