##// END OF EJS Templates
add locks to update everywhere by using options to pass this...
Jonathan Frederic -
Show More
@@ -1,133 +1,129 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 // BoolWidget
9 // BoolWidget
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(widget_manager){
17 define(["notebook/js/widgets/widget"], function(widget_manager){
18
18
19 var BoolWidgetModel = IPython.WidgetModel.extend({});
19 var BoolWidgetModel = IPython.WidgetModel.extend({});
20 widget_manager.register_widget_model('BoolWidgetModel', BoolWidgetModel);
20 widget_manager.register_widget_model('BoolWidgetModel', BoolWidgetModel);
21
21
22 var CheckboxView = IPython.DOMWidgetView.extend({
22 var CheckboxView = IPython.DOMWidgetView.extend({
23
23
24 // Called when view is rendered.
24 // Called when view is rendered.
25 render : function(){
25 render : function(){
26 this.$el
26 this.$el
27 .addClass('widget-hbox-single');
27 .addClass('widget-hbox-single');
28 this.$label = $('<div />')
28 this.$label = $('<div />')
29 .addClass('widget-hlabel')
29 .addClass('widget-hlabel')
30 .appendTo(this.$el)
30 .appendTo(this.$el)
31 .hide();
31 .hide();
32 var that = this;
32 var that = this;
33 this.$checkbox = $('<input />')
33 this.$checkbox = $('<input />')
34 .attr('type', 'checkbox')
34 .attr('type', 'checkbox')
35 .click(function(el) {
35 .click(function(el) {
36 that.user_invoked_update = true;
37
36
38 // Calling model.set will trigger all of the other views of the
37 // Calling model.set will trigger all of the other views of the
39 // model to update.
38 // model to update.
40 that.model.set('value', that.$checkbox.prop('checked'));
39 that.model.set('value', that.$checkbox.prop('checked'), {updated_view: this});
41 that.touch();
40 that.touch();
42 that.user_invoked_update = false;
43 })
41 })
44 .appendTo(this.$el);
42 .appendTo(this.$el);
45
43
46 this.$el_to_style = this.$checkbox; // Set default element to style
44 this.$el_to_style = this.$checkbox; // Set default element to style
47 this.update(); // Set defaults.
45 this.update(); // Set defaults.
48 },
46 },
49
47
50 update : function(){
48 update : function(options){
51 // Update the contents of this view
49 // Update the contents of this view
52 //
50 //
53 // Called when the model is changed. The model may have been
51 // Called when the model is changed. The model may have been
54 // changed by another view or by a state update from the back-end.
52 // changed by another view or by a state update from the back-end.
55 if (!this.user_invoked_update) {
53 if (options === undefined || options.updated_view != this) {
56 this.$checkbox.prop('checked', this.model.get('value'));
54 this.$checkbox.prop('checked', this.model.get('value'));
57
55
58 var disabled = this.model.get('disabled');
56 var disabled = this.model.get('disabled');
59 this.$checkbox.prop('disabled', disabled);
57 this.$checkbox.prop('disabled', disabled);
60
58
61 var description = this.model.get('description');
59 var description = this.model.get('description');
62 if (description.length === 0) {
60 if (description.length === 0) {
63 this.$label.hide();
61 this.$label.hide();
64 } else {
62 } else {
65 this.$label.html(description);
63 this.$label.html(description);
66 this.$label.show();
64 this.$label.show();
67 }
65 }
68 }
66 }
69 return IPython.DOMWidgetView.prototype.update.call(this);
67 return IPython.DOMWidgetView.prototype.update.call(this);
70 },
68 },
71
69
72 });
70 });
73
71
74 widget_manager.register_widget_view('CheckboxView', CheckboxView);
72 widget_manager.register_widget_view('CheckboxView', CheckboxView);
75
73
76 var ToggleButtonView = IPython.DOMWidgetView.extend({
74 var ToggleButtonView = IPython.DOMWidgetView.extend({
77
75
78 // Called when view is rendered.
76 // Called when view is rendered.
79 render : function(){
77 render : function(){
80 this.$el
78 this.$el
81 .html('');
79 .html('');
82 this.$button = $('<button />')
80 this.$button = $('<button />')
83 .addClass('btn')
81 .addClass('btn')
84 .attr('type', 'button')
82 .attr('type', 'button')
85 .attr('data-toggle', 'button')
83 .attr('data-toggle', 'button')
86 .appendTo(this.$el);
84 .appendTo(this.$el);
87 this.$el_to_style = this.$button; // Set default element to style
85 this.$el_to_style = this.$button; // Set default element to style
88
86
89 this.update(); // Set defaults.
87 this.update(); // Set defaults.
90 },
88 },
91
89
92 update : function(){
90 update : function(options){
93 // Update the contents of this view
91 // Update the contents of this view
94 //
92 //
95 // Called when the model is changed. The model may have been
93 // Called when the model is changed. The model may have been
96 // changed by another view or by a state update from the back-end.
94 // changed by another view or by a state update from the back-end.
97 if (!this.user_invoked_update) {
95 if (options === undefined || options.updated_view != this) {
98 if (this.model.get('value')) {
96 if (this.model.get('value')) {
99 this.$button.addClass('active');
97 this.$button.addClass('active');
100 } else {
98 } else {
101 this.$button.removeClass('active');
99 this.$button.removeClass('active');
102 }
100 }
103
101
104 var disabled = this.model.get('disabled');
102 var disabled = this.model.get('disabled');
105 this.$button.prop('disabled', disabled);
103 this.$button.prop('disabled', disabled);
106
104
107 var description = this.model.get('description');
105 var description = this.model.get('description');
108 if (description.length === 0) {
106 if (description.length === 0) {
109 this.$button.html(' '); // Preserve button height
107 this.$button.html(' '); // Preserve button height
110 } else {
108 } else {
111 this.$button.html(description);
109 this.$button.html(description);
112 }
110 }
113 }
111 }
114 return IPython.DOMWidgetView.prototype.update.call(this);
112 return IPython.DOMWidgetView.prototype.update.call(this);
115 },
113 },
116
114
117 events: {"click button" : "handleClick"},
115 events: {"click button" : "handleClick"},
118
116
119 // Handles and validates user input.
117 // Handles and validates user input.
120 handleClick: function(e) {
118 handleClick: function(e) {
121 this.user_invoked_update = true;
119
122
123 // Calling model.set will trigger all of the other views of the
120 // Calling model.set will trigger all of the other views of the
124 // model to update.
121 // model to update.
125 this.model.set('value', ! $(e.target).hasClass('active'));
122 this.model.set('value', ! $(e.target).hasClass('active'), {updated_view: this});
126 this.touch();
123 this.touch();
127 this.user_invoked_update = false;
128 },
124 },
129 });
125 });
130
126
131 widget_manager.register_widget_view('ToggleButtonView', ToggleButtonView);
127 widget_manager.register_widget_view('ToggleButtonView', ToggleButtonView);
132
128
133 });
129 });
@@ -1,269 +1,271 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 // FloatRangeWidget
9 // FloatRangeWidget
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(widget_manager){
17 define(["notebook/js/widgets/widget"], function(widget_manager){
18 var FloatRangeWidgetModel = IPython.WidgetModel.extend({});
18 var FloatRangeWidgetModel = IPython.WidgetModel.extend({});
19 widget_manager.register_widget_model('FloatRangeWidgetModel', FloatRangeWidgetModel);
19 widget_manager.register_widget_model('FloatRangeWidgetModel', FloatRangeWidgetModel);
20
20
21 var FloatSliderView = IPython.DOMWidgetView.extend({
21 var FloatSliderView = IPython.DOMWidgetView.extend({
22
22
23 // Called when view is rendered.
23 // Called when view is rendered.
24 render : function(){
24 render : function(){
25 this.$el
25 this.$el
26 .addClass('widget-hbox-single')
26 .addClass('widget-hbox-single')
27 .html('');
27 .html('');
28 this.$label = $('<div />')
28 this.$label = $('<div />')
29 .appendTo(this.$el)
29 .appendTo(this.$el)
30 .addClass('widget-hlabel')
30 .addClass('widget-hlabel')
31 .hide();
31 .hide();
32 this.$slider = $('<div />')
32 this.$slider = $('<div />')
33 .slider({})
33 .slider({})
34 .addClass('slider');
34 .addClass('slider');
35
35
36 // Put the slider in a container
36 // Put the slider in a container
37 this.$slider_container = $('<div />')
37 this.$slider_container = $('<div />')
38 .addClass('widget-hslider')
38 .addClass('widget-hslider')
39 .append(this.$slider);
39 .append(this.$slider);
40 this.$el_to_style = this.$slider_container; // Set default element to style
40 this.$el_to_style = this.$slider_container; // Set default element to style
41 this.$el.append(this.$slider_container);
41 this.$el.append(this.$slider_container);
42
42
43 // Set defaults.
43 // Set defaults.
44 this.update();
44 this.update();
45 },
45 },
46
46
47 update : function(){
47 update : function(options){
48 // Update the contents of this view
48 // Update the contents of this view
49 //
49 //
50 // Called when the model is changed. The model may have been
50 // Called when the model is changed. The model may have been
51 // changed by another view or by a state update from the back-end.
51 // changed by another view or by a state update from the back-end.
52
52
53 if (options === undefined || options.updated_view != this) {
53 // Slider related keys.
54 // Slider related keys.
54 var _keys = ['step', 'max', 'min', 'disabled'];
55 var _keys = ['step', 'max', 'min', 'disabled'];
55 for (var index in _keys) {
56 for (var index in _keys) {
56 var key = _keys[index];
57 var key = _keys[index];
57 if (this.model.get(key) !== undefined) {
58 if (this.model.get(key) !== undefined) {
58 this.$slider.slider("option", key, this.model.get(key));
59 this.$slider.slider("option", key, this.model.get(key));
60 }
59 }
61 }
60 }
61
62
62 // WORKAROUND FOR JQUERY SLIDER BUG.
63 // WORKAROUND FOR JQUERY SLIDER BUG.
63 // The horizontal position of the slider handle
64 // The horizontal position of the slider handle
64 // depends on the value of the slider at the time
65 // depends on the value of the slider at the time
65 // of orientation change. Before applying the new
66 // of orientation change. Before applying the new
66 // workaround, we set the value to the minimum to
67 // workaround, we set the value to the minimum to
67 // make sure that the horizontal placement of the
68 // make sure that the horizontal placement of the
68 // handle in the vertical slider is always
69 // handle in the vertical slider is always
69 // consistent.
70 // consistent.
70 var orientation = this.model.get('orientation');
71 var orientation = this.model.get('orientation');
71 var value = this.model.get('min');
72 var value = this.model.get('min');
72 this.$slider.slider('option', 'value', value);
73 this.$slider.slider('option', 'value', value);
73 this.$slider.slider('option', 'orientation', orientation);
74 this.$slider.slider('option', 'orientation', orientation);
74 value = this.model.get('value');
75 value = this.model.get('value');
75 this.$slider.slider('option', 'value', value);
76 this.$slider.slider('option', 'value', value);
76
77
77 // Use the right CSS classes for vertical & horizontal sliders
78 // Use the right CSS classes for vertical & horizontal sliders
78 if (orientation=='vertical') {
79 if (orientation=='vertical') {
79 this.$slider_container
80 this.$slider_container
80 .removeClass('widget-hslider')
81 .removeClass('widget-hslider')
81 .addClass('widget-vslider');
82 .addClass('widget-vslider');
82 this.$el
83 this.$el
83 .removeClass('widget-hbox-single')
84 .removeClass('widget-hbox-single')
84 .addClass('widget-vbox-single');
85 .addClass('widget-vbox-single');
85 this.$label
86 this.$label
86 .removeClass('widget-hlabel')
87 .removeClass('widget-hlabel')
87 .addClass('widget-vlabel');
88 .addClass('widget-vlabel');
88
89
89 } else {
90 } else {
90 this.$slider_container
91 this.$slider_container
91 .removeClass('widget-vslider')
92 .removeClass('widget-vslider')
92 .addClass('widget-hslider');
93 .addClass('widget-hslider');
93 this.$el
94 this.$el
94 .removeClass('widget-vbox-single')
95 .removeClass('widget-vbox-single')
95 .addClass('widget-hbox-single');
96 .addClass('widget-hbox-single');
96 this.$label
97 this.$label
97 .removeClass('widget-vlabel')
98 .removeClass('widget-vlabel')
98 .addClass('widget-hlabel');
99 .addClass('widget-hlabel');
99 }
100 }
100
101
101 var description = this.model.get('description');
102 var description = this.model.get('description');
102 if (description.length === 0) {
103 if (description.length === 0) {
103 this.$label.hide();
104 this.$label.hide();
104 } else {
105 } else {
105 this.$label.html(description);
106 this.$label.html(description);
106 this.$label.show();
107 this.$label.show();
108 }
107 }
109 }
108 return IPython.DOMWidgetView.prototype.update.call(this);
110 return IPython.DOMWidgetView.prototype.update.call(this);
109 },
111 },
110
112
111 // Handles: User input
113 // Handles: User input
112 events: { "slide" : "handleSliderChange" },
114 events: { "slide" : "handleSliderChange" },
113 handleSliderChange: function(e, ui) {
115 handleSliderChange: function(e, ui) {
114
116
115 // Calling model.set will trigger all of the other views of the
117 // Calling model.set will trigger all of the other views of the
116 // model to update.
118 // model to update.
117 this.model.set('value', ui.value);
119 this.model.set('value', ui.value, {updated_view: this});
118 this.touch();
120 this.touch();
119 },
121 },
120 });
122 });
121
123
122 widget_manager.register_widget_view('FloatSliderView', FloatSliderView);
124 widget_manager.register_widget_view('FloatSliderView', FloatSliderView);
123
125
124
126
125 var FloatTextView = IPython.DOMWidgetView.extend({
127 var FloatTextView = IPython.DOMWidgetView.extend({
126
128
127 // Called when view is rendered.
129 // Called when view is rendered.
128 render : function(){
130 render : function(){
129 this.$el
131 this.$el
130 .addClass('widget-hbox-single')
132 .addClass('widget-hbox-single')
131 .html('');
133 .html('');
132 this.$label = $('<div />')
134 this.$label = $('<div />')
133 .appendTo(this.$el)
135 .appendTo(this.$el)
134 .addClass('widget-hlabel')
136 .addClass('widget-hlabel')
135 .hide();
137 .hide();
136 this.$textbox = $('<input type="text" />')
138 this.$textbox = $('<input type="text" />')
137 .addClass('input')
139 .addClass('input')
138 .addClass('widget-numeric-text')
140 .addClass('widget-numeric-text')
139 .appendTo(this.$el);
141 .appendTo(this.$el);
140 this.$el_to_style = this.$textbox; // Set default element to style
142 this.$el_to_style = this.$textbox; // Set default element to style
141 this.update(); // Set defaults.
143 this.update(); // Set defaults.
142 },
144 },
143
145
144 update : function(){
146 update : function(options){
145 // Update the contents of this view
147 // Update the contents of this view
146 //
148 //
147 // Called when the model is changed. The model may have been
149 // 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.
150 // changed by another view or by a state update from the back-end.
149
151
150 var value = this.model.get('value');
152 if (options === undefined || options.updated_view != this) {
151 if (!this.changing && parseFloat(this.$textbox.val()) != value) {
153 var value = this.model.get('value');
152 this.$textbox.val(value);
154 if (parseFloat(this.$textbox.val()) != value) {
153 }
155 this.$textbox.val(value);
154
156 }
155 if (this.model.get('disabled')) {
157
156 this.$textbox.attr('disabled','disabled');
158 if (this.model.get('disabled')) {
157 } else {
159 this.$textbox.attr('disabled','disabled');
158 this.$textbox.removeAttr('disabled');
160 } else {
159 }
161 this.$textbox.removeAttr('disabled');
162 }
160
163
161 var description = this.model.get('description');
164 var description = this.model.get('description');
162 if (description.length === 0) {
165 if (description.length === 0) {
163 this.$label.hide();
166 this.$label.hide();
164 } else {
167 } else {
165 this.$label.html(description);
168 this.$label.html(description);
166 this.$label.show();
169 this.$label.show();
170 }
167 }
171 }
168 return IPython.DOMWidgetView.prototype.update.call(this);
172 return IPython.DOMWidgetView.prototype.update.call(this);
169 },
173 },
170
174
171
175
172 events: {"keyup input" : "handleChanging",
176 events: {"keyup input" : "handleChanging",
173 "paste input" : "handleChanging",
177 "paste input" : "handleChanging",
174 "cut input" : "handleChanging",
178 "cut input" : "handleChanging",
175 "change input" : "handleChanged"}, // Fires only when control is validated or looses focus.
179 "change input" : "handleChanged"}, // Fires only when control is validated or looses focus.
176
180
177 // Handles and validates user input.
181 // Handles and validates user input.
178 handleChanging: function(e) {
182 handleChanging: function(e) {
179
183
180 // Try to parse value as a float.
184 // Try to parse value as a float.
181 var numericalValue = 0.0;
185 var numericalValue = 0.0;
182 if (e.target.value !== '') {
186 if (e.target.value !== '') {
183 numericalValue = parseFloat(e.target.value);
187 numericalValue = parseFloat(e.target.value);
184 }
188 }
185
189
186 // If parse failed, reset value to value stored in model.
190 // If parse failed, reset value to value stored in model.
187 if (isNaN(numericalValue)) {
191 if (isNaN(numericalValue)) {
188 e.target.value = this.model.get('value');
192 e.target.value = this.model.get('value');
189 } else if (!isNaN(numericalValue)) {
193 } else if (!isNaN(numericalValue)) {
190 if (this.model.get('max') !== undefined) {
194 if (this.model.get('max') !== undefined) {
191 numericalValue = Math.min(this.model.get('max'), numericalValue);
195 numericalValue = Math.min(this.model.get('max'), numericalValue);
192 }
196 }
193 if (this.model.get('min') !== undefined) {
197 if (this.model.get('min') !== undefined) {
194 numericalValue = Math.max(this.model.get('min'), numericalValue);
198 numericalValue = Math.max(this.model.get('min'), numericalValue);
195 }
199 }
196
200
197 // Apply the value if it has changed.
201 // Apply the value if it has changed.
198 if (numericalValue != this.model.get('value')) {
202 if (numericalValue != this.model.get('value')) {
199 this.changing = true;
200
203
201 // Calling model.set will trigger all of the other views of the
204 // Calling model.set will trigger all of the other views of the
202 // model to update.
205 // model to update.
203 this.model.set('value', numericalValue);
206 this.model.set('value', numericalValue, {updated_view: this});
204 this.touch();
207 this.touch();
205 this.changing = false;
206 }
208 }
207 }
209 }
208 },
210 },
209
211
210 // Applies validated input.
212 // Applies validated input.
211 handleChanged: function(e) {
213 handleChanged: function(e) {
212 // Update the textbox
214 // Update the textbox
213 if (this.model.get('value') != e.target.value) {
215 if (this.model.get('value') != e.target.value) {
214 e.target.value = this.model.get('value');
216 e.target.value = this.model.get('value');
215 }
217 }
216 }
218 }
217 });
219 });
218
220
219 widget_manager.register_widget_view('FloatTextView', FloatTextView);
221 widget_manager.register_widget_view('FloatTextView', FloatTextView);
220
222
221
223
222 var ProgressView = IPython.DOMWidgetView.extend({
224 var ProgressView = IPython.DOMWidgetView.extend({
223
225
224 // Called when view is rendered.
226 // Called when view is rendered.
225 render : function(){
227 render : function(){
226 this.$el
228 this.$el
227 .addClass('widget-hbox-single')
229 .addClass('widget-hbox-single')
228 .html('');
230 .html('');
229 this.$label = $('<div />')
231 this.$label = $('<div />')
230 .appendTo(this.$el)
232 .appendTo(this.$el)
231 .addClass('widget-hlabel')
233 .addClass('widget-hlabel')
232 .hide();
234 .hide();
233 this.$progress = $('<div />')
235 this.$progress = $('<div />')
234 .addClass('progress')
236 .addClass('progress')
235 .addClass('widget-progress')
237 .addClass('widget-progress')
236 .appendTo(this.$el);
238 .appendTo(this.$el);
237 this.$el_to_style = this.$progress; // Set default element to style
239 this.$el_to_style = this.$progress; // Set default element to style
238 this.$bar = $('<div />')
240 this.$bar = $('<div />')
239 .addClass('bar')
241 .addClass('bar')
240 .css('width', '50%')
242 .css('width', '50%')
241 .appendTo(this.$progress);
243 .appendTo(this.$progress);
242 this.update(); // Set defaults.
244 this.update(); // Set defaults.
243 },
245 },
244
246
245 update : function(){
247 update : function(){
246 // Update the contents of this view
248 // Update the contents of this view
247 //
249 //
248 // Called when the model is changed. The model may have been
250 // Called when the model is changed. The model may have been
249 // changed by another view or by a state update from the back-end.
251 // changed by another view or by a state update from the back-end.
250 var value = this.model.get('value');
252 var value = this.model.get('value');
251 var max = this.model.get('max');
253 var max = this.model.get('max');
252 var min = this.model.get('min');
254 var min = this.model.get('min');
253 var percent = 100.0 * (value - min) / (max - min);
255 var percent = 100.0 * (value - min) / (max - min);
254 this.$bar.css('width', percent + '%');
256 this.$bar.css('width', percent + '%');
255
257
256 var description = this.model.get('description');
258 var description = this.model.get('description');
257 if (description.length === 0) {
259 if (description.length === 0) {
258 this.$label.hide();
260 this.$label.hide();
259 } else {
261 } else {
260 this.$label.html(description);
262 this.$label.html(description);
261 this.$label.show();
263 this.$label.show();
262 }
264 }
263 return IPython.DOMWidgetView.prototype.update.call(this);
265 return IPython.DOMWidgetView.prototype.update.call(this);
264 },
266 },
265
267
266 });
268 });
267
269
268 widget_manager.register_widget_view('ProgressView', ProgressView);
270 widget_manager.register_widget_view('ProgressView', ProgressView);
269 });
271 });
@@ -1,219 +1,219 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 // IntRangeWidget
9 // IntRangeWidget
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(widget_manager){
17 define(["notebook/js/widgets/widget"], function(widget_manager){
18 var IntRangeWidgetModel = IPython.WidgetModel.extend({});
18 var IntRangeWidgetModel = IPython.WidgetModel.extend({});
19 widget_manager.register_widget_model('IntRangeWidgetModel', IntRangeWidgetModel);
19 widget_manager.register_widget_model('IntRangeWidgetModel', IntRangeWidgetModel);
20
20
21 var IntSliderView = IPython.DOMWidgetView.extend({
21 var IntSliderView = IPython.DOMWidgetView.extend({
22
22
23 // Called when view is rendered.
23 // Called when view is rendered.
24 render : function(){
24 render : function(){
25 this.$el
25 this.$el
26 .addClass('widget-hbox-single')
26 .addClass('widget-hbox-single')
27 .html('');
27 .html('');
28 this.$label = $('<div />')
28 this.$label = $('<div />')
29 .appendTo(this.$el)
29 .appendTo(this.$el)
30 .addClass('widget-hlabel')
30 .addClass('widget-hlabel')
31 .hide();
31 .hide();
32 this.$slider = $('<div />')
32 this.$slider = $('<div />')
33 .slider({})
33 .slider({})
34 .addClass('slider');
34 .addClass('slider');
35
35
36 // Put the slider in a container
36 // Put the slider in a container
37 this.$slider_container = $('<div />')
37 this.$slider_container = $('<div />')
38 .addClass('widget-hslider')
38 .addClass('widget-hslider')
39 .append(this.$slider);
39 .append(this.$slider);
40 this.$el_to_style = this.$slider_container; // Set default element to style
40 this.$el_to_style = this.$slider_container; // Set default element to style
41 this.$el.append(this.$slider_container);
41 this.$el.append(this.$slider_container);
42
42
43 // Set defaults.
43 // Set defaults.
44 this.update();
44 this.update();
45 },
45 },
46
46
47 update : function(){
47 update : function(options){
48 // Update the contents of this view
48 // Update the contents of this view
49 //
49 //
50 // Called when the model is changed. The model may have been
50 // Called when the model is changed. The model may have been
51 // changed by another view or by a state update from the back-end.
51 // changed by another view or by a state update from the back-end.
52
52 if (options === undefined || options.updated_view != this) {
53 // Slider related keys.
53 // Slider related keys.
54 var _keys = ['step', 'max', 'min', 'disabled'];
54 var _keys = ['step', 'max', 'min', 'disabled'];
55 for (var index in _keys) {
55 for (var index in _keys) {
56 var key = _keys[index];
56 var key = _keys[index];
57 if (this.model.get(key) !== undefined) {
57 if (this.model.get(key) !== undefined) {
58 this.$slider.slider("option", key, this.model.get(key));
58 this.$slider.slider("option", key, this.model.get(key));
59 }
59 }
60 }
60 }
61
61
62 // WORKAROUND FOR JQUERY SLIDER BUG.
62 // WORKAROUND FOR JQUERY SLIDER BUG.
63 // The horizontal position of the slider handle
63 // The horizontal position of the slider handle
64 // depends on the value of the slider at the time
64 // depends on the value of the slider at the time
65 // of orientation change. Before applying the new
65 // of orientation change. Before applying the new
66 // workaround, we set the value to the minimum to
66 // workaround, we set the value to the minimum to
67 // make sure that the horizontal placement of the
67 // make sure that the horizontal placement of the
68 // handle in the vertical slider is always
68 // handle in the vertical slider is always
69 // consistent.
69 // consistent.
70 var orientation = this.model.get('orientation');
70 var orientation = this.model.get('orientation');
71 var value = this.model.get('min');
71 var value = this.model.get('min');
72 this.$slider.slider('option', 'value', value);
72 this.$slider.slider('option', 'value', value);
73 this.$slider.slider('option', 'orientation', orientation);
73 this.$slider.slider('option', 'orientation', orientation);
74 value = this.model.get('value');
74 value = this.model.get('value');
75 this.$slider.slider('option', 'value', value);
75 this.$slider.slider('option', 'value', value);
76
76
77 // Use the right CSS classes for vertical & horizontal sliders
77 // Use the right CSS classes for vertical & horizontal sliders
78 if (orientation=='vertical') {
78 if (orientation=='vertical') {
79 this.$slider_container
79 this.$slider_container
80 .removeClass('widget-hslider')
80 .removeClass('widget-hslider')
81 .addClass('widget-vslider');
81 .addClass('widget-vslider');
82 this.$el
82 this.$el
83 .removeClass('widget-hbox-single')
83 .removeClass('widget-hbox-single')
84 .addClass('widget-vbox-single');
84 .addClass('widget-vbox-single');
85 this.$label
85 this.$label
86 .removeClass('widget-hlabel')
86 .removeClass('widget-hlabel')
87 .addClass('widget-vlabel');
87 .addClass('widget-vlabel');
88
88
89 } else {
89 } else {
90 this.$slider_container
90 this.$slider_container
91 .removeClass('widget-vslider')
91 .removeClass('widget-vslider')
92 .addClass('widget-hslider');
92 .addClass('widget-hslider');
93 this.$el
93 this.$el
94 .removeClass('widget-vbox-single')
94 .removeClass('widget-vbox-single')
95 .addClass('widget-hbox-single');
95 .addClass('widget-hbox-single');
96 this.$label
96 this.$label
97 .removeClass('widget-vlabel')
97 .removeClass('widget-vlabel')
98 .addClass('widget-hlabel');
98 .addClass('widget-hlabel');
99 }
99 }
100
100
101 var description = this.model.get('description');
101 var description = this.model.get('description');
102 if (description.length === 0) {
102 if (description.length === 0) {
103 this.$label.hide();
103 this.$label.hide();
104 } else {
104 } else {
105 this.$label.html(description);
105 this.$label.html(description);
106 this.$label.show();
106 this.$label.show();
107 }
107 }
108 }
108 return IPython.DOMWidgetView.prototype.update.call(this);
109 return IPython.DOMWidgetView.prototype.update.call(this);
109 },
110 },
110
111
111 // Handles: User input
112 // Handles: User input
112 events: { "slide" : "handleSliderChange" },
113 events: { "slide" : "handleSliderChange" },
113 handleSliderChange: function(e, ui) {
114 handleSliderChange: function(e, ui) {
114
115
115 // Calling model.set will trigger all of the other views of the
116 // Calling model.set will trigger all of the other views of the
116 // model to update.
117 // model to update.
117 this.model.set('value', ~~ui.value); // Double bit-wise not to truncate decimel
118 this.model.set('value', ~~ui.value, {updated_view: this}); // Double bit-wise not to truncate decimel
118 this.touch();
119 this.touch();
119 },
120 },
120 });
121 });
121
122
122 widget_manager.register_widget_view('IntSliderView', IntSliderView);
123 widget_manager.register_widget_view('IntSliderView', IntSliderView);
123
124
124 var IntTextView = IPython.DOMWidgetView.extend({
125 var IntTextView = IPython.DOMWidgetView.extend({
125
126
126 // Called when view is rendered.
127 // Called when view is rendered.
127 render : function(){
128 render : function(){
128 this.$el
129 this.$el
129 .addClass('widget-hbox-single')
130 .addClass('widget-hbox-single')
130 .html('');
131 .html('');
131 this.$label = $('<div />')
132 this.$label = $('<div />')
132 .appendTo(this.$el)
133 .appendTo(this.$el)
133 .addClass('widget-hlabel')
134 .addClass('widget-hlabel')
134 .hide();
135 .hide();
135 this.$textbox = $('<input type="text" />')
136 this.$textbox = $('<input type="text" />')
136 .addClass('input')
137 .addClass('input')
137 .addClass('widget-numeric-text')
138 .addClass('widget-numeric-text')
138 .appendTo(this.$el);
139 .appendTo(this.$el);
139 this.$el_to_style = this.$textbox; // Set default element to style
140 this.$el_to_style = this.$textbox; // Set default element to style
140 this.update(); // Set defaults.
141 this.update(); // Set defaults.
141 },
142 },
142
143
143 update : function(){
144 update : function(options){
144 // Update the contents of this view
145 // Update the contents of this view
145 //
146 //
146 // Called when the model is changed. The model may have been
147 // Called when the model is changed. The model may have been
147 // changed by another view or by a state update from the back-end.
148 // changed by another view or by a state update from the back-end.
149 if (options === undefined || options.updated_view != this) {
150 var value = this.model.get('value');
151 if (parseInt(this.$textbox.val()) != value) {
152 this.$textbox.val(value);
153 }
154
155 if (this.model.get('disabled')) {
156 this.$textbox.attr('disabled','disabled');
157 } else {
158 this.$textbox.removeAttr('disabled');
159 }
148
160
149 var value = this.model.get('value');
161 var description = this.model.get('description');
150 if (!this.changing && parseInt(this.$textbox.val()) != value) {
162 if (description.length === 0) {
151 this.$textbox.val(value);
163 this.$label.hide();
152 }
164 } else {
153
165 this.$label.html(description);
154 if (this.model.get('disabled')) {
166 this.$label.show();
155 this.$textbox.attr('disabled','disabled');
167 }
156 } else {
157 this.$textbox.removeAttr('disabled');
158 }
159
160 var description = this.model.get('description');
161 if (description.length === 0) {
162 this.$label.hide();
163 } else {
164 this.$label.html(description);
165 this.$label.show();
166 }
168 }
167 return IPython.DOMWidgetView.prototype.update.call(this);
169 return IPython.DOMWidgetView.prototype.update.call(this);
168 },
170 },
169
171
170
172
171 events: {"keyup input" : "handleChanging",
173 events: {"keyup input" : "handleChanging",
172 "paste input" : "handleChanging",
174 "paste input" : "handleChanging",
173 "cut input" : "handleChanging",
175 "cut input" : "handleChanging",
174 "change input" : "handleChanged"}, // Fires only when control is validated or looses focus.
176 "change input" : "handleChanged"}, // Fires only when control is validated or looses focus.
175
177
176 // Handles and validates user input.
178 // Handles and validates user input.
177 handleChanging: function(e) {
179 handleChanging: function(e) {
178
180
179 // Try to parse value as a float.
181 // Try to parse value as a float.
180 var numericalValue = 0;
182 var numericalValue = 0;
181 if (e.target.value !== '') {
183 if (e.target.value !== '') {
182 numericalValue = parseInt(e.target.value);
184 numericalValue = parseInt(e.target.value);
183 }
185 }
184
186
185 // If parse failed, reset value to value stored in model.
187 // If parse failed, reset value to value stored in model.
186 if (isNaN(numericalValue)) {
188 if (isNaN(numericalValue)) {
187 e.target.value = this.model.get('value');
189 e.target.value = this.model.get('value');
188 } else if (!isNaN(numericalValue)) {
190 } else if (!isNaN(numericalValue)) {
189 if (this.model.get('max') !== undefined) {
191 if (this.model.get('max') !== undefined) {
190 numericalValue = Math.min(this.model.get('max'), numericalValue);
192 numericalValue = Math.min(this.model.get('max'), numericalValue);
191 }
193 }
192 if (this.model.get('min') !== undefined) {
194 if (this.model.get('min') !== undefined) {
193 numericalValue = Math.max(this.model.get('min'), numericalValue);
195 numericalValue = Math.max(this.model.get('min'), numericalValue);
194 }
196 }
195
197
196 // Apply the value if it has changed.
198 // Apply the value if it has changed.
197 if (numericalValue != this.model.get('value')) {
199 if (numericalValue != this.model.get('value')) {
198 this.changing = true;
199
200
200 // Calling model.set will trigger all of the other views of the
201 // Calling model.set will trigger all of the other views of the
201 // model to update.
202 // model to update.
202 this.model.set('value', numericalValue);
203 this.model.set('value', numericalValue, {updated_view: this});
203 this.touch();
204 this.touch();
204 this.changing = false;
205 }
205 }
206 }
206 }
207 },
207 },
208
208
209 // Applies validated input.
209 // Applies validated input.
210 handleChanged: function(e) {
210 handleChanged: function(e) {
211 // Update the textbox
211 // Update the textbox
212 if (this.model.get('value') != e.target.value) {
212 if (this.model.get('value') != e.target.value) {
213 e.target.value = this.model.get('value');
213 e.target.value = this.model.get('value');
214 }
214 }
215 }
215 }
216 });
216 });
217
217
218 widget_manager.register_widget_view('IntTextView', IntTextView);
218 widget_manager.register_widget_view('IntTextView', IntTextView);
219 });
219 });
@@ -1,224 +1,225 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 // MultiContainerWidget
9 // MultiContainerWidget
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(widget_manager){
17 define(["notebook/js/widgets/widget"], function(widget_manager){
18 var MulticontainerModel = IPython.WidgetModel.extend({});
18 var MulticontainerModel = IPython.WidgetModel.extend({});
19 widget_manager.register_widget_model('MulticontainerWidgetModel', MulticontainerModel);
19 widget_manager.register_widget_model('MulticontainerWidgetModel', MulticontainerModel);
20
20
21 var AccordionView = IPython.DOMWidgetView.extend({
21 var AccordionView = IPython.DOMWidgetView.extend({
22
22
23 render: function(){
23 render: function(){
24 var guid = 'accordion' + IPython.utils.uuid();
24 var guid = 'accordion' + IPython.utils.uuid();
25 this.$el
25 this.$el
26 .attr('id', guid)
26 .attr('id', guid)
27 .addClass('accordion');
27 .addClass('accordion');
28 this.containers = [];
28 this.containers = [];
29 this.update_children([], this.model.get('children'));
29 this.update_children([], this.model.get('children'));
30 this.model.on('change:children', function(model, value, options) {
30 this.model.on('change:children', function(model, value, options) {
31 this.update_children(model.previous('children'), value);
31 this.update_children(model.previous('children'), value);
32 }, this);
32 }, this);
33 },
33 },
34
34
35 update_children: function(old_list, new_list) {
35 update_children: function(old_list, new_list) {
36 _.each(this.containers, function(element, index, list) {
36 _.each(this.containers, function(element, index, list) {
37 element.remove();
37 element.remove();
38 }, this);
38 }, this);
39 this.containers = [];
39 this.containers = [];
40 this.update_child_views(old_list, new_list);
40 this.update_child_views(old_list, new_list);
41 _.each(new_list, function(element, index, list) {
41 _.each(new_list, function(element, index, list) {
42 this.add_child_view(this.child_views[element]);
42 this.add_child_view(this.child_views[element]);
43 }, this)
43 }, this)
44 },
44 },
45
45
46
46
47 update: function() {
47 update: function(options) {
48 // Update the contents of this view
48 // Update the contents of this view
49 //
49 //
50 // Called when the model is changed. The model may have been
50 // Called when the model is changed. The model may have been
51 // changed by another view or by a state update from the back-end.
51 // changed by another view or by a state update from the back-end.
52
52
53 // Set tab titles
53 if (options === undefined || options.updated_view != this) {
54 var titles = this.model.get('_titles');
54 // Set tab titles
55 for (var page_index in titles) {
55 var titles = this.model.get('_titles');
56
56 for (var page_index in titles) {
57 var accordian = this.containers[page_index];
57
58 if (accordian !== undefined) {
58 var accordian = this.containers[page_index];
59 accordian
59 if (accordian !== undefined) {
60 .find('.accordion-heading')
60 accordian
61 .find('.accordion-toggle')
61 .find('.accordion-heading')
62 .html(titles[page_index]);
62 .find('.accordion-toggle')
63 .html(titles[page_index]);
64 }
63 }
65 }
64 }
65
66
66 // Set selected page
67 // Set selected page
67 var selected_index = this.model.get("selected_index");
68 var selected_index = this.model.get("selected_index");
68 if (0 <= selected_index && selected_index < this.containers.length) {
69 if (0 <= selected_index && selected_index < this.containers.length) {
69 for (var index in this.containers) {
70 for (var index in this.containers) {
70 if (index==selected_index) {
71 if (index==selected_index) {
71 this.containers[index].find('.accordion-body').collapse('show');
72 this.containers[index].find('.accordion-body').collapse('show');
72 } else {
73 } else {
73 this.containers[index].find('.accordion-body').collapse('hide');
74 this.containers[index].find('.accordion-body').collapse('hide');
75 }
76
74 }
77 }
75
76 }
78 }
77 }
79 }
78
79 return IPython.DOMWidgetView.prototype.update.call(this);
80 return IPython.DOMWidgetView.prototype.update.call(this);
80 },
81 },
81
82
82 add_child_view: function(view) {
83 add_child_view: function(view) {
83
84
84 var index = this.containers.length;
85 var index = this.containers.length;
85 var uuid = IPython.utils.uuid();
86 var uuid = IPython.utils.uuid();
86 var accordion_group = $('<div />')
87 var accordion_group = $('<div />')
87 .addClass('accordion-group')
88 .addClass('accordion-group')
88 .appendTo(this.$el);
89 .appendTo(this.$el);
89 var accordion_heading = $('<div />')
90 var accordion_heading = $('<div />')
90 .addClass('accordion-heading')
91 .addClass('accordion-heading')
91 .appendTo(accordion_group);
92 .appendTo(accordion_group);
92 var that = this;
93 var that = this;
93 var accordion_toggle = $('<a />')
94 var accordion_toggle = $('<a />')
94 .addClass('accordion-toggle')
95 .addClass('accordion-toggle')
95 .attr('data-toggle', 'collapse')
96 .attr('data-toggle', 'collapse')
96 .attr('data-parent', '#' + this.$el.attr('id'))
97 .attr('data-parent', '#' + this.$el.attr('id'))
97 .attr('href', '#' + uuid)
98 .attr('href', '#' + uuid)
98 .click(function(evt){
99 .click(function(evt){
99
100
100 // Calling model.set will trigger all of the other views of the
101 // Calling model.set will trigger all of the other views of the
101 // model to update.
102 // model to update.
102 that.model.set("selected_index", index);
103 that.model.set("selected_index", index, {updated_view: this});
103 that.touch();
104 that.touch();
104 })
105 })
105 .html('Page ' + index)
106 .html('Page ' + index)
106 .appendTo(accordion_heading);
107 .appendTo(accordion_heading);
107 var accordion_body = $('<div />', {id: uuid})
108 var accordion_body = $('<div />', {id: uuid})
108 .addClass('accordion-body collapse')
109 .addClass('accordion-body collapse')
109 .appendTo(accordion_group);
110 .appendTo(accordion_group);
110 var accordion_inner = $('<div />')
111 var accordion_inner = $('<div />')
111 .addClass('accordion-inner')
112 .addClass('accordion-inner')
112 .appendTo(accordion_body);
113 .appendTo(accordion_body);
113 this.containers.push(accordion_group);
114 this.containers.push(accordion_group);
114 accordion_inner.append(view.$el);
115 accordion_inner.append(view.$el);
115
116
116 this.update();
117 this.update();
117
118
118 // Stupid workaround to close the bootstrap accordion tabs which
119 // Stupid workaround to close the bootstrap accordion tabs which
119 // open by default even though they don't have the `in` class
120 // open by default even though they don't have the `in` class
120 // attached to them. For some reason a delay is required.
121 // attached to them. For some reason a delay is required.
121 // TODO: Better fix.
122 // TODO: Better fix.
122 setTimeout(function(){ that.update(); }, 500);
123 setTimeout(function(){ that.update(); }, 500);
123 },
124 },
124 });
125 });
125
126
126 widget_manager.register_widget_view('AccordionView', AccordionView);
127 widget_manager.register_widget_view('AccordionView', AccordionView);
127
128
128 var TabView = IPython.DOMWidgetView.extend({
129 var TabView = IPython.DOMWidgetView.extend({
129
130
130 initialize: function() {
131 initialize: function() {
131 this.containers = [];
132 this.containers = [];
132 IPython.DOMWidgetView.prototype.initialize.apply(this, arguments);
133 IPython.DOMWidgetView.prototype.initialize.apply(this, arguments);
133 },
134 },
134
135
135 render: function(){
136 render: function(){
136 var uuid = 'tabs'+IPython.utils.uuid();
137 var uuid = 'tabs'+IPython.utils.uuid();
137 var that = this;
138 var that = this;
138 this.$tabs = $('<div />', {id: uuid})
139 this.$tabs = $('<div />', {id: uuid})
139 .addClass('nav')
140 .addClass('nav')
140 .addClass('nav-tabs')
141 .addClass('nav-tabs')
141 .appendTo(this.$el);
142 .appendTo(this.$el);
142 this.$tab_contents = $('<div />', {id: uuid + 'Content'})
143 this.$tab_contents = $('<div />', {id: uuid + 'Content'})
143 .addClass('tab-content')
144 .addClass('tab-content')
144 .appendTo(this.$el);
145 .appendTo(this.$el);
145 this.containers = [];
146 this.containers = [];
146 this.update_children([], this.model.get('children'));
147 this.update_children([], this.model.get('children'));
147 this.model.on('change:children', function(model, value, options) {
148 this.model.on('change:children', function(model, value, options) {
148 this.update_children(model.previous('children'), value);
149 this.update_children(model.previous('children'), value);
149 }, this);
150 }, this);
150 },
151 },
151
152
152 update_children: function(old_list, new_list) {
153 update_children: function(old_list, new_list) {
153 _.each(this.containers, function(element, index, list) {
154 _.each(this.containers, function(element, index, list) {
154 element.remove();
155 element.remove();
155 }, this);
156 }, this);
156 this.containers = [];
157 this.containers = [];
157 this.update_child_views(old_list, new_list);
158 this.update_child_views(old_list, new_list);
158 _.each(new_list, function(element, index, list) {
159 _.each(new_list, function(element, index, list) {
159 this.add_child_view(this.child_views[element]);
160 this.add_child_view(this.child_views[element]);
160 }, this)
161 }, this)
161 },
162 },
162
163
163 update: function() {
164 update: function(options) {
164 // Update the contents of this view
165 // Update the contents of this view
165 //
166 //
166 // Called when the model is changed. The model may have been
167 // Called when the model is changed. The model may have been
167 // changed by another view or by a state update from the back-end.
168 // changed by another view or by a state update from the back-end.
168
169 if (options === undefined || options.updated_view != this) {
169 // Set tab titles
170 // Set tab titles
170 var titles = this.model.get('_titles');
171 var titles = this.model.get('_titles');
171 for (var page_index in titles) {
172 for (var page_index in titles) {
172 var tab_text = this.containers[page_index];
173 var tab_text = this.containers[page_index];
173 if (tab_text !== undefined) {
174 if (tab_text !== undefined) {
174 tab_text.html(titles[page_index]);
175 tab_text.html(titles[page_index]);
176 }
175 }
177 }
176 }
177
178
178 var selected_index = this.model.get('selected_index');
179 var selected_index = this.model.get('selected_index');
179 if (0 <= selected_index && selected_index < this.containers.length) {
180 if (0 <= selected_index && selected_index < this.containers.length) {
180 this.select_page(selected_index);
181 this.select_page(selected_index);
182 }
181 }
183 }
182
183 return IPython.DOMWidgetView.prototype.update.call(this);
184 return IPython.DOMWidgetView.prototype.update.call(this);
184 },
185 },
185
186
186 add_child_view: function(view) {
187 add_child_view: function(view) {
187 var index = this.containers.length;
188 var index = this.containers.length;
188 var uuid = IPython.utils.uuid();
189 var uuid = IPython.utils.uuid();
189
190
190 var that = this;
191 var that = this;
191 var tab = $('<li />')
192 var tab = $('<li />')
192 .css('list-style-type', 'none')
193 .css('list-style-type', 'none')
193 .appendTo(this.$tabs);
194 .appendTo(this.$tabs);
194 var tab_text = $('<a />')
195 var tab_text = $('<a />')
195 .attr('href', '#' + uuid)
196 .attr('href', '#' + uuid)
196 .attr('data-toggle', 'tab')
197 .attr('data-toggle', 'tab')
197 .html('Page ' + index)
198 .html('Page ' + index)
198 .appendTo(tab)
199 .appendTo(tab)
199 .click(function (e) {
200 .click(function (e) {
200
201
201 // Calling model.set will trigger all of the other views of the
202 // Calling model.set will trigger all of the other views of the
202 // model to update.
203 // model to update.
203 that.model.set("selected_index", index);
204 that.model.set("selected_index", index, {updated_view: this});
204 that.touch();
205 that.touch();
205 that.select_page(index);
206 that.select_page(index);
206 });
207 });
207 this.containers.push(tab_text);
208 this.containers.push(tab_text);
208
209
209 var contents_div = $('<div />', {id: uuid})
210 var contents_div = $('<div />', {id: uuid})
210 .addClass('tab-pane')
211 .addClass('tab-pane')
211 .addClass('fade')
212 .addClass('fade')
212 .append(view.$el)
213 .append(view.$el)
213 .appendTo(this.$tab_contents);
214 .appendTo(this.$tab_contents);
214 },
215 },
215
216
216 select_page: function(index) {
217 select_page: function(index) {
217 this.$tabs.find('li')
218 this.$tabs.find('li')
218 .removeClass('active');
219 .removeClass('active');
219 this.containers[index].tab('show');
220 this.containers[index].tab('show');
220 },
221 },
221 });
222 });
222
223
223 widget_manager.register_widget_view('TabView', TabView);
224 widget_manager.register_widget_view('TabView', TabView);
224 });
225 });
@@ -1,380 +1,385 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 // SelectionWidget
9 // SelectionWidget
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(widget_manager){
17 define(["notebook/js/widgets/widget"], function(widget_manager){
18 var SelectionWidgetModel = IPython.WidgetModel.extend({});
18 var SelectionWidgetModel = IPython.WidgetModel.extend({});
19 widget_manager.register_widget_model('SelectionWidgetModel', SelectionWidgetModel);
19 widget_manager.register_widget_model('SelectionWidgetModel', SelectionWidgetModel);
20
20
21 var DropdownView = IPython.DOMWidgetView.extend({
21 var DropdownView = IPython.DOMWidgetView.extend({
22
22
23 // Called when view is rendered.
23 // Called when view is rendered.
24 render : function(){
24 render : function(){
25
25
26 this.$el
26 this.$el
27 .addClass('widget-hbox-single')
27 .addClass('widget-hbox-single')
28 .html('');
28 .html('');
29 this.$label = $('<div />')
29 this.$label = $('<div />')
30 .appendTo(this.$el)
30 .appendTo(this.$el)
31 .addClass('widget-hlabel')
31 .addClass('widget-hlabel')
32 .hide();
32 .hide();
33 this.$buttongroup = $('<div />')
33 this.$buttongroup = $('<div />')
34 .addClass('widget_item')
34 .addClass('widget_item')
35 .addClass('btn-group')
35 .addClass('btn-group')
36 .appendTo(this.$el);
36 .appendTo(this.$el);
37 this.$el_to_style = this.$buttongroup; // Set default element to style
37 this.$el_to_style = this.$buttongroup; // Set default element to style
38 this.$droplabel = $('<button />')
38 this.$droplabel = $('<button />')
39 .addClass('btn')
39 .addClass('btn')
40 .addClass('widget-combo-btn')
40 .addClass('widget-combo-btn')
41 .html('&nbsp;')
41 .html('&nbsp;')
42 .appendTo(this.$buttongroup);
42 .appendTo(this.$buttongroup);
43 this.$dropbutton = $('<button />')
43 this.$dropbutton = $('<button />')
44 .addClass('btn')
44 .addClass('btn')
45 .addClass('dropdown-toggle')
45 .addClass('dropdown-toggle')
46 .addClass('widget-combo-carrot-btn')
46 .addClass('widget-combo-carrot-btn')
47 .attr('data-toggle', 'dropdown')
47 .attr('data-toggle', 'dropdown')
48 .html('<span class="caret"></span>')
48 .html('<span class="caret"></span>')
49 .appendTo(this.$buttongroup);
49 .appendTo(this.$buttongroup);
50 this.$droplist = $('<ul />')
50 this.$droplist = $('<ul />')
51 .addClass('dropdown-menu')
51 .addClass('dropdown-menu')
52 .appendTo(this.$buttongroup);
52 .appendTo(this.$buttongroup);
53
53
54 // Set defaults.
54 // Set defaults.
55 this.update();
55 this.update();
56 },
56 },
57
57
58 update : function(){
58 update : function(options){
59 // Update the contents of this view
59 // Update the contents of this view
60 //
60 //
61 // Called when the model is changed. The model may have been
61 // Called when the model is changed. The model may have been
62 // changed by another view or by a state update from the back-end.
62 // changed by another view or by a state update from the back-end.
63
63
64 var selected_item_text = this.model.get('value');
64 if (options === undefined || options.updated_view != this) {
65 selected_item_text = selected_item_text.replace(/ /g, '&nbsp;');
65 var selected_item_text = this.model.get('value');
66 selected_item_text = selected_item_text.replace(/\n/g, '<br>\n');
66 selected_item_text = selected_item_text.replace(/ /g, '&nbsp;');
67 if (selected_item_text.length === 0) {
67 selected_item_text = selected_item_text.replace(/\n/g, '<br>\n');
68 this.$droplabel.html('&nbsp;');
68 if (selected_item_text.length === 0) {
69 } else {
69 this.$droplabel.html('&nbsp;');
70 this.$droplabel.html(selected_item_text);
70 } else {
71 }
71 this.$droplabel.html(selected_item_text);
72
72 }
73 var items = this.model.get('values');
73
74 this.$droplist.html('');
74 var items = this.model.get('values');
75 for (var index in items) {
75 this.$droplist.html('');
76 var that = this;
76 for (var index in items) {
77 var item_button = $('<a href="#"/>')
77 var that = this;
78 .html(items[index])
78 var item_button = $('<a href="#"/>')
79 .on('click', $.proxy(this.handle_click, this));
79 .html(items[index])
80 this.$droplist.append($('<li />').append(item_button));
80 .on('click', $.proxy(this.handle_click, this));
81 }
81 this.$droplist.append($('<li />').append(item_button));
82
82 }
83 if (this.model.get('disabled')) {
83
84 this.$buttongroup.attr('disabled','disabled');
84 if (this.model.get('disabled')) {
85 this.$droplabel.attr('disabled','disabled');
85 this.$buttongroup.attr('disabled','disabled');
86 this.$dropbutton.attr('disabled','disabled');
86 this.$droplabel.attr('disabled','disabled');
87 this.$droplist.attr('disabled','disabled');
87 this.$dropbutton.attr('disabled','disabled');
88 } else {
88 this.$droplist.attr('disabled','disabled');
89 this.$buttongroup.removeAttr('disabled');
89 } else {
90 this.$droplabel.removeAttr('disabled');
90 this.$buttongroup.removeAttr('disabled');
91 this.$dropbutton.removeAttr('disabled');
91 this.$droplabel.removeAttr('disabled');
92 this.$droplist.removeAttr('disabled');
92 this.$dropbutton.removeAttr('disabled');
93 }
93 this.$droplist.removeAttr('disabled');
94 }
94
95
95 var description = this.model.get('description');
96 var description = this.model.get('description');
96 if (description.length === 0) {
97 if (description.length === 0) {
97 this.$label.hide();
98 this.$label.hide();
98 } else {
99 } else {
99 this.$label.html(description);
100 this.$label.html(description);
100 this.$label.show();
101 this.$label.show();
102 }
101 }
103 }
102 return IPython.DOMWidgetView.prototype.update.call(this);
104 return IPython.DOMWidgetView.prototype.update.call(this);
103 },
105 },
104
106
105 // Handle when a value is clicked.
107 // Handle when a value is clicked.
106 handle_click: function (e) {
108 handle_click: function (e) {
107
109
108 // Calling model.set will trigger all of the other views of the
110 // Calling model.set will trigger all of the other views of the
109 // model to update.
111 // model to update.
110 this.model.set('value', $(e.target).html(), this);
112 this.model.set('value', $(e.target).html(), {updated_view: this});
111 this.touch();
113 this.touch();
112 },
114 },
113
115
114 });
116 });
115
117
116 widget_manager.register_widget_view('DropdownView', DropdownView);
118 widget_manager.register_widget_view('DropdownView', DropdownView);
117
119
118 var RadioButtonsView = IPython.DOMWidgetView.extend({
120 var RadioButtonsView = IPython.DOMWidgetView.extend({
119
121
120 // Called when view is rendered.
122 // Called when view is rendered.
121 render : function(){
123 render : function(){
122 this.$el
124 this.$el
123 .addClass('widget-hbox')
125 .addClass('widget-hbox')
124 .html('');
126 .html('');
125 this.$label = $('<div />')
127 this.$label = $('<div />')
126 .appendTo(this.$el)
128 .appendTo(this.$el)
127 .addClass('widget-hlabel')
129 .addClass('widget-hlabel')
128 .hide();
130 .hide();
129 this.$container = $('<div />')
131 this.$container = $('<div />')
130 .appendTo(this.$el)
132 .appendTo(this.$el)
131 .addClass('widget-container')
133 .addClass('widget-container')
132 .addClass('vbox');
134 .addClass('vbox');
133 this.$el_to_style = this.$container; // Set default element to style
135 this.$el_to_style = this.$container; // Set default element to style
134 this.update();
136 this.update();
135 },
137 },
136
138
137 update : function(){
139 update : function(options){
138 // Update the contents of this view
140 // Update the contents of this view
139 //
141 //
140 // Called when the model is changed. The model may have been
142 // Called when the model is changed. The model may have been
141 // changed by another view or by a state update from the back-end.
143 // changed by another view or by a state update from the back-end.
142
144 if (options === undefined || options.updated_view != this) {
143 // Add missing items to the DOM.
145 // Add missing items to the DOM.
144 var items = this.model.get('values');
146 var items = this.model.get('values');
145 var disabled = this.model.get('disabled');
147 var disabled = this.model.get('disabled');
146 for (var index in items) {
147 var item_query = ' :input[value="' + items[index] + '"]';
148 if (this.$el.find(item_query).length === 0) {
149 var $label = $('<label />')
150 .addClass('radio')
151 .html(items[index])
152 .appendTo(this.$container);
153
154 $('<input />')
155 .attr('type', 'radio')
156 .addClass(this.model)
157 .val(items[index])
158 .prependTo($label)
159 .on('click', $.proxy(this.handle_click, this));
160 }
161
162 var $item_element = this.$container.find(item_query);
163 if (this.model.get('value') == items[index]) {
164 $item_element.prop('checked', true);
165 } else {
166 $item_element.prop('checked', false);
167 }
168 $item_element.prop('disabled', disabled);
169 }
170
171 // Remove items that no longer exist.
172 this.$container.find('input').each(function(i, obj) {
173 var value = $(obj).val();
174 var found = false;
175 for (var index in items) {
148 for (var index in items) {
176 if (items[index] == value) {
149 var item_query = ' :input[value="' + items[index] + '"]';
177 found = true;
150 if (this.$el.find(item_query).length === 0) {
178 break;
151 var $label = $('<label />')
152 .addClass('radio')
153 .html(items[index])
154 .appendTo(this.$container);
155
156 $('<input />')
157 .attr('type', 'radio')
158 .addClass(this.model)
159 .val(items[index])
160 .prependTo($label)
161 .on('click', $.proxy(this.handle_click, this));
162 }
163
164 var $item_element = this.$container.find(item_query);
165 if (this.model.get('value') == items[index]) {
166 $item_element.prop('checked', true);
167 } else {
168 $item_element.prop('checked', false);
179 }
169 }
170 $item_element.prop('disabled', disabled);
180 }
171 }
181
172
182 if (!found) {
173 // Remove items that no longer exist.
183 $(obj).parent().remove();
174 this.$container.find('input').each(function(i, obj) {
184 }
175 var value = $(obj).val();
185 });
176 var found = false;
177 for (var index in items) {
178 if (items[index] == value) {
179 found = true;
180 break;
181 }
182 }
183
184 if (!found) {
185 $(obj).parent().remove();
186 }
187 });
186
188
187 var description = this.model.get('description');
189 var description = this.model.get('description');
188 if (description.length === 0) {
190 if (description.length === 0) {
189 this.$label.hide();
191 this.$label.hide();
190 } else {
192 } else {
191 this.$label.html(description);
193 this.$label.html(description);
192 this.$label.show();
194 this.$label.show();
195 }
193 }
196 }
194 return IPython.DOMWidgetView.prototype.update.call(this);
197 return IPython.DOMWidgetView.prototype.update.call(this);
195 },
198 },
196
199
197 // Handle when a value is clicked.
200 // Handle when a value is clicked.
198 handle_click: function (e) {
201 handle_click: function (e) {
199
202
200 // Calling model.set will trigger all of the other views of the
203 // Calling model.set will trigger all of the other views of the
201 // model to update.
204 // model to update.
202 this.model.set('value', $(e.target).val(), this);
205 this.model.set('value', $(e.target).val(), {updated_view: this});
203 this.touch();
206 this.touch();
204 },
207 },
205 });
208 });
206
209
207 widget_manager.register_widget_view('RadioButtonsView', RadioButtonsView);
210 widget_manager.register_widget_view('RadioButtonsView', RadioButtonsView);
208
211
209
212
210 var ToggleButtonsView = IPython.DOMWidgetView.extend({
213 var ToggleButtonsView = IPython.DOMWidgetView.extend({
211
214
212 // Called when view is rendered.
215 // Called when view is rendered.
213 render : function(){
216 render : function(){
214 this.$el
217 this.$el
215 .addClass('widget-hbox-single')
218 .addClass('widget-hbox-single')
216 .html('');
219 .html('');
217 this.$label = $('<div />')
220 this.$label = $('<div />')
218 .appendTo(this.$el)
221 .appendTo(this.$el)
219 .addClass('widget-hlabel')
222 .addClass('widget-hlabel')
220 .hide();
223 .hide();
221 this.$buttongroup = $('<div />')
224 this.$buttongroup = $('<div />')
222 .addClass('btn-group')
225 .addClass('btn-group')
223 .attr('data-toggle', 'buttons-radio')
226 .attr('data-toggle', 'buttons-radio')
224 .appendTo(this.$el);
227 .appendTo(this.$el);
225 this.$el_to_style = this.$buttongroup; // Set default element to style
228 this.$el_to_style = this.$buttongroup; // Set default element to style
226 this.update();
229 this.update();
227 },
230 },
228
231
229 update : function(){
232 update : function(options){
230 // Update the contents of this view
233 // Update the contents of this view
231 //
234 //
232 // Called when the model is changed. The model may have been
235 // Called when the model is changed. The model may have been
233 // changed by another view or by a state update from the back-end.
236 // changed by another view or by a state update from the back-end.
234
237 if (options === undefined || options.updated_view != this) {
235 // Add missing items to the DOM.
238 // Add missing items to the DOM.
236 var items = this.model.get('values');
239 var items = this.model.get('values');
237 var disabled = this.model.get('disabled');
240 var disabled = this.model.get('disabled');
238 for (var index in items) {
239 var item_query = ' :contains("' + items[index] + '")';
240 if (this.$buttongroup.find(item_query).length === 0) {
241 $('<button />')
242 .attr('type', 'button')
243 .addClass('btn')
244 .html(items[index])
245 .appendTo(this.$buttongroup)
246 .on('click', $.proxy(this.handle_click, this));
247 }
248
249 var $item_element = this.$buttongroup.find(item_query);
250 if (this.model.get('value') == items[index]) {
251 $item_element.addClass('active');
252 } else {
253 $item_element.removeClass('active');
254 }
255 $item_element.prop('disabled', disabled);
256 }
257
258 // Remove items that no longer exist.
259 this.$buttongroup.find('button').each(function(i, obj) {
260 var value = $(obj).html();
261 var found = false;
262 for (var index in items) {
241 for (var index in items) {
263 if (items[index] == value) {
242 var item_query = ' :contains("' + items[index] + '")';
264 found = true;
243 if (this.$buttongroup.find(item_query).length === 0) {
265 break;
244 $('<button />')
245 .attr('type', 'button')
246 .addClass('btn')
247 .html(items[index])
248 .appendTo(this.$buttongroup)
249 .on('click', $.proxy(this.handle_click, this));
250 }
251
252 var $item_element = this.$buttongroup.find(item_query);
253 if (this.model.get('value') == items[index]) {
254 $item_element.addClass('active');
255 } else {
256 $item_element.removeClass('active');
266 }
257 }
258 $item_element.prop('disabled', disabled);
267 }
259 }
268
260
269 if (!found) {
261 // Remove items that no longer exist.
270 $(obj).remove();
262 this.$buttongroup.find('button').each(function(i, obj) {
271 }
263 var value = $(obj).html();
272 });
264 var found = false;
265 for (var index in items) {
266 if (items[index] == value) {
267 found = true;
268 break;
269 }
270 }
271
272 if (!found) {
273 $(obj).remove();
274 }
275 });
273
276
274 var description = this.model.get('description');
277 var description = this.model.get('description');
275 if (description.length === 0) {
278 if (description.length === 0) {
276 this.$label.hide();
279 this.$label.hide();
277 } else {
280 } else {
278 this.$label.html(description);
281 this.$label.html(description);
279 this.$label.show();
282 this.$label.show();
283 }
280 }
284 }
281 return IPython.DOMWidgetView.prototype.update.call(this);
285 return IPython.DOMWidgetView.prototype.update.call(this);
282 },
286 },
283
287
284 // Handle when a value is clicked.
288 // Handle when a value is clicked.
285 handle_click: function (e) {
289 handle_click: function (e) {
286
290
287 // Calling model.set will trigger all of the other views of the
291 // Calling model.set will trigger all of the other views of the
288 // model to update.
292 // model to update.
289 this.model.set('value', $(e.target).html(), this);
293 this.model.set('value', $(e.target).html(), {updated_view: this});
290 this.touch();
294 this.touch();
291 },
295 },
292
296
293 });
297 });
294
298
295 widget_manager.register_widget_view('ToggleButtonsView', ToggleButtonsView);
299 widget_manager.register_widget_view('ToggleButtonsView', ToggleButtonsView);
296
300
297 var ListBoxView = IPython.DOMWidgetView.extend({
301 var ListBoxView = IPython.DOMWidgetView.extend({
298
302
299 // Called when view is rendered.
303 // Called when view is rendered.
300 render : function(){
304 render : function(){
301 this.$el
305 this.$el
302 .addClass('widget-hbox')
306 .addClass('widget-hbox')
303 .html('');
307 .html('');
304 this.$label = $('<div />')
308 this.$label = $('<div />')
305 .appendTo(this.$el)
309 .appendTo(this.$el)
306 .addClass('widget-hlabel')
310 .addClass('widget-hlabel')
307 .hide();
311 .hide();
308 this.$listbox = $('<select />')
312 this.$listbox = $('<select />')
309 .addClass('widget-listbox')
313 .addClass('widget-listbox')
310 .attr('size', 6)
314 .attr('size', 6)
311 .appendTo(this.$el);
315 .appendTo(this.$el);
312 this.$el_to_style = this.$listbox; // Set default element to style
316 this.$el_to_style = this.$listbox; // Set default element to style
313 this.update();
317 this.update();
314 },
318 },
315
319
316 update : function(){
320 update : function(options){
317 // Update the contents of this view
321 // Update the contents of this view
318 //
322 //
319 // Called when the model is changed. The model may have been
323 // Called when the model is changed. The model may have been
320 // changed by another view or by a state update from the back-end.
324 // changed by another view or by a state update from the back-end.
321
325 if (options === undefined || options.updated_view != this) {
322 // Add missing items to the DOM.
326 // Add missing items to the DOM.
323 var items = this.model.get('values');
327 var items = this.model.get('values');
324 for (var index in items) {
325 var item_query = ' :contains("' + items[index] + '")';
326 if (this.$listbox.find(item_query).length === 0) {
327 $('<option />')
328 .html(items[index])
329 .attr('value', items[index])
330 .appendTo(this.$listbox)
331 .on('click', $.proxy(this.handle_click, this));
332 }
333 }
334
335 // Select the correct element
336 this.$listbox.val(this.model.get('value'));
337
338 // Disable listbox if needed
339 var disabled = this.model.get('disabled');
340 this.$listbox.prop('disabled', disabled);
341
342 // Remove items that no longer exist.
343 this.$listbox.find('option').each(function(i, obj) {
344 var value = $(obj).html();
345 var found = false;
346 for (var index in items) {
328 for (var index in items) {
347 if (items[index] == value) {
329 var item_query = ' :contains("' + items[index] + '")';
348 found = true;
330 if (this.$listbox.find(item_query).length === 0) {
349 break;
331 $('<option />')
332 .html(items[index])
333 .attr('value', items[index])
334 .appendTo(this.$listbox)
335 .on('click', $.proxy(this.handle_click, this));
350 }
336 }
351 }
337 }
338
339 // Select the correct element
340 this.$listbox.val(this.model.get('value'));
352
341
353 if (!found) {
342 // Disable listbox if needed
354 $(obj).remove();
343 var disabled = this.model.get('disabled');
355 }
344 this.$listbox.prop('disabled', disabled);
356 });
345
346 // Remove items that no longer exist.
347 this.$listbox.find('option').each(function(i, obj) {
348 var value = $(obj).html();
349 var found = false;
350 for (var index in items) {
351 if (items[index] == value) {
352 found = true;
353 break;
354 }
355 }
356
357 if (!found) {
358 $(obj).remove();
359 }
360 });
357
361
358 var description = this.model.get('description');
362 var description = this.model.get('description');
359 if (description.length === 0) {
363 if (description.length === 0) {
360 this.$label.hide();
364 this.$label.hide();
361 } else {
365 } else {
362 this.$label.html(description);
366 this.$label.html(description);
363 this.$label.show();
367 this.$label.show();
368 }
364 }
369 }
365 return IPython.DOMWidgetView.prototype.update.call(this);
370 return IPython.DOMWidgetView.prototype.update.call(this);
366 },
371 },
367
372
368 // Handle when a value is clicked.
373 // Handle when a value is clicked.
369 handle_click: function (e) {
374 handle_click: function (e) {
370
375
371 // Calling model.set will trigger all of the other views of the
376 // Calling model.set will trigger all of the other views of the
372 // model to update.
377 // model to update.
373 this.model.set('value', $(e.target).html(), this);
378 this.model.set('value', $(e.target).html(), {updated_view: this});
374 this.touch();
379 this.touch();
375 },
380 },
376
381
377 });
382 });
378
383
379 widget_manager.register_widget_view('ListBoxView', ListBoxView);
384 widget_manager.register_widget_view('ListBoxView', ListBoxView);
380 });
385 });
@@ -1,202 +1,202 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 // StringWidget
9 // StringWidget
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(widget_manager){
17 define(["notebook/js/widgets/widget"], function(widget_manager){
18 var StringWidgetModel = IPython.WidgetModel.extend({});
18 var StringWidgetModel = IPython.WidgetModel.extend({});
19 widget_manager.register_widget_model('StringWidgetModel', StringWidgetModel);
19 widget_manager.register_widget_model('StringWidgetModel', StringWidgetModel);
20
20
21 var HTMLView = IPython.DOMWidgetView.extend({
21 var HTMLView = IPython.DOMWidgetView.extend({
22
22
23 // Called when view is rendered.
23 // Called when view is rendered.
24 render : function(){
24 render : function(){
25 this.update(); // Set defaults.
25 this.update(); // Set defaults.
26 },
26 },
27
27
28 update : function(){
28 update : function(){
29 // Update the contents of this view
29 // Update the contents of this view
30 //
30 //
31 // Called when the model is changed. The model may have been
31 // Called when the model is changed. The model may have been
32 // changed by another view or by a state update from the back-end.
32 // changed by another view or by a state update from the back-end.
33 this.$el.html(this.model.get('value'));
33 this.$el.html(this.model.get('value'));
34 return IPython.DOMWidgetView.prototype.update.call(this);
34 return IPython.DOMWidgetView.prototype.update.call(this);
35 },
35 },
36
36
37 });
37 });
38
38
39 widget_manager.register_widget_view('HTMLView', HTMLView);
39 widget_manager.register_widget_view('HTMLView', HTMLView);
40
40
41
41
42 var LatexView = IPython.DOMWidgetView.extend({
42 var LatexView = IPython.DOMWidgetView.extend({
43
43
44 // Called when view is rendered.
44 // Called when view is rendered.
45 render : function(){
45 render : function(){
46 this.update(); // Set defaults.
46 this.update(); // Set defaults.
47 },
47 },
48
48
49 update : function(){
49 update : function(){
50 // Update the contents of this view
50 // Update the contents of this view
51 //
51 //
52 // Called when the model is changed. The model may have been
52 // Called when the model is changed. The model may have been
53 // changed by another view or by a state update from the back-end.
53 // changed by another view or by a state update from the back-end.
54 this.$el.html(this.model.get('value'));
54 this.$el.html(this.model.get('value'));
55 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$el.get(0)]);
55 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$el.get(0)]);
56
56
57 return IPython.DOMWidgetView.prototype.update.call(this);
57 return IPython.DOMWidgetView.prototype.update.call(this);
58 },
58 },
59
59
60 });
60 });
61
61
62 widget_manager.register_widget_view('LatexView', LatexView);
62 widget_manager.register_widget_view('LatexView', LatexView);
63
63
64 var TextAreaView = IPython.DOMWidgetView.extend({
64 var TextAreaView = IPython.DOMWidgetView.extend({
65
65
66 // Called when view is rendered.
66 // Called when view is rendered.
67 render: function(){
67 render: function(){
68 this.$el
68 this.$el
69 .addClass('widget-hbox')
69 .addClass('widget-hbox')
70 .html('');
70 .html('');
71 this.$label = $('<div />')
71 this.$label = $('<div />')
72 .appendTo(this.$el)
72 .appendTo(this.$el)
73 .addClass('widget-hlabel')
73 .addClass('widget-hlabel')
74 .hide();
74 .hide();
75 this.$textbox = $('<textarea />')
75 this.$textbox = $('<textarea />')
76 .attr('rows', 5)
76 .attr('rows', 5)
77 .addClass('widget-text')
77 .addClass('widget-text')
78 .appendTo(this.$el);
78 .appendTo(this.$el);
79 this.$el_to_style = this.$textbox; // Set default element to style
79 this.$el_to_style = this.$textbox; // Set default element to style
80 this.update(); // Set defaults.
80 this.update(); // Set defaults.
81
81
82 this.model.on('msg:custom', $.proxy(this._handle_textarea_msg, this));
82 this.model.on('msg:custom', $.proxy(this._handle_textarea_msg, this));
83 },
83 },
84
84
85
85
86 _handle_textarea_msg: function (content){
86 _handle_textarea_msg: function (content){
87 if (content.method == "scroll_to_bottom") {
87 if (content.method == "scroll_to_bottom") {
88 this.scroll_to_bottom();
88 this.scroll_to_bottom();
89 }
89 }
90 },
90 },
91
91
92
92
93 scroll_to_bottom: function (){
93 scroll_to_bottom: function (){
94 this.$textbox.scrollTop(this.$textbox[0].scrollHeight);
94 this.$textbox.scrollTop(this.$textbox[0].scrollHeight);
95 },
95 },
96
96
97
97
98 update: function(){
98 update: function(options){
99 // Update the contents of this view
99 // Update the contents of this view
100 //
100 //
101 // Called when the model is changed. The model may have been
101 // Called when the model is changed. The model may have been
102 // changed by another view or by a state update from the back-end.
102 // changed by another view or by a state update from the back-end.
103 if (!this.user_invoked_update) {
103 if (options === undefined || options.updated_view != this) {
104 this.$textbox.val(this.model.get('value'));
104 this.$textbox.val(this.model.get('value'));
105 }
106
105
107 var disabled = this.model.get('disabled');
106 var disabled = this.model.get('disabled');
108 this.$textbox.prop('disabled', disabled);
107 this.$textbox.prop('disabled', disabled);
109
108
110 var description = this.model.get('description');
109 var description = this.model.get('description');
111 if (description.length === 0) {
110 if (description.length === 0) {
112 this.$label.hide();
111 this.$label.hide();
113 } else {
112 } else {
114 this.$label.html(description);
113 this.$label.html(description);
115 this.$label.show();
114 this.$label.show();
115 }
116 }
116 }
117 return IPython.DOMWidgetView.prototype.update.call(this);
117 return IPython.DOMWidgetView.prototype.update.call(this);
118 },
118 },
119
119
120 events: {"keyup textarea": "handleChanging",
120 events: {"keyup textarea": "handleChanging",
121 "paste textarea": "handleChanging",
121 "paste textarea": "handleChanging",
122 "cut textarea": "handleChanging"},
122 "cut textarea": "handleChanging"},
123
123
124 // Handles and validates user input.
124 // Handles and validates user input.
125 handleChanging: function(e) {
125 handleChanging: function(e) {
126 this.user_invoked_update = true;
127
126
128 // Calling model.set will trigger all of the other views of the
127 // Calling model.set will trigger all of the other views of the
129 // model to update.
128 // model to update.
130 this.model.set('value', e.target.value);
129 this.model.set('value', e.target.value, {updated_view: this});
131 this.touch();
130 this.touch();
132 this.user_invoked_update = false;
133 },
131 },
134 });
132 });
135
133
136 widget_manager.register_widget_view('TextAreaView', TextAreaView);
134 widget_manager.register_widget_view('TextAreaView', TextAreaView);
137
135
138 var TextBoxView = IPython.DOMWidgetView.extend({
136 var TextBoxView = IPython.DOMWidgetView.extend({
139
137
140 // Called when view is rendered.
138 // Called when view is rendered.
141 render: function(){
139 render: function(){
142 this.$el
140 this.$el
143 .addClass('widget-hbox-single')
141 .addClass('widget-hbox-single')
144 .html('');
142 .html('');
145 this.$label = $('<div />')
143 this.$label = $('<div />')
146 .addClass('widget-hlabel')
144 .addClass('widget-hlabel')
147 .appendTo(this.$el)
145 .appendTo(this.$el)
148 .hide();
146 .hide();
149 this.$textbox = $('<input type="text" />')
147 this.$textbox = $('<input type="text" />')
150 .addClass('input')
148 .addClass('input')
151 .addClass('widget-text')
149 .addClass('widget-text')
152 .appendTo(this.$el);
150 .appendTo(this.$el);
153 this.$el_to_style = this.$textbox; // Set default element to style
151 this.$el_to_style = this.$textbox; // Set default element to style
154 this.update(); // Set defaults.
152 this.update(); // Set defaults.
155 },
153 },
156
154
157 update: function(){
155 update: function(options){
158 // Update the contents of this view
156 // Update the contents of this view
159 //
157 //
160 // Called when the model is changed. The model may have been
158 // Called when the model is changed. The model may have been
161 // changed by another view or by a state update from the back-end.
159 // changed by another view or by a state update from the back-end.
162 if (this.$textbox.val() != this.model.get('value')) {
160 if (options === undefined || options.updated_view != this) {
163 this.$textbox.val(this.model.get('value'));
161 if (this.$textbox.val() != this.model.get('value')) {
164 }
162 this.$textbox.val(this.model.get('value'));
165
163 }
166 var disabled = this.model.get('disabled');
164
167 this.$textbox.prop('disabled', disabled);
165 var disabled = this.model.get('disabled');
168
166 this.$textbox.prop('disabled', disabled);
169 var description = this.model.get('description');
167
170 if (description.length === 0) {
168 var description = this.model.get('description');
171 this.$label.hide();
169 if (description.length === 0) {
172 } else {
170 this.$label.hide();
173 this.$label.html(description);
171 } else {
174 this.$label.show();
172 this.$label.html(description);
173 this.$label.show();
174 }
175 }
175 }
176 return IPython.DOMWidgetView.prototype.update.call(this);
176 return IPython.DOMWidgetView.prototype.update.call(this);
177 },
177 },
178
178
179 events: {"keyup input": "handleChanging",
179 events: {"keyup input": "handleChanging",
180 "paste input": "handleChanging",
180 "paste input": "handleChanging",
181 "cut input": "handleChanging",
181 "cut input": "handleChanging",
182 "keypress input": "handleKeypress"},
182 "keypress input": "handleKeypress"},
183
183
184 // Handles and validates user input.
184 // Handles and validates user input.
185 handleChanging: function(e) {
185 handleChanging: function(e) {
186
186
187 // Calling model.set will trigger all of the other views of the
187 // Calling model.set will trigger all of the other views of the
188 // model to update.
188 // model to update.
189 this.model.set('value', e.target.value);
189 this.model.set('value', e.target.value, {updated_view: this});
190 this.touch();
190 this.touch();
191 },
191 },
192
192
193 // Handles text submition
193 // Handles text submition
194 handleKeypress: function(e) {
194 handleKeypress: function(e) {
195 if (e.keyCode == 13) { // Return key
195 if (e.keyCode == 13) { // Return key
196 this.send({event: 'submit'});
196 this.send({event: 'submit'});
197 }
197 }
198 },
198 },
199 });
199 });
200
200
201 widget_manager.register_widget_view('TextBoxView', TextBoxView);
201 widget_manager.register_widget_view('TextBoxView', TextBoxView);
202 });
202 });
General Comments 0
You need to be logged in to leave comments. Login now