import * as utils from './utils' ; import * as backbonePatch from './backbone-patch' ; import * as Backbone from 'backbone' ; import $ from 'jquery' ; import { NativeView } from './nativeview' ; import { JSONObject } from '@lumino/coreutils' ; import { Message , MessageLoop } from '@lumino/messaging' ; import { Widget , Panel } from '@lumino/widgets' ; import { LayoutModel } from './widget_layout' ; import { StyleModel } from './widget_style' ; import { IWidgetManager } from './manager' ; import { IClassicComm , ICallbacks } from './services-shim' ; import { JUPYTER_WIDGETS_VERSION } from './version' ; import { Dict } from './utils' ; import { KernelMessage } from '@jupyterlab/services' ; /**
 * Replace model ids with models recursively.
 */ export function unpack_models ( value , manager ) { if ( Array . isArray ( value ) ) { const unpacked = [ ] ; value . forEach ( ( sub_value , key ) => { unpacked . push ( unpack_models ( sub_value , manager ) ) ; } ) ; return Promise . all ( unpacked ) ; } else if ( value instanceof Object && typeof value !== 'string' ) { const unpacked = { } ; Object . keys ( value ) . forEach ( ( key ) => { unpacked [ key ] = unpack_models ( value [ key ] , manager ) ; } ) ; return utils . resolvePromisesDict ( unpacked ) ; } else if ( typeof value === 'string' && value . slice ( 0 , 10 ) === 'IPY_MODEL_' ) { return Promise . resolve ( manager . get_model ( value . slice ( 10 , value . length ) ) ) ; } else { return Promise . resolve ( value ) ; } } /**
 * Type declaration for general widget serializers.
 */ export interface ISerializers { [ key ] : { deserialize ? : ( value ? : any , manager ? : IWidgetManager ) => any ; serialize ? : ( value ? : any , widget ? : WidgetModel ) => any ; } ; } export interface IBackboneModelOptions extends Backbone . ModelSetOptions { model_id : string ; comm ? : any ; widget_manager : any ; } export class WidgetModel extends Backbone . Model { /**
     * The default attributes.
     */ defaults ( ) { return { _model_module : '@jupyter-widgets/base' , _model_name : 'WidgetModel' , _model_module_version : JUPYTER_WIDGETS_VERSION , _view_module : '@jupyter-widgets/base' , _view_name : null as string | null , _view_module_version : JUPYTER_WIDGETS_VERSION , _view_count : null as number | null , } ; } /**
     * Test to see if the model has been synced with the server.
     *
     * #### Notes
     * As of backbone 1.1, backbone ignores `patch` if it thinks the
     * model has never been pushed.
     */ isNew ( ) { return false ; } /**
     * Constructor
     *
     * Initializes a WidgetModel instance. Called by the Backbone constructor.
     *
     * Parameters
     * ----------
     * widget_manager : WidgetManager instance
     * model_id : string
     *      An ID unique to this model.
     * comm : Comm instance (optional)
     */ initialize ( attributes , options ) { this . expectedEchoMsgIds = { } ; this . attrsToUpdate = new Set < string > ( ) ; super . initialize ( attributes , options ) ; this . widget_manager = options . widget_manager ; this . model_id = options . model_id ; const comm = options . comm ; this . views = Object . create ( null ) ; this . state_change = Promise . resolve ( ) ; this . _closed = false ; this . _state_lock = null ; this . _msg_buffer = null ; this . _msg_buffer_callbacks = null ; this . _pending_msgs = 0 ; this . _buffered_state_diff = { } ; if ( comm ) { this . comm = comm ; comm . on_close ( this . _handle_comm_closed . bind ( this ) ) ; comm . on_msg ( this . _handle_comm_msg . bind ( this ) ) ; this . comm_live = true ; } else { this . comm_live = false ; } } get comm_live ( ) : boolean { return this . _comm_live ; } set comm_live ( x ) { this . _comm_live = x ; this . trigger ( 'comm_live_update' ) ; } /**
     * Send a custom msg over the comm.
     */ send ( content , callbacks , buffers ? ) { if ( this . comm !== undefined ) { const data = { method : 'custom' , content : content } ; this . comm . send ( data , callbacks , { } , buffers ) ; } } param comm_closed returns close ( comm_closed = false ) { if ( this . _closed ) { return Promise . resolve ( ) ; } this . _closed = true ; if ( this . comm && ! comm_closed ) { this . comm . close ( ) ; } this . stopListening ( ) ; this . trigger ( 'destroy' , this ) ; if ( this . comm ) { delete this . comm ; } if ( this . views ) { const views = Object . keys ( this . views ) . map ( ( id ) => { return this . views ! [ id ] . then ( ( view ) => view . remove ( ) ) ; } ) ; delete this . views ; return Promise . all ( views ) . then ( ( ) => { return ; } ) ; } return Promise . resolve ( ) ; } /**
     * Handle when a widget comm is closed.
     */ _handle_comm_closed ( msg ) { this . trigger ( 'comm:close' ) ; this . close ( true ) ; } /**
     * Handle incoming comm msg.
     */ _handle_comm_msg ( msg ) { const data = msg . content . data as any ; const method = data . method ; switch ( method ) { case 'update' : this . state_change = this . state_change . then ( ( ) => { const state = data . state ; const buffer_paths = data . buffer_paths || [ ] ; const buffers = msg . buffers || [ ] ; utils . put_buffers ( state , buffer_paths , buffers ) ; if ( msg . parent_header && data . echo ) { const msgId = ( msg . parent_header as any ) . msg_id ; const expectedEcho = data . echo . filter ( ( attrName ) => Object . keys ( this . expectedEchoMsgIds ) . includes ( attrName ) ) ; expectedEcho . forEach ( ( attrName ) => { const isOldMessage = this . expectedEchoMsgIds [ attrName ] !== msgId ; if ( isOldMessage ) { delete state [ attrName ] ; } else { delete this . expectedEchoMsgIds [ attrName ] ; if ( this . _msg_buffer !== null && Object . prototype . hasOwnProperty . call ( this . _msg_buffer , attrName ) ) { delete state [ attrName ] ; } } } ) ; } return ( this . constructor as typeof WidgetModel ) . _deserialize_state ( state , this . widget_manager ) ; } ) . then ( ( state ) => { this . set_state ( state ) ; } ) . catch ( utils . reject ( `Could not process update msg for model id: ${ this . model_id }` , true ) ) ; return this . state_change ; case 'custom' : this . trigger ( 'msg:custom' , data . content , msg . buffers ) ; return Promise . resolve ( ) ; } return Promise . resolve ( ) ; } /**
     * Handle when a widget is updated from the backend.
     *
     * This function is meant for internal use only. Values set here will not be propagated on a sync.
     */ set_state ( state ) { this . _state_lock = state ; try { this . set ( state ) ; } catch ( e ) { console . error ( `Error setting state: ${ e . message }` ) ; } finally { this . _state_lock = null ; } } /**
     * Get the serializable state of the model.
     *
     * If drop_default is truthy, attributes that are equal to their default
     * values are dropped.
     */ get_state ( drop_defaults ? ) { const fullState = this . attributes ; if ( drop_defaults ) { const d = this . defaults ; const defaults = typeof d === 'function' ? d . call ( this ) : d ; const state = { } ; Object . keys ( fullState ) . forEach ( ( key ) => { if ( ! utils . isEqual ( fullState [ key ] , defaults [ key ] ) ) { state [ key ] = fullState [ key ] ; } } ) ; return state ; } else { return { ... fullState } ; } } /**
     * Handle status msgs.
     *
     * execution_state : ('busy', 'idle', 'starting')
     */ _handle_status ( msg ) { if ( this . comm !== void 0 ) { if ( msg . content . execution_state === 'idle' ) { this . _pending_msgs -- ; if ( this . _msg_buffer !== null && this . _pending_msgs < 1 ) { const msgId = this . send_sync_message ( this . _msg_buffer , this . _msg_buffer_callbacks ) ; this . rememberLastUpdateFor ( msgId ) ; this . _msg_buffer = null ; this . _msg_buffer_callbacks = null ; } } } } /**
     * Create msg callbacks for a comm msg.
     */ callbacks ( view ? ) { return this . widget_manager . callbacks ( view ) ; } /**
     * Set one or more values.
     *
     * We just call the super method, in which val and options are optional.
     * Handles both "key", value and {key: value} -style arguments.
     */ set ( key , val ? , options ? ) { const return_value = backbonePatch . set . call ( this , key , val , options ) ; if ( this . _buffered_state_diff !== void 0 ) { const attrs = this . changedAttributes ( ) || { } ; if ( this . _state_lock ) { for ( const key of Object . keys ( this . _state_lock ) ) { if ( attrs [ key ] === this . _state_lock [ key ] ) { delete attrs [ key ] ; } } } if ( this . _buffered_state_diff_synced ) { for ( const key of Object . keys ( this . _buffered_state_diff_synced ) ) { if ( attrs [ key ] === this . _buffered_state_diff_synced [ key ] ) { delete attrs [ key ] ; } } } this . _buffered_state_diff = utils . assign ( this . _buffered_state_diff , attrs ) ; } if ( ( this as any ) . _changing === false ) { this . _buffered_state_diff_synced = { } ; } return return_value ; } /**
     * Handle sync to the back-end.  Called when a model.save() is called.
     *
     * Make sure a comm exists.
     *
     * Parameters
     * ----------
     * method : create, update, patch, delete, read
     *   create/update always send the full attribute set
     *   patch - only send attributes listed in options.attrs, and if we
     *   are queuing up messages, combine with previous messages that have
     *   not been sent yet
     * model : the model we are syncing
     *   will normally be the same as `this`
     * options : dict
     *   the `attrs` key, if it exists, gives an {attr: value} dict that
     *   should be synced, otherwise, sync all attributes.
     *
     */ sync ( method , model , options = { } ) { if ( this . comm === undefined ) { throw 'Syncing error: no comm channel defined' ; } const attrs = method === 'patch' ? options . attrs : model . get_state ( options . drop_defaults ) ; if ( this . _state_lock ) { for ( const key of Object . keys ( this . _state_lock ) ) { if ( attrs [ key ] === this . _state_lock [ key ] ) { delete attrs [ key ] ; } } } Object . keys ( attrs ) . forEach ( ( attrName ) => { this . attrsToUpdate . add ( attrName ) ; } ) ; const msgState = this . serialize ( attrs ) ; if ( Object . keys ( msgState ) . length > 0 ) { const callbacks = options . callbacks || this . callbacks ( ) ; if ( this . _pending_msgs >= 1 ) { switch ( method ) { case 'patch' : this . _msg_buffer = utils . assign ( this . _msg_buffer || { } , msgState ) ; break ; case 'update' : case 'create' : this . _msg_buffer = msgState ; break ; default : throw 'unrecognized syncing method' ; } this . _msg_buffer_callbacks = callbacks ; } else { const msgId = this . send_sync_message ( attrs , callbacks ) ; this . rememberLastUpdateFor ( msgId ) ; } } } rememberLastUpdateFor ( msgId ) { [ ... this . attrsToUpdate ] . forEach ( ( attrName ) => { this . expectedEchoMsgIds [ attrName ] = msgId ; } ) ; this . attrsToUpdate = new Set < string > ( ) ; } /**
     * Serialize widget state.
     *
     * A serializer is a function which takes in a state attribute and a widget,
     * and synchronously returns a JSONable object. The returned object will
     * have toJSON called if possible, and the final result should be a
     * primitive object that is a snapshot of the widget state that may have
     * binary array buffers.
     */ serialize ( state ) { const serializers = ( this . constructor as typeof WidgetModel ) . serializers || { } ; for ( const k of Object . keys ( state ) ) { try { if ( serializers [ k ] && serializers [ k ] . serialize ) { state [ k ] = serializers [ k ] . serialize ! ( state [ k ] , this ) ; } else { state [ k ] = JSON . parse ( JSON . stringify ( state [ k ] ) ) ; } if ( state [ k ] && state [ k ] . toJSON ) { state [ k ] = state [ k ] . toJSON ( ) ; } } catch ( e ) { console . error ( 'Error serializing widget state attribute: ' , k ) ; throw e ; } } return state ; } /**
     * Send a sync message to the kernel.
     */ send_sync_message ( state , callbacks = { } ) { if ( ! this . comm ) { return '' ; } try { callbacks . iopub = callbacks . iopub || { } ; const statuscb = callbacks . iopub . status ; callbacks . iopub . status = ( msg ) : void => { this . _handle_status ( msg ) ; if ( statuscb ) { statuscb ( msg ) ; } } ; const split = utils . remove_buffers ( state ) ; const msgId = this . comm . send ( { method : 'update' , state : split . state , buffer_paths : split . buffer_paths , } , callbacks , { } , split . buffers ) ; this . _pending_msgs ++ ; return msgId ; } catch ( e ) { console . error ( 'Could not send widget sync message' , e ) ; } return '' ; } /**
     * Push this model's state to the back-end
     *
     * This invokes a Backbone.Sync.
     */ save_changes ( callbacks ? ) { if ( this . comm_live ) { const options = { patch : true } ; if ( callbacks ) { options . callbacks = callbacks ; } this . save ( this . _buffered_state_diff , options ) ; if ( ( this as any ) . _changing ) { utils . assign ( this . _buffered_state_diff_synced , this . _buffered_state_diff ) ; } this . _buffered_state_diff = { } ; } } /**
     * on_some_change(['key1', 'key2'], foo, context) differs from
     * on('change:key1 change:key2', foo, context).
     * If the widget attributes key1 and key2 are both modified,
     * the second form will result in foo being called twice
     * while the first will call foo only once.
     */ on_some_change ( keys , callback , context ) { this . on ( 'change' , ( ... args ) => { if ( keys . some ( this . hasChanged , this ) ) { callback . apply ( context , args ) ; } } , this ) ; } /**
     * Serialize the model.  See the deserialization function at the top of this file
     * and the kernel-side serializer/deserializer.
     */ toJSON ( options ? ) { return `IPY_MODEL_${ this . model_id }` ; } /**
     * Returns a promise for the deserialized state. The second argument
     * is an instance of widget manager, which is required for the
     * deserialization of widget models.
     */ static _deserialize_state ( state , manager ) { const serializers = this . serializers ; let deserialized ; if ( serializers ) { deserialized = { } ; for ( const k in state ) { if ( serializers [ k ] && serializers [ k ] . deserialize ) { deserialized [ k ] = serializers [ k ] . deserialize ! ( state [ k ] , manager ) ; } else { deserialized [ k ] = state [ k ] ; } } } else { deserialized = state ; } return utils . resolvePromisesDict ( deserialized ) ; } static serializers : ISerializers ; widget_manager : IWidgetManager ; model_id : string ; views ? : { [ key ] : Promise < WidgetView > ; } ; state_change : Promise < any > ; comm ? : IClassicComm ; name : string ; module : string ; private _comm_live : boolean ; private _closed : boolean ; private _state_lock : any ; private _buffered_state_diff : any ; private _buffered_state_diff_synced : any ; private _msg_buffer : any ; private _msg_buffer_callbacks : any ; private _pending_msgs : number ; private expectedEchoMsgIds : any ; private attrsToUpdate : Set < string > ; } export class DOMWidgetModel extends WidgetModel { static serializers : ISerializers = { ... WidgetModel . serializers , layout : { deserialize : unpack_models } , style : { deserialize : unpack_models } , } ; defaults ( ) { return utils . assign ( super . defaults ( ) , { _dom_classes : [ ] , tabbable : null , tooltip : null , } ) ; } } export class WidgetView extends NativeView < WidgetModel > { /**
     * Public constructor.
     */ constructor ( options ? ) { super ( options ) ; } /**
     * Initializer, called at the end of the constructor.
     */ initialize ( parameters ) { this . listenTo ( this . model , 'change' , ( ) => { const changed = Object . keys ( this . model . changedAttributes ( ) || { } ) ; if ( changed [ 0 ] === '_view_count' && changed . length === 1 ) { return ; } this . update ( ) ; } ) ; this . options = parameters . options ; this . once ( 'remove' , ( ) => { if ( typeof this . model . get ( '_view_count' ) === 'number' ) { this . model . set ( '_view_count' , this . model . get ( '_view_count' ) - 1 ) ; this . model . save_changes ( ) ; } } ) ; this . once ( 'displayed' , ( ) => { if ( typeof this . model . get ( '_view_count' ) === 'number' ) { this . model . set ( '_view_count' , this . model . get ( '_view_count' ) + 1 ) ; this . model . save_changes ( ) ; } } ) ; this . displayed = new Promise ( ( resolve , reject ) => { this . once ( 'displayed' , resolve ) ; this . model . on ( 'msg:custom' , this . handle_message . bind ( this ) ) ; } ) ; } /**
     * Handle message sent to the front end.
     *
     * Used to focus or blur the widget.
     */ handle_message ( content ) { if ( content . do === 'focus' ) { this . el . focus ( ) ; } else if ( content . do === 'blur' ) { this . el . blur ( ) ; } } /**
     * Triggered on model change.
     *
     * Update view to be consistent with this.model
     */ update ( options ? ) { return ; } returns render ( ) { return ; } /**
     * Create and promise that resolves to a child view of a given model
     */ create_child_view < VT extends DOMWidgetView = DOMWidgetView > ( child_model , options ? ) ; create_child_view < VT extends WidgetView = WidgetView > ( child_model , options ? ) ; create_child_view < VT extends WidgetView = WidgetView > ( child_model , options = { } ) { options = { parent : this , ... options } ; return this . model . widget_manager . create_view < VT > ( child_model , options ) . catch ( utils . reject ( 'Could not create child view' , true ) ) ; } /**
     * Create msg callbacks for a comm msg.
     */ callbacks ( ) { return this . model . callbacks ( this ) ; } /**
     * Send a custom msg associated with this view.
     */ send ( content , buffers ? ) { this . model . send ( content , this . callbacks ( ) , buffers ) ; } touch ( ) { this . model . save_changes ( this . callbacks ( ) ) ; } remove ( ) { super . remove ( ) ; this . trigger ( 'remove' ) ; return this ; } options : any ; /**
     * A promise that resolves to the parent view when a child view is displayed.
     */ displayed : Promise < WidgetView > ; } export namespace WidgetView { export interface IInitializeParameters < T extends WidgetModel = WidgetModel > extends Backbone . ViewOptions < T > { options : any ; } } export namespace JupyterLuminoWidget { export interface IOptions { view : DOMWidgetView ; } } export class JupyterLuminoWidget extends Widget { constructor ( options ) { const view = options . view ; delete ( options as any ) . view ; super ( options ) ; this . _view = view ; } /**
     * Dispose the widget.
     *
     * This causes the view to be destroyed as well with 'remove'
     */ dispose ( ) { if ( this . isDisposed ) { return ; } super . dispose ( ) ; this . _view . remove ( ) ; this . _view = null ! ; } /**
     * Process the Lumino message.
     *
     * Any custom Lumino widget used inside a Jupyter widget should override
     * the processMessage function like this.
     */ processMessage ( msg ) { super . processMessage ( msg ) ; this . _view . processLuminoMessage ( msg ) ; } private _view : DOMWidgetView ; } export class JupyterLuminoPanelWidget extends Panel { constructor ( options ) { const view = options . view ; delete ( options as any ) . view ; super ( options ) ; this . _view = view ; } /**
     * Process the Lumino message.
     *
     * Any custom Lumino widget used inside a Jupyter widget should override
     * the processMessage function like this.
     */ processMessage ( msg ) { super . processMessage ( msg ) ; this . _view . processLuminoMessage ( msg ) ; } /**
     * Dispose the widget.
     *
     * This causes the view to be destroyed as well with 'remove'
     */ dispose ( ) { if ( this . isDisposed ) { return ; } super . dispose ( ) ; this . _view . remove ( ) ; this . _view = null ! ; } private _view : DOMWidgetView ; } export class DOMWidgetView extends WidgetView { /**
     * Public constructor
     */ initialize ( parameters ) { super . initialize ( parameters ) ; this . listenTo ( this . model , 'change:_dom_classes' , ( model , new_classes ) => { const old_classes = model . previous ( '_dom_classes' ) ; this . update_classes ( old_classes , new_classes ) ; } ) ; this . layoutPromise = Promise . resolve ( ) ; this . listenTo ( this . model , 'change:layout' , ( model , value ) => { this . setLayout ( value , model . previous ( 'layout' ) ) ; } ) ; this . stylePromise = Promise . resolve ( ) ; this . listenTo ( this . model , 'change:style' , ( model , value ) => { this . setStyle ( value , model . previous ( 'style' ) ) ; } ) ; this . displayed . then ( ( ) => { this . update_classes ( [ ] , this . model . get ( '_dom_classes' ) ) ; this . setLayout ( this . model . get ( 'layout' ) ) ; this . setStyle ( this . model . get ( 'style' ) ) ; } ) ; this . _comm_live_update ( ) ; this . listenTo ( this . model , 'comm_live_update' , ( ) => { this . _comm_live_update ( ) ; } ) ; this . listenTo ( this . model , 'change:tooltip' , this . updateTooltip ) ; this . updateTooltip ( ) ; } setLayout ( layout , oldLayout ? ) { if ( layout ) { this . layoutPromise = this . layoutPromise . then ( ( oldLayoutView ) => { if ( oldLayoutView ) { oldLayoutView . unlayout ( ) ; this . stopListening ( oldLayoutView . model ) ; oldLayoutView . remove ( ) ; } return this . create_child_view ( layout ) . then ( ( view ) => { return this . displayed . then ( ( ) => { view . trigger ( 'displayed' ) ; this . listenTo ( view . model , 'change' , ( ) => { MessageLoop . postMessage ( this . luminoWidget , Widget . ResizeMessage . UnknownSize ) ; } ) ; MessageLoop . postMessage ( this . luminoWidget , Widget . ResizeMessage . UnknownSize ) ; this . trigger ( 'layout-changed' ) ; return view ; } ) ; } ) . catch ( utils . reject ( 'Could not add LayoutView to DOMWidgetView' , true ) ) ; } ) ; } } setStyle ( style , oldStyle ? ) { if ( style ) { this . stylePromise = this . stylePromise . then ( ( oldStyleView ) => { if ( oldStyleView ) { oldStyleView . unstyle ( ) ; this . stopListening ( oldStyleView . model ) ; oldStyleView . remove ( ) ; } return this . create_child_view ( style ) . then ( ( view ) => { return this . displayed . then ( ( ) => { view . trigger ( 'displayed' ) ; this . trigger ( 'style-changed' ) ; return view ; } ) ; } ) . catch ( utils . reject ( 'Could not add styleView to DOMWidgetView' , true ) ) ; } ) ; } } updateTooltip ( ) { const title = this . model . get ( 'tooltip' ) ; if ( ! title ) { this . el . removeAttribute ( 'title' ) ; } else if ( this . model . get ( 'description' ) . length === 0 ) { this . el . setAttribute ( 'title' , title ) ; } } /**
     * Update the DOM classes applied to an element, default to this.el.
     */ update_classes ( old_classes , new_classes , el ? ) { if ( el === undefined ) { el = this . el ; } utils . difference ( old_classes , new_classes ) . map ( function ( c ) { if ( el ! . classList ) { el ! . classList . remove ( c ) ; } else { el ! . setAttribute ( 'class' , el ! . getAttribute ( 'class' ) ! . replace ( c , '' ) ) ; } } ) ; utils . difference ( new_classes , old_classes ) . map ( function ( c ) { if ( el ! . classList ) { el ! . classList . add ( c ) ; } else { el ! . setAttribute ( 'class' , el ! . getAttribute ( 'class' ) ! . concat ( ' ' , c ) ) ; } } ) ; } /**
     * Update the DOM classes applied to the widget based on a single
     * trait's value.
     *
     * Given a trait value classes map, this function automatically
     * handles applying the appropriate classes to the widget element
     * and removing classes that are no longer valid.
     *
     * Parameters
     * ----------
     * class_map: dictionary
     *  Dictionary of trait values to class lists.
     *  Example:
     *      {
     *          success: ['alert', 'alert-success'],
     *          info: ['alert', 'alert-info'],
     *          warning: ['alert', 'alert-warning'],
     *          danger: ['alert', 'alert-danger']
     *      };
     * trait_name: string
     *  Name of the trait to check the value of.
     * el: optional DOM element handle, defaults to this.el
     *  Element that the classes are applied to.
     */ update_mapped_classes ( class_map , trait_name , el ? ) { let key = this . model . previous ( trait_name ) as string ; const old_classes = class_map [ key ] ? class_map [ key ] : [ ] ; key = this . model . get ( trait_name ) ; const new_classes = class_map [ key ] ? class_map [ key ] : [ ] ; this . update_classes ( old_classes , new_classes , el || this . el ) ; } set_mapped_classes ( class_map , trait_name , el ? ) { const key = this . model . get ( trait_name ) ; const new_classes = class_map [ key ] ? class_map [ key ] : [ ] ; this . update_classes ( [ ] , new_classes , el || this . el ) ; } _setElement ( el ) { if ( this . luminoWidget ) { this . luminoWidget . dispose ( ) ; } this . $el = el instanceof $ ? el : $ ( el ) ; this . el = this . $el [ 0 ] ; this . luminoWidget = new JupyterLuminoWidget ( { node : el , view : this , } ) ; } remove ( ) { if ( this . luminoWidget ) { this . luminoWidget . dispose ( ) ; } return super . remove ( ) ; } processLuminoMessage ( msg ) { switch ( msg . type ) { case 'after-attach' : this . trigger ( 'displayed' ) ; break ; case 'show' : this . trigger ( 'shown' ) ; break ; } } private _comm_live_update ( ) { if ( this . model . comm_live ) { this . luminoWidget . removeClass ( 'jupyter-widgets-disconnected' ) ; } else { this . luminoWidget . addClass ( 'jupyter-widgets-disconnected' ) ; } } updateTabindex ( ) { const tabbable = this . model . get ( 'tabbable' ) ; if ( tabbable === true ) { this . el . setAttribute ( 'tabIndex' , '0' ) ; } else if ( tabbable === false ) { this . el . setAttribute ( 'tabIndex' , '-1' ) ; } else if ( tabbable === null ) { this . el . removeAttribute ( 'tabIndex' ) ; } } el : HTMLElement ; '$el' : any ; luminoWidget : Widget ; layoutPromise : Promise < any > ; stylePromise : Promise < any > ; }