Show More
@@ -86,6 +86,7 b'' | |||
|
86 | 86 | cell.widget_area.show(); |
|
87 | 87 | this._handle_display_view(view); |
|
88 | 88 | cell.widget_subarea.append(view.$el); |
|
89 | view.trigger('displayed'); | |
|
89 | 90 | } |
|
90 | 91 | } |
|
91 | 92 | }; |
@@ -83,7 +83,6 b' function(WidgetManager, _, Backbone){' | |||
|
83 | 83 | break; |
|
84 | 84 | case 'display': |
|
85 | 85 | this.widget_manager.display_view(msg, this); |
|
86 | this.trigger('displayed'); | |
|
87 | 86 | break; |
|
88 | 87 | } |
|
89 | 88 | }, |
@@ -283,8 +282,10 b' function(WidgetManager, _, Backbone){' | |||
|
283 | 282 | // Public constructor. |
|
284 | 283 | this.model.on('change',this.update,this); |
|
285 | 284 | this.options = parameters.options; |
|
286 |
this.child_views = |
|
|
285 | this.child_model_views = {}; | |
|
286 | this.child_views = {}; | |
|
287 | 287 | this.model.views.push(this); |
|
288 | this.id = this.id || IPython.utils.uuid(); | |
|
288 | 289 | }, |
|
289 | 290 | |
|
290 | 291 | update: function(){ |
@@ -302,19 +303,39 b' function(WidgetManager, _, Backbone){' | |||
|
302 | 303 | // TODO: this is hacky, and makes the view depend on this cell attribute and widget manager behavior |
|
303 | 304 | // it would be great to have the widget manager add the cell metadata |
|
304 | 305 | // to the subview without having to add it here. |
|
305 | var child_view = this.model.widget_manager.create_view(child_model, options || {}, this); | |
|
306 | this.child_views[child_model.id] = child_view; | |
|
306 | options = $.extend({ parent: this }, options || {}); | |
|
307 | var child_view = this.model.widget_manager.create_view(child_model, options, this); | |
|
308 | ||
|
309 | // Associate the view id with the model id. | |
|
310 | if (this.child_model_views[child_model.id] === undefined) { | |
|
311 | this.child_model_views[child_model.id] = []; | |
|
312 | } | |
|
313 | this.child_model_views[child_model.id].push(child_view.id); | |
|
314 | ||
|
315 | // Remember the view by id. | |
|
316 | this.child_views[child_view.id] = child_view; | |
|
307 | 317 | return child_view; |
|
308 | 318 | }, |
|
309 | 319 | |
|
310 |
|
|
|
320 | pop_child_view: function(child_model) { | |
|
311 | 321 | // Delete a child view that was previously created using create_child_view. |
|
312 | var view = this.child_views[child_model.id]; | |
|
313 | if (view !== undefined) { | |
|
314 | delete this.child_views[child_model.id]; | |
|
315 | view.remove(); | |
|
322 | var view_ids = this.child_model_views[child_model.id]; | |
|
323 | if (view_ids !== undefined) { | |
|
324 | ||
|
325 | // Only delete the first view in the list. | |
|
326 | var view_id = view_ids[0]; | |
|
327 | var view = this.child_views[view_id]; | |
|
328 | delete this.child_views[view_id]; | |
|
329 | view_ids.splice(0,1); | |
|
316 | 330 | child_model.views.pop(view); |
|
331 | ||
|
332 | // Remove the view list specific to this model if it is empty. | |
|
333 | if (view_ids.length === 0) { | |
|
334 | delete this.child_model_views[child_model.id]; | |
|
335 | } | |
|
336 | return view; | |
|
317 | 337 | } |
|
338 | return null; | |
|
318 | 339 | }, |
|
319 | 340 | |
|
320 | 341 | do_diff: function(old_list, new_list, removed_callback, added_callback) { |
@@ -330,16 +351,23 b' function(WidgetManager, _, Backbone){' | |||
|
330 | 351 | // added_callback : Callback(item) |
|
331 | 352 | // Callback that is called for each item added. |
|
332 | 353 | |
|
354 | // Walk the lists until an unequal entry is found. | |
|
355 | var i; | |
|
356 | for (i = 0; i < new_list.length; i++) { | |
|
357 | if (i < old_list.length || new_list[i] !== old_list[i]) { | |
|
358 | break; | |
|
359 | } | |
|
360 | } | |
|
333 | 361 | |
|
334 | // removed items | |
|
335 | _.each(_.difference(old_list, new_list), function(item, index, list) { | |
|
336 |
removed_callback( |
|
|
337 |
} |
|
|
362 | // Remove the non-matching items from the old list. | |
|
363 | for (var j = i; j < old_list.length; j++) { | |
|
364 | removed_callback(old_list[j]); | |
|
365 | } | |
|
338 | 366 | |
|
339 |
// |
|
|
340 | _.each(_.difference(new_list, old_list), function(item, index, list) { | |
|
341 |
added_callback( |
|
|
342 |
} |
|
|
367 | // Add the rest of the new list items. | |
|
368 | for (i; i < new_list.length; i++) { | |
|
369 | added_callback(new_list[i]); | |
|
370 | } | |
|
343 | 371 | }, |
|
344 | 372 | |
|
345 | 373 | callbacks: function(){ |
@@ -21,21 +21,20 b' define(["widgets/js/widget"], function(WidgetManager) {' | |||
|
21 | 21 | // Called when view is rendered. |
|
22 | 22 | this.$el.addClass('widget-container') |
|
23 | 23 | .addClass('vbox'); |
|
24 | this.children={}; | |
|
25 | this.update_children([], this.model.get('_children')); | |
|
26 | this.model.on('change:_children', function(model, value, options) { | |
|
27 | this.update_children(model.previous('_children'), value); | |
|
24 | this.update_children([], this.model.get('children')); | |
|
25 | this.model.on('change:children', function(model, value, options) { | |
|
26 | this.update_children(model.previous('children'), value); | |
|
28 | 27 | }, this); |
|
29 | 28 | this.update(); |
|
30 | 29 | |
|
31 | 30 | // Trigger model displayed events for any models that are child to |
|
32 | 31 | // this model when this model is displayed. |
|
33 | 32 | var that = this; |
|
34 |
this |
|
|
33 | this.on('displayed', function(){ | |
|
35 | 34 | that.is_displayed = true; |
|
36 | 35 | for (var property in that.child_views) { |
|
37 | 36 | if (that.child_views.hasOwnProperty(property)) { |
|
38 |
that.child_views[property]. |
|
|
37 | that.child_views[property].trigger('displayed'); | |
|
39 | 38 | } |
|
40 | 39 | } |
|
41 | 40 | }); |
@@ -51,8 +50,7 b' define(["widgets/js/widget"], function(WidgetManager) {' | |||
|
51 | 50 | |
|
52 | 51 | remove_child_model: function(model) { |
|
53 | 52 | // Called when a model is removed from the children list. |
|
54 |
this.child_view |
|
|
55 | this.delete_child_view(model); | |
|
53 | this.pop_child_view(model).remove(); | |
|
56 | 54 | }, |
|
57 | 55 | |
|
58 | 56 | add_child_model: function(model) { |
@@ -62,7 +60,7 b' define(["widgets/js/widget"], function(WidgetManager) {' | |||
|
62 | 60 | |
|
63 | 61 | // Trigger the displayed event if this model is displayed. |
|
64 | 62 | if (this.is_displayed) { |
|
65 |
|
|
|
63 | view.trigger('displayed'); | |
|
66 | 64 | } |
|
67 | 65 | }, |
|
68 | 66 | |
@@ -81,7 +79,6 b' define(["widgets/js/widget"], function(WidgetManager) {' | |||
|
81 | 79 | render: function(){ |
|
82 | 80 | // Called when view is rendered. |
|
83 | 81 | var that = this; |
|
84 | this.children={}; | |
|
85 | 82 | |
|
86 | 83 | this.$el.on("remove", function(){ |
|
87 | 84 | that.$backdrop.remove(); |
@@ -187,19 +184,19 b' define(["widgets/js/widget"], function(WidgetManager) {' | |||
|
187 | 184 | this._shown_once = false; |
|
188 | 185 | this.popped_out = true; |
|
189 | 186 | |
|
190 |
this.update_children([], this.model.get(' |
|
|
191 |
this.model.on('change: |
|
|
192 |
this.update_children(model.previous(' |
|
|
187 | this.update_children([], this.model.get('children')); | |
|
188 | this.model.on('change:children', function(model, value, options) { | |
|
189 | this.update_children(model.previous('children'), value); | |
|
193 | 190 | }, this); |
|
194 | 191 | this.update(); |
|
195 | 192 | |
|
196 | 193 | // Trigger model displayed events for any models that are child to |
|
197 | 194 | // this model when this model is displayed. |
|
198 |
this |
|
|
195 | this.on('displayed', function(){ | |
|
199 | 196 | that.is_displayed = true; |
|
200 | 197 | for (var property in that.child_views) { |
|
201 | 198 | if (that.child_views.hasOwnProperty(property)) { |
|
202 |
that.child_views[property]. |
|
|
199 | that.child_views[property].trigger('displayed'); | |
|
203 | 200 | } |
|
204 | 201 | } |
|
205 | 202 | }); |
@@ -257,8 +254,7 b' define(["widgets/js/widget"], function(WidgetManager) {' | |||
|
257 | 254 | |
|
258 | 255 | remove_child_model: function(model) { |
|
259 | 256 | // Called when a child is removed from children list. |
|
260 |
this.child_view |
|
|
261 | this.delete_child_view(model); | |
|
257 | this.pop_child_view(model).remove(); | |
|
262 | 258 | }, |
|
263 | 259 | |
|
264 | 260 | add_child_model: function(model) { |
@@ -268,7 +264,7 b' define(["widgets/js/widget"], function(WidgetManager) {' | |||
|
268 | 264 | |
|
269 | 265 | // Trigger the displayed event if this model is displayed. |
|
270 | 266 | if (this.is_displayed) { |
|
271 |
|
|
|
267 | view.trigger('displayed'); | |
|
272 | 268 | } |
|
273 | 269 | }, |
|
274 | 270 |
@@ -55,6 +55,7 b' define(["widgets/js/widget"], function(WidgetManager){' | |||
|
55 | 55 | // one-to-one mapping with the corrosponding keys of the model. |
|
56 | 56 | var jquery_slider_keys = ['step', 'max', 'min', 'disabled']; |
|
57 | 57 | var that = this; |
|
58 | that.$slider.slider({}); | |
|
58 | 59 | _.each(jquery_slider_keys, function(key, i) { |
|
59 | 60 | var model_value = that.model.get(key); |
|
60 | 61 | if (model_value !== undefined) { |
@@ -25,9 +25,9 b' define(["widgets/js/widget"], function(WidgetManager){' | |||
|
25 | 25 | .addClass('panel-group'); |
|
26 | 26 | this.containers = []; |
|
27 | 27 | this.model_containers = {}; |
|
28 |
this.update_children([], this.model.get(' |
|
|
29 |
this.model.on('change: |
|
|
30 |
this.update_children(model.previous(' |
|
|
28 | this.update_children([], this.model.get('children')); | |
|
29 | this.model.on('change:children', function(model, value, options) { | |
|
30 | this.update_children(model.previous('children'), value); | |
|
31 | 31 | }, this); |
|
32 | 32 | this.model.on('change:selected_index', function(model, value, options) { |
|
33 | 33 | this.update_selected_index(model.previous('selected_index'), value, options); |
@@ -36,14 +36,14 b' define(["widgets/js/widget"], function(WidgetManager){' | |||
|
36 | 36 | this.update_titles(value); |
|
37 | 37 | }, this); |
|
38 | 38 | var that = this; |
|
39 |
this |
|
|
39 | this.on('displayed', function() { | |
|
40 | 40 | this.update_titles(); |
|
41 | 41 | // Trigger model displayed events for any models that are child to |
|
42 | 42 | // this model when this model is displayed. |
|
43 | 43 | that.is_displayed = true; |
|
44 | 44 | for (var property in that.child_views) { |
|
45 | 45 | if (that.child_views.hasOwnProperty(property)) { |
|
46 |
that.child_views[property]. |
|
|
46 | that.child_views[property].trigger('displayed'); | |
|
47 | 47 | } |
|
48 | 48 | } |
|
49 | 49 | }, this); |
@@ -92,7 +92,7 b' define(["widgets/js/widget"], function(WidgetManager){' | |||
|
92 | 92 | this.containers.splice(accordion_group.container_index, 1); |
|
93 | 93 | delete this.model_containers[model.id]; |
|
94 | 94 | accordion_group.remove(); |
|
95 |
this. |
|
|
95 | this.pop_child_view(model); | |
|
96 | 96 | }, |
|
97 | 97 | |
|
98 | 98 | add_child_model: function(model) { |
@@ -137,7 +137,7 b' define(["widgets/js/widget"], function(WidgetManager){' | |||
|
137 | 137 | |
|
138 | 138 | // Trigger the displayed event if this model is displayed. |
|
139 | 139 | if (this.is_displayed) { |
|
140 |
|
|
|
140 | view.trigger('displayed'); | |
|
141 | 141 | } |
|
142 | 142 | }, |
|
143 | 143 | }); |
@@ -163,18 +163,18 b' define(["widgets/js/widget"], function(WidgetManager){' | |||
|
163 | 163 | .addClass('tab-content') |
|
164 | 164 | .appendTo(this.$el); |
|
165 | 165 | this.containers = []; |
|
166 |
this.update_children([], this.model.get(' |
|
|
167 |
this.model.on('change: |
|
|
168 |
this.update_children(model.previous(' |
|
|
166 | this.update_children([], this.model.get('children')); | |
|
167 | this.model.on('change:children', function(model, value, options) { | |
|
168 | this.update_children(model.previous('children'), value); | |
|
169 | 169 | }, this); |
|
170 | 170 | |
|
171 | 171 | // Trigger model displayed events for any models that are child to |
|
172 | 172 | // this model when this model is displayed. |
|
173 |
this |
|
|
173 | this.on('displayed', function(){ | |
|
174 | 174 | that.is_displayed = true; |
|
175 | 175 | for (var property in that.child_views) { |
|
176 | 176 | if (that.child_views.hasOwnProperty(property)) { |
|
177 |
that.child_views[property]. |
|
|
177 | that.child_views[property].trigger('displayed'); | |
|
178 | 178 | } |
|
179 | 179 | } |
|
180 | 180 | }); |
@@ -190,12 +190,11 b' define(["widgets/js/widget"], function(WidgetManager){' | |||
|
190 | 190 | |
|
191 | 191 | remove_child_model: function(model) { |
|
192 | 192 | // Called when a child is removed from children list. |
|
193 |
var view = this.child_view |
|
|
193 | var view = this.pop_child_view(model); | |
|
194 | 194 | this.containers.splice(view.parent_tab.tab_text_index, 1); |
|
195 | 195 | view.parent_tab.remove(); |
|
196 | 196 | view.parent_container.remove(); |
|
197 | 197 | view.remove(); |
|
198 | this.delete_child_view(model); | |
|
199 | 198 | }, |
|
200 | 199 | |
|
201 | 200 | add_child_model: function(model) { |
@@ -234,7 +233,7 b' define(["widgets/js/widget"], function(WidgetManager){' | |||
|
234 | 233 | |
|
235 | 234 | // Trigger the displayed event if this model is displayed. |
|
236 | 235 | if (this.is_displayed) { |
|
237 |
|
|
|
236 | view.trigger('displayed'); | |
|
238 | 237 | } |
|
239 | 238 | }, |
|
240 | 239 |
@@ -2,58 +2,29 b'' | |||
|
2 | 2 | |
|
3 | 3 | Represents a container that can be used to group other widgets. |
|
4 | 4 | """ |
|
5 | #----------------------------------------------------------------------------- | |
|
6 |
# Copyright (c) |
|
|
7 | # | |
|
5 | ||
|
6 | # Copyright (c) IPython Development Team. | |
|
8 | 7 | # Distributed under the terms of the Modified BSD License. |
|
9 | # | |
|
10 | # The full license is in the file COPYING.txt, distributed with this software. | |
|
11 | #----------------------------------------------------------------------------- | |
|
12 | 8 | |
|
13 | #----------------------------------------------------------------------------- | |
|
14 | # Imports | |
|
15 | #----------------------------------------------------------------------------- | |
|
16 | 9 | from .widget import DOMWidget |
|
17 | 10 | from IPython.utils.traitlets import Unicode, Tuple, TraitError |
|
18 | 11 | |
|
19 | #----------------------------------------------------------------------------- | |
|
20 | # Classes | |
|
21 | #----------------------------------------------------------------------------- | |
|
22 | ||
|
23 | 12 | class ContainerWidget(DOMWidget): |
|
24 | 13 | _view_name = Unicode('ContainerView', sync=True) |
|
25 | 14 | |
|
26 | 15 | # Child widgets in the container. |
|
27 | 16 | # Using a tuple here to force reassignment to update the list. |
|
28 | 17 | # When a proper notifying-list trait exists, that is what should be used here. |
|
29 | children = Tuple() | |
|
30 | _children = Tuple(sync=True) | |
|
31 | ||
|
18 | children = Tuple(sync=True) | |
|
32 | 19 | |
|
33 | 20 | def __init__(self, **kwargs): |
|
34 | 21 | super(ContainerWidget, self).__init__(**kwargs) |
|
35 | 22 | self.on_displayed(ContainerWidget._fire_children_displayed) |
|
36 | 23 | |
|
37 | 24 | def _fire_children_displayed(self): |
|
38 |
for child in self. |
|
|
25 | for child in self.children: | |
|
39 | 26 | child._handle_displayed() |
|
40 | 27 | |
|
41 | def _children_changed(self, name, old, new): | |
|
42 | """Validate children list. | |
|
43 | ||
|
44 | Makes sure only one instance of any given model can exist in the | |
|
45 | children list. | |
|
46 | An excellent post on uniqifiers is available at | |
|
47 | http://www.peterbe.com/plog/uniqifiers-benchmark | |
|
48 | which provides the inspiration for using this implementation. Below | |
|
49 | I've implemented the `f5` algorithm using Python comprehensions.""" | |
|
50 | if new is not None: | |
|
51 | seen = {} | |
|
52 | def add_item(i): | |
|
53 | seen[i.model_id] = True | |
|
54 | return i | |
|
55 | self._children = [add_item(i) for i in new if not i.model_id in seen] | |
|
56 | ||
|
57 | 28 | |
|
58 | 29 | class PopupWidget(ContainerWidget): |
|
59 | 30 | _view_name = Unicode('PopupView', sync=True) |
General Comments 0
You need to be logged in to leave comments.
Login now