##// END OF EJS Templates
Merge pull request #6454 from jasongrout/links...
Jonathan Frederic -
r19401:ce5036c2 merge
parent child Browse files
Show More
@@ -0,0 +1,86 b''
1 // Copyright (c) IPython Development Team.
2 // Distributed under the terms of the Modified BSD License.
3
4 define([
5 "widgets/js/widget",
6 "jquery",
7 ], function(widget, $){
8 var LinkModel = widget.WidgetModel.extend({
9 initialize: function() {
10 this.on("change:widgets", function(model, value, options) {
11 this.update_bindings(model.previous("widgets") || [], value);
12 this.update_value(this.get("widgets")[0]);
13 }, this);
14 this.once("destroy", function(model, collection, options) {
15 this.update_bindings(this.get("widgets"), []);
16 }, this);
17 },
18 update_bindings: function(oldlist, newlist) {
19 var that = this;
20 _.each(oldlist, function(elt) {elt[0].off("change:" + elt[1], null, that);});
21 _.each(newlist, function(elt) {elt[0].on("change:" + elt[1],
22 function(model, value, options) {
23 that.update_value(elt);
24 }, that);
25 // TODO: register for any destruction handlers
26 // to take an item out of the list
27 });
28 },
29 update_value: function(elt) {
30 if (this.updating) {return;}
31 var model = elt[0];
32 var attr = elt[1];
33 var new_value = model.get(attr);
34 this.updating = true;
35 _.each(_.without(this.get("widgets"), elt),
36 function(element, index, list) {
37 if (element[0]) {
38 element[0].set(element[1], new_value);
39 element[0].save_changes();
40 }
41 }, this);
42 this.updating = false;
43 },
44 });
45
46 var DirectionalLinkModel = widget.WidgetModel.extend({
47 initialize: function() {
48 this.on("change", this.update_bindings, this);
49 this.once("destroy", function() {
50 if (this.source) {
51 this.source[0].off("change:" + this.source[1], null, this);
52 }
53 }, this);
54 },
55 update_bindings: function() {
56 if (this.source) {
57 this.source[0].off("change:" + this.source[1], null, this);
58 }
59 this.source = this.get("source");
60 if (this.source) {
61 this.source[0].on("change:" + this.source[1], function() { this.update_value(this.source); }, this);
62 this.update_value(this.source);
63 }
64 },
65 update_value: function(elt) {
66 if (this.updating) {return;}
67 var model = elt[0];
68 var attr = elt[1];
69 var new_value = model.get(attr);
70 this.updating = true;
71 _.each(this.get("targets"),
72 function(element, index, list) {
73 if (element[0]) {
74 element[0].set(element[1], new_value);
75 element[0].save_changes();
76 }
77 }, this);
78 this.updating = false;
79 },
80 });
81
82 return {
83 "LinkModel": LinkModel,
84 "DirectionalLinkModel": DirectionalLinkModel,
85 }
86 });
@@ -0,0 +1,61 b''
1 """Link and DirectionalLink classes.
2
3 Propagate changes between widgets on the javascript side
4 """
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2014, the IPython Development Team.
7 #
8 # Distributed under the terms of the Modified BSD License.
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
12
13 #-----------------------------------------------------------------------------
14 # Imports
15 #-----------------------------------------------------------------------------
16 from .widget import Widget
17 from IPython.utils.traitlets import Unicode, Tuple, Any
18
19 #-----------------------------------------------------------------------------
20 # Classes
21 #-----------------------------------------------------------------------------
22
23
24 class Link(Widget):
25 """Link Widget"""
26 _model_name = Unicode('LinkModel', sync=True)
27 widgets = Tuple(sync=True, allow_none=False)
28
29 def __init__(self, widgets=(), **kwargs):
30 kwargs['widgets'] = widgets
31 super(Link, self).__init__(**kwargs)
32
33 # for compatibility with traitlet links
34 def unlink(self):
35 self.close()
36
37
38 def link(*args):
39 return Link(widgets=args)
40
41
42 class DirectionalLink(Widget):
43 """Directional Link Widget"""
44 _model_name = Unicode('DirectionalLinkModel', sync=True)
45 targets = Any(sync=True)
46 source = Tuple(sync=True)
47
48 # Does not quite behave like other widgets but reproduces
49 # the behavior of IPython.utils.traitlets.directional_link
50 def __init__(self, source, targets=(), **kwargs):
51 kwargs['source'] = source
52 kwargs['targets'] = targets
53 super(DirectionalLink, self).__init__(**kwargs)
54
55 # for compatibility with traitlet links
56 def unlink(self):
57 self.close()
58
59
60 def dlink(source, *targets):
61 return DirectionalLink(source, targets)
@@ -1,217 +1,217 b''
1 // Copyright (c) IPython Development Team.
1 // Copyright (c) IPython Development Team.
2 // Distributed under the terms of the Modified BSD License.
2 // Distributed under the terms of the Modified BSD License.
3
3
4 define([
4 define([
5 'base/js/namespace',
5 'base/js/namespace',
6 'jquery',
6 'jquery',
7 'base/js/utils',
7 'base/js/utils',
8 ], function(IPython, $, utils) {
8 ], function(IPython, $, utils) {
9 "use strict";
9 "use strict";
10
10
11 //-----------------------------------------------------------------------
11 //-----------------------------------------------------------------------
12 // CommManager class
12 // CommManager class
13 //-----------------------------------------------------------------------
13 //-----------------------------------------------------------------------
14
14
15 var CommManager = function (kernel) {
15 var CommManager = function (kernel) {
16 this.comms = {};
16 this.comms = {};
17 this.targets = {};
17 this.targets = {};
18 if (kernel !== undefined) {
18 if (kernel !== undefined) {
19 this.init_kernel(kernel);
19 this.init_kernel(kernel);
20 }
20 }
21 };
21 };
22
22
23 CommManager.prototype.init_kernel = function (kernel) {
23 CommManager.prototype.init_kernel = function (kernel) {
24 /**
24 /**
25 * connect the kernel, and register message handlers
25 * connect the kernel, and register message handlers
26 */
26 */
27 this.kernel = kernel;
27 this.kernel = kernel;
28 var msg_types = ['comm_open', 'comm_msg', 'comm_close'];
28 var msg_types = ['comm_open', 'comm_msg', 'comm_close'];
29 for (var i = 0; i < msg_types.length; i++) {
29 for (var i = 0; i < msg_types.length; i++) {
30 var msg_type = msg_types[i];
30 var msg_type = msg_types[i];
31 kernel.register_iopub_handler(msg_type, $.proxy(this[msg_type], this));
31 kernel.register_iopub_handler(msg_type, $.proxy(this[msg_type], this));
32 }
32 }
33 };
33 };
34
34
35 CommManager.prototype.new_comm = function (target_name, data, callbacks, metadata) {
35 CommManager.prototype.new_comm = function (target_name, data, callbacks, metadata) {
36 /**
36 /**
37 * Create a new Comm, register it, and open its Kernel-side counterpart
37 * Create a new Comm, register it, and open its Kernel-side counterpart
38 * Mimics the auto-registration in `Comm.__init__` in the IPython Comm
38 * Mimics the auto-registration in `Comm.__init__` in the IPython Comm
39 */
39 */
40 var comm = new Comm(target_name);
40 var comm = new Comm(target_name);
41 this.register_comm(comm);
41 this.register_comm(comm);
42 comm.open(data, callbacks, metadata);
42 comm.open(data, callbacks, metadata);
43 return comm;
43 return comm;
44 };
44 };
45
45
46 CommManager.prototype.register_target = function (target_name, f) {
46 CommManager.prototype.register_target = function (target_name, f) {
47 /**
47 /**
48 * Register a target function for a given target name
48 * Register a target function for a given target name
49 */
49 */
50 this.targets[target_name] = f;
50 this.targets[target_name] = f;
51 };
51 };
52
52
53 CommManager.prototype.unregister_target = function (target_name, f) {
53 CommManager.prototype.unregister_target = function (target_name, f) {
54 /**
54 /**
55 * Unregister a target function for a given target name
55 * Unregister a target function for a given target name
56 */
56 */
57 delete this.targets[target_name];
57 delete this.targets[target_name];
58 };
58 };
59
59
60 CommManager.prototype.register_comm = function (comm) {
60 CommManager.prototype.register_comm = function (comm) {
61 /**
61 /**
62 * Register a comm in the mapping
62 * Register a comm in the mapping
63 */
63 */
64 this.comms[comm.comm_id] = Promise.resolve(comm);
64 this.comms[comm.comm_id] = Promise.resolve(comm);
65 comm.kernel = this.kernel;
65 comm.kernel = this.kernel;
66 return comm.comm_id;
66 return comm.comm_id;
67 };
67 };
68
68
69 CommManager.prototype.unregister_comm = function (comm) {
69 CommManager.prototype.unregister_comm = function (comm) {
70 /**
70 /**
71 * Remove a comm from the mapping
71 * Remove a comm from the mapping
72 */
72 */
73 delete this.comms[comm.comm_id];
73 delete this.comms[comm.comm_id];
74 };
74 };
75
75
76 // comm message handlers
76 // comm message handlers
77
77
78 CommManager.prototype.comm_open = function (msg) {
78 CommManager.prototype.comm_open = function (msg) {
79 var content = msg.content;
79 var content = msg.content;
80 var that = this;
80 var that = this;
81 var comm_id = content.comm_id;
81 var comm_id = content.comm_id;
82
82
83 this.comms[comm_id] = utils.load_class(content.target_name, content.target_module,
83 this.comms[comm_id] = utils.load_class(content.target_name, content.target_module,
84 this.targets).then(function(target) {
84 this.targets).then(function(target) {
85 var comm = new Comm(content.target_name, comm_id);
85 var comm = new Comm(content.target_name, comm_id);
86 comm.kernel = that.kernel;
86 comm.kernel = that.kernel;
87 try {
87 try {
88 var response = target(comm, msg);
88 var response = target(comm, msg);
89 } catch (e) {
89 } catch (e) {
90 comm.close();
90 comm.close();
91 that.unregister_comm(comm);
91 that.unregister_comm(comm);
92 var wrapped_error = new utils.WrappedError("Exception opening new comm", e);
92 var wrapped_error = new utils.WrappedError("Exception opening new comm", e);
93 console.error(wrapped_error);
93 console.error(wrapped_error);
94 return Promise.reject(wrapped_error);
94 return Promise.reject(wrapped_error);
95 }
95 }
96 // Regardless of the target return value, we need to
96 // Regardless of the target return value, we need to
97 // then return the comm
97 // then return the comm
98 return Promise.resolve(response).then(function() {return comm;});
98 return Promise.resolve(response).then(function() {return comm;});
99 }, utils.reject('Could not open comm', true));
99 }, utils.reject('Could not open comm', true));
100 return this.comms[comm_id];
100 return this.comms[comm_id];
101 };
101 };
102
102
103 CommManager.prototype.comm_close = function(msg) {
103 CommManager.prototype.comm_close = function(msg) {
104 var content = msg.content;
104 var content = msg.content;
105 if (this.comms[content.comm_id] === undefined) {
105 if (this.comms[content.comm_id] === undefined) {
106 console.error('Comm promise not found for comm id ' + content.comm_id);
106 console.error('Comm promise not found for comm id ' + content.comm_id);
107 return;
107 return;
108 }
108 }
109
109 var that = this;
110 this.comms[content.comm_id] = this.comms[content.comm_id].then(function(comm) {
110 this.comms[content.comm_id] = this.comms[content.comm_id].then(function(comm) {
111 this.unregister_comm(comm);
111 that.unregister_comm(comm);
112 try {
112 try {
113 comm.handle_close(msg);
113 comm.handle_close(msg);
114 } catch (e) {
114 } catch (e) {
115 console.log("Exception closing comm: ", e, e.stack, msg);
115 console.log("Exception closing comm: ", e, e.stack, msg);
116 }
116 }
117 // don't return a comm, so that further .then() functions
117 // don't return a comm, so that further .then() functions
118 // get an undefined comm input
118 // get an undefined comm input
119 });
119 });
120 };
120 };
121
121
122 CommManager.prototype.comm_msg = function(msg) {
122 CommManager.prototype.comm_msg = function(msg) {
123 var content = msg.content;
123 var content = msg.content;
124 if (this.comms[content.comm_id] === undefined) {
124 if (this.comms[content.comm_id] === undefined) {
125 console.error('Comm promise not found for comm id ' + content.comm_id);
125 console.error('Comm promise not found for comm id ' + content.comm_id);
126 return;
126 return;
127 }
127 }
128
128
129 this.comms[content.comm_id] = this.comms[content.comm_id].then(function(comm) {
129 this.comms[content.comm_id] = this.comms[content.comm_id].then(function(comm) {
130 try {
130 try {
131 comm.handle_msg(msg);
131 comm.handle_msg(msg);
132 } catch (e) {
132 } catch (e) {
133 console.log("Exception handling comm msg: ", e, e.stack, msg);
133 console.log("Exception handling comm msg: ", e, e.stack, msg);
134 }
134 }
135 return comm;
135 return comm;
136 });
136 });
137 };
137 };
138
138
139 //-----------------------------------------------------------------------
139 //-----------------------------------------------------------------------
140 // Comm base class
140 // Comm base class
141 //-----------------------------------------------------------------------
141 //-----------------------------------------------------------------------
142
142
143 var Comm = function (target_name, comm_id) {
143 var Comm = function (target_name, comm_id) {
144 this.target_name = target_name;
144 this.target_name = target_name;
145 this.comm_id = comm_id || utils.uuid();
145 this.comm_id = comm_id || utils.uuid();
146 this._msg_callback = this._close_callback = null;
146 this._msg_callback = this._close_callback = null;
147 };
147 };
148
148
149 // methods for sending messages
149 // methods for sending messages
150 Comm.prototype.open = function (data, callbacks, metadata) {
150 Comm.prototype.open = function (data, callbacks, metadata) {
151 var content = {
151 var content = {
152 comm_id : this.comm_id,
152 comm_id : this.comm_id,
153 target_name : this.target_name,
153 target_name : this.target_name,
154 data : data || {},
154 data : data || {},
155 };
155 };
156 return this.kernel.send_shell_message("comm_open", content, callbacks, metadata);
156 return this.kernel.send_shell_message("comm_open", content, callbacks, metadata);
157 };
157 };
158
158
159 Comm.prototype.send = function (data, callbacks, metadata, buffers) {
159 Comm.prototype.send = function (data, callbacks, metadata, buffers) {
160 var content = {
160 var content = {
161 comm_id : this.comm_id,
161 comm_id : this.comm_id,
162 data : data || {},
162 data : data || {},
163 };
163 };
164 return this.kernel.send_shell_message("comm_msg", content, callbacks, metadata, buffers);
164 return this.kernel.send_shell_message("comm_msg", content, callbacks, metadata, buffers);
165 };
165 };
166
166
167 Comm.prototype.close = function (data, callbacks, metadata) {
167 Comm.prototype.close = function (data, callbacks, metadata) {
168 var content = {
168 var content = {
169 comm_id : this.comm_id,
169 comm_id : this.comm_id,
170 data : data || {},
170 data : data || {},
171 };
171 };
172 return this.kernel.send_shell_message("comm_close", content, callbacks, metadata);
172 return this.kernel.send_shell_message("comm_close", content, callbacks, metadata);
173 };
173 };
174
174
175 // methods for registering callbacks for incoming messages
175 // methods for registering callbacks for incoming messages
176 Comm.prototype._register_callback = function (key, callback) {
176 Comm.prototype._register_callback = function (key, callback) {
177 this['_' + key + '_callback'] = callback;
177 this['_' + key + '_callback'] = callback;
178 };
178 };
179
179
180 Comm.prototype.on_msg = function (callback) {
180 Comm.prototype.on_msg = function (callback) {
181 this._register_callback('msg', callback);
181 this._register_callback('msg', callback);
182 };
182 };
183
183
184 Comm.prototype.on_close = function (callback) {
184 Comm.prototype.on_close = function (callback) {
185 this._register_callback('close', callback);
185 this._register_callback('close', callback);
186 };
186 };
187
187
188 // methods for handling incoming messages
188 // methods for handling incoming messages
189
189
190 Comm.prototype._callback = function (key, msg) {
190 Comm.prototype._callback = function (key, msg) {
191 var callback = this['_' + key + '_callback'];
191 var callback = this['_' + key + '_callback'];
192 if (callback) {
192 if (callback) {
193 try {
193 try {
194 callback(msg);
194 callback(msg);
195 } catch (e) {
195 } catch (e) {
196 console.log("Exception in Comm callback", e, e.stack, msg);
196 console.log("Exception in Comm callback", e, e.stack, msg);
197 }
197 }
198 }
198 }
199 };
199 };
200
200
201 Comm.prototype.handle_msg = function (msg) {
201 Comm.prototype.handle_msg = function (msg) {
202 this._callback('msg', msg);
202 this._callback('msg', msg);
203 };
203 };
204
204
205 Comm.prototype.handle_close = function (msg) {
205 Comm.prototype.handle_close = function (msg) {
206 this._callback('close', msg);
206 this._callback('close', msg);
207 };
207 };
208
208
209 // For backwards compatability.
209 // For backwards compatability.
210 IPython.CommManager = CommManager;
210 IPython.CommManager = CommManager;
211 IPython.Comm = Comm;
211 IPython.Comm = Comm;
212
212
213 return {
213 return {
214 'CommManager': CommManager,
214 'CommManager': CommManager,
215 'Comm': Comm
215 'Comm': Comm
216 };
216 };
217 });
217 });
@@ -1,28 +1,34 b''
1 // Copyright (c) IPython Development Team.
1 // Copyright (c) IPython Development Team.
2 // Distributed under the terms of the Modified BSD License.
2 // Distributed under the terms of the Modified BSD License.
3
3
4 define([
4 define([
5 "widgets/js/manager",
5 "widgets/js/manager",
6 "widgets/js/widget_link",
6 "widgets/js/widget_bool",
7 "widgets/js/widget_bool",
7 "widgets/js/widget_button",
8 "widgets/js/widget_button",
8 "widgets/js/widget_box",
9 "widgets/js/widget_box",
9 "widgets/js/widget_float",
10 "widgets/js/widget_float",
10 "widgets/js/widget_image",
11 "widgets/js/widget_image",
11 "widgets/js/widget_int",
12 "widgets/js/widget_int",
12 "widgets/js/widget_output",
13 "widgets/js/widget_output",
13 "widgets/js/widget_selection",
14 "widgets/js/widget_selection",
14 "widgets/js/widget_selectioncontainer",
15 "widgets/js/widget_selectioncontainer",
15 "widgets/js/widget_string",
16 "widgets/js/widget_string",
16 ], function(widgetmanager) {
17 ], function(widgetmanager, linkModels) {
18 for (var target_name in linkModels) {
19 if (linkModels.hasOwnProperty(target_name)) {
20 widgetmanager.WidgetManager.register_widget_model(target_name, linkModels[target_name]);
21 }
22 }
17
23
18 // Register all of the loaded views with the widget manager.
24 // Register all of the loaded views with the widget manager.
19 for (var i = 1; i < arguments.length; i++) {
25 for (var i = 2; i < arguments.length; i++) {
20 for (var target_name in arguments[i]) {
26 for (var target_name in arguments[i]) {
21 if (arguments[i].hasOwnProperty(target_name)) {
27 if (arguments[i].hasOwnProperty(target_name)) {
22 widgetmanager.WidgetManager.register_widget_view(target_name, arguments[i][target_name]);
28 widgetmanager.WidgetManager.register_widget_view(target_name, arguments[i][target_name]);
23 }
29 }
24 }
30 }
25 }
31 }
26
32
27 return {'WidgetManager': widgetmanager.WidgetManager};
33 return {'WidgetManager': widgetmanager.WidgetManager};
28 });
34 });
@@ -1,29 +1,30 b''
1 from .widget import Widget, DOMWidget, CallbackDispatcher, register
1 from .widget import Widget, DOMWidget, CallbackDispatcher, register
2
2
3 from .widget_bool import Checkbox, ToggleButton
3 from .widget_bool import Checkbox, ToggleButton
4 from .widget_button import Button
4 from .widget_button import Button
5 from .widget_box import Box, Popup, FlexBox, HBox, VBox
5 from .widget_box import Box, Popup, FlexBox, HBox, VBox
6 from .widget_float import FloatText, BoundedFloatText, FloatSlider, FloatProgress, FloatRangeSlider
6 from .widget_float import FloatText, BoundedFloatText, FloatSlider, FloatProgress, FloatRangeSlider
7 from .widget_image import Image
7 from .widget_image import Image
8 from .widget_int import IntText, BoundedIntText, IntSlider, IntProgress, IntRangeSlider
8 from .widget_int import IntText, BoundedIntText, IntSlider, IntProgress, IntRangeSlider
9 from .widget_output import Output
9 from .widget_output import Output
10 from .widget_selection import RadioButtons, ToggleButtons, Dropdown, Select
10 from .widget_selection import RadioButtons, ToggleButtons, Dropdown, Select
11 from .widget_selectioncontainer import Tab, Accordion
11 from .widget_selectioncontainer import Tab, Accordion
12 from .widget_string import HTML, Latex, Text, Textarea
12 from .widget_string import HTML, Latex, Text, Textarea
13 from .interaction import interact, interactive, fixed, interact_manual
13 from .interaction import interact, interactive, fixed, interact_manual
14 from .widget_link import Link, link, DirectionalLink, dlink
14
15
15 # Deprecated classes
16 # Deprecated classes
16 from .widget_bool import CheckboxWidget, ToggleButtonWidget
17 from .widget_bool import CheckboxWidget, ToggleButtonWidget
17 from .widget_button import ButtonWidget
18 from .widget_button import ButtonWidget
18 from .widget_box import ContainerWidget, PopupWidget
19 from .widget_box import ContainerWidget, PopupWidget
19 from .widget_float import FloatTextWidget, BoundedFloatTextWidget, FloatSliderWidget, FloatProgressWidget
20 from .widget_float import FloatTextWidget, BoundedFloatTextWidget, FloatSliderWidget, FloatProgressWidget
20 from .widget_image import ImageWidget
21 from .widget_image import ImageWidget
21 from .widget_int import IntTextWidget, BoundedIntTextWidget, IntSliderWidget, IntProgressWidget
22 from .widget_int import IntTextWidget, BoundedIntTextWidget, IntSliderWidget, IntProgressWidget
22 from .widget_selection import RadioButtonsWidget, ToggleButtonsWidget, DropdownWidget, SelectWidget
23 from .widget_selection import RadioButtonsWidget, ToggleButtonsWidget, DropdownWidget, SelectWidget
23 from .widget_selectioncontainer import TabWidget, AccordionWidget
24 from .widget_selectioncontainer import TabWidget, AccordionWidget
24 from .widget_string import HTMLWidget, LatexWidget, TextWidget, TextareaWidget
25 from .widget_string import HTMLWidget, LatexWidget, TextWidget, TextareaWidget
25
26
26 # Warn on import
27 # Warn on import
27 from IPython.utils.warn import warn
28 from IPython.utils.warn import warn
28 warn("""The widget API is still considered experimental and
29 warn("""The widget API is still considered experimental and
29 may change by the next major release of IPython.""")
30 may change by the next major release of IPython.""")
@@ -1,228 +1,383 b''
1 {
1 {
2 "cells": [
2 "cells": [
3 {
3 {
4 "cell_type": "markdown",
4 "cell_type": "markdown",
5 "metadata": {},
5 "metadata": {},
6 "source": [
6 "source": [
7 "[Index](Index.ipynb) - [Back](Widget List.ipynb) - [Next](Widget Styling.ipynb)"
7 "[Index](Index.ipynb) - [Back](Widget List.ipynb) - [Next](Widget Styling.ipynb)"
8 ]
8 ]
9 },
9 },
10 {
10 {
11 "cell_type": "markdown",
11 "cell_type": "markdown",
12 "metadata": {
12 "metadata": {
13 "slideshow": {
13 "slideshow": {
14 "slide_type": "slide"
14 "slide_type": "slide"
15 }
15 }
16 },
16 },
17 "source": [
17 "source": [
18 "# Widget Events"
18 "# Widget Events"
19 ]
19 ]
20 },
20 },
21 {
21 {
22 "cell_type": "markdown",
22 "cell_type": "markdown",
23 "metadata": {},
23 "metadata": {},
24 "source": [
24 "source": [
25 "## Special events"
25 "## Special events"
26 ]
26 ]
27 },
27 },
28 {
28 {
29 "cell_type": "code",
29 "cell_type": "code",
30 "execution_count": null,
30 "execution_count": null,
31 "metadata": {
31 "metadata": {
32 "collapsed": false
32 "collapsed": false
33 },
33 },
34 "outputs": [],
34 "outputs": [],
35 "source": [
35 "source": [
36 "from __future__ import print_function"
36 "from __future__ import print_function"
37 ]
37 ]
38 },
38 },
39 {
39 {
40 "cell_type": "markdown",
40 "cell_type": "markdown",
41 "metadata": {},
41 "metadata": {},
42 "source": [
42 "source": [
43 "The `Button` is not used to represent a data type. Instead the button widget is used to **handle mouse clicks**. The **`on_click` method** of the `Button` can be used to register function to be called when the button is clicked. The doc string of the `on_click` can be seen below."
43 "The `Button` is not used to represent a data type. Instead the button widget is used to **handle mouse clicks**. The **`on_click` method** of the `Button` can be used to register function to be called when the button is clicked. The doc string of the `on_click` can be seen below."
44 ]
44 ]
45 },
45 },
46 {
46 {
47 "cell_type": "code",
47 "cell_type": "code",
48 "execution_count": null,
48 "execution_count": null,
49 "metadata": {
49 "metadata": {
50 "collapsed": false
50 "collapsed": false
51 },
51 },
52 "outputs": [],
52 "outputs": [],
53 "source": [
53 "source": [
54 "from IPython.html import widgets\n",
54 "from IPython.html import widgets\n",
55 "print(widgets.Button.on_click.__doc__)"
55 "print(widgets.Button.on_click.__doc__)"
56 ]
56 ]
57 },
57 },
58 {
58 {
59 "cell_type": "markdown",
59 "cell_type": "markdown",
60 "metadata": {
60 "metadata": {
61 "slideshow": {
61 "slideshow": {
62 "slide_type": "slide"
62 "slide_type": "slide"
63 }
63 }
64 },
64 },
65 "source": [
65 "source": [
66 "### Example"
66 "### Example"
67 ]
67 ]
68 },
68 },
69 {
69 {
70 "cell_type": "markdown",
70 "cell_type": "markdown",
71 "metadata": {},
71 "metadata": {},
72 "source": [
72 "source": [
73 "Since button clicks are **stateless**, they are **transmitted from the front-end to the back-end using custom messages**. By using the `on_click` method, a button that prints a message when it has been clicked is shown below."
73 "Since button clicks are **stateless**, they are **transmitted from the front-end to the back-end using custom messages**. By using the `on_click` method, a button that prints a message when it has been clicked is shown below."
74 ]
74 ]
75 },
75 },
76 {
76 {
77 "cell_type": "code",
77 "cell_type": "code",
78 "execution_count": null,
78 "execution_count": null,
79 "metadata": {
79 "metadata": {
80 "collapsed": false
80 "collapsed": false
81 },
81 },
82 "outputs": [],
82 "outputs": [],
83 "source": [
83 "source": [
84 "from IPython.display import display\n",
84 "from IPython.display import display\n",
85 "button = widgets.Button(description=\"Click Me!\")\n",
85 "button = widgets.Button(description=\"Click Me!\")\n",
86 "display(button)\n",
86 "display(button)\n",
87 "\n",
87 "\n",
88 "def on_button_clicked(b):\n",
88 "def on_button_clicked(b):\n",
89 " print(\"Button clicked.\")\n",
89 " print(\"Button clicked.\")\n",
90 "\n",
90 "\n",
91 "button.on_click(on_button_clicked)"
91 "button.on_click(on_button_clicked)"
92 ]
92 ]
93 },
93 },
94 {
94 {
95 "cell_type": "markdown",
95 "cell_type": "markdown",
96 "metadata": {
96 "metadata": {
97 "slideshow": {
97 "slideshow": {
98 "slide_type": "slide"
98 "slide_type": "slide"
99 }
99 }
100 },
100 },
101 "source": [
101 "source": [
102 "### on_sumbit"
102 "### on_sumbit"
103 ]
103 ]
104 },
104 },
105 {
105 {
106 "cell_type": "markdown",
106 "cell_type": "markdown",
107 "metadata": {},
107 "metadata": {},
108 "source": [
108 "source": [
109 "The **`Text`** also has a special **`on_submit` event**. The `on_submit` event **fires when the user hits return**."
109 "The **`Text`** also has a special **`on_submit` event**. The `on_submit` event **fires when the user hits return**."
110 ]
110 ]
111 },
111 },
112 {
112 {
113 "cell_type": "code",
113 "cell_type": "code",
114 "execution_count": null,
114 "execution_count": null,
115 "metadata": {
115 "metadata": {
116 "collapsed": false
116 "collapsed": false
117 },
117 },
118 "outputs": [],
118 "outputs": [],
119 "source": [
119 "source": [
120 "text = widgets.Text()\n",
120 "text = widgets.Text()\n",
121 "display(text)\n",
121 "display(text)\n",
122 "\n",
122 "\n",
123 "def handle_submit(sender):\n",
123 "def handle_submit(sender):\n",
124 " print(text.value)\n",
124 " print(text.value)\n",
125 "\n",
125 "\n",
126 "text.on_submit(handle_submit)"
126 "text.on_submit(handle_submit)"
127 ]
127 ]
128 },
128 },
129 {
129 {
130 "cell_type": "markdown",
130 "cell_type": "markdown",
131 "metadata": {
131 "metadata": {
132 "slideshow": {
132 "slideshow": {
133 "slide_type": "slide"
133 "slide_type": "slide"
134 }
134 }
135 },
135 },
136 "source": [
136 "source": [
137 "## Traitlet events"
137 "## Traitlet events"
138 ]
138 ]
139 },
139 },
140 {
140 {
141 "cell_type": "markdown",
141 "cell_type": "markdown",
142 "metadata": {},
142 "metadata": {},
143 "source": [
143 "source": [
144 "**Widget properties are IPython traitlets** and **traitlets are eventful**. To handle changes, the **`on_trait_change` method** of the widget can be used to **register a callback**. The doc string for `on_trait_change` can be seen below."
144 "**Widget properties are IPython traitlets** and **traitlets are eventful**. To handle changes, the **`on_trait_change` method** of the widget can be used to **register a callback**. The doc string for `on_trait_change` can be seen below."
145 ]
145 ]
146 },
146 },
147 {
147 {
148 "cell_type": "code",
148 "cell_type": "code",
149 "execution_count": null,
149 "execution_count": null,
150 "metadata": {
150 "metadata": {
151 "collapsed": false
151 "collapsed": false
152 },
152 },
153 "outputs": [],
153 "outputs": [],
154 "source": [
154 "source": [
155 "print(widgets.Widget.on_trait_change.__doc__)"
155 "print(widgets.Widget.on_trait_change.__doc__)"
156 ]
156 ]
157 },
157 },
158 {
158 {
159 "cell_type": "markdown",
159 "cell_type": "markdown",
160 "metadata": {
160 "metadata": {
161 "slideshow": {
161 "slideshow": {
162 "slide_type": "slide"
162 "slide_type": "slide"
163 }
163 }
164 },
164 },
165 "source": [
165 "source": [
166 "### Signatures"
166 "### Signatures"
167 ]
167 ]
168 },
168 },
169 {
169 {
170 "cell_type": "markdown",
170 "cell_type": "markdown",
171 "metadata": {},
171 "metadata": {},
172 "source": [
172 "source": [
173 "Mentioned in the doc string, the callback registered can have **4 possible signatures**:\n",
173 "Mentioned in the doc string, the callback registered can have **4 possible signatures**:\n",
174 "\n",
174 "\n",
175 "- callback()\n",
175 "- callback()\n",
176 "- callback(trait_name)\n",
176 "- callback(trait_name)\n",
177 "- callback(trait_name, new_value)\n",
177 "- callback(trait_name, new_value)\n",
178 "- callback(trait_name, old_value, new_value)\n",
178 "- callback(trait_name, old_value, new_value)\n",
179 "\n",
179 "\n",
180 "Using this method, an example of how to output an `IntSlider`'s value as it is changed can be seen below."
180 "Using this method, an example of how to output an `IntSlider`'s value as it is changed can be seen below."
181 ]
181 ]
182 },
182 },
183 {
183 {
184 "cell_type": "code",
184 "cell_type": "code",
185 "execution_count": null,
185 "execution_count": null,
186 "metadata": {
186 "metadata": {
187 "collapsed": false
187 "collapsed": false
188 },
188 },
189 "outputs": [],
189 "outputs": [],
190 "source": [
190 "source": [
191 "int_range = widgets.IntSlider()\n",
191 "int_range = widgets.IntSlider()\n",
192 "display(int_range)\n",
192 "display(int_range)\n",
193 "\n",
193 "\n",
194 "def on_value_change(name, value):\n",
194 "def on_value_change(name, value):\n",
195 " print(value)\n",
195 " print(value)\n",
196 "\n",
196 "\n",
197 "int_range.on_trait_change(on_value_change, 'value')"
197 "int_range.on_trait_change(on_value_change, 'value')"
198 ]
198 ]
199 },
199 },
200 {
200 {
201 "cell_type": "markdown",
201 "cell_type": "markdown",
202 "metadata": {},
202 "metadata": {},
203 "source": [
203 "source": [
204 "# Linking Widgets"
205 ]
206 },
207 {
208 "cell_type": "markdown",
209 "metadata": {},
210 "source": [
211 "Often, you may want to simply link widget attributes together. Synchronization of attributes can be done in a simpler way than by using bare traitlets events. \n",
212 "\n",
213 "The first method is to use the `link` and `directional_link` functions from the `traitlets` module. "
214 ]
215 },
216 {
217 "cell_type": "markdown",
218 "metadata": {},
219 "source": [
220 "## Linking traitlets attributes from the server side"
221 ]
222 },
223 {
224 "cell_type": "code",
225 "execution_count": null,
226 "metadata": {
227 "collapsed": false
228 },
229 "outputs": [],
230 "source": [
231 "from IPython.utils import traitlets"
232 ]
233 },
234 {
235 "cell_type": "code",
236 "execution_count": null,
237 "metadata": {
238 "collapsed": false
239 },
240 "outputs": [],
241 "source": [
242 "caption = widgets.Latex(value = 'The values of slider1, slider2 and slider3 are synchronized')\n",
243 "sliders1, slider2, slider3 = widgets.IntSlider(description='Slider 1'),\\\n",
244 " widgets.IntSlider(description='Slider 2'),\\\n",
245 " widgets.IntSlider(description='Slider 3')\n",
246 "l = traitlets.link((sliders1, 'value'), (slider2, 'value'), (slider3, 'value'))\n",
247 "display(caption, sliders1, slider2, slider3)"
248 ]
249 },
250 {
251 "cell_type": "code",
252 "execution_count": null,
253 "metadata": {
254 "collapsed": false
255 },
256 "outputs": [],
257 "source": [
258 "caption = widgets.Latex(value = 'Changes in source values are reflected in target1 and target2')\n",
259 "source, target1, target2 = widgets.IntSlider(description='Source'),\\\n",
260 " widgets.IntSlider(description='Target 1'),\\\n",
261 " widgets.IntSlider(description='Target 2')\n",
262 "traitlets.dlink((source, 'value'), (target1, 'value'), (target2, 'value'))\n",
263 "display(caption, source, target1, target2)"
264 ]
265 },
266 {
267 "cell_type": "markdown",
268 "metadata": {},
269 "source": [
270 "Function `traitlets.link` returns a `Link` object. The link can be broken by calling the `unlink` method."
271 ]
272 },
273 {
274 "cell_type": "code",
275 "execution_count": null,
276 "metadata": {
277 "collapsed": false
278 },
279 "outputs": [],
280 "source": [
281 "# l.unlink()"
282 ]
283 },
284 {
285 "cell_type": "markdown",
286 "metadata": {},
287 "source": [
288 "## Linking widgets attributes from the client side"
289 ]
290 },
291 {
292 "cell_type": "markdown",
293 "metadata": {},
294 "source": [
295 "When synchronizing traitlets attributes, you may experience a lag because of the latency dues to the rountrip to the server side. You can also directly link widgets attributes, either in a unidirectional or a bidirectional fashion using the link widgets. "
296 ]
297 },
298 {
299 "cell_type": "code",
300 "execution_count": null,
301 "metadata": {
302 "collapsed": false
303 },
304 "outputs": [],
305 "source": [
306 "caption = widgets.Latex(value = 'The values of range1, range2 and range3 are synchronized')\n",
307 "range1, range2, range3 = widgets.IntSlider(description='Range 1'),\\\n",
308 " widgets.IntSlider(description='Range 2'),\\\n",
309 " widgets.IntSlider(description='Range 3')\n",
310 "l = widgets.link((range1, 'value'), (range2, 'value'), (range3, 'value'))\n",
311 "display(caption, range1, range2, range3)"
312 ]
313 },
314 {
315 "cell_type": "code",
316 "execution_count": null,
317 "metadata": {
318 "collapsed": false
319 },
320 "outputs": [],
321 "source": [
322 "caption = widgets.Latex(value = 'Changes in source_range values are reflected in target_range1 and target_range2')\n",
323 "source_range, target_range1, target_range2 = widgets.IntSlider(description='Source range'),\\\n",
324 " widgets.IntSlider(description='Target range 1'),\\\n",
325 " widgets.IntSlider(description='Target range 2')\n",
326 "widgets.dlink((source_range, 'value'), (target_range1, 'value'), (target_range2, 'value'))\n",
327 "display(caption, source_range, target_range1, target_range2)"
328 ]
329 },
330 {
331 "cell_type": "markdown",
332 "metadata": {},
333 "source": [
334 "Function `widgets.link` returns a `Link` widget. The link can be broken by calling the `unlink` method."
335 ]
336 },
337 {
338 "cell_type": "code",
339 "execution_count": null,
340 "metadata": {
341 "collapsed": false
342 },
343 "outputs": [],
344 "source": [
345 "# l.unlink()"
346 ]
347 },
348 {
349 "cell_type": "markdown",
350 "metadata": {},
351 "source": [
204 "[Index](Index.ipynb) - [Back](Widget List.ipynb) - [Next](Widget Styling.ipynb)"
352 "[Index](Index.ipynb) - [Back](Widget List.ipynb) - [Next](Widget Styling.ipynb)"
205 ]
353 ]
206 }
354 }
207 ],
355 ],
208 "metadata": {
356 "metadata": {
209 "cell_tags": [
357 "cell_tags": [
210 [
358 [
211 "<None>",
359 "<None>",
212 null
360 null
213 ]
361 ]
214 ],
362 ],
215 "kernelspec": {
363 "kernelspec": {
364 "display_name": "Python 2",
365 "name": "python2"
366 },
367 "language_info": {
216 "codemirror_mode": {
368 "codemirror_mode": {
217 "name": "python",
369 "name": "ipython",
218 "version": 2
370 "version": 2
219 },
371 },
220 "display_name": "Python 2",
372 "file_extension": ".py",
221 "language": "python",
373 "mimetype": "text/x-python",
222 "name": "python2"
374 "name": "python",
375 "nbconvert_exporter": "python",
376 "pygments_lexer": "ipython2",
377 "version": "2.7.8"
223 },
378 },
224 "signature": "sha256:05a3e92089b37f68e3134587ffef6ef73830e5f8b3c515ba24640d7c803820c3"
379 "signature": "sha256:b6eadc174d0d9c1907518d9f37760eb3dca3aec0ef1f3746e6f0537a36e99919"
225 },
380 },
226 "nbformat": 4,
381 "nbformat": 4,
227 "nbformat_minor": 0
382 "nbformat_minor": 0
228 } No newline at end of file
383 }
General Comments 0
You need to be logged in to leave comments. Login now