##// END OF EJS Templates
Merge pull request #8550 from SylvainCorlay/Backport_ipython_ipywidets#22...
Min RK -
r21466:ded6199b merge
parent child Browse files
Show More
@@ -1,324 +1,324 b''
1 1 // Copyright (c) IPython Development Team.
2 2 // Distributed under the terms of the Modified BSD License.
3 3
4 4 define([
5 5 "widgets/js/widget",
6 6 "base/js/utils",
7 7 "jquery",
8 8 "bootstrap",
9 9 ], function(widget, utils, $){
10 10
11 11 var AccordionView = widget.DOMWidgetView.extend({
12 12 initialize: function(){
13 13 AccordionView.__super__.initialize.apply(this, arguments);
14 14
15 15 this.containers = [];
16 16 this.model_containers = {};
17 17 this.children_views = new widget.ViewList(this.add_child_view, this.remove_child_view, this);
18 18 this.listenTo(this.model, 'change:children', function(model, value) {
19 19 this.children_views.update(value);
20 20 }, this);
21 21 },
22 22
23 23 render: function(){
24 24 /**
25 25 * Called when view is rendered.
26 26 */
27 27 var guid = 'panel-group' + utils.uuid();
28 28 this.$el
29 29 .attr('id', guid)
30 30 .addClass('panel-group');
31 31 this.model.on('change:selected_index', function(model, value, options) {
32 32 this.update_selected_index(options);
33 33 }, this);
34 34 this.model.on('change:_titles', function(model, value, options) {
35 35 this.update_titles(options);
36 36 }, this);
37 37 this.on('displayed', function() {
38 38 this.update_titles();
39 39 }, this);
40 40 this.children_views.update(this.model.get('children'));
41 41 },
42 42
43 43 /**
44 44 * Update the contents of this view
45 45 *
46 46 * Called when the model is changed. The model may have been
47 47 * changed by another view or by a state update from the back-end.
48 48 */
49 49 update: function(options) {
50 50 this.update_titles();
51 51 this.update_selected_index(options);
52 52 return TabView.__super__.update.apply(this);
53 53 },
54 54
55 55 update_titles: function() {
56 56 /**
57 57 * Set tab titles
58 58 */
59 59 var titles = this.model.get('_titles');
60 60 var that = this;
61 61 _.each(titles, function(title, page_index) {
62 62 var accordian = that.containers[page_index];
63 63 if (accordian !== undefined) {
64 64 accordian
65 65 .find('.panel-heading')
66 66 .find('.accordion-toggle')
67 67 .text(title);
68 68 }
69 69 });
70 70 },
71 71
72 72 update_selected_index: function(options) {
73 73 /**
74 74 * Only update the selection if the selection wasn't triggered
75 75 * by the front-end. It must be triggered by the back-end.
76 76 */
77 77 if (options === undefined || options.updated_view != this) {
78 78 var old_index = this.model.previous('selected_index');
79 79 var new_index = this.model.get('selected_index');
80 80 this.containers[old_index].find('.panel-collapse').collapse('hide');
81 81 if (0 <= new_index && new_index < this.containers.length) {
82 82 this.containers[new_index].find('.panel-collapse').collapse('show');
83 83 }
84 84 }
85 85 },
86 86
87 87 remove_child_view: function(view) {
88 88 /**
89 89 * Called when a child is removed from children list.
90 90 * TODO: does this handle two different views of the same model as children?
91 91 */
92 92 var model = view.model;
93 93 var accordion_group = this.model_containers[model.id];
94 94 this.containers.splice(accordion_group.container_index, 1);
95 95 delete this.model_containers[model.id];
96 96 accordion_group.remove();
97 97 },
98 98
99 99 add_child_view: function(model) {
100 100 /**
101 101 * Called when a child is added to children list.
102 102 */
103 103 var index = this.containers.length;
104 104 var uuid = utils.uuid();
105 105 var accordion_group = $('<div />')
106 106 .addClass('panel panel-default')
107 107 .appendTo(this.$el);
108 108 var accordion_heading = $('<div />')
109 109 .addClass('panel-heading')
110 110 .appendTo(accordion_group);
111 111 var that = this;
112 112 var accordion_toggle = $('<a />')
113 113 .addClass('accordion-toggle')
114 114 .attr('data-toggle', 'collapse')
115 115 .attr('data-parent', '#' + this.$el.attr('id'))
116 116 .attr('href', '#' + uuid)
117 117 .click(function(evt){
118 118
119 119 // Calling model.set will trigger all of the other views of the
120 120 // model to update.
121 121 that.model.set("selected_index", index, {updated_view: that});
122 122 that.touch();
123 123 })
124 124 .text('Page ' + index)
125 125 .appendTo(accordion_heading);
126 126 var accordion_body = $('<div />', {id: uuid})
127 127 .addClass('panel-collapse collapse')
128 128 .appendTo(accordion_group);
129 129 var accordion_inner = $('<div />')
130 130 .addClass('panel-body')
131 131 .appendTo(accordion_body);
132 132 var container_index = this.containers.push(accordion_group) - 1;
133 133 accordion_group.container_index = container_index;
134 134 this.model_containers[model.id] = accordion_group;
135 135
136 136 var dummy = $('<div/>');
137 137 accordion_inner.append(dummy);
138 138 return this.create_child_view(model).then(function(view) {
139 139 dummy.replaceWith(view.$el);
140 140 that.update();
141 141 that.update_titles();
142 142
143 143 // Trigger the displayed event of the child view.
144 144 that.after_displayed(function() {
145 145 view.trigger('displayed');
146 146 });
147 147 return view;
148 148 }).catch(utils.reject("Couldn't add child view to box", true));
149 149 },
150 150
151 151 remove: function() {
152 152 /**
153 153 * We remove this widget before removing the children as an optimization
154 154 * we want to remove the entire container from the DOM first before
155 155 * removing each individual child separately.
156 156 */
157 157 AccordionView.__super__.remove.apply(this, arguments);
158 158 this.children_views.remove();
159 159 },
160 160 });
161 161
162 162
163 163 var TabView = widget.DOMWidgetView.extend({
164 164 initialize: function() {
165 165 /**
166 166 * Public constructor.
167 167 */
168 168 TabView.__super__.initialize.apply(this, arguments);
169 169
170 170 this.containers = [];
171 171 this.children_views = new widget.ViewList(this.add_child_view, this.remove_child_view, this);
172 172 this.listenTo(this.model, 'change:children', function(model, value) {
173 173 this.children_views.update(value);
174 174 }, this);
175 175 },
176 176
177 177 render: function(){
178 178 /**
179 179 * Called when view is rendered.
180 180 */
181 181 var uuid = 'tabs'+utils.uuid();
182 182 this.$tabs = $('<div />', {id: uuid})
183 183 .addClass('nav')
184 184 .addClass('nav-tabs')
185 185 .appendTo(this.$el);
186 186 this.$tab_contents = $('<div />', {id: uuid + 'Content'})
187 187 .addClass('tab-content')
188 188 .appendTo(this.$el);
189 189 this.children_views.update(this.model.get('children'));
190 190 },
191 191
192 192 update_attr: function(name, value) {
193 193 /**
194 194 * Set a css attr of the widget view.
195 195 */
196 if (name == 'padding' || name == 'margin') {
196 if (['padding', 'margin', 'height', 'width'].indexOf(name) !== -1) {
197 197 this.$el.css(name, value);
198 198 } else {
199 199 this.$tabs.css(name, value);
200 200 }
201 201 },
202 202
203 203 remove_child_view: function(view) {
204 204 /**
205 205 * Called when a child is removed from children list.
206 206 */
207 207 this.containers.splice(view.parent_tab.tab_text_index, 1);
208 208 view.parent_tab.remove();
209 209 view.parent_container.remove();
210 210 view.remove();
211 211 },
212 212
213 213 add_child_view: function(model) {
214 214 /**
215 215 * Called when a child is added to children list.
216 216 */
217 217 var index = this.containers.length;
218 218 var uuid = utils.uuid();
219 219
220 220 var that = this;
221 221 var tab = $('<li />')
222 222 .css('list-style-type', 'none')
223 223 .appendTo(this.$tabs);
224 224
225 225 var tab_text = $('<a />')
226 226 .attr('href', '#' + uuid)
227 227 .attr('data-toggle', 'tab')
228 228 .text('Page ' + index)
229 229 .appendTo(tab)
230 230 .click(function (e) {
231 231
232 232 // Calling model.set will trigger all of the other views of the
233 233 // model to update.
234 234 that.model.set("selected_index", index, {updated_view: that});
235 235 that.touch();
236 236 that.select_page(index);
237 237 });
238 238 tab.tab_text_index = that.containers.push(tab_text) - 1;
239 239
240 240 var dummy = $('<div />');
241 241 var contents_div = $('<div />', {id: uuid})
242 242 .addClass('tab-pane')
243 243 .addClass('fade')
244 244 .append(dummy)
245 245 .appendTo(that.$tab_contents);
246 246
247 247 this.update();
248 248 return this.create_child_view(model).then(function(view) {
249 249 dummy.replaceWith(view.$el);
250 250 view.parent_tab = tab;
251 251 view.parent_container = contents_div;
252 252
253 253 // Trigger the displayed event of the child view.
254 254 that.after_displayed(function() {
255 255 view.trigger('displayed');
256 256 that.update();
257 257 });
258 258 return view;
259 259 }).catch(utils.reject("Couldn't add child view to box", true));
260 260 },
261 261
262 262 update: function(options) {
263 263 /**
264 264 * Update the contents of this view
265 265 *
266 266 * Called when the model is changed. The model may have been
267 267 * changed by another view or by a state update from the back-end.
268 268 */
269 269 this.update_titles();
270 270 this.update_selected_index(options);
271 271 return TabView.__super__.update.apply(this);
272 272 },
273 273
274 274 /**
275 275 * Updates the tab page titles.
276 276 */
277 277 update_titles: function() {
278 278 var titles = this.model.get('_titles');
279 279 var that = this;
280 280 _.each(titles, function(title, page_index) {
281 281 var tab_text = that.containers[page_index];
282 282 if (tab_text !== undefined) {
283 283 tab_text.text(title);
284 284 }
285 285 });
286 286 },
287 287
288 288 /**
289 289 * Updates the tab page titles.
290 290 */
291 291 update_selected_index: function(options) {
292 292 if (options === undefined || options.updated_view != this) {
293 293 var selected_index = this.model.get('selected_index');
294 294 if (0 <= selected_index && selected_index < this.containers.length) {
295 295 this.select_page(selected_index);
296 296 }
297 297 }
298 298 },
299 299
300 300 select_page: function(index) {
301 301 /**
302 302 * Select a page.
303 303 */
304 304 this.$tabs.find('li')
305 305 .removeClass('active');
306 306 this.containers[index].tab('show');
307 307 },
308 308
309 309 remove: function() {
310 310 /**
311 311 * We remove this widget before removing the children as an optimization
312 312 * we want to remove the entire container from the DOM first before
313 313 * removing each individual child separately.
314 314 */
315 315 TabView.__super__.remove.apply(this, arguments);
316 316 this.children_views.remove();
317 317 },
318 318 });
319 319
320 320 return {
321 321 'AccordionView': AccordionView,
322 322 'TabView': TabView,
323 323 };
324 324 });
General Comments 0
You need to be logged in to leave comments. Login now