##// END OF EJS Templates
Fixed some typos related to _.each loops
Jonathan Frederic -
Show More
@@ -1,188 +1,189
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 (function () {
19 19 "use strict";
20 20
21 21 // Use require.js 'define' method so that require.js is intelligent enough to
22 22 // syncronously load everything within this file when it is being 'required'
23 23 // elsewhere.
24 24 define(["underscore",
25 25 "backbone",
26 26 ], function (Underscore, Backbone) {
27 27
28 28 //--------------------------------------------------------------------
29 29 // WidgetManager class
30 30 //--------------------------------------------------------------------
31 31 var WidgetManager = function (comm_manager) {
32 32 // Public constructor
33 33 WidgetManager._managers.push(this);
34 34
35 35 // Attach a comm manager to the
36 36 this.comm_manager = comm_manager;
37 37 this._models = {}; /* Dictionary of model ids and model instances */
38 38
39 39 // Register already-registered widget model types with the comm manager.
40 var that = this;
40 41 _.each(WidgetManager._model_types, function(value, key) {
41 this.comm_manager.register_target(value, $.proxy(this._handle_comm_open, this));
42 that.comm_manager.register_target(value, $.proxy(that._handle_comm_open, that));
42 43 });
43 44 };
44 45
45 46 //--------------------------------------------------------------------
46 47 // Class level
47 48 //--------------------------------------------------------------------
48 49 WidgetManager._model_types = {}; /* Dictionary of model type names (target_name) and model types. */
49 50 WidgetManager._view_types = {}; /* Dictionary of view names and view types. */
50 51 WidgetManager._managers = []; /* List of widget managers */
51 52
52 53 WidgetManager.register_widget_model = function (model_name, model_type) {
53 54 // Registers a widget model by name.
54 55 WidgetManager._model_types[model_name] = model_type;
55 56
56 57 // Register the widget with the comm manager. Make sure to pass this object's context
57 58 // in so `this` works in the call back.
58 59 _.each(WidgetManager._managers, function(instance, i) {
59 60 if (instance.comm_manager !== null) {
60 61 instance.comm_manager.register_target(model_name, $.proxy(instance._handle_comm_open, instance));
61 62 }
62 63 });
63 64 };
64 65
65 66 WidgetManager.register_widget_view = function (view_name, view_type) {
66 67 // Registers a widget view by name.
67 68 WidgetManager._view_types[view_name] = view_type;
68 69 };
69 70
70 71 //--------------------------------------------------------------------
71 72 // Instance level
72 73 //--------------------------------------------------------------------
73 74 WidgetManager.prototype.display_view = function(msg, model) {
74 75 var cell = this.get_msg_cell(msg.parent_header.msg_id);
75 76 if (cell === null) {
76 77 console.log("Could not determine where the display" +
77 78 " message was from. Widget will not be displayed");
78 79 } else {
79 80 var view = this.create_view(model, {cell: cell});
80 81 if (view === null) {
81 82 console.error("View creation failed", model);
82 83 }
83 84 if (cell.widget_subarea !== undefined
84 85 && cell.widget_subarea !== null) {
85 86
86 87 cell.widget_area.show();
87 88 cell.widget_subarea.append(view.$el);
88 89 }
89 90 }
90 91 },
91 92
92 93 WidgetManager.prototype.create_view = function(model, options) {
93 94 var view_name = model.get('view_name');
94 95 var ViewType = WidgetManager._view_types[view_name];
95 96 if (ViewType !== undefined && ViewType !== null) {
96 97 var parameters = {model: model, options: options};
97 98 var view = new ViewType(parameters);
98 99 view.render();
99 100 IPython.keyboard_manager.register_events(view.$el);
100 101 model.views.push(view);
101 102 model.on('destroy', view.remove, view);
102 103 return view;
103 104 }
104 105 return null;
105 106 },
106 107
107 108 WidgetManager.prototype.get_msg_cell = function (msg_id) {
108 109 var cell = null;
109 110 // First, check to see if the msg was triggered by cell execution.
110 111 if (IPython.notebook !== undefined && IPython.notebook !== null) {
111 112 cell = IPython.notebook.get_msg_cell(msg_id);
112 113 }
113 114 if (cell !== null) {
114 115 return cell
115 116 }
116 117 // Second, check to see if a get_cell callback was defined
117 118 // for the message. get_cell callbacks are registered for
118 119 // widget messages, so this block is actually checking to see if the
119 120 // message was triggered by a widget.
120 121 var kernel = this.comm_manager.kernel;
121 122 if (kernel !== undefined && kernel !== null) {
122 123 var callbacks = kernel.get_callbacks_for_msg(msg_id);
123 124 if (callbacks !== undefined &&
124 125 callbacks.iopub !== undefined &&
125 126 callbacks.iopub.get_cell !== undefined) {
126 127
127 128 return callbacks.iopub.get_cell();
128 129 }
129 130 }
130 131
131 132 // Not triggered by a cell or widget (no get_cell callback
132 133 // exists).
133 134 return null;
134 135 };
135 136
136 137 WidgetManager.prototype.callbacks = function (view) {
137 138 // callback handlers specific a view
138 139 var callbacks = {};
139 140 var cell = view.options.cell;
140 141 if (cell !== null) {
141 142 // Try to get output handlers
142 143 var handle_output = null;
143 144 var handle_clear_output = null;
144 145 if (cell.output_area !== undefined && cell.output_area !== null) {
145 146 handle_output = $.proxy(cell.output_area.handle_output, cell.output_area);
146 147 handle_clear_output = $.proxy(cell.output_area.handle_clear_output, cell.output_area);
147 148 }
148 149
149 150 // Create callback dict using what is known
150 151 var that = this;
151 152 callbacks = {
152 153 iopub : {
153 154 output : handle_output,
154 155 clear_output : handle_clear_output,
155 156
156 157 // Special function only registered by widget messages.
157 158 // Allows us to get the cell for a message so we know
158 159 // where to add widgets if the code requires it.
159 160 get_cell : function () {
160 161 return cell;
161 162 },
162 163 },
163 164 };
164 165 }
165 166 return callbacks;
166 167 };
167 168
168 169 WidgetManager.prototype.get_model = function (model_id) {
169 170 // Look-up a model instance by its id.
170 171 var model = this._models[model_id];
171 172 if (model !== undefined && model.id == model_id) {
172 173 return model;
173 174 }
174 175 return null;
175 176 };
176 177
177 178 WidgetManager.prototype._handle_comm_open = function (comm, msg) {
178 179 // Handle when a comm is opened.
179 180 var model_id = comm.comm_id;
180 181 var widget_type_name = msg.content.target_name;
181 182 var widget_model = new WidgetManager._model_types[widget_type_name](this, model_id, comm);
182 183 this._models[model_id] = widget_model;
183 184 };
184 185
185 186 IPython.WidgetManager = WidgetManager;
186 187 return IPython.WidgetManager;
187 188 });
188 189 }());
@@ -1,372 +1,372
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 // SelectionWidget
10 10 //============================================================================
11 11
12 12 /**
13 13 * @module IPython
14 14 * @namespace IPython
15 15 **/
16 16
17 17 define(["notebook/js/widgets/widget"], function(WidgetManager){
18 18
19 19 var DropdownView = IPython.DOMWidgetView.extend({
20 20 render : function(){
21 21 // Called when view is rendered.
22 22 this.$el
23 23 .addClass('widget-hbox-single');
24 24 this.$label = $('<div />')
25 25 .appendTo(this.$el)
26 26 .addClass('widget-hlabel')
27 27 .hide();
28 28 this.$buttongroup = $('<div />')
29 29 .addClass('widget_item')
30 30 .addClass('btn-group')
31 31 .appendTo(this.$el);
32 32 this.$el_to_style = this.$buttongroup; // Set default element to style
33 33 this.$droplabel = $('<button />')
34 34 .addClass('btn')
35 35 .addClass('widget-combo-btn')
36 36 .text(' ')
37 37 .appendTo(this.$buttongroup);
38 38 this.$dropbutton = $('<button />')
39 39 .addClass('btn')
40 40 .addClass('dropdown-toggle')
41 41 .addClass('widget-combo-carrot-btn')
42 42 .attr('data-toggle', 'dropdown')
43 43 .append($('<span />').addClass("caret"))
44 44 .appendTo(this.$buttongroup);
45 45 this.$droplist = $('<ul />')
46 46 .addClass('dropdown-menu')
47 47 .appendTo(this.$buttongroup);
48 48
49 49 // Set defaults.
50 50 this.update();
51 51 },
52 52
53 53 update : function(options){
54 54 // Update the contents of this view
55 55 //
56 56 // Called when the model is changed. The model may have been
57 57 // changed by another view or by a state update from the back-end.
58 58
59 59 if (options === undefined || options.updated_view != this) {
60 60 var selected_item_text = this.model.get('value');
61 61 if (selected_item_text.length === 0) {
62 62 this.$droplabel.text(' ');
63 63 } else {
64 64 this.$droplabel.text(selected_item_text);
65 65 }
66 66
67 67 var items = this.model.get('values');
68 68 var $replace_droplist = $('<ul />')
69 69 .addClass('dropdown-menu');
70 70 _.each(items, function(item, i) {
71 71 var item_button = $('<a href="#"/>')
72 72 .text(item)
73 73 .on('click', $.proxy(this.handle_click, this));
74 74 $replace_droplist.append($('<li />').append(item_button));
75 75 });
76 76
77 77 this.$droplist.replaceWith($replace_droplist);
78 78 this.$droplist.remove();
79 79 this.$droplist = $replace_droplist;
80 80
81 81 if (this.model.get('disabled')) {
82 82 this.$buttongroup.attr('disabled','disabled');
83 83 this.$droplabel.attr('disabled','disabled');
84 84 this.$dropbutton.attr('disabled','disabled');
85 85 this.$droplist.attr('disabled','disabled');
86 86 } else {
87 87 this.$buttongroup.removeAttr('disabled');
88 88 this.$droplabel.removeAttr('disabled');
89 89 this.$dropbutton.removeAttr('disabled');
90 90 this.$droplist.removeAttr('disabled');
91 91 }
92 92
93 93 var description = this.model.get('description');
94 94 if (description.length === 0) {
95 95 this.$label.hide();
96 96 } else {
97 97 this.$label.text(description);
98 98 this.$label.show();
99 99 }
100 100 }
101 101 return DropdownView.__super__.update.apply(this);
102 102 },
103 103
104 104 handle_click: function (e) {
105 105 // Handle when a value is clicked.
106 106
107 107 // Calling model.set will trigger all of the other views of the
108 108 // model to update.
109 109 this.model.set('value', $(e.target).text(), {updated_view: this});
110 110 this.touch();
111 111 },
112 112
113 113 });
114 114 WidgetManager.register_widget_view('DropdownView', DropdownView);
115 115
116 116
117 117 var RadioButtonsView = IPython.DOMWidgetView.extend({
118 118 render : function(){
119 119 // Called when view is rendered.
120 120 this.$el
121 121 .addClass('widget-hbox');
122 122 this.$label = $('<div />')
123 123 .appendTo(this.$el)
124 124 .addClass('widget-hlabel')
125 125 .hide();
126 126 this.$container = $('<div />')
127 127 .appendTo(this.$el)
128 128 .addClass('widget-container')
129 129 .addClass('vbox');
130 130 this.$el_to_style = this.$container; // Set default element to style
131 131 this.update();
132 132 },
133 133
134 134 update : function(options){
135 135 // Update the contents of this view
136 136 //
137 137 // Called when the model is changed. The model may have been
138 138 // changed by another view or by a state update from the back-end.
139 139 if (options === undefined || options.updated_view != this) {
140 140 // Add missing items to the DOM.
141 141 var items = this.model.get('values');
142 142 var disabled = this.model.get('disabled');
143 143 _.each(items, function(item, index) {
144 144 var item_query = ' :input[value="' + item + '"]';
145 145 if (this.$el.find(item_query).length === 0) {
146 146 var $label = $('<label />')
147 147 .addClass('radio')
148 148 .text(item)
149 149 .appendTo(this.$container);
150 150
151 151 $('<input />')
152 152 .attr('type', 'radio')
153 153 .addClass(this.model)
154 154 .val(item)
155 155 .prependTo($label)
156 156 .on('click', $.proxy(this.handle_click, this));
157 157 }
158 158
159 159 var $item_element = this.$container.find(item_query);
160 160 if (this.model.get('value') == item) {
161 161 $item_element.prop('checked', true);
162 162 } else {
163 163 $item_element.prop('checked', false);
164 164 }
165 165 $item_element.prop('disabled', disabled);
166 166 });
167 167
168 168 // Remove items that no longer exist.
169 169 this.$container.find('input').each(function(i, obj) {
170 170 var value = $(obj).val();
171 171 var found = false;
172 172 _.each(items, function(item, index) {
173 173 if (item == value) {
174 174 found = true;
175 break;
175 return false;
176 176 }
177 177 });
178 178
179 179 if (!found) {
180 180 $(obj).parent().remove();
181 181 }
182 182 });
183 183
184 184 var description = this.model.get('description');
185 185 if (description.length === 0) {
186 186 this.$label.hide();
187 187 } else {
188 188 this.$label.text(description);
189 189 this.$label.show();
190 190 }
191 191 }
192 192 return RadioButtonsView.__super__.update.apply(this);
193 193 },
194 194
195 195 handle_click: function (e) {
196 196 // Handle when a value is clicked.
197 197
198 198 // Calling model.set will trigger all of the other views of the
199 199 // model to update.
200 200 this.model.set('value', $(e.target).val(), {updated_view: this});
201 201 this.touch();
202 202 },
203 203 });
204 204 WidgetManager.register_widget_view('RadioButtonsView', RadioButtonsView);
205 205
206 206
207 207 var ToggleButtonsView = IPython.DOMWidgetView.extend({
208 208 render : function(){
209 209 // Called when view is rendered.
210 210 this.$el
211 211 .addClass('widget-hbox-single');
212 212 this.$label = $('<div />')
213 213 .appendTo(this.$el)
214 214 .addClass('widget-hlabel')
215 215 .hide();
216 216 this.$buttongroup = $('<div />')
217 217 .addClass('btn-group')
218 218 .attr('data-toggle', 'buttons-radio')
219 219 .appendTo(this.$el);
220 220 this.$el_to_style = this.$buttongroup; // Set default element to style
221 221 this.update();
222 222 },
223 223
224 224 update : function(options){
225 225 // Update the contents of this view
226 226 //
227 227 // Called when the model is changed. The model may have been
228 228 // changed by another view or by a state update from the back-end.
229 229 if (options === undefined || options.updated_view != this) {
230 230 // Add missing items to the DOM.
231 231 var items = this.model.get('values');
232 232 var disabled = this.model.get('disabled');
233 233 _.each(items, function(item, index) {
234 234 var item_query = ' :contains("' + item + '")';
235 235 if (this.$buttongroup.find(item_query).length === 0) {
236 236 $('<button />')
237 237 .attr('type', 'button')
238 238 .addClass('btn')
239 239 .text(item)
240 240 .appendTo(this.$buttongroup)
241 241 .on('click', $.proxy(this.handle_click, this));
242 242 }
243 243
244 244 var $item_element = this.$buttongroup.find(item_query);
245 245 if (this.model.get('value') == item) {
246 246 $item_element.addClass('active');
247 247 } else {
248 248 $item_element.removeClass('active');
249 249 }
250 250 $item_element.prop('disabled', disabled);
251 251 });
252 252
253 253 // Remove items that no longer exist.
254 254 this.$buttongroup.find('button').each(function(i, obj) {
255 255 var value = $(obj).text();
256 256 var found = false;
257 257 _.each(items, function(item, index) {
258 258 if (item == value) {
259 259 found = true;
260 break;
260 return false;
261 261 }
262 262 });
263 263
264 264 if (!found) {
265 265 $(obj).remove();
266 266 }
267 267 });
268 268
269 269 var description = this.model.get('description');
270 270 if (description.length === 0) {
271 271 this.$label.hide();
272 272 } else {
273 273 this.$label.text(description);
274 274 this.$label.show();
275 275 }
276 276 }
277 277 return ToggleButtonsView.__super__.update.apply(this);
278 278 },
279 279
280 280 handle_click: function (e) {
281 281 // Handle when a value is clicked.
282 282
283 283 // Calling model.set will trigger all of the other views of the
284 284 // model to update.
285 285 this.model.set('value', $(e.target).text(), {updated_view: this});
286 286 this.touch();
287 287 },
288 288 });
289 289 WidgetManager.register_widget_view('ToggleButtonsView', ToggleButtonsView);
290 290
291 291
292 292 var ListBoxView = IPython.DOMWidgetView.extend({
293 293 render : function(){
294 294 // Called when view is rendered.
295 295 this.$el
296 296 .addClass('widget-hbox');
297 297 this.$label = $('<div />')
298 298 .appendTo(this.$el)
299 299 .addClass('widget-hlabel')
300 300 .hide();
301 301 this.$listbox = $('<select />')
302 302 .addClass('widget-listbox')
303 303 .attr('size', 6)
304 304 .appendTo(this.$el);
305 305 this.$el_to_style = this.$listbox; // Set default element to style
306 306 this.update();
307 307 },
308 308
309 309 update : function(options){
310 310 // Update the contents of this view
311 311 //
312 312 // Called when the model is changed. The model may have been
313 313 // changed by another view or by a state update from the back-end.
314 314 if (options === undefined || options.updated_view != this) {
315 315 // Add missing items to the DOM.
316 316 var items = this.model.get('values');
317 317 _.each(items, function(item, index) {
318 318 var item_query = ' :contains("' + item + '")';
319 319 if (this.$listbox.find(item_query).length === 0) {
320 320 $('<option />')
321 321 .text(item)
322 322 .attr('value', item)
323 323 .appendTo(this.$listbox)
324 324 .on('click', $.proxy(this.handle_click, this));
325 325 }
326 326 });
327 327
328 328 // Select the correct element
329 329 this.$listbox.val(this.model.get('value'));
330 330
331 331 // Disable listbox if needed
332 332 var disabled = this.model.get('disabled');
333 333 this.$listbox.prop('disabled', disabled);
334 334
335 335 // Remove items that no longer exist.
336 336 this.$listbox.find('option').each(function(i, obj) {
337 337 var value = $(obj).text();
338 338 var found = false;
339 339 _.each(items, function(item, index) {
340 340 if (item == value) {
341 341 found = true;
342 break;
342 return false;
343 343 }
344 344 });
345 345
346 346 if (!found) {
347 347 $(obj).remove();
348 348 }
349 349 });
350 350
351 351 var description = this.model.get('description');
352 352 if (description.length === 0) {
353 353 this.$label.hide();
354 354 } else {
355 355 this.$label.text(description);
356 356 this.$label.show();
357 357 }
358 358 }
359 359 return ListBoxView.__super__.update.apply(this);
360 360 },
361 361
362 362 handle_click: function (e) {
363 363 // Handle when a value is clicked.
364 364
365 365 // Calling model.set will trigger all of the other views of the
366 366 // model to update.
367 367 this.model.set('value', $(e.target).text(), {updated_view: this});
368 368 this.touch();
369 369 },
370 370 });
371 371 WidgetManager.register_widget_view('ListBoxView', ListBoxView);
372 372 });
General Comments 0
You need to be logged in to leave comments. Login now