##// END OF EJS Templates
Make dropdown view DOM swap elements on update.
Jonathan Frederic -
Show More
@@ -1,371 +1,375
1 1 //----------------------------------------------------------------------------
2 2 // Copyright (C) 2013 The IPython Development Team
3 3 //
4 4 // Distributed under the terms of the BSD License. The full license is in
5 5 // the file COPYING, distributed as part of this software.
6 6 //----------------------------------------------------------------------------
7 7
8 8 //============================================================================
9 9 // SelectionWidget
10 10 //============================================================================
11 11
12 12 /**
13 13 * @module IPython
14 14 * @namespace IPython
15 15 **/
16 16
17 17 define(["notebook/js/widgets/widget"], function(widget_manager){
18 18
19 19 var DropdownView = IPython.DOMWidgetView.extend({
20 20 render : function(){
21 21 // Called when view is rendered.
22 22 this.$el
23 23 .addClass('widget-hbox-single')
24 24 .html('');
25 25 this.$label = $('<div />')
26 26 .appendTo(this.$el)
27 27 .addClass('widget-hlabel')
28 28 .hide();
29 29 this.$buttongroup = $('<div />')
30 30 .addClass('widget_item')
31 31 .addClass('btn-group')
32 32 .appendTo(this.$el);
33 33 this.$el_to_style = this.$buttongroup; // Set default element to style
34 34 this.$droplabel = $('<button />')
35 35 .addClass('btn')
36 36 .addClass('widget-combo-btn')
37 37 .html('&nbsp;')
38 38 .appendTo(this.$buttongroup);
39 39 this.$dropbutton = $('<button />')
40 40 .addClass('btn')
41 41 .addClass('dropdown-toggle')
42 42 .addClass('widget-combo-carrot-btn')
43 43 .attr('data-toggle', 'dropdown')
44 44 .html('<span class="caret"></span>')
45 45 .appendTo(this.$buttongroup);
46 46 this.$droplist = $('<ul />')
47 47 .addClass('dropdown-menu')
48 48 .appendTo(this.$buttongroup);
49 49
50 50 // Set defaults.
51 51 this.update();
52 52 },
53 53
54 54 update : function(options){
55 55 // Update the contents of this view
56 56 //
57 57 // Called when the model is changed. The model may have been
58 58 // changed by another view or by a state update from the back-end.
59 59
60 60 if (options === undefined || options.updated_view != this) {
61 61 var selected_item_text = this.model.get('value');
62 62 selected_item_text = selected_item_text.replace(/ /g, '&nbsp;');
63 63 selected_item_text = selected_item_text.replace(/\n/g, '<br>\n');
64 64 if (selected_item_text.length === 0) {
65 65 this.$droplabel.html('&nbsp;');
66 66 } else {
67 67 this.$droplabel.html(selected_item_text);
68 68 }
69 69
70 70 var items = this.model.get('values');
71 this.$droplist.html('');
71 var $replace_droplist = $('<ul />')
72 .addClass('dropdown-menu');
72 73 for (var index in items) {
73 74 var that = this;
74 75 var item_button = $('<a href="#"/>')
75 76 .html(items[index])
76 77 .on('click', $.proxy(this.handle_click, this));
77 this.$droplist.append($('<li />').append(item_button));
78 $replace_droplist.append($('<li />').append(item_button));
78 79 }
80 this.$droplist.replaceWith($replace_droplist);
81 this.$droplist.remove();
82 this.$droplist = $replace_droplist;
79 83
80 84 if (this.model.get('disabled')) {
81 85 this.$buttongroup.attr('disabled','disabled');
82 86 this.$droplabel.attr('disabled','disabled');
83 87 this.$dropbutton.attr('disabled','disabled');
84 88 this.$droplist.attr('disabled','disabled');
85 89 } else {
86 90 this.$buttongroup.removeAttr('disabled');
87 91 this.$droplabel.removeAttr('disabled');
88 92 this.$dropbutton.removeAttr('disabled');
89 93 this.$droplist.removeAttr('disabled');
90 94 }
91 95
92 96 var description = this.model.get('description');
93 97 if (description.length === 0) {
94 98 this.$label.hide();
95 99 } else {
96 100 this.$label.html(description);
97 101 this.$label.show();
98 102 }
99 103 }
100 104 return DropdownView.__super__.update.apply(this);
101 105 },
102 106
103 107 handle_click: function (e) {
104 108 // Handle when a value is clicked.
105 109
106 110 // Calling model.set will trigger all of the other views of the
107 111 // model to update.
108 112 this.model.set('value', $(e.target).html(), {updated_view: this});
109 113 this.touch();
110 114 },
111 115
112 116 });
113 117 widget_manager.register_widget_view('DropdownView', DropdownView);
114 118
115 119
116 120 var RadioButtonsView = IPython.DOMWidgetView.extend({
117 121 render : function(){
118 122 // Called when view is rendered.
119 123 this.$el
120 124 .addClass('widget-hbox');
121 125 this.$label = $('<div />')
122 126 .appendTo(this.$el)
123 127 .addClass('widget-hlabel')
124 128 .hide();
125 129 this.$container = $('<div />')
126 130 .appendTo(this.$el)
127 131 .addClass('widget-container')
128 132 .addClass('vbox');
129 133 this.$el_to_style = this.$container; // Set default element to style
130 134 this.update();
131 135 },
132 136
133 137 update : function(options){
134 138 // Update the contents of this view
135 139 //
136 140 // Called when the model is changed. The model may have been
137 141 // changed by another view or by a state update from the back-end.
138 142 if (options === undefined || options.updated_view != this) {
139 143 // Add missing items to the DOM.
140 144 var items = this.model.get('values');
141 145 var disabled = this.model.get('disabled');
142 146 for (var index in items) {
143 147 var item_query = ' :input[value="' + items[index] + '"]';
144 148 if (this.$el.find(item_query).length === 0) {
145 149 var $label = $('<label />')
146 150 .addClass('radio')
147 151 .html(items[index])
148 152 .appendTo(this.$container);
149 153
150 154 $('<input />')
151 155 .attr('type', 'radio')
152 156 .addClass(this.model)
153 157 .val(items[index])
154 158 .prependTo($label)
155 159 .on('click', $.proxy(this.handle_click, this));
156 160 }
157 161
158 162 var $item_element = this.$container.find(item_query);
159 163 if (this.model.get('value') == items[index]) {
160 164 $item_element.prop('checked', true);
161 165 } else {
162 166 $item_element.prop('checked', false);
163 167 }
164 168 $item_element.prop('disabled', disabled);
165 169 }
166 170
167 171 // Remove items that no longer exist.
168 172 this.$container.find('input').each(function(i, obj) {
169 173 var value = $(obj).val();
170 174 var found = false;
171 175 for (var index in items) {
172 176 if (items[index] == value) {
173 177 found = true;
174 178 break;
175 179 }
176 180 }
177 181
178 182 if (!found) {
179 183 $(obj).parent().remove();
180 184 }
181 185 });
182 186
183 187 var description = this.model.get('description');
184 188 if (description.length === 0) {
185 189 this.$label.hide();
186 190 } else {
187 191 this.$label.html(description);
188 192 this.$label.show();
189 193 }
190 194 }
191 195 return RadioButtonsView.__super__.update.apply(this);
192 196 },
193 197
194 198 handle_click: function (e) {
195 199 // Handle when a value is clicked.
196 200
197 201 // Calling model.set will trigger all of the other views of the
198 202 // model to update.
199 203 this.model.set('value', $(e.target).val(), {updated_view: this});
200 204 this.touch();
201 205 },
202 206 });
203 207 widget_manager.register_widget_view('RadioButtonsView', RadioButtonsView);
204 208
205 209
206 210 var ToggleButtonsView = IPython.DOMWidgetView.extend({
207 211 render : function(){
208 212 // Called when view is rendered.
209 213 this.$el
210 214 .addClass('widget-hbox-single');
211 215 this.$label = $('<div />')
212 216 .appendTo(this.$el)
213 217 .addClass('widget-hlabel')
214 218 .hide();
215 219 this.$buttongroup = $('<div />')
216 220 .addClass('btn-group')
217 221 .attr('data-toggle', 'buttons-radio')
218 222 .appendTo(this.$el);
219 223 this.$el_to_style = this.$buttongroup; // Set default element to style
220 224 this.update();
221 225 },
222 226
223 227 update : function(options){
224 228 // Update the contents of this view
225 229 //
226 230 // Called when the model is changed. The model may have been
227 231 // changed by another view or by a state update from the back-end.
228 232 if (options === undefined || options.updated_view != this) {
229 233 // Add missing items to the DOM.
230 234 var items = this.model.get('values');
231 235 var disabled = this.model.get('disabled');
232 236 for (var index in items) {
233 237 var item_query = ' :contains("' + items[index] + '")';
234 238 if (this.$buttongroup.find(item_query).length === 0) {
235 239 $('<button />')
236 240 .attr('type', 'button')
237 241 .addClass('btn')
238 242 .html(items[index])
239 243 .appendTo(this.$buttongroup)
240 244 .on('click', $.proxy(this.handle_click, this));
241 245 }
242 246
243 247 var $item_element = this.$buttongroup.find(item_query);
244 248 if (this.model.get('value') == items[index]) {
245 249 $item_element.addClass('active');
246 250 } else {
247 251 $item_element.removeClass('active');
248 252 }
249 253 $item_element.prop('disabled', disabled);
250 254 }
251 255
252 256 // Remove items that no longer exist.
253 257 this.$buttongroup.find('button').each(function(i, obj) {
254 258 var value = $(obj).html();
255 259 var found = false;
256 260 for (var index in items) {
257 261 if (items[index] == value) {
258 262 found = true;
259 263 break;
260 264 }
261 265 }
262 266
263 267 if (!found) {
264 268 $(obj).remove();
265 269 }
266 270 });
267 271
268 272 var description = this.model.get('description');
269 273 if (description.length === 0) {
270 274 this.$label.hide();
271 275 } else {
272 276 this.$label.html(description);
273 277 this.$label.show();
274 278 }
275 279 }
276 280 return ToggleButtonsView.__super__.update.apply(this);
277 281 },
278 282
279 283 handle_click: function (e) {
280 284 // Handle when a value is clicked.
281 285
282 286 // Calling model.set will trigger all of the other views of the
283 287 // model to update.
284 288 this.model.set('value', $(e.target).html(), {updated_view: this});
285 289 this.touch();
286 290 },
287 291 });
288 292 widget_manager.register_widget_view('ToggleButtonsView', ToggleButtonsView);
289 293
290 294
291 295 var ListBoxView = IPython.DOMWidgetView.extend({
292 296 render : function(){
293 297 // Called when view is rendered.
294 298 this.$el
295 299 .addClass('widget-hbox');
296 300 this.$label = $('<div />')
297 301 .appendTo(this.$el)
298 302 .addClass('widget-hlabel')
299 303 .hide();
300 304 this.$listbox = $('<select />')
301 305 .addClass('widget-listbox')
302 306 .attr('size', 6)
303 307 .appendTo(this.$el);
304 308 this.$el_to_style = this.$listbox; // Set default element to style
305 309 this.update();
306 310 },
307 311
308 312 update : function(options){
309 313 // Update the contents of this view
310 314 //
311 315 // Called when the model is changed. The model may have been
312 316 // changed by another view or by a state update from the back-end.
313 317 if (options === undefined || options.updated_view != this) {
314 318 // Add missing items to the DOM.
315 319 var items = this.model.get('values');
316 320 for (var index in items) {
317 321 var item_query = ' :contains("' + items[index] + '")';
318 322 if (this.$listbox.find(item_query).length === 0) {
319 323 $('<option />')
320 324 .html(items[index])
321 325 .attr('value', items[index])
322 326 .appendTo(this.$listbox)
323 327 .on('click', $.proxy(this.handle_click, this));
324 328 }
325 329 }
326 330
327 331 // Select the correct element
328 332 this.$listbox.val(this.model.get('value'));
329 333
330 334 // Disable listbox if needed
331 335 var disabled = this.model.get('disabled');
332 336 this.$listbox.prop('disabled', disabled);
333 337
334 338 // Remove items that no longer exist.
335 339 this.$listbox.find('option').each(function(i, obj) {
336 340 var value = $(obj).html();
337 341 var found = false;
338 342 for (var index in items) {
339 343 if (items[index] == value) {
340 344 found = true;
341 345 break;
342 346 }
343 347 }
344 348
345 349 if (!found) {
346 350 $(obj).remove();
347 351 }
348 352 });
349 353
350 354 var description = this.model.get('description');
351 355 if (description.length === 0) {
352 356 this.$label.hide();
353 357 } else {
354 358 this.$label.html(description);
355 359 this.$label.show();
356 360 }
357 361 }
358 362 return ListBoxView.__super__.update.apply(this);
359 363 },
360 364
361 365 handle_click: function (e) {
362 366 // Handle when a value is clicked.
363 367
364 368 // Calling model.set will trigger all of the other views of the
365 369 // model to update.
366 370 this.model.set('value', $(e.target).html(), {updated_view: this});
367 371 this.touch();
368 372 },
369 373 });
370 374 widget_manager.register_widget_view('ListBoxView', ListBoxView);
371 375 });
General Comments 0
You need to be logged in to leave comments. Login now