##// END OF EJS Templates
Handle widget hide/show logic...
Jonathan Frederic -
Show More
@@ -1,241 +1,257
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2013 The IPython Development Team
2 // Copyright (C) 2013 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // WidgetModel, WidgetView, and WidgetManager
9 // WidgetModel, WidgetView, and WidgetManager
10 //============================================================================
10 //============================================================================
11 /**
11 /**
12 * Base Widget classes
12 * Base Widget classes
13 * @module IPython
13 * @module IPython
14 * @namespace IPython
14 * @namespace IPython
15 * @submodule widget
15 * @submodule widget
16 */
16 */
17
17
18
18
19 // require(['components/underscore/underscore-min.js',
19 // require(['components/underscore/underscore-min.js',
20 // 'components/backbone/backbone-min.js'],
20 // 'components/backbone/backbone-min.js'],
21
21
22 var IPython = (function (IPython) {
22 "use strict";
23 "use strict";
23
24 // Only run once on a notebook.
25 if (IPython.notebook.widget_manager == undefined) {
24
26
25 //-----------------------------------------------------------------------
27 //-----------------------------------------------------------------------
26 // WidgetModel class
28 // WidgetModel class
27 //-----------------------------------------------------------------------
29 //-----------------------------------------------------------------------
28 var WidgetModel = Backbone.Model.extend({
30 var WidgetModel = Backbone.Model.extend({
29 apply: function(sender) {
31 apply: function(sender) {
30 this.save();
32 this.save();
31
33
32 for (var index in this.views) {
34 for (var index in this.views) {
33 var view = this.views[index];
35 var view = this.views[index];
34 if (view !== sender) {
36 if (view !== sender) {
35 view.refresh();
37 view.refresh();
36 }
38 }
37 }
39 }
38 }
40 }
39 });
41 });
40
42
41
43
42 //-----------------------------------------------------------------------
44 //-----------------------------------------------------------------------
43 // WidgetView class
45 // WidgetView class
44 //-----------------------------------------------------------------------
46 //-----------------------------------------------------------------------
45 var WidgetView = Backbone.View.extend({
47 var WidgetView = Backbone.View.extend({
46
48
47 initialize: function() {
49 initialize: function() {
48 this.model.on('change',this.refresh,this);
50 this.model.on('change',this.refresh,this);
49 },
51 },
50
52
51 refresh: function() {
53 refresh: function() {
52 this.update();
54 this.update();
53
55
54 if (this.model.css != undefined) {
56 if (this.model.css != undefined) {
55 for (var selector in this.model.css) {
57 for (var selector in this.model.css) {
56 if (this.model.css.hasOwnProperty(selector)) {
58 if (this.model.css.hasOwnProperty(selector)) {
57
59
58 // Get the elements via the css selector. If the selector is
60 // Get the elements via the css selector. If the selector is
59 // blank, assume the current element is the target.
61 // blank, assume the current element is the target.
60 var elements = this.$el.find(selector);
62 var elements = this.$el.find(selector);
61 if (selector=='') {
63 if (selector=='') {
62 elements = this.$el;
64 elements = this.$el;
63 }
65 }
64
66
65 // Apply the css traits to all elements that match the selector.
67 // Apply the css traits to all elements that match the selector.
66 if (elements.length>0){
68 if (elements.length>0){
67 var css_traits = this.model.css[selector];
69 var css_traits = this.model.css[selector];
68 for (var css_key in css_traits) {
70 for (var css_key in css_traits) {
69 if (css_traits.hasOwnProperty(css_key)) {
71 if (css_traits.hasOwnProperty(css_key)) {
70 elements.css(css_key, css_traits[css_key]);
72 elements.css(css_key, css_traits[css_key]);
71 }
73 }
72 }
74 }
73 }
75 }
74 }
76 }
75 }
77 }
76 }
78 }
77 },
79 },
78 });
80 });
79
81
80
82
81 //-----------------------------------------------------------------------
83 //-----------------------------------------------------------------------
82 // WidgetManager class
84 // WidgetManager class
83 //-----------------------------------------------------------------------
85 //-----------------------------------------------------------------------
84 // Public constructor
86 // Public constructor
85 var WidgetManager = function(comm_manager){
87 var WidgetManager = function(comm_manager){
86 this.comm_manager = comm_manager;
88 this.comm_manager = comm_manager;
87 this.widget_model_types = {};
89 this.widget_model_types = {};
88 this.widget_view_types = {};
90 this.widget_view_types = {};
89 this.model_widget_views = {};
91 this.model_widget_views = {};
90
92
91 var that = this;
93 var that = this;
92 Backbone.sync = function(method, model, options, error) {
94 Backbone.sync = function(method, model, options, error) {
93 var result = that.send_sync(method, model);
95 var result = that.send_sync(method, model);
94 if (options.success) {
96 if (options.success) {
95 options.success(result);
97 options.success(result);
96 }
98 }
97 };
99 };
98 }
100 }
99
101
100 // Register a widget model type.
102 // Register a widget model type.
101 WidgetManager.prototype.register_widget_model = function (widget_model_name, widget_model_type) {
103 WidgetManager.prototype.register_widget_model = function (widget_model_name, widget_model_type) {
102
104
103 // Register the widget with the comm manager. Make sure to pass this object's context
105 // Register the widget with the comm manager. Make sure to pass this object's context
104 // in so `this` works in the call back.
106 // in so `this` works in the call back.
105 this.comm_manager.register_target(widget_model_name, $.proxy(this.handle_com_open, this));
107 this.comm_manager.register_target(widget_model_name, $.proxy(this.handle_com_open, this));
106
108
107 // Register the types of the model and view correspong to this widget type. Later
109 // Register the types of the model and view correspong to this widget type. Later
108 // the widget manager will initialize these when the comm is opened.
110 // the widget manager will initialize these when the comm is opened.
109 this.widget_model_types[widget_model_name] = widget_model_type;
111 this.widget_model_types[widget_model_name] = widget_model_type;
110 }
112 }
111
113
112 // Register a widget view type.
114 // Register a widget view type.
113 WidgetManager.prototype.register_widget_view = function (widget_view_name, widget_view_type) {
115 WidgetManager.prototype.register_widget_view = function (widget_view_name, widget_view_type) {
114 this.widget_view_types[widget_view_name] = widget_view_type;
116 this.widget_view_types[widget_view_name] = widget_view_type;
115 }
117 }
116
118
117 // Handle when a comm is opened.
119 // Handle when a comm is opened.
118 WidgetManager.prototype.handle_com_open = function (comm, msg) {
120 WidgetManager.prototype.handle_com_open = function (comm, msg) {
119 var widget_type_name = msg.content.target_name;
121 var widget_type_name = msg.content.target_name;
120
122
121 // Create the corresponding widget model.
123 // Create the corresponding widget model.
122 var widget_model = new this.widget_model_types[widget_type_name];
124 var widget_model = new this.widget_model_types[widget_type_name];
123
125
124 // Remember comm associated with the model.
126 // Remember comm associated with the model.
125 widget_model.comm = comm;
127 widget_model.comm = comm;
126 comm.model = widget_model;
128 comm.model = widget_model;
127
129
128 // Create an array to remember the views associated with the model.
130 // Create an array to remember the views associated with the model.
129 widget_model.views = [];
131 widget_model.views = [];
130
132
131 // Add a handle to delete the control when the comm is closed.
133 // Add a handle to delete the control when the comm is closed.
132 var that = this;
134 var that = this;
133 var handle_close = function(msg) {
135 var handle_close = function(msg) {
134 that.handle_comm_closed(comm, msg);
136 that.handle_comm_closed(comm, msg);
135 }
137 }
136 comm.on_close(handle_close);
138 comm.on_close(handle_close);
137
139
138 // Handle incomming messages.
140 // Handle incomming messages.
139 var handle_msg = function(msg) {
141 var handle_msg = function(msg) {
140 that.handle_comm_msg(comm, msg);
142 that.handle_comm_msg(comm, msg);
141 }
143 }
142 comm.on_msg(handle_msg);
144 comm.on_msg(handle_msg);
143 }
145 }
144
146
145 // Create view that represents the model.
147 // Create view that represents the model.
146 WidgetManager.prototype.show_view = function (widget_area, widget_model, widget_view_name) {
148 WidgetManager.prototype.show_view = function (widget_area, widget_model, widget_view_name) {
147 var widget_view = new this.widget_view_types[widget_view_name]({model: widget_model});
149 var widget_view = new this.widget_view_types[widget_view_name]({model: widget_model});
148 widget_view.render();
150 widget_view.render();
149 widget_model.views.push(widget_view);
151 widget_model.views.push(widget_view);
150
152
153 // Handle when the view element is remove from the page.
154 widget_view.$el.on("remove", function(){
155 var index = widget_model.views.indexOf(widget_view);
156 if (index > -1) {
157 widget_model.views.splice(index, 1);
158 }
159 widget_view.remove(); // Clean-up view
160
161 // Close the comm if there are no views left.
162 if (widget_model.views.length()==0) {
163 widget_model.comm.close();
164 }
165 });
166
151 // Add the view's element to cell's widget div.
167 // Add the view's element to cell's widget div.
152 widget_area
168 widget_area
153 .append($("<div />").append(widget_view.$el));
169 .append($("<div />").append(widget_view.$el))
154
170 .parent().show(); // Show the widget_area (parent of widget_subarea)
171
155 // Update the view based on the model contents.
172 // Update the view based on the model contents.
156 widget_view.refresh();
173 widget_view.refresh();
157 }
174 }
158
175
159 // Handle incomming comm msg.
176 // Handle incomming comm msg.
160 WidgetManager.prototype.handle_comm_msg = function (comm, msg) {
177 WidgetManager.prototype.handle_comm_msg = function (comm, msg) {
161 // Different logic for different methods.
178 // Different logic for different methods.
162 var method = msg.content.data.method;
179 var method = msg.content.data.method;
163 switch (method){
180 switch (method){
164 case 'show':
181 case 'show':
165
182
166 // TODO: Get cell from registered output handler.
183 // TODO: Get cell from registered output handler.
167 var cell = IPython.notebook.get_cell(IPython.notebook.get_selected_index()-1);
184 var cell = IPython.notebook.get_cell(IPython.notebook.get_selected_index()-1);
168 var widget_subarea = cell.element.find('.widget_area').find('.widget_subarea');
185 var widget_subarea = cell.element.find('.widget_area').find('.widget_subarea');
169
186
170 if (msg.content.data.parent != undefined) {
187 if (msg.content.data.parent != undefined) {
171 var find_results = widget_subarea.find("." + msg.content.data.parent);
188 var find_results = widget_subarea.find("." + msg.content.data.parent);
172 if (find_results.length > 0) {
189 if (find_results.length > 0) {
173 widget_subarea = find_results;
190 widget_subarea = find_results;
174 }
191 }
175 }
192 }
176
193
177 this.show_view(widget_subarea, comm.model, msg.content.data.view_name);
194 this.show_view(widget_subarea, comm.model, msg.content.data.view_name);
178 break;
195 break;
179 case 'update':
196 case 'update':
180 this.handle_update(comm, msg.content.data.state);
197 this.handle_update(comm, msg.content.data.state);
181 break;
198 break;
182 }
199 }
183 }
200 }
184
201
185 // Handle when a widget is updated via the python side.
202 // Handle when a widget is updated via the python side.
186 WidgetManager.prototype.handle_update = function (comm, state) {
203 WidgetManager.prototype.handle_update = function (comm, state) {
187 for (var key in state) {
204 for (var key in state) {
188 if (state.hasOwnProperty(key)) {
205 if (state.hasOwnProperty(key)) {
189 if (key=="_css"){
206 if (key=="_css"){
190 comm.model.css = state[key];
207 comm.model.css = state[key];
191 } else {
208 } else {
192 comm.model.set(key, state[key]);
209 comm.model.set(key, state[key]);
193 }
210 }
194 }
211 }
195 }
212 }
196 comm.model.save();
213 comm.model.save();
197 }
214 }
198
215
199 // Handle when a widget is closed.
216 // Handle when a widget is closed.
200 WidgetManager.prototype.handle_comm_closed = function (comm, msg) {
217 WidgetManager.prototype.handle_comm_closed = function (comm, msg) {
201 for (var view_index in comm.model.views) {
218 for (var view_index in comm.model.views) {
202 var view = comm.model.views[view_index];
219 var view = comm.model.views[view_index];
203 view.remove();
220 view.remove();
204 }
221 }
205 }
222 }
206
223
207 // Get the cell output area corresponding to the comm.
224 // Get the cell output area corresponding to the comm.
208 WidgetManager.prototype._get_comm_outputarea = function (comm) {
225 WidgetManager.prototype._get_comm_outputarea = function (comm) {
209 // TODO: get element from comm instead of guessing
226 // TODO: get element from comm instead of guessing
210 var cell = IPython.notebook.get_cell(IPython.notebook.get_selected_index())
227 var cell = IPython.notebook.get_cell(IPython.notebook.get_selected_index())
211 return cell.output_area;
228 return cell.output_area;
212 }
229 }
213
230
214 // Send widget state to python backend.
231 // Send widget state to python backend.
215 WidgetManager.prototype.send_sync = function (method, model) {
232 WidgetManager.prototype.send_sync = function (method, model) {
216
233
217 // Create a callback for the output if the widget has an output area associate with it.
234 // Create a callback for the output if the widget has an output area associate with it.
218 var callbacks = {};
235 var callbacks = {};
219 var comm = model.comm;
236 var comm = model.comm;
220 var outputarea = this._get_comm_outputarea(comm);
237 var outputarea = this._get_comm_outputarea(comm);
221 if (outputarea != null) {
238 if (outputarea != null) {
222 callbacks = {
239 callbacks = {
223 iopub : {
240 iopub : {
224 output : $.proxy(outputarea.handle_output, outputarea),
241 output : $.proxy(outputarea.handle_output, outputarea),
225 clear_output : $.proxy(outputarea.handle_clear_output, outputarea)}
242 clear_output : $.proxy(outputarea.handle_clear_output, outputarea)}
226 };
243 };
227 };
244 };
228 var model_json = model.toJSON();
245 var model_json = model.toJSON();
229 var data = {sync_method: method, sync_data: model_json};
246 var data = {sync_method: method, sync_data: model_json};
230 comm.send(data, callbacks);
247 comm.send(data, callbacks);
231 return model_json;
248 return model_json;
232 }
249 }
233
250
234 IPython.WidgetManager = WidgetManager;
251 IPython.WidgetManager = WidgetManager;
235 IPython.WidgetModel = WidgetModel;
252 IPython.WidgetModel = WidgetModel;
236 IPython.WidgetView = WidgetView;
253 IPython.WidgetView = WidgetView;
237
254
238
255 IPython.notebook.widget_manager = new WidgetManager(IPython.notebook.kernel.comm_manager);
239 return IPython;
240
256
241 }(IPython));
257 }
General Comments 0
You need to be logged in to leave comments. Login now