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