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