##// 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 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 delete_child_view: function(child_model, options) {
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(item);
364 removed_callback(old_list[j]);
337 }, this);
365 }
338
366
339 // added items
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(item);
369 added_callback(new_list[i]);
342 }, this);
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.model.on('displayed', function(){
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].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 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_views[model.id].remove();
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 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 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('_children'));
187 this.update_children([], this.model.get('children'));
191 this.model.on('change:_children', function(model, value, options) {
188 this.model.on('change:children', function(model, value, options) {
192 this.update_children(model.previous('_children'), value);
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.model.on('displayed', function(){
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].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 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_views[model.id].remove();
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 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 // 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('_children'));
28 this.update_children([], this.model.get('children'));
29 this.model.on('change:_children', function(model, value, options) {
29 this.model.on('change:children', function(model, value, options) {
30 this.update_children(model.previous('_children'), value);
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.model.on('displayed', function() {
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].model.trigger('displayed');
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.delete_child_view(model);
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 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 .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('_children'));
166 this.update_children([], this.model.get('children'));
167 this.model.on('change:_children', function(model, value, options) {
167 this.model.on('change:children', function(model, value, options) {
168 this.update_children(model.previous('_children'), value);
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.model.on('displayed', function(){
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].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 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_views[model.id];
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 model.trigger('displayed');
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) 2013, the IPython Development Team.
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._children:
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