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