##// END OF EJS Templates
make js / Python widgets symmetrical...
MinRK -
Show More
@@ -31,6 +31,7 b' var IPython = (function (IPython) {'
31 };
31 };
32
32
33 WidgetManager.prototype.init_kernel = function (kernel) {
33 WidgetManager.prototype.init_kernel = function (kernel) {
34 // connect the kernel, and register message handlers
34 this.kernel = kernel;
35 this.kernel = kernel;
35 var msg_types = ['widget_create', 'widget_destroy', 'widget_update'];
36 var msg_types = ['widget_create', 'widget_destroy', 'widget_update'];
36 for (var i = 0; i < msg_types.length; i++) {
37 for (var i = 0; i < msg_types.length; i++) {
@@ -44,6 +45,20 b' var IPython = (function (IPython) {'
44 this.widget_types[widget_type] = constructor;
45 this.widget_types[widget_type] = constructor;
45 };
46 };
46
47
48 WidgetManager.prototype.register_widget = function (widget) {
49 // Register a widget in the mapping
50 this.widgets[widget.widget_id] = widget;
51 widget.kernel = this.kernel;
52 return widget.widget_id;
53 };
54
55 WidgetManager.prototype.unregister_widget = function (widget_id) {
56 // Remove a widget from the mapping
57 delete this.widgets[widget_id];
58 };
59
60 // widget message handlers
61
47 WidgetManager.prototype.widget_create = function (msg) {
62 WidgetManager.prototype.widget_create = function (msg) {
48 var content = msg.content;
63 var content = msg.content;
49 var constructor = this.widget_types[content.widget_type];
64 var constructor = this.widget_types[content.widget_type];
@@ -52,7 +67,10 b' var IPython = (function (IPython) {'
52 console.log("Available widget types are: ", this.widget_types);
67 console.log("Available widget types are: ", this.widget_types);
53 return;
68 return;
54 }
69 }
55 var widget = new constructor(this.kernel, content);
70 var widget = new constructor(content.widget_id);
71 this.register_widget(widget);
72 widget.handle_create(content.data);
73
56 this.widgets[content.widget_id] = widget;
74 this.widgets[content.widget_id] = widget;
57 };
75 };
58
76
@@ -79,39 +97,48 b' var IPython = (function (IPython) {'
79 // Widget base class
97 // Widget base class
80 //-----------------------------------------------------------------------
98 //-----------------------------------------------------------------------
81
99
82 var Widget = function (kernel, content) {
100 var Widget = function (widget_id) {
83 this.kernel = kernel;
101 this.widget_id = widget_id;
84 if (!content) return;
102 this.widget_type = 'widget';
85 this.widget_id = content.widget_id;
86 this.handle_create(content.data);
87 };
103 };
88
104
89 Widget.prototype.handle_create = function (data) {
105 // methods for sending messages
90 };
106 Widget.prototype.create = function (data) {
91
107 var content = {
92 Widget.prototype.handle_update = function (data) {
108 widget_id : this.widget_id,
109 widget_type : this.widget_type,
110 data : data || {},
93 };
111 };
94
112 this.kernel.send_shell_message("widget_create", content);
95 Widget.prototype.handle_destroy = function (data) {
96 };
113 };
97
114
98 Widget.prototype.update = function (data) {
115 Widget.prototype.update = function (data) {
99 var content = {
116 var content = {
100 widget_id : this.widget_id,
117 widget_id : this.widget_id,
101 data : data,
118 data : data || {},
102 };
119 };
103 this.kernel.send_shell_message("widget_update", content);
120 this.kernel.send_shell_message("widget_update", content);
104 };
121 };
105
122
106
107 Widget.prototype.destroy = function (data) {
123 Widget.prototype.destroy = function (data) {
108 var content = {
124 var content = {
109 widget_id : this.widget_id,
125 widget_id : this.widget_id,
110 data : data,
126 data : data || {},
111 };
127 };
112 this.kernel.send_shell_message("widget_destroy", content);
128 this.kernel.send_shell_message("widget_destroy", content);
113 };
129 };
114
130
131 // methods for handling incoming messages
132
133 Widget.prototype.handle_create = function (data) {
134 };
135
136 Widget.prototype.handle_update = function (data) {
137 };
138
139 Widget.prototype.handle_destroy = function (data) {
140 };
141
115 IPython.WidgetManager = WidgetManager;
142 IPython.WidgetManager = WidgetManager;
116 IPython.Widget = Widget;
143 IPython.Widget = Widget;
117
144
@@ -11,11 +11,11 b''
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 from weakref import ref
15
16 from IPython.config import LoggingConfigurable
14 from IPython.config import LoggingConfigurable
17 from IPython.core.prompts import LazyEvaluate
15 from IPython.core.prompts import LazyEvaluate
18 from IPython.core.getipython import get_ipython
16 from IPython.core.getipython import get_ipython
17
18 from IPython.utils.importstring import import_item
19 from IPython.utils.traitlets import Instance, Unicode, Dict, Any
19 from IPython.utils.traitlets import Instance, Unicode, Dict, Any
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
@@ -30,6 +30,7 b' def lazy_keys(dikt):'
30 """
30 """
31 return LazyEvaluate(lambda d: list(d.keys()))
31 return LazyEvaluate(lambda d: list(d.keys()))
32
32
33
33 class WidgetManager(LoggingConfigurable):
34 class WidgetManager(LoggingConfigurable):
34 """Manager for Widgets in the Kernel"""
35 """Manager for Widgets in the Kernel"""
35
36
@@ -46,25 +47,32 b' class WidgetManager(LoggingConfigurable):'
46 return self.shell.parent.session
47 return self.shell.parent.session
47
48
48 widgets = Dict()
49 widgets = Dict()
50 widget_types = Dict()
49
51
50 # Public APIs
52 # Public APIs
51
53
54 def register_widget_type(self, widget_type, constructor):
55 """Register a constructor for a given widget_type
56
57 constructor can be a Widget class or an importstring for a Widget class.
58 """
59 if isinstance(constructor, basestring):
60 constructor = import_item(constructor)
61
62 self.widget_types[widget_type] = constructor
63
52 def register_widget(self, widget):
64 def register_widget(self, widget):
53 """Register a new widget"""
65 """Register a new widget"""
54 self.widgets[widget.widget_id] = ref(widget)
66 widget_id = widget.widget_id
55 widget.shell = self.shell
67 widget.shell = self.shell
56 widget.iopub_socket = self.iopub_socket
68 widget.iopub_socket = self.iopub_socket
57 widget.create()
69 self.widgets[widget_id] = widget
58 return widget.widget_id
70 return widget_id
59
71
60 def unregister_widget(self, widget_id):
72 def unregister_widget(self, widget_id):
61 """Unregister a widget, and destroy its counterpart"""
73 """Unregister a widget, and destroy its counterpart"""
62 # unlike get_widget, this should raise a KeyError
74 # unlike get_widget, this should raise a KeyError
63 widget_ref = self.widgets.pop(widget_id)
75 widget = self.widgets.pop(widget_id)
64 widget = widget_ref()
65 if widget is None:
66 # already destroyed, nothing to do
67 return
68 widget.destroy()
76 widget.destroy()
69
77
70 def get_widget(self, widget_id):
78 def get_widget(self, widget_id):
@@ -80,16 +88,27 b' class WidgetManager(LoggingConfigurable):'
80 self.log.debug("Current widgets: %s", lazy_keys(self.widgets))
88 self.log.debug("Current widgets: %s", lazy_keys(self.widgets))
81 return
89 return
82 # call, because we store weakrefs
90 # call, because we store weakrefs
83 widget = self.widgets[widget_id]()
91 widget = self.widgets[widget_id]
84 if widget is None:
85 self.log.error("Widget %s has been removed", widget_id)
86 del self.widgets[widget_id]
87 self.log.debug("Current widgets: %s", lazy_keys(self.widgets))
88 return
89 return widget
92 return widget
90
93
91 # Message handlers
94 # Message handlers
92
95
96 def widget_create(self, stream, ident, msg):
97 """Handler for widget_update messages"""
98 content = msg['content']
99 widget_id = content['widget_id']
100 widget_type = content['widget_type']
101 constructor = self.widget_types.get(widget_type, None)
102 if constructor is None:
103 self.log.error("No such widget_type registered: %s", widget_type)
104 return
105 widget = constructor(widget_id=widget_id,
106 shell=self.shell,
107 iopub_socket=self.iopub_socket,
108 _create_data=content['data'],
109 )
110 self.register_widget(widget)
111
93 def widget_update(self, stream, ident, msg):
112 def widget_update(self, stream, ident, msg):
94 """Handler for widget_update messages"""
113 """Handler for widget_update messages"""
95 content = msg['content']
114 content = msg['content']
@@ -13,6 +13,7 b''
13
13
14 import uuid
14 import uuid
15
15
16 from IPython.core.getipython import get_ipython
16 from IPython.config import LoggingConfigurable
17 from IPython.config import LoggingConfigurable
17 from IPython.utils.traitlets import Instance, Unicode, Bytes, Bool, Dict, Any
18 from IPython.utils.traitlets import Instance, Unicode, Bytes, Bool, Dict, Any
18
19
@@ -47,6 +48,18 b' class Widget(LoggingConfigurable):'
47 def _widget_id_default(self):
48 def _widget_id_default(self):
48 return uuid.uuid4().hex
49 return uuid.uuid4().hex
49
50
51 primary = Bool(False, help="Am I the primary or secondary Widget?")
52
53 def __init__(self, **kwargs):
54 super(Widget, self).__init__(**kwargs)
55 get_ipython().widget_manager.register_widget(self)
56 if self.primary:
57 # I am primary, create my peer
58 self.create()
59 else:
60 # I am secondary, handle creation
61 self.handle_create(self._create_data)
62
50 def _publish_msg(self, msg_type, data=None, **keys):
63 def _publish_msg(self, msg_type, data=None, **keys):
51 """Helper for sending a widget message on IOPub"""
64 """Helper for sending a widget message on IOPub"""
52 data = {} if data is None else data
65 data = {} if data is None else data
@@ -61,16 +74,20 b' class Widget(LoggingConfigurable):'
61
74
62 # publishing messages
75 # publishing messages
63
76
64 def create(self):
77 def create(self, data=None):
65 """Create the frontend-side version of this widget"""
78 """Create the frontend-side version of this widget"""
66 self._publish_msg('widget_create', self._create_data, widget_type = self.widget_type)
79 if data is None:
80 data = self._create_data
81 self._publish_msg('widget_create', data, widget_type=self.widget_type)
67
82
68 def destroy(self):
83 def destroy(self, data=None):
69 """Destroy the frontend-side version of this widget"""
84 """Destroy the frontend-side version of this widget"""
70 if self._destroyed:
85 if self._destroyed:
71 # only destroy once
86 # only destroy once
72 return
87 return
73 self._publish_msg('widget_destroy', self._destroy_data)
88 if data is None:
89 data = self._destroy_data
90 self._publish_msg('widget_destroy', data)
74 self._destroyed = True
91 self._destroyed = True
75
92
76 def update(self, data=None):
93 def update(self, data=None):
@@ -79,6 +96,10 b' class Widget(LoggingConfigurable):'
79
96
80 # handling of incoming messages
97 # handling of incoming messages
81
98
99 def handle_create(self, data):
100 """Handle a widget_create message"""
101 self.log.debug("handle_create %s", data)
102
82 def handle_destroy(self, data):
103 def handle_destroy(self, data):
83 """Handle a widget_destroy message"""
104 """Handle a widget_destroy message"""
84 self.log.debug("handle_destroy %s", data)
105 self.log.debug("handle_destroy %s", data)
@@ -168,7 +168,7 b' class Kernel(Configurable):'
168 for msg_type in msg_types:
168 for msg_type in msg_types:
169 self.shell_handlers[msg_type] = getattr(self, msg_type)
169 self.shell_handlers[msg_type] = getattr(self, msg_type)
170
170
171 widget_msg_types = [ 'widget_update', 'widget_destroy' ]
171 widget_msg_types = [ 'widget_create', 'widget_update', 'widget_destroy' ]
172 widget_manager = self.shell.widget_manager
172 widget_manager = self.shell.widget_manager
173 for msg_type in widget_msg_types:
173 for msg_type in widget_msg_types:
174 self.shell_handlers[msg_type] = getattr(widget_manager, msg_type)
174 self.shell_handlers[msg_type] = getattr(widget_manager, msg_type)
General Comments 0
You need to be logged in to leave comments. Login now