Show More
@@ -86,6 +86,7 b'' | |||||
86 | cell.widget_area.show(); |
|
86 | cell.widget_area.show(); | |
87 | this._handle_display_view(view); |
|
87 | this._handle_display_view(view); | |
88 | cell.widget_subarea.append(view.$el); |
|
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 | break; |
|
83 | break; | |
84 | case 'display': |
|
84 | case 'display': | |
85 | this.widget_manager.display_view(msg, this); |
|
85 | this.widget_manager.display_view(msg, this); | |
86 | this.trigger('displayed'); |
|
|||
87 | break; |
|
86 | break; | |
88 | } |
|
87 | } | |
89 | }, |
|
88 | }, | |
@@ -283,8 +282,10 b' function(WidgetManager, _, Backbone){' | |||||
283 | // Public constructor. |
|
282 | // Public constructor. | |
284 | this.model.on('change',this.update,this); |
|
283 | this.model.on('change',this.update,this); | |
285 | this.options = parameters.options; |
|
284 | this.options = parameters.options; | |
286 |
this.child_views = |
|
285 | this.child_model_views = {}; | |
|
286 | this.child_views = {}; | |||
287 | this.model.views.push(this); |
|
287 | this.model.views.push(this); | |
|
288 | this.id = this.id || IPython.utils.uuid(); | |||
288 | }, |
|
289 | }, | |
289 |
|
290 | |||
290 | update: function(){ |
|
291 | update: function(){ | |
@@ -302,19 +303,39 b' function(WidgetManager, _, Backbone){' | |||||
302 | // TODO: this is hacky, and makes the view depend on this cell attribute and widget manager behavior |
|
303 | // TODO: this is hacky, and makes the view depend on this cell attribute and widget manager behavior | |
303 | // it would be great to have the widget manager add the cell metadata |
|
304 | // it would be great to have the widget manager add the cell metadata | |
304 | // to the subview without having to add it here. |
|
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 | options = $.extend({ parent: this }, options || {}); | |
306 | this.child_views[child_model.id] = child_view; |
|
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 | return child_view; |
|
317 | return child_view; | |
308 | }, |
|
318 | }, | |
309 |
|
319 | |||
310 |
|
|
320 | pop_child_view: function(child_model) { | |
311 | // Delete a child view that was previously created using create_child_view. |
|
321 | // Delete a child view that was previously created using create_child_view. | |
312 | var view = this.child_views[child_model.id]; |
|
322 | var view_ids = this.child_model_views[child_model.id]; | |
313 | if (view !== undefined) { |
|
323 | if (view_ids !== undefined) { | |
314 | delete this.child_views[child_model.id]; |
|
324 | ||
315 | view.remove(); |
|
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 | child_model.views.pop(view); |
|
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 | do_diff: function(old_list, new_list, removed_callback, added_callback) { |
|
341 | do_diff: function(old_list, new_list, removed_callback, added_callback) { | |
@@ -330,16 +351,23 b' function(WidgetManager, _, Backbone){' | |||||
330 | // added_callback : Callback(item) |
|
351 | // added_callback : Callback(item) | |
331 | // Callback that is called for each item added. |
|
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 |
|
362 | // Remove the non-matching items from the old list. | |
335 | _.each(_.difference(old_list, new_list), function(item, index, list) { |
|
363 | for (var j = i; j < old_list.length; j++) { | |
336 |
removed_callback( |
|
364 | removed_callback(old_list[j]); | |
337 |
} |
|
365 | } | |
338 |
|
366 | |||
339 |
// |
|
367 | // Add the rest of the new list items. | |
340 | _.each(_.difference(new_list, old_list), function(item, index, list) { |
|
368 | for (i; i < new_list.length; i++) { | |
341 |
added_callback( |
|
369 | added_callback(new_list[i]); | |
342 |
} |
|
370 | } | |
343 | }, |
|
371 | }, | |
344 |
|
372 | |||
345 | callbacks: function(){ |
|
373 | callbacks: function(){ |
@@ -21,21 +21,20 b' define(["widgets/js/widget"], function(WidgetManager) {' | |||||
21 | // Called when view is rendered. |
|
21 | // Called when view is rendered. | |
22 | this.$el.addClass('widget-container') |
|
22 | this.$el.addClass('widget-container') | |
23 | .addClass('vbox'); |
|
23 | .addClass('vbox'); | |
24 | this.children={}; |
|
24 | this.update_children([], this.model.get('children')); | |
25 | this.update_children([], this.model.get('_children')); |
|
25 | this.model.on('change:children', function(model, value, options) { | |
26 | this.model.on('change:_children', function(model, value, options) { |
|
26 | this.update_children(model.previous('children'), value); | |
27 | this.update_children(model.previous('_children'), value); |
|
|||
28 | }, this); |
|
27 | }, this); | |
29 | this.update(); |
|
28 | this.update(); | |
30 |
|
29 | |||
31 | // Trigger model displayed events for any models that are child to |
|
30 | // Trigger model displayed events for any models that are child to | |
32 | // this model when this model is displayed. |
|
31 | // this model when this model is displayed. | |
33 | var that = this; |
|
32 | var that = this; | |
34 |
this |
|
33 | this.on('displayed', function(){ | |
35 | that.is_displayed = true; |
|
34 | that.is_displayed = true; | |
36 | for (var property in that.child_views) { |
|
35 | for (var property in that.child_views) { | |
37 | if (that.child_views.hasOwnProperty(property)) { |
|
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 | remove_child_model: function(model) { |
|
51 | remove_child_model: function(model) { | |
53 | // Called when a model is removed from the children list. |
|
52 | // Called when a model is removed from the children list. | |
54 |
this.child_view |
|
53 | this.pop_child_view(model).remove(); | |
55 | this.delete_child_view(model); |
|
|||
56 | }, |
|
54 | }, | |
57 |
|
55 | |||
58 | add_child_model: function(model) { |
|
56 | add_child_model: function(model) { | |
@@ -62,7 +60,7 b' define(["widgets/js/widget"], function(WidgetManager) {' | |||||
62 |
|
60 | |||
63 | // Trigger the displayed event if this model is displayed. |
|
61 | // Trigger the displayed event if this model is displayed. | |
64 | if (this.is_displayed) { |
|
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 | render: function(){ |
|
79 | render: function(){ | |
82 | // Called when view is rendered. |
|
80 | // Called when view is rendered. | |
83 | var that = this; |
|
81 | var that = this; | |
84 | this.children={}; |
|
|||
85 |
|
82 | |||
86 | this.$el.on("remove", function(){ |
|
83 | this.$el.on("remove", function(){ | |
87 | that.$backdrop.remove(); |
|
84 | that.$backdrop.remove(); | |
@@ -187,19 +184,19 b' define(["widgets/js/widget"], function(WidgetManager) {' | |||||
187 | this._shown_once = false; |
|
184 | this._shown_once = false; | |
188 | this.popped_out = true; |
|
185 | this.popped_out = true; | |
189 |
|
186 | |||
190 |
this.update_children([], this.model.get(' |
|
187 | this.update_children([], this.model.get('children')); | |
191 |
this.model.on('change: |
|
188 | this.model.on('change:children', function(model, value, options) { | |
192 |
this.update_children(model.previous(' |
|
189 | this.update_children(model.previous('children'), value); | |
193 | }, this); |
|
190 | }, this); | |
194 | this.update(); |
|
191 | this.update(); | |
195 |
|
192 | |||
196 | // Trigger model displayed events for any models that are child to |
|
193 | // Trigger model displayed events for any models that are child to | |
197 | // this model when this model is displayed. |
|
194 | // this model when this model is displayed. | |
198 |
this |
|
195 | this.on('displayed', function(){ | |
199 | that.is_displayed = true; |
|
196 | that.is_displayed = true; | |
200 | for (var property in that.child_views) { |
|
197 | for (var property in that.child_views) { | |
201 | if (that.child_views.hasOwnProperty(property)) { |
|
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 | remove_child_model: function(model) { |
|
255 | remove_child_model: function(model) { | |
259 | // Called when a child is removed from children list. |
|
256 | // Called when a child is removed from children list. | |
260 |
this.child_view |
|
257 | this.pop_child_view(model).remove(); | |
261 | this.delete_child_view(model); |
|
|||
262 | }, |
|
258 | }, | |
263 |
|
259 | |||
264 | add_child_model: function(model) { |
|
260 | add_child_model: function(model) { | |
@@ -268,7 +264,7 b' define(["widgets/js/widget"], function(WidgetManager) {' | |||||
268 |
|
264 | |||
269 | // Trigger the displayed event if this model is displayed. |
|
265 | // Trigger the displayed event if this model is displayed. | |
270 | if (this.is_displayed) { |
|
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 | // one-to-one mapping with the corrosponding keys of the model. |
|
55 | // one-to-one mapping with the corrosponding keys of the model. | |
56 | var jquery_slider_keys = ['step', 'max', 'min', 'disabled']; |
|
56 | var jquery_slider_keys = ['step', 'max', 'min', 'disabled']; | |
57 | var that = this; |
|
57 | var that = this; | |
|
58 | that.$slider.slider({}); | |||
58 | _.each(jquery_slider_keys, function(key, i) { |
|
59 | _.each(jquery_slider_keys, function(key, i) { | |
59 | var model_value = that.model.get(key); |
|
60 | var model_value = that.model.get(key); | |
60 | if (model_value !== undefined) { |
|
61 | if (model_value !== undefined) { |
@@ -25,9 +25,9 b' define(["widgets/js/widget"], function(WidgetManager){' | |||||
25 | .addClass('panel-group'); |
|
25 | .addClass('panel-group'); | |
26 | this.containers = []; |
|
26 | this.containers = []; | |
27 | this.model_containers = {}; |
|
27 | this.model_containers = {}; | |
28 |
this.update_children([], this.model.get(' |
|
28 | this.update_children([], this.model.get('children')); | |
29 |
this.model.on('change: |
|
29 | this.model.on('change:children', function(model, value, options) { | |
30 |
this.update_children(model.previous(' |
|
30 | this.update_children(model.previous('children'), value); | |
31 | }, this); |
|
31 | }, this); | |
32 | this.model.on('change:selected_index', function(model, value, options) { |
|
32 | this.model.on('change:selected_index', function(model, value, options) { | |
33 | this.update_selected_index(model.previous('selected_index'), value, options); |
|
33 | this.update_selected_index(model.previous('selected_index'), value, options); | |
@@ -36,14 +36,14 b' define(["widgets/js/widget"], function(WidgetManager){' | |||||
36 | this.update_titles(value); |
|
36 | this.update_titles(value); | |
37 | }, this); |
|
37 | }, this); | |
38 | var that = this; |
|
38 | var that = this; | |
39 |
this |
|
39 | this.on('displayed', function() { | |
40 | this.update_titles(); |
|
40 | this.update_titles(); | |
41 | // Trigger model displayed events for any models that are child to |
|
41 | // Trigger model displayed events for any models that are child to | |
42 | // this model when this model is displayed. |
|
42 | // this model when this model is displayed. | |
43 | that.is_displayed = true; |
|
43 | that.is_displayed = true; | |
44 | for (var property in that.child_views) { |
|
44 | for (var property in that.child_views) { | |
45 | if (that.child_views.hasOwnProperty(property)) { |
|
45 | if (that.child_views.hasOwnProperty(property)) { | |
46 |
that.child_views[property]. |
|
46 | that.child_views[property].trigger('displayed'); | |
47 | } |
|
47 | } | |
48 | } |
|
48 | } | |
49 | }, this); |
|
49 | }, this); | |
@@ -92,7 +92,7 b' define(["widgets/js/widget"], function(WidgetManager){' | |||||
92 | this.containers.splice(accordion_group.container_index, 1); |
|
92 | this.containers.splice(accordion_group.container_index, 1); | |
93 | delete this.model_containers[model.id]; |
|
93 | delete this.model_containers[model.id]; | |
94 | accordion_group.remove(); |
|
94 | accordion_group.remove(); | |
95 |
this. |
|
95 | this.pop_child_view(model); | |
96 | }, |
|
96 | }, | |
97 |
|
97 | |||
98 | add_child_model: function(model) { |
|
98 | add_child_model: function(model) { | |
@@ -137,7 +137,7 b' define(["widgets/js/widget"], function(WidgetManager){' | |||||
137 |
|
137 | |||
138 | // Trigger the displayed event if this model is displayed. |
|
138 | // Trigger the displayed event if this model is displayed. | |
139 | if (this.is_displayed) { |
|
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 | .addClass('tab-content') |
|
163 | .addClass('tab-content') | |
164 | .appendTo(this.$el); |
|
164 | .appendTo(this.$el); | |
165 | this.containers = []; |
|
165 | this.containers = []; | |
166 |
this.update_children([], this.model.get(' |
|
166 | this.update_children([], this.model.get('children')); | |
167 |
this.model.on('change: |
|
167 | this.model.on('change:children', function(model, value, options) { | |
168 |
this.update_children(model.previous(' |
|
168 | this.update_children(model.previous('children'), value); | |
169 | }, this); |
|
169 | }, this); | |
170 |
|
170 | |||
171 | // Trigger model displayed events for any models that are child to |
|
171 | // Trigger model displayed events for any models that are child to | |
172 | // this model when this model is displayed. |
|
172 | // this model when this model is displayed. | |
173 |
this |
|
173 | this.on('displayed', function(){ | |
174 | that.is_displayed = true; |
|
174 | that.is_displayed = true; | |
175 | for (var property in that.child_views) { |
|
175 | for (var property in that.child_views) { | |
176 | if (that.child_views.hasOwnProperty(property)) { |
|
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 | remove_child_model: function(model) { |
|
191 | remove_child_model: function(model) { | |
192 | // Called when a child is removed from children list. |
|
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 | this.containers.splice(view.parent_tab.tab_text_index, 1); |
|
194 | this.containers.splice(view.parent_tab.tab_text_index, 1); | |
195 | view.parent_tab.remove(); |
|
195 | view.parent_tab.remove(); | |
196 | view.parent_container.remove(); |
|
196 | view.parent_container.remove(); | |
197 | view.remove(); |
|
197 | view.remove(); | |
198 | this.delete_child_view(model); |
|
|||
199 | }, |
|
198 | }, | |
200 |
|
199 | |||
201 | add_child_model: function(model) { |
|
200 | add_child_model: function(model) { | |
@@ -234,7 +233,7 b' define(["widgets/js/widget"], function(WidgetManager){' | |||||
234 |
|
233 | |||
235 | // Trigger the displayed event if this model is displayed. |
|
234 | // Trigger the displayed event if this model is displayed. | |
236 | if (this.is_displayed) { |
|
235 | if (this.is_displayed) { | |
237 |
|
|
236 | view.trigger('displayed'); | |
238 | } |
|
237 | } | |
239 | }, |
|
238 | }, | |
240 |
|
239 |
@@ -2,58 +2,29 b'' | |||||
2 |
|
2 | |||
3 | Represents a container that can be used to group other widgets. |
|
3 | Represents a container that can be used to group other widgets. | |
4 | """ |
|
4 | """ | |
5 | #----------------------------------------------------------------------------- |
|
5 | ||
6 |
# Copyright (c) |
|
6 | # Copyright (c) IPython Development Team. | |
7 | # |
|
|||
8 | # Distributed under the terms of the Modified BSD License. |
|
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 | from .widget import DOMWidget |
|
9 | from .widget import DOMWidget | |
17 | from IPython.utils.traitlets import Unicode, Tuple, TraitError |
|
10 | from IPython.utils.traitlets import Unicode, Tuple, TraitError | |
18 |
|
11 | |||
19 | #----------------------------------------------------------------------------- |
|
|||
20 | # Classes |
|
|||
21 | #----------------------------------------------------------------------------- |
|
|||
22 |
|
||||
23 | class ContainerWidget(DOMWidget): |
|
12 | class ContainerWidget(DOMWidget): | |
24 | _view_name = Unicode('ContainerView', sync=True) |
|
13 | _view_name = Unicode('ContainerView', sync=True) | |
25 |
|
14 | |||
26 | # Child widgets in the container. |
|
15 | # Child widgets in the container. | |
27 | # Using a tuple here to force reassignment to update the list. |
|
16 | # Using a tuple here to force reassignment to update the list. | |
28 | # When a proper notifying-list trait exists, that is what should be used here. |
|
17 | # When a proper notifying-list trait exists, that is what should be used here. | |
29 | children = Tuple() |
|
18 | children = Tuple(sync=True) | |
30 | _children = Tuple(sync=True) |
|
|||
31 |
|
||||
32 |
|
19 | |||
33 | def __init__(self, **kwargs): |
|
20 | def __init__(self, **kwargs): | |
34 | super(ContainerWidget, self).__init__(**kwargs) |
|
21 | super(ContainerWidget, self).__init__(**kwargs) | |
35 | self.on_displayed(ContainerWidget._fire_children_displayed) |
|
22 | self.on_displayed(ContainerWidget._fire_children_displayed) | |
36 |
|
23 | |||
37 | def _fire_children_displayed(self): |
|
24 | def _fire_children_displayed(self): | |
38 |
for child in self. |
|
25 | for child in self.children: | |
39 | child._handle_displayed() |
|
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 | class PopupWidget(ContainerWidget): |
|
29 | class PopupWidget(ContainerWidget): | |
59 | _view_name = Unicode('PopupView', sync=True) |
|
30 | _view_name = Unicode('PopupView', sync=True) |
General Comments 0
You need to be logged in to leave comments.
Login now