|
|
|
|
@ -11,16 +11,18 @@ define(["widgets/js/manager",
|
|
|
|
|
|
|
|
|
|
var WidgetModel = Backbone.Model.extend({
|
|
|
|
|
constructor: function (widget_manager, model_id, comm) {
|
|
|
|
|
// Constructor
|
|
|
|
|
//
|
|
|
|
|
// Creates a WidgetModel instance.
|
|
|
|
|
//
|
|
|
|
|
// Parameters
|
|
|
|
|
// ----------
|
|
|
|
|
// widget_manager : WidgetManager instance
|
|
|
|
|
// model_id : string
|
|
|
|
|
// An ID unique to this model.
|
|
|
|
|
// comm : Comm instance (optional)
|
|
|
|
|
/**
|
|
|
|
|
* Constructor
|
|
|
|
|
*
|
|
|
|
|
* Creates a WidgetModel instance.
|
|
|
|
|
*
|
|
|
|
|
* Parameters
|
|
|
|
|
* ----------
|
|
|
|
|
* widget_manager : WidgetManager instance
|
|
|
|
|
* model_id : string
|
|
|
|
|
* An ID unique to this model.
|
|
|
|
|
* comm : Comm instance (optional)
|
|
|
|
|
*/
|
|
|
|
|
this.widget_manager = widget_manager;
|
|
|
|
|
this.state_change = Promise.resolve();
|
|
|
|
|
this._buffered_state_diff = {};
|
|
|
|
|
@ -43,7 +45,9 @@ define(["widgets/js/manager",
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
send: function (content, callbacks) {
|
|
|
|
|
// Send a custom msg over the comm.
|
|
|
|
|
/**
|
|
|
|
|
* Send a custom msg over the comm.
|
|
|
|
|
*/
|
|
|
|
|
if (this.comm !== undefined) {
|
|
|
|
|
var data = {method: 'custom', content: content};
|
|
|
|
|
this.comm.send(data, callbacks);
|
|
|
|
|
@ -52,7 +56,9 @@ define(["widgets/js/manager",
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
_handle_comm_closed: function (msg) {
|
|
|
|
|
// Handle when a widget is closed.
|
|
|
|
|
/**
|
|
|
|
|
* Handle when a widget is closed.
|
|
|
|
|
*/
|
|
|
|
|
this.trigger('comm:close');
|
|
|
|
|
this.stopListening();
|
|
|
|
|
this.trigger('destroy', this);
|
|
|
|
|
@ -67,7 +73,9 @@ define(["widgets/js/manager",
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
_handle_comm_msg: function (msg) {
|
|
|
|
|
// Handle incoming comm msg.
|
|
|
|
|
/**
|
|
|
|
|
* Handle incoming comm msg.
|
|
|
|
|
*/
|
|
|
|
|
var method = msg.content.data.method;
|
|
|
|
|
var that = this;
|
|
|
|
|
switch (method) {
|
|
|
|
|
@ -99,9 +107,11 @@ define(["widgets/js/manager",
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
_handle_status: function (msg, callbacks) {
|
|
|
|
|
// Handle status msgs.
|
|
|
|
|
|
|
|
|
|
// execution_state : ('busy', 'idle', 'starting')
|
|
|
|
|
/**
|
|
|
|
|
* Handle status msgs.
|
|
|
|
|
*
|
|
|
|
|
* execution_state : ('busy', 'idle', 'starting')
|
|
|
|
|
*/
|
|
|
|
|
if (this.comm !== undefined) {
|
|
|
|
|
if (msg.content.execution_state ==='idle') {
|
|
|
|
|
// Send buffer if this message caused another message to be
|
|
|
|
|
@ -119,7 +129,9 @@ define(["widgets/js/manager",
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
callbacks: function(view) {
|
|
|
|
|
// Create msg callbacks for a comm msg.
|
|
|
|
|
/**
|
|
|
|
|
* Create msg callbacks for a comm msg.
|
|
|
|
|
*/
|
|
|
|
|
var callbacks = this.widget_manager.callbacks(view);
|
|
|
|
|
|
|
|
|
|
if (callbacks.iopub === undefined) {
|
|
|
|
|
@ -134,7 +146,9 @@ define(["widgets/js/manager",
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
set: function(key, val, options) {
|
|
|
|
|
// Set a value.
|
|
|
|
|
/**
|
|
|
|
|
* Set a value.
|
|
|
|
|
*/
|
|
|
|
|
var return_value = WidgetModel.__super__.set.apply(this, arguments);
|
|
|
|
|
|
|
|
|
|
// Backbone only remembers the diff of the most recent set()
|
|
|
|
|
@ -145,9 +159,11 @@ define(["widgets/js/manager",
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
sync: function (method, model, options) {
|
|
|
|
|
// Handle sync to the back-end. Called when a model.save() is called.
|
|
|
|
|
|
|
|
|
|
// Make sure a comm exists.
|
|
|
|
|
/**
|
|
|
|
|
* Handle sync to the back-end. Called when a model.save() is called.
|
|
|
|
|
*
|
|
|
|
|
* Make sure a comm exists.
|
|
|
|
|
*/
|
|
|
|
|
var error = options.error || function() {
|
|
|
|
|
console.error('Backbone sync error:', arguments);
|
|
|
|
|
};
|
|
|
|
|
@ -213,14 +229,18 @@ define(["widgets/js/manager",
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
save_changes: function(callbacks) {
|
|
|
|
|
// Push this model's state to the back-end
|
|
|
|
|
//
|
|
|
|
|
// This invokes a Backbone.Sync.
|
|
|
|
|
/**
|
|
|
|
|
* Push this model's state to the back-end
|
|
|
|
|
*
|
|
|
|
|
* This invokes a Backbone.Sync.
|
|
|
|
|
*/
|
|
|
|
|
this.save(this._buffered_state_diff, {patch: true, callbacks: callbacks});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
_pack_models: function(value) {
|
|
|
|
|
// Replace models with model ids recursively.
|
|
|
|
|
/**
|
|
|
|
|
* Replace models with model ids recursively.
|
|
|
|
|
*/
|
|
|
|
|
var that = this;
|
|
|
|
|
var packed;
|
|
|
|
|
if (value instanceof Backbone.Model) {
|
|
|
|
|
@ -247,7 +267,9 @@ define(["widgets/js/manager",
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
_unpack_models: function(value) {
|
|
|
|
|
// Replace model ids with models recursively.
|
|
|
|
|
/**
|
|
|
|
|
* Replace model ids with models recursively.
|
|
|
|
|
*/
|
|
|
|
|
var that = this;
|
|
|
|
|
var unpacked;
|
|
|
|
|
if ($.isArray(value)) {
|
|
|
|
|
@ -271,11 +293,13 @@ define(["widgets/js/manager",
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
on_some_change: function(keys, callback, context) {
|
|
|
|
|
// 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(["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.
|
|
|
|
|
*/
|
|
|
|
|
this.on('change', function() {
|
|
|
|
|
if (keys.some(this.hasChanged, this)) {
|
|
|
|
|
callback.apply(context);
|
|
|
|
|
@ -289,7 +313,9 @@ define(["widgets/js/manager",
|
|
|
|
|
|
|
|
|
|
var WidgetView = Backbone.View.extend({
|
|
|
|
|
initialize: function(parameters) {
|
|
|
|
|
// Public constructor.
|
|
|
|
|
/**
|
|
|
|
|
* Public constructor.
|
|
|
|
|
*/
|
|
|
|
|
this.model.on('change',this.update,this);
|
|
|
|
|
this.options = parameters.options;
|
|
|
|
|
this.id = this.id || utils.uuid();
|
|
|
|
|
@ -300,31 +326,41 @@ define(["widgets/js/manager",
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
update: function(){
|
|
|
|
|
// Triggered on model change.
|
|
|
|
|
//
|
|
|
|
|
// Update view to be consistent with this.model
|
|
|
|
|
/**
|
|
|
|
|
* Triggered on model change.
|
|
|
|
|
*
|
|
|
|
|
* Update view to be consistent with this.model
|
|
|
|
|
*/
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
create_child_view: function(child_model, options) {
|
|
|
|
|
// Create and promise that resolves to a child view of a given model
|
|
|
|
|
/**
|
|
|
|
|
* Create and promise that resolves to a child view of a given model
|
|
|
|
|
*/
|
|
|
|
|
var that = this;
|
|
|
|
|
options = $.extend({ parent: this }, options || {});
|
|
|
|
|
return this.model.widget_manager.create_view(child_model, options).catch(utils.reject("Couldn't create child view"), true);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
callbacks: function(){
|
|
|
|
|
// Create msg callbacks for a comm msg.
|
|
|
|
|
/**
|
|
|
|
|
* Create msg callbacks for a comm msg.
|
|
|
|
|
*/
|
|
|
|
|
return this.model.callbacks(this);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
render: function(){
|
|
|
|
|
// Render the view.
|
|
|
|
|
//
|
|
|
|
|
// By default, this is only called the first time the view is created
|
|
|
|
|
/**
|
|
|
|
|
* Render the view.
|
|
|
|
|
*
|
|
|
|
|
* By default, this is only called the first time the view is created
|
|
|
|
|
*/
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
show: function(){
|
|
|
|
|
// Show the widget-area
|
|
|
|
|
/**
|
|
|
|
|
* Show the widget-area
|
|
|
|
|
*/
|
|
|
|
|
if (this.options && this.options.cell &&
|
|
|
|
|
this.options.cell.widget_area !== undefined) {
|
|
|
|
|
this.options.cell.widget_area.show();
|
|
|
|
|
@ -332,7 +368,9 @@ define(["widgets/js/manager",
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
send: function (content) {
|
|
|
|
|
// Send a custom msg associated with this view.
|
|
|
|
|
/**
|
|
|
|
|
* Send a custom msg associated with this view.
|
|
|
|
|
*/
|
|
|
|
|
this.model.send(content, this.callbacks());
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
@ -341,8 +379,10 @@ define(["widgets/js/manager",
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
after_displayed: function (callback, context) {
|
|
|
|
|
// Calls the callback right away is the view is already displayed
|
|
|
|
|
// otherwise, register the callback to the 'displayed' event.
|
|
|
|
|
/**
|
|
|
|
|
* Calls the callback right away is the view is already displayed
|
|
|
|
|
* otherwise, register the callback to the 'displayed' event.
|
|
|
|
|
*/
|
|
|
|
|
if (this.is_displayed) {
|
|
|
|
|
callback.apply(context);
|
|
|
|
|
} else {
|
|
|
|
|
@ -354,7 +394,9 @@ define(["widgets/js/manager",
|
|
|
|
|
|
|
|
|
|
var DOMWidgetView = WidgetView.extend({
|
|
|
|
|
initialize: function (parameters) {
|
|
|
|
|
// Public constructor
|
|
|
|
|
/**
|
|
|
|
|
* Public constructor
|
|
|
|
|
*/
|
|
|
|
|
DOMWidgetView.__super__.initialize.apply(this, [parameters]);
|
|
|
|
|
this.on('displayed', this.show, this);
|
|
|
|
|
this.model.on('change:visible', this.update_visible, this);
|
|
|
|
|
@ -431,7 +473,9 @@ define(["widgets/js/manager",
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
_default_px: function(value) {
|
|
|
|
|
// Makes browser interpret a numerical string as a pixel value.
|
|
|
|
|
/**
|
|
|
|
|
* Makes browser interpret a numerical string as a pixel value.
|
|
|
|
|
*/
|
|
|
|
|
if (/^\d+\.?(\d+)?$/.test(value.trim())) {
|
|
|
|
|
return value.trim() + 'px';
|
|
|
|
|
}
|
|
|
|
|
@ -439,17 +483,23 @@ define(["widgets/js/manager",
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
update_attr: function(name, value) {
|
|
|
|
|
// Set a css attr of the widget view.
|
|
|
|
|
/**
|
|
|
|
|
* Set a css attr of the widget view.
|
|
|
|
|
*/
|
|
|
|
|
this.$el.css(name, value);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
update_visible: function(model, value) {
|
|
|
|
|
// Update visibility
|
|
|
|
|
/**
|
|
|
|
|
* Update visibility
|
|
|
|
|
*/
|
|
|
|
|
this.$el.toggle(value);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
update_css: function (model, css) {
|
|
|
|
|
// Update the css styling of this view.
|
|
|
|
|
/**
|
|
|
|
|
* Update the css styling of this view.
|
|
|
|
|
*/
|
|
|
|
|
var e = this.$el;
|
|
|
|
|
if (css === undefined) {return;}
|
|
|
|
|
for (var i = 0; i < css.length; i++) {
|
|
|
|
|
@ -465,7 +515,9 @@ define(["widgets/js/manager",
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
update_classes: function (old_classes, new_classes, $el) {
|
|
|
|
|
// Update the DOM classes applied to an element, default to this.$el.
|
|
|
|
|
/**
|
|
|
|
|
* Update the DOM classes applied to an element, default to this.$el.
|
|
|
|
|
*/
|
|
|
|
|
if ($el===undefined) {
|
|
|
|
|
$el = this.$el;
|
|
|
|
|
}
|
|
|
|
|
@ -474,30 +526,32 @@ define(["widgets/js/manager",
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
update_mapped_classes: function(class_map, trait_name, previous_trait_value, $el) {
|
|
|
|
|
// 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.
|
|
|
|
|
// previous_trait_value: optional string, default ''
|
|
|
|
|
// Last trait value
|
|
|
|
|
// $el: optional jQuery element handle, defaults to this.$el
|
|
|
|
|
// Element that the classes are applied to.
|
|
|
|
|
/**
|
|
|
|
|
* 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.
|
|
|
|
|
* previous_trait_value: optional string, default ''
|
|
|
|
|
* Last trait value
|
|
|
|
|
* $el: optional jQuery element handle, defaults to this.$el
|
|
|
|
|
* Element that the classes are applied to.
|
|
|
|
|
*/
|
|
|
|
|
var key = previous_trait_value;
|
|
|
|
|
if (key === undefined) {
|
|
|
|
|
key = this.model.previous(trait_name);
|
|
|
|
|
@ -510,7 +564,9 @@ define(["widgets/js/manager",
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
_get_selector_element: function (selector) {
|
|
|
|
|
// Get the elements via the css selector.
|
|
|
|
|
/**
|
|
|
|
|
* Get the elements via the css selector.
|
|
|
|
|
*/
|
|
|
|
|
var elements;
|
|
|
|
|
if (!selector) {
|
|
|
|
|
elements = this.$el;
|
|
|
|
|
@ -523,16 +579,18 @@ define(["widgets/js/manager",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var ViewList = function(create_view, remove_view, context) {
|
|
|
|
|
// * create_view and remove_view are default functions called when adding or removing views
|
|
|
|
|
// * create_view takes a model and returns a view or a promise for a view for that model
|
|
|
|
|
// * remove_view takes a view and destroys it (including calling `view.remove()`)
|
|
|
|
|
// * each time the update() function is called with a new list, the create and remove
|
|
|
|
|
// callbacks will be called in an order so that if you append the views created in the
|
|
|
|
|
// create callback and remove the views in the remove callback, you will duplicate
|
|
|
|
|
// the order of the list.
|
|
|
|
|
// * the remove callback defaults to just removing the view (e.g., pass in null for the second parameter)
|
|
|
|
|
// * the context defaults to the created ViewList. If you pass another context, the create and remove
|
|
|
|
|
// will be called in that context.
|
|
|
|
|
/**
|
|
|
|
|
* * create_view and remove_view are default functions called when adding or removing views
|
|
|
|
|
* * create_view takes a model and returns a view or a promise for a view for that model
|
|
|
|
|
* * remove_view takes a view and destroys it (including calling `view.remove()`)
|
|
|
|
|
* * each time the update() function is called with a new list, the create and remove
|
|
|
|
|
* callbacks will be called in an order so that if you append the views created in the
|
|
|
|
|
* create callback and remove the views in the remove callback, you will duplicate
|
|
|
|
|
* the order of the list.
|
|
|
|
|
* * the remove callback defaults to just removing the view (e.g., pass in null for the second parameter)
|
|
|
|
|
* * the context defaults to the created ViewList. If you pass another context, the create and remove
|
|
|
|
|
* will be called in that context.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
this.initialize.apply(this, arguments);
|
|
|
|
|
};
|
|
|
|
|
@ -548,9 +606,11 @@ define(["widgets/js/manager",
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
update: function(new_models, create_view, remove_view, context) {
|
|
|
|
|
// the create_view, remove_view, and context arguments override the defaults
|
|
|
|
|
// specified when the list is created.
|
|
|
|
|
// returns a promise that resolves after this update is done
|
|
|
|
|
/**
|
|
|
|
|
* the create_view, remove_view, and context arguments override the defaults
|
|
|
|
|
* specified when the list is created.
|
|
|
|
|
* returns a promise that resolves after this update is done
|
|
|
|
|
*/
|
|
|
|
|
var remove = remove_view || this._remove_view;
|
|
|
|
|
var create = create_view || this._create_view;
|
|
|
|
|
if (create === undefined || remove === undefined){
|
|
|
|
|
@ -588,9 +648,11 @@ define(["widgets/js/manager",
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
remove: function() {
|
|
|
|
|
// removes every view in the list; convenience function for `.update([])`
|
|
|
|
|
// that should be faster
|
|
|
|
|
// returns a promise that resolves after this removal is done
|
|
|
|
|
/**
|
|
|
|
|
* removes every view in the list; convenience function for `.update([])`
|
|
|
|
|
* that should be faster
|
|
|
|
|
* returns a promise that resolves after this removal is done
|
|
|
|
|
*/
|
|
|
|
|
var that = this;
|
|
|
|
|
this.state_change = this.state_change.then(function() {
|
|
|
|
|
for (var i = 0; i < that.views.length; i++) {
|
|
|
|
|
|