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