##// END OF EJS Templates
Make `SelectionWidget.values` a dict...
MinRK -
Show More
@@ -57,14 +57,14 b' define(["notebook/js/widgets/widget"], function(WidgetManager){'
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 if (options === undefined || options.updated_view != this) {
59 if (options === undefined || options.updated_view != this) {
60 var selected_item_text = this.model.get('_value');
60 var selected_item_text = this.model.get('value_name');
61 if (selected_item_text.length === 0) {
61 if (selected_item_text.length === 0) {
62 this.$droplabel.text(' ');
62 this.$droplabel.text(' ');
63 } else {
63 } else {
64 this.$droplabel.text(selected_item_text);
64 this.$droplabel.text(selected_item_text);
65 }
65 }
66
66
67 var items = this.model.get('labels');
67 var items = this.model.get('value_names');
68 var $replace_droplist = $('<ul />')
68 var $replace_droplist = $('<ul />')
69 .addClass('dropdown-menu');
69 .addClass('dropdown-menu');
70 var that = this;
70 var that = this;
@@ -107,7 +107,7 b' define(["notebook/js/widgets/widget"], function(WidgetManager){'
107
107
108 // Calling model.set will trigger all of the other views of the
108 // Calling model.set will trigger all of the other views of the
109 // model to update.
109 // model to update.
110 this.model.set('_value', $(e.target).text(), {updated_view: this});
110 this.model.set('value_name', $(e.target).text(), {updated_view: this});
111 this.touch();
111 this.touch();
112 },
112 },
113
113
@@ -139,7 +139,7 b' define(["notebook/js/widgets/widget"], function(WidgetManager){'
139 // changed by another view or by a state update from the back-end.
139 // changed by another view or by a state update from the back-end.
140 if (options === undefined || options.updated_view != this) {
140 if (options === undefined || options.updated_view != this) {
141 // Add missing items to the DOM.
141 // Add missing items to the DOM.
142 var items = this.model.get('labels');
142 var items = this.model.get('value_names');
143 var disabled = this.model.get('disabled');
143 var disabled = this.model.get('disabled');
144 var that = this;
144 var that = this;
145 _.each(items, function(item, index) {
145 _.each(items, function(item, index) {
@@ -159,7 +159,7 b' define(["notebook/js/widgets/widget"], function(WidgetManager){'
159 }
159 }
160
160
161 var $item_element = that.$container.find(item_query);
161 var $item_element = that.$container.find(item_query);
162 if (that.model.get('_value') == item) {
162 if (that.model.get('value_name') == item) {
163 $item_element.prop('checked', true);
163 $item_element.prop('checked', true);
164 } else {
164 } else {
165 $item_element.prop('checked', false);
165 $item_element.prop('checked', false);
@@ -199,14 +199,14 b' define(["notebook/js/widgets/widget"], function(WidgetManager){'
199
199
200 // Calling model.set will trigger all of the other views of the
200 // Calling model.set will trigger all of the other views of the
201 // model to update.
201 // model to update.
202 this.model.set('_value', $(e.target).val(), {updated_view: this});
202 this.model.set('value_name', $(e.target).val(), {updated_view: this});
203 this.touch();
203 this.touch();
204 },
204 },
205 });
205 });
206 WidgetManager.register_widget_view('RadioButtonsView', RadioButtonsView);
206 WidgetManager.register_widget_view('RadioButtonsView', RadioButtonsView);
207
207
208
208
209 var ToggleButtonsView = IPython.DOMWidgetView.extend({
209 var ToggleButtonsView = IPython.DOMWidgetView.extend({
210 render : function(){
210 render : function(){
211 // Called when view is rendered.
211 // Called when view is rendered.
212 this.$el
212 this.$el
@@ -230,7 +230,7 b' define(["notebook/js/widgets/widget"], function(WidgetManager){'
230 // changed by another view or by a state update from the back-end.
230 // changed by another view or by a state update from the back-end.
231 if (options === undefined || options.updated_view != this) {
231 if (options === undefined || options.updated_view != this) {
232 // Add missing items to the DOM.
232 // Add missing items to the DOM.
233 var items = this.model.get('labels');
233 var items = this.model.get('value_names');
234 var disabled = this.model.get('disabled');
234 var disabled = this.model.get('disabled');
235 var that = this;
235 var that = this;
236 _.each(items, function(item, index) {
236 _.each(items, function(item, index) {
@@ -245,7 +245,7 b' define(["notebook/js/widgets/widget"], function(WidgetManager){'
245 }
245 }
246
246
247 var $item_element = that.$buttongroup.find(item_query);
247 var $item_element = that.$buttongroup.find(item_query);
248 if (that.model.get('_value') == item) {
248 if (that.model.get('value_name') == item) {
249 $item_element.addClass('active');
249 $item_element.addClass('active');
250 } else {
250 } else {
251 $item_element.removeClass('active');
251 $item_element.removeClass('active');
@@ -285,7 +285,7 b' define(["notebook/js/widgets/widget"], function(WidgetManager){'
285
285
286 // Calling model.set will trigger all of the other views of the
286 // Calling model.set will trigger all of the other views of the
287 // model to update.
287 // model to update.
288 this.model.set('_value', $(e.target).text(), {updated_view: this});
288 this.model.set('value_name', $(e.target).text(), {updated_view: this});
289 this.touch();
289 this.touch();
290 },
290 },
291 });
291 });
@@ -316,21 +316,21 b' define(["notebook/js/widgets/widget"], function(WidgetManager){'
316 // changed by another view or by a state update from the back-end.
316 // changed by another view or by a state update from the back-end.
317 if (options === undefined || options.updated_view != this) {
317 if (options === undefined || options.updated_view != this) {
318 // Add missing items to the DOM.
318 // Add missing items to the DOM.
319 var items = this.model.get('labels');
319 var items = this.model.get('value_names');
320 var that = this;
320 var that = this;
321 _.each(items, function(item, index) {
321 _.each(items, function(item, index) {
322 var item_query = ' :contains("' + item + '")';
322 var item_query = ' :contains("' + item + '")';
323 if (that.$listbox.find(item_query).length === 0) {
323 if (that.$listbox.find(item_query).length === 0) {
324 $('<option />')
324 $('<option />')
325 .text(item)
325 .text(item)
326 .attr('_value', item)
326 .attr('value_name', item)
327 .appendTo(that.$listbox)
327 .appendTo(that.$listbox)
328 .on('click', $.proxy(that.handle_click, that));
328 .on('click', $.proxy(that.handle_click, that));
329 }
329 }
330 });
330 });
331
331
332 // Select the correct element
332 // Select the correct element
333 this.$listbox.val(this.model.get('_value'));
333 this.$listbox.val(this.model.get('value_name'));
334
334
335 // Disable listbox if needed
335 // Disable listbox if needed
336 var disabled = this.model.get('disabled');
336 var disabled = this.model.get('disabled');
@@ -368,7 +368,7 b' define(["notebook/js/widgets/widget"], function(WidgetManager){'
368
368
369 // Calling model.set will trigger all of the other views of the
369 // Calling model.set will trigger all of the other views of the
370 // model to update.
370 // model to update.
371 this.model.set('_value', $(e.target).text(), {updated_view: this});
371 this.model.set('value_name', $(e.target).text(), {updated_view: this});
372 this.touch();
372 this.touch();
373 },
373 },
374 });
374 });
@@ -123,7 +123,9 b' casper.notebook_test(function () {'
123
123
124 index = this.append_cell(
124 index = this.append_cell(
125 'for widget in selection:\n' +
125 'for widget in selection:\n' +
126 ' widget.values = list(widget.values) + ["z"]\n' +
126 ' d = widget.values.copy()\n' +
127 ' d["z"] = "z"\n' +
128 ' widget.values = d\n' +
127 'selection[0].value = "z"');
129 'selection[0].value = "z"');
128 this.execute_cell_then(index, function(index){
130 this.execute_cell_then(index, function(index){
129
131
@@ -1,4 +1,4 b''
1 """SelectionWidget class.
1 """SelectionWidget classes.
2
2
3 Represents an enumeration using a widget.
3 Represents an enumeration using a widget.
4 """
4 """
@@ -13,66 +13,84 b' Represents an enumeration using a widget.'
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
17 from collections import OrderedDict
16 from threading import Lock
18 from threading import Lock
17
19
18 from .widget import DOMWidget
20 from .widget import DOMWidget
19 from IPython.utils.traitlets import Unicode, List, Bool, Any, Dict
21 from IPython.utils.traitlets import Unicode, List, Bool, Any, Dict, TraitError
22 from IPython.utils.py3compat import unicode_type
20
23
21 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
22 # SelectionWidget
25 # SelectionWidget
23 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
24 class _SelectionWidget(DOMWidget):
27 class _SelectionWidget(DOMWidget):
25 value = Any(help="Selected value")
28 """Base class for Selection widgets
26 values = List(help="List of values the user can select")
29
27 labels = List(help="""List of string representations for each value.
30 ``values`` can be specified as a list or dict. If given as a list,
28 These string representations are used to display the values in the
31 it will be transformed to a dict of the form ``{str(value):value}``.
29 front-end.""", sync=True) # Only synced to the back-end.
32 """
33
34 value = Any(help="Selected value")
35 values = Dict(help="""Dictionary of {name: value} the user can select.
36
37 The keys of this dictionary are the strings that will be displayed in the UI,
38 representing the actual Python choices.
39
40 The keys of this dictionary are also available as value_names.
41 """)
42 value_name = Unicode(help="The name of the selected value", sync=True)
43 value_names = List(Unicode, help="""List of names for each value.
44
45 If values is specified as a list, this is the string representation of each element.
46 Otherwise, it is the keys of the values dictionary.
47
48 These strings are used to display the choices in the front-end.""", sync=True)
30 disabled = Bool(False, help="Enable or disable user changes", sync=True)
49 disabled = Bool(False, help="Enable or disable user changes", sync=True)
31 description = Unicode(help="Description of the value this widget represents", sync=True)
50 description = Unicode(help="Description of the value this widget represents", sync=True)
51
32
52
33 _value = Unicode(sync=True) # Bi-directionally synced.
53 def __init__(self, *args, **kwargs):
34
35 def __init__(self, *pargs, **kwargs):
36 """Constructor"""
37 self.value_lock = Lock()
54 self.value_lock = Lock()
38 self.on_trait_change(self._string_value_set, ['_value'])
55 if 'values' in kwargs:
39 DOMWidget.__init__(self, *pargs, **kwargs)
56 values = kwargs['values']
40
57 # convert list values to an dict of {str(v):v}
41 def _labels_changed(self, name=None, old=None, new=None):
58 if isinstance(values, list):
42 """Handles when the value_names Dict has been changed.
59 # preserve list order with an OrderedDict
60 kwargs['values'] = OrderedDict((unicode_type(v), v) for v in values)
61 DOMWidget.__init__(self, *args, **kwargs)
62
63 def _values_changed(self, name, old, new):
64 """Handles when the values dict has been changed.
43
65
44 This method sets the _reverse_value_names Dict to the inverse of the new
66 Setting values implies setting value names from the keys of the dict.
45 value for the value_names Dict."""
67 """
68 self.value_names = list(new.keys())
69
70 def _value_names_changed(self, name, old, new):
46 if len(new) != len(self.values):
71 if len(new) != len(self.values):
47 raise TypeError('Labels list must be the same size as the values list.')
72 raise TraitError("Expected %i value names, got %i." % (len(self.values), len(new)))
48
49 def _values_changed(self, name=None, old=None, new=None):
50 """Handles when the value_names Dict has been changed.
51
52 This method sets the _reverse_value_names Dict to the inverse of the new
53 value for the value_names Dict."""
54 if len(new) != len(self.labels):
55 self.labels = [(self.labels[i] if i < len(self.labels) else str(v)) for i, v in enumerate(new)]
56
73
57 def _value_changed(self, name, old, new):
74 def _value_changed(self, name, old, new):
58 """Called when value has been changed"""
75 """Called when value has been changed"""
59 if self.value_lock.acquire(False):
76 if self.value_lock.acquire(False):
60 try:
77 try:
61 # Make sure the value is in the list of values.
78 # Make sure the value is one of the options
62 if new in self.values:
79 for k,v in self.values.items():
63 # Set the string version of the value.
80 if new == v:
64 self._value = self.labels[self.values.index(new)]
81 # set the selected value name
65 else:
82 self.value_name = k
66 raise TypeError('Value must be a value in the values list.')
83 return
84 raise TraitError('Value not found: %r' % new)
67 finally:
85 finally:
68 self.value_lock.release()
86 self.value_lock.release()
69
87
70 def _string_value_set(self, name, old, new):
88 def _value_name_changed(self, name, old, new):
71 """Called when _value has been changed."""
89 """Called when the value name has been changed (typically by the frontend)."""
72 if self.value_lock.acquire(False):
90 if self.value_lock.acquire(False):
73 try:
91 try:
74 if new in self.labels:
92 if new in self.values:
75 self.value = self.values[self.labels.index(new)]
93 self.value = self.values[new]
76 else:
94 else:
77 self.value = None
95 self.value = None
78 finally:
96 finally:
General Comments 0
You need to be logged in to leave comments. Login now