##// END OF EJS Templates
Float widget views now inherit from int counterparts
Jonathan Frederic -
Show More
@@ -1,268 +1,42 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2013 The IPython Development Team
2 // Copyright (C) 2013 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // FloatWidget
9 // FloatWidget
10 //============================================================================
10 //============================================================================
11
11
12 /**
12 /**
13 * @module IPython
13 * @module IPython
14 * @namespace IPython
14 * @namespace IPython
15 **/
15 **/
16
16
17 define(["notebook/js/widgets/widget"], function(WidgetManager){
17 define(["notebook/js/widgets/widget",
18 "notebook/js/widgets/widget_int"],
19 function(WidgetManager, int_widgets){
18
20
19 var FloatSliderView = IPython.DOMWidgetView.extend({
21 var IntSliderView = int_widgets[0];
20 render : function(){
22 var IntTextView = int_widgets[1];
21 // Called when view is rendered.
22 this.$el
23 .addClass('widget-hbox-single');
24 this.$label = $('<div />')
25 .appendTo(this.$el)
26 .addClass('widget-hlabel')
27 .hide();
28 this.$slider = $('<div />')
29 .slider({})
30 .addClass('slider');
31
32 // Put the slider in a container
33 this.$slider_container = $('<div />')
34 .addClass('widget-hslider')
35 .append(this.$slider);
36 this.$el_to_style = this.$slider_container; // Set default element to style
37 this.$el.append(this.$slider_container);
38
39 // Set defaults.
40 this.update();
41 },
42
43 update : function(options){
44 // Update the contents of this view
45 //
46 // Called when the model is changed. The model may have been
47 // changed by another view or by a state update from the back-end.
48
49 if (options === undefined || options.updated_view != this) {
50 // JQuery slider option keys. These keys happen to have a
51 // one-to-one mapping with the corrosponding keys of the model.
52 var jquery_slider_keys = ['step', 'max', 'min', 'disabled'];
53 var that = this;
54 _.each(jquery_slider_keys, function(key, i) {
55 var model_value = that.model.get(key);
56 if (model_value !== undefined) {
57 that.$slider.slider("option", key, model_value);
58 }
59 });
60
61 // WORKAROUND FOR JQUERY SLIDER BUG.
62 // The horizontal position of the slider handle
63 // depends on the value of the slider at the time
64 // of orientation change. Before applying the new
65 // workaround, we set the value to the minimum to
66 // make sure that the horizontal placement of the
67 // handle in the vertical slider is always
68 // consistent.
69 var orientation = this.model.get('orientation');
70 var value = this.model.get('min');
71 this.$slider.slider('option', 'value', value);
72 this.$slider.slider('option', 'orientation', orientation);
73 value = this.model.get('value');
74 this.$slider.slider('option', 'value', value);
75
76 // Use the right CSS classes for vertical & horizontal sliders
77 if (orientation=='vertical') {
78 this.$slider_container
79 .removeClass('widget-hslider')
80 .addClass('widget-vslider');
81 this.$el
82 .removeClass('widget-hbox-single')
83 .addClass('widget-vbox-single');
84 this.$label
85 .removeClass('widget-hlabel')
86 .addClass('widget-vlabel');
87
88 } else {
89 this.$slider_container
90 .removeClass('widget-vslider')
91 .addClass('widget-hslider');
92 this.$el
93 .removeClass('widget-vbox-single')
94 .addClass('widget-hbox-single');
95 this.$label
96 .removeClass('widget-vlabel')
97 .addClass('widget-hlabel');
98 }
99
23
100 var description = this.model.get('description');
101 if (description.length === 0) {
102 this.$label.hide();
103 } else {
104 this.$label.text(description);
105 this.$label.show();
106 }
107 }
108 return FloatSliderView.__super__.update.apply(this);
109 },
110
111 events: {
112 // Dictionary of events and their handlers.
113 "slide" : "handleSliderChange"
114 },
115
116 handleSliderChange: function(e, ui) {
117 // Handle when the slider value is changed.
118
24
119 // Calling model.set will trigger all of the other views of the
25 var FloatSliderView = IntSliderView.extend({
120 // model to update.
26 _validate_slide_value: function(x) {
121 this.model.set('value', ui.value, {updated_view: this});
27 // Validate the value of the slider before sending it to the back-end
122 this.touch();
28 // and applying it to the other views on the page.
29 return x;
123 },
30 },
124 });
31 });
125 WidgetManager.register_widget_view('FloatSliderView', FloatSliderView);
32 WidgetManager.register_widget_view('FloatSliderView', FloatSliderView);
126
33
127
34
128 var FloatTextView = IPython.DOMWidgetView.extend({
35 var FloatTextView = IntTextView.extend({
129 render : function(){
36 _parse_value: function(value) {
130 // Called when view is rendered.
37 // Parse the value stored in a string.
131 this.$el
38 return parseFloat(value);
132 .addClass('widget-hbox-single');
133 this.$label = $('<div />')
134 .appendTo(this.$el)
135 .addClass('widget-hlabel')
136 .hide();
137 this.$textbox = $('<input type="text" />')
138 .addClass('input')
139 .addClass('widget-numeric-text')
140 .appendTo(this.$el);
141 this.$el_to_style = this.$textbox; // Set default element to style
142 this.update(); // Set defaults.
143 },
144
145 update : function(options){
146 // Update the contents of this view
147 //
148 // Called when the model is changed. The model may have been
149 // changed by another view or by a state update from the back-end.
150 if (options === undefined || options.updated_view != this) {
151 var value = this.model.get('value');
152 if (parseFloat(this.$textbox.val()) != value) {
153 this.$textbox.val(value);
154 }
155
156 if (this.model.get('disabled')) {
157 this.$textbox.attr('disabled','disabled');
158 } else {
159 this.$textbox.removeAttr('disabled');
160 }
161
162 var description = this.model.get('description');
163 if (description.length === 0) {
164 this.$label.hide();
165 } else {
166 this.$label.text(description);
167 this.$label.show();
168 }
169 }
170 return FloatTextView.__super__.update.apply(this);
171 },
172
173 events: {
174 // Dictionary of events and their handlers.
175
176 "keyup input" : "handleChanging",
177 "paste input" : "handleChanging",
178 "cut input" : "handleChanging",
179
180 // Fires only when control is validated or looses focus.
181 "change input" : "handleChanged"
182 },
183
184 handleChanging: function(e) {
185 // Handles and validates user input.
186
187 // Try to parse value as a float.
188 var numericalValue = 0.0;
189 if (e.target.value !== '') {
190 numericalValue = parseFloat(e.target.value);
191 }
192
193 // If parse failed, reset value to value stored in model.
194 if (isNaN(numericalValue)) {
195 e.target.value = this.model.get('value');
196 } else if (!isNaN(numericalValue)) {
197 if (this.model.get('max') !== undefined) {
198 numericalValue = Math.min(this.model.get('max'), numericalValue);
199 }
200 if (this.model.get('min') !== undefined) {
201 numericalValue = Math.max(this.model.get('min'), numericalValue);
202 }
203
204 // Apply the value if it has changed.
205 if (numericalValue != this.model.get('value')) {
206
207 // Calling model.set will trigger all of the other views of the
208 // model to update.
209 this.model.set('value', numericalValue, {updated_view: this});
210 this.touch();
211 }
212 }
213 },
39 },
214
215 handleChanged: function(e) {
216 // Applies validated input.
217 if (this.model.get('value') != e.target.value) {
218 e.target.value = this.model.get('value');
219 }
220 }
221 });
40 });
222 WidgetManager.register_widget_view('FloatTextView', FloatTextView);
41 WidgetManager.register_widget_view('FloatTextView', FloatTextView);
223
224
225 var ProgressView = IPython.DOMWidgetView.extend({
226 render : function(){
227 // Called when view is rendered.
228 this.$el
229 .addClass('widget-hbox-single');
230 this.$label = $('<div />')
231 .appendTo(this.$el)
232 .addClass('widget-hlabel')
233 .hide();
234 this.$progress = $('<div />')
235 .addClass('progress')
236 .addClass('widget-progress')
237 .appendTo(this.$el);
238 this.$el_to_style = this.$progress; // Set default element to style
239 this.$bar = $('<div />')
240 .addClass('bar')
241 .css('width', '50%')
242 .appendTo(this.$progress);
243 this.update(); // Set defaults.
244 },
245
246 update : function(){
247 // Update the contents of this view
248 //
249 // Called when the model is changed. The model may have been
250 // changed by another view or by a state update from the back-end.
251 var value = this.model.get('value');
252 var max = this.model.get('max');
253 var min = this.model.get('min');
254 var percent = 100.0 * (value - min) / (max - min);
255 this.$bar.css('width', percent + '%');
256
257 var description = this.model.get('description');
258 if (description.length === 0) {
259 this.$label.hide();
260 } else {
261 this.$label.text(description);
262 this.$label.show();
263 }
264 return ProgressView.__super__.update.apply(this);
265 },
266 });
267 WidgetManager.register_widget_view('ProgressView', ProgressView);
268 });
42 });
@@ -1,221 +1,284 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2013 The IPython Development Team
2 // Copyright (C) 2013 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // IntWidget
9 // IntWidget
10 //============================================================================
10 //============================================================================
11
11
12 /**
12 /**
13 * @module IPython
13 * @module IPython
14 * @namespace IPython
14 * @namespace IPython
15 **/
15 **/
16
16
17 define(["notebook/js/widgets/widget"], function(WidgetManager){
17 define(["notebook/js/widgets/widget"], function(WidgetManager){
18
18
19 var IntSliderView = IPython.DOMWidgetView.extend({
19 var IntSliderView = IPython.DOMWidgetView.extend({
20 render : function(){
20 render : function(){
21 // Called when view is rendered.
21 // Called when view is rendered.
22 this.$el
22 this.$el
23 .addClass('widget-hbox-single');
23 .addClass('widget-hbox-single');
24 this.$label = $('<div />')
24 this.$label = $('<div />')
25 .appendTo(this.$el)
25 .appendTo(this.$el)
26 .addClass('widget-hlabel')
26 .addClass('widget-hlabel')
27 .hide();
27 .hide();
28 this.$slider = $('<div />')
28 this.$slider = $('<div />')
29 .slider({})
29 .slider({})
30 .addClass('slider');
30 .addClass('slider');
31
31
32 // Put the slider in a container
32 // Put the slider in a container
33 this.$slider_container = $('<div />')
33 this.$slider_container = $('<div />')
34 .addClass('widget-hslider')
34 .addClass('widget-hslider')
35 .append(this.$slider);
35 .append(this.$slider);
36 this.$el_to_style = this.$slider_container; // Set default element to style
36 this.$el_to_style = this.$slider_container; // Set default element to style
37 this.$el.append(this.$slider_container);
37 this.$el.append(this.$slider_container);
38
38
39 // Set defaults.
39 // Set defaults.
40 this.update();
40 this.update();
41 },
41 },
42
42
43 update : function(options){
43 update : function(options){
44 // Update the contents of this view
44 // Update the contents of this view
45 //
45 //
46 // Called when the model is changed. The model may have been
46 // Called when the model is changed. The model may have been
47 // changed by another view or by a state update from the back-end.
47 // changed by another view or by a state update from the back-end.
48 if (options === undefined || options.updated_view != this) {
48 if (options === undefined || options.updated_view != this) {
49 // JQuery slider option keys. These keys happen to have a
49 // JQuery slider option keys. These keys happen to have a
50 // one-to-one mapping with the corrosponding keys of the model.
50 // one-to-one mapping with the corrosponding keys of the model.
51 var jquery_slider_keys = ['step', 'max', 'min', 'disabled'];
51 var jquery_slider_keys = ['step', 'max', 'min', 'disabled'];
52 var that = this;
52 var that = this;
53 _.each(jquery_slider_keys, function(key, i) {
53 _.each(jquery_slider_keys, function(key, i) {
54 var model_value = that.model.get(key);
54 var model_value = that.model.get(key);
55 if (model_value !== undefined) {
55 if (model_value !== undefined) {
56 that.$slider.slider("option", key, model_value);
56 that.$slider.slider("option", key, model_value);
57 }
57 }
58 });
58 });
59
59
60 // WORKAROUND FOR JQUERY SLIDER BUG.
60 // WORKAROUND FOR JQUERY SLIDER BUG.
61 // The horizontal position of the slider handle
61 // The horizontal position of the slider handle
62 // depends on the value of the slider at the time
62 // depends on the value of the slider at the time
63 // of orientation change. Before applying the new
63 // of orientation change. Before applying the new
64 // workaround, we set the value to the minimum to
64 // workaround, we set the value to the minimum to
65 // make sure that the horizontal placement of the
65 // make sure that the horizontal placement of the
66 // handle in the vertical slider is always
66 // handle in the vertical slider is always
67 // consistent.
67 // consistent.
68 var orientation = this.model.get('orientation');
68 var orientation = this.model.get('orientation');
69 var value = this.model.get('min');
69 var value = this.model.get('min');
70 this.$slider.slider('option', 'value', value);
70 this.$slider.slider('option', 'value', value);
71 this.$slider.slider('option', 'orientation', orientation);
71 this.$slider.slider('option', 'orientation', orientation);
72 value = this.model.get('value');
72 value = this.model.get('value');
73 this.$slider.slider('option', 'value', value);
73 this.$slider.slider('option', 'value', value);
74
74
75 // Use the right CSS classes for vertical & horizontal sliders
75 // Use the right CSS classes for vertical & horizontal sliders
76 if (orientation=='vertical') {
76 if (orientation=='vertical') {
77 this.$slider_container
77 this.$slider_container
78 .removeClass('widget-hslider')
78 .removeClass('widget-hslider')
79 .addClass('widget-vslider');
79 .addClass('widget-vslider');
80 this.$el
80 this.$el
81 .removeClass('widget-hbox-single')
81 .removeClass('widget-hbox-single')
82 .addClass('widget-vbox-single');
82 .addClass('widget-vbox-single');
83 this.$label
83 this.$label
84 .removeClass('widget-hlabel')
84 .removeClass('widget-hlabel')
85 .addClass('widget-vlabel');
85 .addClass('widget-vlabel');
86
86
87 } else {
87 } else {
88 this.$slider_container
88 this.$slider_container
89 .removeClass('widget-vslider')
89 .removeClass('widget-vslider')
90 .addClass('widget-hslider');
90 .addClass('widget-hslider');
91 this.$el
91 this.$el
92 .removeClass('widget-vbox-single')
92 .removeClass('widget-vbox-single')
93 .addClass('widget-hbox-single');
93 .addClass('widget-hbox-single');
94 this.$label
94 this.$label
95 .removeClass('widget-vlabel')
95 .removeClass('widget-vlabel')
96 .addClass('widget-hlabel');
96 .addClass('widget-hlabel');
97 }
97 }
98
98
99 var description = this.model.get('description');
99 var description = this.model.get('description');
100 if (description.length === 0) {
100 if (description.length === 0) {
101 this.$label.hide();
101 this.$label.hide();
102 } else {
102 } else {
103 this.$label.text(description);
103 this.$label.text(description);
104 this.$label.show();
104 this.$label.show();
105 }
105 }
106 }
106 }
107 return IntSliderView.__super__.update.apply(this);
107 return IntSliderView.__super__.update.apply(this);
108 },
108 },
109
109
110 events: {
110 events: {
111 // Dictionary of events and their handlers.
111 // Dictionary of events and their handlers.
112 "slide" : "handleSliderChange"
112 "slide" : "handleSliderChange"
113 },
113 },
114
114
115 handleSliderChange: function(e, ui) {
115 handleSliderChange: function(e, ui) {
116 // Called when the slider value is changed.
116 // Called when the slider value is changed.
117
117
118 // Calling model.set will trigger all of the other views of the
118 // Calling model.set will trigger all of the other views of the
119 // model to update.
119 // model to update.
120 this.model.set('value', ~~ui.value, {updated_view: this}); // Double bit-wise not to truncate decimel
120 this.model.set('value', this._validate_slide_value(ui.value), {updated_view: this});
121 this.touch();
121 this.touch();
122 },
122 },
123
124 _validate_slide_value: function(x) {
125 // Validate the value of the slider before sending it to the back-end
126 // and applying it to the other views on the page.
127
128 // Double bit-wise not truncates the decimel (int cast).
129 return ~~x;
130 },
123 });
131 });
124 WidgetManager.register_widget_view('IntSliderView', IntSliderView);
132 WidgetManager.register_widget_view('IntSliderView', IntSliderView);
125
133
126
134
127 var IntTextView = IPython.DOMWidgetView.extend({
135 var IntTextView = IPython.DOMWidgetView.extend({
128 render : function(){
136 render : function(){
129 // Called when view is rendered.
137 // Called when view is rendered.
130 this.$el
138 this.$el
131 .addClass('widget-hbox-single');
139 .addClass('widget-hbox-single');
132 this.$label = $('<div />')
140 this.$label = $('<div />')
133 .appendTo(this.$el)
141 .appendTo(this.$el)
134 .addClass('widget-hlabel')
142 .addClass('widget-hlabel')
135 .hide();
143 .hide();
136 this.$textbox = $('<input type="text" />')
144 this.$textbox = $('<input type="text" />')
137 .addClass('input')
145 .addClass('input')
138 .addClass('widget-numeric-text')
146 .addClass('widget-numeric-text')
139 .appendTo(this.$el);
147 .appendTo(this.$el);
140 this.$el_to_style = this.$textbox; // Set default element to style
148 this.$el_to_style = this.$textbox; // Set default element to style
141 this.update(); // Set defaults.
149 this.update(); // Set defaults.
142 },
150 },
143
151
144 update : function(options){
152 update : function(options){
145 // Update the contents of this view
153 // Update the contents of this view
146 //
154 //
147 // Called when the model is changed. The model may have been
155 // Called when the model is changed. The model may have been
148 // changed by another view or by a state update from the back-end.
156 // changed by another view or by a state update from the back-end.
149 if (options === undefined || options.updated_view != this) {
157 if (options === undefined || options.updated_view != this) {
150 var value = this.model.get('value');
158 var value = this.model.get('value');
151 if (parseInt(this.$textbox.val()) != value) {
159 if (this._parse_value(this.$textbox.val()) != value) {
152 this.$textbox.val(value);
160 this.$textbox.val(value);
153 }
161 }
154
162
155 if (this.model.get('disabled')) {
163 if (this.model.get('disabled')) {
156 this.$textbox.attr('disabled','disabled');
164 this.$textbox.attr('disabled','disabled');
157 } else {
165 } else {
158 this.$textbox.removeAttr('disabled');
166 this.$textbox.removeAttr('disabled');
159 }
167 }
160
168
161 var description = this.model.get('description');
169 var description = this.model.get('description');
162 if (description.length === 0) {
170 if (description.length === 0) {
163 this.$label.hide();
171 this.$label.hide();
164 } else {
172 } else {
165 this.$label.text(description);
173 this.$label.text(description);
166 this.$label.show();
174 this.$label.show();
167 }
175 }
168 }
176 }
169 return IntTextView.__super__.update.apply(this);
177 return IntTextView.__super__.update.apply(this);
170 },
178 },
171
179
172 events: {
180 events: {
173 // Dictionary of events and their handlers.
181 // Dictionary of events and their handlers.
174 "keyup input" : "handleChanging",
182 "keyup input" : "handleChanging",
175 "paste input" : "handleChanging",
183 "paste input" : "handleChanging",
176 "cut input" : "handleChanging",
184 "cut input" : "handleChanging",
177
185
178 // Fires only when control is validated or looses focus.
186 // Fires only when control is validated or looses focus.
179 "change input" : "handleChanged"
187 "change input" : "handleChanged"
180 },
188 },
181
189
182 handleChanging: function(e) {
190 handleChanging: function(e) {
183 // Handles and validates user input.
191 // Handles and validates user input.
184
192
185 // Try to parse value as a float.
193 // Try to parse value as a int.
186 var numericalValue = 0;
194 var numericalValue = 0;
187 if (e.target.value !== '') {
195 if (e.target.value !== '') {
188 numericalValue = parseInt(e.target.value);
196 numericalValue = this._parse_value(e.target.value);
189 }
197 }
190
198
191 // If parse failed, reset value to value stored in model.
199 // If parse failed, reset value to value stored in model.
192 if (isNaN(numericalValue)) {
200 if (isNaN(numericalValue)) {
193 e.target.value = this.model.get('value');
201 e.target.value = this.model.get('value');
194 } else if (!isNaN(numericalValue)) {
202 } else if (!isNaN(numericalValue)) {
195 if (this.model.get('max') !== undefined) {
203 if (this.model.get('max') !== undefined) {
196 numericalValue = Math.min(this.model.get('max'), numericalValue);
204 numericalValue = Math.min(this.model.get('max'), numericalValue);
197 }
205 }
198 if (this.model.get('min') !== undefined) {
206 if (this.model.get('min') !== undefined) {
199 numericalValue = Math.max(this.model.get('min'), numericalValue);
207 numericalValue = Math.max(this.model.get('min'), numericalValue);
200 }
208 }
201
209
202 // Apply the value if it has changed.
210 // Apply the value if it has changed.
203 if (numericalValue != this.model.get('value')) {
211 if (numericalValue != this.model.get('value')) {
204
212
205 // Calling model.set will trigger all of the other views of the
213 // Calling model.set will trigger all of the other views of the
206 // model to update.
214 // model to update.
207 this.model.set('value', numericalValue, {updated_view: this});
215 this.model.set('value', numericalValue, {updated_view: this});
208 this.touch();
216 this.touch();
209 }
217 }
210 }
218 }
211 },
219 },
212
220
213 handleChanged: function(e) {
221 handleChanged: function(e) {
214 // Applies validated input.
222 // Applies validated input.
215 if (this.model.get('value') != e.target.value) {
223 if (this.model.get('value') != e.target.value) {
216 e.target.value = this.model.get('value');
224 e.target.value = this.model.get('value');
217 }
225 }
218 }
226 },
227
228 _parse_value: function(value) {
229 // Parse the value stored in a string.
230 return parseInt(value);
231 },
219 });
232 });
220 WidgetManager.register_widget_view('IntTextView', IntTextView);
233 WidgetManager.register_widget_view('IntTextView', IntTextView);
234
235
236 var ProgressView = IPython.DOMWidgetView.extend({
237 render : function(){
238 // Called when view is rendered.
239 this.$el
240 .addClass('widget-hbox-single');
241 this.$label = $('<div />')
242 .appendTo(this.$el)
243 .addClass('widget-hlabel')
244 .hide();
245 this.$progress = $('<div />')
246 .addClass('progress')
247 .addClass('widget-progress')
248 .appendTo(this.$el);
249 this.$el_to_style = this.$progress; // Set default element to style
250 this.$bar = $('<div />')
251 .addClass('bar')
252 .css('width', '50%')
253 .appendTo(this.$progress);
254 this.update(); // Set defaults.
255 },
256
257 update : function(){
258 // Update the contents of this view
259 //
260 // Called when the model is changed. The model may have been
261 // changed by another view or by a state update from the back-end.
262 var value = this.model.get('value');
263 var max = this.model.get('max');
264 var min = this.model.get('min');
265 var percent = 100.0 * (value - min) / (max - min);
266 this.$bar.css('width', percent + '%');
267
268 var description = this.model.get('description');
269 if (description.length === 0) {
270 this.$label.hide();
271 } else {
272 this.$label.text(description);
273 this.$label.show();
274 }
275 return ProgressView.__super__.update.apply(this);
276 },
277 });
278 WidgetManager.register_widget_view('ProgressView', ProgressView);
279
280
281 // Return the slider and text views so they can be inheritted to create the
282 // float versions.
283 return [IntSliderView, IntTextView];
221 });
284 });
General Comments 0
You need to be logged in to leave comments. Login now