From 15b3b7e5ea4135a80d78f4c72521fbb137927374 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Wed, 2 Oct 2013 18:53:14 +0000 Subject: [PATCH 001/473] Added widget output area --- IPython/html/static/notebook/js/codecell.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/IPython/html/static/notebook/js/codecell.js b/IPython/html/static/notebook/js/codecell.js index c21a13618dc..25afa3f05e8 100644 --- a/IPython/html/static/notebook/js/codecell.js +++ b/IPython/html/static/notebook/js/codecell.js @@ -132,8 +132,14 @@ var IPython = (function (IPython) { $(this.code_mirror.getInputField()).attr("spellcheck", "false"); inner_cell.append(input_area); input.append(prompt).append(inner_cell); + + var widget_area = $('
').addClass('widget_area'); + var widget_prompt = $('
').addClass('prompt'); + var widget_subarea = $('
').addClass('widget_subarea'); + widget_area.append(widget_prompt).append(widget_subarea); + var output = $('
'); - cell.append(input).append(output); + cell.append(input).append(widget_area).append(output); this.element = cell; this.output_area = new IPython.OutputArea(output, true); this.completer = new IPython.Completer(this); From d1d9dfe049b91303fbb06145c8439a6ebc529887 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Wed, 2 Oct 2013 19:20:40 +0000 Subject: [PATCH 002/473] Add widget subarea style --- IPython/html/static/notebook/less/style.less | 2 -- IPython/html/static/notebook/less/widgetarea.less | 8 ++++++++ IPython/html/static/style/style.min.css | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 IPython/html/static/notebook/less/widgetarea.less diff --git a/IPython/html/static/notebook/less/style.less b/IPython/html/static/notebook/less/style.less index 27fc9599c5f..8d489e17776 100644 --- a/IPython/html/static/notebook/less/style.less +++ b/IPython/html/static/notebook/less/style.less @@ -11,5 +11,3 @@ @import "savewidget.less"; @import "toolbar.less"; @import "tooltip.less"; - - diff --git a/IPython/html/static/notebook/less/widgetarea.less b/IPython/html/static/notebook/less/widgetarea.less new file mode 100644 index 00000000000..1921522236f --- /dev/null +++ b/IPython/html/static/notebook/less/widgetarea.less @@ -0,0 +1,8 @@ + +/* This class is for the widget subarea inside the widget_area and after + the prompt div. */ +div.widget_subarea { + padding: 0.44em 0.4em 0.4em 1px; + margin-left: 6px; + .box-flex1(); +} diff --git a/IPython/html/static/style/style.min.css b/IPython/html/static/style/style.min.css index f20a963b9ba..fefd7be2b19 100644 --- a/IPython/html/static/style/style.min.css +++ b/IPython/html/static/style/style.min.css @@ -1584,3 +1584,4 @@ span#checkpoint_status,span#autosave_status{font-size:small;} .ipython_tooltip .tooltiptext pre{border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;font-size:100%;background-color:#f7f7f7;} .pretooltiparrow{left:0px;margin:0px;top:-16px;width:40px;height:16px;overflow:hidden;position:absolute;} .pretooltiparrow:before{background-color:#f7f7f7;border:1px #ababab solid;z-index:11;content:"";position:absolute;left:15px;top:10px;width:25px;height:25px;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);} +div.widget_subarea{padding:0.44em 0.4em 0.4em 1px;margin-left:6px;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;} From 3467e524a16e0ec0ef39dc9b5587dec0492d69e5 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Thu, 10 Oct 2013 08:21:31 -0700 Subject: [PATCH 003/473] Added dependencies to page.html template and added widget.js to notebook.html --- IPython/html/templates/notebook.html | 1 + IPython/html/templates/page.html | 2 ++ 2 files changed, 3 insertions(+) diff --git a/IPython/html/templates/notebook.html b/IPython/html/templates/notebook.html index 7d05482661b..45d3e29d075 100644 --- a/IPython/html/templates/notebook.html +++ b/IPython/html/templates/notebook.html @@ -291,6 +291,7 @@ + diff --git a/IPython/html/templates/page.html b/IPython/html/templates/page.html index 5bef21d42d6..25539cac83c 100644 --- a/IPython/html/templates/page.html +++ b/IPython/html/templates/page.html @@ -71,6 +71,8 @@ + + From 8493b7d4f5d4b7de848a2e233fb0a8e0e497bd4d Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Thu, 10 Oct 2013 08:22:39 -0700 Subject: [PATCH 004/473] Added widget.js --- IPython/html/static/notebook/js/notebook.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js index 6cc0745458b..e1cc2b1c682 100644 --- a/IPython/html/static/notebook/js/notebook.js +++ b/IPython/html/static/notebook/js/notebook.js @@ -1,5 +1,5 @@ //---------------------------------------------------------------------------- -// Copyright (C) 2011 The IPython Development Team +// Copyright (C) 2008-2013 The IPython Development Team // // Distributed under the terms of the BSD License. The full license is in // the file COPYING, distributed as part of this software. From d12dc75e953f7f5db7475b4c3eac7da8b4d8ac2d Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Thu, 10 Oct 2013 08:23:19 -0700 Subject: [PATCH 005/473] Added widget.py --- IPython/html/widgets/__init__.py | 1 + IPython/html/widgets/widget.py | 148 +++++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+) create mode 100644 IPython/html/widgets/__init__.py create mode 100644 IPython/html/widgets/widget.py diff --git a/IPython/html/widgets/__init__.py b/IPython/html/widgets/__init__.py new file mode 100644 index 00000000000..58dd1472d80 --- /dev/null +++ b/IPython/html/widgets/__init__.py @@ -0,0 +1 @@ +from widget import Widget \ No newline at end of file diff --git a/IPython/html/widgets/widget.py b/IPython/html/widgets/widget.py new file mode 100644 index 00000000000..5f7feb06483 --- /dev/null +++ b/IPython/html/widgets/widget.py @@ -0,0 +1,148 @@ +from IPython.kernel.comm import Comm +from IPython.config import LoggingConfigurable +from IPython.utils.traitlets import Unicode, Float, Bool, Dict +from IPython.display import clear_output + +from copy import copy +import uuid +import sys + + +class Widget(Comm): + + ### Public declarations + target_name = Unicode('widget') + default_view_name = Unicode() + + + ### Private/protected declarations + _keys = [] + _property_lock = False + _parent = None + _children = [] + _css = Dict() + + + ### Public constructor + def __init__(self, parent=None, **kwargs): + super(Widget, self).__init__(**kwargs) + + self._children = [] + if parent is not None: + parent._children.append(self) + self._parent = parent + + self.comm = Comm(target_name=self.target_name) + self.comm.on_msg(self._handle_msg) + + # Register after init to allow default values to be specified + self.on_trait_change(self._handle_property_changed, self.keys) + + # Set initial properties on client model. + self.send_state() + + + def __del__(self): + self.close() + + def close(self): + self.comm.close() + del self.comm + + + ### Properties + def _get_parent(self): + return self._parent + parent = property(_get_parent) + + + def _get_children(self): + return copy(self._children) + children = property(_get_children) + + + def _get_keys(self): + keys = ['_css'] + keys.extend(self._keys) + return keys + keys = property(_get_keys) + + def _get_css(self, key, selector=""): + if selector in self._css and key in self._css[selector]: + return self._css[selector][key] + else: + return None + def _set_css(self, value, key, selector=""): + if selector not in self._css: + self._css[selector] = {} + + # Only update the property if it has changed. + if not (key in self._css[selector] and value in self._css[selector][key]): + self._css[selector][key] = value + self.send_state() # Send new state to client. + + css = property(_get_css, _set_css) + + + ### Event handlers + def _handle_msg(self, msg): + + # Handle backbone sync methods + sync_method = msg['content']['data']['sync_method'] + sync_data = msg['content']['data']['sync_data'] + if sync_method.lower() in ['create', 'update']: + self._handle_recieve_state(sync_data) + + + def _handle_recieve_state(self, sync_data): + self._property_lock = True + try: + + # Use _keys instead of keys - Don't get retrieve the css from the client side. + for name in self._keys: + if name in sync_data: + setattr(self, name, sync_data[name]) + finally: + self._property_lock = False + + + def _handle_property_changed(self, name, old, new): + if not self._property_lock: + # TODO: Validate properties. + # Send new state to frontend + self.send_state() + + + ### Public methods + def show(self, view_name=None): + if not view_name: + view_name = self.default_view_name + if not view_name: + view_name = self.target_name + + # Make sure model is syncronized + self.send_state() + + # Show view. + if self.parent is None: + self.comm.send({"method": "show", "view_name": view_name}) + else: + self.comm.send({"method": "show", + "view_name": view_name, + "parent": self.parent.comm.comm_id}) + + # Now show children if any. + for child in self.children: + child.show() + + + def send_state(self): + state = {} + for key in self.keys: + try: + state[key] = getattr(self, key) + except Exception as e: + pass # Eat errors, nom nom nom + self.comm.send({"method": "update", + "state": state}) + \ No newline at end of file From 649b42e5b3b079aa5ff36501c44519f1e2f75b6e Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Thu, 10 Oct 2013 08:25:08 -0700 Subject: [PATCH 006/473] Added widjet.js Other commit actually added notebook.js changes --- IPython/html/static/notebook/js/widget.js | 229 ++++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 IPython/html/static/notebook/js/widget.js diff --git a/IPython/html/static/notebook/js/widget.js b/IPython/html/static/notebook/js/widget.js new file mode 100644 index 00000000000..dca305b280a --- /dev/null +++ b/IPython/html/static/notebook/js/widget.js @@ -0,0 +1,229 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2013 The IPython Development Team +// +// Distributed under the terms of the BSD License. The full license is in +// the file COPYING, distributed as part of this software. +//---------------------------------------------------------------------------- + +//============================================================================ +// WidgetModel, WidgetView, and WidgetManager +//============================================================================ +/** + * Base Widget classes + * @module IPython + * @namespace IPython + * @submodule widget + */ + + +// require(['components/underscore/underscore-min.js', +// 'components/backbone/backbone-min.js'], + +var IPython = function (IPython) { + "use strict"; + + //----------------------------------------------------------------------- + // WidgetModel class + //----------------------------------------------------------------------- + var WidgetModel = Backbone.Model.extend({}); + + + //----------------------------------------------------------------------- + // WidgetView class + //----------------------------------------------------------------------- + var WidgetView = Backbone.View.extend({ + + initialize: function() { + this.model.on('change',this.refresh,this); + }, + + refresh: function() { + this.update(); + + if (this.model.css != undefined) { + for (var selector in this.model.css) { + if (this.model.css.hasOwnProperty(selector)) { + + // Get the elements via the css selector. If the selector is + // blank, assume the current element is the target. + var elements = this.$el.find(selector); + if (selector=='') { + elements = this.$el; + } + + // Apply the css traits to all elements that match the selector. + if (elements.length>0){ + var css_traits = this.model.css[selector]; + for (var css_key in css_traits) { + if (css_traits.hasOwnProperty(css_key)) { + elements.css(css_key, css_traits[css_key]); + } + } + } + } + } + } + }, + }); + + + //----------------------------------------------------------------------- + // WidgetManager class + //----------------------------------------------------------------------- + // Public constructor + var WidgetManager = function(comm_manager){ + this.comm_manager = comm_manager; + this.widget_model_types = {}; + this.widget_view_types = {}; + this.model_widget_views = {}; + + var that = this; + Backbone.sync = function(method, model, options, error) { + var result = that.send_sync(method, model); + if (options.success) { + options.success(result); + } + }; + } + + // Register a widget model type. + WidgetManager.prototype.register_widget_model = function (widget_model_name, widget_model_type) { + + // Register the widget with the comm manager. Make sure to pass this object's context + // in so `this` works in the call back. + this.comm_manager.register_target(widget_model_name, $.proxy(this.handle_com_open, this)); + + // Register the types of the model and view correspong to this widget type. Later + // the widget manager will initialize these when the comm is opened. + this.widget_model_types[widget_model_name] = widget_model_type; + } + + // Register a widget view type. + WidgetManager.prototype.register_widget_view = function (widget_view_name, widget_view_type) { + this.widget_view_types[widget_view_name] = widget_view_type; + } + + // Handle when a comm is opened. + WidgetManager.prototype.handle_com_open = function (comm, msg) { + var widget_type_name = msg.content.target_name; + + // Create the corresponding widget model. + var widget_model = new this.widget_model_types[widget_type_name]; + + // Remember comm associated with the model. + widget_model.comm = comm; + comm.model = widget_model; + + // Create an array to remember the views associated with the model. + widget_model.views = []; + + // Add a handle to delete the control when the comm is closed. + var that = this; + var handle_close = function(msg) { + that.handle_comm_closed(comm, msg); + } + comm.on_close(handle_close); + + // Handle incomming messages. + var handle_msg = function(msg) { + that.handle_comm_msg(comm, msg); + } + comm.on_msg(handle_msg); + } + + // Create view that represents the model. + WidgetManager.prototype.show_view = function (widget_area, widget_model, widget_view_name) { + var widget_view = new this.widget_view_types[widget_view_name]({model: widget_model}); + widget_view.render(); + widget_model.views.push(widget_view); + + // Add the view's element to cell's widget div. + widget_area + .append($("
").append(widget_view.$el)); + + // Update the view based on the model contents. + widget_view.refresh(); + } + + // Handle incomming comm msg. + WidgetManager.prototype.handle_comm_msg = function (comm, msg) { + // Different logic for different methods. + var method = msg.content.data.method; + switch (method){ + case 'show': + + // TODO: Get cell from registered output handler. + var cell = IPython.notebook.get_cell(IPython.notebook.get_selected_index()-1); + var widget_subarea = cell.element.find('.widget_area').find('.widget_subarea'); + + if (msg.content.data.parent != undefined) { + var find_results = widget_subarea.find("." + msg.content.data.parent); + if (find_results.length > 0) { + widget_subarea = find_results; + } + } + + this.show_view(widget_subarea, comm.model, msg.content.data.view_name); + break; + case 'update': + this.handle_update(comm, msg.content.data.state); + break; + } + } + + // Handle when a widget is updated via the python side. + WidgetManager.prototype.handle_update = function (comm, state) { + for (var key in state) { + if (state.hasOwnProperty(key)) { + if (key=="_css"){ + comm.model.css = state[key]; + } else { + comm.model.set(key, state[key]); + } + } + } + comm.model.save(); + } + + // Handle when a widget is closed. + WidgetManager.prototype.handle_comm_closed = function (comm, msg) { + for (var view_index in comm.model.views) { + var view = comm.model.views[view_index]; + view.remove(); + } + } + + // Get the cell output area corresponding to the comm. + WidgetManager.prototype._get_comm_outputarea = function (comm) { + // TODO: get element from comm instead of guessing + var cell = IPython.notebook.get_cell(IPython.notebook.get_selected_index()) + return cell.output_area; + } + + // Send widget state to python backend. + WidgetManager.prototype.send_sync = function (method, model) { + + // Create a callback for the output if the widget has an output area associate with it. + var callbacks = {}; + var comm = model.comm; + var outputarea = this._get_comm_outputarea(comm); + if (outputarea != null) { + callbacks = { + iopub : { + output : $.proxy(outputarea.handle_output, outputarea), + clear_output : $.proxy(outputarea.handle_clear_output, outputarea)} + }; + }; + + var data = {sync_method: method, sync_data: model.toJSON()}; + comm.send(data, callbacks); + return data; + } + + IPython.WidgetManager = WidgetManager; + IPython.WidgetModel = WidgetModel; + IPython.WidgetView = WidgetView; + + return IPython; + +}; From 57ec09e18fa1e68b4b02d0ce57738b4161f14b4f Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Thu, 10 Oct 2013 16:45:21 +0000 Subject: [PATCH 007/473] Fixed widget.js and notebook.js so IPython.notebook.widget_manager is created. --- IPython/html/static/notebook/js/notebook.js | 20 +++++++------------- IPython/html/static/notebook/js/widget.js | 5 +++-- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js index e1cc2b1c682..13420142b2e 100644 --- a/IPython/html/static/notebook/js/notebook.js +++ b/IPython/html/static/notebook/js/notebook.js @@ -1288,25 +1288,19 @@ var IPython = (function (IPython) { * * @method start_session */ - Notebook.prototype.start_session = function () { - this.session = new IPython.Session(this.notebook_name, this.notebook_path, this); - this.session.start($.proxy(this._session_started, this)); - }; - - - /** - * Once a session is started, link the code cells to the kernel - * - */ - Notebook.prototype._session_started = function(){ - this.kernel = this.session.kernel; + Notebook.prototype.start_kernel = function () { + var base_url = $('body').data('baseKernelUrl') + "kernels"; + this.kernel = new IPython.Kernel(base_url); + this.kernel.start({notebook: this.notebook_id}); + // Now that the kernel has been created, tell the CodeCells about it. var ncells = this.ncells(); for (var i=0; i Date: Thu, 10 Oct 2013 14:08:14 -0700 Subject: [PATCH 008/473] Fixing infinite recursion. --- IPython/html/static/notebook/js/widget.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/IPython/html/static/notebook/js/widget.js b/IPython/html/static/notebook/js/widget.js index 335c51cc168..ce293abd128 100644 --- a/IPython/html/static/notebook/js/widget.js +++ b/IPython/html/static/notebook/js/widget.js @@ -215,9 +215,10 @@ var IPython = (function (IPython) { }; }; - var data = {sync_method: method, sync_data: model.toJSON()}; + var model_json = model.toJSON(); + var data = {sync_method: method, sync_data: model_json}; comm.send(data, callbacks); - return data; + return model_json; } IPython.WidgetManager = WidgetManager; From 09ef35b0db21dfa293786a45593c7773b583d747 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Mon, 14 Oct 2013 22:16:18 +0000 Subject: [PATCH 009/473] Added apply method to base model. Allows model to propogate changes to all views except for the one specified. --- IPython/html/static/notebook/js/widget.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/IPython/html/static/notebook/js/widget.js b/IPython/html/static/notebook/js/widget.js index ce293abd128..f4d2b5bf9f6 100644 --- a/IPython/html/static/notebook/js/widget.js +++ b/IPython/html/static/notebook/js/widget.js @@ -25,7 +25,18 @@ var IPython = (function (IPython) { //----------------------------------------------------------------------- // WidgetModel class //----------------------------------------------------------------------- - var WidgetModel = Backbone.Model.extend({}); + var WidgetModel = Backbone.Model.extend({ + apply: function(sender) { + this.save(); + + for (var index in this.views) { + var view = this.views[index]; + if (view !== sender) { + view.refresh(); + } + } + } + }); //----------------------------------------------------------------------- @@ -214,7 +225,6 @@ var IPython = (function (IPython) { clear_output : $.proxy(outputarea.handle_clear_output, outputarea)} }; }; - var model_json = model.toJSON(); var data = {sync_method: method, sync_data: model_json}; comm.send(data, callbacks); From 4ddc07b945fabb68157b9947d7cb306fee6068fc Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Tue, 15 Oct 2013 10:12:15 -0700 Subject: [PATCH 010/473] Added display hook logic to handle widgets --- IPython/core/display.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/IPython/core/display.py b/IPython/core/display.py index 85150eb620a..e919ada859d 100644 --- a/IPython/core/display.py +++ b/IPython/core/display.py @@ -24,6 +24,7 @@ from IPython.utils.py3compat import (string_types, cast_bytes_py2, cast_unicode, unicode_type) +from IPython.html.widgets import Widget from .displaypub import publish_display_data @@ -110,17 +111,20 @@ def display(*objs, **kwargs): from IPython.core.interactiveshell import InteractiveShell - if raw: - for obj in objs: - publish_display_data('display', obj, metadata) + if isinstance(obj, Widget): + obj._repr_widget_(**kwargs) else: - format = InteractiveShell.instance().display_formatter.format - for obj in objs: - format_dict, md_dict = format(obj, include=include, exclude=exclude) - if metadata: - # kwarg-specified metadata gets precedence - _merge(md_dict, metadata) - publish_display_data('display', format_dict, md_dict) + if raw: + for obj in objs: + publish_display_data('display', obj, metadata) + else: + format = InteractiveShell.instance().display_formatter.format + for obj in objs: + format_dict, md_dict = format(obj, include=include, exclude=exclude) + if metadata: + # kwarg-specified metadata gets precedence + _merge(md_dict, metadata) + publish_display_data('display', format_dict, md_dict) def display_pretty(*objs, **kwargs): From 2f1e00b2fdbd069aa3feddacd6e1f25f170bccbb Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Tue, 15 Oct 2013 10:14:04 -0700 Subject: [PATCH 011/473] Basic display logic s/show/_repr_... Added code to display Javascript in frontend. --- IPython/html/widgets/widget.py | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/IPython/html/widgets/widget.py b/IPython/html/widgets/widget.py index 5f7feb06483..85efc864cf9 100644 --- a/IPython/html/widgets/widget.py +++ b/IPython/html/widgets/widget.py @@ -1,18 +1,18 @@ -from IPython.kernel.comm import Comm -from IPython.config import LoggingConfigurable -from IPython.utils.traitlets import Unicode, Float, Bool, Dict -from IPython.display import clear_output from copy import copy import uuid import sys +from IPython.kernel.comm import Comm +from IPython.config import LoggingConfigurable +from IPython.utils.traitlets import Unicode, Dict +from IPython.display import Javascript, display class Widget(Comm): ### Public declarations target_name = Unicode('widget') - default_view_name = Unicode() + view_name = Unicode() ### Private/protected declarations @@ -31,7 +31,11 @@ def __init__(self, parent=None, **kwargs): if parent is not None: parent._children.append(self) self._parent = parent - + + # Send frontend type code. + display(Javascript(data=self._get_backbone_js())) + + # Create a comm. self.comm = Comm(target_name=self.target_name) self.comm.on_msg(self._handle_msg) @@ -114,9 +118,8 @@ def _handle_property_changed(self, name, old, new): ### Public methods - def show(self, view_name=None): - if not view_name: - view_name = self.default_view_name + def _repr_widget_(self): + view_name = self.view_name if not view_name: view_name = self.target_name @@ -133,7 +136,8 @@ def show(self, view_name=None): # Now show children if any. for child in self.children: - child.show() + child._repr_widget_() + return self._get_backbone_js def send_state(self): @@ -145,4 +149,7 @@ def send_state(self): pass # Eat errors, nom nom nom self.comm.send({"method": "update", "state": state}) - \ No newline at end of file + + ### Private methods + def _get_backbone_js(self): + return 'alert("woohoo!");' From 4124b34ad764ae2085cf73c336a7b7d79ce70d73 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Tue, 15 Oct 2013 20:55:50 +0000 Subject: [PATCH 012/473] Moved widget.js into widget code directory --- IPython/html/{static/notebook/js => widgets}/widget.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename IPython/html/{static/notebook/js => widgets}/widget.js (100%) diff --git a/IPython/html/static/notebook/js/widget.js b/IPython/html/widgets/widget.js similarity index 100% rename from IPython/html/static/notebook/js/widget.js rename to IPython/html/widgets/widget.js From dc86179329d27a5b2649a7e6a33533f6ea3f8c49 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Thu, 17 Oct 2013 06:05:51 +0000 Subject: [PATCH 013/473] Added utility function to send all the javascript in the current directory to the frontend. --- IPython/utils/javascript.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 IPython/utils/javascript.py diff --git a/IPython/utils/javascript.py b/IPython/utils/javascript.py new file mode 100644 index 00000000000..818ff3da5c7 --- /dev/null +++ b/IPython/utils/javascript.py @@ -0,0 +1,28 @@ +"""Utilities to manipulate Javascript files. +""" +#----------------------------------------------------------------------------- +# Copyright (C) 2013 The IPython Development Team +# +# Distributed under the terms of the BSD License. The full license is in +# the file COPYING.txt, distributed as part of this software. +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- + +import glob +import os + +from IPython.display import display, Javascript + +#----------------------------------------------------------------------------- +# Methods +#----------------------------------------------------------------------------- + +def display_all_js(directory): + + # Display each javascript file in the directory. + for filename in glob.glob(os.path.join(directory, '*.js')): + with open(filename, 'r') as f: + display(Javascript(data=f.read())) From c0cac1e81eb1a6c87dbc8b7f1d691a2544fb0f50 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Thu, 17 Oct 2013 06:09:20 +0000 Subject: [PATCH 014/473] Updates to widget.py Added global init js function Moved init comm logic to show function --- IPython/html/widgets/widget.py | 60 ++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/IPython/html/widgets/widget.py b/IPython/html/widgets/widget.py index 85efc864cf9..23793ccd614 100644 --- a/IPython/html/widgets/widget.py +++ b/IPython/html/widgets/widget.py @@ -1,18 +1,31 @@ from copy import copy +from glob import glob import uuid import sys +import os +import IPython from IPython.kernel.comm import Comm from IPython.config import LoggingConfigurable from IPython.utils.traitlets import Unicode, Dict from IPython.display import Javascript, display +from IPython.utils.py3compat import string_types +from IPython.utils.javascript import display_all_js + +def init_widget_js(cls): + path = os.path.split(os.path.abspath( __file__ ))[0] + display_all_js(path) + for root, dirs, files in os.walk(path): + for sub_directory in dirs: + display_all_js(os.path.join(path, sub_directory)) + + +class Widget(LoggingConfigurable): -class Widget(Comm): - ### Public declarations target_name = Unicode('widget') - view_name = Unicode() + default_view_name = Unicode() ### Private/protected declarations @@ -31,20 +44,11 @@ def __init__(self, parent=None, **kwargs): if parent is not None: parent._children.append(self) self._parent = parent - - # Send frontend type code. - display(Javascript(data=self._get_backbone_js())) - - # Create a comm. - self.comm = Comm(target_name=self.target_name) - self.comm.on_msg(self._handle_msg) + self.comm = None # Register after init to allow default values to be specified self.on_trait_change(self._handle_property_changed, self.keys) - # Set initial properties on client model. - self.send_state() - def __del__(self): self.close() @@ -115,14 +119,23 @@ def _handle_property_changed(self, name, old, new): # TODO: Validate properties. # Send new state to frontend self.send_state() + + + def _handle_close(self): + self.comm = None ### Public methods - def _repr_widget_(self): - view_name = self.view_name + def _repr_widget_(self, view_name=None): if not view_name: - view_name = self.target_name - + view_name = self.default_view_name + + # Create a comm. + if self.comm is None: + self.comm = Comm(target_name=self.target_name) + self.comm.on_msg(self._handle_msg) + self.comm.on_close(self._handle_close) + # Make sure model is syncronized self.send_state() @@ -137,9 +150,9 @@ def _repr_widget_(self): # Now show children if any. for child in self.children: child._repr_widget_() - return self._get_backbone_js - - + return None + + def send_state(self): state = {} for key in self.keys: @@ -148,8 +161,5 @@ def send_state(self): except Exception as e: pass # Eat errors, nom nom nom self.comm.send({"method": "update", - "state": state}) - - ### Private methods - def _get_backbone_js(self): - return 'alert("woohoo!");' + "state": state}) + \ No newline at end of file From 3ac69b98ffbe08479d1f2e51e8d49929de7ca403 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Thu, 17 Oct 2013 06:09:50 +0000 Subject: [PATCH 015/473] Widget Display logic --- IPython/core/display.py | 18 +++++++++--------- IPython/core/displayhook.py | 17 ++++++++++------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/IPython/core/display.py b/IPython/core/display.py index e919ada859d..f1f9ed6dc3f 100644 --- a/IPython/core/display.py +++ b/IPython/core/display.py @@ -24,7 +24,6 @@ from IPython.utils.py3compat import (string_types, cast_bytes_py2, cast_unicode, unicode_type) -from IPython.html.widgets import Widget from .displaypub import publish_display_data @@ -111,15 +110,16 @@ def display(*objs, **kwargs): from IPython.core.interactiveshell import InteractiveShell - if isinstance(obj, Widget): - obj._repr_widget_(**kwargs) - else: - if raw: - for obj in objs: - publish_display_data('display', obj, metadata) + if not raw: + format = InteractiveShell.instance().display_formatter.format + + for obj in objs: + if hasattr(obj, '_repr_widget_'): + obj._repr_widget_(**kwargs) else: - format = InteractiveShell.instance().display_formatter.format - for obj in objs: + if raw: + publish_display_data('display', obj, metadata) + else: format_dict, md_dict = format(obj, include=include, exclude=exclude) if metadata: # kwarg-specified metadata gets precedence diff --git a/IPython/core/displayhook.py b/IPython/core/displayhook.py index 0ecfb3b455a..f228ffe1c38 100644 --- a/IPython/core/displayhook.py +++ b/IPython/core/displayhook.py @@ -241,13 +241,16 @@ def __call__(self, result=None): """ self.check_for_underscore() if result is not None and not self.quiet(): - self.start_displayhook() - self.write_output_prompt() - format_dict, md_dict = self.compute_format_data(result) - self.write_format_data(format_dict, md_dict) - self.update_user_ns(result) - self.log_output(format_dict) - self.finish_displayhook() + if hasattr(result, '_repr_widget_'): + result._repr_widget_() + else: + self.start_displayhook() + self.write_output_prompt() + format_dict, md_dict = self.compute_format_data(result) + self.write_format_data(format_dict, md_dict) + self.update_user_ns(result) + self.log_output(format_dict) + self.finish_displayhook() def flush(self): if not self.do_full_cache: From 9f44bc74f839400a23022a8ae0a260910f3990f5 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Thu, 17 Oct 2013 06:10:28 +0000 Subject: [PATCH 016/473] Added clear widget area button --- IPython/html/static/notebook/js/codecell.js | 23 +++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/IPython/html/static/notebook/js/codecell.js b/IPython/html/static/notebook/js/codecell.js index 25afa3f05e8..8487357924a 100644 --- a/IPython/html/static/notebook/js/codecell.js +++ b/IPython/html/static/notebook/js/codecell.js @@ -133,10 +133,25 @@ var IPython = (function (IPython) { inner_cell.append(input_area); input.append(prompt).append(inner_cell); - var widget_area = $('
').addClass('widget_area'); - var widget_prompt = $('
').addClass('prompt'); - var widget_subarea = $('
').addClass('widget_subarea'); - widget_area.append(widget_prompt).append(widget_subarea); + var widget_area = $('
') + .addClass('widget_area') + .hide(); + this.widget_area = widget_area; + var widget_prompt = $('
') + .addClass('prompt') + .appendTo(widget_area); + var widget_subarea = $('
') + .addClass('widget_subarea') + .appendTo(widget_area); + this.widget_subarea = widget_subarea; + var widget_clear_buton = $('