##// END OF EJS Templates
Hide variables that shouldn't be exposed to the user
Jonathan Frederic -
Show More
@@ -1,472 +1,472 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 DropdownView = widget.DOMWidgetView.extend({
11 var DropdownView = widget.DOMWidgetView.extend({
12 render : function(){
12 render : function(){
13 // Called when view is rendered.
13 // Called when view is rendered.
14 this.$el
14 this.$el
15 .addClass('widget-hbox widget-dropdown');
15 .addClass('widget-hbox widget-dropdown');
16 this.$label = $('<div />')
16 this.$label = $('<div />')
17 .appendTo(this.$el)
17 .appendTo(this.$el)
18 .addClass('widget-label')
18 .addClass('widget-label')
19 .hide();
19 .hide();
20 this.$buttongroup = $('<div />')
20 this.$buttongroup = $('<div />')
21 .addClass('widget_item')
21 .addClass('widget_item')
22 .addClass('btn-group')
22 .addClass('btn-group')
23 .appendTo(this.$el);
23 .appendTo(this.$el);
24 this.$droplabel = $('<button />')
24 this.$droplabel = $('<button />')
25 .addClass('btn btn-default')
25 .addClass('btn btn-default')
26 .addClass('widget-combo-btn')
26 .addClass('widget-combo-btn')
27 .html("&nbsp;")
27 .html("&nbsp;")
28 .appendTo(this.$buttongroup);
28 .appendTo(this.$buttongroup);
29 this.$dropbutton = $('<button />')
29 this.$dropbutton = $('<button />')
30 .addClass('btn btn-default')
30 .addClass('btn btn-default')
31 .addClass('dropdown-toggle')
31 .addClass('dropdown-toggle')
32 .addClass('widget-combo-carrot-btn')
32 .addClass('widget-combo-carrot-btn')
33 .attr('data-toggle', 'dropdown')
33 .attr('data-toggle', 'dropdown')
34 .append($('<span />').addClass("caret"))
34 .append($('<span />').addClass("caret"))
35 .appendTo(this.$buttongroup);
35 .appendTo(this.$buttongroup);
36 this.$droplist = $('<ul />')
36 this.$droplist = $('<ul />')
37 .addClass('dropdown-menu')
37 .addClass('dropdown-menu')
38 .appendTo(this.$buttongroup);
38 .appendTo(this.$buttongroup);
39
39
40 this.model.on('change:button_style', function(model, value) {
40 this.model.on('change:button_style', function(model, value) {
41 this.update_button_style();
41 this.update_button_style();
42 }, this);
42 }, this);
43 this.update_button_style('');
43 this.update_button_style('');
44
44
45 // Set defaults.
45 // Set defaults.
46 this.update();
46 this.update();
47 },
47 },
48
48
49 update : function(options){
49 update : function(options){
50 // Update the contents of this view
50 // Update the contents of this view
51 //
51 //
52 // Called when the model is changed. The model may have been
52 // Called when the model is changed. The model may have been
53 // changed by another view or by a state update from the back-end.
53 // changed by another view or by a state update from the back-end.
54
54
55 if (options === undefined || options.updated_view != this) {
55 if (options === undefined || options.updated_view != this) {
56 var selected_item_text = this.model.get('value_name');
56 var selected_item_text = this.model.get('value_name');
57 if (selected_item_text.trim().length === 0) {
57 if (selected_item_text.trim().length === 0) {
58 this.$droplabel.html("&nbsp;");
58 this.$droplabel.html("&nbsp;");
59 } else {
59 } else {
60 this.$droplabel.text(selected_item_text);
60 this.$droplabel.text(selected_item_text);
61 }
61 }
62
62
63 var items = this.model.get('value_names');
63 var items = this.model.get('_value_names');
64 var $replace_droplist = $('<ul />')
64 var $replace_droplist = $('<ul />')
65 .addClass('dropdown-menu');
65 .addClass('dropdown-menu');
66 // Copy the style
66 // Copy the style
67 $replace_droplist.attr('style', this.$droplist.attr('style'));
67 $replace_droplist.attr('style', this.$droplist.attr('style'));
68 var that = this;
68 var that = this;
69 _.each(items, function(item, i) {
69 _.each(items, function(item, i) {
70 var item_button = $('<a href="#"/>')
70 var item_button = $('<a href="#"/>')
71 .text(item)
71 .text(item)
72 .on('click', $.proxy(that.handle_click, that));
72 .on('click', $.proxy(that.handle_click, that));
73 $replace_droplist.append($('<li />').append(item_button));
73 $replace_droplist.append($('<li />').append(item_button));
74 });
74 });
75
75
76 this.$droplist.replaceWith($replace_droplist);
76 this.$droplist.replaceWith($replace_droplist);
77 this.$droplist.remove();
77 this.$droplist.remove();
78 this.$droplist = $replace_droplist;
78 this.$droplist = $replace_droplist;
79
79
80 if (this.model.get('disabled')) {
80 if (this.model.get('disabled')) {
81 this.$buttongroup.attr('disabled','disabled');
81 this.$buttongroup.attr('disabled','disabled');
82 this.$droplabel.attr('disabled','disabled');
82 this.$droplabel.attr('disabled','disabled');
83 this.$dropbutton.attr('disabled','disabled');
83 this.$dropbutton.attr('disabled','disabled');
84 this.$droplist.attr('disabled','disabled');
84 this.$droplist.attr('disabled','disabled');
85 } else {
85 } else {
86 this.$buttongroup.removeAttr('disabled');
86 this.$buttongroup.removeAttr('disabled');
87 this.$droplabel.removeAttr('disabled');
87 this.$droplabel.removeAttr('disabled');
88 this.$dropbutton.removeAttr('disabled');
88 this.$dropbutton.removeAttr('disabled');
89 this.$droplist.removeAttr('disabled');
89 this.$droplist.removeAttr('disabled');
90 }
90 }
91
91
92 var description = this.model.get('description');
92 var description = this.model.get('description');
93 if (description.length === 0) {
93 if (description.length === 0) {
94 this.$label.hide();
94 this.$label.hide();
95 } else {
95 } else {
96 this.$label.text(description);
96 this.$label.text(description);
97 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
97 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
98 this.$label.show();
98 this.$label.show();
99 }
99 }
100 }
100 }
101 return DropdownView.__super__.update.apply(this);
101 return DropdownView.__super__.update.apply(this);
102 },
102 },
103
103
104 update_button_style: function(previous_trait_value) {
104 update_button_style: function(previous_trait_value) {
105 var class_map = {
105 var class_map = {
106 primary: ['btn-primary'],
106 primary: ['btn-primary'],
107 success: ['btn-success'],
107 success: ['btn-success'],
108 info: ['btn-info'],
108 info: ['btn-info'],
109 warning: ['btn-warning'],
109 warning: ['btn-warning'],
110 danger: ['btn-danger']
110 danger: ['btn-danger']
111 };
111 };
112 this.update_mapped_classes(class_map, 'button_style', previous_trait_value, this.$droplabel);
112 this.update_mapped_classes(class_map, 'button_style', previous_trait_value, this.$droplabel);
113 this.update_mapped_classes(class_map, 'button_style', previous_trait_value, this.$dropbutton);
113 this.update_mapped_classes(class_map, 'button_style', previous_trait_value, this.$dropbutton);
114 },
114 },
115
115
116 update_attr: function(name, value) {
116 update_attr: function(name, value) {
117 // Set a css attr of the widget view.
117 // Set a css attr of the widget view.
118 if (name.substring(0, 6) == 'border' || name == 'background' || name == 'color') {
118 if (name.substring(0, 6) == 'border' || name == 'background' || name == 'color') {
119 this.$droplabel.css(name, value);
119 this.$droplabel.css(name, value);
120 this.$dropbutton.css(name, value);
120 this.$dropbutton.css(name, value);
121 this.$droplist.css(name, value);
121 this.$droplist.css(name, value);
122 } else if (name == 'width') {
122 } else if (name == 'width') {
123 this.$droplist.css(name, value);
123 this.$droplist.css(name, value);
124 this.$droplabel.css(name, value);
124 this.$droplabel.css(name, value);
125 } else if (name == 'padding') {
125 } else if (name == 'padding') {
126 this.$droplist.css(name, value);
126 this.$droplist.css(name, value);
127 this.$buttongroup.css(name, value);
127 this.$buttongroup.css(name, value);
128 } else if (name == 'margin') {
128 } else if (name == 'margin') {
129 this.$buttongroup.css(name, value);
129 this.$buttongroup.css(name, value);
130 } else if (name == 'height') {
130 } else if (name == 'height') {
131 this.$droplabel.css(name, value);
131 this.$droplabel.css(name, value);
132 this.$dropbutton.css(name, value);
132 this.$dropbutton.css(name, value);
133 } else {
133 } else {
134 this.$droplist.css(name, value);
134 this.$droplist.css(name, value);
135 this.$droplabel.css(name, value);
135 this.$droplabel.css(name, value);
136 }
136 }
137 },
137 },
138
138
139 handle_click: function (e) {
139 handle_click: function (e) {
140 // Handle when a value is clicked.
140 // Handle when a value is clicked.
141
141
142 // Calling model.set will trigger all of the other views of the
142 // Calling model.set will trigger all of the other views of the
143 // model to update.
143 // model to update.
144 this.model.set('value_name', $(e.target).text(), {updated_view: this});
144 this.model.set('value_name', $(e.target).text(), {updated_view: this});
145 this.touch();
145 this.touch();
146 },
146 },
147
147
148 });
148 });
149
149
150
150
151 var RadioButtonsView = widget.DOMWidgetView.extend({
151 var RadioButtonsView = widget.DOMWidgetView.extend({
152 render : function(){
152 render : function(){
153 // Called when view is rendered.
153 // Called when view is rendered.
154 this.$el
154 this.$el
155 .addClass('widget-hbox widget-radio');
155 .addClass('widget-hbox widget-radio');
156 this.$label = $('<div />')
156 this.$label = $('<div />')
157 .appendTo(this.$el)
157 .appendTo(this.$el)
158 .addClass('widget-label')
158 .addClass('widget-label')
159 .hide();
159 .hide();
160 this.$container = $('<div />')
160 this.$container = $('<div />')
161 .appendTo(this.$el)
161 .appendTo(this.$el)
162 .addClass('widget-radio-box');
162 .addClass('widget-radio-box');
163 this.update();
163 this.update();
164 },
164 },
165
165
166 update : function(options){
166 update : function(options){
167 // Update the contents of this view
167 // Update the contents of this view
168 //
168 //
169 // Called when the model is changed. The model may have been
169 // Called when the model is changed. The model may have been
170 // changed by another view or by a state update from the back-end.
170 // changed by another view or by a state update from the back-end.
171 if (options === undefined || options.updated_view != this) {
171 if (options === undefined || options.updated_view != this) {
172 // Add missing items to the DOM.
172 // Add missing items to the DOM.
173 var items = this.model.get('value_names');
173 var items = this.model.get('_value_names');
174 var disabled = this.model.get('disabled');
174 var disabled = this.model.get('disabled');
175 var that = this;
175 var that = this;
176 _.each(items, function(item, index) {
176 _.each(items, function(item, index) {
177 var item_query = ' :input[value="' + item + '"]';
177 var item_query = ' :input[value="' + item + '"]';
178 if (that.$el.find(item_query).length === 0) {
178 if (that.$el.find(item_query).length === 0) {
179 var $label = $('<label />')
179 var $label = $('<label />')
180 .addClass('radio')
180 .addClass('radio')
181 .text(item)
181 .text(item)
182 .appendTo(that.$container);
182 .appendTo(that.$container);
183
183
184 $('<input />')
184 $('<input />')
185 .attr('type', 'radio')
185 .attr('type', 'radio')
186 .addClass(that.model)
186 .addClass(that.model)
187 .val(item)
187 .val(item)
188 .prependTo($label)
188 .prependTo($label)
189 .on('click', $.proxy(that.handle_click, that));
189 .on('click', $.proxy(that.handle_click, that));
190 }
190 }
191
191
192 var $item_element = that.$container.find(item_query);
192 var $item_element = that.$container.find(item_query);
193 if (that.model.get('value_name') == item) {
193 if (that.model.get('value_name') == item) {
194 $item_element.prop('checked', true);
194 $item_element.prop('checked', true);
195 } else {
195 } else {
196 $item_element.prop('checked', false);
196 $item_element.prop('checked', false);
197 }
197 }
198 $item_element.prop('disabled', disabled);
198 $item_element.prop('disabled', disabled);
199 });
199 });
200
200
201 // Remove items that no longer exist.
201 // Remove items that no longer exist.
202 this.$container.find('input').each(function(i, obj) {
202 this.$container.find('input').each(function(i, obj) {
203 var value = $(obj).val();
203 var value = $(obj).val();
204 var found = false;
204 var found = false;
205 _.each(items, function(item, index) {
205 _.each(items, function(item, index) {
206 if (item == value) {
206 if (item == value) {
207 found = true;
207 found = true;
208 return false;
208 return false;
209 }
209 }
210 });
210 });
211
211
212 if (!found) {
212 if (!found) {
213 $(obj).parent().remove();
213 $(obj).parent().remove();
214 }
214 }
215 });
215 });
216
216
217 var description = this.model.get('description');
217 var description = this.model.get('description');
218 if (description.length === 0) {
218 if (description.length === 0) {
219 this.$label.hide();
219 this.$label.hide();
220 } else {
220 } else {
221 this.$label.text(description);
221 this.$label.text(description);
222 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
222 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
223 this.$label.show();
223 this.$label.show();
224 }
224 }
225 }
225 }
226 return RadioButtonsView.__super__.update.apply(this);
226 return RadioButtonsView.__super__.update.apply(this);
227 },
227 },
228
228
229 update_attr: function(name, value) {
229 update_attr: function(name, value) {
230 // Set a css attr of the widget view.
230 // Set a css attr of the widget view.
231 this.$container.css(name, value);
231 this.$container.css(name, value);
232 },
232 },
233
233
234 handle_click: function (e) {
234 handle_click: function (e) {
235 // Handle when a value is clicked.
235 // Handle when a value is clicked.
236
236
237 // Calling model.set will trigger all of the other views of the
237 // Calling model.set will trigger all of the other views of the
238 // model to update.
238 // model to update.
239 this.model.set('value_name', $(e.target).val(), {updated_view: this});
239 this.model.set('value_name', $(e.target).val(), {updated_view: this});
240 this.touch();
240 this.touch();
241 },
241 },
242 });
242 });
243
243
244
244
245 var ToggleButtonsView = widget.DOMWidgetView.extend({
245 var ToggleButtonsView = widget.DOMWidgetView.extend({
246 initialize: function() {
246 initialize: function() {
247 this._css_state = {};
247 this._css_state = {};
248 ToggleButtonsView.__super__.initialize.apply(this, arguments);
248 ToggleButtonsView.__super__.initialize.apply(this, arguments);
249 },
249 },
250
250
251 render: function() {
251 render: function() {
252 // Called when view is rendered.
252 // Called when view is rendered.
253 this.$el
253 this.$el
254 .addClass('widget-hbox widget-toggle-buttons');
254 .addClass('widget-hbox widget-toggle-buttons');
255 this.$label = $('<div />')
255 this.$label = $('<div />')
256 .appendTo(this.$el)
256 .appendTo(this.$el)
257 .addClass('widget-label')
257 .addClass('widget-label')
258 .hide();
258 .hide();
259 this.$buttongroup = $('<div />')
259 this.$buttongroup = $('<div />')
260 .addClass('btn-group')
260 .addClass('btn-group')
261 .attr('data-toggle', 'buttons-radio')
261 .attr('data-toggle', 'buttons-radio')
262 .appendTo(this.$el);
262 .appendTo(this.$el);
263
263
264 this.model.on('change:button_style', function(model, value) {
264 this.model.on('change:button_style', function(model, value) {
265 this.update_button_style();
265 this.update_button_style();
266 }, this);
266 }, this);
267 this.update_button_style('');
267 this.update_button_style('');
268 this.update();
268 this.update();
269 },
269 },
270
270
271 update : function(options){
271 update : function(options){
272 // Update the contents of this view
272 // Update the contents of this view
273 //
273 //
274 // Called when the model is changed. The model may have been
274 // Called when the model is changed. The model may have been
275 // changed by another view or by a state update from the back-end.
275 // changed by another view or by a state update from the back-end.
276 if (options === undefined || options.updated_view != this) {
276 if (options === undefined || options.updated_view != this) {
277 // Add missing items to the DOM.
277 // Add missing items to the DOM.
278 var items = this.model.get('value_names');
278 var items = this.model.get('_value_names');
279 var disabled = this.model.get('disabled');
279 var disabled = this.model.get('disabled');
280 var that = this;
280 var that = this;
281 var item_html;
281 var item_html;
282 _.each(items, function(item, index) {
282 _.each(items, function(item, index) {
283 if (item.trim().length == 0) {
283 if (item.trim().length == 0) {
284 item_html = "&nbsp;";
284 item_html = "&nbsp;";
285 } else {
285 } else {
286 item_html = utils.escape_html(item);
286 item_html = utils.escape_html(item);
287 }
287 }
288 var item_query = '[data-value="' + item + '"]';
288 var item_query = '[data-value="' + item + '"]';
289 var $item_element = that.$buttongroup.find(item_query);
289 var $item_element = that.$buttongroup.find(item_query);
290 if (!$item_element.length) {
290 if (!$item_element.length) {
291 $item_element = $('<button/>')
291 $item_element = $('<button/>')
292 .attr('type', 'button')
292 .attr('type', 'button')
293 .addClass('btn btn-default')
293 .addClass('btn btn-default')
294 .html(item_html)
294 .html(item_html)
295 .appendTo(that.$buttongroup)
295 .appendTo(that.$buttongroup)
296 .attr('data-value', item)
296 .attr('data-value', item)
297 .on('click', $.proxy(that.handle_click, that));
297 .on('click', $.proxy(that.handle_click, that));
298 that.update_style_traits($item_element);
298 that.update_style_traits($item_element);
299 }
299 }
300 if (that.model.get('value_name') == item) {
300 if (that.model.get('value_name') == item) {
301 $item_element.addClass('active');
301 $item_element.addClass('active');
302 } else {
302 } else {
303 $item_element.removeClass('active');
303 $item_element.removeClass('active');
304 }
304 }
305 $item_element.prop('disabled', disabled);
305 $item_element.prop('disabled', disabled);
306 });
306 });
307
307
308 // Remove items that no longer exist.
308 // Remove items that no longer exist.
309 this.$buttongroup.find('button').each(function(i, obj) {
309 this.$buttongroup.find('button').each(function(i, obj) {
310 var value = $(obj).data('value');
310 var value = $(obj).data('value');
311 var found = false;
311 var found = false;
312 _.each(items, function(item, index) {
312 _.each(items, function(item, index) {
313 if (item == value) {
313 if (item == value) {
314 found = true;
314 found = true;
315 return false;
315 return false;
316 }
316 }
317 });
317 });
318
318
319 if (!found) {
319 if (!found) {
320 $(obj).remove();
320 $(obj).remove();
321 }
321 }
322 });
322 });
323
323
324 var description = this.model.get('description');
324 var description = this.model.get('description');
325 if (description.length === 0) {
325 if (description.length === 0) {
326 this.$label.hide();
326 this.$label.hide();
327 } else {
327 } else {
328 this.$label.text(description);
328 this.$label.text(description);
329 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
329 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
330 this.$label.show();
330 this.$label.show();
331 }
331 }
332 }
332 }
333 return ToggleButtonsView.__super__.update.apply(this);
333 return ToggleButtonsView.__super__.update.apply(this);
334 },
334 },
335
335
336 update_attr: function(name, value) {
336 update_attr: function(name, value) {
337 // Set a css attr of the widget view.
337 // Set a css attr of the widget view.
338 this._css_state[name] = value;
338 this._css_state[name] = value;
339 this.update_style_traits();
339 this.update_style_traits();
340 },
340 },
341
341
342 update_style_traits: function(button) {
342 update_style_traits: function(button) {
343 for (var name in this._css_state) {
343 for (var name in this._css_state) {
344 if (this._css_state.hasOwnProperty(name)) {
344 if (this._css_state.hasOwnProperty(name)) {
345 if (name == 'margin') {
345 if (name == 'margin') {
346 this.$buttongroup.css(name, this._css_state[name]);
346 this.$buttongroup.css(name, this._css_state[name]);
347 } else if (name != 'width') {
347 } else if (name != 'width') {
348 if (button) {
348 if (button) {
349 button.css(name, this._css_state[name]);
349 button.css(name, this._css_state[name]);
350 } else {
350 } else {
351 this.$buttongroup.find('button').css(name, this._css_state[name]);
351 this.$buttongroup.find('button').css(name, this._css_state[name]);
352 }
352 }
353 }
353 }
354 }
354 }
355 }
355 }
356 },
356 },
357
357
358 update_button_style: function(previous_trait_value) {
358 update_button_style: function(previous_trait_value) {
359 var class_map = {
359 var class_map = {
360 primary: ['btn-primary'],
360 primary: ['btn-primary'],
361 success: ['btn-success'],
361 success: ['btn-success'],
362 info: ['btn-info'],
362 info: ['btn-info'],
363 warning: ['btn-warning'],
363 warning: ['btn-warning'],
364 danger: ['btn-danger']
364 danger: ['btn-danger']
365 };
365 };
366 this.update_mapped_classes(class_map, 'button_style', previous_trait_value, this.$buttongroup.find('button'));
366 this.update_mapped_classes(class_map, 'button_style', previous_trait_value, this.$buttongroup.find('button'));
367 },
367 },
368
368
369 handle_click: function (e) {
369 handle_click: function (e) {
370 // Handle when a value is clicked.
370 // Handle when a value is clicked.
371
371
372 // Calling model.set will trigger all of the other views of the
372 // Calling model.set will trigger all of the other views of the
373 // model to update.
373 // model to update.
374 this.model.set('value_name', $(e.target).data('value'), {updated_view: this});
374 this.model.set('value_name', $(e.target).data('value'), {updated_view: this});
375 this.touch();
375 this.touch();
376 },
376 },
377 });
377 });
378
378
379
379
380 var SelectView = widget.DOMWidgetView.extend({
380 var SelectView = widget.DOMWidgetView.extend({
381 render : function(){
381 render : function(){
382 // Called when view is rendered.
382 // Called when view is rendered.
383 this.$el
383 this.$el
384 .addClass('widget-hbox widget-select');
384 .addClass('widget-hbox widget-select');
385 this.$label = $('<div />')
385 this.$label = $('<div />')
386 .appendTo(this.$el)
386 .appendTo(this.$el)
387 .addClass('widget-label')
387 .addClass('widget-label')
388 .hide();
388 .hide();
389 this.$listbox = $('<select />')
389 this.$listbox = $('<select />')
390 .addClass('widget-listbox form-control')
390 .addClass('widget-listbox form-control')
391 .attr('size', 6)
391 .attr('size', 6)
392 .appendTo(this.$el);
392 .appendTo(this.$el);
393 this.update();
393 this.update();
394 },
394 },
395
395
396 update : function(options){
396 update : function(options){
397 // Update the contents of this view
397 // Update the contents of this view
398 //
398 //
399 // Called when the model is changed. The model may have been
399 // Called when the model is changed. The model may have been
400 // changed by another view or by a state update from the back-end.
400 // changed by another view or by a state update from the back-end.
401 if (options === undefined || options.updated_view != this) {
401 if (options === undefined || options.updated_view != this) {
402 // Add missing items to the DOM.
402 // Add missing items to the DOM.
403 var items = this.model.get('value_names');
403 var items = this.model.get('_value_names');
404 var that = this;
404 var that = this;
405 _.each(items, function(item, index) {
405 _.each(items, function(item, index) {
406 var item_query = 'option[value_name="' + item + '"]';
406 var item_query = 'option[value_name="' + item + '"]';
407 if (that.$listbox.find(item_query).length === 0) {
407 if (that.$listbox.find(item_query).length === 0) {
408 $('<option />')
408 $('<option />')
409 .text(item)
409 .text(item)
410 .attr('value_name', item)
410 .attr('value_name', item)
411 .appendTo(that.$listbox)
411 .appendTo(that.$listbox)
412 .on('click', $.proxy(that.handle_click, that));
412 .on('click', $.proxy(that.handle_click, that));
413 }
413 }
414 });
414 });
415
415
416 // Select the correct element
416 // Select the correct element
417 this.$listbox.val(this.model.get('value_name'));
417 this.$listbox.val(this.model.get('value_name'));
418
418
419 // Disable listbox if needed
419 // Disable listbox if needed
420 var disabled = this.model.get('disabled');
420 var disabled = this.model.get('disabled');
421 this.$listbox.prop('disabled', disabled);
421 this.$listbox.prop('disabled', disabled);
422
422
423 // Remove items that no longer exist.
423 // Remove items that no longer exist.
424 this.$listbox.find('option').each(function(i, obj) {
424 this.$listbox.find('option').each(function(i, obj) {
425 var value = $(obj).text();
425 var value = $(obj).text();
426 var found = false;
426 var found = false;
427 _.each(items, function(item, index) {
427 _.each(items, function(item, index) {
428 if (item == value) {
428 if (item == value) {
429 found = true;
429 found = true;
430 return false;
430 return false;
431 }
431 }
432 });
432 });
433
433
434 if (!found) {
434 if (!found) {
435 $(obj).remove();
435 $(obj).remove();
436 }
436 }
437 });
437 });
438
438
439 var description = this.model.get('description');
439 var description = this.model.get('description');
440 if (description.length === 0) {
440 if (description.length === 0) {
441 this.$label.hide();
441 this.$label.hide();
442 } else {
442 } else {
443 this.$label.text(description);
443 this.$label.text(description);
444 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
444 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
445 this.$label.show();
445 this.$label.show();
446 }
446 }
447 }
447 }
448 return SelectView.__super__.update.apply(this);
448 return SelectView.__super__.update.apply(this);
449 },
449 },
450
450
451 update_attr: function(name, value) {
451 update_attr: function(name, value) {
452 // Set a css attr of the widget view.
452 // Set a css attr of the widget view.
453 this.$listbox.css(name, value);
453 this.$listbox.css(name, value);
454 },
454 },
455
455
456 handle_click: function (e) {
456 handle_click: function (e) {
457 // Handle when a value is clicked.
457 // Handle when a value is clicked.
458
458
459 // Calling model.set will trigger all of the other views of the
459 // Calling model.set will trigger all of the other views of the
460 // model to update.
460 // model to update.
461 this.model.set('value_name', $(e.target).text(), {updated_view: this});
461 this.model.set('value_name', $(e.target).text(), {updated_view: this});
462 this.touch();
462 this.touch();
463 },
463 },
464 });
464 });
465
465
466 return {
466 return {
467 'DropdownView': DropdownView,
467 'DropdownView': DropdownView,
468 'RadioButtonsView': RadioButtonsView,
468 'RadioButtonsView': RadioButtonsView,
469 'ToggleButtonsView': ToggleButtonsView,
469 'ToggleButtonsView': ToggleButtonsView,
470 'SelectView': SelectView,
470 'SelectView': SelectView,
471 };
471 };
472 });
472 });
@@ -1,172 +1,172 b''
1 """Selection classes.
1 """Selection classes.
2
2
3 Represents an enumeration using a widget.
3 Represents an enumeration using a widget.
4 """
4 """
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 from collections import OrderedDict
17 from collections import OrderedDict
18 from threading import Lock
18 from threading import Lock
19
19
20 from .widget import DOMWidget, register
20 from .widget import DOMWidget, register
21 from IPython.utils.traitlets import (
21 from IPython.utils.traitlets import (
22 Unicode, Bool, Any, Dict, TraitError, CaselessStrEnum, Tuple
22 Unicode, Bool, Any, Dict, TraitError, CaselessStrEnum, Tuple
23 )
23 )
24 from IPython.utils.py3compat import unicode_type
24 from IPython.utils.py3compat import unicode_type
25 from IPython.utils.warn import DeprecatedClass
25 from IPython.utils.warn import DeprecatedClass
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # SelectionWidget
28 # SelectionWidget
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 class _Selection(DOMWidget):
30 class _Selection(DOMWidget):
31 """Base class for Selection widgets
31 """Base class for Selection widgets
32
32
33 ``values`` can be specified as a list or dict. If given as a list,
33 ``values`` can be specified as a list or dict. If given as a list,
34 it will be transformed to a dict of the form ``{str(value):value}``.
34 it will be transformed to a dict of the form ``{str(value):value}``.
35 """
35 """
36
36
37 value = Any(help="Selected value")
37 value = Any(help="Selected value")
38 value_name = Unicode(help="The name of the selected value", sync=True)
38 value_name = Unicode(help="The name of the selected value", sync=True)
39 values = Any(help="""List of (key, value) tuples or dict of values that the
39 values = Any(help="""List of (key, value) tuples or dict of values that the
40 user can select.
40 user can select.
41
41
42 The keys of this list are the strings that will be displayed in the UI,
42 The keys of this list are the strings that will be displayed in the UI,
43 representing the actual Python choices.
43 representing the actual Python choices.
44
44
45 The keys of this list are also available as value_names.
45 The keys of this list are also available as _value_names.
46 """)
46 """)
47
47
48 values_dict = Dict()
48 _values_dict = Dict()
49 value_names = Tuple(sync=True)
49 _value_names = Tuple(sync=True)
50 value_values = Tuple()
50 _value_values = Tuple()
51
51
52 disabled = Bool(False, help="Enable or disable user changes", sync=True)
52 disabled = Bool(False, help="Enable or disable user changes", sync=True)
53 description = Unicode(help="Description of the value this widget represents", sync=True)
53 description = Unicode(help="Description of the value this widget represents", sync=True)
54
54
55 def __init__(self, *args, **kwargs):
55 def __init__(self, *args, **kwargs):
56 self.value_lock = Lock()
56 self.value_lock = Lock()
57 self.values_lock = Lock()
57 self.values_lock = Lock()
58 self.on_trait_change(self._values_readonly_changed, ['values_dict', 'value_names', 'value_values', '_values'])
58 self.on_trait_change(self._values_readonly_changed, ['_values_dict', '_value_names', '_value_values', '_values'])
59 if 'values' in kwargs:
59 if 'values' in kwargs:
60 self.values = kwargs.pop('values')
60 self.values = kwargs.pop('values')
61 DOMWidget.__init__(self, *args, **kwargs)
61 DOMWidget.__init__(self, *args, **kwargs)
62 self._value_in_values()
62 self._value_in_values()
63
63
64 def _make_values(self, x):
64 def _make_values(self, x):
65 # If x is a dict, convert it to list format.
65 # If x is a dict, convert it to list format.
66 if isinstance(x, (OrderedDict, dict)):
66 if isinstance(x, (OrderedDict, dict)):
67 return [(k, v) for k, v in x.items()]
67 return [(k, v) for k, v in x.items()]
68
68
69 # Make sure x is a list or tuple.
69 # Make sure x is a list or tuple.
70 if not isinstance(x, (list, tuple)):
70 if not isinstance(x, (list, tuple)):
71 raise ValueError('x')
71 raise ValueError('x')
72
72
73 # If x is an ordinary list, use the values as names.
73 # If x is an ordinary list, use the values as names.
74 for y in x:
74 for y in x:
75 if not isinstance(y, (list, tuple)) or len(y) < 2:
75 if not isinstance(y, (list, tuple)) or len(y) < 2:
76 return [(i, i) for i in x]
76 return [(i, i) for i in x]
77
77
78 # Value is already in the correct format.
78 # Value is already in the correct format.
79 return x
79 return x
80
80
81 def _values_changed(self, name, old, new):
81 def _values_changed(self, name, old, new):
82 """Handles when the values tuple has been changed.
82 """Handles when the values tuple has been changed.
83
83
84 Setting values implies setting value names from the keys of the dict.
84 Setting values implies setting value names from the keys of the dict.
85 """
85 """
86 if self.values_lock.acquire(False):
86 if self.values_lock.acquire(False):
87 try:
87 try:
88 self.values = new
88 self.values = new
89
89
90 values = self._make_values(new)
90 values = self._make_values(new)
91 self.values_dict = {i[0]: i[1] for i in values}
91 self._values_dict = {i[0]: i[1] for i in values}
92 self.value_names = [i[0] for i in values]
92 self._value_names = [i[0] for i in values]
93 self.value_values = [i[1] for i in values]
93 self._value_values = [i[1] for i in values]
94 self._value_in_values()
94 self._value_in_values()
95 finally:
95 finally:
96 self.values_lock.release()
96 self.values_lock.release()
97
97
98 def _value_in_values(self):
98 def _value_in_values(self):
99 # ensure that the chosen value is one of the choices
99 # ensure that the chosen value is one of the choices
100 if self.value_values:
100 if self._value_values:
101 if self.value not in self.value_values:
101 if self.value not in self._value_values:
102 self.value = next(iter(self.value_values))
102 self.value = next(iter(self._value_values))
103
103
104 def _values_readonly_changed(self, name, old, new):
104 def _values_readonly_changed(self, name, old, new):
105 if not self.values_lock.locked():
105 if not self.values_lock.locked():
106 raise TraitError("`.%s` is a read-only trait. Use the `.values` tuple instead." % name)
106 raise TraitError("`.%s` is a read-only trait. Use the `.values` tuple instead." % name)
107
107
108 def _value_changed(self, name, old, new):
108 def _value_changed(self, name, old, new):
109 """Called when value has been changed"""
109 """Called when value has been changed"""
110 if self.value_lock.acquire(False):
110 if self.value_lock.acquire(False):
111 try:
111 try:
112 # Reverse dictionary lookup for the value name
112 # Reverse dictionary lookup for the value name
113 for k,v in self.values_dict.items():
113 for k,v in self._values_dict.items():
114 if new == v:
114 if new == v:
115 # set the selected value name
115 # set the selected value name
116 self.value_name = k
116 self.value_name = k
117 return
117 return
118 # undo the change, and raise KeyError
118 # undo the change, and raise KeyError
119 self.value = old
119 self.value = old
120 raise KeyError(new)
120 raise KeyError(new)
121 finally:
121 finally:
122 self.value_lock.release()
122 self.value_lock.release()
123
123
124 def _value_name_changed(self, name, old, new):
124 def _value_name_changed(self, name, old, new):
125 """Called when the value name has been changed (typically by the frontend)."""
125 """Called when the value name has been changed (typically by the frontend)."""
126 if self.value_lock.acquire(False):
126 if self.value_lock.acquire(False):
127 try:
127 try:
128 self.value = self.values_dict[new]
128 self.value = self._values_dict[new]
129 finally:
129 finally:
130 self.value_lock.release()
130 self.value_lock.release()
131
131
132
132
133 @register('IPython.ToggleButtons')
133 @register('IPython.ToggleButtons')
134 class ToggleButtons(_Selection):
134 class ToggleButtons(_Selection):
135 """Group of toggle buttons that represent an enumeration. Only one toggle
135 """Group of toggle buttons that represent an enumeration. Only one toggle
136 button can be toggled at any point in time."""
136 button can be toggled at any point in time."""
137 _view_name = Unicode('ToggleButtonsView', sync=True)
137 _view_name = Unicode('ToggleButtonsView', sync=True)
138
138
139 button_style = CaselessStrEnum(
139 button_style = CaselessStrEnum(
140 values=['primary', 'success', 'info', 'warning', 'danger', ''],
140 values=['primary', 'success', 'info', 'warning', 'danger', ''],
141 default_value='', allow_none=True, sync=True, help="""Use a
141 default_value='', allow_none=True, sync=True, help="""Use a
142 predefined styling for the buttons.""")
142 predefined styling for the buttons.""")
143
143
144 @register('IPython.Dropdown')
144 @register('IPython.Dropdown')
145 class Dropdown(_Selection):
145 class Dropdown(_Selection):
146 """Allows you to select a single item from a dropdown."""
146 """Allows you to select a single item from a dropdown."""
147 _view_name = Unicode('DropdownView', sync=True)
147 _view_name = Unicode('DropdownView', sync=True)
148
148
149 button_style = CaselessStrEnum(
149 button_style = CaselessStrEnum(
150 values=['primary', 'success', 'info', 'warning', 'danger', ''],
150 values=['primary', 'success', 'info', 'warning', 'danger', ''],
151 default_value='', allow_none=True, sync=True, help="""Use a
151 default_value='', allow_none=True, sync=True, help="""Use a
152 predefined styling for the buttons.""")
152 predefined styling for the buttons.""")
153
153
154 @register('IPython.RadioButtons')
154 @register('IPython.RadioButtons')
155 class RadioButtons(_Selection):
155 class RadioButtons(_Selection):
156 """Group of radio buttons that represent an enumeration. Only one radio
156 """Group of radio buttons that represent an enumeration. Only one radio
157 button can be toggled at any point in time."""
157 button can be toggled at any point in time."""
158 _view_name = Unicode('RadioButtonsView', sync=True)
158 _view_name = Unicode('RadioButtonsView', sync=True)
159
159
160
160
161
161
162 @register('IPython.Select')
162 @register('IPython.Select')
163 class Select(_Selection):
163 class Select(_Selection):
164 """Listbox that only allows one item to be selected at any given time."""
164 """Listbox that only allows one item to be selected at any given time."""
165 _view_name = Unicode('SelectView', sync=True)
165 _view_name = Unicode('SelectView', sync=True)
166
166
167
167
168 # Remove in IPython 4.0
168 # Remove in IPython 4.0
169 ToggleButtonsWidget = DeprecatedClass(ToggleButtons, 'ToggleButtonsWidget')
169 ToggleButtonsWidget = DeprecatedClass(ToggleButtons, 'ToggleButtonsWidget')
170 DropdownWidget = DeprecatedClass(Dropdown, 'DropdownWidget')
170 DropdownWidget = DeprecatedClass(Dropdown, 'DropdownWidget')
171 RadioButtonsWidget = DeprecatedClass(RadioButtons, 'RadioButtonsWidget')
171 RadioButtonsWidget = DeprecatedClass(RadioButtons, 'RadioButtonsWidget')
172 SelectWidget = DeprecatedClass(Select, 'SelectWidget')
172 SelectWidget = DeprecatedClass(Select, 'SelectWidget')
General Comments 0
You need to be logged in to leave comments. Login now