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