##// END OF EJS Templates
Add support for parsing pairs of numbers for range sliders
Gordon Ball -
Show More
@@ -1,34 +1,34
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 "widgets/js/widget_int",
6 "widgets/js/widget_int",
7 ], function(widget, int_widgets){
7 ], function(widget, int_widgets){
8 var IntSliderView = int_widgets.IntSliderView;
8 var IntSliderView = int_widgets.IntSliderView;
9 var IntTextView = int_widgets.IntTextView;
9 var IntTextView = int_widgets.IntTextView;
10
10
11 var FloatSliderView = IntSliderView.extend({
11 var FloatSliderView = IntSliderView.extend({
12 _validate_text_input: function(x) {
12 _parse_text_input: parseFloat,
13 return parseFloat(x);
13
14 },
14 _range_regex: /^\s*([+-]?\d*\.?\d+)\s*[-:]\s*([+-]?\d*\.?\d+)/,
15
15
16 _validate_slide_value: function(x) {
16 _validate_slide_value: function(x) {
17 // Validate the value of the slider before sending it to the back-end
17 // Validate the value of the slider before sending it to the back-end
18 // and applying it to the other views on the page.
18 // and applying it to the other views on the page.
19 return x;
19 return x;
20 },
20 },
21 });
21 });
22
22
23 var FloatTextView = IntTextView.extend({
23 var FloatTextView = IntTextView.extend({
24 _parse_value: function(value) {
24 _parse_value: function(value) {
25 // Parse the value stored in a string.
25 // Parse the value stored in a string.
26 return parseFloat(value);
26 return parseFloat(value);
27 },
27 },
28 });
28 });
29
29
30 return {
30 return {
31 'FloatSliderView': FloatSliderView,
31 'FloatSliderView': FloatSliderView,
32 'FloatTextView': FloatTextView,
32 'FloatTextView': FloatTextView,
33 };
33 };
34 });
34 });
@@ -1,413 +1,449
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 "bootstrap",
7 "bootstrap",
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');
14 .addClass('widget-hbox');
15 this.$label = $('<div />')
15 this.$label = $('<div />')
16 .appendTo(this.$el)
16 .appendTo(this.$el)
17 .addClass('widget-label')
17 .addClass('widget-label')
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.append(this.$slider_container);
27 this.$el.append(this.$slider_container);
28
28
29 this.$readout = $('<div/>')
29 this.$readout = $('<div/>')
30 .appendTo(this.$el)
30 .appendTo(this.$el)
31 .addClass('widget-readout')
31 .addClass('widget-readout')
32 .attr('contentEditable', true)
32 .attr('contentEditable', true)
33 .hide();
33 .hide();
34
34
35 this.model.on('change:slider_color', function(sender, value) {
35 this.model.on('change:slider_color', function(sender, value) {
36 this.$slider.find('a').css('background', value);
36 this.$slider.find('a').css('background', value);
37 }, this);
37 }, this);
38 this.$slider.find('a').css('background', this.model.get('slider_color'));
38 this.$slider.find('a').css('background', this.model.get('slider_color'));
39
39
40 // Set defaults.
40 // Set defaults.
41 this.update();
41 this.update();
42 },
42 },
43
43
44 update_attr: function(name, value) {
44 update_attr: function(name, value) {
45 // Set a css attr of the widget view.
45 // Set a css attr of the widget view.
46 if (name == 'color') {
46 if (name == 'color') {
47 this.$readout.css(name, value);
47 this.$readout.css(name, value);
48 } else if (name.substring(0, 4) == 'font') {
48 } else if (name.substring(0, 4) == 'font') {
49 this.$readout.css(name, value);
49 this.$readout.css(name, value);
50 } else if (name.substring(0, 6) == 'border') {
50 } else if (name.substring(0, 6) == 'border') {
51 this.$slider.find('a').css(name, value);
51 this.$slider.find('a').css(name, value);
52 this.$slider_container.css(name, value);
52 this.$slider_container.css(name, value);
53 } else if (name == 'width' || name == 'height' || name == 'background') {
53 } else if (name == 'width' || name == 'height' || name == 'background') {
54 this.$slider_container.css(name, value);
54 this.$slider_container.css(name, value);
55 } else {
55 } else {
56 this.$slider.css(name, value);
56 this.$slider.css(name, value);
57 }
57 }
58 },
58 },
59
59
60 update : function(options){
60 update : function(options){
61 // Update the contents of this view
61 // Update the contents of this view
62 //
62 //
63 // Called when the model is changed. The model may have been
63 // Called when the model is changed. The model may have been
64 // changed by another view or by a state update from the back-end.
64 // changed by another view or by a state update from the back-end.
65 if (options === undefined || options.updated_view != this) {
65 if (options === undefined || options.updated_view != this) {
66 // JQuery slider option keys. These keys happen to have a
66 // JQuery slider option keys. These keys happen to have a
67 // one-to-one mapping with the corrosponding keys of the model.
67 // one-to-one mapping with the corrosponding keys of the model.
68 var jquery_slider_keys = ['step', 'max', 'min', 'disabled'];
68 var jquery_slider_keys = ['step', 'max', 'min', 'disabled'];
69 var that = this;
69 var that = this;
70 that.$slider.slider({});
70 that.$slider.slider({});
71 _.each(jquery_slider_keys, function(key, i) {
71 _.each(jquery_slider_keys, function(key, i) {
72 var model_value = that.model.get(key);
72 var model_value = that.model.get(key);
73 if (model_value !== undefined) {
73 if (model_value !== undefined) {
74 that.$slider.slider("option", key, model_value);
74 that.$slider.slider("option", key, model_value);
75 }
75 }
76 });
76 });
77 var range_value = this.model.get("_range");
77 var range_value = this.model.get("_range");
78 if (range_value !== undefined) {
78 if (range_value !== undefined) {
79 this.$slider.slider("option", "range", range_value);
79 this.$slider.slider("option", "range", range_value);
80 }
80 }
81
81
82 // WORKAROUND FOR JQUERY SLIDER BUG.
82 // WORKAROUND FOR JQUERY SLIDER BUG.
83 // The horizontal position of the slider handle
83 // The horizontal position of the slider handle
84 // depends on the value of the slider at the time
84 // depends on the value of the slider at the time
85 // of orientation change. Before applying the new
85 // of orientation change. Before applying the new
86 // workaround, we set the value to the minimum to
86 // workaround, we set the value to the minimum to
87 // make sure that the horizontal placement of the
87 // make sure that the horizontal placement of the
88 // handle in the vertical slider is always
88 // handle in the vertical slider is always
89 // consistent.
89 // consistent.
90 var orientation = this.model.get('orientation');
90 var orientation = this.model.get('orientation');
91 var min = this.model.get('min');
91 var min = this.model.get('min');
92 var max = this.model.get('max');
92 var max = this.model.get('max');
93 if (this.model.get('_range')) {
93 if (this.model.get('_range')) {
94 this.$slider.slider('option', 'values', [min, min]);
94 this.$slider.slider('option', 'values', [min, min]);
95 } else {
95 } else {
96 this.$slider.slider('option', 'value', min);
96 this.$slider.slider('option', 'value', min);
97 }
97 }
98 this.$slider.slider('option', 'orientation', orientation);
98 this.$slider.slider('option', 'orientation', orientation);
99 var value = this.model.get('value');
99 var value = this.model.get('value');
100 if (this.model.get('_range')) {
100 if (this.model.get('_range')) {
101 // values for the range case are validated python-side in
101 // values for the range case are validated python-side in
102 // _Bounded{Int,Float}RangeWidget._validate
102 // _Bounded{Int,Float}RangeWidget._validate
103 this.$slider.slider('option', 'values', value);
103 this.$slider.slider('option', 'values', value);
104 this.$readout.text(value.join("-"));
104 this.$readout.text(value.join("-"));
105 } else {
105 } else {
106 if(value > max) {
106 if(value > max) {
107 value = max;
107 value = max;
108 }
108 }
109 else if(value < min){
109 else if(value < min){
110 value = min;
110 value = min;
111 }
111 }
112 this.$slider.slider('option', 'value', value);
112 this.$slider.slider('option', 'value', value);
113 this.$readout.text(value);
113 this.$readout.text(value);
114 }
114 }
115
115
116 if(this.model.get('value')!=value) {
116 if(this.model.get('value')!=value) {
117 this.model.set('value', value, {updated_view: this});
117 this.model.set('value', value, {updated_view: this});
118 this.touch();
118 this.touch();
119 }
119 }
120
120
121 // Use the right CSS classes for vertical & horizontal sliders
121 // Use the right CSS classes for vertical & horizontal sliders
122 if (orientation=='vertical') {
122 if (orientation=='vertical') {
123 this.$slider_container
123 this.$slider_container
124 .removeClass('widget-hslider')
124 .removeClass('widget-hslider')
125 .addClass('widget-vslider');
125 .addClass('widget-vslider');
126 this.$el
126 this.$el
127 .removeClass('widget-hbox')
127 .removeClass('widget-hbox')
128 .addClass('widget-vbox');
128 .addClass('widget-vbox');
129
129
130 } else {
130 } else {
131 this.$slider_container
131 this.$slider_container
132 .removeClass('widget-vslider')
132 .removeClass('widget-vslider')
133 .addClass('widget-hslider');
133 .addClass('widget-hslider');
134 this.$el
134 this.$el
135 .removeClass('widget-vbox')
135 .removeClass('widget-vbox')
136 .addClass('widget-hbox');
136 .addClass('widget-hbox');
137 }
137 }
138
138
139 var description = this.model.get('description');
139 var description = this.model.get('description');
140 if (description.length === 0) {
140 if (description.length === 0) {
141 this.$label.hide();
141 this.$label.hide();
142 } else {
142 } else {
143 this.$label.text(description);
143 this.$label.text(description);
144 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
144 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
145 this.$label.show();
145 this.$label.show();
146 }
146 }
147
147
148 var readout = this.model.get('readout');
148 var readout = this.model.get('readout');
149 if (readout) {
149 if (readout) {
150 this.$readout.show();
150 this.$readout.show();
151 } else {
151 } else {
152 this.$readout.hide();
152 this.$readout.hide();
153 }
153 }
154 }
154 }
155 return IntSliderView.__super__.update.apply(this);
155 return IntSliderView.__super__.update.apply(this);
156 },
156 },
157
157
158 events: {
158 events: {
159 // Dictionary of events and their handlers.
159 // Dictionary of events and their handlers.
160 "slide" : "handleSliderChange",
160 "slide" : "handleSliderChange",
161 "blur [contentEditable=true]": "handleTextChange",
161 "blur [contentEditable=true]": "handleTextChange",
162 "keydown [contentEditable=true]": "handleKeyDown"
162 "keydown [contentEditable=true]": "handleKeyDown"
163 },
163 },
164
164
165 handleKeyDown: function(e) {
165 handleKeyDown: function(e) {
166 if (e.keyCode == 13) {
166 if (e.keyCode == 13) {
167 e.preventDefault();
167 e.preventDefault();
168 this.handleTextChange();
168 this.handleTextChange();
169 }
169 }
170 },
170 },
171
171
172 handleTextChange: function() {
172 handleTextChange: function() {
173 // this handles the entry of text into the contentEditable label
174 // first, the value is checked if it contains a parseable number
175 // (or pair of numbers, for the _range case)
176 // then it is clamped within the min-max range of the slider
177 // finally, the model is updated if the value is to be changed
178 //
179 // if any of these conditions are not met, the text is reset
180 //
181 // the step size is not enforced
182
173 var text = this.$readout.text();
183 var text = this.$readout.text();
174 var value = this._validate_text_input(text);
184 var vmin = this.model.get('min');
175 if (isNaN(value)) {
185 var vmax = this.model.get('max');
176 this.$readout.text(this.model.get('value'));
186 if (this.model.get("_range")) {
187 // range case
188 // ranges can be expressed either "val-val" or "val:val" (+spaces)
189 var match = this._range_regex.exec(text);
190 if (match) {
191 var values = [this._parse_text_input(match[1]),
192 this._parse_text_input(match[2])];
193 // reject input where NaN or lower > upper
194 if (isNaN(values[0]) ||
195 isNaN(values[1]) ||
196 (values[0] > values[1])) {
197 this.$readout.text(this.model.get('value').join('-'));
198 } else {
199 // clamp to range
200 values = [Math.max(Math.min(values[0], vmax), vmin),
201 Math.max(Math.min(values[1], vmax), vmin)];
202
203 if ((values[0] != this.model.get('value')[0]) ||
204 (values[1] != this.model.get('value')[1])) {
205 this.$readout.text(values.join('-'));
206 this.model.set('value', values, {updated_view: this});
207 this.touch();
208 } else {
209 this.$readout.text(this.model.get('value').join('-'));
210 }
211 }
212 } else {
213 this.$readout.text(this.model.get('value').join('-'));
214 }
177 } else {
215 } else {
178 //check for outside range
216 // single value case
179 if (value > this.model.get('max')) value = this.model.get('max');
217 var value = this._parse_text_input(text);
180 if (value < this.model.get('min')) value = this.model.get('min');
218 if (isNaN(value)) {
181
219 this.$readout.text(this.model.get('value'));
182 //update the readout unconditionally
220 } else {
183 //this covers eg, entering a float value which rounds to the
221 value = Math.max(Math.min(value, vmax), vmin);
184 //existing int value, which will not trigger an update since the model
222
185 //doesn't change, but we should update the text to reflect that
223 if (value != this.model.get('value')) {
186 //a float value isn't being used
224 this.$readout.text(value);
187 this.$readout.text(value);
225 this.model.set('value', value, {updated_view: this});
188
226 this.touch();
189 //note that the step size currently isn't enforced, so if an
227 } else {
190 //off-step value is input it will be retained
228 this.$readout.text(this.model.get('value'));
191
229 }
192 //update the model
230 }
193 this.model.set('value', value, {updated_view: this});
194 this.touch();
195 }
231 }
196 },
232 },
197
233
198 _validate_text_input: function(x) {
234 _parse_text_input: parseInt,
199 return parseInt(x);
235
200 },
236 _range_regex: /^\s*([+-]?\d+)\s*[-:]\s*([+-]?\d+)/,
201
237
202 handleSliderChange: function(e, ui) {
238 handleSliderChange: function(e, ui) {
203 // Called when the slider value is changed.
239 // Called when the slider value is changed.
204
240
205 // Calling model.set will trigger all of the other views of the
241 // Calling model.set will trigger all of the other views of the
206 // model to update.
242 // model to update.
207 if (this.model.get("_range")) {
243 if (this.model.get("_range")) {
208 var actual_value = ui.values.map(this._validate_slide_value);
244 var actual_value = ui.values.map(this._validate_slide_value);
209 this.$readout.text(actual_value.join("-"));
245 this.$readout.text(actual_value.join("-"));
210 } else {
246 } else {
211 var actual_value = this._validate_slide_value(ui.value);
247 var actual_value = this._validate_slide_value(ui.value);
212 this.$readout.text(actual_value);
248 this.$readout.text(actual_value);
213 }
249 }
214 this.model.set('value', actual_value, {updated_view: this});
250 this.model.set('value', actual_value, {updated_view: this});
215 this.touch();
251 this.touch();
216 },
252 },
217
253
218 _validate_slide_value: function(x) {
254 _validate_slide_value: function(x) {
219 // Validate the value of the slider before sending it to the back-end
255 // Validate the value of the slider before sending it to the back-end
220 // and applying it to the other views on the page.
256 // and applying it to the other views on the page.
221
257
222 // Double bit-wise not truncates the decimel (int cast).
258 // Double bit-wise not truncates the decimel (int cast).
223 return ~~x;
259 return ~~x;
224 },
260 },
225 });
261 });
226
262
227
263
228 var IntTextView = widget.DOMWidgetView.extend({
264 var IntTextView = widget.DOMWidgetView.extend({
229 render : function(){
265 render : function(){
230 // Called when view is rendered.
266 // Called when view is rendered.
231 this.$el
267 this.$el
232 .addClass('widget-hbox');
268 .addClass('widget-hbox');
233 this.$label = $('<div />')
269 this.$label = $('<div />')
234 .appendTo(this.$el)
270 .appendTo(this.$el)
235 .addClass('widget-label')
271 .addClass('widget-label')
236 .hide();
272 .hide();
237 this.$textbox = $('<input type="text" />')
273 this.$textbox = $('<input type="text" />')
238 .addClass('form-control')
274 .addClass('form-control')
239 .addClass('widget-numeric-text')
275 .addClass('widget-numeric-text')
240 .appendTo(this.$el);
276 .appendTo(this.$el);
241 this.update(); // Set defaults.
277 this.update(); // Set defaults.
242 },
278 },
243
279
244 update : function(options){
280 update : function(options){
245 // Update the contents of this view
281 // Update the contents of this view
246 //
282 //
247 // Called when the model is changed. The model may have been
283 // Called when the model is changed. The model may have been
248 // changed by another view or by a state update from the back-end.
284 // changed by another view or by a state update from the back-end.
249 if (options === undefined || options.updated_view != this) {
285 if (options === undefined || options.updated_view != this) {
250 var value = this.model.get('value');
286 var value = this.model.get('value');
251 if (this._parse_value(this.$textbox.val()) != value) {
287 if (this._parse_value(this.$textbox.val()) != value) {
252 this.$textbox.val(value);
288 this.$textbox.val(value);
253 }
289 }
254
290
255 if (this.model.get('disabled')) {
291 if (this.model.get('disabled')) {
256 this.$textbox.attr('disabled','disabled');
292 this.$textbox.attr('disabled','disabled');
257 } else {
293 } else {
258 this.$textbox.removeAttr('disabled');
294 this.$textbox.removeAttr('disabled');
259 }
295 }
260
296
261 var description = this.model.get('description');
297 var description = this.model.get('description');
262 if (description.length === 0) {
298 if (description.length === 0) {
263 this.$label.hide();
299 this.$label.hide();
264 } else {
300 } else {
265 this.$label.text(description);
301 this.$label.text(description);
266 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
302 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
267 this.$label.show();
303 this.$label.show();
268 }
304 }
269 }
305 }
270 return IntTextView.__super__.update.apply(this);
306 return IntTextView.__super__.update.apply(this);
271 },
307 },
272
308
273 update_attr: function(name, value) {
309 update_attr: function(name, value) {
274 // Set a css attr of the widget view.
310 // Set a css attr of the widget view.
275 this.$textbox.css(name, value);
311 this.$textbox.css(name, value);
276 },
312 },
277
313
278 events: {
314 events: {
279 // Dictionary of events and their handlers.
315 // Dictionary of events and their handlers.
280 "keyup input" : "handleChanging",
316 "keyup input" : "handleChanging",
281 "paste input" : "handleChanging",
317 "paste input" : "handleChanging",
282 "cut input" : "handleChanging",
318 "cut input" : "handleChanging",
283
319
284 // Fires only when control is validated or looses focus.
320 // Fires only when control is validated or looses focus.
285 "change input" : "handleChanged"
321 "change input" : "handleChanged"
286 },
322 },
287
323
288 handleChanging: function(e) {
324 handleChanging: function(e) {
289 // Handles and validates user input.
325 // Handles and validates user input.
290
326
291 // Try to parse value as a int.
327 // Try to parse value as a int.
292 var numericalValue = 0;
328 var numericalValue = 0;
293 if (e.target.value !== '') {
329 if (e.target.value !== '') {
294 var trimmed = e.target.value.trim();
330 var trimmed = e.target.value.trim();
295 if (!(['-', '-.', '.', '+.', '+'].indexOf(trimmed) >= 0)) {
331 if (!(['-', '-.', '.', '+.', '+'].indexOf(trimmed) >= 0)) {
296 numericalValue = this._parse_value(e.target.value);
332 numericalValue = this._parse_value(e.target.value);
297 }
333 }
298 }
334 }
299
335
300 // If parse failed, reset value to value stored in model.
336 // If parse failed, reset value to value stored in model.
301 if (isNaN(numericalValue)) {
337 if (isNaN(numericalValue)) {
302 e.target.value = this.model.get('value');
338 e.target.value = this.model.get('value');
303 } else if (!isNaN(numericalValue)) {
339 } else if (!isNaN(numericalValue)) {
304 if (this.model.get('max') !== undefined) {
340 if (this.model.get('max') !== undefined) {
305 numericalValue = Math.min(this.model.get('max'), numericalValue);
341 numericalValue = Math.min(this.model.get('max'), numericalValue);
306 }
342 }
307 if (this.model.get('min') !== undefined) {
343 if (this.model.get('min') !== undefined) {
308 numericalValue = Math.max(this.model.get('min'), numericalValue);
344 numericalValue = Math.max(this.model.get('min'), numericalValue);
309 }
345 }
310
346
311 // Apply the value if it has changed.
347 // Apply the value if it has changed.
312 if (numericalValue != this.model.get('value')) {
348 if (numericalValue != this.model.get('value')) {
313
349
314 // Calling model.set will trigger all of the other views of the
350 // Calling model.set will trigger all of the other views of the
315 // model to update.
351 // model to update.
316 this.model.set('value', numericalValue, {updated_view: this});
352 this.model.set('value', numericalValue, {updated_view: this});
317 this.touch();
353 this.touch();
318 }
354 }
319 }
355 }
320 },
356 },
321
357
322 handleChanged: function(e) {
358 handleChanged: function(e) {
323 // Applies validated input.
359 // Applies validated input.
324 if (this.model.get('value') != e.target.value) {
360 if (this.model.get('value') != e.target.value) {
325 e.target.value = this.model.get('value');
361 e.target.value = this.model.get('value');
326 }
362 }
327 },
363 },
328
364
329 _parse_value: function(value) {
365 _parse_value: function(value) {
330 // Parse the value stored in a string.
366 // Parse the value stored in a string.
331 return parseInt(value);
367 return parseInt(value);
332 },
368 },
333 });
369 });
334
370
335
371
336 var ProgressView = widget.DOMWidgetView.extend({
372 var ProgressView = widget.DOMWidgetView.extend({
337 render : function(){
373 render : function(){
338 // Called when view is rendered.
374 // Called when view is rendered.
339 this.$el
375 this.$el
340 .addClass('widget-hbox');
376 .addClass('widget-hbox');
341 this.$label = $('<div />')
377 this.$label = $('<div />')
342 .appendTo(this.$el)
378 .appendTo(this.$el)
343 .addClass('widget-label')
379 .addClass('widget-label')
344 .hide();
380 .hide();
345 this.$progress = $('<div />')
381 this.$progress = $('<div />')
346 .addClass('progress')
382 .addClass('progress')
347 .addClass('widget-progress')
383 .addClass('widget-progress')
348 .appendTo(this.$el);
384 .appendTo(this.$el);
349 this.$bar = $('<div />')
385 this.$bar = $('<div />')
350 .addClass('progress-bar')
386 .addClass('progress-bar')
351 .css('width', '50%')
387 .css('width', '50%')
352 .appendTo(this.$progress);
388 .appendTo(this.$progress);
353 this.update(); // Set defaults.
389 this.update(); // Set defaults.
354
390
355 this.model.on('change:bar_style', function(model, value) {
391 this.model.on('change:bar_style', function(model, value) {
356 this.update_bar_style();
392 this.update_bar_style();
357 }, this);
393 }, this);
358 this.update_bar_style('');
394 this.update_bar_style('');
359 },
395 },
360
396
361 update : function(){
397 update : function(){
362 // Update the contents of this view
398 // Update the contents of this view
363 //
399 //
364 // Called when the model is changed. The model may have been
400 // Called when the model is changed. The model may have been
365 // changed by another view or by a state update from the back-end.
401 // changed by another view or by a state update from the back-end.
366 var value = this.model.get('value');
402 var value = this.model.get('value');
367 var max = this.model.get('max');
403 var max = this.model.get('max');
368 var min = this.model.get('min');
404 var min = this.model.get('min');
369 var percent = 100.0 * (value - min) / (max - min);
405 var percent = 100.0 * (value - min) / (max - min);
370 this.$bar.css('width', percent + '%');
406 this.$bar.css('width', percent + '%');
371
407
372 var description = this.model.get('description');
408 var description = this.model.get('description');
373 if (description.length === 0) {
409 if (description.length === 0) {
374 this.$label.hide();
410 this.$label.hide();
375 } else {
411 } else {
376 this.$label.text(description);
412 this.$label.text(description);
377 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
413 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
378 this.$label.show();
414 this.$label.show();
379 }
415 }
380 return ProgressView.__super__.update.apply(this);
416 return ProgressView.__super__.update.apply(this);
381 },
417 },
382
418
383 update_bar_style: function(previous_trait_value) {
419 update_bar_style: function(previous_trait_value) {
384 var class_map = {
420 var class_map = {
385 success: ['progress-bar-success'],
421 success: ['progress-bar-success'],
386 info: ['progress-bar-info'],
422 info: ['progress-bar-info'],
387 warning: ['progress-bar-warning'],
423 warning: ['progress-bar-warning'],
388 danger: ['progress-bar-danger']
424 danger: ['progress-bar-danger']
389 };
425 };
390 this.update_mapped_classes(class_map, 'bar_style', previous_trait_value, this.$bar);
426 this.update_mapped_classes(class_map, 'bar_style', previous_trait_value, this.$bar);
391 },
427 },
392
428
393 update_attr: function(name, value) {
429 update_attr: function(name, value) {
394 // Set a css attr of the widget view.
430 // Set a css attr of the widget view.
395 if (name.substring(0, 6) == 'border' || name == 'width' ||
431 if (name.substring(0, 6) == 'border' || name == 'width' ||
396 name == 'height' || name == 'background' || name == 'margin' ||
432 name == 'height' || name == 'background' || name == 'margin' ||
397 name == 'padding') {
433 name == 'padding') {
398
434
399 this.$progress.css(name, value);
435 this.$progress.css(name, value);
400 } else if (name == 'color') {
436 } else if (name == 'color') {
401 this.$bar.css('background', value);
437 this.$bar.css('background', value);
402 } else {
438 } else {
403 this.$bar.css(name, value);
439 this.$bar.css(name, value);
404 }
440 }
405 },
441 },
406 });
442 });
407
443
408 return {
444 return {
409 'IntSliderView': IntSliderView,
445 'IntSliderView': IntSliderView,
410 'IntTextView': IntTextView,
446 'IntTextView': IntTextView,
411 'ProgressView': ProgressView,
447 'ProgressView': ProgressView,
412 };
448 };
413 });
449 });
General Comments 0
You need to be logged in to leave comments. Login now