##// END OF EJS Templates
Merge pull request #8027 from bollwyvl/fix-select-multiple...
Min RK -
r20695:883fe6f3 merge
parent child Browse files
Show More
@@ -1,583 +1,592 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 "underscore",
8 "underscore",
9 "bootstrap",
9 "bootstrap",
10 ], function(widget, utils, $, _){
10 ], function(widget, utils, $, _){
11
11
12 var DropdownView = widget.DOMWidgetView.extend({
12 var DropdownView = widget.DOMWidgetView.extend({
13 render : function(){
13 render : function(){
14 /**
14 /**
15 * Called when view is rendered.
15 * Called when view is rendered.
16 */
16 */
17 this.$el
17 this.$el
18 .addClass('widget-hbox widget-dropdown');
18 .addClass('widget-hbox widget-dropdown');
19 this.$label = $('<div />')
19 this.$label = $('<div />')
20 .appendTo(this.$el)
20 .appendTo(this.$el)
21 .addClass('widget-label')
21 .addClass('widget-label')
22 .hide();
22 .hide();
23 this.$buttongroup = $('<div />')
23 this.$buttongroup = $('<div />')
24 .addClass('widget_item')
24 .addClass('widget_item')
25 .addClass('btn-group')
25 .addClass('btn-group')
26 .appendTo(this.$el);
26 .appendTo(this.$el);
27 this.$droplabel = $('<button />')
27 this.$droplabel = $('<button />')
28 .addClass('btn btn-default')
28 .addClass('btn btn-default')
29 .addClass('widget-combo-btn')
29 .addClass('widget-combo-btn')
30 .html("&nbsp;")
30 .html("&nbsp;")
31 .appendTo(this.$buttongroup);
31 .appendTo(this.$buttongroup);
32 this.$dropbutton = $('<button />')
32 this.$dropbutton = $('<button />')
33 .addClass('btn btn-default')
33 .addClass('btn btn-default')
34 .addClass('dropdown-toggle')
34 .addClass('dropdown-toggle')
35 .addClass('widget-combo-carrot-btn')
35 .addClass('widget-combo-carrot-btn')
36 .attr('data-toggle', 'dropdown')
36 .attr('data-toggle', 'dropdown')
37 .append($('<span />').addClass("caret"))
37 .append($('<span />').addClass("caret"))
38 .appendTo(this.$buttongroup);
38 .appendTo(this.$buttongroup);
39 this.$droplist = $('<ul />')
39 this.$droplist = $('<ul />')
40 .addClass('dropdown-menu')
40 .addClass('dropdown-menu')
41 .appendTo(this.$buttongroup);
41 .appendTo(this.$buttongroup);
42
42
43 this.model.on('change:button_style', function(model, value) {
43 this.model.on('change:button_style', function(model, value) {
44 this.update_button_style();
44 this.update_button_style();
45 }, this);
45 }, this);
46 this.update_button_style('');
46 this.update_button_style('');
47
47
48 // Set defaults.
48 // Set defaults.
49 this.update();
49 this.update();
50 },
50 },
51
51
52 update : function(options){
52 update : function(options){
53 /**
53 /**
54 * Update the contents of this view
54 * Update the contents of this view
55 *
55 *
56 * Called when the model is changed. The model may have been
56 * Called when the model is changed. The model may have been
57 * changed by another view or by a state update from the back-end.
57 * changed by another view or by a state update from the back-end.
58 */
58 */
59
59
60 if (options === undefined || options.updated_view != this) {
60 if (options === undefined || options.updated_view != this) {
61 var selected_item_text = this.model.get('selected_label');
61 var selected_item_text = this.model.get('selected_label');
62 if (selected_item_text.trim().length === 0) {
62 if (selected_item_text.trim().length === 0) {
63 this.$droplabel.html("&nbsp;");
63 this.$droplabel.html("&nbsp;");
64 } else {
64 } else {
65 this.$droplabel.text(selected_item_text);
65 this.$droplabel.text(selected_item_text);
66 }
66 }
67
67
68 var items = this.model.get('_options_labels');
68 var items = this.model.get('_options_labels');
69 var $replace_droplist = $('<ul />')
69 var $replace_droplist = $('<ul />')
70 .addClass('dropdown-menu');
70 .addClass('dropdown-menu');
71 // Copy the style
71 // Copy the style
72 $replace_droplist.attr('style', this.$droplist.attr('style'));
72 $replace_droplist.attr('style', this.$droplist.attr('style'));
73 var that = this;
73 var that = this;
74 _.each(items, function(item, i) {
74 _.each(items, function(item, i) {
75 var item_button = $('<a href="#"/>')
75 var item_button = $('<a href="#"/>')
76 .text(item)
76 .text(item)
77 .on('click', $.proxy(that.handle_click, that));
77 .on('click', $.proxy(that.handle_click, that));
78 $replace_droplist.append($('<li />').append(item_button));
78 $replace_droplist.append($('<li />').append(item_button));
79 });
79 });
80
80
81 this.$droplist.replaceWith($replace_droplist);
81 this.$droplist.replaceWith($replace_droplist);
82 this.$droplist.remove();
82 this.$droplist.remove();
83 this.$droplist = $replace_droplist;
83 this.$droplist = $replace_droplist;
84
84
85 if (this.model.get('disabled')) {
85 if (this.model.get('disabled')) {
86 this.$buttongroup.attr('disabled','disabled');
86 this.$buttongroup.attr('disabled','disabled');
87 this.$droplabel.attr('disabled','disabled');
87 this.$droplabel.attr('disabled','disabled');
88 this.$dropbutton.attr('disabled','disabled');
88 this.$dropbutton.attr('disabled','disabled');
89 this.$droplist.attr('disabled','disabled');
89 this.$droplist.attr('disabled','disabled');
90 } else {
90 } else {
91 this.$buttongroup.removeAttr('disabled');
91 this.$buttongroup.removeAttr('disabled');
92 this.$droplabel.removeAttr('disabled');
92 this.$droplabel.removeAttr('disabled');
93 this.$dropbutton.removeAttr('disabled');
93 this.$dropbutton.removeAttr('disabled');
94 this.$droplist.removeAttr('disabled');
94 this.$droplist.removeAttr('disabled');
95 }
95 }
96
96
97 var description = this.model.get('description');
97 var description = this.model.get('description');
98 if (description.length === 0) {
98 if (description.length === 0) {
99 this.$label.hide();
99 this.$label.hide();
100 } else {
100 } else {
101 this.typeset(this.$label, description);
101 this.typeset(this.$label, description);
102 this.$label.show();
102 this.$label.show();
103 }
103 }
104 }
104 }
105 return DropdownView.__super__.update.apply(this);
105 return DropdownView.__super__.update.apply(this);
106 },
106 },
107
107
108 update_button_style: function(previous_trait_value) {
108 update_button_style: function(previous_trait_value) {
109 var class_map = {
109 var class_map = {
110 primary: ['btn-primary'],
110 primary: ['btn-primary'],
111 success: ['btn-success'],
111 success: ['btn-success'],
112 info: ['btn-info'],
112 info: ['btn-info'],
113 warning: ['btn-warning'],
113 warning: ['btn-warning'],
114 danger: ['btn-danger']
114 danger: ['btn-danger']
115 };
115 };
116 this.update_mapped_classes(class_map, 'button_style', previous_trait_value, this.$droplabel);
116 this.update_mapped_classes(class_map, 'button_style', previous_trait_value, this.$droplabel);
117 this.update_mapped_classes(class_map, 'button_style', previous_trait_value, this.$dropbutton);
117 this.update_mapped_classes(class_map, 'button_style', previous_trait_value, this.$dropbutton);
118 },
118 },
119
119
120 update_attr: function(name, value) {
120 update_attr: function(name, value) {
121 /**
121 /**
122 * Set a css attr of the widget view.
122 * Set a css attr of the widget view.
123 */
123 */
124 if (name.substring(0, 6) == 'border' || name == 'background' || name == 'color') {
124 if (name.substring(0, 6) == 'border' || name == 'background' || name == 'color') {
125 this.$droplabel.css(name, value);
125 this.$droplabel.css(name, value);
126 this.$dropbutton.css(name, value);
126 this.$dropbutton.css(name, value);
127 this.$droplist.css(name, value);
127 this.$droplist.css(name, value);
128 } else if (name == 'width') {
128 } else if (name == 'width') {
129 this.$droplist.css(name, value);
129 this.$droplist.css(name, value);
130 this.$droplabel.css(name, value);
130 this.$droplabel.css(name, value);
131 } else if (name == 'padding') {
131 } else if (name == 'padding') {
132 this.$droplist.css(name, value);
132 this.$droplist.css(name, value);
133 this.$buttongroup.css(name, value);
133 this.$buttongroup.css(name, value);
134 } else if (name == 'margin') {
134 } else if (name == 'margin') {
135 this.$buttongroup.css(name, value);
135 this.$buttongroup.css(name, value);
136 } else if (name == 'height') {
136 } else if (name == 'height') {
137 this.$droplabel.css(name, value);
137 this.$droplabel.css(name, value);
138 this.$dropbutton.css(name, value);
138 this.$dropbutton.css(name, value);
139 } else if (name == 'padding' || name == 'margin') {
139 } else if (name == 'padding' || name == 'margin') {
140 this.$el.css(name, value);
140 this.$el.css(name, value);
141 } else {
141 } else {
142 this.$droplist.css(name, value);
142 this.$droplist.css(name, value);
143 this.$droplabel.css(name, value);
143 this.$droplabel.css(name, value);
144 }
144 }
145 },
145 },
146
146
147 handle_click: function (e) {
147 handle_click: function (e) {
148 /**
148 /**
149 * Handle when a value is clicked.
149 * Handle when a value is clicked.
150 *
150 *
151 * Calling model.set will trigger all of the other views of the
151 * Calling model.set will trigger all of the other views of the
152 * model to update.
152 * model to update.
153 */
153 */
154 this.model.set('selected_label', $(e.target).text(), {updated_view: this});
154 this.model.set('selected_label', $(e.target).text(), {updated_view: this});
155 this.touch();
155 this.touch();
156
156
157 // Manually hide the droplist.
157 // Manually hide the droplist.
158 e.stopPropagation();
158 e.stopPropagation();
159 e.preventDefault();
159 e.preventDefault();
160 this.$buttongroup.removeClass('open');
160 this.$buttongroup.removeClass('open');
161 },
161 },
162
162
163 });
163 });
164
164
165
165
166 var RadioButtonsView = widget.DOMWidgetView.extend({
166 var RadioButtonsView = widget.DOMWidgetView.extend({
167 render : function(){
167 render : function(){
168 /**
168 /**
169 * Called when view is rendered.
169 * Called when view is rendered.
170 */
170 */
171 this.$el
171 this.$el
172 .addClass('widget-hbox widget-radio');
172 .addClass('widget-hbox widget-radio');
173 this.$label = $('<div />')
173 this.$label = $('<div />')
174 .appendTo(this.$el)
174 .appendTo(this.$el)
175 .addClass('widget-label')
175 .addClass('widget-label')
176 .hide();
176 .hide();
177 this.$container = $('<div />')
177 this.$container = $('<div />')
178 .appendTo(this.$el)
178 .appendTo(this.$el)
179 .addClass('widget-radio-box');
179 .addClass('widget-radio-box');
180 this.update();
180 this.update();
181 },
181 },
182
182
183 update : function(options){
183 update : function(options){
184 /**
184 /**
185 * Update the contents of this view
185 * Update the contents of this view
186 *
186 *
187 * Called when the model is changed. The model may have been
187 * Called when the model is changed. The model may have been
188 * changed by another view or by a state update from the back-end.
188 * changed by another view or by a state update from the back-end.
189 */
189 */
190 if (options === undefined || options.updated_view != this) {
190 if (options === undefined || options.updated_view != this) {
191 // Add missing items to the DOM.
191 // Add missing items to the DOM.
192 var items = this.model.get('_options_labels');
192 var items = this.model.get('_options_labels');
193 var disabled = this.model.get('disabled');
193 var disabled = this.model.get('disabled');
194 var that = this;
194 var that = this;
195 _.each(items, function(item, index) {
195 _.each(items, function(item, index) {
196 var item_query = ' :input[data-value="' + encodeURIComponent(item) + '"]';
196 var item_query = ' :input[data-value="' + encodeURIComponent(item) + '"]';
197 if (that.$el.find(item_query).length === 0) {
197 if (that.$el.find(item_query).length === 0) {
198 var $label = $('<label />')
198 var $label = $('<label />')
199 .addClass('radio')
199 .addClass('radio')
200 .text(item)
200 .text(item)
201 .appendTo(that.$container);
201 .appendTo(that.$container);
202
202
203 $('<input />')
203 $('<input />')
204 .attr('type', 'radio')
204 .attr('type', 'radio')
205 .addClass(that.model)
205 .addClass(that.model)
206 .val(item)
206 .val(item)
207 .attr('data-value', encodeURIComponent(item))
207 .attr('data-value', encodeURIComponent(item))
208 .prependTo($label)
208 .prependTo($label)
209 .on('click', $.proxy(that.handle_click, that));
209 .on('click', $.proxy(that.handle_click, that));
210 }
210 }
211
211
212 var $item_element = that.$container.find(item_query);
212 var $item_element = that.$container.find(item_query);
213 if (that.model.get('selected_label') == item) {
213 if (that.model.get('selected_label') == item) {
214 $item_element.prop('checked', true);
214 $item_element.prop('checked', true);
215 } else {
215 } else {
216 $item_element.prop('checked', false);
216 $item_element.prop('checked', false);
217 }
217 }
218 $item_element.prop('disabled', disabled);
218 $item_element.prop('disabled', disabled);
219 });
219 });
220
220
221 // Remove items that no longer exist.
221 // Remove items that no longer exist.
222 this.$container.find('input').each(function(i, obj) {
222 this.$container.find('input').each(function(i, obj) {
223 var value = $(obj).val();
223 var value = $(obj).val();
224 var found = false;
224 var found = false;
225 _.each(items, function(item, index) {
225 _.each(items, function(item, index) {
226 if (item == value) {
226 if (item == value) {
227 found = true;
227 found = true;
228 return false;
228 return false;
229 }
229 }
230 });
230 });
231
231
232 if (!found) {
232 if (!found) {
233 $(obj).parent().remove();
233 $(obj).parent().remove();
234 }
234 }
235 });
235 });
236
236
237 var description = this.model.get('description');
237 var description = this.model.get('description');
238 if (description.length === 0) {
238 if (description.length === 0) {
239 this.$label.hide();
239 this.$label.hide();
240 } else {
240 } else {
241 this.$label.text(description);
241 this.$label.text(description);
242 this.typeset(this.$label, description);
242 this.typeset(this.$label, description);
243 this.$label.show();
243 this.$label.show();
244 }
244 }
245 }
245 }
246 return RadioButtonsView.__super__.update.apply(this);
246 return RadioButtonsView.__super__.update.apply(this);
247 },
247 },
248
248
249 update_attr: function(name, value) {
249 update_attr: function(name, value) {
250 /**
250 /**
251 * Set a css attr of the widget view.
251 * Set a css attr of the widget view.
252 */
252 */
253 if (name == 'padding' || name == 'margin') {
253 if (name == 'padding' || name == 'margin') {
254 this.$el.css(name, value);
254 this.$el.css(name, value);
255 } else {
255 } else {
256 this.$container.css(name, value);
256 this.$container.css(name, value);
257 }
257 }
258 },
258 },
259
259
260 handle_click: function (e) {
260 handle_click: function (e) {
261 /**
261 /**
262 * Handle when a value is clicked.
262 * Handle when a value is clicked.
263 *
263 *
264 * Calling model.set will trigger all of the other views of the
264 * Calling model.set will trigger all of the other views of the
265 * model to update.
265 * model to update.
266 */
266 */
267 this.model.set('selected_label', $(e.target).val(), {updated_view: this});
267 this.model.set('selected_label', $(e.target).val(), {updated_view: this});
268 this.touch();
268 this.touch();
269 },
269 },
270 });
270 });
271
271
272
272
273 var ToggleButtonsView = widget.DOMWidgetView.extend({
273 var ToggleButtonsView = widget.DOMWidgetView.extend({
274 initialize: function() {
274 initialize: function() {
275 this._css_state = {};
275 this._css_state = {};
276 ToggleButtonsView.__super__.initialize.apply(this, arguments);
276 ToggleButtonsView.__super__.initialize.apply(this, arguments);
277 },
277 },
278
278
279 render: function() {
279 render: function() {
280 /**
280 /**
281 * Called when view is rendered.
281 * Called when view is rendered.
282 */
282 */
283 this.$el
283 this.$el
284 .addClass('widget-hbox widget-toggle-buttons');
284 .addClass('widget-hbox widget-toggle-buttons');
285 this.$label = $('<div />')
285 this.$label = $('<div />')
286 .appendTo(this.$el)
286 .appendTo(this.$el)
287 .addClass('widget-label')
287 .addClass('widget-label')
288 .hide();
288 .hide();
289 this.$buttongroup = $('<div />')
289 this.$buttongroup = $('<div />')
290 .addClass('btn-group')
290 .addClass('btn-group')
291 .appendTo(this.$el);
291 .appendTo(this.$el);
292
292
293 this.model.on('change:button_style', function(model, value) {
293 this.model.on('change:button_style', function(model, value) {
294 this.update_button_style();
294 this.update_button_style();
295 }, this);
295 }, this);
296 this.update_button_style('');
296 this.update_button_style('');
297 this.update();
297 this.update();
298 },
298 },
299
299
300 update : function(options){
300 update : function(options){
301 /**
301 /**
302 * Update the contents of this view
302 * Update the contents of this view
303 *
303 *
304 * Called when the model is changed. The model may have been
304 * Called when the model is changed. The model may have been
305 * changed by another view or by a state update from the back-end.
305 * changed by another view or by a state update from the back-end.
306 */
306 */
307 if (options === undefined || options.updated_view != this) {
307 if (options === undefined || options.updated_view != this) {
308 // Add missing items to the DOM.
308 // Add missing items to the DOM.
309 var items = this.model.get('_options_labels');
309 var items = this.model.get('_options_labels');
310 var icons = this.model.get('icons');
310 var icons = this.model.get('icons');
311 var previous_icons = this.model.previous('icons') || [];
311 var previous_icons = this.model.previous('icons') || [];
312 var disabled = this.model.get('disabled');
312 var disabled = this.model.get('disabled');
313 var that = this;
313 var that = this;
314 var item_html;
314 var item_html;
315 _.each(items, function(item, index) {
315 _.each(items, function(item, index) {
316 if (item.trim().length === 0 && (!icons[index] ||
316 if (item.trim().length === 0 && (!icons[index] ||
317 icons[index].trim().length === 0)) {
317 icons[index].trim().length === 0)) {
318 item_html = "&nbsp;";
318 item_html = "&nbsp;";
319 } else {
319 } else {
320 item_html = utils.escape_html(item);
320 item_html = utils.escape_html(item);
321 }
321 }
322 var item_query = '[data-value="' + encodeURIComponent(item) + '"]';
322 var item_query = '[data-value="' + encodeURIComponent(item) + '"]';
323 var $item_element = that.$buttongroup.find(item_query);
323 var $item_element = that.$buttongroup.find(item_query);
324 var $icon_element = $item_element.find('.fa');
324 var $icon_element = $item_element.find('.fa');
325 if (!$item_element.length) {
325 if (!$item_element.length) {
326 $item_element = $('<button/>')
326 $item_element = $('<button/>')
327 .attr('type', 'button')
327 .attr('type', 'button')
328 .addClass('btn btn-default')
328 .addClass('btn btn-default')
329 .html(item_html)
329 .html(item_html)
330 .appendTo(that.$buttongroup)
330 .appendTo(that.$buttongroup)
331 .attr('data-value', encodeURIComponent(item))
331 .attr('data-value', encodeURIComponent(item))
332 .attr('data-toggle', 'tooltip')
332 .attr('data-toggle', 'tooltip')
333 .attr('value', item)
333 .attr('value', item)
334 .on('click', $.proxy(that.handle_click, that));
334 .on('click', $.proxy(that.handle_click, that));
335 that.update_style_traits($item_element);
335 that.update_style_traits($item_element);
336 $icon_element = $('<i class="fa"></i>').prependTo($item_element);
336 $icon_element = $('<i class="fa"></i>').prependTo($item_element);
337 }
337 }
338 if (that.model.get('selected_label') == item) {
338 if (that.model.get('selected_label') == item) {
339 $item_element.addClass('active');
339 $item_element.addClass('active');
340 } else {
340 } else {
341 $item_element.removeClass('active');
341 $item_element.removeClass('active');
342 }
342 }
343 $item_element.prop('disabled', disabled);
343 $item_element.prop('disabled', disabled);
344 $item_element.attr('title', that.model.get('tooltips')[index]);
344 $item_element.attr('title', that.model.get('tooltips')[index]);
345 $icon_element
345 $icon_element
346 .removeClass(previous_icons[index])
346 .removeClass(previous_icons[index])
347 .addClass(icons[index]);
347 .addClass(icons[index]);
348 });
348 });
349
349
350 // Remove items that no longer exist.
350 // Remove items that no longer exist.
351 this.$buttongroup.find('button').each(function(i, obj) {
351 this.$buttongroup.find('button').each(function(i, obj) {
352 var value = $(obj).attr('value');
352 var value = $(obj).attr('value');
353 var found = false;
353 var found = false;
354 _.each(items, function(item, index) {
354 _.each(items, function(item, index) {
355 if (item == value) {
355 if (item == value) {
356 found = true;
356 found = true;
357 return false;
357 return false;
358 }
358 }
359 });
359 });
360
360
361 if (!found) {
361 if (!found) {
362 $(obj).remove();
362 $(obj).remove();
363 }
363 }
364 });
364 });
365
365
366 var description = this.model.get('description');
366 var description = this.model.get('description');
367 if (description.length === 0) {
367 if (description.length === 0) {
368 this.$label.hide();
368 this.$label.hide();
369 } else {
369 } else {
370 this.$label.text();
370 this.$label.text();
371 this.typeset(this.$label, description);
371 this.typeset(this.$label, description);
372 this.$label.show();
372 this.$label.show();
373 }
373 }
374 }
374 }
375 return ToggleButtonsView.__super__.update.apply(this);
375 return ToggleButtonsView.__super__.update.apply(this);
376 },
376 },
377
377
378 update_attr: function(name, value) {
378 update_attr: function(name, value) {
379 /**
379 /**
380 * Set a css attr of the widget view.
380 * Set a css attr of the widget view.
381 */
381 */
382 if (name == 'padding' || name == 'margin') {
382 if (name == 'padding' || name == 'margin') {
383 this.$el.css(name, value);
383 this.$el.css(name, value);
384 } else {
384 } else {
385 this._css_state[name] = value;
385 this._css_state[name] = value;
386 this.update_style_traits();
386 this.update_style_traits();
387 }
387 }
388 },
388 },
389
389
390 update_style_traits: function(button) {
390 update_style_traits: function(button) {
391 for (var name in this._css_state) {
391 for (var name in this._css_state) {
392 if (this._css_state.hasOwnProperty(name)) {
392 if (this._css_state.hasOwnProperty(name)) {
393 if (name == 'margin') {
393 if (name == 'margin') {
394 this.$buttongroup.css(name, this._css_state[name]);
394 this.$buttongroup.css(name, this._css_state[name]);
395 } else if (name != 'width') {
395 } else if (name != 'width') {
396 if (button) {
396 if (button) {
397 button.css(name, this._css_state[name]);
397 button.css(name, this._css_state[name]);
398 } else {
398 } else {
399 this.$buttongroup.find('button').css(name, this._css_state[name]);
399 this.$buttongroup.find('button').css(name, this._css_state[name]);
400 }
400 }
401 }
401 }
402 }
402 }
403 }
403 }
404 },
404 },
405
405
406 update_button_style: function(previous_trait_value) {
406 update_button_style: function(previous_trait_value) {
407 var class_map = {
407 var class_map = {
408 primary: ['btn-primary'],
408 primary: ['btn-primary'],
409 success: ['btn-success'],
409 success: ['btn-success'],
410 info: ['btn-info'],
410 info: ['btn-info'],
411 warning: ['btn-warning'],
411 warning: ['btn-warning'],
412 danger: ['btn-danger']
412 danger: ['btn-danger']
413 };
413 };
414 this.update_mapped_classes(class_map, 'button_style', previous_trait_value, this.$buttongroup.find('button'));
414 this.update_mapped_classes(class_map, 'button_style', previous_trait_value, this.$buttongroup.find('button'));
415 },
415 },
416
416
417 handle_click: function (e) {
417 handle_click: function (e) {
418 /**
418 /**
419 * Handle when a value is clicked.
419 * Handle when a value is clicked.
420 *
420 *
421 * Calling model.set will trigger all of the other views of the
421 * Calling model.set will trigger all of the other views of the
422 * model to update.
422 * model to update.
423 */
423 */
424 this.model.set('selected_label', $(e.target).attr('value'), {updated_view: this});
424 this.model.set('selected_label', $(e.target).attr('value'), {updated_view: this});
425 this.touch();
425 this.touch();
426 },
426 },
427 });
427 });
428
428
429
429
430 var SelectView = widget.DOMWidgetView.extend({
430 var SelectView = widget.DOMWidgetView.extend({
431 render : function(){
431 render : function(){
432 /**
432 /**
433 * Called when view is rendered.
433 * Called when view is rendered.
434 */
434 */
435 this.$el
435 this.$el
436 .addClass('widget-hbox widget-select');
436 .addClass('widget-hbox widget-select');
437 this.$label = $('<div />')
437 this.$label = $('<div />')
438 .appendTo(this.$el)
438 .appendTo(this.$el)
439 .addClass('widget-label')
439 .addClass('widget-label')
440 .hide();
440 .hide();
441 this.$listbox = $('<select />')
441 this.$listbox = $('<select />')
442 .addClass('widget-listbox form-control')
442 .addClass('widget-listbox form-control')
443 .attr('size', 6)
443 .attr('size', 6)
444 .appendTo(this.$el)
444 .appendTo(this.$el)
445 .on('change', $.proxy(this.handle_change, this));
445 .on('change', $.proxy(this.handle_change, this));
446 this.update();
446 this.update();
447 },
447 },
448
448
449 update : function(options){
449 update : function(options){
450 /**
450 /**
451 * Update the contents of this view
451 * Update the contents of this view
452 *
452 *
453 * Called when the model is changed. The model may have been
453 * Called when the model is changed. The model may have been
454 * changed by another view or by a state update from the back-end.
454 * changed by another view or by a state update from the back-end.
455 */
455 */
456 if (options === undefined || options.updated_view != this) {
456 if (options === undefined || options.updated_view != this) {
457 // Add missing items to the DOM.
457 // Add missing items to the DOM.
458 var items = this.model.get('_options_labels');
458 var items = this.model.get('_options_labels');
459 var that = this;
459 var that = this;
460 _.each(items, function(item, index) {
460 _.each(items, function(item, index) {
461 var item_query = 'option[data-value="' + encodeURIComponent(item) + '"]';
461 var item_query = 'option[data-value="' + encodeURIComponent(item) + '"]';
462 if (that.$listbox.find(item_query).length === 0) {
462 if (that.$listbox.find(item_query).length === 0) {
463 $('<option />')
463 $('<option />')
464 .text(item)
464 .text(item)
465 .attr('data-value', encodeURIComponent(item))
465 .attr('data-value', encodeURIComponent(item))
466 .attr('selected_label', item)
466 .attr('selected_label', item)
467 .on("click", $.proxy(that.handle_click, that))
467 .on("click", $.proxy(that.handle_click, that))
468 .appendTo(that.$listbox);
468 .appendTo(that.$listbox);
469 }
469 }
470 });
470 });
471
471
472 // Select the correct element
472 // Select the correct element
473 this.$listbox.val(this.model.get('selected_label'));
473 this.$listbox.val(this.model.get('selected_label'));
474
474
475 // Disable listbox if needed
475 // Disable listbox if needed
476 var disabled = this.model.get('disabled');
476 var disabled = this.model.get('disabled');
477 this.$listbox.prop('disabled', disabled);
477 this.$listbox.prop('disabled', disabled);
478
478
479 // Remove items that no longer exist.
479 // Remove items that no longer exist.
480 this.$listbox.find('option').each(function(i, obj) {
480 this.$listbox.find('option').each(function(i, obj) {
481 var value = $(obj).text();
481 var value = $(obj).text();
482 var found = false;
482 var found = false;
483 _.each(items, function(item, index) {
483 _.each(items, function(item, index) {
484 if (item == value) {
484 if (item == value) {
485 found = true;
485 found = true;
486 return false;
486 return false;
487 }
487 }
488 });
488 });
489
489
490 if (!found) {
490 if (!found) {
491 $(obj).remove();
491 $(obj).remove();
492 }
492 }
493 });
493 });
494
494
495 var description = this.model.get('description');
495 var description = this.model.get('description');
496 if (description.length === 0) {
496 if (description.length === 0) {
497 this.$label.hide();
497 this.$label.hide();
498 } else {
498 } else {
499 this.typeset(this.$label, description);
499 this.typeset(this.$label, description);
500 this.$label.show();
500 this.$label.show();
501 }
501 }
502 }
502 }
503 return SelectView.__super__.update.apply(this);
503 return SelectView.__super__.update.apply(this);
504 },
504 },
505
505
506 update_attr: function(name, value) {
506 update_attr: function(name, value) {
507 /**
507 /**
508 * Set a css attr of the widget view.
508 * Set a css attr of the widget view.
509 */
509 */
510 if (name == 'padding' || name == 'margin') {
510 if (name == 'padding' || name == 'margin') {
511 this.$el.css(name, value);
511 this.$el.css(name, value);
512 } else {
512 } else {
513 this.$listbox.css(name, value);
513 this.$listbox.css(name, value);
514 }
514 }
515 },
515 },
516
516
517 handle_click: function (e) {
517 handle_click: function (e) {
518 /**
518 /**
519 * Handle when a new value is clicked.
519 * Handle when a new value is clicked.
520 */
520 */
521 this.$listbox.val($(e.target).val()).change();
521 this.$listbox.val($(e.target).val()).change();
522 },
522 },
523
523
524 handle_change: function (e) {
524 handle_change: function (e) {
525 /**
525 /**
526 * Handle when a new value is selected.
526 * Handle when a new value is selected.
527 *
527 *
528 * Calling model.set will trigger all of the other views of the
528 * Calling model.set will trigger all of the other views of the
529 * model to update.
529 * model to update.
530 */
530 */
531 this.model.set('selected_label', this.$listbox.val(), {updated_view: this});
531 this.model.set('selected_label', this.$listbox.val(), {updated_view: this});
532 this.touch();
532 this.touch();
533 },
533 },
534 });
534 });
535
535
536
536
537 var SelectMultipleView = SelectView.extend({
537 var SelectMultipleView = SelectView.extend({
538 render: function(){
538 render: function(){
539 /**
539 /**
540 * Called when view is rendered.
540 * Called when view is rendered.
541 */
541 */
542 SelectMultipleView.__super__.render.apply(this);
542 SelectMultipleView.__super__.render.apply(this);
543 this.$el.removeClass('widget-select')
543 this.$el.removeClass('widget-select')
544 .addClass('widget-select-multiple');
544 .addClass('widget-select-multiple');
545 this.$listbox.attr('multiple', true)
545 this.$listbox.attr('multiple', true)
546 .on('change', $.proxy(this.handle_change, this));
546 .on('change', $.proxy(this.handle_change, this));
547 return this;
547 return this;
548 },
548 },
549
549
550 update: function(){
550 update: function(){
551 /**
551 /**
552 * Update the contents of this view
552 * Update the contents of this view
553 *
553 *
554 * Called when the model is changed. The model may have been
554 * Called when the model is changed. The model may have been
555 * changed by another view or by a state update from the back-end.
555 * changed by another view or by a state update from the back-end.
556 */
556 */
557 SelectMultipleView.__super__.update.apply(this, arguments);
557 SelectMultipleView.__super__.update.apply(this, arguments);
558 this.$listbox.val(this.model.get('selected_labels'));
558 this.$listbox.val(this.model.get('selected_labels'));
559 },
559 },
560
561 handle_click: function(){
562 /**
563 * Overload click from select
564 *
565 * Apparently it's needed from there for testing purposes,
566 * but breaks behavior of this.
567 */
568 },
560
569
561 handle_change: function (e) {
570 handle_change: function (e) {
562 /**
571 /**
563 * Handle when a new value is selected.
572 * Handle when a new value is selected.
564 *
573 *
565 * Calling model.set will trigger all of the other views of the
574 * Calling model.set will trigger all of the other views of the
566 * model to update.
575 * model to update.
567 */
576 */
568 this.model.set('selected_labels',
577 this.model.set('selected_labels',
569 (this.$listbox.val() || []).slice(),
578 (this.$listbox.val() || []).slice(),
570 {updated_view: this});
579 {updated_view: this});
571 this.touch();
580 this.touch();
572 },
581 },
573 });
582 });
574
583
575
584
576 return {
585 return {
577 'DropdownView': DropdownView,
586 'DropdownView': DropdownView,
578 'RadioButtonsView': RadioButtonsView,
587 'RadioButtonsView': RadioButtonsView,
579 'ToggleButtonsView': ToggleButtonsView,
588 'ToggleButtonsView': ToggleButtonsView,
580 'SelectView': SelectView,
589 'SelectView': SelectView,
581 'SelectMultipleView': SelectMultipleView,
590 'SelectMultipleView': SelectMultipleView,
582 };
591 };
583 });
592 });
General Comments 0
You need to be logged in to leave comments. Login now