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