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