@ -7,7 +7,8 @@ define([
"jquery" ,
"base/js/utils" ,
"base/js/namespace" ,
] , function ( _ , Backbone , $ , utils , IPython ) {
"services/kernels/comm"
] , function ( _ , Backbone , $ , utils , IPython , comm ) {
"use strict" ;
//--------------------------------------------------------------------
// WidgetManager class
@ -22,10 +23,11 @@ define([
this . keyboard _manager = notebook . keyboard _manager ;
this . notebook = notebook ;
this . comm _manager = comm _manager ;
this . comm _target _name = 'ipython.widget' ;
this . _models = { } ; /* Dictionary of model ids and model instances */
// Register with the comm manager.
this . comm _manager . register _target ( 'ipython.widget' , $ . proxy ( this . _handle _comm _open , this ) ) ;
this . comm _manager . register _target ( this . comm _target _name , $ . proxy ( this . _handle _comm _open , this ) ) ;
} ;
//--------------------------------------------------------------------
@ -53,21 +55,34 @@ define([
* Displays a view for a particular model .
* /
var that = this ;
var cell = this . get _msg _cell ( msg . parent _header . msg _id ) ;
if ( cell === null ) {
return Promise . reject ( new Error ( "Could not determine where the display" +
" message was from. Widget will not be displayed" ) ) ;
} else if ( cell . widget _subarea ) {
var dummy = $ ( '<div />' ) ;
cell . widget _subarea . append ( dummy ) ;
return this . create _view ( model , { cell : cell } ) . then (
function ( view ) {
return new Promise ( function ( resolve , reject ) {
var cell = that . get _msg _cell ( msg . parent _header . msg _id ) ;
if ( cell === null ) {
reject ( new Error ( "Could not determine where the display" +
" message was from. Widget will not be displayed" ) ) ;
} else {
return that . display _view _in _cell ( cell , model ) ;
}
} ) ;
} ;
WidgetManager . prototype . display _view _in _cell = function ( cell , model ) {
// Displays a view in a cell.
return new Promise ( function ( resolve , reject ) {
if ( cell . display _widget _view ) {
cell . display _widget _view ( that . create _view ( model , { cell : cell } ) )
. then ( function ( view ) {
that . _handle _display _view ( view ) ;
dummy . replaceWith ( view . $el ) ;
view . trigger ( 'displayed' ) ;
return view ;
} ) . catch ( utils . reject ( 'Could not display view' , true ) ) ;
}
resolve ( view ) ;
} , function ( error ) {
reject ( new utils . WrappedError ( 'Could not display view' , error ) ) ;
} ) ;
} else {
reject ( new Error ( 'Cell does not have a `display_widget_view` method.' ) ) ;
}
} ) ;
} ;
WidgetManager . prototype . _handle _display _view = function ( view ) {
@ -238,6 +253,8 @@ define([
widget _model . once ( 'comm:close' , function ( ) {
delete that . _models [ model _id ] ;
} ) ;
widget _model . name = options . model _name ;
widget _model . module = options . model _module ;
return widget _model ;
} , function ( error ) {
@ -249,6 +266,100 @@ define([
return model _promise ;
} ;
WidgetManager . prototype . get _state = function ( options ) {
// Get the state of the widget manager.
//
// This includes all of the widget models and the cells that they are
// displayed in.
//
// Parameters
// ----------
// options: dictionary
// Dictionary of options with the following contents:
// only_displayed: (optional) boolean=false
// Only return models with one or more displayed views.
// not_alive: (optional) boolean=false
// Include models that have comms with severed connections.
return utils . resolve _promise _dict ( function ( models ) {
var state = { } ;
for ( var model _id in models ) {
if ( models . hasOwnProperty ( model _id ) ) {
var model = models [ model _id ] ;
// If the model has one or more views defined for it,
// consider it displayed.
var displayed _flag = ! ( options && options . only _displayed ) || Object . keys ( model . views ) . length > 0 ;
var alive _flag = ( options && options . not _alive ) || model . comm _alive ;
if ( displayed _flag && alive _flag ) {
state [ model . model _id ] = {
model _name : model . name ,
model _module : model . module ,
views : [ ] ,
} ;
// Get the views that are displayed *now*.
for ( var id in model . views ) {
if ( model . views . hasOwnProperty ( id ) ) {
var view = model . views [ id ] ;
var cell _index = this . notebook . find _cell _index ( view . options . cell ) ;
state [ model . model _id ] . views . push ( cell _index ) ;
}
}
}
}
}
return state ;
} ) ;
} ;
WidgetManager . prototype . set _state = function ( state ) {
// Set the notebook's state.
//
// Reconstructs all of the widget models and attempts to redisplay the
// widgets in the appropriate cells by cell index.
// Get the kernel when it's available.
var that = this ;
return ( new Promise ( function ( resolve , reject ) {
if ( that . kernel ) {
resolve ( that . kernel ) ;
} else {
that . events . on ( 'kernel_created.Session' , function ( event , data ) {
resolve ( data . kernel ) ;
} ) ;
}
} ) ) . then ( function ( kernel ) {
// Recreate all the widget models for the given state.
that . widget _models = [ ] ;
for ( var i = 0 ; i < state . length ; i ++ ) {
// Recreate a comm using the widget's model id (model_id == comm_id).
var new _comm = new comm . Comm ( kernel . widget _manager . comm _target _name , state [ i ] . model _id ) ;
kernel . comm _manager . register _comm ( new _comm ) ;
// Create the model using the recreated comm. When the model is
// created we don't know yet if the comm is valid so set_comm_alive
// false. Once we receive the first state push from the back-end
// we know the comm is alive.
var model = kernel . widget _manager . create _model ( {
comm : new _comm ,
model _name : state [ i ] . model _name ,
model _module : state [ i ] . model _module } ) . then ( function ( model ) {
model . set _comm _alive ( false ) ;
model . request _state ( ) ;
model . received _state . then ( function ( ) {
model . set _comm _alive ( true ) ;
} ) ;
return model ;
} ) ;
that . widget _models . push ( model ) ;
}
return Promise . all ( that . widget _models ) ;
} ) ;
} ;
// Backwards compatibility.
IPython . WidgetManager = WidgetManager ;