##// END OF EJS Templates
s/view_name/_view_name
Jonathan Frederic -
Show More
@@ -1,197 +1,197 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2013 The IPython Development Team
2 // Copyright (C) 2013 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // WidgetModel, WidgetView, and WidgetManager
9 // WidgetModel, WidgetView, and WidgetManager
10 //============================================================================
10 //============================================================================
11 /**
11 /**
12 * Base Widget classes
12 * Base Widget classes
13 * @module IPython
13 * @module IPython
14 * @namespace IPython
14 * @namespace IPython
15 * @submodule widget
15 * @submodule widget
16 */
16 */
17
17
18 (function () {
18 (function () {
19 "use strict";
19 "use strict";
20
20
21 // Use require.js 'define' method so that require.js is intelligent enough to
21 // Use require.js 'define' method so that require.js is intelligent enough to
22 // syncronously load everything within this file when it is being 'required'
22 // syncronously load everything within this file when it is being 'required'
23 // elsewhere.
23 // elsewhere.
24 define(["underscore",
24 define(["underscore",
25 "backbone",
25 "backbone",
26 ], function (Underscore, Backbone) {
26 ], function (Underscore, Backbone) {
27
27
28 //--------------------------------------------------------------------
28 //--------------------------------------------------------------------
29 // WidgetManager class
29 // WidgetManager class
30 //--------------------------------------------------------------------
30 //--------------------------------------------------------------------
31 var WidgetManager = function (comm_manager) {
31 var WidgetManager = function (comm_manager) {
32 // Public constructor
32 // Public constructor
33 WidgetManager._managers.push(this);
33 WidgetManager._managers.push(this);
34
34
35 // Attach a comm manager to the
35 // Attach a comm manager to the
36 this.comm_manager = comm_manager;
36 this.comm_manager = comm_manager;
37 this._models = {}; /* Dictionary of model ids and model instances */
37 this._models = {}; /* Dictionary of model ids and model instances */
38
38
39 // Register already-registered widget model types with the comm manager.
39 // Register already-registered widget model types with the comm manager.
40 var that = this;
40 var that = this;
41 _.each(WidgetManager._model_types, function(model_type, model_name) {
41 _.each(WidgetManager._model_types, function(model_type, model_name) {
42 that.comm_manager.register_target(model_name, $.proxy(that._handle_comm_open, that));
42 that.comm_manager.register_target(model_name, $.proxy(that._handle_comm_open, that));
43 });
43 });
44 };
44 };
45
45
46 //--------------------------------------------------------------------
46 //--------------------------------------------------------------------
47 // Class level
47 // Class level
48 //--------------------------------------------------------------------
48 //--------------------------------------------------------------------
49 WidgetManager._model_types = {}; /* Dictionary of model type names (target_name) and model types. */
49 WidgetManager._model_types = {}; /* Dictionary of model type names (target_name) and model types. */
50 WidgetManager._view_types = {}; /* Dictionary of view names and view types. */
50 WidgetManager._view_types = {}; /* Dictionary of view names and view types. */
51 WidgetManager._managers = []; /* List of widget managers */
51 WidgetManager._managers = []; /* List of widget managers */
52
52
53 WidgetManager.register_widget_model = function (model_name, model_type) {
53 WidgetManager.register_widget_model = function (model_name, model_type) {
54 // Registers a widget model by name.
54 // Registers a widget model by name.
55 WidgetManager._model_types[model_name] = model_type;
55 WidgetManager._model_types[model_name] = model_type;
56
56
57 // Register the widget with the comm manager. Make sure to pass this object's context
57 // Register the widget with the comm manager. Make sure to pass this object's context
58 // in so `this` works in the call back.
58 // in so `this` works in the call back.
59 _.each(WidgetManager._managers, function(instance, i) {
59 _.each(WidgetManager._managers, function(instance, i) {
60 if (instance.comm_manager !== null) {
60 if (instance.comm_manager !== null) {
61 instance.comm_manager.register_target(model_name, $.proxy(instance._handle_comm_open, instance));
61 instance.comm_manager.register_target(model_name, $.proxy(instance._handle_comm_open, instance));
62 }
62 }
63 });
63 });
64 };
64 };
65
65
66 WidgetManager.register_widget_view = function (view_name, view_type) {
66 WidgetManager.register_widget_view = function (view_name, view_type) {
67 // Registers a widget view by name.
67 // Registers a widget view by name.
68 WidgetManager._view_types[view_name] = view_type;
68 WidgetManager._view_types[view_name] = view_type;
69 };
69 };
70
70
71 //--------------------------------------------------------------------
71 //--------------------------------------------------------------------
72 // Instance level
72 // Instance level
73 //--------------------------------------------------------------------
73 //--------------------------------------------------------------------
74 WidgetManager.prototype.display_view = function(msg, model) {
74 WidgetManager.prototype.display_view = function(msg, model) {
75 var cell = this.get_msg_cell(msg.parent_header.msg_id);
75 var cell = this.get_msg_cell(msg.parent_header.msg_id);
76 if (cell === null) {
76 if (cell === null) {
77 console.log("Could not determine where the display" +
77 console.log("Could not determine where the display" +
78 " message was from. Widget will not be displayed");
78 " message was from. Widget will not be displayed");
79 } else {
79 } else {
80 var view = this.create_view(model, {cell: cell});
80 var view = this.create_view(model, {cell: cell});
81 if (view === null) {
81 if (view === null) {
82 console.error("View creation failed", model);
82 console.error("View creation failed", model);
83 }
83 }
84 if (cell.widget_subarea !== undefined
84 if (cell.widget_subarea !== undefined
85 && cell.widget_subarea !== null) {
85 && cell.widget_subarea !== null) {
86
86
87 cell.widget_area.show();
87 cell.widget_area.show();
88 cell.widget_subarea.append(view.$el);
88 cell.widget_subarea.append(view.$el);
89 }
89 }
90 }
90 }
91 },
91 },
92
92
93 WidgetManager.prototype.create_view = function(model, options, view) {
93 WidgetManager.prototype.create_view = function(model, options, view) {
94 var view_name = model.get('view_name');
94 var view_name = model.get('_view_name');
95 var ViewType = WidgetManager._view_types[view_name];
95 var ViewType = WidgetManager._view_types[view_name];
96 if (ViewType !== undefined && ViewType !== null) {
96 if (ViewType !== undefined && ViewType !== null) {
97
97
98 // If a view is passed into the method, use that view's cell as
98 // If a view is passed into the method, use that view's cell as
99 // the cell for the view that is created.
99 // the cell for the view that is created.
100 options = options || {};
100 options = options || {};
101 if (view !== undefined) {
101 if (view !== undefined) {
102 options.cell = view.options.cell;
102 options.cell = view.options.cell;
103 }
103 }
104
104
105 var parameters = {model: model, options: options};
105 var parameters = {model: model, options: options};
106 var view = new ViewType(parameters);
106 var view = new ViewType(parameters);
107 view.render();
107 view.render();
108 IPython.keyboard_manager.register_events(view.$el);
108 IPython.keyboard_manager.register_events(view.$el);
109 model.views.push(view);
109 model.views.push(view);
110 model.on('destroy', view.remove, view);
110 model.on('destroy', view.remove, view);
111 return view;
111 return view;
112 }
112 }
113 return null;
113 return null;
114 },
114 },
115
115
116 WidgetManager.prototype.get_msg_cell = function (msg_id) {
116 WidgetManager.prototype.get_msg_cell = function (msg_id) {
117 var cell = null;
117 var cell = null;
118 // First, check to see if the msg was triggered by cell execution.
118 // First, check to see if the msg was triggered by cell execution.
119 if (IPython.notebook !== undefined && IPython.notebook !== null) {
119 if (IPython.notebook !== undefined && IPython.notebook !== null) {
120 cell = IPython.notebook.get_msg_cell(msg_id);
120 cell = IPython.notebook.get_msg_cell(msg_id);
121 }
121 }
122 if (cell !== null) {
122 if (cell !== null) {
123 return cell
123 return cell
124 }
124 }
125 // Second, check to see if a get_cell callback was defined
125 // Second, check to see if a get_cell callback was defined
126 // for the message. get_cell callbacks are registered for
126 // for the message. get_cell callbacks are registered for
127 // widget messages, so this block is actually checking to see if the
127 // widget messages, so this block is actually checking to see if the
128 // message was triggered by a widget.
128 // message was triggered by a widget.
129 var kernel = this.comm_manager.kernel;
129 var kernel = this.comm_manager.kernel;
130 if (kernel !== undefined && kernel !== null) {
130 if (kernel !== undefined && kernel !== null) {
131 var callbacks = kernel.get_callbacks_for_msg(msg_id);
131 var callbacks = kernel.get_callbacks_for_msg(msg_id);
132 if (callbacks !== undefined &&
132 if (callbacks !== undefined &&
133 callbacks.iopub !== undefined &&
133 callbacks.iopub !== undefined &&
134 callbacks.iopub.get_cell !== undefined) {
134 callbacks.iopub.get_cell !== undefined) {
135
135
136 return callbacks.iopub.get_cell();
136 return callbacks.iopub.get_cell();
137 }
137 }
138 }
138 }
139
139
140 // Not triggered by a cell or widget (no get_cell callback
140 // Not triggered by a cell or widget (no get_cell callback
141 // exists).
141 // exists).
142 return null;
142 return null;
143 };
143 };
144
144
145 WidgetManager.prototype.callbacks = function (view) {
145 WidgetManager.prototype.callbacks = function (view) {
146 // callback handlers specific a view
146 // callback handlers specific a view
147 var callbacks = {};
147 var callbacks = {};
148 var cell = view.options.cell;
148 var cell = view.options.cell;
149 if (cell !== null) {
149 if (cell !== null) {
150 // Try to get output handlers
150 // Try to get output handlers
151 var handle_output = null;
151 var handle_output = null;
152 var handle_clear_output = null;
152 var handle_clear_output = null;
153 if (cell.output_area !== undefined && cell.output_area !== null) {
153 if (cell.output_area !== undefined && cell.output_area !== null) {
154 handle_output = $.proxy(cell.output_area.handle_output, cell.output_area);
154 handle_output = $.proxy(cell.output_area.handle_output, cell.output_area);
155 handle_clear_output = $.proxy(cell.output_area.handle_clear_output, cell.output_area);
155 handle_clear_output = $.proxy(cell.output_area.handle_clear_output, cell.output_area);
156 }
156 }
157
157
158 // Create callback dict using what is known
158 // Create callback dict using what is known
159 var that = this;
159 var that = this;
160 callbacks = {
160 callbacks = {
161 iopub : {
161 iopub : {
162 output : handle_output,
162 output : handle_output,
163 clear_output : handle_clear_output,
163 clear_output : handle_clear_output,
164
164
165 // Special function only registered by widget messages.
165 // Special function only registered by widget messages.
166 // Allows us to get the cell for a message so we know
166 // Allows us to get the cell for a message so we know
167 // where to add widgets if the code requires it.
167 // where to add widgets if the code requires it.
168 get_cell : function () {
168 get_cell : function () {
169 return cell;
169 return cell;
170 },
170 },
171 },
171 },
172 };
172 };
173 }
173 }
174 return callbacks;
174 return callbacks;
175 };
175 };
176
176
177 WidgetManager.prototype.get_model = function (model_id) {
177 WidgetManager.prototype.get_model = function (model_id) {
178 // Look-up a model instance by its id.
178 // Look-up a model instance by its id.
179 var model = this._models[model_id];
179 var model = this._models[model_id];
180 if (model !== undefined && model.id == model_id) {
180 if (model !== undefined && model.id == model_id) {
181 return model;
181 return model;
182 }
182 }
183 return null;
183 return null;
184 };
184 };
185
185
186 WidgetManager.prototype._handle_comm_open = function (comm, msg) {
186 WidgetManager.prototype._handle_comm_open = function (comm, msg) {
187 // Handle when a comm is opened.
187 // Handle when a comm is opened.
188 var model_id = comm.comm_id;
188 var model_id = comm.comm_id;
189 var widget_type_name = msg.content.target_name;
189 var widget_type_name = msg.content.target_name;
190 var widget_model = new WidgetManager._model_types[widget_type_name](this, model_id, comm);
190 var widget_model = new WidgetManager._model_types[widget_type_name](this, model_id, comm);
191 this._models[model_id] = widget_model;
191 this._models[model_id] = widget_model;
192 };
192 };
193
193
194 IPython.WidgetManager = WidgetManager;
194 IPython.WidgetManager = WidgetManager;
195 return IPython.WidgetManager;
195 return IPython.WidgetManager;
196 });
196 });
197 }());
197 }());
@@ -1,483 +1,483 b''
1 """Base Widget class. Allows user to create widgets in the back-end that render
1 """Base Widget class. Allows user to create widgets in the back-end that render
2 in the IPython notebook front-end.
2 in the IPython notebook front-end.
3 """
3 """
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2013, the IPython Development Team.
5 # Copyright (c) 2013, the IPython Development Team.
6 #
6 #
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8 #
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 from contextlib import contextmanager
15 from contextlib import contextmanager
16 import inspect
16 import inspect
17 import types
17 import types
18
18
19 from IPython.kernel.comm import Comm
19 from IPython.kernel.comm import Comm
20 from IPython.config import LoggingConfigurable
20 from IPython.config import LoggingConfigurable
21 from IPython.utils.traitlets import Unicode, Dict, Instance, Bool, List
21 from IPython.utils.traitlets import Unicode, Dict, Instance, Bool, List
22 from IPython.utils.py3compat import string_types
22 from IPython.utils.py3compat import string_types
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Classes
25 # Classes
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 class CallbackDispatcher(LoggingConfigurable):
27 class CallbackDispatcher(LoggingConfigurable):
28 acceptable_nargs = List([], help="""List of integers.
28 acceptable_nargs = List([], help="""List of integers.
29 The number of arguments in the callbacks registered must match one of
29 The number of arguments in the callbacks registered must match one of
30 the integers in this list. If this list is empty or None, it will be
30 the integers in this list. If this list is empty or None, it will be
31 ignored.""")
31 ignored.""")
32
32
33 def __init__(self, *pargs, **kwargs):
33 def __init__(self, *pargs, **kwargs):
34 """Constructor"""
34 """Constructor"""
35 LoggingConfigurable.__init__(self, *pargs, **kwargs)
35 LoggingConfigurable.__init__(self, *pargs, **kwargs)
36 self.callbacks = {}
36 self.callbacks = {}
37
37
38 def __call__(self, *pargs, **kwargs):
38 def __call__(self, *pargs, **kwargs):
39 """Call all of the registered callbacks that have the same number of
39 """Call all of the registered callbacks that have the same number of
40 positional arguments."""
40 positional arguments."""
41 nargs = len(pargs)
41 nargs = len(pargs)
42 self._validate_nargs(nargs)
42 self._validate_nargs(nargs)
43 if nargs in self.callbacks:
43 if nargs in self.callbacks:
44 for callback in self.callbacks[nargs]:
44 for callback in self.callbacks[nargs]:
45 callback(*pargs, **kwargs)
45 callback(*pargs, **kwargs)
46
46
47 def register_callback(self, callback, remove=False):
47 def register_callback(self, callback, remove=False):
48 """(Un)Register a callback
48 """(Un)Register a callback
49
49
50 Parameters
50 Parameters
51 ----------
51 ----------
52 callback: method handle
52 callback: method handle
53 Method to be registered or unregisted.
53 Method to be registered or unregisted.
54 remove=False: bool
54 remove=False: bool
55 Whether or not to unregister the callback."""
55 Whether or not to unregister the callback."""
56
56
57 # Validate the number of arguments that the callback accepts.
57 # Validate the number of arguments that the callback accepts.
58 nargs = self._get_nargs(callback)
58 nargs = self._get_nargs(callback)
59 self._validate_nargs(nargs)
59 self._validate_nargs(nargs)
60
60
61 # Get/create the appropriate list of callbacks.
61 # Get/create the appropriate list of callbacks.
62 if nargs not in self.callbacks:
62 if nargs not in self.callbacks:
63 self.callbacks[nargs] = []
63 self.callbacks[nargs] = []
64 callback_list = self.callbacks[nargs]
64 callback_list = self.callbacks[nargs]
65
65
66 # (Un)Register the callback.
66 # (Un)Register the callback.
67 if remove and callback in callback_list:
67 if remove and callback in callback_list:
68 callback_list.remove(callback)
68 callback_list.remove(callback)
69 elif not remove and callback not in callback_list:
69 elif not remove and callback not in callback_list:
70 callback_list.append(callback)
70 callback_list.append(callback)
71
71
72 def _validate_nargs(self, nargs):
72 def _validate_nargs(self, nargs):
73 if self.acceptable_nargs is not None and \
73 if self.acceptable_nargs is not None and \
74 len(self.acceptable_nargs) > 0 and \
74 len(self.acceptable_nargs) > 0 and \
75 nargs not in self.acceptable_nargs:
75 nargs not in self.acceptable_nargs:
76
76
77 raise TypeError('Invalid number of positional arguments. See acceptable_nargs list.')
77 raise TypeError('Invalid number of positional arguments. See acceptable_nargs list.')
78
78
79 def _get_nargs(self, callback):
79 def _get_nargs(self, callback):
80 """Gets the number of arguments in a callback"""
80 """Gets the number of arguments in a callback"""
81 if callable(callback):
81 if callable(callback):
82 argspec = inspect.getargspec(callback)
82 argspec = inspect.getargspec(callback)
83 if argspec[0] is None:
83 if argspec[0] is None:
84 nargs = 0
84 nargs = 0
85 elif argspec[3] is None:
85 elif argspec[3] is None:
86 nargs = len(argspec[0]) # Only count vargs!
86 nargs = len(argspec[0]) # Only count vargs!
87 else:
87 else:
88 nargs = len(argspec[0]) - len(argspec[3]) # Subtract number of defaults.
88 nargs = len(argspec[0]) - len(argspec[3]) # Subtract number of defaults.
89
89
90 # Bound methods have an additional 'self' argument
90 # Bound methods have an additional 'self' argument
91 if isinstance(callback, types.MethodType):
91 if isinstance(callback, types.MethodType):
92 nargs -= 1
92 nargs -= 1
93 return nargs
93 return nargs
94 else:
94 else:
95 raise TypeError('Callback must be callable.')
95 raise TypeError('Callback must be callable.')
96
96
97
97
98 class Widget(LoggingConfigurable):
98 class Widget(LoggingConfigurable):
99 #-------------------------------------------------------------------------
99 #-------------------------------------------------------------------------
100 # Class attributes
100 # Class attributes
101 #-------------------------------------------------------------------------
101 #-------------------------------------------------------------------------
102 widget_construction_callback = None
102 widget_construction_callback = None
103 widgets = {}
103 widgets = {}
104
104
105 def on_widget_constructed(callback):
105 def on_widget_constructed(callback):
106 """Registers a callback to be called when a widget is constructed.
106 """Registers a callback to be called when a widget is constructed.
107
107
108 The callback must have the following signature:
108 The callback must have the following signature:
109 callback(widget)"""
109 callback(widget)"""
110 Widget.widget_construction_callback = callback
110 Widget.widget_construction_callback = callback
111
111
112 def _call_widget_constructed(widget):
112 def _call_widget_constructed(widget):
113 """Class method, called when a widget is constructed."""
113 """Class method, called when a widget is constructed."""
114 if Widget.widget_construction_callback is not None and callable(Widget.widget_construction_callback):
114 if Widget.widget_construction_callback is not None and callable(Widget.widget_construction_callback):
115 Widget.widget_construction_callback(widget)
115 Widget.widget_construction_callback(widget)
116
116
117 #-------------------------------------------------------------------------
117 #-------------------------------------------------------------------------
118 # Traits
118 # Traits
119 #-------------------------------------------------------------------------
119 #-------------------------------------------------------------------------
120 model_name = Unicode('WidgetModel', help="""Name of the backbone model
120 model_name = Unicode('WidgetModel', help="""Name of the backbone model
121 registered in the front-end to create and sync this widget with.""")
121 registered in the front-end to create and sync this widget with.""")
122 view_name = Unicode(help="""Default view registered in the front-end
122 _view_name = Unicode(help="""Default view registered in the front-end
123 to use to represent the widget.""", sync=True)
123 to use to represent the widget.""", sync=True)
124 _comm = Instance('IPython.kernel.comm.Comm')
124 _comm = Instance('IPython.kernel.comm.Comm')
125
125
126 #-------------------------------------------------------------------------
126 #-------------------------------------------------------------------------
127 # (Con/de)structor
127 # (Con/de)structor
128 #-------------------------------------------------------------------------
128 #-------------------------------------------------------------------------
129 def __init__(self, **kwargs):
129 def __init__(self, **kwargs):
130 """Public constructor"""
130 """Public constructor"""
131 self.closed = False
131 self.closed = False
132
132
133 self._property_lock = (None, None)
133 self._property_lock = (None, None)
134 self._keys = None
134 self._keys = None
135
135
136 self._display_callbacks = CallbackDispatcher(acceptable_nargs=[0])
136 self._display_callbacks = CallbackDispatcher(acceptable_nargs=[0])
137 self._msg_callbacks = CallbackDispatcher(acceptable_nargs=[1, 2])
137 self._msg_callbacks = CallbackDispatcher(acceptable_nargs=[1, 2])
138
138
139 super(Widget, self).__init__(**kwargs)
139 super(Widget, self).__init__(**kwargs)
140
140
141 self.on_trait_change(self._handle_property_changed, self.keys)
141 self.on_trait_change(self._handle_property_changed, self.keys)
142 Widget._call_widget_constructed(self)
142 Widget._call_widget_constructed(self)
143
143
144 def __del__(self):
144 def __del__(self):
145 """Object disposal"""
145 """Object disposal"""
146 self.close()
146 self.close()
147
147
148 #-------------------------------------------------------------------------
148 #-------------------------------------------------------------------------
149 # Properties
149 # Properties
150 #-------------------------------------------------------------------------
150 #-------------------------------------------------------------------------
151 @property
151 @property
152 def keys(self):
152 def keys(self):
153 """Gets a list of the traitlets that should be synced with the front-end."""
153 """Gets a list of the traitlets that should be synced with the front-end."""
154 if self._keys is None:
154 if self._keys is None:
155 self._keys = []
155 self._keys = []
156 for trait_name in self.trait_names():
156 for trait_name in self.trait_names():
157 if self.trait_metadata(trait_name, 'sync'):
157 if self.trait_metadata(trait_name, 'sync'):
158 self._keys.append(trait_name)
158 self._keys.append(trait_name)
159 return self._keys
159 return self._keys
160
160
161 @property
161 @property
162 def comm(self):
162 def comm(self):
163 """Gets the Comm associated with this widget.
163 """Gets the Comm associated with this widget.
164
164
165 If a Comm doesn't exist yet, a Comm will be created automagically."""
165 If a Comm doesn't exist yet, a Comm will be created automagically."""
166 if self._comm is None:
166 if self._comm is None:
167 # Create a comm.
167 # Create a comm.
168 self._comm = Comm(target_name=self.model_name)
168 self._comm = Comm(target_name=self.model_name)
169 self._comm.on_msg(self._handle_msg)
169 self._comm.on_msg(self._handle_msg)
170 self._comm.on_close(self._close)
170 self._comm.on_close(self._close)
171 Widget.widgets[self.model_id] = self
171 Widget.widgets[self.model_id] = self
172
172
173 # first update
173 # first update
174 self.send_state()
174 self.send_state()
175 return self._comm
175 return self._comm
176
176
177 @property
177 @property
178 def model_id(self):
178 def model_id(self):
179 """Gets the model id of this widget.
179 """Gets the model id of this widget.
180
180
181 If a Comm doesn't exist yet, a Comm will be created automagically."""
181 If a Comm doesn't exist yet, a Comm will be created automagically."""
182 return self.comm.comm_id
182 return self.comm.comm_id
183
183
184 #-------------------------------------------------------------------------
184 #-------------------------------------------------------------------------
185 # Methods
185 # Methods
186 #-------------------------------------------------------------------------
186 #-------------------------------------------------------------------------
187 def close(self):
187 def close(self):
188 """Close method.
188 """Close method.
189
189
190 Closes the widget which closes the underlying comm.
190 Closes the widget which closes the underlying comm.
191 When the comm is closed, all of the widget views are automatically
191 When the comm is closed, all of the widget views are automatically
192 removed from the front-end."""
192 removed from the front-end."""
193 if not self.closed:
193 if not self.closed:
194 self._comm.close()
194 self._comm.close()
195 self._close()
195 self._close()
196
196
197 def send_state(self, key=None):
197 def send_state(self, key=None):
198 """Sends the widget state, or a piece of it, to the front-end.
198 """Sends the widget state, or a piece of it, to the front-end.
199
199
200 Parameters
200 Parameters
201 ----------
201 ----------
202 key : unicode (optional)
202 key : unicode (optional)
203 A single property's name to sync with the front-end.
203 A single property's name to sync with the front-end.
204 """
204 """
205 self._send({
205 self._send({
206 "method" : "update",
206 "method" : "update",
207 "state" : self.get_state()
207 "state" : self.get_state()
208 })
208 })
209
209
210 def get_state(self, key=None):
210 def get_state(self, key=None):
211 """Gets the widget state, or a piece of it.
211 """Gets the widget state, or a piece of it.
212
212
213 Parameters
213 Parameters
214 ----------
214 ----------
215 key : unicode (optional)
215 key : unicode (optional)
216 A single property's name to get.
216 A single property's name to get.
217 """
217 """
218 keys = self.keys if key is None else [key]
218 keys = self.keys if key is None else [key]
219 return {k: self._pack_widgets(getattr(self, k)) for k in keys}
219 return {k: self._pack_widgets(getattr(self, k)) for k in keys}
220
220
221 def send(self, content):
221 def send(self, content):
222 """Sends a custom msg to the widget model in the front-end.
222 """Sends a custom msg to the widget model in the front-end.
223
223
224 Parameters
224 Parameters
225 ----------
225 ----------
226 content : dict
226 content : dict
227 Content of the message to send.
227 Content of the message to send.
228 """
228 """
229 self._send({"method": "custom", "content": content})
229 self._send({"method": "custom", "content": content})
230
230
231 def on_msg(self, callback, remove=False):
231 def on_msg(self, callback, remove=False):
232 """(Un)Register a custom msg recieve callback.
232 """(Un)Register a custom msg recieve callback.
233
233
234 Parameters
234 Parameters
235 ----------
235 ----------
236 callback: method handler
236 callback: method handler
237 Can have a signature of:
237 Can have a signature of:
238 - callback(content) Signature 1
238 - callback(content) Signature 1
239 - callback(sender, content) Signature 2
239 - callback(sender, content) Signature 2
240 remove: bool
240 remove: bool
241 True if the callback should be unregistered."""
241 True if the callback should be unregistered."""
242 self._msg_callbacks.register_callback(callback, remove=remove)
242 self._msg_callbacks.register_callback(callback, remove=remove)
243
243
244 def on_displayed(self, callback, remove=False):
244 def on_displayed(self, callback, remove=False):
245 """(Un)Register a widget displayed callback.
245 """(Un)Register a widget displayed callback.
246
246
247 Parameters
247 Parameters
248 ----------
248 ----------
249 callback: method handler
249 callback: method handler
250 Can have a signature of:
250 Can have a signature of:
251 - callback(sender, **kwargs)
251 - callback(sender, **kwargs)
252 kwargs from display call passed through without modification.
252 kwargs from display call passed through without modification.
253 remove: bool
253 remove: bool
254 True if the callback should be unregistered."""
254 True if the callback should be unregistered."""
255 self._display_callbacks.register_callback(callback, remove=remove)
255 self._display_callbacks.register_callback(callback, remove=remove)
256
256
257 #-------------------------------------------------------------------------
257 #-------------------------------------------------------------------------
258 # Support methods
258 # Support methods
259 #-------------------------------------------------------------------------
259 #-------------------------------------------------------------------------
260 @contextmanager
260 @contextmanager
261 def _lock_property(self, key, value):
261 def _lock_property(self, key, value):
262 """Lock a property-value pair.
262 """Lock a property-value pair.
263
263
264 NOTE: This, in addition to the single lock for all state changes, is
264 NOTE: This, in addition to the single lock for all state changes, is
265 flawed. In the future we may want to look into buffering state changes
265 flawed. In the future we may want to look into buffering state changes
266 back to the front-end."""
266 back to the front-end."""
267 self._property_lock = (key, value)
267 self._property_lock = (key, value)
268 try:
268 try:
269 yield
269 yield
270 finally:
270 finally:
271 self._property_lock = (None, None)
271 self._property_lock = (None, None)
272
272
273 def _should_send_property(self, key, value):
273 def _should_send_property(self, key, value):
274 """Check the property lock (property_lock)"""
274 """Check the property lock (property_lock)"""
275 return key != self._property_lock[0] or \
275 return key != self._property_lock[0] or \
276 value != self._property_lock[1]
276 value != self._property_lock[1]
277
277
278 def _close(self):
278 def _close(self):
279 """Unsafe close"""
279 """Unsafe close"""
280 del Widget.widgets[self.model_id]
280 del Widget.widgets[self.model_id]
281 self._comm = None
281 self._comm = None
282 self.closed = True
282 self.closed = True
283
283
284 # Event handlers
284 # Event handlers
285 def _handle_msg(self, msg):
285 def _handle_msg(self, msg):
286 """Called when a msg is received from the front-end"""
286 """Called when a msg is received from the front-end"""
287 data = msg['content']['data']
287 data = msg['content']['data']
288 method = data['method']
288 method = data['method']
289 if not method in ['backbone', 'custom']:
289 if not method in ['backbone', 'custom']:
290 self.log.error('Unknown front-end to back-end widget msg with method "%s"' % method)
290 self.log.error('Unknown front-end to back-end widget msg with method "%s"' % method)
291
291
292 # Handle backbone sync methods CREATE, PATCH, and UPDATE all in one.
292 # Handle backbone sync methods CREATE, PATCH, and UPDATE all in one.
293 if method == 'backbone' and 'sync_data' in data:
293 if method == 'backbone' and 'sync_data' in data:
294 sync_data = data['sync_data']
294 sync_data = data['sync_data']
295 self._handle_receive_state(sync_data) # handles all methods
295 self._handle_receive_state(sync_data) # handles all methods
296
296
297 # Handle a custom msg from the front-end
297 # Handle a custom msg from the front-end
298 elif method == 'custom':
298 elif method == 'custom':
299 if 'content' in data:
299 if 'content' in data:
300 self._handle_custom_msg(data['content'])
300 self._handle_custom_msg(data['content'])
301
301
302 def _handle_receive_state(self, sync_data):
302 def _handle_receive_state(self, sync_data):
303 """Called when a state is received from the front-end."""
303 """Called when a state is received from the front-end."""
304 for name in self.keys:
304 for name in self.keys:
305 if name in sync_data:
305 if name in sync_data:
306 value = self._unpack_widgets(sync_data[name])
306 value = self._unpack_widgets(sync_data[name])
307 with self._lock_property(name, value):
307 with self._lock_property(name, value):
308 setattr(self, name, value)
308 setattr(self, name, value)
309
309
310 def _handle_custom_msg(self, content):
310 def _handle_custom_msg(self, content):
311 """Called when a custom msg is received."""
311 """Called when a custom msg is received."""
312 self._msg_callbacks(content) # Signature 1
312 self._msg_callbacks(content) # Signature 1
313 self._msg_callbacks(self, content) # Signature 2
313 self._msg_callbacks(self, content) # Signature 2
314
314
315 def _handle_property_changed(self, name, old, new):
315 def _handle_property_changed(self, name, old, new):
316 """Called when a property has been changed."""
316 """Called when a property has been changed."""
317 # Make sure this isn't information that the front-end just sent us.
317 # Make sure this isn't information that the front-end just sent us.
318 if self._should_send_property(name, new):
318 if self._should_send_property(name, new):
319 # Send new state to front-end
319 # Send new state to front-end
320 self.send_state(key=name)
320 self.send_state(key=name)
321
321
322 def _handle_displayed(self, **kwargs):
322 def _handle_displayed(self, **kwargs):
323 """Called when a view has been displayed for this widget instance"""
323 """Called when a view has been displayed for this widget instance"""
324 self._display_callbacks(**kwargs)
324 self._display_callbacks(**kwargs)
325
325
326 def _pack_widgets(self, x):
326 def _pack_widgets(self, x):
327 """Recursively converts all widget instances to model id strings.
327 """Recursively converts all widget instances to model id strings.
328
328
329 Children widgets will be stored and transmitted to the front-end by
329 Children widgets will be stored and transmitted to the front-end by
330 their model ids. Return value must be JSON-able."""
330 their model ids. Return value must be JSON-able."""
331 if isinstance(x, dict):
331 if isinstance(x, dict):
332 return {k: self._pack_widgets(v) for k, v in x.items()}
332 return {k: self._pack_widgets(v) for k, v in x.items()}
333 elif isinstance(x, list):
333 elif isinstance(x, list):
334 return [self._pack_widgets(v) for v in x]
334 return [self._pack_widgets(v) for v in x]
335 elif isinstance(x, Widget):
335 elif isinstance(x, Widget):
336 return x.model_id
336 return x.model_id
337 else:
337 else:
338 return x # Value must be JSON-able
338 return x # Value must be JSON-able
339
339
340 def _unpack_widgets(self, x):
340 def _unpack_widgets(self, x):
341 """Recursively converts all model id strings to widget instances.
341 """Recursively converts all model id strings to widget instances.
342
342
343 Children widgets will be stored and transmitted to the front-end by
343 Children widgets will be stored and transmitted to the front-end by
344 their model ids."""
344 their model ids."""
345 if isinstance(x, dict):
345 if isinstance(x, dict):
346 return {k: self._unpack_widgets(v) for k, v in x.items()}
346 return {k: self._unpack_widgets(v) for k, v in x.items()}
347 elif isinstance(x, list):
347 elif isinstance(x, list):
348 return [self._unpack_widgets(v) for v in x]
348 return [self._unpack_widgets(v) for v in x]
349 elif isinstance(x, string_types):
349 elif isinstance(x, string_types):
350 return x if x not in Widget.widgets else Widget.widgets[x]
350 return x if x not in Widget.widgets else Widget.widgets[x]
351 else:
351 else:
352 return x
352 return x
353
353
354 def _ipython_display_(self, **kwargs):
354 def _ipython_display_(self, **kwargs):
355 """Called when `IPython.display.display` is called on the widget."""
355 """Called when `IPython.display.display` is called on the widget."""
356 # Show view. By sending a display message, the comm is opened and the
356 # Show view. By sending a display message, the comm is opened and the
357 # initial state is sent.
357 # initial state is sent.
358 self._send({"method": "display"})
358 self._send({"method": "display"})
359 self._handle_displayed(**kwargs)
359 self._handle_displayed(**kwargs)
360
360
361 def _send(self, msg):
361 def _send(self, msg):
362 """Sends a message to the model in the front-end."""
362 """Sends a message to the model in the front-end."""
363 self.comm.send(msg)
363 self.comm.send(msg)
364
364
365
365
366 class DOMWidget(Widget):
366 class DOMWidget(Widget):
367 visible = Bool(True, help="Whether or not the widget is visible.", sync=True)
367 visible = Bool(True, help="Whether or not the widget is visible.", sync=True)
368 _css = Dict(sync=True) # Internal CSS property dict
368 _css = Dict(sync=True) # Internal CSS property dict
369
369
370 def get_css(self, key, selector=""):
370 def get_css(self, key, selector=""):
371 """Get a CSS property of the widget.
371 """Get a CSS property of the widget.
372
372
373 Note: This function does not actually request the CSS from the
373 Note: This function does not actually request the CSS from the
374 front-end; Only properties that have been set with set_css can be read.
374 front-end; Only properties that have been set with set_css can be read.
375
375
376 Parameters
376 Parameters
377 ----------
377 ----------
378 key: unicode
378 key: unicode
379 CSS key
379 CSS key
380 selector: unicode (optional)
380 selector: unicode (optional)
381 JQuery selector used when the CSS key/value was set.
381 JQuery selector used when the CSS key/value was set.
382 """
382 """
383 if selector in self._css and key in self._css[selector]:
383 if selector in self._css and key in self._css[selector]:
384 return self._css[selector][key]
384 return self._css[selector][key]
385 else:
385 else:
386 return None
386 return None
387
387
388 def set_css(self, *args, **kwargs):
388 def set_css(self, *args, **kwargs):
389 """Set one or more CSS properties of the widget.
389 """Set one or more CSS properties of the widget.
390
390
391 This function has two signatures:
391 This function has two signatures:
392 - set_css(css_dict, selector='')
392 - set_css(css_dict, selector='')
393 - set_css(key, value, selector='')
393 - set_css(key, value, selector='')
394
394
395 Parameters
395 Parameters
396 ----------
396 ----------
397 css_dict : dict
397 css_dict : dict
398 CSS key/value pairs to apply
398 CSS key/value pairs to apply
399 key: unicode
399 key: unicode
400 CSS key
400 CSS key
401 value
401 value
402 CSS value
402 CSS value
403 selector: unicode (optional)
403 selector: unicode (optional)
404 JQuery selector to use to apply the CSS key/value. If no selector
404 JQuery selector to use to apply the CSS key/value. If no selector
405 is provided, an empty selector is used. An empty selector makes the
405 is provided, an empty selector is used. An empty selector makes the
406 front-end try to apply the css to a default element. The default
406 front-end try to apply the css to a default element. The default
407 element is an attribute unique to each view, which is a DOM element
407 element is an attribute unique to each view, which is a DOM element
408 of the view that should be styled with common CSS (see
408 of the view that should be styled with common CSS (see
409 `$el_to_style` in the Javascript code).
409 `$el_to_style` in the Javascript code).
410 """
410 """
411 selector = kwargs.get('selector', '')
411 selector = kwargs.get('selector', '')
412 if not selector in self._css:
412 if not selector in self._css:
413 self._css[selector] = {}
413 self._css[selector] = {}
414
414
415 # Signature 1: set_css(css_dict, selector='')
415 # Signature 1: set_css(css_dict, selector='')
416 if len(args) == 1:
416 if len(args) == 1:
417 if isinstance(args[0], dict):
417 if isinstance(args[0], dict):
418 for (key, value) in args[0].items():
418 for (key, value) in args[0].items():
419 if not (key in self._css[selector] and value == self._css[selector][key]):
419 if not (key in self._css[selector] and value == self._css[selector][key]):
420 self._css[selector][key] = value
420 self._css[selector][key] = value
421 self.send_state('_css')
421 self.send_state('_css')
422 else:
422 else:
423 raise Exception('css_dict must be a dict.')
423 raise Exception('css_dict must be a dict.')
424
424
425 # Signature 2: set_css(key, value, selector='')
425 # Signature 2: set_css(key, value, selector='')
426 elif len(args) == 2 or len(args) == 3:
426 elif len(args) == 2 or len(args) == 3:
427
427
428 # Selector can be a positional arg if it's the 3rd value
428 # Selector can be a positional arg if it's the 3rd value
429 if len(args) == 3:
429 if len(args) == 3:
430 selector = args[2]
430 selector = args[2]
431 if selector not in self._css:
431 if selector not in self._css:
432 self._css[selector] = {}
432 self._css[selector] = {}
433
433
434 # Only update the property if it has changed.
434 # Only update the property if it has changed.
435 key = args[0]
435 key = args[0]
436 value = args[1]
436 value = args[1]
437 if not (key in self._css[selector] and value == self._css[selector][key]):
437 if not (key in self._css[selector] and value == self._css[selector][key]):
438 self._css[selector][key] = value
438 self._css[selector][key] = value
439 self.send_state('_css') # Send new state to client.
439 self.send_state('_css') # Send new state to client.
440 else:
440 else:
441 raise Exception('set_css only accepts 1-3 arguments')
441 raise Exception('set_css only accepts 1-3 arguments')
442
442
443 def add_class(self, class_names, selector=""):
443 def add_class(self, class_names, selector=""):
444 """Add class[es] to a DOM element.
444 """Add class[es] to a DOM element.
445
445
446 Parameters
446 Parameters
447 ----------
447 ----------
448 class_names: unicode or list
448 class_names: unicode or list
449 Class name(s) to add to the DOM element(s).
449 Class name(s) to add to the DOM element(s).
450 selector: unicode (optional)
450 selector: unicode (optional)
451 JQuery selector to select the DOM element(s) that the class(es) will
451 JQuery selector to select the DOM element(s) that the class(es) will
452 be added to.
452 be added to.
453 """
453 """
454 class_list = class_names
454 class_list = class_names
455 if isinstance(class_list, list):
455 if isinstance(class_list, list):
456 class_list = ' '.join(class_list)
456 class_list = ' '.join(class_list)
457
457
458 self.send({
458 self.send({
459 "msg_type" : "add_class",
459 "msg_type" : "add_class",
460 "class_list" : class_list,
460 "class_list" : class_list,
461 "selector" : selector
461 "selector" : selector
462 })
462 })
463
463
464 def remove_class(self, class_names, selector=""):
464 def remove_class(self, class_names, selector=""):
465 """Remove class[es] from a DOM element.
465 """Remove class[es] from a DOM element.
466
466
467 Parameters
467 Parameters
468 ----------
468 ----------
469 class_names: unicode or list
469 class_names: unicode or list
470 Class name(s) to remove from the DOM element(s).
470 Class name(s) to remove from the DOM element(s).
471 selector: unicode (optional)
471 selector: unicode (optional)
472 JQuery selector to select the DOM element(s) that the class(es) will
472 JQuery selector to select the DOM element(s) that the class(es) will
473 be removed from.
473 be removed from.
474 """
474 """
475 class_list = class_names
475 class_list = class_names
476 if isinstance(class_list, list):
476 if isinstance(class_list, list):
477 class_list = ' '.join(class_list)
477 class_list = ' '.join(class_list)
478
478
479 self.send({
479 self.send({
480 "msg_type" : "remove_class",
480 "msg_type" : "remove_class",
481 "class_list" : class_list,
481 "class_list" : class_list,
482 "selector" : selector,
482 "selector" : selector,
483 })
483 })
@@ -1,34 +1,34 b''
1 """BoolWidget class.
1 """BoolWidget class.
2
2
3 Represents a boolean using a widget.
3 Represents a boolean using a widget.
4 """
4 """
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from .widget import DOMWidget
16 from .widget import DOMWidget
17 from IPython.utils.traitlets import Unicode, Bool, List
17 from IPython.utils.traitlets import Unicode, Bool, List
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Classes
20 # Classes
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 class _BoolWidget(DOMWidget):
22 class _BoolWidget(DOMWidget):
23 value = Bool(False, help="Bool value", sync=True)
23 value = Bool(False, help="Bool value", sync=True)
24 description = Unicode('', help="Description of the boolean (label).", sync=True)
24 description = Unicode('', help="Description of the boolean (label).", sync=True)
25 disabled = Bool(False, help="Enable or disable user changes.", sync=True)
25 disabled = Bool(False, help="Enable or disable user changes.", sync=True)
26
26
27
27
28 class CheckBoxWidget(_BoolWidget):
28 class CheckBoxWidget(_BoolWidget):
29 view_name = Unicode('CheckBoxView', sync=True)
29 _view_name = Unicode('CheckBoxView', sync=True)
30
30
31
31
32 class ToggleButtonWidget(_BoolWidget):
32 class ToggleButtonWidget(_BoolWidget):
33 view_name = Unicode('ToggleButtonView', sync=True)
33 _view_name = Unicode('ToggleButtonView', sync=True)
34 No newline at end of file
34
@@ -1,60 +1,60 b''
1 """ButtonWidget class.
1 """ButtonWidget class.
2
2
3 Represents a button in the frontend using a widget. Allows user to listen for
3 Represents a button in the frontend using a widget. Allows user to listen for
4 click events on the button and trigger backend code when the clicks are fired.
4 click events on the button and trigger backend code when the clicks are fired.
5 """
5 """
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (c) 2013, the IPython Development Team.
7 # Copyright (c) 2013, the IPython Development Team.
8 #
8 #
9 # Distributed under the terms of the Modified BSD License.
9 # Distributed under the terms of the Modified BSD License.
10 #
10 #
11 # The full license is in the file COPYING.txt, distributed with this software.
11 # The full license is in the file COPYING.txt, distributed with this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 from .widget import DOMWidget, CallbackDispatcher
17 from .widget import DOMWidget, CallbackDispatcher
18 from IPython.utils.traitlets import Unicode, Bool
18 from IPython.utils.traitlets import Unicode, Bool
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Classes
21 # Classes
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 class ButtonWidget(DOMWidget):
23 class ButtonWidget(DOMWidget):
24 view_name = Unicode('ButtonView', sync=True)
24 _view_name = Unicode('ButtonView', sync=True)
25
25
26 # Keys
26 # Keys
27 description = Unicode('', help="Description of the button (label).", sync=True)
27 description = Unicode('', help="Description of the button (label).", sync=True)
28 disabled = Bool(False, help="Enable or disable user changes.", sync=True)
28 disabled = Bool(False, help="Enable or disable user changes.", sync=True)
29
29
30 def __init__(self, **kwargs):
30 def __init__(self, **kwargs):
31 """Constructor"""
31 """Constructor"""
32 super(ButtonWidget, self).__init__(**kwargs)
32 super(ButtonWidget, self).__init__(**kwargs)
33 self._click_handlers = CallbackDispatcher(acceptable_nargs=[0, 1])
33 self._click_handlers = CallbackDispatcher(acceptable_nargs=[0, 1])
34 self.on_msg(self._handle_button_msg)
34 self.on_msg(self._handle_button_msg)
35
35
36 def on_click(self, callback, remove=False):
36 def on_click(self, callback, remove=False):
37 """Register a callback to execute when the button is clicked.
37 """Register a callback to execute when the button is clicked.
38
38
39 The callback can either accept no parameters or one sender parameter:
39 The callback can either accept no parameters or one sender parameter:
40 - callback()
40 - callback()
41 - callback(sender)
41 - callback(sender)
42 If the callback has a sender parameter, the ButtonWidget instance that
42 If the callback has a sender parameter, the ButtonWidget instance that
43 called the callback will be passed into the method as the sender.
43 called the callback will be passed into the method as the sender.
44
44
45 Parameters
45 Parameters
46 ----------
46 ----------
47 remove : bool (optional)
47 remove : bool (optional)
48 Set to true to remove the callback from the list of callbacks."""
48 Set to true to remove the callback from the list of callbacks."""
49 self._click_handlers.register_callback(callback, remove=remove)
49 self._click_handlers.register_callback(callback, remove=remove)
50
50
51 def _handle_button_msg(self, content):
51 def _handle_button_msg(self, content):
52 """Handle a msg from the front-end.
52 """Handle a msg from the front-end.
53
53
54 Parameters
54 Parameters
55 ----------
55 ----------
56 content: dict
56 content: dict
57 Content of the msg."""
57 Content of the msg."""
58 if 'event' in content and content['event'] == 'click':
58 if 'event' in content and content['event'] == 'click':
59 self._click_handlers()
59 self._click_handlers()
60 self._click_handlers(self)
60 self._click_handlers(self)
@@ -1,56 +1,56 b''
1 """ContainerWidget class.
1 """ContainerWidget class.
2
2
3 Represents a container that can be used to group other widgets.
3 Represents a container that can be used to group other widgets.
4 """
4 """
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from .widget import DOMWidget
16 from .widget import DOMWidget
17 from IPython.utils.traitlets import Unicode, Bool, List, Instance
17 from IPython.utils.traitlets import Unicode, Bool, List, Instance
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Classes
20 # Classes
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 class ContainerWidget(DOMWidget):
22 class ContainerWidget(DOMWidget):
23 view_name = Unicode('ContainerView', sync=True)
23 _view_name = Unicode('ContainerView', sync=True)
24
24
25 # Keys, all private and managed by helper methods. Flexible box model
25 # Keys, all private and managed by helper methods. Flexible box model
26 # classes...
26 # classes...
27 children = List(Instance(DOMWidget))
27 children = List(Instance(DOMWidget))
28 _children = List(Instance(DOMWidget), sync=True)
28 _children = List(Instance(DOMWidget), sync=True)
29
29
30 def __init__(self, *pargs, **kwargs):
30 def __init__(self, *pargs, **kwargs):
31 """Constructor"""
31 """Constructor"""
32 DOMWidget.__init__(self, *pargs, **kwargs)
32 DOMWidget.__init__(self, *pargs, **kwargs)
33 self.on_trait_change(self._validate, ['children'])
33 self.on_trait_change(self._validate, ['children'])
34
34
35 def _validate(self, name, old, new):
35 def _validate(self, name, old, new):
36 """Validate children list.
36 """Validate children list.
37
37
38 Makes sure only one instance of any given model can exist in the
38 Makes sure only one instance of any given model can exist in the
39 children list.
39 children list.
40 An excellent post on uniqifiers is available at
40 An excellent post on uniqifiers is available at
41 http://www.peterbe.com/plog/uniqifiers-benchmark
41 http://www.peterbe.com/plog/uniqifiers-benchmark
42 which provides the inspiration for using this implementation. Below
42 which provides the inspiration for using this implementation. Below
43 I've implemented the `f5` algorithm using Python comprehensions."""
43 I've implemented the `f5` algorithm using Python comprehensions."""
44 if new is not None and isinstance(new, list):
44 if new is not None and isinstance(new, list):
45 seen = {}
45 seen = {}
46 def add_item(i):
46 def add_item(i):
47 seen[i.model_id] = True
47 seen[i.model_id] = True
48 return i
48 return i
49 return [add_item(i) for i in new if not i.model_id in seen]
49 return [add_item(i) for i in new if not i.model_id in seen]
50
50
51
51
52 class PopupWidget(ContainerWidget):
52 class PopupWidget(ContainerWidget):
53 view_name = Unicode('PopupView', sync=True)
53 _view_name = Unicode('PopupView', sync=True)
54
54
55 description = Unicode(sync=True)
55 description = Unicode(sync=True)
56 button_text = Unicode(sync=True)
56 button_text = Unicode(sync=True)
@@ -1,59 +1,59 b''
1 """FloatWidget class.
1 """FloatWidget class.
2
2
3 Represents an unbounded float using a widget.
3 Represents an unbounded float using a widget.
4 """
4 """
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from .widget import DOMWidget
16 from .widget import DOMWidget
17 from IPython.utils.traitlets import Unicode, CFloat, Bool, List, Enum
17 from IPython.utils.traitlets import Unicode, CFloat, Bool, List, Enum
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Classes
20 # Classes
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 class _FloatWidget(DOMWidget):
22 class _FloatWidget(DOMWidget):
23 value = CFloat(0.0, help="Float value", sync=True)
23 value = CFloat(0.0, help="Float value", sync=True)
24 disabled = Bool(False, help="Enable or disable user changes", sync=True)
24 disabled = Bool(False, help="Enable or disable user changes", sync=True)
25 description = Unicode(help="Description of the value this widget represents", sync=True)
25 description = Unicode(help="Description of the value this widget represents", sync=True)
26
26
27
27
28 class _BoundedFloatWidget(_FloatWidget):
28 class _BoundedFloatWidget(_FloatWidget):
29 max = CFloat(100.0, help="Max value", sync=True)
29 max = CFloat(100.0, help="Max value", sync=True)
30 min = CFloat(0.0, help="Min value", sync=True)
30 min = CFloat(0.0, help="Min value", sync=True)
31 step = CFloat(0.1, help="Minimum step that the value can take (ignored by some views)", sync=True)
31 step = CFloat(0.1, help="Minimum step that the value can take (ignored by some views)", sync=True)
32
32
33 def __init__(self, *pargs, **kwargs):
33 def __init__(self, *pargs, **kwargs):
34 """Constructor"""
34 """Constructor"""
35 DOMWidget.__init__(self, *pargs, **kwargs)
35 DOMWidget.__init__(self, *pargs, **kwargs)
36 self.on_trait_change(self._validate, ['value', 'min', 'max'])
36 self.on_trait_change(self._validate, ['value', 'min', 'max'])
37
37
38 def _validate(self, name, old, new):
38 def _validate(self, name, old, new):
39 """Validate value, max, min."""
39 """Validate value, max, min."""
40 if self.min > new or new > self.max:
40 if self.min > new or new > self.max:
41 self.value = min(max(new, self.min), self.max)
41 self.value = min(max(new, self.min), self.max)
42
42
43
43
44 class FloatTextWidget(_FloatWidget):
44 class FloatTextWidget(_FloatWidget):
45 view_name = Unicode('FloatTextView', sync=True)
45 _view_name = Unicode('FloatTextView', sync=True)
46
46
47
47
48 class BoundedFloatTextWidget(_BoundedFloatWidget):
48 class BoundedFloatTextWidget(_BoundedFloatWidget):
49 view_name = Unicode('FloatTextView', sync=True)
49 _view_name = Unicode('FloatTextView', sync=True)
50
50
51
51
52 class FloatSliderWidget(_BoundedFloatWidget):
52 class FloatSliderWidget(_BoundedFloatWidget):
53 view_name = Unicode('FloatSliderView', sync=True)
53 _view_name = Unicode('FloatSliderView', sync=True)
54 orientation = Enum([u'horizontal', u'vertical'], u'horizontal',
54 orientation = Enum([u'horizontal', u'vertical'], u'horizontal',
55 help="Vertical or horizontal.", sync=True)
55 help="Vertical or horizontal.", sync=True)
56
56
57
57
58 class FloatProgressWidget(_BoundedFloatWidget):
58 class FloatProgressWidget(_BoundedFloatWidget):
59 view_name = Unicode('ProgressView', sync=True)
59 _view_name = Unicode('ProgressView', sync=True)
@@ -1,36 +1,36 b''
1 """ButtonWidget class.
1 """ButtonWidget class.
2
2
3 Represents a button in the frontend using a widget. Allows user to listen for
3 Represents a button in the frontend using a widget. Allows user to listen for
4 click events on the button and trigger backend code when the clicks are fired.
4 click events on the button and trigger backend code when the clicks are fired.
5 """
5 """
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (c) 2013, the IPython Development Team.
7 # Copyright (c) 2013, the IPython Development Team.
8 #
8 #
9 # Distributed under the terms of the Modified BSD License.
9 # Distributed under the terms of the Modified BSD License.
10 #
10 #
11 # The full license is in the file COPYING.txt, distributed with this software.
11 # The full license is in the file COPYING.txt, distributed with this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 import base64
17 import base64
18
18
19 from .widget import DOMWidget
19 from .widget import DOMWidget
20 from IPython.utils.traitlets import Unicode, CUnicode, Bytes
20 from IPython.utils.traitlets import Unicode, CUnicode, Bytes
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Classes
23 # Classes
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 class ImageWidget(DOMWidget):
25 class ImageWidget(DOMWidget):
26 view_name = Unicode('ImageView', sync=True)
26 _view_name = Unicode('ImageView', sync=True)
27
27
28 # Define the custom state properties to sync with the front-end
28 # Define the custom state properties to sync with the front-end
29 format = Unicode('png', sync=True)
29 format = Unicode('png', sync=True)
30 width = CUnicode(sync=True)
30 width = CUnicode(sync=True)
31 height = CUnicode(sync=True)
31 height = CUnicode(sync=True)
32 _b64value = Unicode(sync=True)
32 _b64value = Unicode(sync=True)
33
33
34 value = Bytes()
34 value = Bytes()
35 def _value_changed(self, name, old, new):
35 def _value_changed(self, name, old, new):
36 self._b64value = base64.b64encode(new) No newline at end of file
36 self._b64value = base64.b64encode(new)
@@ -1,59 +1,59 b''
1 """IntWidget class.
1 """IntWidget class.
2
2
3 Represents an unbounded int using a widget.
3 Represents an unbounded int using a widget.
4 """
4 """
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from .widget import DOMWidget
16 from .widget import DOMWidget
17 from IPython.utils.traitlets import Unicode, CInt, Bool, List, Enum
17 from IPython.utils.traitlets import Unicode, CInt, Bool, List, Enum
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Classes
20 # Classes
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 class _IntWidget(DOMWidget):
22 class _IntWidget(DOMWidget):
23 value = CInt(0, help="Int value", sync=True)
23 value = CInt(0, help="Int value", sync=True)
24 disabled = Bool(False, help="Enable or disable user changes", sync=True)
24 disabled = Bool(False, help="Enable or disable user changes", sync=True)
25 description = Unicode(help="Description of the value this widget represents", sync=True)
25 description = Unicode(help="Description of the value this widget represents", sync=True)
26
26
27
27
28 class _BoundedIntWidget(_IntWidget):
28 class _BoundedIntWidget(_IntWidget):
29 step = CInt(1, help="Minimum step that the value can take (ignored by some views)", sync=True)
29 step = CInt(1, help="Minimum step that the value can take (ignored by some views)", sync=True)
30 max = CInt(100, help="Max value", sync=True)
30 max = CInt(100, help="Max value", sync=True)
31 min = CInt(0, help="Min value", sync=True)
31 min = CInt(0, help="Min value", sync=True)
32
32
33 def __init__(self, *pargs, **kwargs):
33 def __init__(self, *pargs, **kwargs):
34 """Constructor"""
34 """Constructor"""
35 DOMWidget.__init__(self, *pargs, **kwargs)
35 DOMWidget.__init__(self, *pargs, **kwargs)
36 self.on_trait_change(self._validate, ['value', 'min', 'max'])
36 self.on_trait_change(self._validate, ['value', 'min', 'max'])
37
37
38 def _validate(self, name, old, new):
38 def _validate(self, name, old, new):
39 """Validate value, max, min."""
39 """Validate value, max, min."""
40 if self.min > new or new > self.max:
40 if self.min > new or new > self.max:
41 self.value = min(max(new, self.min), self.max)
41 self.value = min(max(new, self.min), self.max)
42
42
43
43
44 class IntTextWidget(_IntWidget):
44 class IntTextWidget(_IntWidget):
45 view_name = Unicode('IntTextView', sync=True)
45 _view_name = Unicode('IntTextView', sync=True)
46
46
47
47
48 class BoundedIntTextWidget(_BoundedIntWidget):
48 class BoundedIntTextWidget(_BoundedIntWidget):
49 view_name = Unicode('IntTextView', sync=True)
49 _view_name = Unicode('IntTextView', sync=True)
50
50
51
51
52 class IntSliderWidget(_BoundedIntWidget):
52 class IntSliderWidget(_BoundedIntWidget):
53 view_name = Unicode('IntSliderView', sync=True)
53 _view_name = Unicode('IntSliderView', sync=True)
54 orientation = Enum([u'horizontal', u'vertical'], u'horizontal',
54 orientation = Enum([u'horizontal', u'vertical'], u'horizontal',
55 help="Vertical or horizontal.", sync=True)
55 help="Vertical or horizontal.", sync=True)
56
56
57
57
58 class IntProgressWidget(_BoundedIntWidget):
58 class IntProgressWidget(_BoundedIntWidget):
59 view_name = Unicode('ProgressView', sync=True)
59 _view_name = Unicode('ProgressView', sync=True)
@@ -1,100 +1,100 b''
1 """SelectionWidget class.
1 """SelectionWidget class.
2
2
3 Represents an enumeration using a widget.
3 Represents an enumeration using a widget.
4 """
4 """
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from threading import Lock
16 from threading import Lock
17
17
18 from .widget import DOMWidget
18 from .widget import DOMWidget
19 from IPython.utils.traitlets import Unicode, List, Bool, Any, Dict
19 from IPython.utils.traitlets import Unicode, List, Bool, Any, Dict
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # SelectionWidget
22 # SelectionWidget
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24 class _SelectionWidget(DOMWidget):
24 class _SelectionWidget(DOMWidget):
25 value = Any(help="Selected value")
25 value = Any(help="Selected value")
26 values = List(help="List of values the user can select")
26 values = List(help="List of values the user can select")
27 value_names = Dict(help="""List of string representations for each value.
27 value_names = Dict(help="""List of string representations for each value.
28 These string representations are used to display the values in the
28 These string representations are used to display the values in the
29 front-end.""")
29 front-end.""")
30 disabled = Bool(False, help="Enable or disable user changes", sync=True)
30 disabled = Bool(False, help="Enable or disable user changes", sync=True)
31 description = Unicode(help="Description of the value this widget represents", sync=True)
31 description = Unicode(help="Description of the value this widget represents", sync=True)
32
32
33 _value = Unicode(sync=True) # Bi-directionally synced.
33 _value = Unicode(sync=True) # Bi-directionally synced.
34 _values = List(sync=True) # Only back-end to front-end synced.
34 _values = List(sync=True) # Only back-end to front-end synced.
35 _reverse_value_names = Dict()
35 _reverse_value_names = Dict()
36
36
37 def __init__(self, *pargs, **kwargs):
37 def __init__(self, *pargs, **kwargs):
38 """Constructor"""
38 """Constructor"""
39 DOMWidget.__init__(self, *pargs, **kwargs)
39 DOMWidget.__init__(self, *pargs, **kwargs)
40 self.value_lock = Lock()
40 self.value_lock = Lock()
41 self.on_trait_change(self._string_value_set, ['_value'])
41 self.on_trait_change(self._string_value_set, ['_value'])
42
42
43 def _value_names_changed(self, name=None, old=None, new=None):
43 def _value_names_changed(self, name=None, old=None, new=None):
44 """Handles when the value_names Dict has been changed.
44 """Handles when the value_names Dict has been changed.
45
45
46 This method sets the _reverse_value_names Dict to the inverse of the new
46 This method sets the _reverse_value_names Dict to the inverse of the new
47 value for the value_names Dict."""
47 value for the value_names Dict."""
48 self._reverse_value_names = {v:k for k, v in self.value_names.items()}
48 self._reverse_value_names = {v:k for k, v in self.value_names.items()}
49 self._values_changed()
49 self._values_changed()
50
50
51 def _values_changed(self, name=None, old=None, new=None):
51 def _values_changed(self, name=None, old=None, new=None):
52 """Called when values has been changed"""
52 """Called when values has been changed"""
53 self._values = [self._get_string_repr(v) for v in self.values]
53 self._values = [self._get_string_repr(v) for v in self.values]
54
54
55 def _value_changed(self, name, old, new):
55 def _value_changed(self, name, old, new):
56 """Called when value has been changed"""
56 """Called when value has been changed"""
57 if self.value_lock.acquire(False):
57 if self.value_lock.acquire(False):
58 try:
58 try:
59 # Make sure the value is in the list of values.
59 # Make sure the value is in the list of values.
60 if new in self.values:
60 if new in self.values:
61 # Set the string version of the value.
61 # Set the string version of the value.
62 self._value = self._get_string_repr(new)
62 self._value = self._get_string_repr(new)
63 else:
63 else:
64 raise TypeError('Value must be a value in the values list.')
64 raise TypeError('Value must be a value in the values list.')
65 finally:
65 finally:
66 self.value_lock.release()
66 self.value_lock.release()
67
67
68 def _get_string_repr(self, value):
68 def _get_string_repr(self, value):
69 """Get the string repr of a value"""
69 """Get the string repr of a value"""
70 if value not in self.value_names:
70 if value not in self.value_names:
71 self.value_names[value] = str(value)
71 self.value_names[value] = str(value)
72 self._value_names_changed()
72 self._value_names_changed()
73 return self.value_names[value]
73 return self.value_names[value]
74
74
75 def _string_value_set(self, name, old, new):
75 def _string_value_set(self, name, old, new):
76 """Called when _value has been changed."""
76 """Called when _value has been changed."""
77 if self.value_lock.acquire(False):
77 if self.value_lock.acquire(False):
78 try:
78 try:
79 if new in self._reverse_value_names:
79 if new in self._reverse_value_names:
80 self.value = self._reverse_value_names[new]
80 self.value = self._reverse_value_names[new]
81 else:
81 else:
82 self.value = None
82 self.value = None
83 finally:
83 finally:
84 self.value_lock.release()
84 self.value_lock.release()
85
85
86
86
87 class ToggleButtonsWidget(_SelectionWidget):
87 class ToggleButtonsWidget(_SelectionWidget):
88 view_name = Unicode('ToggleButtonsView', sync=True)
88 _view_name = Unicode('ToggleButtonsView', sync=True)
89
89
90
90
91 class DropdownWidget(_SelectionWidget):
91 class DropdownWidget(_SelectionWidget):
92 view_name = Unicode('DropdownView', sync=True)
92 _view_name = Unicode('DropdownView', sync=True)
93
93
94
94
95 class RadioButtonsWidget(_SelectionWidget):
95 class RadioButtonsWidget(_SelectionWidget):
96 view_name = Unicode('RadioButtonsView', sync=True)
96 _view_name = Unicode('RadioButtonsView', sync=True)
97
97
98
98
99 class ListBoxWidget(_SelectionWidget):
99 class ListBoxWidget(_SelectionWidget):
100 view_name = Unicode('ListBoxView', sync=True)
100 _view_name = Unicode('ListBoxView', sync=True)
@@ -1,58 +1,58 b''
1 """SelectionContainerWidget class.
1 """SelectionContainerWidget class.
2
2
3 Represents a multipage container that can be used to group other widgets into
3 Represents a multipage container that can be used to group other widgets into
4 pages.
4 pages.
5 """
5 """
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (c) 2013, the IPython Development Team.
7 # Copyright (c) 2013, the IPython Development Team.
8 #
8 #
9 # Distributed under the terms of the Modified BSD License.
9 # Distributed under the terms of the Modified BSD License.
10 #
10 #
11 # The full license is in the file COPYING.txt, distributed with this software.
11 # The full license is in the file COPYING.txt, distributed with this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 from .widget_container import ContainerWidget
17 from .widget_container import ContainerWidget
18 from IPython.utils.traitlets import Unicode, Dict, CInt, List, Instance
18 from IPython.utils.traitlets import Unicode, Dict, CInt, List, Instance
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Classes
21 # Classes
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 class _SelectionContainerWidget(ContainerWidget):
23 class _SelectionContainerWidget(ContainerWidget):
24 _titles = Dict(help="Titles of the pages", sync=True)
24 _titles = Dict(help="Titles of the pages", sync=True)
25 selected_index = CInt(0, sync=True)
25 selected_index = CInt(0, sync=True)
26
26
27 # Public methods
27 # Public methods
28 def set_title(self, index, title):
28 def set_title(self, index, title):
29 """Sets the title of a container page.
29 """Sets the title of a container page.
30
30
31 Parameters
31 Parameters
32 ----------
32 ----------
33 index : int
33 index : int
34 Index of the container page
34 Index of the container page
35 title : unicode
35 title : unicode
36 New title"""
36 New title"""
37 self._titles[index] = title
37 self._titles[index] = title
38 self.send_state('_titles')
38 self.send_state('_titles')
39
39
40 def get_title(self, index):
40 def get_title(self, index):
41 """Gets the title of a container pages.
41 """Gets the title of a container pages.
42
42
43 Parameters
43 Parameters
44 ----------
44 ----------
45 index : int
45 index : int
46 Index of the container page"""
46 Index of the container page"""
47 if index in self._titles:
47 if index in self._titles:
48 return self._titles[index]
48 return self._titles[index]
49 else:
49 else:
50 return None
50 return None
51
51
52
52
53 class AccordionWidget(_SelectionContainerWidget):
53 class AccordionWidget(_SelectionContainerWidget):
54 view_name = Unicode('AccordionView', sync=True)
54 _view_name = Unicode('AccordionView', sync=True)
55
55
56
56
57 class TabWidget(_SelectionContainerWidget):
57 class TabWidget(_SelectionContainerWidget):
58 view_name = Unicode('TabView', sync=True)
58 _view_name = Unicode('TabView', sync=True)
@@ -1,75 +1,75 b''
1 """StringWidget class.
1 """StringWidget class.
2
2
3 Represents a unicode string using a widget.
3 Represents a unicode string using a widget.
4 """
4 """
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from .widget import DOMWidget, CallbackDispatcher
16 from .widget import DOMWidget, CallbackDispatcher
17 from IPython.utils.traitlets import Unicode, Bool, List
17 from IPython.utils.traitlets import Unicode, Bool, List
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Classes
20 # Classes
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 class _StringWidget(DOMWidget):
22 class _StringWidget(DOMWidget):
23 value = Unicode(help="String value", sync=True)
23 value = Unicode(help="String value", sync=True)
24 disabled = Bool(False, help="Enable or disable user changes", sync=True)
24 disabled = Bool(False, help="Enable or disable user changes", sync=True)
25 description = Unicode(help="Description of the value this widget represents", sync=True)
25 description = Unicode(help="Description of the value this widget represents", sync=True)
26
26
27
27
28 class HTMLWidget(_StringWidget):
28 class HTMLWidget(_StringWidget):
29 view_name = Unicode('HTMLView', sync=True)
29 _view_name = Unicode('HTMLView', sync=True)
30
30
31
31
32 class LatexWidget(_StringWidget):
32 class LatexWidget(_StringWidget):
33 view_name = Unicode('LatexView', sync=True)
33 _view_name = Unicode('LatexView', sync=True)
34
34
35
35
36 class TextAreaWidget(_StringWidget):
36 class TextAreaWidget(_StringWidget):
37 view_name = Unicode('TextAreaView', sync=True)
37 _view_name = Unicode('TextAreaView', sync=True)
38
38
39 def scroll_to_bottom(self):
39 def scroll_to_bottom(self):
40 self.send({"method": "scroll_to_bottom"})
40 self.send({"method": "scroll_to_bottom"})
41
41
42
42
43 class TextBoxWidget(_StringWidget):
43 class TextBoxWidget(_StringWidget):
44 view_name = Unicode('TextBoxView', sync=True)
44 _view_name = Unicode('TextBoxView', sync=True)
45
45
46 def __init__(self, **kwargs):
46 def __init__(self, **kwargs):
47 super(TextBoxWidget, self).__init__(**kwargs)
47 super(TextBoxWidget, self).__init__(**kwargs)
48 self._submission_callbacks = CallbackDispatcher(acceptable_nargs=[0, 1])
48 self._submission_callbacks = CallbackDispatcher(acceptable_nargs=[0, 1])
49 self.on_msg(self._handle_string_msg)
49 self.on_msg(self._handle_string_msg)
50
50
51 def _handle_string_msg(self, content):
51 def _handle_string_msg(self, content):
52 """Handle a msg from the front-end.
52 """Handle a msg from the front-end.
53
53
54 Parameters
54 Parameters
55 ----------
55 ----------
56 content: dict
56 content: dict
57 Content of the msg."""
57 Content of the msg."""
58 if 'event' in content and content['event'] == 'submit':
58 if 'event' in content and content['event'] == 'submit':
59 self._submission_callbacks()
59 self._submission_callbacks()
60 self._submission_callbacks(self)
60 self._submission_callbacks(self)
61
61
62 def on_submit(self, callback, remove=False):
62 def on_submit(self, callback, remove=False):
63 """(Un)Register a callback to handle text submission.
63 """(Un)Register a callback to handle text submission.
64
64
65 Triggered when the user clicks enter.
65 Triggered when the user clicks enter.
66
66
67 Parameters
67 Parameters
68 callback: Method handle
68 callback: Method handle
69 Function to be called when the text has been submitted. Function
69 Function to be called when the text has been submitted. Function
70 can have two possible signatures:
70 can have two possible signatures:
71 callback()
71 callback()
72 callback(sender)
72 callback(sender)
73 remove: bool (optional)
73 remove: bool (optional)
74 Whether or not to unregister the callback"""
74 Whether or not to unregister the callback"""
75 self._submission_callbacks.register_callback(callback, remove=remove)
75 self._submission_callbacks.register_callback(callback, remove=remove)
General Comments 0
You need to be logged in to leave comments. Login now