##// END OF EJS Templates
Updated require references to point to new files
Jonathan Frederic -
Show More
@@ -1,121 +1,121
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2011 The IPython Development Team
2 // Copyright (C) 2011 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 // On document ready
9 // On document ready
10 //============================================================================
10 //============================================================================
11
11
12 // for the time beeing, we have to pass marked as a parameter here,
12 // for the time beeing, we have to pass marked as a parameter here,
13 // as injecting require.js make marked not to put itself in the globals,
13 // as injecting require.js make marked not to put itself in the globals,
14 // which make both this file fail at setting marked configuration, and textcell.js
14 // which make both this file fail at setting marked configuration, and textcell.js
15 // which search marked into global.
15 // which search marked into global.
16 require(['components/marked/lib/marked',
16 require(['components/marked/lib/marked',
17 'notebook/js/widgets/init'],
17 'widgets/js/init'],
18
18
19 function (marked) {
19 function (marked) {
20 "use strict";
20 "use strict";
21
21
22 window.marked = marked;
22 window.marked = marked;
23
23
24 // monkey patch CM to be able to syntax highlight cell magics
24 // monkey patch CM to be able to syntax highlight cell magics
25 // bug reported upstream,
25 // bug reported upstream,
26 // see https://github.com/marijnh/CodeMirror2/issues/670
26 // see https://github.com/marijnh/CodeMirror2/issues/670
27 if(CodeMirror.getMode(1,'text/plain').indent === undefined ){
27 if(CodeMirror.getMode(1,'text/plain').indent === undefined ){
28 console.log('patching CM for undefined indent');
28 console.log('patching CM for undefined indent');
29 CodeMirror.modes.null = function() {
29 CodeMirror.modes.null = function() {
30 return {token: function(stream) {stream.skipToEnd();},indent : function(){return 0;}};
30 return {token: function(stream) {stream.skipToEnd();},indent : function(){return 0;}};
31 };
31 };
32 }
32 }
33
33
34 CodeMirror.patchedGetMode = function(config, mode){
34 CodeMirror.patchedGetMode = function(config, mode){
35 var cmmode = CodeMirror.getMode(config, mode);
35 var cmmode = CodeMirror.getMode(config, mode);
36 if(cmmode.indent === null) {
36 if(cmmode.indent === null) {
37 console.log('patch mode "' , mode, '" on the fly');
37 console.log('patch mode "' , mode, '" on the fly');
38 cmmode.indent = function(){return 0;};
38 cmmode.indent = function(){return 0;};
39 }
39 }
40 return cmmode;
40 return cmmode;
41 };
41 };
42 // end monkey patching CodeMirror
42 // end monkey patching CodeMirror
43
43
44 IPython.mathjaxutils.init();
44 IPython.mathjaxutils.init();
45
45
46 $('#ipython-main-app').addClass('border-box-sizing');
46 $('#ipython-main-app').addClass('border-box-sizing');
47 $('div#notebook_panel').addClass('border-box-sizing');
47 $('div#notebook_panel').addClass('border-box-sizing');
48
48
49 var opts = {
49 var opts = {
50 base_url : IPython.utils.get_body_data("baseUrl"),
50 base_url : IPython.utils.get_body_data("baseUrl"),
51 notebook_path : IPython.utils.get_body_data("notebookPath"),
51 notebook_path : IPython.utils.get_body_data("notebookPath"),
52 notebook_name : IPython.utils.get_body_data('notebookName')
52 notebook_name : IPython.utils.get_body_data('notebookName')
53 };
53 };
54
54
55 IPython.page = new IPython.Page();
55 IPython.page = new IPython.Page();
56 IPython.layout_manager = new IPython.LayoutManager();
56 IPython.layout_manager = new IPython.LayoutManager();
57 IPython.pager = new IPython.Pager('div#pager', 'div#pager_splitter');
57 IPython.pager = new IPython.Pager('div#pager', 'div#pager_splitter');
58 IPython.quick_help = new IPython.QuickHelp();
58 IPython.quick_help = new IPython.QuickHelp();
59 IPython.login_widget = new IPython.LoginWidget('span#login_widget', opts);
59 IPython.login_widget = new IPython.LoginWidget('span#login_widget', opts);
60 IPython.notebook = new IPython.Notebook('div#notebook', opts);
60 IPython.notebook = new IPython.Notebook('div#notebook', opts);
61 IPython.keyboard_manager = new IPython.KeyboardManager();
61 IPython.keyboard_manager = new IPython.KeyboardManager();
62 IPython.save_widget = new IPython.SaveWidget('span#save_widget');
62 IPython.save_widget = new IPython.SaveWidget('span#save_widget');
63 IPython.menubar = new IPython.MenuBar('#menubar', opts);
63 IPython.menubar = new IPython.MenuBar('#menubar', opts);
64 IPython.toolbar = new IPython.MainToolBar('#maintoolbar-container');
64 IPython.toolbar = new IPython.MainToolBar('#maintoolbar-container');
65 IPython.tooltip = new IPython.Tooltip();
65 IPython.tooltip = new IPython.Tooltip();
66 IPython.notification_area = new IPython.NotificationArea('#notification_area');
66 IPython.notification_area = new IPython.NotificationArea('#notification_area');
67 IPython.notification_area.init_notification_widgets();
67 IPython.notification_area.init_notification_widgets();
68
68
69 IPython.layout_manager.do_resize();
69 IPython.layout_manager.do_resize();
70
70
71 $('body').append('<div id="fonttest"><pre><span id="test1">x</span>'+
71 $('body').append('<div id="fonttest"><pre><span id="test1">x</span>'+
72 '<span id="test2" style="font-weight: bold;">x</span>'+
72 '<span id="test2" style="font-weight: bold;">x</span>'+
73 '<span id="test3" style="font-style: italic;">x</span></pre></div>');
73 '<span id="test3" style="font-style: italic;">x</span></pre></div>');
74 var nh = $('#test1').innerHeight();
74 var nh = $('#test1').innerHeight();
75 var bh = $('#test2').innerHeight();
75 var bh = $('#test2').innerHeight();
76 var ih = $('#test3').innerHeight();
76 var ih = $('#test3').innerHeight();
77 if(nh != bh || nh != ih) {
77 if(nh != bh || nh != ih) {
78 $('head').append('<style>.CodeMirror span { vertical-align: bottom; }</style>');
78 $('head').append('<style>.CodeMirror span { vertical-align: bottom; }</style>');
79 }
79 }
80 $('#fonttest').remove();
80 $('#fonttest').remove();
81
81
82 IPython.page.show();
82 IPython.page.show();
83
83
84 IPython.layout_manager.do_resize();
84 IPython.layout_manager.do_resize();
85 var first_load = function () {
85 var first_load = function () {
86 IPython.layout_manager.do_resize();
86 IPython.layout_manager.do_resize();
87 var hash = document.location.hash;
87 var hash = document.location.hash;
88 if (hash) {
88 if (hash) {
89 document.location.hash = '';
89 document.location.hash = '';
90 document.location.hash = hash;
90 document.location.hash = hash;
91 }
91 }
92 IPython.notebook.set_autosave_interval(IPython.notebook.minimum_autosave_interval);
92 IPython.notebook.set_autosave_interval(IPython.notebook.minimum_autosave_interval);
93 // only do this once
93 // only do this once
94 $([IPython.events]).off('notebook_loaded.Notebook', first_load);
94 $([IPython.events]).off('notebook_loaded.Notebook', first_load);
95 };
95 };
96
96
97 $([IPython.events]).on('notebook_loaded.Notebook', first_load);
97 $([IPython.events]).on('notebook_loaded.Notebook', first_load);
98 $([IPython.events]).trigger('app_initialized.NotebookApp');
98 $([IPython.events]).trigger('app_initialized.NotebookApp');
99 IPython.notebook.load_notebook(opts.notebook_name, opts.notebook_path);
99 IPython.notebook.load_notebook(opts.notebook_name, opts.notebook_path);
100
100
101 if (marked) {
101 if (marked) {
102 marked.setOptions({
102 marked.setOptions({
103 gfm : true,
103 gfm : true,
104 tables: true,
104 tables: true,
105 langPrefix: "language-",
105 langPrefix: "language-",
106 highlight: function(code, lang) {
106 highlight: function(code, lang) {
107 if (!lang) {
107 if (!lang) {
108 // no language, no highlight
108 // no language, no highlight
109 return code;
109 return code;
110 }
110 }
111 var highlighted;
111 var highlighted;
112 try {
112 try {
113 highlighted = hljs.highlight(lang, code, false);
113 highlighted = hljs.highlight(lang, code, false);
114 } catch(err) {
114 } catch(err) {
115 highlighted = hljs.highlightAuto(code);
115 highlighted = hljs.highlightAuto(code);
116 }
116 }
117 return highlighted.value;
117 return highlighted.value;
118 }
118 }
119 });
119 });
120 }
120 }
121 });
121 });
@@ -1,22 +1,22
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 // Basic Widgets
9 // Basic Widgets
10 //============================================================================
10 //============================================================================
11
11
12 define([
12 define([
13 "notebook/js/widgets/widget_bool",
13 "widgets/js/widget_bool",
14 "notebook/js/widgets/widget_button",
14 "widgets/js/widget_button",
15 "notebook/js/widgets/widget_container",
15 "widgets/js/widget_container",
16 "notebook/js/widgets/widget_float",
16 "widgets/js/widget_float",
17 "notebook/js/widgets/widget_image",
17 "widgets/js/widget_image",
18 "notebook/js/widgets/widget_int",
18 "widgets/js/widget_int",
19 "notebook/js/widgets/widget_selection",
19 "widgets/js/widget_selection",
20 "notebook/js/widgets/widget_selectioncontainer",
20 "widgets/js/widget_selectioncontainer",
21 "notebook/js/widgets/widget_string",
21 "widgets/js/widget_string",
22 ], function(){ return true; });
22 ], function(){ return true; });
@@ -1,450 +1,450
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 // Base Widget Model and View classes
9 // Base Widget Model and View classes
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/widgetmanager",
17 define(["widgets/js/manager",
18 "underscore",
18 "underscore",
19 "backbone"],
19 "backbone"],
20 function(WidgetManager, _, Backbone){
20 function(WidgetManager, _, Backbone){
21
21
22 var WidgetModel = Backbone.Model.extend({
22 var WidgetModel = Backbone.Model.extend({
23 constructor: function (widget_manager, model_id, comm) {
23 constructor: function (widget_manager, model_id, comm) {
24 // Constructor
24 // Constructor
25 //
25 //
26 // Creates a WidgetModel instance.
26 // Creates a WidgetModel instance.
27 //
27 //
28 // Parameters
28 // Parameters
29 // ----------
29 // ----------
30 // widget_manager : WidgetManager instance
30 // widget_manager : WidgetManager instance
31 // model_id : string
31 // model_id : string
32 // An ID unique to this model.
32 // An ID unique to this model.
33 // comm : Comm instance (optional)
33 // comm : Comm instance (optional)
34 this.widget_manager = widget_manager;
34 this.widget_manager = widget_manager;
35 this._buffered_state_diff = {};
35 this._buffered_state_diff = {};
36 this.pending_msgs = 0;
36 this.pending_msgs = 0;
37 this.msg_buffer = null;
37 this.msg_buffer = null;
38 this.key_value_lock = null;
38 this.key_value_lock = null;
39 this.id = model_id;
39 this.id = model_id;
40 this.views = [];
40 this.views = [];
41
41
42 if (comm !== undefined) {
42 if (comm !== undefined) {
43 // Remember comm associated with the model.
43 // Remember comm associated with the model.
44 this.comm = comm;
44 this.comm = comm;
45 comm.model = this;
45 comm.model = this;
46
46
47 // Hook comm messages up to model.
47 // Hook comm messages up to model.
48 comm.on_close($.proxy(this._handle_comm_closed, this));
48 comm.on_close($.proxy(this._handle_comm_closed, this));
49 comm.on_msg($.proxy(this._handle_comm_msg, this));
49 comm.on_msg($.proxy(this._handle_comm_msg, this));
50 }
50 }
51 return Backbone.Model.apply(this);
51 return Backbone.Model.apply(this);
52 },
52 },
53
53
54 send: function (content, callbacks) {
54 send: function (content, callbacks) {
55 // Send a custom msg over the comm.
55 // Send a custom msg over the comm.
56 if (this.comm !== undefined) {
56 if (this.comm !== undefined) {
57 var data = {method: 'custom', content: content};
57 var data = {method: 'custom', content: content};
58 this.comm.send(data, callbacks);
58 this.comm.send(data, callbacks);
59 this.pending_msgs++;
59 this.pending_msgs++;
60 }
60 }
61 },
61 },
62
62
63 _handle_comm_closed: function (msg) {
63 _handle_comm_closed: function (msg) {
64 // Handle when a widget is closed.
64 // Handle when a widget is closed.
65 this.trigger('comm:close');
65 this.trigger('comm:close');
66 delete this.comm.model; // Delete ref so GC will collect widget model.
66 delete this.comm.model; // Delete ref so GC will collect widget model.
67 delete this.comm;
67 delete this.comm;
68 delete this.model_id; // Delete id from model so widget manager cleans up.
68 delete this.model_id; // Delete id from model so widget manager cleans up.
69 _.each(this.views, function(view, i) {
69 _.each(this.views, function(view, i) {
70 view.remove();
70 view.remove();
71 });
71 });
72 },
72 },
73
73
74 _handle_comm_msg: function (msg) {
74 _handle_comm_msg: function (msg) {
75 // Handle incoming comm msg.
75 // Handle incoming comm msg.
76 var method = msg.content.data.method;
76 var method = msg.content.data.method;
77 switch (method) {
77 switch (method) {
78 case 'update':
78 case 'update':
79 this.apply_update(msg.content.data.state);
79 this.apply_update(msg.content.data.state);
80 break;
80 break;
81 case 'custom':
81 case 'custom':
82 this.trigger('msg:custom', msg.content.data.content);
82 this.trigger('msg:custom', msg.content.data.content);
83 break;
83 break;
84 case 'display':
84 case 'display':
85 this.widget_manager.display_view(msg, this);
85 this.widget_manager.display_view(msg, this);
86 break;
86 break;
87 }
87 }
88 },
88 },
89
89
90 apply_update: function (state) {
90 apply_update: function (state) {
91 // Handle when a widget is updated via the python side.
91 // Handle when a widget is updated via the python side.
92 var that = this;
92 var that = this;
93 _.each(state, function(value, key) {
93 _.each(state, function(value, key) {
94 that.key_value_lock = [key, value];
94 that.key_value_lock = [key, value];
95 try {
95 try {
96 WidgetModel.__super__.set.apply(that, [key, that._unpack_models(value)]);
96 WidgetModel.__super__.set.apply(that, [key, that._unpack_models(value)]);
97 } finally {
97 } finally {
98 that.key_value_lock = null;
98 that.key_value_lock = null;
99 }
99 }
100 });
100 });
101 },
101 },
102
102
103 _handle_status: function (msg, callbacks) {
103 _handle_status: function (msg, callbacks) {
104 // Handle status msgs.
104 // Handle status msgs.
105
105
106 // execution_state : ('busy', 'idle', 'starting')
106 // execution_state : ('busy', 'idle', 'starting')
107 if (this.comm !== undefined) {
107 if (this.comm !== undefined) {
108 if (msg.content.execution_state ==='idle') {
108 if (msg.content.execution_state ==='idle') {
109 // Send buffer if this message caused another message to be
109 // Send buffer if this message caused another message to be
110 // throttled.
110 // throttled.
111 if (this.msg_buffer !== null &&
111 if (this.msg_buffer !== null &&
112 (this.get('msg_throttle') || 3) === this.pending_msgs) {
112 (this.get('msg_throttle') || 3) === this.pending_msgs) {
113 var data = {method: 'backbone', sync_method: 'update', sync_data: this.msg_buffer};
113 var data = {method: 'backbone', sync_method: 'update', sync_data: this.msg_buffer};
114 this.comm.send(data, callbacks);
114 this.comm.send(data, callbacks);
115 this.msg_buffer = null;
115 this.msg_buffer = null;
116 } else {
116 } else {
117 --this.pending_msgs;
117 --this.pending_msgs;
118 }
118 }
119 }
119 }
120 }
120 }
121 },
121 },
122
122
123 callbacks: function(view) {
123 callbacks: function(view) {
124 // Create msg callbacks for a comm msg.
124 // Create msg callbacks for a comm msg.
125 var callbacks = this.widget_manager.callbacks(view);
125 var callbacks = this.widget_manager.callbacks(view);
126
126
127 if (callbacks.iopub === undefined) {
127 if (callbacks.iopub === undefined) {
128 callbacks.iopub = {};
128 callbacks.iopub = {};
129 }
129 }
130
130
131 var that = this;
131 var that = this;
132 callbacks.iopub.status = function (msg) {
132 callbacks.iopub.status = function (msg) {
133 that._handle_status(msg, callbacks);
133 that._handle_status(msg, callbacks);
134 };
134 };
135 return callbacks;
135 return callbacks;
136 },
136 },
137
137
138 set: function(key, val, options) {
138 set: function(key, val, options) {
139 // Set a value.
139 // Set a value.
140 var return_value = WidgetModel.__super__.set.apply(this, arguments);
140 var return_value = WidgetModel.__super__.set.apply(this, arguments);
141
141
142 // Backbone only remembers the diff of the most recent set()
142 // Backbone only remembers the diff of the most recent set()
143 // operation. Calling set multiple times in a row results in a
143 // operation. Calling set multiple times in a row results in a
144 // loss of diff information. Here we keep our own running diff.
144 // loss of diff information. Here we keep our own running diff.
145 this._buffered_state_diff = $.extend(this._buffered_state_diff, this.changedAttributes() || {});
145 this._buffered_state_diff = $.extend(this._buffered_state_diff, this.changedAttributes() || {});
146 return return_value;
146 return return_value;
147 },
147 },
148
148
149 sync: function (method, model, options) {
149 sync: function (method, model, options) {
150 // Handle sync to the back-end. Called when a model.save() is called.
150 // Handle sync to the back-end. Called when a model.save() is called.
151
151
152 // Make sure a comm exists.
152 // Make sure a comm exists.
153 var error = options.error || function() {
153 var error = options.error || function() {
154 console.error('Backbone sync error:', arguments);
154 console.error('Backbone sync error:', arguments);
155 };
155 };
156 if (this.comm === undefined) {
156 if (this.comm === undefined) {
157 error();
157 error();
158 return false;
158 return false;
159 }
159 }
160
160
161 // Delete any key value pairs that the back-end already knows about.
161 // Delete any key value pairs that the back-end already knows about.
162 var attrs = (method === 'patch') ? options.attrs : model.toJSON(options);
162 var attrs = (method === 'patch') ? options.attrs : model.toJSON(options);
163 if (this.key_value_lock !== null) {
163 if (this.key_value_lock !== null) {
164 var key = this.key_value_lock[0];
164 var key = this.key_value_lock[0];
165 var value = this.key_value_lock[1];
165 var value = this.key_value_lock[1];
166 if (attrs[key] === value) {
166 if (attrs[key] === value) {
167 delete attrs[key];
167 delete attrs[key];
168 }
168 }
169 }
169 }
170
170
171 // Only sync if there are attributes to send to the back-end.
171 // Only sync if there are attributes to send to the back-end.
172 attrs = this._pack_models(attrs);
172 attrs = this._pack_models(attrs);
173 if (_.size(attrs) > 0) {
173 if (_.size(attrs) > 0) {
174
174
175 // If this message was sent via backbone itself, it will not
175 // If this message was sent via backbone itself, it will not
176 // have any callbacks. It's important that we create callbacks
176 // have any callbacks. It's important that we create callbacks
177 // so we can listen for status messages, etc...
177 // so we can listen for status messages, etc...
178 var callbacks = options.callbacks || this.callbacks();
178 var callbacks = options.callbacks || this.callbacks();
179
179
180 // Check throttle.
180 // Check throttle.
181 if (this.pending_msgs >= (this.get('msg_throttle') || 3)) {
181 if (this.pending_msgs >= (this.get('msg_throttle') || 3)) {
182 // The throttle has been exceeded, buffer the current msg so
182 // The throttle has been exceeded, buffer the current msg so
183 // it can be sent once the kernel has finished processing
183 // it can be sent once the kernel has finished processing
184 // some of the existing messages.
184 // some of the existing messages.
185
185
186 // Combine updates if it is a 'patch' sync, otherwise replace updates
186 // Combine updates if it is a 'patch' sync, otherwise replace updates
187 switch (method) {
187 switch (method) {
188 case 'patch':
188 case 'patch':
189 this.msg_buffer = $.extend(this.msg_buffer || {}, attrs);
189 this.msg_buffer = $.extend(this.msg_buffer || {}, attrs);
190 break;
190 break;
191 case 'update':
191 case 'update':
192 case 'create':
192 case 'create':
193 this.msg_buffer = attrs;
193 this.msg_buffer = attrs;
194 break;
194 break;
195 default:
195 default:
196 error();
196 error();
197 return false;
197 return false;
198 }
198 }
199 this.msg_buffer_callbacks = callbacks;
199 this.msg_buffer_callbacks = callbacks;
200
200
201 } else {
201 } else {
202 // We haven't exceeded the throttle, send the message like
202 // We haven't exceeded the throttle, send the message like
203 // normal.
203 // normal.
204 var data = {method: 'backbone', sync_data: attrs};
204 var data = {method: 'backbone', sync_data: attrs};
205 this.comm.send(data, callbacks);
205 this.comm.send(data, callbacks);
206 this.pending_msgs++;
206 this.pending_msgs++;
207 }
207 }
208 }
208 }
209 // Since the comm is a one-way communication, assume the message
209 // Since the comm is a one-way communication, assume the message
210 // arrived. Don't call success since we don't have a model back from the server
210 // arrived. Don't call success since we don't have a model back from the server
211 // this means we miss out on the 'sync' event.
211 // this means we miss out on the 'sync' event.
212 this._buffered_state_diff = {};
212 this._buffered_state_diff = {};
213 },
213 },
214
214
215 save_changes: function(callbacks) {
215 save_changes: function(callbacks) {
216 // Push this model's state to the back-end
216 // Push this model's state to the back-end
217 //
217 //
218 // This invokes a Backbone.Sync.
218 // This invokes a Backbone.Sync.
219 this.save(this._buffered_state_diff, {patch: true, callbacks: callbacks});
219 this.save(this._buffered_state_diff, {patch: true, callbacks: callbacks});
220 },
220 },
221
221
222 _pack_models: function(value) {
222 _pack_models: function(value) {
223 // Replace models with model ids recursively.
223 // Replace models with model ids recursively.
224 if (value instanceof Backbone.Model) {
224 if (value instanceof Backbone.Model) {
225 return value.id;
225 return value.id;
226
226
227 } else if ($.isArray(value)) {
227 } else if ($.isArray(value)) {
228 var packed = [];
228 var packed = [];
229 var that = this;
229 var that = this;
230 _.each(value, function(sub_value, key) {
230 _.each(value, function(sub_value, key) {
231 packed.push(that._pack_models(sub_value));
231 packed.push(that._pack_models(sub_value));
232 });
232 });
233 return packed;
233 return packed;
234
234
235 } else if (value instanceof Object) {
235 } else if (value instanceof Object) {
236 var packed = {};
236 var packed = {};
237 var that = this;
237 var that = this;
238 _.each(value, function(sub_value, key) {
238 _.each(value, function(sub_value, key) {
239 packed[key] = that._pack_models(sub_value);
239 packed[key] = that._pack_models(sub_value);
240 });
240 });
241 return packed;
241 return packed;
242
242
243 } else {
243 } else {
244 return value;
244 return value;
245 }
245 }
246 },
246 },
247
247
248 _unpack_models: function(value) {
248 _unpack_models: function(value) {
249 // Replace model ids with models recursively.
249 // Replace model ids with models recursively.
250 if ($.isArray(value)) {
250 if ($.isArray(value)) {
251 var unpacked = [];
251 var unpacked = [];
252 var that = this;
252 var that = this;
253 _.each(value, function(sub_value, key) {
253 _.each(value, function(sub_value, key) {
254 unpacked.push(that._unpack_models(sub_value));
254 unpacked.push(that._unpack_models(sub_value));
255 });
255 });
256 return unpacked;
256 return unpacked;
257
257
258 } else if (value instanceof Object) {
258 } else if (value instanceof Object) {
259 var unpacked = {};
259 var unpacked = {};
260 var that = this;
260 var that = this;
261 _.each(value, function(sub_value, key) {
261 _.each(value, function(sub_value, key) {
262 unpacked[key] = that._unpack_models(sub_value);
262 unpacked[key] = that._unpack_models(sub_value);
263 });
263 });
264 return unpacked;
264 return unpacked;
265
265
266 } else {
266 } else {
267 var model = this.widget_manager.get_model(value);
267 var model = this.widget_manager.get_model(value);
268 if (model) {
268 if (model) {
269 return model;
269 return model;
270 } else {
270 } else {
271 return value;
271 return value;
272 }
272 }
273 }
273 }
274 },
274 },
275
275
276 });
276 });
277 WidgetManager.register_widget_model('WidgetModel', WidgetModel);
277 WidgetManager.register_widget_model('WidgetModel', WidgetModel);
278
278
279
279
280 var WidgetView = Backbone.View.extend({
280 var WidgetView = Backbone.View.extend({
281 initialize: function(parameters) {
281 initialize: function(parameters) {
282 // Public constructor.
282 // Public constructor.
283 this.model.on('change',this.update,this);
283 this.model.on('change',this.update,this);
284 this.options = parameters.options;
284 this.options = parameters.options;
285 this.child_views = [];
285 this.child_views = [];
286 this.model.views.push(this);
286 this.model.views.push(this);
287 },
287 },
288
288
289 update: function(){
289 update: function(){
290 // Triggered on model change.
290 // Triggered on model change.
291 //
291 //
292 // Update view to be consistent with this.model
292 // Update view to be consistent with this.model
293 },
293 },
294
294
295 create_child_view: function(child_model, options) {
295 create_child_view: function(child_model, options) {
296 // Create and return a child view.
296 // Create and return a child view.
297 //
297 //
298 // -given a model and (optionally) a view name if the view name is
298 // -given a model and (optionally) a view name if the view name is
299 // not given, it defaults to the model's default view attribute.
299 // not given, it defaults to the model's default view attribute.
300
300
301 // TODO: this is hacky, and makes the view depend on this cell attribute and widget manager behavior
301 // TODO: this is hacky, and makes the view depend on this cell attribute and widget manager behavior
302 // it would be great to have the widget manager add the cell metadata
302 // it would be great to have the widget manager add the cell metadata
303 // to the subview without having to add it here.
303 // to the subview without having to add it here.
304 var child_view = this.model.widget_manager.create_view(child_model, options || {}, this);
304 var child_view = this.model.widget_manager.create_view(child_model, options || {}, this);
305 this.child_views[child_model.id] = child_view;
305 this.child_views[child_model.id] = child_view;
306 return child_view;
306 return child_view;
307 },
307 },
308
308
309 delete_child_view: function(child_model, options) {
309 delete_child_view: function(child_model, options) {
310 // Delete a child view that was previously created using create_child_view.
310 // Delete a child view that was previously created using create_child_view.
311 var view = this.child_views[child_model.id];
311 var view = this.child_views[child_model.id];
312 if (view !== undefined) {
312 if (view !== undefined) {
313 delete this.child_views[child_model.id];
313 delete this.child_views[child_model.id];
314 view.remove();
314 view.remove();
315 }
315 }
316 },
316 },
317
317
318 do_diff: function(old_list, new_list, removed_callback, added_callback) {
318 do_diff: function(old_list, new_list, removed_callback, added_callback) {
319 // Difference a changed list and call remove and add callbacks for
319 // Difference a changed list and call remove and add callbacks for
320 // each removed and added item in the new list.
320 // each removed and added item in the new list.
321 //
321 //
322 // Parameters
322 // Parameters
323 // ----------
323 // ----------
324 // old_list : array
324 // old_list : array
325 // new_list : array
325 // new_list : array
326 // removed_callback : Callback(item)
326 // removed_callback : Callback(item)
327 // Callback that is called for each item removed.
327 // Callback that is called for each item removed.
328 // added_callback : Callback(item)
328 // added_callback : Callback(item)
329 // Callback that is called for each item added.
329 // Callback that is called for each item added.
330
330
331
331
332 // removed items
332 // removed items
333 _.each(_.difference(old_list, new_list), function(item, index, list) {
333 _.each(_.difference(old_list, new_list), function(item, index, list) {
334 removed_callback(item);
334 removed_callback(item);
335 }, this);
335 }, this);
336
336
337 // added items
337 // added items
338 _.each(_.difference(new_list, old_list), function(item, index, list) {
338 _.each(_.difference(new_list, old_list), function(item, index, list) {
339 added_callback(item);
339 added_callback(item);
340 }, this);
340 }, this);
341 },
341 },
342
342
343 callbacks: function(){
343 callbacks: function(){
344 // Create msg callbacks for a comm msg.
344 // Create msg callbacks for a comm msg.
345 return this.model.callbacks(this);
345 return this.model.callbacks(this);
346 },
346 },
347
347
348 render: function(){
348 render: function(){
349 // Render the view.
349 // Render the view.
350 //
350 //
351 // By default, this is only called the first time the view is created
351 // By default, this is only called the first time the view is created
352 },
352 },
353
353
354 send: function (content) {
354 send: function (content) {
355 // Send a custom msg associated with this view.
355 // Send a custom msg associated with this view.
356 this.model.send(content, this.callbacks());
356 this.model.send(content, this.callbacks());
357 },
357 },
358
358
359 touch: function () {
359 touch: function () {
360 this.model.save_changes(this.callbacks());
360 this.model.save_changes(this.callbacks());
361 },
361 },
362 });
362 });
363
363
364
364
365 var DOMWidgetView = WidgetView.extend({
365 var DOMWidgetView = WidgetView.extend({
366 initialize: function (options) {
366 initialize: function (options) {
367 // Public constructor
367 // Public constructor
368
368
369 // In the future we may want to make changes more granular
369 // In the future we may want to make changes more granular
370 // (e.g., trigger on visible:change).
370 // (e.g., trigger on visible:change).
371 this.model.on('change', this.update, this);
371 this.model.on('change', this.update, this);
372 this.model.on('msg:custom', this.on_msg, this);
372 this.model.on('msg:custom', this.on_msg, this);
373 DOMWidgetView.__super__.initialize.apply(this, arguments);
373 DOMWidgetView.__super__.initialize.apply(this, arguments);
374 },
374 },
375
375
376 on_msg: function(msg) {
376 on_msg: function(msg) {
377 // Handle DOM specific msgs.
377 // Handle DOM specific msgs.
378 switch(msg.msg_type) {
378 switch(msg.msg_type) {
379 case 'add_class':
379 case 'add_class':
380 this.add_class(msg.selector, msg.class_list);
380 this.add_class(msg.selector, msg.class_list);
381 break;
381 break;
382 case 'remove_class':
382 case 'remove_class':
383 this.remove_class(msg.selector, msg.class_list);
383 this.remove_class(msg.selector, msg.class_list);
384 break;
384 break;
385 }
385 }
386 },
386 },
387
387
388 add_class: function (selector, class_list) {
388 add_class: function (selector, class_list) {
389 // Add a DOM class to an element.
389 // Add a DOM class to an element.
390 this._get_selector_element(selector).addClass(class_list);
390 this._get_selector_element(selector).addClass(class_list);
391 },
391 },
392
392
393 remove_class: function (selector, class_list) {
393 remove_class: function (selector, class_list) {
394 // Remove a DOM class from an element.
394 // Remove a DOM class from an element.
395 this._get_selector_element(selector).removeClass(class_list);
395 this._get_selector_element(selector).removeClass(class_list);
396 },
396 },
397
397
398 update: function () {
398 update: function () {
399 // Update the contents of this view
399 // Update the contents of this view
400 //
400 //
401 // Called when the model is changed. The model may have been
401 // Called when the model is changed. The model may have been
402 // changed by another view or by a state update from the back-end.
402 // changed by another view or by a state update from the back-end.
403 // The very first update seems to happen before the element is
403 // The very first update seems to happen before the element is
404 // finished rendering so we use setTimeout to give the element time
404 // finished rendering so we use setTimeout to give the element time
405 // to render
405 // to render
406 var e = this.$el;
406 var e = this.$el;
407 var visible = this.model.get('visible');
407 var visible = this.model.get('visible');
408 setTimeout(function() {e.toggle(visible);},0);
408 setTimeout(function() {e.toggle(visible);},0);
409
409
410 var css = this.model.get('_css');
410 var css = this.model.get('_css');
411 if (css === undefined) {return;}
411 if (css === undefined) {return;}
412 var that = this;
412 var that = this;
413 _.each(css, function(css_traits, selector){
413 _.each(css, function(css_traits, selector){
414 // Apply the css traits to all elements that match the selector.
414 // Apply the css traits to all elements that match the selector.
415 var elements = that._get_selector_element(selector);
415 var elements = that._get_selector_element(selector);
416 if (elements.length > 0) {
416 if (elements.length > 0) {
417 _.each(css_traits, function(css_value, css_key){
417 _.each(css_traits, function(css_value, css_key){
418 elements.css(css_key, css_value);
418 elements.css(css_key, css_value);
419 });
419 });
420 }
420 }
421 });
421 });
422 },
422 },
423
423
424 _get_selector_element: function (selector) {
424 _get_selector_element: function (selector) {
425 // Get the elements via the css selector.
425 // Get the elements via the css selector.
426
426
427 // If the selector is blank, apply the style to the $el_to_style
427 // If the selector is blank, apply the style to the $el_to_style
428 // element. If the $el_to_style element is not defined, use apply
428 // element. If the $el_to_style element is not defined, use apply
429 // the style to the view's element.
429 // the style to the view's element.
430 var elements;
430 var elements;
431 if (!selector) {
431 if (!selector) {
432 if (this.$el_to_style === undefined) {
432 if (this.$el_to_style === undefined) {
433 elements = this.$el;
433 elements = this.$el;
434 } else {
434 } else {
435 elements = this.$el_to_style;
435 elements = this.$el_to_style;
436 }
436 }
437 } else {
437 } else {
438 elements = this.$el.find(selector);
438 elements = this.$el.find(selector);
439 }
439 }
440 return elements;
440 return elements;
441 },
441 },
442 });
442 });
443
443
444 IPython.WidgetModel = WidgetModel;
444 IPython.WidgetModel = WidgetModel;
445 IPython.WidgetView = WidgetView;
445 IPython.WidgetView = WidgetView;
446 IPython.DOMWidgetView = DOMWidgetView;
446 IPython.DOMWidgetView = DOMWidgetView;
447
447
448 // Pass through WidgetManager namespace.
448 // Pass through WidgetManager namespace.
449 return WidgetManager;
449 return WidgetManager;
450 });
450 });
@@ -1,125 +1,125
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(WidgetManager){
17 define(["widgets/js/widget"], function(WidgetManager){
18
18
19 var CheckboxView = IPython.DOMWidgetView.extend({
19 var CheckboxView = IPython.DOMWidgetView.extend({
20 render : function(){
20 render : function(){
21 // Called when view is rendered.
21 // Called when view is rendered.
22 this.$el
22 this.$el
23 .addClass('widget-hbox-single');
23 .addClass('widget-hbox-single');
24 this.$label = $('<div />')
24 this.$label = $('<div />')
25 .addClass('widget-hlabel')
25 .addClass('widget-hlabel')
26 .appendTo(this.$el)
26 .appendTo(this.$el)
27 .hide();
27 .hide();
28 this.$checkbox = $('<input />')
28 this.$checkbox = $('<input />')
29 .attr('type', 'checkbox')
29 .attr('type', 'checkbox')
30 .appendTo(this.$el)
30 .appendTo(this.$el)
31 .click($.proxy(this.handle_click, this));
31 .click($.proxy(this.handle_click, this));
32
32
33 this.$el_to_style = this.$checkbox; // Set default element to style
33 this.$el_to_style = this.$checkbox; // Set default element to style
34 this.update(); // Set defaults.
34 this.update(); // Set defaults.
35 },
35 },
36
36
37 handle_click: function() {
37 handle_click: function() {
38 // Handles when the checkbox is clicked.
38 // Handles when the checkbox is clicked.
39
39
40 // Calling model.set will trigger all of the other views of the
40 // Calling model.set will trigger all of the other views of the
41 // model to update.
41 // model to update.
42 var value = this.model.get('value');
42 var value = this.model.get('value');
43 this.model.set('value', ! value, {updated_view: this});
43 this.model.set('value', ! value, {updated_view: this});
44 this.touch();
44 this.touch();
45 },
45 },
46
46
47 update : function(options){
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 this.$checkbox.prop('checked', this.model.get('value'));
52 this.$checkbox.prop('checked', this.model.get('value'));
53
53
54 if (options === undefined || options.updated_view != this) {
54 if (options === undefined || options.updated_view != this) {
55 var disabled = this.model.get('disabled');
55 var disabled = this.model.get('disabled');
56 this.$checkbox.prop('disabled', disabled);
56 this.$checkbox.prop('disabled', disabled);
57
57
58 var description = this.model.get('description');
58 var description = this.model.get('description');
59 if (description.trim().length === 0) {
59 if (description.trim().length === 0) {
60 this.$label.hide();
60 this.$label.hide();
61 } else {
61 } else {
62 this.$label.text(description);
62 this.$label.text(description);
63 this.$label.show();
63 this.$label.show();
64 }
64 }
65 }
65 }
66 return CheckboxView.__super__.update.apply(this);
66 return CheckboxView.__super__.update.apply(this);
67 },
67 },
68
68
69 });
69 });
70 WidgetManager.register_widget_view('CheckboxView', CheckboxView);
70 WidgetManager.register_widget_view('CheckboxView', CheckboxView);
71
71
72
72
73 var ToggleButtonView = IPython.DOMWidgetView.extend({
73 var ToggleButtonView = IPython.DOMWidgetView.extend({
74 render : function() {
74 render : function() {
75 // Called when view is rendered.
75 // Called when view is rendered.
76 var that = this;
76 var that = this;
77 this.setElement($('<button />')
77 this.setElement($('<button />')
78 .addClass('btn')
78 .addClass('btn')
79 .attr('type', 'button')
79 .attr('type', 'button')
80 .on('click', function (e) {
80 .on('click', function (e) {
81 e.preventDefault();
81 e.preventDefault();
82 that.handle_click();
82 that.handle_click();
83 }));
83 }));
84
84
85 this.update(); // Set defaults.
85 this.update(); // Set defaults.
86 },
86 },
87
87
88 update : function(options){
88 update : function(options){
89 // Update the contents of this view
89 // Update the contents of this view
90 //
90 //
91 // Called when the model is changed. The model may have been
91 // Called when the model is changed. The model may have been
92 // changed by another view or by a state update from the back-end.
92 // changed by another view or by a state update from the back-end.
93 if (this.model.get('value')) {
93 if (this.model.get('value')) {
94 this.$el.addClass('active');
94 this.$el.addClass('active');
95 } else {
95 } else {
96 this.$el.removeClass('active');
96 this.$el.removeClass('active');
97 }
97 }
98
98
99 if (options === undefined || options.updated_view != this) {
99 if (options === undefined || options.updated_view != this) {
100
100
101 var disabled = this.model.get('disabled');
101 var disabled = this.model.get('disabled');
102 this.$el.prop('disabled', disabled);
102 this.$el.prop('disabled', disabled);
103
103
104 var description = this.model.get('description');
104 var description = this.model.get('description');
105 if (description.trim().length === 0) {
105 if (description.trim().length === 0) {
106 this.$el.html("&nbsp;"); // Preserve button height
106 this.$el.html("&nbsp;"); // Preserve button height
107 } else {
107 } else {
108 this.$el.text(description);
108 this.$el.text(description);
109 }
109 }
110 }
110 }
111 return ToggleButtonView.__super__.update.apply(this);
111 return ToggleButtonView.__super__.update.apply(this);
112 },
112 },
113
113
114 handle_click: function(e) {
114 handle_click: function(e) {
115 // Handles and validates user input.
115 // Handles and validates user input.
116
116
117 // 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
118 // model to update.
118 // model to update.
119 var value = this.model.get('value');
119 var value = this.model.get('value');
120 this.model.set('value', ! value, {updated_view: this});
120 this.model.set('value', ! value, {updated_view: this});
121 this.touch();
121 this.touch();
122 },
122 },
123 });
123 });
124 WidgetManager.register_widget_view('ToggleButtonView', ToggleButtonView);
124 WidgetManager.register_widget_view('ToggleButtonView', ToggleButtonView);
125 });
125 });
@@ -1,60 +1,60
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 // ButtonWidget
9 // ButtonWidget
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(WidgetManager){
17 define(["widgets/js/widget"], function(WidgetManager){
18
18
19 var ButtonView = IPython.DOMWidgetView.extend({
19 var ButtonView = IPython.DOMWidgetView.extend({
20 render : function(){
20 render : function(){
21 // Called when view is rendered.
21 // Called when view is rendered.
22 this.setElement($("<button />")
22 this.setElement($("<button />")
23 .addClass('btn'));
23 .addClass('btn'));
24
24
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 var description = this.model.get('description');
33 var description = this.model.get('description');
34 if (description.length === 0) {
34 if (description.length === 0) {
35 this.$el.html("&nbsp;"); // Preserve button height
35 this.$el.html("&nbsp;"); // Preserve button height
36 } else {
36 } else {
37 this.$el.text(description);
37 this.$el.text(description);
38 }
38 }
39
39
40 if (this.model.get('disabled')) {
40 if (this.model.get('disabled')) {
41 this.$el.attr('disabled','disabled');
41 this.$el.attr('disabled','disabled');
42 } else {
42 } else {
43 this.$el.removeAttr('disabled');
43 this.$el.removeAttr('disabled');
44 }
44 }
45
45
46 return ButtonView.__super__.update.apply(this);
46 return ButtonView.__super__.update.apply(this);
47 },
47 },
48
48
49 events: {
49 events: {
50 // Dictionary of events and their handlers.
50 // Dictionary of events and their handlers.
51 'click': '_handle_click',
51 'click': '_handle_click',
52 },
52 },
53
53
54 _handle_click: function(){
54 _handle_click: function(){
55 // Handles when the button is clicked.
55 // Handles when the button is clicked.
56 this.send({event: 'click'});
56 this.send({event: 'click'});
57 },
57 },
58 });
58 });
59 WidgetManager.register_widget_view('ButtonView', ButtonView);
59 WidgetManager.register_widget_view('ButtonView', ButtonView);
60 });
60 });
@@ -1,282 +1,282
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 // ContainerWidget
9 // ContainerWidget
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(WidgetManager) {
17 define(["widgets/js/widget"], function(WidgetManager) {
18
18
19 var ContainerView = IPython.DOMWidgetView.extend({
19 var ContainerView = IPython.DOMWidgetView.extend({
20 render: function(){
20 render: function(){
21 // Called when view is rendered.
21 // Called when view is rendered.
22 this.$el.addClass('widget-container')
22 this.$el.addClass('widget-container')
23 .addClass('vbox');
23 .addClass('vbox');
24 this.children={};
24 this.children={};
25 this.update_children([], this.model.get('_children'));
25 this.update_children([], this.model.get('_children'));
26 this.model.on('change:_children', function(model, value, options) {
26 this.model.on('change:_children', function(model, value, options) {
27 this.update_children(model.previous('_children'), value);
27 this.update_children(model.previous('_children'), value);
28 }, this);
28 }, this);
29 this.update();
29 this.update();
30 },
30 },
31
31
32 update_children: function(old_list, new_list) {
32 update_children: function(old_list, new_list) {
33 // Called when the children list changes.
33 // Called when the children list changes.
34 this.do_diff(old_list,
34 this.do_diff(old_list,
35 new_list,
35 new_list,
36 $.proxy(this.remove_child_model, this),
36 $.proxy(this.remove_child_model, this),
37 $.proxy(this.add_child_model, this));
37 $.proxy(this.add_child_model, this));
38 },
38 },
39
39
40 remove_child_model: function(model) {
40 remove_child_model: function(model) {
41 // Called when a model is removed from the children list.
41 // Called when a model is removed from the children list.
42 this.child_views[model.id].remove();
42 this.child_views[model.id].remove();
43 this.delete_child_view(model);
43 this.delete_child_view(model);
44 },
44 },
45
45
46 add_child_model: function(model) {
46 add_child_model: function(model) {
47 // Called when a model is added to the children list.
47 // Called when a model is added to the children list.
48 var view = this.create_child_view(model);
48 var view = this.create_child_view(model);
49 this.$el.append(view.$el);
49 this.$el.append(view.$el);
50 },
50 },
51
51
52 update: function(){
52 update: function(){
53 // Update the contents of this view
53 // Update the contents of this view
54 //
54 //
55 // Called when the model is changed. The model may have been
55 // Called when the model is changed. The model may have been
56 // changed by another view or by a state update from the back-end.
56 // changed by another view or by a state update from the back-end.
57 return ContainerView.__super__.update.apply(this);
57 return ContainerView.__super__.update.apply(this);
58 },
58 },
59 });
59 });
60
60
61 WidgetManager.register_widget_view('ContainerView', ContainerView);
61 WidgetManager.register_widget_view('ContainerView', ContainerView);
62
62
63 var PopupView = IPython.DOMWidgetView.extend({
63 var PopupView = IPython.DOMWidgetView.extend({
64 render: function(){
64 render: function(){
65 // Called when view is rendered.
65 // Called when view is rendered.
66 var that = this;
66 var that = this;
67 this.children={};
67 this.children={};
68
68
69 this.$el.on("remove", function(){
69 this.$el.on("remove", function(){
70 that.$window.remove();
70 that.$window.remove();
71 });
71 });
72 this.$window = $('<div />')
72 this.$window = $('<div />')
73 .addClass('modal widget-modal')
73 .addClass('modal widget-modal')
74 .appendTo($('#notebook-container'))
74 .appendTo($('#notebook-container'))
75 .mousedown(function(){
75 .mousedown(function(){
76 that.bring_to_front();
76 that.bring_to_front();
77 });
77 });
78
78
79 // Set the elements array since the this.$window element is not child
79 // Set the elements array since the this.$window element is not child
80 // of this.$el and the parent widget manager or other widgets may
80 // of this.$el and the parent widget manager or other widgets may
81 // need to know about all of the top-level widgets. The IPython
81 // need to know about all of the top-level widgets. The IPython
82 // widget manager uses this to register the elements with the
82 // widget manager uses this to register the elements with the
83 // keyboard manager.
83 // keyboard manager.
84 this.additional_elements = [this.$window]
84 this.additional_elements = [this.$window]
85
85
86 this.$title_bar = $('<div />')
86 this.$title_bar = $('<div />')
87 .addClass('popover-title')
87 .addClass('popover-title')
88 .appendTo(this.$window)
88 .appendTo(this.$window)
89 .mousedown(function(){
89 .mousedown(function(){
90 that.bring_to_front();
90 that.bring_to_front();
91 });
91 });
92 this.$close = $('<button />')
92 this.$close = $('<button />')
93 .addClass('close icon-remove')
93 .addClass('close icon-remove')
94 .css('margin-left', '5px')
94 .css('margin-left', '5px')
95 .appendTo(this.$title_bar)
95 .appendTo(this.$title_bar)
96 .click(function(){
96 .click(function(){
97 that.hide();
97 that.hide();
98 event.stopPropagation();
98 event.stopPropagation();
99 });
99 });
100 this.$minimize = $('<button />')
100 this.$minimize = $('<button />')
101 .addClass('close icon-arrow-down')
101 .addClass('close icon-arrow-down')
102 .appendTo(this.$title_bar)
102 .appendTo(this.$title_bar)
103 .click(function(){
103 .click(function(){
104 that.popped_out = !that.popped_out;
104 that.popped_out = !that.popped_out;
105 if (!that.popped_out) {
105 if (!that.popped_out) {
106 that.$minimize
106 that.$minimize
107 .removeClass('icon-arrow-down')
107 .removeClass('icon-arrow-down')
108 .addClass('icon-arrow-up');
108 .addClass('icon-arrow-up');
109
109
110 that.$window
110 that.$window
111 .draggable('destroy')
111 .draggable('destroy')
112 .resizable('destroy')
112 .resizable('destroy')
113 .removeClass('widget-modal modal')
113 .removeClass('widget-modal modal')
114 .addClass('docked-widget-modal')
114 .addClass('docked-widget-modal')
115 .detach()
115 .detach()
116 .insertBefore(that.$show_button);
116 .insertBefore(that.$show_button);
117 that.$show_button.hide();
117 that.$show_button.hide();
118 that.$close.hide();
118 that.$close.hide();
119 } else {
119 } else {
120 that.$minimize
120 that.$minimize
121 .addClass('icon-arrow-down')
121 .addClass('icon-arrow-down')
122 .removeClass('icon-arrow-up');
122 .removeClass('icon-arrow-up');
123
123
124 that.$window
124 that.$window
125 .removeClass('docked-widget-modal')
125 .removeClass('docked-widget-modal')
126 .addClass('widget-modal modal')
126 .addClass('widget-modal modal')
127 .detach()
127 .detach()
128 .appendTo($('#notebook-container'))
128 .appendTo($('#notebook-container'))
129 .draggable({handle: '.popover-title', snap: '#notebook, .modal', snapMode: 'both'})
129 .draggable({handle: '.popover-title', snap: '#notebook, .modal', snapMode: 'both'})
130 .resizable()
130 .resizable()
131 .children('.ui-resizable-handle').show();
131 .children('.ui-resizable-handle').show();
132 that.show();
132 that.show();
133 that.$show_button.show();
133 that.$show_button.show();
134 that.$close.show();
134 that.$close.show();
135 }
135 }
136 event.stopPropagation();
136 event.stopPropagation();
137 });
137 });
138 this.$title = $('<div />')
138 this.$title = $('<div />')
139 .addClass('widget-modal-title')
139 .addClass('widget-modal-title')
140 .html("&nbsp;")
140 .html("&nbsp;")
141 .appendTo(this.$title_bar);
141 .appendTo(this.$title_bar);
142 this.$body = $('<div />')
142 this.$body = $('<div />')
143 .addClass('modal-body')
143 .addClass('modal-body')
144 .addClass('widget-modal-body')
144 .addClass('widget-modal-body')
145 .addClass('widget-container')
145 .addClass('widget-container')
146 .addClass('vbox')
146 .addClass('vbox')
147 .appendTo(this.$window);
147 .appendTo(this.$window);
148
148
149 this.$show_button = $('<button />')
149 this.$show_button = $('<button />')
150 .html("&nbsp;")
150 .html("&nbsp;")
151 .addClass('btn btn-info widget-modal-show')
151 .addClass('btn btn-info widget-modal-show')
152 .appendTo(this.$el)
152 .appendTo(this.$el)
153 .click(function(){
153 .click(function(){
154 that.show();
154 that.show();
155 });
155 });
156
156
157 this.$window.draggable({handle: '.popover-title', snap: '#notebook, .modal', snapMode: 'both'});
157 this.$window.draggable({handle: '.popover-title', snap: '#notebook, .modal', snapMode: 'both'});
158 this.$window.resizable();
158 this.$window.resizable();
159 this.$window.on('resize', function(){
159 this.$window.on('resize', function(){
160 that.$body.outerHeight(that.$window.innerHeight() - that.$title_bar.outerHeight());
160 that.$body.outerHeight(that.$window.innerHeight() - that.$title_bar.outerHeight());
161 });
161 });
162
162
163 this.$el_to_style = this.$body;
163 this.$el_to_style = this.$body;
164 this._shown_once = false;
164 this._shown_once = false;
165 this.popped_out = true;
165 this.popped_out = true;
166
166
167 this.update_children([], this.model.get('_children'));
167 this.update_children([], this.model.get('_children'));
168 this.model.on('change:_children', function(model, value, options) {
168 this.model.on('change:_children', function(model, value, options) {
169 this.update_children(model.previous('_children'), value);
169 this.update_children(model.previous('_children'), value);
170 }, this);
170 }, this);
171 this.update();
171 this.update();
172 },
172 },
173
173
174 hide: function() {
174 hide: function() {
175 // Called when the modal hide button is clicked.
175 // Called when the modal hide button is clicked.
176 this.$window.hide();
176 this.$window.hide();
177 this.$show_button.removeClass('btn-info');
177 this.$show_button.removeClass('btn-info');
178 },
178 },
179
179
180 show: function() {
180 show: function() {
181 // Called when the modal show button is clicked.
181 // Called when the modal show button is clicked.
182 this.$show_button.addClass('btn-info');
182 this.$show_button.addClass('btn-info');
183 this.$window.show();
183 this.$window.show();
184 if (this.popped_out) {
184 if (this.popped_out) {
185 this.$window.css("positon", "absolute");
185 this.$window.css("positon", "absolute");
186 this.$window.css("top", "0px");
186 this.$window.css("top", "0px");
187 this.$window.css("left", Math.max(0, (($('body').outerWidth() - this.$window.outerWidth()) / 2) +
187 this.$window.css("left", Math.max(0, (($('body').outerWidth() - this.$window.outerWidth()) / 2) +
188 $(window).scrollLeft()) + "px");
188 $(window).scrollLeft()) + "px");
189 this.bring_to_front();
189 this.bring_to_front();
190 }
190 }
191 },
191 },
192
192
193 bring_to_front: function() {
193 bring_to_front: function() {
194 // Make the modal top-most, z-ordered about the other modals.
194 // Make the modal top-most, z-ordered about the other modals.
195 var $widget_modals = $(".widget-modal");
195 var $widget_modals = $(".widget-modal");
196 var max_zindex = 0;
196 var max_zindex = 0;
197 $widget_modals.each(function (index, el){
197 $widget_modals.each(function (index, el){
198 max_zindex = Math.max(max_zindex, parseInt($(el).css('z-index')));
198 max_zindex = Math.max(max_zindex, parseInt($(el).css('z-index')));
199 });
199 });
200
200
201 // Start z-index of widget modals at 2000
201 // Start z-index of widget modals at 2000
202 max_zindex = Math.max(max_zindex, 2000);
202 max_zindex = Math.max(max_zindex, 2000);
203
203
204 $widget_modals.each(function (index, el){
204 $widget_modals.each(function (index, el){
205 $el = $(el);
205 $el = $(el);
206 if (max_zindex == parseInt($el.css('z-index'))) {
206 if (max_zindex == parseInt($el.css('z-index'))) {
207 $el.css('z-index', max_zindex - 1);
207 $el.css('z-index', max_zindex - 1);
208 }
208 }
209 });
209 });
210 this.$window.css('z-index', max_zindex);
210 this.$window.css('z-index', max_zindex);
211 },
211 },
212
212
213 update_children: function(old_list, new_list) {
213 update_children: function(old_list, new_list) {
214 // Called when the children list is modified.
214 // Called when the children list is modified.
215 this.do_diff(old_list,
215 this.do_diff(old_list,
216 new_list,
216 new_list,
217 $.proxy(this.remove_child_model, this),
217 $.proxy(this.remove_child_model, this),
218 $.proxy(this.add_child_model, this));
218 $.proxy(this.add_child_model, this));
219 },
219 },
220
220
221 remove_child_model: function(model) {
221 remove_child_model: function(model) {
222 // Called when a child is removed from children list.
222 // Called when a child is removed from children list.
223 this.child_views[model.id].remove();
223 this.child_views[model.id].remove();
224 this.delete_child_view(model);
224 this.delete_child_view(model);
225 },
225 },
226
226
227 add_child_model: function(model) {
227 add_child_model: function(model) {
228 // Called when a child is added to children list.
228 // Called when a child is added to children list.
229 var view = this.create_child_view(model);
229 var view = this.create_child_view(model);
230 this.$body.append(view.$el);
230 this.$body.append(view.$el);
231 },
231 },
232
232
233 update: function(){
233 update: function(){
234 // Update the contents of this view
234 // Update the contents of this view
235 //
235 //
236 // Called when the model is changed. The model may have been
236 // Called when the model is changed. The model may have been
237 // changed by another view or by a state update from the back-end.
237 // changed by another view or by a state update from the back-end.
238 var description = this.model.get('description');
238 var description = this.model.get('description');
239 if (description.trim().length === 0) {
239 if (description.trim().length === 0) {
240 this.$title.html("&nbsp;"); // Preserve title height
240 this.$title.html("&nbsp;"); // Preserve title height
241 } else {
241 } else {
242 this.$title.text(description);
242 this.$title.text(description);
243 }
243 }
244
244
245 var button_text = this.model.get('button_text');
245 var button_text = this.model.get('button_text');
246 if (button_text.trim().length === 0) {
246 if (button_text.trim().length === 0) {
247 this.$show_button.html("&nbsp;"); // Preserve button height
247 this.$show_button.html("&nbsp;"); // Preserve button height
248 } else {
248 } else {
249 this.$show_button.text(button_text);
249 this.$show_button.text(button_text);
250 }
250 }
251
251
252 if (!this._shown_once) {
252 if (!this._shown_once) {
253 this._shown_once = true;
253 this._shown_once = true;
254 this.show();
254 this.show();
255 }
255 }
256
256
257 return PopupView.__super__.update.apply(this);
257 return PopupView.__super__.update.apply(this);
258 },
258 },
259
259
260 _get_selector_element: function(selector) {
260 _get_selector_element: function(selector) {
261 // Get an element view a 'special' jquery selector. (see widget.js)
261 // Get an element view a 'special' jquery selector. (see widget.js)
262 //
262 //
263 // Since the modal actually isn't within the $el in the DOM, we need to extend
263 // Since the modal actually isn't within the $el in the DOM, we need to extend
264 // the selector logic to allow the user to set css on the modal if need be.
264 // the selector logic to allow the user to set css on the modal if need be.
265 // The convention used is:
265 // The convention used is:
266 // "modal" - select the modal div
266 // "modal" - select the modal div
267 // "modal [selector]" - select element(s) within the modal div.
267 // "modal [selector]" - select element(s) within the modal div.
268 // "[selector]" - select elements within $el
268 // "[selector]" - select elements within $el
269 // "" - select the $el_to_style
269 // "" - select the $el_to_style
270 if (selector.substring(0, 5) == 'modal') {
270 if (selector.substring(0, 5) == 'modal') {
271 if (selector == 'modal') {
271 if (selector == 'modal') {
272 return this.$window;
272 return this.$window;
273 } else {
273 } else {
274 return this.$window.find(selector.substring(6));
274 return this.$window.find(selector.substring(6));
275 }
275 }
276 } else {
276 } else {
277 return PopupView.__super__._get_selector_element.apply(this, [selector]);
277 return PopupView.__super__._get_selector_element.apply(this, [selector]);
278 }
278 }
279 },
279 },
280 });
280 });
281 WidgetManager.register_widget_view('PopupView', PopupView);
281 WidgetManager.register_widget_view('PopupView', PopupView);
282 });
282 });
@@ -1,42 +1,42
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 // FloatWidget
9 // FloatWidget
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",
17 define(["widgets/js/widget",
18 "notebook/js/widgets/widget_int"],
18 "widgets/js/widget_int"],
19 function(WidgetManager, int_widgets){
19 function(WidgetManager, int_widgets){
20
20
21 var IntSliderView = int_widgets[0];
21 var IntSliderView = int_widgets[0];
22 var IntTextView = int_widgets[1];
22 var IntTextView = int_widgets[1];
23
23
24
24
25 var FloatSliderView = IntSliderView.extend({
25 var FloatSliderView = IntSliderView.extend({
26 _validate_slide_value: function(x) {
26 _validate_slide_value: function(x) {
27 // Validate the value of the slider before sending it to the back-end
27 // Validate the value of the slider before sending it to the back-end
28 // and applying it to the other views on the page.
28 // and applying it to the other views on the page.
29 return x;
29 return x;
30 },
30 },
31 });
31 });
32 WidgetManager.register_widget_view('FloatSliderView', FloatSliderView);
32 WidgetManager.register_widget_view('FloatSliderView', FloatSliderView);
33
33
34
34
35 var FloatTextView = IntTextView.extend({
35 var FloatTextView = IntTextView.extend({
36 _parse_value: function(value) {
36 _parse_value: function(value) {
37 // Parse the value stored in a string.
37 // Parse the value stored in a string.
38 return parseFloat(value);
38 return parseFloat(value);
39 },
39 },
40 });
40 });
41 WidgetManager.register_widget_view('FloatTextView', FloatTextView);
41 WidgetManager.register_widget_view('FloatTextView', FloatTextView);
42 });
42 });
@@ -1,51 +1,51
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 // ImageWidget
9 // ImageWidget
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(WidgetManager){
17 define(["widgets/js/widget"], function(WidgetManager){
18
18
19 var ImageView = IPython.DOMWidgetView.extend({
19 var ImageView = IPython.DOMWidgetView.extend({
20 render : function(){
20 render : function(){
21 // Called when view is rendered.
21 // Called when view is rendered.
22 this.setElement($("<img />"));
22 this.setElement($("<img />"));
23 this.update(); // Set defaults.
23 this.update(); // Set defaults.
24 },
24 },
25
25
26 update : function(){
26 update : function(){
27 // Update the contents of this view
27 // Update the contents of this view
28 //
28 //
29 // Called when the model is changed. The model may have been
29 // Called when the model is changed. The model may have been
30 // changed by another view or by a state update from the back-end.
30 // changed by another view or by a state update from the back-end.
31 var image_src = 'data:image/' + this.model.get('format') + ';base64,' + this.model.get('_b64value');
31 var image_src = 'data:image/' + this.model.get('format') + ';base64,' + this.model.get('_b64value');
32 this.$el.attr('src', image_src);
32 this.$el.attr('src', image_src);
33
33
34 var width = this.model.get('width');
34 var width = this.model.get('width');
35 if (width !== undefined && width.length > 0) {
35 if (width !== undefined && width.length > 0) {
36 this.$el.attr('width', width);
36 this.$el.attr('width', width);
37 } else {
37 } else {
38 this.$el.removeAttr('width');
38 this.$el.removeAttr('width');
39 }
39 }
40
40
41 var height = this.model.get('height');
41 var height = this.model.get('height');
42 if (height !== undefined && height.length > 0) {
42 if (height !== undefined && height.length > 0) {
43 this.$el.attr('height', height);
43 this.$el.attr('height', height);
44 } else {
44 } else {
45 this.$el.removeAttr('height');
45 this.$el.removeAttr('height');
46 }
46 }
47 return ImageView.__super__.update.apply(this);
47 return ImageView.__super__.update.apply(this);
48 },
48 },
49 });
49 });
50 WidgetManager.register_widget_view('ImageView', ImageView);
50 WidgetManager.register_widget_view('ImageView', ImageView);
51 });
51 });
@@ -1,305 +1,305
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 // IntWidget
9 // IntWidget
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(WidgetManager){
17 define(["widgets/js/widget"], function(WidgetManager){
18
18
19 var IntSliderView = IPython.DOMWidgetView.extend({
19 var IntSliderView = IPython.DOMWidgetView.extend({
20 render : function(){
20 render : function(){
21 // Called when view is rendered.
21 // Called when view is rendered.
22 this.$el
22 this.$el
23 .addClass('widget-hbox-single');
23 .addClass('widget-hbox-single');
24 this.$label = $('<div />')
24 this.$label = $('<div />')
25 .appendTo(this.$el)
25 .appendTo(this.$el)
26 .addClass('widget-hlabel')
26 .addClass('widget-hlabel')
27 .hide();
27 .hide();
28
28
29 this.$slider = $('<div />')
29 this.$slider = $('<div />')
30 .slider({})
30 .slider({})
31 .addClass('slider');
31 .addClass('slider');
32 // Put the slider in a container
32 // Put the slider in a container
33 this.$slider_container = $('<div />')
33 this.$slider_container = $('<div />')
34 .addClass('widget-hslider')
34 .addClass('widget-hslider')
35 .append(this.$slider)
35 .append(this.$slider)
36 this.$el_to_style = this.$slider_container; // Set default element to style
36 this.$el_to_style = this.$slider_container; // Set default element to style
37 this.$el.append(this.$slider_container);
37 this.$el.append(this.$slider_container);
38
38
39 this.$readout = $('<div/>')
39 this.$readout = $('<div/>')
40 .appendTo(this.$el)
40 .appendTo(this.$el)
41 .addClass('widget-hreadout')
41 .addClass('widget-hreadout')
42 .hide();
42 .hide();
43
43
44 // Set defaults.
44 // Set defaults.
45 this.update();
45 this.update();
46 },
46 },
47
47
48 update : function(options){
48 update : function(options){
49 // Update the contents of this view
49 // Update the contents of this view
50 //
50 //
51 // Called when the model is changed. The model may have been
51 // Called when the model is changed. The model may have been
52 // 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.
53 if (options === undefined || options.updated_view != this) {
53 if (options === undefined || options.updated_view != this) {
54 // JQuery slider option keys. These keys happen to have a
54 // JQuery slider option keys. These keys happen to have a
55 // one-to-one mapping with the corrosponding keys of the model.
55 // one-to-one mapping with the corrosponding keys of the model.
56 var jquery_slider_keys = ['step', 'max', 'min', 'disabled'];
56 var jquery_slider_keys = ['step', 'max', 'min', 'disabled'];
57 var that = this;
57 var that = this;
58 _.each(jquery_slider_keys, function(key, i) {
58 _.each(jquery_slider_keys, function(key, i) {
59 var model_value = that.model.get(key);
59 var model_value = that.model.get(key);
60 if (model_value !== undefined) {
60 if (model_value !== undefined) {
61 that.$slider.slider("option", key, model_value);
61 that.$slider.slider("option", key, model_value);
62 }
62 }
63 });
63 });
64
64
65 // WORKAROUND FOR JQUERY SLIDER BUG.
65 // WORKAROUND FOR JQUERY SLIDER BUG.
66 // The horizontal position of the slider handle
66 // The horizontal position of the slider handle
67 // depends on the value of the slider at the time
67 // depends on the value of the slider at the time
68 // of orientation change. Before applying the new
68 // of orientation change. Before applying the new
69 // workaround, we set the value to the minimum to
69 // workaround, we set the value to the minimum to
70 // make sure that the horizontal placement of the
70 // make sure that the horizontal placement of the
71 // handle in the vertical slider is always
71 // handle in the vertical slider is always
72 // consistent.
72 // consistent.
73 var orientation = this.model.get('orientation');
73 var orientation = this.model.get('orientation');
74 var value = this.model.get('min');
74 var value = this.model.get('min');
75 this.$slider.slider('option', 'value', value);
75 this.$slider.slider('option', 'value', value);
76 this.$slider.slider('option', 'orientation', orientation);
76 this.$slider.slider('option', 'orientation', orientation);
77 value = this.model.get('value');
77 value = this.model.get('value');
78 this.$slider.slider('option', 'value', value);
78 this.$slider.slider('option', 'value', value);
79 this.$readout.text(value);
79 this.$readout.text(value);
80
80
81 // Use the right CSS classes for vertical & horizontal sliders
81 // Use the right CSS classes for vertical & horizontal sliders
82 if (orientation=='vertical') {
82 if (orientation=='vertical') {
83 this.$slider_container
83 this.$slider_container
84 .removeClass('widget-hslider')
84 .removeClass('widget-hslider')
85 .addClass('widget-vslider');
85 .addClass('widget-vslider');
86 this.$el
86 this.$el
87 .removeClass('widget-hbox-single')
87 .removeClass('widget-hbox-single')
88 .addClass('widget-vbox-single');
88 .addClass('widget-vbox-single');
89 this.$label
89 this.$label
90 .removeClass('widget-hlabel')
90 .removeClass('widget-hlabel')
91 .addClass('widget-vlabel');
91 .addClass('widget-vlabel');
92 this.$readout
92 this.$readout
93 .removeClass('widget-hreadout')
93 .removeClass('widget-hreadout')
94 .addClass('widget-vreadout');
94 .addClass('widget-vreadout');
95
95
96 } else {
96 } else {
97 this.$slider_container
97 this.$slider_container
98 .removeClass('widget-vslider')
98 .removeClass('widget-vslider')
99 .addClass('widget-hslider');
99 .addClass('widget-hslider');
100 this.$el
100 this.$el
101 .removeClass('widget-vbox-single')
101 .removeClass('widget-vbox-single')
102 .addClass('widget-hbox-single');
102 .addClass('widget-hbox-single');
103 this.$label
103 this.$label
104 .removeClass('widget-vlabel')
104 .removeClass('widget-vlabel')
105 .addClass('widget-hlabel');
105 .addClass('widget-hlabel');
106 this.$readout
106 this.$readout
107 .removeClass('widget-vreadout')
107 .removeClass('widget-vreadout')
108 .addClass('widget-hreadout');
108 .addClass('widget-hreadout');
109 }
109 }
110
110
111 var description = this.model.get('description');
111 var description = this.model.get('description');
112 if (description.length === 0) {
112 if (description.length === 0) {
113 this.$label.hide();
113 this.$label.hide();
114 } else {
114 } else {
115 this.$label.text(description);
115 this.$label.text(description);
116 this.$label.show();
116 this.$label.show();
117 }
117 }
118
118
119 var readout = this.model.get('readout');
119 var readout = this.model.get('readout');
120 if (readout) {
120 if (readout) {
121 this.$readout.show();
121 this.$readout.show();
122 } else {
122 } else {
123 this.$readout.hide();
123 this.$readout.hide();
124 }
124 }
125 }
125 }
126 return IntSliderView.__super__.update.apply(this);
126 return IntSliderView.__super__.update.apply(this);
127 },
127 },
128
128
129 events: {
129 events: {
130 // Dictionary of events and their handlers.
130 // Dictionary of events and their handlers.
131 "slide" : "handleSliderChange"
131 "slide" : "handleSliderChange"
132 },
132 },
133
133
134 handleSliderChange: function(e, ui) {
134 handleSliderChange: function(e, ui) {
135 // Called when the slider value is changed.
135 // Called when the slider value is changed.
136
136
137 // Calling model.set will trigger all of the other views of the
137 // Calling model.set will trigger all of the other views of the
138 // model to update.
138 // model to update.
139 var actual_value = this._validate_slide_value(ui.value);
139 var actual_value = this._validate_slide_value(ui.value);
140 this.model.set('value', actual_value, {updated_view: this});
140 this.model.set('value', actual_value, {updated_view: this});
141 this.$readout.text(actual_value);
141 this.$readout.text(actual_value);
142 this.touch();
142 this.touch();
143 },
143 },
144
144
145 _validate_slide_value: function(x) {
145 _validate_slide_value: function(x) {
146 // Validate the value of the slider before sending it to the back-end
146 // Validate the value of the slider before sending it to the back-end
147 // and applying it to the other views on the page.
147 // and applying it to the other views on the page.
148
148
149 // Double bit-wise not truncates the decimel (int cast).
149 // Double bit-wise not truncates the decimel (int cast).
150 return ~~x;
150 return ~~x;
151 },
151 },
152 });
152 });
153 WidgetManager.register_widget_view('IntSliderView', IntSliderView);
153 WidgetManager.register_widget_view('IntSliderView', IntSliderView);
154
154
155
155
156 var IntTextView = IPython.DOMWidgetView.extend({
156 var IntTextView = IPython.DOMWidgetView.extend({
157 render : function(){
157 render : function(){
158 // Called when view is rendered.
158 // Called when view is rendered.
159 this.$el
159 this.$el
160 .addClass('widget-hbox-single');
160 .addClass('widget-hbox-single');
161 this.$label = $('<div />')
161 this.$label = $('<div />')
162 .appendTo(this.$el)
162 .appendTo(this.$el)
163 .addClass('widget-hlabel')
163 .addClass('widget-hlabel')
164 .hide();
164 .hide();
165 this.$textbox = $('<input type="text" />')
165 this.$textbox = $('<input type="text" />')
166 .addClass('input')
166 .addClass('input')
167 .addClass('widget-numeric-text')
167 .addClass('widget-numeric-text')
168 .appendTo(this.$el);
168 .appendTo(this.$el);
169 this.$el_to_style = this.$textbox; // Set default element to style
169 this.$el_to_style = this.$textbox; // Set default element to style
170 this.update(); // Set defaults.
170 this.update(); // Set defaults.
171 },
171 },
172
172
173 update : function(options){
173 update : function(options){
174 // Update the contents of this view
174 // Update the contents of this view
175 //
175 //
176 // Called when the model is changed. The model may have been
176 // Called when the model is changed. The model may have been
177 // changed by another view or by a state update from the back-end.
177 // changed by another view or by a state update from the back-end.
178 if (options === undefined || options.updated_view != this) {
178 if (options === undefined || options.updated_view != this) {
179 var value = this.model.get('value');
179 var value = this.model.get('value');
180 if (this._parse_value(this.$textbox.val()) != value) {
180 if (this._parse_value(this.$textbox.val()) != value) {
181 this.$textbox.val(value);
181 this.$textbox.val(value);
182 }
182 }
183
183
184 if (this.model.get('disabled')) {
184 if (this.model.get('disabled')) {
185 this.$textbox.attr('disabled','disabled');
185 this.$textbox.attr('disabled','disabled');
186 } else {
186 } else {
187 this.$textbox.removeAttr('disabled');
187 this.$textbox.removeAttr('disabled');
188 }
188 }
189
189
190 var description = this.model.get('description');
190 var description = this.model.get('description');
191 if (description.length === 0) {
191 if (description.length === 0) {
192 this.$label.hide();
192 this.$label.hide();
193 } else {
193 } else {
194 this.$label.text(description);
194 this.$label.text(description);
195 this.$label.show();
195 this.$label.show();
196 }
196 }
197 }
197 }
198 return IntTextView.__super__.update.apply(this);
198 return IntTextView.__super__.update.apply(this);
199 },
199 },
200
200
201 events: {
201 events: {
202 // Dictionary of events and their handlers.
202 // Dictionary of events and their handlers.
203 "keyup input" : "handleChanging",
203 "keyup input" : "handleChanging",
204 "paste input" : "handleChanging",
204 "paste input" : "handleChanging",
205 "cut input" : "handleChanging",
205 "cut input" : "handleChanging",
206
206
207 // Fires only when control is validated or looses focus.
207 // Fires only when control is validated or looses focus.
208 "change input" : "handleChanged"
208 "change input" : "handleChanged"
209 },
209 },
210
210
211 handleChanging: function(e) {
211 handleChanging: function(e) {
212 // Handles and validates user input.
212 // Handles and validates user input.
213
213
214 // Try to parse value as a int.
214 // Try to parse value as a int.
215 var numericalValue = 0;
215 var numericalValue = 0;
216 if (e.target.value !== '') {
216 if (e.target.value !== '') {
217 numericalValue = this._parse_value(e.target.value);
217 numericalValue = this._parse_value(e.target.value);
218 }
218 }
219
219
220 // If parse failed, reset value to value stored in model.
220 // If parse failed, reset value to value stored in model.
221 if (isNaN(numericalValue)) {
221 if (isNaN(numericalValue)) {
222 e.target.value = this.model.get('value');
222 e.target.value = this.model.get('value');
223 } else if (!isNaN(numericalValue)) {
223 } else if (!isNaN(numericalValue)) {
224 if (this.model.get('max') !== undefined) {
224 if (this.model.get('max') !== undefined) {
225 numericalValue = Math.min(this.model.get('max'), numericalValue);
225 numericalValue = Math.min(this.model.get('max'), numericalValue);
226 }
226 }
227 if (this.model.get('min') !== undefined) {
227 if (this.model.get('min') !== undefined) {
228 numericalValue = Math.max(this.model.get('min'), numericalValue);
228 numericalValue = Math.max(this.model.get('min'), numericalValue);
229 }
229 }
230
230
231 // Apply the value if it has changed.
231 // Apply the value if it has changed.
232 if (numericalValue != this.model.get('value')) {
232 if (numericalValue != this.model.get('value')) {
233
233
234 // Calling model.set will trigger all of the other views of the
234 // Calling model.set will trigger all of the other views of the
235 // model to update.
235 // model to update.
236 this.model.set('value', numericalValue, {updated_view: this});
236 this.model.set('value', numericalValue, {updated_view: this});
237 this.touch();
237 this.touch();
238 }
238 }
239 }
239 }
240 },
240 },
241
241
242 handleChanged: function(e) {
242 handleChanged: function(e) {
243 // Applies validated input.
243 // Applies validated input.
244 if (this.model.get('value') != e.target.value) {
244 if (this.model.get('value') != e.target.value) {
245 e.target.value = this.model.get('value');
245 e.target.value = this.model.get('value');
246 }
246 }
247 },
247 },
248
248
249 _parse_value: function(value) {
249 _parse_value: function(value) {
250 // Parse the value stored in a string.
250 // Parse the value stored in a string.
251 return parseInt(value);
251 return parseInt(value);
252 },
252 },
253 });
253 });
254 WidgetManager.register_widget_view('IntTextView', IntTextView);
254 WidgetManager.register_widget_view('IntTextView', IntTextView);
255
255
256
256
257 var ProgressView = IPython.DOMWidgetView.extend({
257 var ProgressView = IPython.DOMWidgetView.extend({
258 render : function(){
258 render : function(){
259 // Called when view is rendered.
259 // Called when view is rendered.
260 this.$el
260 this.$el
261 .addClass('widget-hbox-single');
261 .addClass('widget-hbox-single');
262 this.$label = $('<div />')
262 this.$label = $('<div />')
263 .appendTo(this.$el)
263 .appendTo(this.$el)
264 .addClass('widget-hlabel')
264 .addClass('widget-hlabel')
265 .hide();
265 .hide();
266 this.$progress = $('<div />')
266 this.$progress = $('<div />')
267 .addClass('progress')
267 .addClass('progress')
268 .addClass('widget-progress')
268 .addClass('widget-progress')
269 .appendTo(this.$el);
269 .appendTo(this.$el);
270 this.$el_to_style = this.$progress; // Set default element to style
270 this.$el_to_style = this.$progress; // Set default element to style
271 this.$bar = $('<div />')
271 this.$bar = $('<div />')
272 .addClass('bar')
272 .addClass('bar')
273 .css('width', '50%')
273 .css('width', '50%')
274 .appendTo(this.$progress);
274 .appendTo(this.$progress);
275 this.update(); // Set defaults.
275 this.update(); // Set defaults.
276 },
276 },
277
277
278 update : function(){
278 update : function(){
279 // Update the contents of this view
279 // Update the contents of this view
280 //
280 //
281 // Called when the model is changed. The model may have been
281 // Called when the model is changed. The model may have been
282 // changed by another view or by a state update from the back-end.
282 // changed by another view or by a state update from the back-end.
283 var value = this.model.get('value');
283 var value = this.model.get('value');
284 var max = this.model.get('max');
284 var max = this.model.get('max');
285 var min = this.model.get('min');
285 var min = this.model.get('min');
286 var percent = 100.0 * (value - min) / (max - min);
286 var percent = 100.0 * (value - min) / (max - min);
287 this.$bar.css('width', percent + '%');
287 this.$bar.css('width', percent + '%');
288
288
289 var description = this.model.get('description');
289 var description = this.model.get('description');
290 if (description.length === 0) {
290 if (description.length === 0) {
291 this.$label.hide();
291 this.$label.hide();
292 } else {
292 } else {
293 this.$label.text(description);
293 this.$label.text(description);
294 this.$label.show();
294 this.$label.show();
295 }
295 }
296 return ProgressView.__super__.update.apply(this);
296 return ProgressView.__super__.update.apply(this);
297 },
297 },
298 });
298 });
299 WidgetManager.register_widget_view('ProgressView', ProgressView);
299 WidgetManager.register_widget_view('ProgressView', ProgressView);
300
300
301
301
302 // Return the slider and text views so they can be inheritted to create the
302 // Return the slider and text views so they can be inheritted to create the
303 // float versions.
303 // float versions.
304 return [IntSliderView, IntTextView];
304 return [IntSliderView, IntTextView];
305 });
305 });
@@ -1,381 +1,381
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(WidgetManager){
17 define(["widgets/js/widget"], function(WidgetManager){
18
18
19 var DropdownView = IPython.DOMWidgetView.extend({
19 var DropdownView = IPython.DOMWidgetView.extend({
20 render : function(){
20 render : function(){
21 // Called when view is rendered.
21 // Called when view is rendered.
22 this.$el
22 this.$el
23 .addClass('widget-hbox-single');
23 .addClass('widget-hbox-single');
24 this.$label = $('<div />')
24 this.$label = $('<div />')
25 .appendTo(this.$el)
25 .appendTo(this.$el)
26 .addClass('widget-hlabel')
26 .addClass('widget-hlabel')
27 .hide();
27 .hide();
28 this.$buttongroup = $('<div />')
28 this.$buttongroup = $('<div />')
29 .addClass('widget_item')
29 .addClass('widget_item')
30 .addClass('btn-group')
30 .addClass('btn-group')
31 .appendTo(this.$el);
31 .appendTo(this.$el);
32 this.$el_to_style = this.$buttongroup; // Set default element to style
32 this.$el_to_style = this.$buttongroup; // Set default element to style
33 this.$droplabel = $('<button />')
33 this.$droplabel = $('<button />')
34 .addClass('btn')
34 .addClass('btn')
35 .addClass('widget-combo-btn')
35 .addClass('widget-combo-btn')
36 .html("&nbsp;")
36 .html("&nbsp;")
37 .appendTo(this.$buttongroup);
37 .appendTo(this.$buttongroup);
38 this.$dropbutton = $('<button />')
38 this.$dropbutton = $('<button />')
39 .addClass('btn')
39 .addClass('btn')
40 .addClass('dropdown-toggle')
40 .addClass('dropdown-toggle')
41 .addClass('widget-combo-carrot-btn')
41 .addClass('widget-combo-carrot-btn')
42 .attr('data-toggle', 'dropdown')
42 .attr('data-toggle', 'dropdown')
43 .append($('<span />').addClass("caret"))
43 .append($('<span />').addClass("caret"))
44 .appendTo(this.$buttongroup);
44 .appendTo(this.$buttongroup);
45 this.$droplist = $('<ul />')
45 this.$droplist = $('<ul />')
46 .addClass('dropdown-menu')
46 .addClass('dropdown-menu')
47 .appendTo(this.$buttongroup);
47 .appendTo(this.$buttongroup);
48
48
49 // Set defaults.
49 // Set defaults.
50 this.update();
50 this.update();
51 },
51 },
52
52
53 update : function(options){
53 update : function(options){
54 // Update the contents of this view
54 // Update the contents of this view
55 //
55 //
56 // Called when the model is changed. The model may have been
56 // Called when the model is changed. The model may have been
57 // changed by another view or by a state update from the back-end.
57 // changed by another view or by a state update from the back-end.
58
58
59 if (options === undefined || options.updated_view != this) {
59 if (options === undefined || options.updated_view != this) {
60 var selected_item_text = this.model.get('value_name');
60 var selected_item_text = this.model.get('value_name');
61 if (selected_item_text.trim().length === 0) {
61 if (selected_item_text.trim().length === 0) {
62 this.$droplabel.html("&nbsp;");
62 this.$droplabel.html("&nbsp;");
63 } else {
63 } else {
64 this.$droplabel.text(selected_item_text);
64 this.$droplabel.text(selected_item_text);
65 }
65 }
66
66
67 var items = this.model.get('value_names');
67 var items = this.model.get('value_names');
68 var $replace_droplist = $('<ul />')
68 var $replace_droplist = $('<ul />')
69 .addClass('dropdown-menu');
69 .addClass('dropdown-menu');
70 var that = this;
70 var that = this;
71 _.each(items, function(item, i) {
71 _.each(items, function(item, i) {
72 var item_button = $('<a href="#"/>')
72 var item_button = $('<a href="#"/>')
73 .text(item)
73 .text(item)
74 .on('click', $.proxy(that.handle_click, that));
74 .on('click', $.proxy(that.handle_click, that));
75 $replace_droplist.append($('<li />').append(item_button));
75 $replace_droplist.append($('<li />').append(item_button));
76 });
76 });
77
77
78 this.$droplist.replaceWith($replace_droplist);
78 this.$droplist.replaceWith($replace_droplist);
79 this.$droplist.remove();
79 this.$droplist.remove();
80 this.$droplist = $replace_droplist;
80 this.$droplist = $replace_droplist;
81
81
82 if (this.model.get('disabled')) {
82 if (this.model.get('disabled')) {
83 this.$buttongroup.attr('disabled','disabled');
83 this.$buttongroup.attr('disabled','disabled');
84 this.$droplabel.attr('disabled','disabled');
84 this.$droplabel.attr('disabled','disabled');
85 this.$dropbutton.attr('disabled','disabled');
85 this.$dropbutton.attr('disabled','disabled');
86 this.$droplist.attr('disabled','disabled');
86 this.$droplist.attr('disabled','disabled');
87 } else {
87 } else {
88 this.$buttongroup.removeAttr('disabled');
88 this.$buttongroup.removeAttr('disabled');
89 this.$droplabel.removeAttr('disabled');
89 this.$droplabel.removeAttr('disabled');
90 this.$dropbutton.removeAttr('disabled');
90 this.$dropbutton.removeAttr('disabled');
91 this.$droplist.removeAttr('disabled');
91 this.$droplist.removeAttr('disabled');
92 }
92 }
93
93
94 var description = this.model.get('description');
94 var description = this.model.get('description');
95 if (description.length === 0) {
95 if (description.length === 0) {
96 this.$label.hide();
96 this.$label.hide();
97 } else {
97 } else {
98 this.$label.text(description);
98 this.$label.text(description);
99 this.$label.show();
99 this.$label.show();
100 }
100 }
101 }
101 }
102 return DropdownView.__super__.update.apply(this);
102 return DropdownView.__super__.update.apply(this);
103 },
103 },
104
104
105 handle_click: function (e) {
105 handle_click: function (e) {
106 // Handle when a value is clicked.
106 // Handle when a value is clicked.
107
107
108 // Calling model.set will trigger all of the other views of the
108 // Calling model.set will trigger all of the other views of the
109 // model to update.
109 // model to update.
110 this.model.set('value_name', $(e.target).text(), {updated_view: this});
110 this.model.set('value_name', $(e.target).text(), {updated_view: this});
111 this.touch();
111 this.touch();
112 },
112 },
113
113
114 });
114 });
115 WidgetManager.register_widget_view('DropdownView', DropdownView);
115 WidgetManager.register_widget_view('DropdownView', DropdownView);
116
116
117
117
118 var RadioButtonsView = IPython.DOMWidgetView.extend({
118 var RadioButtonsView = IPython.DOMWidgetView.extend({
119 render : function(){
119 render : function(){
120 // Called when view is rendered.
120 // Called when view is rendered.
121 this.$el
121 this.$el
122 .addClass('widget-hbox');
122 .addClass('widget-hbox');
123 this.$label = $('<div />')
123 this.$label = $('<div />')
124 .appendTo(this.$el)
124 .appendTo(this.$el)
125 .addClass('widget-hlabel')
125 .addClass('widget-hlabel')
126 .hide();
126 .hide();
127 this.$container = $('<div />')
127 this.$container = $('<div />')
128 .appendTo(this.$el)
128 .appendTo(this.$el)
129 .addClass('widget-radio-box');
129 .addClass('widget-radio-box');
130 this.$el_to_style = this.$container; // Set default element to style
130 this.$el_to_style = this.$container; // Set default element to style
131 this.update();
131 this.update();
132 },
132 },
133
133
134 update : function(options){
134 update : function(options){
135 // Update the contents of this view
135 // Update the contents of this view
136 //
136 //
137 // Called when the model is changed. The model may have been
137 // Called when the model is changed. The model may have been
138 // changed by another view or by a state update from the back-end.
138 // changed by another view or by a state update from the back-end.
139 if (options === undefined || options.updated_view != this) {
139 if (options === undefined || options.updated_view != this) {
140 // Add missing items to the DOM.
140 // Add missing items to the DOM.
141 var items = this.model.get('value_names');
141 var items = this.model.get('value_names');
142 var disabled = this.model.get('disabled');
142 var disabled = this.model.get('disabled');
143 var that = this;
143 var that = this;
144 _.each(items, function(item, index) {
144 _.each(items, function(item, index) {
145 var item_query = ' :input[value="' + item + '"]';
145 var item_query = ' :input[value="' + item + '"]';
146 if (that.$el.find(item_query).length === 0) {
146 if (that.$el.find(item_query).length === 0) {
147 var $label = $('<label />')
147 var $label = $('<label />')
148 .addClass('radio')
148 .addClass('radio')
149 .text(item)
149 .text(item)
150 .appendTo(that.$container);
150 .appendTo(that.$container);
151
151
152 $('<input />')
152 $('<input />')
153 .attr('type', 'radio')
153 .attr('type', 'radio')
154 .addClass(that.model)
154 .addClass(that.model)
155 .val(item)
155 .val(item)
156 .prependTo($label)
156 .prependTo($label)
157 .on('click', $.proxy(that.handle_click, that));
157 .on('click', $.proxy(that.handle_click, that));
158 }
158 }
159
159
160 var $item_element = that.$container.find(item_query);
160 var $item_element = that.$container.find(item_query);
161 if (that.model.get('value_name') == item) {
161 if (that.model.get('value_name') == item) {
162 $item_element.prop('checked', true);
162 $item_element.prop('checked', true);
163 } else {
163 } else {
164 $item_element.prop('checked', false);
164 $item_element.prop('checked', false);
165 }
165 }
166 $item_element.prop('disabled', disabled);
166 $item_element.prop('disabled', disabled);
167 });
167 });
168
168
169 // Remove items that no longer exist.
169 // Remove items that no longer exist.
170 this.$container.find('input').each(function(i, obj) {
170 this.$container.find('input').each(function(i, obj) {
171 var value = $(obj).val();
171 var value = $(obj).val();
172 var found = false;
172 var found = false;
173 _.each(items, function(item, index) {
173 _.each(items, function(item, index) {
174 if (item == value) {
174 if (item == value) {
175 found = true;
175 found = true;
176 return false;
176 return false;
177 }
177 }
178 });
178 });
179
179
180 if (!found) {
180 if (!found) {
181 $(obj).parent().remove();
181 $(obj).parent().remove();
182 }
182 }
183 });
183 });
184
184
185 var description = this.model.get('description');
185 var description = this.model.get('description');
186 if (description.length === 0) {
186 if (description.length === 0) {
187 this.$label.hide();
187 this.$label.hide();
188 } else {
188 } else {
189 this.$label.text(description);
189 this.$label.text(description);
190 this.$label.show();
190 this.$label.show();
191 }
191 }
192 }
192 }
193 return RadioButtonsView.__super__.update.apply(this);
193 return RadioButtonsView.__super__.update.apply(this);
194 },
194 },
195
195
196 handle_click: function (e) {
196 handle_click: function (e) {
197 // Handle when a value is clicked.
197 // Handle when a value is clicked.
198
198
199 // Calling model.set will trigger all of the other views of the
199 // Calling model.set will trigger all of the other views of the
200 // model to update.
200 // model to update.
201 this.model.set('value_name', $(e.target).val(), {updated_view: this});
201 this.model.set('value_name', $(e.target).val(), {updated_view: this});
202 this.touch();
202 this.touch();
203 },
203 },
204 });
204 });
205 WidgetManager.register_widget_view('RadioButtonsView', RadioButtonsView);
205 WidgetManager.register_widget_view('RadioButtonsView', RadioButtonsView);
206
206
207
207
208 var ToggleButtonsView = IPython.DOMWidgetView.extend({
208 var ToggleButtonsView = IPython.DOMWidgetView.extend({
209 render : function(){
209 render : function(){
210 // Called when view is rendered.
210 // Called when view is rendered.
211 this.$el
211 this.$el
212 .addClass('widget-hbox-single');
212 .addClass('widget-hbox-single');
213 this.$label = $('<div />')
213 this.$label = $('<div />')
214 .appendTo(this.$el)
214 .appendTo(this.$el)
215 .addClass('widget-hlabel')
215 .addClass('widget-hlabel')
216 .hide();
216 .hide();
217 this.$buttongroup = $('<div />')
217 this.$buttongroup = $('<div />')
218 .addClass('btn-group')
218 .addClass('btn-group')
219 .attr('data-toggle', 'buttons-radio')
219 .attr('data-toggle', 'buttons-radio')
220 .appendTo(this.$el);
220 .appendTo(this.$el);
221 this.$el_to_style = this.$buttongroup; // Set default element to style
221 this.$el_to_style = this.$buttongroup; // Set default element to style
222 this.update();
222 this.update();
223 },
223 },
224
224
225 update : function(options){
225 update : function(options){
226 // Update the contents of this view
226 // Update the contents of this view
227 //
227 //
228 // Called when the model is changed. The model may have been
228 // Called when the model is changed. The model may have been
229 // changed by another view or by a state update from the back-end.
229 // changed by another view or by a state update from the back-end.
230 if (options === undefined || options.updated_view != this) {
230 if (options === undefined || options.updated_view != this) {
231 // Add missing items to the DOM.
231 // Add missing items to the DOM.
232 var items = this.model.get('value_names');
232 var items = this.model.get('value_names');
233 var disabled = this.model.get('disabled');
233 var disabled = this.model.get('disabled');
234 var that = this;
234 var that = this;
235 var item_html;
235 var item_html;
236 _.each(items, function(item, index) {
236 _.each(items, function(item, index) {
237 if (item.trim().length == 0) {
237 if (item.trim().length == 0) {
238 item_html = "&nbsp;";
238 item_html = "&nbsp;";
239 } else {
239 } else {
240 item_html = IPython.utils.escape_html(item);
240 item_html = IPython.utils.escape_html(item);
241 }
241 }
242 var item_query = '[data-value="' + item + '"]';
242 var item_query = '[data-value="' + item + '"]';
243 var $item_element = that.$buttongroup.find(item_query);
243 var $item_element = that.$buttongroup.find(item_query);
244 if (!$item_element.length) {
244 if (!$item_element.length) {
245 $item_element = $('<button/>')
245 $item_element = $('<button/>')
246 .attr('type', 'button')
246 .attr('type', 'button')
247 .addClass('btn')
247 .addClass('btn')
248 .html(item_html)
248 .html(item_html)
249 .appendTo(that.$buttongroup)
249 .appendTo(that.$buttongroup)
250 .attr('data-value', item)
250 .attr('data-value', item)
251 .on('click', $.proxy(that.handle_click, that));
251 .on('click', $.proxy(that.handle_click, that));
252 }
252 }
253 if (that.model.get('value_name') == item) {
253 if (that.model.get('value_name') == item) {
254 $item_element.addClass('active');
254 $item_element.addClass('active');
255 } else {
255 } else {
256 $item_element.removeClass('active');
256 $item_element.removeClass('active');
257 }
257 }
258 $item_element.prop('disabled', disabled);
258 $item_element.prop('disabled', disabled);
259 });
259 });
260
260
261 // Remove items that no longer exist.
261 // Remove items that no longer exist.
262 this.$buttongroup.find('button').each(function(i, obj) {
262 this.$buttongroup.find('button').each(function(i, obj) {
263 var value = $(obj).data('value');
263 var value = $(obj).data('value');
264 var found = false;
264 var found = false;
265 _.each(items, function(item, index) {
265 _.each(items, function(item, index) {
266 if (item == value) {
266 if (item == value) {
267 found = true;
267 found = true;
268 return false;
268 return false;
269 }
269 }
270 });
270 });
271
271
272 if (!found) {
272 if (!found) {
273 $(obj).remove();
273 $(obj).remove();
274 }
274 }
275 });
275 });
276
276
277 var description = this.model.get('description');
277 var description = this.model.get('description');
278 if (description.length === 0) {
278 if (description.length === 0) {
279 this.$label.hide();
279 this.$label.hide();
280 } else {
280 } else {
281 this.$label.text(description);
281 this.$label.text(description);
282 this.$label.show();
282 this.$label.show();
283 }
283 }
284 }
284 }
285 return ToggleButtonsView.__super__.update.apply(this);
285 return ToggleButtonsView.__super__.update.apply(this);
286 },
286 },
287
287
288 handle_click: function (e) {
288 handle_click: function (e) {
289 // Handle when a value is clicked.
289 // Handle when a value is clicked.
290
290
291 // 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
292 // model to update.
292 // model to update.
293 this.model.set('value_name', $(e.target).data('value'), {updated_view: this});
293 this.model.set('value_name', $(e.target).data('value'), {updated_view: this});
294 this.touch();
294 this.touch();
295 },
295 },
296 });
296 });
297 WidgetManager.register_widget_view('ToggleButtonsView', ToggleButtonsView);
297 WidgetManager.register_widget_view('ToggleButtonsView', ToggleButtonsView);
298
298
299
299
300 var SelectView = IPython.DOMWidgetView.extend({
300 var SelectView = IPython.DOMWidgetView.extend({
301 render : function(){
301 render : function(){
302 // Called when view is rendered.
302 // Called when view is rendered.
303 this.$el
303 this.$el
304 .addClass('widget-hbox');
304 .addClass('widget-hbox');
305 this.$label = $('<div />')
305 this.$label = $('<div />')
306 .appendTo(this.$el)
306 .appendTo(this.$el)
307 .addClass('widget-hlabel')
307 .addClass('widget-hlabel')
308 .hide();
308 .hide();
309 this.$listbox = $('<select />')
309 this.$listbox = $('<select />')
310 .addClass('widget-listbox')
310 .addClass('widget-listbox')
311 .attr('size', 6)
311 .attr('size', 6)
312 .appendTo(this.$el);
312 .appendTo(this.$el);
313 this.$el_to_style = this.$listbox; // Set default element to style
313 this.$el_to_style = this.$listbox; // Set default element to style
314 this.update();
314 this.update();
315 },
315 },
316
316
317 update : function(options){
317 update : function(options){
318 // Update the contents of this view
318 // Update the contents of this view
319 //
319 //
320 // Called when the model is changed. The model may have been
320 // Called when the model is changed. The model may have been
321 // changed by another view or by a state update from the back-end.
321 // changed by another view or by a state update from the back-end.
322 if (options === undefined || options.updated_view != this) {
322 if (options === undefined || options.updated_view != this) {
323 // Add missing items to the DOM.
323 // Add missing items to the DOM.
324 var items = this.model.get('value_names');
324 var items = this.model.get('value_names');
325 var that = this;
325 var that = this;
326 _.each(items, function(item, index) {
326 _.each(items, function(item, index) {
327 var item_query = ' :contains("' + item + '")';
327 var item_query = ' :contains("' + item + '")';
328 if (that.$listbox.find(item_query).length === 0) {
328 if (that.$listbox.find(item_query).length === 0) {
329 $('<option />')
329 $('<option />')
330 .text(item)
330 .text(item)
331 .attr('value_name', item)
331 .attr('value_name', item)
332 .appendTo(that.$listbox)
332 .appendTo(that.$listbox)
333 .on('click', $.proxy(that.handle_click, that));
333 .on('click', $.proxy(that.handle_click, that));
334 }
334 }
335 });
335 });
336
336
337 // Select the correct element
337 // Select the correct element
338 this.$listbox.val(this.model.get('value_name'));
338 this.$listbox.val(this.model.get('value_name'));
339
339
340 // Disable listbox if needed
340 // Disable listbox if needed
341 var disabled = this.model.get('disabled');
341 var disabled = this.model.get('disabled');
342 this.$listbox.prop('disabled', disabled);
342 this.$listbox.prop('disabled', disabled);
343
343
344 // Remove items that no longer exist.
344 // Remove items that no longer exist.
345 this.$listbox.find('option').each(function(i, obj) {
345 this.$listbox.find('option').each(function(i, obj) {
346 var value = $(obj).text();
346 var value = $(obj).text();
347 var found = false;
347 var found = false;
348 _.each(items, function(item, index) {
348 _.each(items, function(item, index) {
349 if (item == value) {
349 if (item == value) {
350 found = true;
350 found = true;
351 return false;
351 return false;
352 }
352 }
353 });
353 });
354
354
355 if (!found) {
355 if (!found) {
356 $(obj).remove();
356 $(obj).remove();
357 }
357 }
358 });
358 });
359
359
360 var description = this.model.get('description');
360 var description = this.model.get('description');
361 if (description.length === 0) {
361 if (description.length === 0) {
362 this.$label.hide();
362 this.$label.hide();
363 } else {
363 } else {
364 this.$label.text(description);
364 this.$label.text(description);
365 this.$label.show();
365 this.$label.show();
366 }
366 }
367 }
367 }
368 return SelectView.__super__.update.apply(this);
368 return SelectView.__super__.update.apply(this);
369 },
369 },
370
370
371 handle_click: function (e) {
371 handle_click: function (e) {
372 // Handle when a value is clicked.
372 // Handle when a value is clicked.
373
373
374 // Calling model.set will trigger all of the other views of the
374 // Calling model.set will trigger all of the other views of the
375 // model to update.
375 // model to update.
376 this.model.set('value_name', $(e.target).text(), {updated_view: this});
376 this.model.set('value_name', $(e.target).text(), {updated_view: this});
377 this.touch();
377 this.touch();
378 },
378 },
379 });
379 });
380 WidgetManager.register_widget_view('SelectView', SelectView);
380 WidgetManager.register_widget_view('SelectView', SelectView);
381 });
381 });
@@ -1,244 +1,244
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 // SelectionContainerWidget
9 // SelectionContainerWidget
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(WidgetManager){
17 define(["widgets/js/widget"], function(WidgetManager){
18
18
19 var AccordionView = IPython.DOMWidgetView.extend({
19 var AccordionView = IPython.DOMWidgetView.extend({
20 render: function(){
20 render: function(){
21 // Called when view is rendered.
21 // Called when view is rendered.
22 var guid = 'accordion' + IPython.utils.uuid();
22 var guid = 'accordion' + IPython.utils.uuid();
23 this.$el
23 this.$el
24 .attr('id', guid)
24 .attr('id', guid)
25 .addClass('accordion');
25 .addClass('accordion');
26 this.containers = [];
26 this.containers = [];
27 this.model_containers = {};
27 this.model_containers = {};
28 this.update_children([], this.model.get('_children'));
28 this.update_children([], this.model.get('_children'));
29 this.model.on('change:_children', function(model, value, options) {
29 this.model.on('change:_children', function(model, value, options) {
30 this.update_children(model.previous('_children'), value);
30 this.update_children(model.previous('_children'), value);
31 }, this);
31 }, this);
32 },
32 },
33
33
34 update: function(options) {
34 update: function(options) {
35 // Update the contents of this view
35 // Update the contents of this view
36 //
36 //
37 // Called when the model is changed. The model may have been
37 // Called when the model is changed. The model may have been
38 // changed by another view or by a state update from the back-end.
38 // changed by another view or by a state update from the back-end.
39 if (options === undefined || options.updated_view != this) {
39 if (options === undefined || options.updated_view != this) {
40 // Set tab titles
40 // Set tab titles
41 var titles = this.model.get('_titles');
41 var titles = this.model.get('_titles');
42 var that = this;
42 var that = this;
43 _.each(titles, function(title, page_index) {
43 _.each(titles, function(title, page_index) {
44 var accordian = that.containers[page_index];
44 var accordian = that.containers[page_index];
45 if (accordian !== undefined) {
45 if (accordian !== undefined) {
46 accordian
46 accordian
47 .find('.accordion-heading')
47 .find('.accordion-heading')
48 .find('.accordion-toggle')
48 .find('.accordion-toggle')
49 .text(title);
49 .text(title);
50 }
50 }
51 });
51 });
52
52
53 // Set selected page
53 // Set selected page
54 var selected_index = this.model.get("selected_index");
54 var selected_index = this.model.get("selected_index");
55 if (0 <= selected_index && selected_index < this.containers.length) {
55 if (0 <= selected_index && selected_index < this.containers.length) {
56 _.each(this.containers, function(container, index) {
56 _.each(this.containers, function(container, index) {
57 if (index==selected_index) {
57 if (index==selected_index) {
58 container.find('.accordion-body').collapse('show');
58 container.find('.accordion-body').collapse('show');
59 } else {
59 } else {
60 container.find('.accordion-body').collapse('hide');
60 container.find('.accordion-body').collapse('hide');
61 }
61 }
62 });
62 });
63 }
63 }
64 }
64 }
65 return AccordionView.__super__.update.apply(this);
65 return AccordionView.__super__.update.apply(this);
66 },
66 },
67
67
68 update_children: function(old_list, new_list) {
68 update_children: function(old_list, new_list) {
69 // Called when the children list is modified.
69 // Called when the children list is modified.
70 this.do_diff(old_list,
70 this.do_diff(old_list,
71 new_list,
71 new_list,
72 $.proxy(this.remove_child_model, this),
72 $.proxy(this.remove_child_model, this),
73 $.proxy(this.add_child_model, this));
73 $.proxy(this.add_child_model, this));
74 },
74 },
75
75
76 remove_child_model: function(model) {
76 remove_child_model: function(model) {
77 // Called when a child is removed from children list.
77 // Called when a child is removed from children list.
78 var accordion_group = this.model_containers[model.id];
78 var accordion_group = this.model_containers[model.id];
79 this.containers.splice(accordion_group.container_index, 1);
79 this.containers.splice(accordion_group.container_index, 1);
80 delete this.model_containers[model.id];
80 delete this.model_containers[model.id];
81 accordion_group.remove();
81 accordion_group.remove();
82 this.delete_child_view(model);
82 this.delete_child_view(model);
83 },
83 },
84
84
85 add_child_model: function(model) {
85 add_child_model: function(model) {
86 // Called when a child is added to children list.
86 // Called when a child is added to children list.
87 var view = this.create_child_view(model);
87 var view = this.create_child_view(model);
88 var index = this.containers.length;
88 var index = this.containers.length;
89 var uuid = IPython.utils.uuid();
89 var uuid = IPython.utils.uuid();
90 var accordion_group = $('<div />')
90 var accordion_group = $('<div />')
91 .addClass('accordion-group')
91 .addClass('accordion-group')
92 .appendTo(this.$el);
92 .appendTo(this.$el);
93 var accordion_heading = $('<div />')
93 var accordion_heading = $('<div />')
94 .addClass('accordion-heading')
94 .addClass('accordion-heading')
95 .appendTo(accordion_group);
95 .appendTo(accordion_group);
96 var that = this;
96 var that = this;
97 var accordion_toggle = $('<a />')
97 var accordion_toggle = $('<a />')
98 .addClass('accordion-toggle')
98 .addClass('accordion-toggle')
99 .attr('data-toggle', 'collapse')
99 .attr('data-toggle', 'collapse')
100 .attr('data-parent', '#' + this.$el.attr('id'))
100 .attr('data-parent', '#' + this.$el.attr('id'))
101 .attr('href', '#' + uuid)
101 .attr('href', '#' + uuid)
102 .click(function(evt){
102 .click(function(evt){
103
103
104 // Calling model.set will trigger all of the other views of the
104 // Calling model.set will trigger all of the other views of the
105 // model to update.
105 // model to update.
106 that.model.set("selected_index", index, {updated_view: this});
106 that.model.set("selected_index", index, {updated_view: this});
107 that.touch();
107 that.touch();
108 })
108 })
109 .text('Page ' + index)
109 .text('Page ' + index)
110 .appendTo(accordion_heading);
110 .appendTo(accordion_heading);
111 var accordion_body = $('<div />', {id: uuid})
111 var accordion_body = $('<div />', {id: uuid})
112 .addClass('accordion-body collapse')
112 .addClass('accordion-body collapse')
113 .appendTo(accordion_group);
113 .appendTo(accordion_group);
114 var accordion_inner = $('<div />')
114 var accordion_inner = $('<div />')
115 .addClass('accordion-inner')
115 .addClass('accordion-inner')
116 .appendTo(accordion_body);
116 .appendTo(accordion_body);
117 var container_index = this.containers.push(accordion_group) - 1;
117 var container_index = this.containers.push(accordion_group) - 1;
118 accordion_group.container_index = container_index;
118 accordion_group.container_index = container_index;
119 this.model_containers[model.id] = accordion_group;
119 this.model_containers[model.id] = accordion_group;
120 accordion_inner.append(view.$el);
120 accordion_inner.append(view.$el);
121
121
122 this.update();
122 this.update();
123
123
124 // Stupid workaround to close the bootstrap accordion tabs which
124 // Stupid workaround to close the bootstrap accordion tabs which
125 // open by default even though they don't have the `in` class
125 // open by default even though they don't have the `in` class
126 // attached to them. For some reason a delay is required.
126 // attached to them. For some reason a delay is required.
127 // TODO: Better fix.
127 // TODO: Better fix.
128 setTimeout(function(){ that.update(); }, 500);
128 setTimeout(function(){ that.update(); }, 500);
129 },
129 },
130 });
130 });
131 WidgetManager.register_widget_view('AccordionView', AccordionView);
131 WidgetManager.register_widget_view('AccordionView', AccordionView);
132
132
133
133
134 var TabView = IPython.DOMWidgetView.extend({
134 var TabView = IPython.DOMWidgetView.extend({
135 initialize: function() {
135 initialize: function() {
136 // Public constructor.
136 // Public constructor.
137 this.containers = [];
137 this.containers = [];
138 TabView.__super__.initialize.apply(this, arguments);
138 TabView.__super__.initialize.apply(this, arguments);
139 },
139 },
140
140
141 render: function(){
141 render: function(){
142 // Called when view is rendered.
142 // Called when view is rendered.
143 var uuid = 'tabs'+IPython.utils.uuid();
143 var uuid = 'tabs'+IPython.utils.uuid();
144 var that = this;
144 var that = this;
145 this.$tabs = $('<div />', {id: uuid})
145 this.$tabs = $('<div />', {id: uuid})
146 .addClass('nav')
146 .addClass('nav')
147 .addClass('nav-tabs')
147 .addClass('nav-tabs')
148 .appendTo(this.$el);
148 .appendTo(this.$el);
149 this.$tab_contents = $('<div />', {id: uuid + 'Content'})
149 this.$tab_contents = $('<div />', {id: uuid + 'Content'})
150 .addClass('tab-content')
150 .addClass('tab-content')
151 .appendTo(this.$el);
151 .appendTo(this.$el);
152 this.containers = [];
152 this.containers = [];
153 this.update_children([], this.model.get('_children'));
153 this.update_children([], this.model.get('_children'));
154 this.model.on('change:_children', function(model, value, options) {
154 this.model.on('change:_children', function(model, value, options) {
155 this.update_children(model.previous('_children'), value);
155 this.update_children(model.previous('_children'), value);
156 }, this);
156 }, this);
157 },
157 },
158
158
159 update_children: function(old_list, new_list) {
159 update_children: function(old_list, new_list) {
160 // Called when the children list is modified.
160 // Called when the children list is modified.
161 this.do_diff(old_list,
161 this.do_diff(old_list,
162 new_list,
162 new_list,
163 $.proxy(this.remove_child_model, this),
163 $.proxy(this.remove_child_model, this),
164 $.proxy(this.add_child_model, this));
164 $.proxy(this.add_child_model, this));
165 },
165 },
166
166
167 remove_child_model: function(model) {
167 remove_child_model: function(model) {
168 // Called when a child is removed from children list.
168 // Called when a child is removed from children list.
169 var view = this.child_views[model.id];
169 var view = this.child_views[model.id];
170 this.containers.splice(view.parent_tab.tab_text_index, 1);
170 this.containers.splice(view.parent_tab.tab_text_index, 1);
171 view.parent_tab.remove();
171 view.parent_tab.remove();
172 view.parent_container.remove();
172 view.parent_container.remove();
173 view.remove();
173 view.remove();
174 this.delete_child_view(model);
174 this.delete_child_view(model);
175 },
175 },
176
176
177 add_child_model: function(model) {
177 add_child_model: function(model) {
178 // Called when a child is added to children list.
178 // Called when a child is added to children list.
179 var view = this.create_child_view(model);
179 var view = this.create_child_view(model);
180 var index = this.containers.length;
180 var index = this.containers.length;
181 var uuid = IPython.utils.uuid();
181 var uuid = IPython.utils.uuid();
182
182
183 var that = this;
183 var that = this;
184 var tab = $('<li />')
184 var tab = $('<li />')
185 .css('list-style-type', 'none')
185 .css('list-style-type', 'none')
186 .appendTo(this.$tabs);
186 .appendTo(this.$tabs);
187 view.parent_tab = tab;
187 view.parent_tab = tab;
188
188
189 var tab_text = $('<a />')
189 var tab_text = $('<a />')
190 .attr('href', '#' + uuid)
190 .attr('href', '#' + uuid)
191 .attr('data-toggle', 'tab')
191 .attr('data-toggle', 'tab')
192 .text('Page ' + index)
192 .text('Page ' + index)
193 .appendTo(tab)
193 .appendTo(tab)
194 .click(function (e) {
194 .click(function (e) {
195
195
196 // Calling model.set will trigger all of the other views of the
196 // Calling model.set will trigger all of the other views of the
197 // model to update.
197 // model to update.
198 that.model.set("selected_index", index, {updated_view: this});
198 that.model.set("selected_index", index, {updated_view: this});
199 that.touch();
199 that.touch();
200 that.select_page(index);
200 that.select_page(index);
201 });
201 });
202 tab.tab_text_index = this.containers.push(tab_text) - 1;
202 tab.tab_text_index = this.containers.push(tab_text) - 1;
203
203
204 var contents_div = $('<div />', {id: uuid})
204 var contents_div = $('<div />', {id: uuid})
205 .addClass('tab-pane')
205 .addClass('tab-pane')
206 .addClass('fade')
206 .addClass('fade')
207 .append(view.$el)
207 .append(view.$el)
208 .appendTo(this.$tab_contents);
208 .appendTo(this.$tab_contents);
209 view.parent_container = contents_div;
209 view.parent_container = contents_div;
210 },
210 },
211
211
212 update: function(options) {
212 update: function(options) {
213 // Update the contents of this view
213 // Update the contents of this view
214 //
214 //
215 // Called when the model is changed. The model may have been
215 // Called when the model is changed. The model may have been
216 // changed by another view or by a state update from the back-end.
216 // changed by another view or by a state update from the back-end.
217 if (options === undefined || options.updated_view != this) {
217 if (options === undefined || options.updated_view != this) {
218 // Set tab titles
218 // Set tab titles
219 var titles = this.model.get('_titles');
219 var titles = this.model.get('_titles');
220 var that = this;
220 var that = this;
221 _.each(titles, function(title, page_index) {
221 _.each(titles, function(title, page_index) {
222 var tab_text = that.containers[page_index];
222 var tab_text = that.containers[page_index];
223 if (tab_text !== undefined) {
223 if (tab_text !== undefined) {
224 tab_text.text(title);
224 tab_text.text(title);
225 }
225 }
226 });
226 });
227
227
228 var selected_index = this.model.get('selected_index');
228 var selected_index = this.model.get('selected_index');
229 if (0 <= selected_index && selected_index < this.containers.length) {
229 if (0 <= selected_index && selected_index < this.containers.length) {
230 this.select_page(selected_index);
230 this.select_page(selected_index);
231 }
231 }
232 }
232 }
233 return TabView.__super__.update.apply(this);
233 return TabView.__super__.update.apply(this);
234 },
234 },
235
235
236 select_page: function(index) {
236 select_page: function(index) {
237 // Select a page.
237 // Select a page.
238 this.$tabs.find('li')
238 this.$tabs.find('li')
239 .removeClass('active');
239 .removeClass('active');
240 this.containers[index].tab('show');
240 this.containers[index].tab('show');
241 },
241 },
242 });
242 });
243 WidgetManager.register_widget_view('TabView', TabView);
243 WidgetManager.register_widget_view('TabView', TabView);
244 });
244 });
@@ -1,222 +1,222
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(WidgetManager){
17 define(["widgets/js/widget"], function(WidgetManager){
18
18
19 var HTMLView = IPython.DOMWidgetView.extend({
19 var HTMLView = IPython.DOMWidgetView.extend({
20 render : function(){
20 render : function(){
21 // Called when view is rendered.
21 // Called when view is rendered.
22 this.update(); // Set defaults.
22 this.update(); // Set defaults.
23 },
23 },
24
24
25 update : function(){
25 update : function(){
26 // Update the contents of this view
26 // Update the contents of this view
27 //
27 //
28 // Called when the model is changed. The model may have been
28 // Called when the model is changed. The model may have been
29 // changed by another view or by a state update from the back-end.
29 // changed by another view or by a state update from the back-end.
30 this.$el.html(this.model.get('value')); // CAUTION! .html(...) CALL MANDITORY!!!
30 this.$el.html(this.model.get('value')); // CAUTION! .html(...) CALL MANDITORY!!!
31 return HTMLView.__super__.update.apply(this);
31 return HTMLView.__super__.update.apply(this);
32 },
32 },
33 });
33 });
34 WidgetManager.register_widget_view('HTMLView', HTMLView);
34 WidgetManager.register_widget_view('HTMLView', HTMLView);
35
35
36
36
37 var LatexView = IPython.DOMWidgetView.extend({
37 var LatexView = IPython.DOMWidgetView.extend({
38 render : function(){
38 render : function(){
39 // Called when view is rendered.
39 // Called when view is rendered.
40 this.update(); // Set defaults.
40 this.update(); // Set defaults.
41 },
41 },
42
42
43 update : function(){
43 update : function(){
44 // Update the contents of this view
44 // Update the contents of this view
45 //
45 //
46 // Called when the model is changed. The model may have been
46 // Called when the model is changed. The model may have been
47 // changed by another view or by a state update from the back-end.
47 // changed by another view or by a state update from the back-end.
48 this.$el.text(this.model.get('value'));
48 this.$el.text(this.model.get('value'));
49 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$el.get(0)]);
49 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$el.get(0)]);
50
50
51 return LatexView.__super__.update.apply(this);
51 return LatexView.__super__.update.apply(this);
52 },
52 },
53 });
53 });
54 WidgetManager.register_widget_view('LatexView', LatexView);
54 WidgetManager.register_widget_view('LatexView', LatexView);
55
55
56
56
57 var TextareaView = IPython.DOMWidgetView.extend({
57 var TextareaView = IPython.DOMWidgetView.extend({
58 render: function(){
58 render: function(){
59 // Called when view is rendered.
59 // Called when view is rendered.
60 this.$el
60 this.$el
61 .addClass('widget-hbox');
61 .addClass('widget-hbox');
62 this.$label = $('<div />')
62 this.$label = $('<div />')
63 .appendTo(this.$el)
63 .appendTo(this.$el)
64 .addClass('widget-hlabel')
64 .addClass('widget-hlabel')
65 .hide();
65 .hide();
66 this.$textbox = $('<textarea />')
66 this.$textbox = $('<textarea />')
67 .attr('rows', 5)
67 .attr('rows', 5)
68 .addClass('widget-text')
68 .addClass('widget-text')
69 .appendTo(this.$el);
69 .appendTo(this.$el);
70 this.$el_to_style = this.$textbox; // Set default element to style
70 this.$el_to_style = this.$textbox; // Set default element to style
71 this.update(); // Set defaults.
71 this.update(); // Set defaults.
72
72
73 this.model.on('msg:custom', $.proxy(this._handle_textarea_msg, this));
73 this.model.on('msg:custom', $.proxy(this._handle_textarea_msg, this));
74 },
74 },
75
75
76 _handle_textarea_msg: function (content){
76 _handle_textarea_msg: function (content){
77 // Handle when a custom msg is recieved from the back-end.
77 // Handle when a custom msg is recieved from the back-end.
78 if (content.method == "scroll_to_bottom") {
78 if (content.method == "scroll_to_bottom") {
79 this.scroll_to_bottom();
79 this.scroll_to_bottom();
80 }
80 }
81 },
81 },
82
82
83 scroll_to_bottom: function (){
83 scroll_to_bottom: function (){
84 // Scroll the text-area view to the bottom.
84 // Scroll the text-area view to the bottom.
85 this.$textbox.scrollTop(this.$textbox[0].scrollHeight);
85 this.$textbox.scrollTop(this.$textbox[0].scrollHeight);
86 },
86 },
87
87
88 update: function(options){
88 update: function(options){
89 // Update the contents of this view
89 // Update the contents of this view
90 //
90 //
91 // Called when the model is changed. The model may have been
91 // Called when the model is changed. The model may have been
92 // changed by another view or by a state update from the back-end.
92 // changed by another view or by a state update from the back-end.
93 if (options === undefined || options.updated_view != this) {
93 if (options === undefined || options.updated_view != this) {
94 this.$textbox.val(this.model.get('value'));
94 this.$textbox.val(this.model.get('value'));
95
95
96 var disabled = this.model.get('disabled');
96 var disabled = this.model.get('disabled');
97 this.$textbox.prop('disabled', disabled);
97 this.$textbox.prop('disabled', disabled);
98
98
99 var description = this.model.get('description');
99 var description = this.model.get('description');
100 if (description.length === 0) {
100 if (description.length === 0) {
101 this.$label.hide();
101 this.$label.hide();
102 } else {
102 } else {
103 this.$label.text(description);
103 this.$label.text(description);
104 this.$label.show();
104 this.$label.show();
105 }
105 }
106 }
106 }
107 return TextareaView.__super__.update.apply(this);
107 return TextareaView.__super__.update.apply(this);
108 },
108 },
109
109
110 events: {
110 events: {
111 // Dictionary of events and their handlers.
111 // Dictionary of events and their handlers.
112 "keyup textarea" : "handleChanging",
112 "keyup textarea" : "handleChanging",
113 "paste textarea" : "handleChanging",
113 "paste textarea" : "handleChanging",
114 "cut textarea" : "handleChanging"
114 "cut textarea" : "handleChanging"
115 },
115 },
116
116
117 handleChanging: function(e) {
117 handleChanging: function(e) {
118 // Handles and validates user input.
118 // Handles and validates user input.
119
119
120 // 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
121 // model to update.
121 // model to update.
122 this.model.set('value', e.target.value, {updated_view: this});
122 this.model.set('value', e.target.value, {updated_view: this});
123 this.touch();
123 this.touch();
124 },
124 },
125 });
125 });
126 WidgetManager.register_widget_view('TextareaView', TextareaView);
126 WidgetManager.register_widget_view('TextareaView', TextareaView);
127
127
128
128
129 var TextView = IPython.DOMWidgetView.extend({
129 var TextView = IPython.DOMWidgetView.extend({
130 render: function(){
130 render: function(){
131 // Called when view is rendered.
131 // Called when view is rendered.
132 this.$el
132 this.$el
133 .addClass('widget-hbox-single');
133 .addClass('widget-hbox-single');
134 this.$label = $('<div />')
134 this.$label = $('<div />')
135 .addClass('widget-hlabel')
135 .addClass('widget-hlabel')
136 .appendTo(this.$el)
136 .appendTo(this.$el)
137 .hide();
137 .hide();
138 this.$textbox = $('<input type="text" />')
138 this.$textbox = $('<input type="text" />')
139 .addClass('input')
139 .addClass('input')
140 .addClass('widget-text')
140 .addClass('widget-text')
141 .appendTo(this.$el);
141 .appendTo(this.$el);
142 this.$el_to_style = this.$textbox; // Set default element to style
142 this.$el_to_style = this.$textbox; // Set default element to style
143 this.update(); // Set defaults.
143 this.update(); // Set defaults.
144 },
144 },
145
145
146 update: function(options){
146 update: function(options){
147 // Update the contents of this view
147 // Update the contents of this view
148 //
148 //
149 // Called when the model is changed. The model may have been
149 // Called when the model is changed. The model may have been
150 // 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.
151 if (options === undefined || options.updated_view != this) {
151 if (options === undefined || options.updated_view != this) {
152 if (this.$textbox.val() != this.model.get('value')) {
152 if (this.$textbox.val() != this.model.get('value')) {
153 this.$textbox.val(this.model.get('value'));
153 this.$textbox.val(this.model.get('value'));
154 }
154 }
155
155
156 var disabled = this.model.get('disabled');
156 var disabled = this.model.get('disabled');
157 this.$textbox.prop('disabled', disabled);
157 this.$textbox.prop('disabled', disabled);
158
158
159 var description = this.model.get('description');
159 var description = this.model.get('description');
160 if (description.length === 0) {
160 if (description.length === 0) {
161 this.$label.hide();
161 this.$label.hide();
162 } else {
162 } else {
163 this.$label.text(description);
163 this.$label.text(description);
164 this.$label.show();
164 this.$label.show();
165 }
165 }
166 }
166 }
167 return TextView.__super__.update.apply(this);
167 return TextView.__super__.update.apply(this);
168 },
168 },
169
169
170 events: {
170 events: {
171 // Dictionary of events and their handlers.
171 // Dictionary of events and their handlers.
172 "keyup input" : "handleChanging",
172 "keyup input" : "handleChanging",
173 "paste input" : "handleChanging",
173 "paste input" : "handleChanging",
174 "cut input" : "handleChanging",
174 "cut input" : "handleChanging",
175 "keypress input" : "handleKeypress",
175 "keypress input" : "handleKeypress",
176 "blur input" : "handleBlur",
176 "blur input" : "handleBlur",
177 "focusout input" : "handleFocusOut"
177 "focusout input" : "handleFocusOut"
178 },
178 },
179
179
180 handleChanging: function(e) {
180 handleChanging: function(e) {
181 // Handles user input.
181 // Handles user input.
182
182
183 // Calling model.set will trigger all of the other views of the
183 // Calling model.set will trigger all of the other views of the
184 // model to update.
184 // model to update.
185 this.model.set('value', e.target.value, {updated_view: this});
185 this.model.set('value', e.target.value, {updated_view: this});
186 this.touch();
186 this.touch();
187 },
187 },
188
188
189 handleKeypress: function(e) {
189 handleKeypress: function(e) {
190 // Handles text submition
190 // Handles text submition
191 if (e.keyCode == 13) { // Return key
191 if (e.keyCode == 13) { // Return key
192 this.send({event: 'submit'});
192 this.send({event: 'submit'});
193 event.stopPropagation();
193 event.stopPropagation();
194 event.preventDefault();
194 event.preventDefault();
195 return false;
195 return false;
196 }
196 }
197 },
197 },
198
198
199 handleBlur: function(e) {
199 handleBlur: function(e) {
200 // Prevent a blur from firing if the blur was not user intended.
200 // Prevent a blur from firing if the blur was not user intended.
201 // This is a workaround for the return-key focus loss bug.
201 // This is a workaround for the return-key focus loss bug.
202 // TODO: Is the original bug actually a fault of the keyboard
202 // TODO: Is the original bug actually a fault of the keyboard
203 // manager?
203 // manager?
204 if (e.relatedTarget === null) {
204 if (e.relatedTarget === null) {
205 event.stopPropagation();
205 event.stopPropagation();
206 event.preventDefault();
206 event.preventDefault();
207 return false;
207 return false;
208 }
208 }
209 },
209 },
210
210
211 handleFocusOut: function(e) {
211 handleFocusOut: function(e) {
212 // Prevent a blur from firing if the blur was not user intended.
212 // Prevent a blur from firing if the blur was not user intended.
213 // This is a workaround for the return-key focus loss bug.
213 // This is a workaround for the return-key focus loss bug.
214 if (e.relatedTarget === null) {
214 if (e.relatedTarget === null) {
215 event.stopPropagation();
215 event.stopPropagation();
216 event.preventDefault();
216 event.preventDefault();
217 return false;
217 return false;
218 }
218 }
219 },
219 },
220 });
220 });
221 WidgetManager.register_widget_view('TextView', TextView);
221 WidgetManager.register_widget_view('TextView', TextView);
222 });
222 });
General Comments 0
You need to be logged in to leave comments. Login now