##// END OF EJS Templates
Lots of updates to widget(s) js...
Jonathan Frederic -
Show More
@@ -17,237 +17,245
17
17
18 "use strict";
18 "use strict";
19
19
20 // Only run once on a notebook.
20 // Use require.js 'define' method so that require.js is intelligent enough to
21 if (IPython.notebook.widget_manager == undefined) {
21 // syncronously load everything within this file when it is being 'required'
22
22 // elsewhere.
23 //-----------------------------------------------------------------------
23 define(["static/components/underscore/underscore-min.js",
24 // WidgetModel class
24 "static/components/backbone/backbone-min.js",
25 //-----------------------------------------------------------------------
25 ], function(){
26 var WidgetModel = Backbone.Model.extend({
26
27 apply: function(sender) {
27 // Only run once on a notebook.
28 this.save();
28 if (IPython.notebook.widget_manager == undefined) {
29
29
30 for (var index in this.views) {
30 //--------------------------------------------------------------------
31 var view = this.views[index];
31 // WidgetModel class
32 if (view !== sender) {
32 //--------------------------------------------------------------------
33 view.refresh();
33 var WidgetModel = Backbone.Model.extend({
34 apply: function(sender) {
35 this.save();
36
37 for (var index in this.views) {
38 var view = this.views[index];
39 if (view !== sender) {
40 view.refresh();
41 }
34 }
42 }
35 }
43 }
36 }
44 });
37 });
45
38
46
39
47 //--------------------------------------------------------------------
40 //-----------------------------------------------------------------------
48 // WidgetView class
41 // WidgetView class
49 //--------------------------------------------------------------------
42 //-----------------------------------------------------------------------
50 var WidgetView = Backbone.View.extend({
43 var WidgetView = Backbone.View.extend({
44
45 initialize: function() {
46 this.model.on('change',this.refresh,this);
47 },
48
49 refresh: function() {
50 this.update();
51
51
52 if (this.model.css != undefined) {
52 initialize: function() {
53 for (var selector in this.model.css) {
53 this.model.on('change',this.refresh,this);
54 if (this.model.css.hasOwnProperty(selector)) {
54 },
55
55
56 // Get the elements via the css selector. If the selector is
56 refresh: function() {
57 // blank, assume the current element is the target.
57 this.update();
58 var elements = this.$el.find(selector);
58
59 if (selector=='') {
59 if (this.model.css != undefined) {
60 elements = this.$el;
60 for (var selector in this.model.css) {
61 }
61 if (this.model.css.hasOwnProperty(selector)) {
62
62
63 // Apply the css traits to all elements that match the selector.
63 // Get the elements via the css selector. If the selector is
64 if (elements.length>0){
64 // blank, assume the current element is the target.
65 var css_traits = this.model.css[selector];
65 var elements = this.$el.find(selector);
66 for (var css_key in css_traits) {
66 if (selector=='') {
67 if (css_traits.hasOwnProperty(css_key)) {
67 elements = this.$el;
68 elements.css(css_key, css_traits[css_key]);
68 }
69
70 // Apply the css traits to all elements that match the selector.
71 if (elements.length>0){
72 var css_traits = this.model.css[selector];
73 for (var css_key in css_traits) {
74 if (css_traits.hasOwnProperty(css_key)) {
75 elements.css(css_key, css_traits[css_key]);
76 }
69 }
77 }
70 }
78 }
71 }
79 }
72 }
80 }
73 }
81 }
74 }
82 },
75 },
83 });
76 });
84
77
85
78
86 //--------------------------------------------------------------------
79 //-----------------------------------------------------------------------
87 // WidgetManager class
80 // WidgetManager class
88 //--------------------------------------------------------------------
81 //-----------------------------------------------------------------------
89 // Public constructor
82 // Public constructor
90 var WidgetManager = function(comm_manager){
83 var WidgetManager = function(comm_manager){
91 this.comm_manager = comm_manager;
84 this.comm_manager = comm_manager;
92 this.widget_model_types = {};
85 this.widget_model_types = {};
93 this.widget_view_types = {};
86 this.widget_view_types = {};
94 this.model_widget_views = {};
87 this.model_widget_views = {};
95
88
96 var that = this;
89 var that = this;
97 Backbone.sync = function(method, model, options, error) {
90 Backbone.sync = function(method, model, options, error) {
98 var result = that.send_sync(method, model);
91 var result = that.send_sync(method, model);
99 if (options.success) {
92 if (options.success) {
100 options.success(result);
93 options.success(result);
101 }
94 }
102 };
95 };
96 }
97
98 // Register a widget model type.
99 WidgetManager.prototype.register_widget_model = function (widget_model_name, widget_model_type) {
100
101 // Register the widget with the comm manager. Make sure to pass this object's context
102 // in so `this` works in the call back.
103 this.comm_manager.register_target(widget_model_name, $.proxy(this.handle_com_open, this));
104
105 // Register the types of the model and view correspong to this widget type. Later
106 // the widget manager will initialize these when the comm is opened.
107 this.widget_model_types[widget_model_name] = widget_model_type;
108 }
109
110 // Register a widget view type.
111 WidgetManager.prototype.register_widget_view = function (widget_view_name, widget_view_type) {
112 this.widget_view_types[widget_view_name] = widget_view_type;
113 }
114
115 // Handle when a comm is opened.
116 WidgetManager.prototype.handle_com_open = function (comm, msg) {
117 var widget_type_name = msg.content.target_name;
118
119 // Create the corresponding widget model.
120 var widget_model = new this.widget_model_types[widget_type_name];
121
122 // Remember comm associated with the model.
123 widget_model.comm = comm;
124 comm.model = widget_model;
125
126 // Create an array to remember the views associated with the model.
127 widget_model.views = [];
128
129 // Add a handle to delete the control when the comm is closed.
130 var that = this;
131 var handle_close = function(msg) {
132 that.handle_comm_closed(comm, msg);
133 }
103 }
134 comm.on_close(handle_close);
135
104
136 // Handle incomming messages.
105 // Register a widget model type.
137 var handle_msg = function(msg) {
106 WidgetManager.prototype.register_widget_model = function (widget_model_name, widget_model_type) {
138 that.handle_comm_msg(comm, msg);
107
108 // Register the widget with the comm manager. Make sure to pass this object's context
109 // in so `this` works in the call back.
110 this.comm_manager.register_target(widget_model_name, $.proxy(this.handle_com_open, this));
111
112 // Register the types of the model and view correspong to this widget type. Later
113 // the widget manager will initialize these when the comm is opened.
114 this.widget_model_types[widget_model_name] = widget_model_type;
139 }
115 }
140 comm.on_msg(handle_msg);
116
141 }
117 // Register a widget view type.
142
118 WidgetManager.prototype.register_widget_view = function (widget_view_name, widget_view_type) {
143 // Create view that represents the model.
119 this.widget_view_types[widget_view_name] = widget_view_type;
144 WidgetManager.prototype.show_view = function (widget_area, widget_model, widget_view_name) {
120 }
145 var widget_view = new this.widget_view_types[widget_view_name]({model: widget_model});
121
146 widget_view.render();
122 // Handle when a comm is opened.
147 widget_model.views.push(widget_view);
123 WidgetManager.prototype.handle_com_open = function (comm, msg) {
148
124 var widget_type_name = msg.content.target_name;
149 // Handle when the view element is remove from the page.
125
150 widget_view.$el.on("remove", function(){
126 // Create the corresponding widget model.
151 var index = widget_model.views.indexOf(widget_view);
127 var widget_model = new this.widget_model_types[widget_type_name];
152 if (index > -1) {
128
153 widget_model.views.splice(index, 1);
129 // Remember comm associated with the model.
130 widget_model.comm = comm;
131 comm.model = widget_model;
132
133 // Create an array to remember the views associated with the model.
134 widget_model.views = [];
135
136 // Add a handle to delete the control when the comm is closed.
137 var that = this;
138 var handle_close = function(msg) {
139 that.handle_comm_closed(comm, msg);
154 }
140 }
155 widget_view.remove(); // Clean-up view
141 comm.on_close(handle_close);
156
142
157 // Close the comm if there are no views left.
143 // Handle incomming messages.
158 if (widget_model.views.length()==0) {
144 var handle_msg = function(msg) {
159 widget_model.comm.close();
145 that.handle_comm_msg(comm, msg);
160 }
146 }
161 });
147 comm.on_msg(handle_msg);
148 }
162
149
163 // Add the view's element to cell's widget div.
150 // Create view that represents the model.
164 widget_area
151 WidgetManager.prototype.show_view = function (widget_area, widget_model, widget_view_name) {
165 .append($("<div />").append(widget_view.$el))
152 var widget_view = new this.widget_view_types[widget_view_name]({model: widget_model});
166 .parent().show(); // Show the widget_area (parent of widget_subarea)
153 widget_view.render();
167
154 widget_model.views.push(widget_view);
168 // Update the view based on the model contents.
155
169 widget_view.refresh();
156 // Handle when the view element is remove from the page.
170 }
157 widget_view.$el.on("remove", function(){
171
158 var index = widget_model.views.indexOf(widget_view);
172 // Handle incomming comm msg.
159 if (index > -1) {
173 WidgetManager.prototype.handle_comm_msg = function (comm, msg) {
160 widget_model.views.splice(index, 1);
174 // Different logic for different methods.
161 }
175 var method = msg.content.data.method;
162 widget_view.remove(); // Clean-up view
176 switch (method){
163
177 case 'show':
164 // Close the comm if there are no views left.
178
165 if (widget_model.views.length()==0) {
179 // TODO: Get cell from registered output handler.
166 widget_model.comm.close();
180 var cell = IPython.notebook.get_cell(IPython.notebook.get_selected_index()-1);
181 var widget_subarea = cell.element.find('.widget_area').find('.widget_subarea');
182
183 if (msg.content.data.parent != undefined) {
184 var find_results = widget_subarea.find("." + msg.content.data.parent);
185 if (find_results.length > 0) {
186 widget_subarea = find_results;
187 }
188 }
167 }
168 });
169
170 // Add the view's element to cell's widget div.
171 widget_area
172 .append($("<div />").append(widget_view.$el))
173 .parent().show(); // Show the widget_area (parent of widget_subarea)
174
175 // Update the view based on the model contents.
176 widget_view.refresh();
177 }
178
179 // Handle incomming comm msg.
180 WidgetManager.prototype.handle_comm_msg = function (comm, msg) {
181 // Different logic for different methods.
182 var method = msg.content.data.method;
183 switch (method){
184 case 'show':
185
186 // TODO: Get cell from registered output handler.
187 var cell = IPython.notebook.get_cell(IPython.notebook.get_selected_index()-1);
188 var widget_subarea = cell.element.find('.widget_area').find('.widget_subarea');
189
190 if (msg.content.data.parent != undefined) {
191 var find_results = widget_subarea.find("." + msg.content.data.parent);
192 if (find_results.length > 0) {
193 widget_subarea = find_results;
194 }
195 }
189
196
190 this.show_view(widget_subarea, comm.model, msg.content.data.view_name);
197 this.show_view(widget_subarea, comm.model, msg.content.data.view_name);
191 break;
198 break;
192 case 'update':
199 case 'update':
193 this.handle_update(comm, msg.content.data.state);
200 this.handle_update(comm, msg.content.data.state);
194 break;
201 break;
202 }
195 }
203 }
196 }
204
197
205 // Handle when a widget is updated via the python side.
198 // Handle when a widget is updated via the python side.
206 WidgetManager.prototype.handle_update = function (comm, state) {
199 WidgetManager.prototype.handle_update = function (comm, state) {
207 for (var key in state) {
200 for (var key in state) {
208 if (state.hasOwnProperty(key)) {
201 if (state.hasOwnProperty(key)) {
209 if (key=="_css"){
202 if (key=="_css"){
210 comm.model.css = state[key];
203 comm.model.css = state[key];
211 } else {
204 } else {
212 comm.model.set(key, state[key]);
205 comm.model.set(key, state[key]);
213 }
206 }
214 }
207 }
215 }
216 comm.model.save();
208 }
217 }
209 comm.model.save();
218
210 }
219 // Handle when a widget is closed.
211
220 WidgetManager.prototype.handle_comm_closed = function (comm, msg) {
212 // Handle when a widget is closed.
221 for (var view_index in comm.model.views) {
213 WidgetManager.prototype.handle_comm_closed = function (comm, msg) {
222 var view = comm.model.views[view_index];
214 for (var view_index in comm.model.views) {
223 view.remove();
215 var view = comm.model.views[view_index];
224 }
216 view.remove();
217 }
225 }
218 }
226
219
227 // Get the cell output area corresponding to the comm.
220 // Get the cell output area corresponding to the comm.
228 WidgetManager.prototype._get_comm_outputarea = function (comm) {
221 WidgetManager.prototype._get_comm_outputarea = function (comm) {
229 // TODO: get element from comm instead of guessing
222 // TODO: get element from comm instead of guessing
230 var cell = IPython.notebook.get_cell(IPython.notebook.get_selected_index())
223 var cell = IPython.notebook.get_cell(IPython.notebook.get_selected_index())
231 return cell.output_area;
224 return cell.output_area;
232 }
225 }
233
226
234 // Send widget state to python backend.
227 // Send widget state to python backend.
235 WidgetManager.prototype.send_sync = function (method, model) {
228 WidgetManager.prototype.send_sync = function (method, model) {
236
229
237 // Create a callback for the output if the widget has an output area associate with it.
230 // Create a callback for the output if the widget has an output area associate with it.
238 var callbacks = {};
231 var callbacks = {};
239 var comm = model.comm;
232 var comm = model.comm;
240 var outputarea = this._get_comm_outputarea(comm);
233 var outputarea = this._get_comm_outputarea(comm);
241 if (outputarea != null) {
234 if (outputarea != null) {
242 callbacks = {
235 callbacks = {
243 iopub : {
236 iopub : {
244 output : $.proxy(outputarea.handle_output, outputarea),
237 output : $.proxy(outputarea.handle_output, outputarea),
245 clear_output : $.proxy(outputarea.handle_clear_output, outputarea)}
238 clear_output : $.proxy(outputarea.handle_clear_output, outputarea)}
246 };
239 };
247 };
240 };
248 var model_json = model.toJSON();
241 var model_json = model.toJSON();
249 var data = {sync_method: method, sync_data: model_json};
242 var data = {sync_method: method, sync_data: model_json};
250 comm.send(data, callbacks);
243 comm.send(data, callbacks);
251 return model_json;
244 return model_json;
252 }
245 }
246
253
247 IPython.WidgetManager = WidgetManager;
254 IPython.WidgetManager = WidgetManager;
248 IPython.WidgetModel = WidgetModel;
255 IPython.WidgetModel = WidgetModel;
249 IPython.WidgetView = WidgetView;
256 IPython.WidgetView = WidgetView;
250
257
251 IPython.notebook.widget_manager = new WidgetManager(IPython.notebook.kernel.comm_manager);
258 IPython.notebook.widget_manager = new WidgetManager(IPython.notebook.kernel.comm_manager);
252
259
253 };
260 };
261 });
@@ -1,17 +1,19
1 var ContainerModel = IPython.WidgetModel.extend({});
1 require(["notebook/js/widget"], function(){
2 IPython.notebook.widget_manager.register_widget_model('container_widget', ContainerModel);
2 var ContainerModel = IPython.WidgetModel.extend({});
3 IPython.notebook.widget_manager.register_widget_model('container_widget', ContainerModel);
3
4
4 var ContainerView = IPython.WidgetView.extend({
5 var ContainerView = IPython.WidgetView.extend({
5
6
6 render : function(){
7 render : function(){
7 this.$el.html('');
8 this.$el.html('');
8 this.$container = $('<div />')
9 this.$container = $('<div />')
9 .addClass('container')
10 .addClass('container')
10 .addClass(this.model.comm.comm_id);
11 .addClass(this.model.comm.comm_id);
11 this.$el.append(this.$container);
12 this.$el.append(this.$container);
12 },
13 },
13
14
14 update : function(){},
15 update : function(){},
15 });
16 });
16
17
17 IPython.notebook.widget_manager.register_widget_view('ContainerView', ContainerView);
18 IPython.notebook.widget_manager.register_widget_view('ContainerView', ContainerView);
19 }); No newline at end of file
@@ -1,119 +1,125
1 var FloatRangeWidgetModel = IPython.WidgetModel.extend({});
1 require(["notebook/js/widget"], function(){
2 IPython.notebook.widget_manager.register_widget_model('FloatRangeWidgetModel', FloatRangeWidgetModel);
2 var FloatRangeWidgetModel = IPython.WidgetModel.extend({});
3 IPython.notebook.widget_manager.register_widget_model('FloatRangeWidgetModel', FloatRangeWidgetModel);
3
4
4 var FloatSliderView = IPython.WidgetView.extend({
5 var FloatSliderView = IPython.WidgetView.extend({
5
6 // Called when view is rendered.
7 render : function(){
8 this.$el
9 .html('')
10 .addClass(this.model.comm.comm_id);
11 this.$slider = $('<div />')
12 .slider({})
13 .addClass('slider');
14
6
15 // Put the slider in a container
7 // Called when view is rendered.
16 this.$slider_container = $('<div />')
8 render : function(){
17 .css('padding-top', '4px')
9 this.$el
18 .css('padding-bottom', '4px')
10 .html('')
19 .append(this.$slider);
11 .addClass(this.model.comm.comm_id);
20 this.$el.append(this.$slider_container);
12 this.$slider = $('<div />')
13 .slider({})
14 .addClass('slider');
15
16 // Put the slider in a container
17 this.$slider_container = $('<div />')
18 .css('padding-top', '4px')
19 .css('padding-bottom', '4px')
20 .append(this.$slider);
21 this.$el.append(this.$slider_container);
22
23 // Set defaults.
24 this.update();
25 },
21
26
22 // Set defaults.
27 // Handles: Backend -> Frontend Sync
23 this.update();
28 // Frontent -> Frontend Sync
24 },
29 update : function(){
25
30 // Slider related keys.
26 // Handles: Backend -> Frontend Sync
31 var _keys = ['value', 'step', 'max', 'min', 'disabled', 'orientation'];
27 // Frontent -> Frontend Sync
32 for (var index in _keys) {
28 update : function(){
33 var key = _keys[index];
29 // Slider related keys.
34 if (this.model.get(key) != undefined) {
30 var _keys = ['value', 'step', 'max', 'min', 'disabled', 'orientation'];
35 this.$slider.slider("option", key, this.model.get(key));
31 for (var index in _keys) {
36 }
32 var key = _keys[index];
33 if (this.model.get(key) != undefined) {
34 this.$slider.slider("option", key, this.model.get(key));
35 }
37 }
36 }
38 },
37 },
39
38
40 // Handles: User input
39 // Handles: User input
41 events: { "slide" : "handleSliderChange" },
40 events: { "slide" : "handleSliderChange" },
42 handleSliderChange: function(e, ui) {
41 handleSliderChange: function(e, ui) {
43 this.model.set('value', ui.value);
42 this.model.set('value', ui.value);
44 this.model.apply(this);
43 this.model.apply(this);
45 },
44 },
46 });
45 });
46
47
47 IPython.notebook.widget_manager.register_widget_view('FloatSliderView', FloatSliderView);
48 IPython.notebook.widget_manager.register_widget_view('FloatSliderView', FloatSliderView);
48
49
49
50
50 var FloatTextView = IPython.WidgetView.extend({
51 var FloatTextView = IPython.WidgetView.extend({
51
52 // Called when view is rendered.
53 render : function(){
54 this.$el
55 .html('')
56 .addClass(this.model.comm.comm_id);
57 this.$textbox = $('<input type="text" />')
58 .addClass('input')
59 .appendTo(this.$el);
60 this.update(); // Set defaults.
61 },
62
63 // Handles: Backend -> Frontend Sync
64 // Frontent -> Frontend Sync
65 update : function(){
66 var value = this.model.get('value');
67 if (!this.changing && parseFloat(this.$textbox.val()) != value) {
68 this.$textbox.val(value);
69 }
70
52
71 if (this.model.get('disabled')) {
53 // Called when view is rendered.
72 this.$textbox.attr('disabled','disabled');
54 render : function(){
73 } else {
55 this.$el
74 this.$textbox.removeAttr('disabled');
56 .html('')
75 }
57 .addClass(this.model.comm.comm_id);
76 },
58 this.$textbox = $('<input type="text" />')
77
59 .addClass('input')
78
60 .appendTo(this.$el);
79 events: {"keyup input" : "handleChanging",
61 this.update(); // Set defaults.
80 "paste input" : "handleChanging",
62 },
81 "cut input" : "handleChanging",
82 "change input" : "handleChanged"}, // Fires only when control is validated or looses focus.
83
84 // Handles and validates user input.
85 handleChanging: function(e) {
86
63
87 // Try to parse value as a float.
64 // Handles: Backend -> Frontend Sync
88 var numericalValue = 0.0;
65 // Frontent -> Frontend Sync
89 if (e.target.value != '') {
66 update : function(){
90 numericalValue = parseFloat(e.target.value);
67 var value = this.model.get('value');
91 }
68 if (!this.changing && parseFloat(this.$textbox.val()) != value) {
69 this.$textbox.val(value);
70 }
71
72 if (this.model.get('disabled')) {
73 this.$textbox.attr('disabled','disabled');
74 } else {
75 this.$textbox.removeAttr('disabled');
76 }
77 },
92
78
93 // If parse failed, reset value to value stored in model.
79
94 if (isNaN(numericalValue)) {
80 events: {"keyup input" : "handleChanging",
95 e.target.value = this.model.get('value');
81 "paste input" : "handleChanging",
96 } else if (!isNaN(numericalValue)) {
82 "cut input" : "handleChanging",
97 numericalValue = Math.min(this.model.get('max'), numericalValue);
83 "change input" : "handleChanged"}, // Fires only when control is validated or looses focus.
98 numericalValue = Math.max(this.model.get('min'), numericalValue);
84
85 // Handles and validates user input.
86 handleChanging: function(e) {
99
87
100 // Apply the value if it has changed.
88 // Try to parse value as a float.
101 if (numericalValue != this.model.get('value')) {
89 var numericalValue = 0.0;
102 this.changing = true;
90 if (e.target.value != '') {
103 this.model.set('value', numericalValue);
91 numericalValue = parseFloat(e.target.value);
104 this.model.apply(this);
92 }
105 this.changing = false;
93
94 // If parse failed, reset value to value stored in model.
95 if (isNaN(numericalValue)) {
96 e.target.value = this.model.get('value');
97 } else if (!isNaN(numericalValue)) {
98 if (this.model.get('max') != undefined) {
99 numericalValue = Math.min(this.model.get('max'), numericalValue);
100 }
101 if (this.model.get('min') != undefined) {
102 numericalValue = Math.max(this.model.get('min'), numericalValue);
103 }
104
105 // Apply the value if it has changed.
106 if (numericalValue != this.model.get('value')) {
107 this.changing = true;
108 this.model.set('value', numericalValue);
109 this.model.apply(this);
110 this.changing = false;
111 }
112 }
113 },
114
115 // Applies validated input.
116 handleChanged: function(e) {
117 // Update the textbox
118 if (this.model.get('value') != e.target.value) {
119 e.target.value = this.model.get('value');
106 }
120 }
107 }
121 }
108 },
122 });
109
110 // Applies validated input.
111 handleChanged: function(e) {
112 // Update the textbox
113 if (this.model.get('value') != e.target.value) {
114 e.target.value = this.model.get('value');
115 }
116 }
117 });
118
123
119 IPython.notebook.widget_manager.register_widget_view('FloatTextView', FloatTextView);
124 IPython.notebook.widget_manager.register_widget_view('FloatTextView', FloatTextView);
125 });
@@ -1,117 +1,123
1 var IntRangeWidgetModel = IPython.WidgetModel.extend({});
1 require(["notebook/js/widget"], function(){
2 IPython.notebook.widget_manager.register_widget_model('IntRangeWidgetModel', IntRangeWidgetModel);
2 var IntRangeWidgetModel = IPython.WidgetModel.extend({});
3 IPython.notebook.widget_manager.register_widget_model('IntRangeWidgetModel', IntRangeWidgetModel);
3
4
4 var IntSliderView = IPython.WidgetView.extend({
5 var IntSliderView = IPython.WidgetView.extend({
5
6 // Called when view is rendered.
7 render : function(){
8 this.$el.html('');
9 this.$slider = $('<div />')
10 .slider({})
11 .addClass('slider');
12
6
13 // Put the slider in a container
7 // Called when view is rendered.
14 this.$slider_container = $('<div />')
8 render : function(){
15 .css('padding-top', '4px')
9 this.$el.html('');
16 .css('padding-bottom', '4px')
10 this.$slider = $('<div />')
17 .addClass(this.model.comm.comm_id)
11 .slider({})
18 .append(this.$slider);
12 .addClass('slider');
19 this.$el.append(this.$slider_container);
13
14 // Put the slider in a container
15 this.$slider_container = $('<div />')
16 .css('padding-top', '4px')
17 .css('padding-bottom', '4px')
18 .addClass(this.model.comm.comm_id)
19 .append(this.$slider);
20 this.$el.append(this.$slider_container);
21
22 // Set defaults.
23 this.update();
24 },
20
25
21 // Set defaults.
26 // Handles: Backend -> Frontend Sync
22 this.update();
27 // Frontent -> Frontend Sync
23 },
28 update : function(){
24
29 // Slider related keys.
25 // Handles: Backend -> Frontend Sync
30 var _keys = ['value', 'step', 'max', 'min', 'disabled', 'orientation'];
26 // Frontent -> Frontend Sync
31 for (var index in _keys) {
27 update : function(){
32 var key = _keys[index];
28 // Slider related keys.
33 if (this.model.get(key) != undefined) {
29 var _keys = ['value', 'step', 'max', 'min', 'disabled', 'orientation'];
34 this.$slider.slider("option", key, this.model.get(key));
30 for (var index in _keys) {
35 }
31 var key = _keys[index];
32 if (this.model.get(key) != undefined) {
33 this.$slider.slider("option", key, this.model.get(key));
34 }
36 }
35 }
37 },
36 },
38
37
39 // Handles: User input
38 // Handles: User input
40 events: { "slide" : "handleSliderChange" },
39 events: { "slide" : "handleSliderChange" },
41 handleSliderChange: function(e, ui) {
40 handleSliderChange: function(e, ui) {
42 this.model.set('value', ~~ui.value); // Double bit-wise not to truncate decimel
41 this.model.set('value', ~~ui.value); // Double bit-wise not to truncate decimel
43 this.model.apply(this);
42 this.model.apply(this);
44 },
43 },
45 });
44 });
45
46
46 IPython.notebook.widget_manager.register_widget_view('IntSliderView', IntSliderView);
47 IPython.notebook.widget_manager.register_widget_view('IntSliderView', IntSliderView);
47
48
48 var IntTextView = IPython.WidgetView.extend({
49 var IntTextView = IPython.WidgetView.extend({
49
50 // Called when view is rendered.
51 render : function(){
52 this.$el
53 .html('')
54 .addClass(this.model.comm.comm_id);
55 this.$textbox = $('<input type="text" />')
56 .addClass('input')
57 .appendTo(this.$el);
58 this.update(); // Set defaults.
59 },
60
61 // Handles: Backend -> Frontend Sync
62 // Frontent -> Frontend Sync
63 update : function(){
64 var value = this.model.get('value');
65 if (!this.changing && parseInt(this.$textbox.val()) != value) {
66 this.$textbox.val(value);
67 }
68
50
69 if (this.model.get('disabled')) {
51 // Called when view is rendered.
70 this.$textbox.attr('disabled','disabled');
52 render : function(){
71 } else {
53 this.$el
72 this.$textbox.removeAttr('disabled');
54 .html('')
73 }
55 .addClass(this.model.comm.comm_id);
74 },
56 this.$textbox = $('<input type="text" />')
75
57 .addClass('input')
76
58 .appendTo(this.$el);
77 events: {"keyup input" : "handleChanging",
59 this.update(); // Set defaults.
78 "paste input" : "handleChanging",
60 },
79 "cut input" : "handleChanging",
80 "change input" : "handleChanged"}, // Fires only when control is validated or looses focus.
81
82 // Handles and validates user input.
83 handleChanging: function(e) {
84
61
85 // Try to parse value as a float.
62 // Handles: Backend -> Frontend Sync
86 var numericalValue = 0;
63 // Frontent -> Frontend Sync
87 if (e.target.value != '') {
64 update : function(){
88 numericalValue = parseInt(e.target.value);
65 var value = this.model.get('value');
89 }
66 if (!this.changing && parseInt(this.$textbox.val()) != value) {
67 this.$textbox.val(value);
68 }
69
70 if (this.model.get('disabled')) {
71 this.$textbox.attr('disabled','disabled');
72 } else {
73 this.$textbox.removeAttr('disabled');
74 }
75 },
76
77
78 events: {"keyup input" : "handleChanging",
79 "paste input" : "handleChanging",
80 "cut input" : "handleChanging",
81 "change input" : "handleChanged"}, // Fires only when control is validated or looses focus.
90
82
91 // If parse failed, reset value to value stored in model.
83 // Handles and validates user input.
92 if (isNaN(numericalValue)) {
84 handleChanging: function(e) {
93 e.target.value = this.model.get('value');
94 } else if (!isNaN(numericalValue)) {
95 numericalValue = Math.min(this.model.get('max'), numericalValue);
96 numericalValue = Math.max(this.model.get('min'), numericalValue);
97
85
98 // Apply the value if it has changed.
86 // Try to parse value as a float.
99 if (numericalValue != this.model.get('value')) {
87 var numericalValue = 0;
100 this.changing = true;
88 if (e.target.value != '') {
101 this.model.set('value', numericalValue);
89 numericalValue = parseInt(e.target.value);
102 this.model.apply(this);
90 }
103 this.changing = false;
91
92 // If parse failed, reset value to value stored in model.
93 if (isNaN(numericalValue)) {
94 e.target.value = this.model.get('value');
95 } else if (!isNaN(numericalValue)) {
96 if (this.model.get('max') != undefined) {
97 numericalValue = Math.min(this.model.get('max'), numericalValue);
98 }
99 if (this.model.get('min') != undefined) {
100 numericalValue = Math.max(this.model.get('min'), numericalValue);
101 }
102
103 // Apply the value if it has changed.
104 if (numericalValue != this.model.get('value')) {
105 this.changing = true;
106 this.model.set('value', numericalValue);
107 this.model.apply(this);
108 this.changing = false;
109 }
110 }
111 },
112
113 // Applies validated input.
114 handleChanged: function(e) {
115 // Update the textbox
116 if (this.model.get('value') != e.target.value) {
117 e.target.value = this.model.get('value');
104 }
118 }
105 }
119 }
106 },
120 });
107
108 // Applies validated input.
109 handleChanged: function(e) {
110 // Update the textbox
111 if (this.model.get('value') != e.target.value) {
112 e.target.value = this.model.get('value');
113 }
114 }
115 });
116
121
117 IPython.notebook.widget_manager.register_widget_view('IntTextView', IntTextView);
122 IPython.notebook.widget_manager.register_widget_view('IntTextView', IntTextView);
123 });
@@ -1,194 +1,196
1 var SelectionWidgetModel = IPython.WidgetModel.extend({});
1 require(["notebook/js/widget"], function(){
2 IPython.notebook.widget_manager.register_widget_model('SelectionWidgetModel', SelectionWidgetModel);
2 var SelectionWidgetModel = IPython.WidgetModel.extend({});
3 IPython.notebook.widget_manager.register_widget_model('SelectionWidgetModel', SelectionWidgetModel);
3
4
4 var DropdownView = IPython.WidgetView.extend({
5 var DropdownView = IPython.WidgetView.extend({
5
6 // Called when view is rendered.
7 render : function(){
8
6
9 this.$el
7 // Called when view is rendered.
10 .html('')
8 render : function(){
11 .addClass(this.model.comm.comm_id);
12 this.$buttongroup = $('<div />')
13 .addClass('btn-group')
14 .appendTo(this.$el);
15 this.$droplabel = $('<button />')
16 .addClass('btn')
17 .appendTo(this.$buttongroup);
18 this.$dropbutton = $('<button />')
19 .addClass('btn')
20 .addClass('dropdown-toggle')
21 .attr('data-toggle', 'dropdown')
22 .html('<span class="caret"></span>')
23 .appendTo(this.$buttongroup);
24 this.$droplist = $('<ul />')
25 .addClass('dropdown-menu')
26 .appendTo(this.$buttongroup);
27
28 // Set defaults.
29 this.update();
30 },
31
32 // Handles: Backend -> Frontend Sync
33 // Frontent -> Frontend Sync
34 update : function(){
35 this.$droplabel.html(this.model.get('value'));
36
37 var items = this.model.get('values');
38 this.$droplist.html('');
39 for (var index in items) {
40 var that = this;
41 var item_button = $('<a href="#"/>')
42 .html(items[index])
43 .on('click', function(e){
44 that.model.set('value', $(e.target).html(), this );
45 })
46
9
47 this.$droplist.append($('<li />').append(item_button))
10 this.$el
48 }
11 .html('')
49
12 .addClass(this.model.comm.comm_id);
50 if (this.model.get('disabled')) {
13 this.$buttongroup = $('<div />')
51 this.$buttongroup.attr('disabled','disabled');
14 .addClass('btn-group')
52 this.$droplabel.attr('disabled','disabled');
15 .appendTo(this.$el);
53 this.$dropbutton.attr('disabled','disabled');
16 this.$droplabel = $('<button />')
54 this.$droplist.attr('disabled','disabled');
17 .addClass('btn')
55 } else {
18 .appendTo(this.$buttongroup);
56 this.$buttongroup.removeAttr('disabled');
19 this.$dropbutton = $('<button />')
57 this.$droplabel.removeAttr('disabled');
20 .addClass('btn')
58 this.$dropbutton.removeAttr('disabled');
21 .addClass('dropdown-toggle')
59 this.$droplist.removeAttr('disabled');
22 .attr('data-toggle', 'dropdown')
60 }
23 .html('<span class="caret"></span>')
61 },
24 .appendTo(this.$buttongroup);
62
25 this.$droplist = $('<ul />')
63 });
26 .addClass('dropdown-menu')
64
27 .appendTo(this.$buttongroup);
65 IPython.notebook.widget_manager.register_widget_view('DropdownView', DropdownView);
28
66
29 // Set defaults.
67 var RadioButtonView = IPython.WidgetView.extend({
30 this.update();
68
31 },
69 // Called when view is rendered.
70 render : function(){
71 this.$el
72 .html('')
73 .addClass(this.model.comm.comm_id);
74 this.update();
75 },
76
77 // Handles: Backend -> Frontend Sync
78 // Frontent -> Frontend Sync
79 update : function(){
80
32
81 // Add missing items to the DOM.
33 // Handles: Backend -> Frontend Sync
82 var items = this.model.get('values');
34 // Frontent -> Frontend Sync
83 for (var index in items) {
35 update : function(){
84 var item_query = ' :input[value="' + items[index] + '"]';
36 this.$droplabel.html(this.model.get('value'));
85 if (this.$el.find(item_query).length == 0) {
37
86 var $label = $('<label />')
38 var items = this.model.get('values');
87 .addClass('radio')
39 this.$droplist.html('');
88 .html(items[index])
40 for (var index in items) {
89 .appendTo(this.$el);
90
91 var that = this;
41 var that = this;
92 $('<input />')
42 var item_button = $('<a href="#"/>')
93 .attr('type', 'radio')
43 .html(items[index])
94 .addClass(this.model)
95 .val(items[index])
96 .prependTo($label)
97 .on('click', function(e){
44 .on('click', function(e){
98 that.model.set('value', $(e.target).val(), this);
45 that.model.set('value', $(e.target).html(), this );
99 that.model.apply();
46 })
100 });
47
48 this.$droplist.append($('<li />').append(item_button))
101 }
49 }
102
50
103 if (this.model.get('value') == items[index]) {
51 if (this.model.get('disabled')) {
104 this.$el.find(item_query).prop('checked', true);
52 this.$buttongroup.attr('disabled','disabled');
53 this.$droplabel.attr('disabled','disabled');
54 this.$dropbutton.attr('disabled','disabled');
55 this.$droplist.attr('disabled','disabled');
105 } else {
56 } else {
106 this.$el.find(item_query).prop('checked', false);
57 this.$buttongroup.removeAttr('disabled');
58 this.$droplabel.removeAttr('disabled');
59 this.$dropbutton.removeAttr('disabled');
60 this.$droplist.removeAttr('disabled');
107 }
61 }
108 }
62 },
63
64 });
65
66 IPython.notebook.widget_manager.register_widget_view('DropdownView', DropdownView);
67
68 var RadioButtonsView = IPython.WidgetView.extend({
69
70 // Called when view is rendered.
71 render : function(){
72 this.$el
73 .html('')
74 .addClass(this.model.comm.comm_id);
75 this.update();
76 },
109
77
110 // Remove items that no longer exist.
78 // Handles: Backend -> Frontend Sync
111 this.$el.find('input').each(function(i, obj) {
79 // Frontent -> Frontend Sync
112 var value = $(obj).val();
80 update : function(){
113 var found = false;
81
82 // Add missing items to the DOM.
83 var items = this.model.get('values');
114 for (var index in items) {
84 for (var index in items) {
115 if (items[index] == value) {
85 var item_query = ' :input[value="' + items[index] + '"]';
116 found = true;
86 if (this.$el.find(item_query).length == 0) {
117 break;
87 var $label = $('<label />')
88 .addClass('radio')
89 .html(items[index])
90 .appendTo(this.$el);
91
92 var that = this;
93 $('<input />')
94 .attr('type', 'radio')
95 .addClass(this.model)
96 .val(items[index])
97 .prependTo($label)
98 .on('click', function(e){
99 that.model.set('value', $(e.target).val(), this);
100 that.model.apply();
101 });
102 }
103
104 if (this.model.get('value') == items[index]) {
105 this.$el.find(item_query).prop('checked', true);
106 } else {
107 this.$el.find(item_query).prop('checked', false);
118 }
108 }
119 }
109 }
120
110
121 if (!found) {
111 // Remove items that no longer exist.
122 $(obj).parent().remove();
112 this.$el.find('input').each(function(i, obj) {
123 }
113 var value = $(obj).val();
124 });
114 var found = false;
125 },
115 for (var index in items) {
126
116 if (items[index] == value) {
127 });
117 found = true;
118 break;
119 }
120 }
121
122 if (!found) {
123 $(obj).parent().remove();
124 }
125 });
126 },
127
128 });
128
129
129 IPython.notebook.widget_manager.register_widget_view('RadioButtonView', RadioButtonView);
130 IPython.notebook.widget_manager.register_widget_view('RadioButtonsView', RadioButtonsView);
130
131
131
132
132 var ToggleButtonView = IPython.WidgetView.extend({
133 var ToggleButtonsView = IPython.WidgetView.extend({
133
134 // Called when view is rendered.
135 render : function(){
136 this.$el
137 .html('')
138 .addClass(this.model.comm.comm_id);
139 this.$buttongroup = $('<div />')
140 .addClass('btn-group')
141 .attr('data-toggle', 'buttons-radio')
142 .appendTo(this.$el);
143 this.update();
144 },
145
146 // Handles: Backend -> Frontend Sync
147 // Frontent -> Frontend Sync
148 update : function(){
149
134
150 // Add missing items to the DOM.
135 // Called when view is rendered.
151 var items = this.model.get('values');
136 render : function(){
152 for (var index in items) {
137 this.$el
153 var item_query = ' :contains("' + items[index] + '")';
138 .html('')
154 if (this.$buttongroup.find(item_query).length == 0) {
139 .addClass(this.model.comm.comm_id);
155
140 this.$buttongroup = $('<div />')
156 var that = this;
141 .addClass('btn-group')
157 $('<button />')
142 .attr('data-toggle', 'buttons-radio')
158 .attr('type', 'button')
143 .appendTo(this.$el);
159 .addClass('btn')
144 this.update();
160 .html(items[index])
145 },
161 .appendTo(this.$buttongroup)
162 .on('click', function(e){
163 that.model.set('value', $(e.target).html(), this);
164 that.model.apply();
165 });
166 }
167
168 if (this.model.get('value') == items[index]) {
169 this.$buttongroup.find(item_query).addClass('active');
170 } else {
171 this.$buttongroup.find(item_query).removeClass('active');
172 }
173 }
174
146
175 // Remove items that no longer exist.
147 // Handles: Backend -> Frontend Sync
176 this.$buttongroup.find('button').each(function(i, obj) {
148 // Frontent -> Frontend Sync
177 var value = $(obj).html();
149 update : function(){
178 var found = false;
150
151 // Add missing items to the DOM.
152 var items = this.model.get('values');
179 for (var index in items) {
153 for (var index in items) {
180 if (items[index] == value) {
154 var item_query = ' :contains("' + items[index] + '")';
181 found = true;
155 if (this.$buttongroup.find(item_query).length == 0) {
182 break;
156
157 var that = this;
158 $('<button />')
159 .attr('type', 'button')
160 .addClass('btn')
161 .html(items[index])
162 .appendTo(this.$buttongroup)
163 .on('click', function(e){
164 that.model.set('value', $(e.target).html(), this);
165 that.model.apply();
166 });
167 }
168
169 if (this.model.get('value') == items[index]) {
170 this.$buttongroup.find(item_query).addClass('active');
171 } else {
172 this.$buttongroup.find(item_query).removeClass('active');
183 }
173 }
184 }
174 }
185
175
186 if (!found) {
176 // Remove items that no longer exist.
187 $(obj).remove();
177 this.$buttongroup.find('button').each(function(i, obj) {
188 }
178 var value = $(obj).html();
189 });
179 var found = false;
190 },
180 for (var index in items) {
191
181 if (items[index] == value) {
192 });
182 found = true;
183 break;
184 }
185 }
186
187 if (!found) {
188 $(obj).remove();
189 }
190 });
191 },
192
193 });
193
194
194 IPython.notebook.widget_manager.register_widget_view('ToggleButtonView', ToggleButtonView);
195 IPython.notebook.widget_manager.register_widget_view('ToggleButtonsView', ToggleButtonsView);
196 });
@@ -1,74 +1,98
1 var StringWidgetModel = IPython.WidgetModel.extend({});
1 require(["notebook/js/widget"], function(){
2 IPython.notebook.widget_manager.register_widget_model('StringWidgetModel', StringWidgetModel);
2 var StringWidgetModel = IPython.WidgetModel.extend({});
3 IPython.notebook.widget_manager.register_widget_model('StringWidgetModel', StringWidgetModel);
3
4
4 var TextareaView = IPython.WidgetView.extend({
5 var LabelView = IPython.WidgetView.extend({
5
6
6 // Called when view is rendered.
7 // Called when view is rendered.
7 render : function(){
8 render : function(){
8 this.$el
9 this.$el
9 .html('')
10 .html('');
10 .addClass(this.model.comm.comm_id);
11 this.$label = $('<div />')
11 this.$textbox = $('<textarea />')
12 .addClass(this.model.comm.comm_id)
12 .attr('rows', 5)
13 .appendTo(this.$el);
13 .appendTo(this.$el);
14 this.update(); // Set defaults.
14 this.update(); // Set defaults.
15 },
15 },
16
16
17 // Handles: Backend -> Frontend Sync
17 // Handles: Backend -> Frontend Sync
18 // Frontent -> Frontend Sync
18 // Frontent -> Frontend Sync
19 update : function(){
19 update : function(){
20 this.$label.html(this.model.get('value'));
20 if (!this.user_invoked_update) {
21 },
21 this.$textbox.val(this.model.get('value'));
22
22 }
23 });
23 },
24
25 events: {"keyup textarea" : "handleChanging",
26 "paste textarea" : "handleChanging",
27 "cut textarea" : "handleChanging"},
28
29 // Handles and validates user input.
30 handleChanging: function(e) {
31 this.user_invoked_update = true;
32 this.model.set('value', e.target.value);
33 this.model.apply(this);
34 this.user_invoked_update = false;
35 },
36 });
37
24
38 IPython.notebook.widget_manager.register_widget_view('TextareaView', TextareaView);
25 IPython.notebook.widget_manager.register_widget_view('LabelView', LabelView);
39
26
40 var TextboxView = IPython.WidgetView.extend({
27 var TextareaView = IPython.WidgetView.extend({
41
28
42 // Called when view is rendered.
29 // Called when view is rendered.
43 render : function(){
30 render : function(){
44 this.$el
31 this.$el
45 .html('')
32 .html('')
46 .addClass(this.model.comm.comm_id);
33 .addClass(this.model.comm.comm_id);
47 this.$textbox = $('<input type="text" />')
34 this.$textbox = $('<textarea />')
48 .addClass('input')
35 .attr('rows', 5)
49 .appendTo(this.$el);
36 .appendTo(this.$el);
50 this.update(); // Set defaults.
37 this.update(); // Set defaults.
51 },
38 },
52
39
53 // Handles: Backend -> Frontend Sync
40 // Handles: Backend -> Frontend Sync
54 // Frontent -> Frontend Sync
41 // Frontent -> Frontend Sync
55 update : function(){
42 update : function(){
56 if (!this.user_invoked_update) {
43 if (!this.user_invoked_update) {
57 this.$textbox.val(this.model.get('value'));
44 this.$textbox.val(this.model.get('value'));
58 }
45 }
59 },
46 },
60
47
61 events: {"keyup input" : "handleChanging",
48 events: {"keyup textarea" : "handleChanging",
62 "paste input" : "handleChanging",
49 "paste textarea" : "handleChanging",
63 "cut input" : "handleChanging"},
50 "cut textarea" : "handleChanging"},
64
51
65 // Handles and validates user input.
52 // Handles and validates user input.
66 handleChanging: function(e) {
53 handleChanging: function(e) {
67 this.user_invoked_update = true;
54 this.user_invoked_update = true;
68 this.model.set('value', e.target.value);
55 this.model.set('value', e.target.value);
69 this.model.apply(this);
56 this.model.apply(this);
70 this.user_invoked_update = false;
57 this.user_invoked_update = false;
71 },
58 },
72 });
59 });
60
61 IPython.notebook.widget_manager.register_widget_view('TextareaView', TextareaView);
73
62
74 IPython.notebook.widget_manager.register_widget_view('TextboxView', TextboxView);
63 var TextboxView = IPython.WidgetView.extend({
64
65 // Called when view is rendered.
66 render : function(){
67 this.$el
68 .html('')
69 .addClass(this.model.comm.comm_id);
70 this.$textbox = $('<input type="text" />')
71 .addClass('input')
72 .appendTo(this.$el);
73 this.update(); // Set defaults.
74 },
75
76 // Handles: Backend -> Frontend Sync
77 // Frontent -> Frontend Sync
78 update : function(){
79 if (!this.user_invoked_update) {
80 this.$textbox.val(this.model.get('value'));
81 }
82 },
83
84 events: {"keyup input" : "handleChanging",
85 "paste input" : "handleChanging",
86 "cut input" : "handleChanging"},
87
88 // Handles and validates user input.
89 handleChanging: function(e) {
90 this.user_invoked_update = true;
91 this.model.set('value', e.target.value);
92 this.model.apply(this);
93 this.user_invoked_update = false;
94 },
95 });
96
97 IPython.notebook.widget_manager.register_widget_view('TextboxView', TextboxView);
98 });
@@ -71,8 +71,6
71 <script src="{{static_url("components/jquery/jquery.min.js") }}" type="text/javascript" charset="utf-8"></script>
71 <script src="{{static_url("components/jquery/jquery.min.js") }}" type="text/javascript" charset="utf-8"></script>
72 <script src="{{static_url("components/jquery-ui/ui/minified/jquery-ui.min.js") }}" type="text/javascript" charset="utf-8"></script>
72 <script src="{{static_url("components/jquery-ui/ui/minified/jquery-ui.min.js") }}" type="text/javascript" charset="utf-8"></script>
73 <script src="{{static_url("components/bootstrap/bootstrap/js/bootstrap.min.js") }}" type="text/javascript" charset="utf-8"></script>
73 <script src="{{static_url("components/bootstrap/bootstrap/js/bootstrap.min.js") }}" type="text/javascript" charset="utf-8"></script>
74 <script src="{{static_url("components/underscore/underscore-min.js") }}" type="text/javascript" charset="utf-8"></script>
75 <script src="{{static_url("components/backbone/backbone-min.js") }}" type="text/javascript" charset="utf-8"></script>
76 <script src="{{static_url("base/js/namespace.js") }}" type="text/javascript" charset="utf-8"></script>
74 <script src="{{static_url("base/js/namespace.js") }}" type="text/javascript" charset="utf-8"></script>
77 <script src="{{static_url("base/js/page.js") }}" type="text/javascript" charset="utf-8"></script>
75 <script src="{{static_url("base/js/page.js") }}" type="text/javascript" charset="utf-8"></script>
78 <script src="{{static_url("auth/js/loginwidget.js") }}" type="text/javascript" charset="utf-8"></script>
76 <script src="{{static_url("auth/js/loginwidget.js") }}" type="text/javascript" charset="utf-8"></script>
General Comments 0
You need to be logged in to leave comments. Login now