##// END OF EJS Templates
Merge pull request #5963 from jdfreder/viewids...
Min RK -
r17186:c38a6218 merge
parent child Browse files
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 delete_child_view: function(child_model, options) {
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(item);
337 }, this);
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 // added items
340 _.each(_.difference(new_list, old_list), function(item, index, list) {
341 added_callback(item);
342 }, this);
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.model.on('displayed', function(){
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].model.trigger('displayed');
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_views[model.id].remove();
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 model.trigger('displayed');
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('_children'));
191 this.model.on('change:_children', function(model, value, options) {
192 this.update_children(model.previous('_children'), value);
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.model.on('displayed', function(){
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].model.trigger('displayed');
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_views[model.id].remove();
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 model.trigger('displayed');
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('_children'));
29 this.model.on('change:_children', function(model, value, options) {
30 this.update_children(model.previous('_children'), value);
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.model.on('displayed', function() {
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].model.trigger('displayed');
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.delete_child_view(model);
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 model.trigger('displayed');
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('_children'));
167 this.model.on('change:_children', function(model, value, options) {
168 this.update_children(model.previous('_children'), value);
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.model.on('displayed', function(){
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].model.trigger('displayed');
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_views[model.id];
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 model.trigger('displayed');
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) 2013, the IPython Development Team.
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._children:
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