@ -37,7 +37,7 @@
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 15
"prompt_number": 19
},
{
"cell_type": "markdown",
@ -56,7 +56,7 @@
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 16
"prompt_number": 20
},
{
"cell_type": "heading",
@ -101,25 +101,23 @@
"collapsed": false,
"input": [
"# Import the base Widget class and the traitlets Unicode class.\n",
"from IPython.html.widgets import Widget\n",
"from IPython.html.widgets import DOM Widget\n",
"from IPython.utils.traitlets import Unicode\n",
"\n",
"# Define our DateWidget and its target model and default view.\n",
"class DateWidget(Widget):\n",
" target_name = Unicode('DateWidgetModel')\n",
" default_view_name = Unicode('DatePickerView')"
"class DateWidget(DOMWidget):\n",
" _view_name = Unicode('DatePickerView', sync=True)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 17
"prompt_number": 2 1
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- **target_name** is a special `Widget` property that tells the widget framework which Backbone model in the front-end corresponds to this widget.\n",
"- **default_view_name** is the default Backbone view to display when the user calls `display` to display an instance of this widget.\n"
"- **_view_name** is the default Backbone view to display when the user calls `display` to display an instance of this widget.\n"
]
},
{
@ -134,7 +132,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"In the IPython notebook [require.js](http://requirejs.org/) is used to load JavaScript dependencies. All IPython widget code depends on `notebook/js/widget.js`. In it the base widget model, base view, and widget manager are defined. We need to use require.js to include this file:"
"In the IPython notebook [require.js](http://requirejs.org/) is used to load JavaScript dependencies. All IPython widget code depends on `notebook/js/widgets/widget.js`. In it the base widget model and base view are defined. We need to use require.js to include this file:"
]
},
{
@ -143,7 +141,7 @@
"input": [
"%%javascript\n",
"\n",
"require([\"notebook/js/widgets/\"], function(){\n",
"require([\"notebook/js/widgets/widget \"], function(WidgetManager ){\n",
"\n",
"});"
],
@ -153,66 +151,24 @@
{
"javascript": [
"\n",
"require([\"notebook/js/widget\"], function(){\n",
"require([\"notebook/js/widgets/widget \"], function(WidgetManager ){\n",
"\n",
"});"
],
"metadata": {},
"output_type": "display_data",
"text": [
"<IPython.core.display.Javascript at 0x10a26a85 0>"
"<IPython.core.display.Javascript at 0x1e409d 0>"
]
}
],
"prompt_number": 18
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The next step is to add a definition for the widget's model. It's important to extend the `IPython.WidgetModel` which extends the Backbone.js base model instead of trying to extend the Backbone.js base model directly. After defining the model, it needs to be registed with the widget manager using the `target_name` used in the Python code."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%javascript\n",
"\n",
"require([\"notebook/js/widgets/base\"], function(){\n",
" \n",
" // Define the DateModel and register it with the widget manager.\n",
" var DateModel = IPython.WidgetModel.extend({});\n",
" IPython.widget_manager.register_widget_model('DateWidgetModel', DateModel);\n",
"});"
],
"language": "python",
"metadata": {},
"outputs": [
{
"javascript": [
"\n",
"require([\"notebook/js/widgets/base\"], function(){\n",
" \n",
" // Define the DateModel and register it with the widget manager.\n",
" var DateModel = IPython.WidgetModel.extend({});\n",
" IPython.widget_manager.register_widget_model('DateWidgetModel', DateModel);\n",
"});"
],
"metadata": {},
"output_type": "display_data",
"text": [
"<IPython.core.display.Javascript at 0x10a26aa10>"
]
}
],
"prompt_number": 20
"prompt_number": 22
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now that the model is defined, we need to define a view that can be used to represent the model. To do this, the `IPython.WidgetView` is extended. A render function must be defined. The render function is used to render a widget view instance to the DOM. For now the render function renders a div that contains the text *Hello World!* Lastly, the view needs to be registered with the widget manager like the model was.\n",
"Now we need to define a view that can be used to represent the model. To do this, the `IPython.DOMWidgetView` is extended. A render function must be defined. The render function is used to render a widget view instance to the DOM. For now the render function renders a div that contains the text *Hello World!* Lastly, the view needs to be registered with the widget manager like the model was.\n",
"\n",
"**Final JavaScript code below:**"
]
@ -223,23 +179,15 @@
"input": [
"%%javascript\n",
"\n",
"require([\"notebook/js/widgets/base\"], function(){\n",
" \n",
" // Define the DateModel and register it with the widget manager.\n",
" var DateModel = IPython.WidgetModel.extend({});\n",
" IPython.widget_manager.register_widget_model('DateWidgetModel', DateModel);\n",
"require([\"notebook/js/widgets/widget\"], function(WidgetManager){\n",
" \n",
" // Define the DatePickerView\n",
" var DatePickerView = IPython.WidgetView.extend({\n",
" \n",
" render: function(){\n",
" this.$el = $('<div />')\n",
" .html('Hello World!');\n",
" },\n",
" var DatePickerView = IPython.DOMWidgetView.extend({\n",
" render: function(){ this.$el.text('Hello World!'); },\n",
" });\n",
" \n",
" // Register the DatePickerView with the widget manager.\n",
" IPython.widget_m anager.register_widget_view('DatePickerView', DatePickerView);\n",
" WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
"});"
],
"language": "python",
@ -248,29 +196,21 @@
{
"javascript": [
"\n",
"require([\"notebook/js/widgets/base\"], function(){\n",
" \n",
" // Define the DateModel and register it with the widget manager.\n",
" var DateModel = IPython.WidgetModel.extend({});\n",
" IPython.widget_manager.register_widget_model('DateWidgetModel', DateModel);\n",
"require([\"notebook/js/widgets/widget\"], function(WidgetManager){\n",
" \n",
" // Define the DatePickerView\n",
" var DatePickerView = IPython.WidgetView.extend({\n",
" \n",
" render: function(){\n",
" this.$el = $('<div />')\n",
" .html('Hello World!');\n",
" },\n",
" var DatePickerView = IPython.DOMWidgetView.extend({\n",
" render: function(){ this.$el.text('Hello World!'); },\n",
" });\n",
" \n",
" // Register the DatePickerView with the widget manager.\n",
" IPython.widget_m anager.register_widget_view('DatePickerView', DatePickerView);\n",
" WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
"});"
],
"metadata": {},
"output_type": "display_data",
"text": [
"<IPython.core.display.Javascript at 0x10a26ae9 0>"
"<IPython.core.display.Javascript at 0x1e40a5 0>"
]
}
],
@ -295,8 +235,7 @@
"cell_type": "code",
"collapsed": false,
"input": [
"my_widget = DateWidget()\n",
"display(my_widget)"
"DateWidget()"
],
"language": "python",
"metadata": {},
@ -323,7 +262,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"In the last section we created a simple widget that displayed *Hello World!* There was no custom state information associated with the widget. T o make an actual date widget, we need to add a property that will be synced between the Python model and the JavaScript model. The new property must be a traitlet property so the widget machinery can automatically handle it. The property needs to be added to the the `_keys` list. The `_keys` list tells the widget machinery what traitlets should be synced with the front -end. Adding this to the code from the last section:"
"In the last section we created a simple widget that displayed *Hello World!* To make an actual date widget, we need to add a property that will be synced between the Python model and the JavaScript model. The new property must be a traitlet property so the widget machinery can automatically handle it. The property needs to be constructed with a `sync=True` keyword argument so the widget machinery knows to syncronize it with the fron -end. Adding this to the code from the last section:"
]
},
{
@ -331,17 +270,13 @@
"collapsed": false,
"input": [
"# Import the base Widget class and the traitlets Unicode class.\n",
"from IPython.html.widgets import Widget\n",
"from IPython.html.widgets import DOM Widget\n",
"from IPython.utils.traitlets import Unicode\n",
"\n",
"# Define our DateWidget and its target model and default view.\n",
"class DateWidget(Widget):\n",
" target_name = Unicode('DateWidgetModel')\n",
" default_view_name = Unicode('DatePickerView')\n",
" \n",
" # Define the custom state properties to sync with the front-end\n",
" _keys = ['value']\n",
" value = Unicode()"
"class DateWidget(DOMWidget):\n",
" _view_name = Unicode('DatePickerView', sync=True)\n",
" value = Unicode(sync=True)"
],
"language": "python",
"metadata": {},
@ -369,28 +304,21 @@
"input": [
"%%javascript\n",
"\n",
"require([\"notebook/js/widgets/base\"], function(){\n",
" \n",
" // Define the DateModel and register it with the widget manager.\n",
" var DateModel = IPython.WidgetModel.extend({});\n",
" IPython.widget_manager.register_widget_model('DateWidgetModel', DateModel);\n",
"require([\"notebook/js/widgets/widget\"], function(WidgetManager){\n",
" \n",
" // Define the DatePickerView\n",
" var DatePickerView = IPython.WidgetView.extend({\n",
" \n",
" var DatePickerView = IPython.DOMWidgetView.extend({\n",
" render: function(){\n",
" \n",
" // Create a div to hold our widget.\n",
" this.$el = $('<div />');\n",
" \n",
" // Create the date picker control.\n",
" this.$date = $('<input />')\n",
" .attr('type', 'date');\n",
" .attr('type', 'date')\n",
" .appendTo(this.$el);\n",
" },\n",
" });\n",
" \n",
" // Register the DatePickerView with the widget manager.\n",
" IPython.widget_m anager.register_widget_view('DatePickerView', DatePickerView);\n",
" WidgetM anager.register_widget_view('DatePickerView', DatePickerView);\n",
"});"
],
"language": "python",
@ -399,34 +327,27 @@
{
"javascript": [
"\n",
"require([\"notebook/js/widgets/base\"], function(){\n",
" \n",
" // Define the DateModel and register it with the widget manager.\n",
" var DateModel = IPython.WidgetModel.extend({});\n",
" IPython.widget_manager.register_widget_model('DateWidgetModel', DateModel);\n",
"require([\"notebook/js/widgets/widget\"], function(WidgetManager){\n",
" \n",
" // Define the DatePickerView\n",
" var DatePickerView = IPython.WidgetView.extend({\n",
" \n",
" var DatePickerView = IPython.DOMWidgetView.extend({\n",
" render: function(){\n",
" \n",
" // Create a div to hold our widget.\n",
" this.$el = $('<div />');\n",
" \n",
" // Create the date picker control.\n",
" this.$date = $('<input />')\n",
" .attr('type', 'date');\n",
" .attr('type', 'date')\n",
" .appendTo(this.$el);\n",
" },\n",
" });\n",
" \n",
" // Register the DatePickerView with the widget manager.\n",
" IPython.widget_m anager.register_widget_view('DatePickerView', DatePickerView);\n",
" WidgetM anager.register_widget_view('DatePickerView', DatePickerView);\n",
"});"
],
"metadata": {},
"output_type": "display_data",
"text": [
"<IPython.core.display.Javascript at 0x10a27405 0>"
"<IPython.core.display.Javascript at 0x1e4081 0>"
]
}
],
@ -445,35 +366,28 @@
"input": [
"%%javascript\n",
"\n",
"require([\"notebook/js/widgets/base\"], function(){\n",
" \n",
" // Define the DateModel and register it with the widget manager.\n",
" var DateModel = IPython.WidgetModel.extend({});\n",
" IPython.widget_manager.register_widget_model('DateWidgetModel', DateModel);\n",
"require([\"notebook/js/widgets/widget\"], function(WidgetManager){\n",
" \n",
" // Define the DatePickerView\n",
" var DatePickerView = IPython.WidgetView.extend({\n",
" \n",
" var DatePickerView = IPython.DOMWidgetView.extend({\n",
" render: function(){\n",
" \n",
" // Create a div to hold our widget.\n",
" this.$el = $('<div />');\n",
" \n",
" // Create the date picker control.\n",
" this.$date = $('<input />')\n",
" .attr('type', 'date');\n",
" .attr('type', 'date')\n",
" .appendTo(this.$el);\n",
" },\n",
" \n",
" update: function() {\n",
" \n",
" // Set the value of the date control and then call base.\n",
" this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
" return IPython.WidgetView.prototype.update.call (this);\n",
" return DatePickerView.__super__.update.apply (this);\n",
" },\n",
" });\n",
" \n",
" // Register the DatePickerView with the widget manager.\n",
" IPython.widget_m anager.register_widget_view('DatePickerView', DatePickerView);\n",
" WidgetM anager.register_widget_view('DatePickerView', DatePickerView);\n",
"});"
],
"language": "python",
@ -482,41 +396,34 @@
{
"javascript": [
"\n",
"require([\"notebook/js/widgets/base\"], function(){\n",
" \n",
" // Define the DateModel and register it with the widget manager.\n",
" var DateModel = IPython.WidgetModel.extend({});\n",
" IPython.widget_manager.register_widget_model('DateWidgetModel', DateModel);\n",
"require([\"notebook/js/widgets/widget\"], function(WidgetManager){\n",
" \n",
" // Define the DatePickerView\n",
" var DatePickerView = IPython.WidgetView.extend({\n",
" \n",
" var DatePickerView = IPython.DOMWidgetView.extend({\n",
" render: function(){\n",
" \n",
" // Create a div to hold our widget.\n",
" this.$el = $('<div />');\n",
" \n",
" // Create the date picker control.\n",
" this.$date = $('<input />')\n",
" .attr('type', 'date');\n",
" .attr('type', 'date')\n",
" .appendTo(this.$el);\n",
" },\n",
" \n",
" update: function() {\n",
" \n",
" // Set the value of the date control and then call base.\n",
" this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
" return IPython.WidgetView.prototype.update.call (this);\n",
" return DatePickerView.__super__.update.apply (this);\n",
" },\n",
" });\n",
" \n",
" // Register the DatePickerView with the widget manager.\n",
" IPython.widget_m anager.register_widget_view('DatePickerView', DatePickerView);\n",
" WidgetM anager.register_widget_view('DatePickerView', DatePickerView);\n",
"});"
],
"metadata": {},
"output_type": "display_data",
"text": [
"<IPython.core.display.Javascript at 0x10a2740d 0>"
"<IPython.core.display.Javascript at 0x1e4039 0>"
]
}
],
@ -526,9 +433,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"To get the changed value from the front-end to publish itself to the back-end, we need to listen to the change event triggered by the HTM date control and set the value in the model. By setting the `this.$el` property of the view, we break the Backbone powered event handling. To fix this, a call to `this.delegateEvents()` must be added after `this.$el` is set. \n",
"\n",
"After the date change event fires and the new value is set in the model, it's very important that we call `update_other_views(this)` to make the other views on the page update and to let the widget machinery know which view changed the model. This is important because the widget machinery needs to know which cell to route the message callbacks to.\n",
"To get the changed value from the front-end to publish itself to the back-end, we need to listen to the change event triggered by the HTM date control and set the value in the model. After the date change event fires and the new value is set in the model, it's very important that we call `this.touch()` to let the widget machinery know which view changed the model. This is important because the widget machinery needs to know which cell to route the message callbacks to.\n",
"\n",
"**Final JavaScript code below:**"
]
@ -539,21 +444,13 @@
"input": [
"%%javascript\n",
"\n",
"require([\"notebook/js/widgets/base\"], function(){\n",
" \n",
" // Define the DateModel and register it with the widget manager.\n",
" var DateModel = IPython.WidgetModel.extend({});\n",
" IPython.widget_manager.register_widget_model('DateWidgetModel', DateModel);\n",
"\n",
"require([\"notebook/js/widgets/widget\"], function(WidgetManager){\n",
" \n",
" // Define the DatePickerView\n",
" var DatePickerView = IPython.WidgetView.extend({\n",
" \n",
" var DatePickerView = IPython.DOMWidgetView.extend({\n",
" render: function(){\n",
" \n",
" // Create a div to hold our widget.\n",
" this.$el = $('<div />');\n",
" this.delegateEvents();\n",
" \n",
" // Create the date picker control.\n",
" this.$date = $('<input />')\n",
" .attr('type', 'date')\n",
@ -564,7 +461,7 @@
" \n",
" // Set the value of the date control and then call base.\n",
" this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
" return IPython.WidgetView.prototype.update.call (this);\n",
" return DatePickerView.__super__.update.apply (this);\n",
" },\n",
" \n",
" // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n",
@ -573,12 +470,12 @@
" // Callback for when the date is changed.\n",
" handle_date_change: function(event) {\n",
" this.model.set('value', this.$date.val());\n",
" this.touch();\n",
" },\n",
" \n",
" });\n",
" \n",
" // Register the DatePickerView with the widget manager.\n",
" IPython.widget_m anager.register_widget_view('DatePickerView', DatePickerView);\n",
" WidgetM anager.register_widget_view('DatePickerView', DatePickerView);\n",
"});"
],
"language": "python",
@ -587,21 +484,13 @@
{
"javascript": [
"\n",
"require([\"notebook/js/widgets/base\"], function(){\n",
" \n",
" // Define the DateModel and register it with the widget manager.\n",
" var DateModel = IPython.WidgetModel.extend({});\n",
" IPython.widget_manager.register_widget_model('DateWidgetModel', DateModel);\n",
"\n",
"require([\"notebook/js/widgets/widget\"], function(WidgetManager){\n",
" \n",
" // Define the DatePickerView\n",
" var DatePickerView = IPython.WidgetView.extend({\n",
" \n",
" var DatePickerView = IPython.DOMWidgetView.extend({\n",
" render: function(){\n",
" \n",
" // Create a div to hold our widget.\n",
" this.$el = $('<div />');\n",
" this.delegateEvents();\n",
" \n",
" // Create the date picker control.\n",
" this.$date = $('<input />')\n",
" .attr('type', 'date')\n",
@ -612,7 +501,7 @@
" \n",
" // Set the value of the date control and then call base.\n",
" this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
" return IPython.WidgetView.prototype.update.call (this);\n",
" return DatePickerView.__super__.update.apply (this);\n",
" },\n",
" \n",
" // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n",
@ -621,22 +510,22 @@
" // Callback for when the date is changed.\n",
" handle_date_change: function(event) {\n",
" this.model.set('value', this.$date.val());\n",
" this.touch();\n",
" },\n",
" \n",
" });\n",
" \n",
" // Register the DatePickerView with the widget manager.\n",
" IPython.widget_m anager.register_widget_view('DatePickerView', DatePickerView);\n",
" WidgetM anager.register_widget_view('DatePickerView', DatePickerView);\n",
"});"
],
"metadata": {},
"output_type": "display_data",
"text": [
"<IPython.core.display.Javascript at 0x10a274a1 0>"
"<IPython.core.display.Javascript at 0x1e4089 0>"
]
}
],
"prompt_number": 5 2
"prompt_number": 28
},
{
"cell_type": "heading",
@ -676,7 +565,7 @@
"cell_type": "code",
"collapsed": false,
"input": [
"display( my_widget) "
"my_widget"
],
"language": "python",
"metadata": {},
@ -702,13 +591,13 @@
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 37 ,
"prompt_number": 31 ,
"text": [
"u'1998-12-01 '"
"u''"
]
}
],
"prompt_number": 37
"prompt_number": 31
},
{
"cell_type": "markdown",
@ -726,7 +615,7 @@
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 34
"prompt_number": 32
},
{
"cell_type": "heading",
@ -763,17 +652,13 @@
"collapsed": false,
"input": [
"# Import the base Widget class and the traitlets Unicode class.\n",
"from IPython.html.widgets import Widget\n",
"from IPython.html.widgets import DOM Widget\n",
"from IPython.utils.traitlets import Unicode\n",
"\n",
"# Define our DateWidget and its target model and default view.\n",
"class DateWidget(Widget):\n",
" target_name = Unicode('DateWidgetModel')\n",
" default_view_name = Unicode('DatePickerView')\n",
" \n",
" # Define the custom state properties to sync with the front-end\n",
" _keys = ['value']\n",
" value = Unicode()\n",
"class DateWidget(DOMWidget):\n",
" _view_name = Unicode('DatePickerView', sync=True)\n",
" value = Unicode(sync=True)\n",
" \n",
" # This function automatically gets called by the traitlet machinery when\n",
" # value is modified because of this function's name.\n",
@ -784,7 +669,7 @@
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 38
"prompt_number": 33
},
{
"cell_type": "markdown",
@ -797,19 +682,17 @@
"cell_type": "code",
"collapsed": false,
"input": [
"# Import the dateutil library to parse date strings.\n",
"from dateutil import parser\n",
"\n",
"# Import the base Widget class and the traitlets Unicode class.\n",
"from IPython.html.widgets import Widget\n",
"from IPython.html.widgets import DOM Widget\n",
"from IPython.utils.traitlets import Unicode\n",
"\n",
"# Define our DateWidget and its target model and default view.\n",
"class DateWidget(Widget):\n",
" target_name = Unicode('DateWidgetModel')\n",
" default_view_name = Unicode('DatePickerView')\n",
" \n",
" # Define the custom state properties to sync with the front-end\n",
" _keys = ['value']\n",
" value = Unicode()\n",
"class DateWidget(DOMWidget):\n",
" _view_name = Unicode('DatePickerView', sync=True)\n",
" value = Unicode(sync=True)\n",
" \n",
" # This function automatically gets called by the traitlet machinery when\n",
" # value is modified because of this function's name.\n",
@ -829,7 +712,7 @@
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 39
"prompt_number": 34
},
{
"cell_type": "markdown",
@ -846,18 +729,14 @@
"from dateutil import parser\n",
"\n",
"# Import the base Widget class and the traitlets Unicode class.\n",
"from IPython.html.widgets import Widget\n",
"from IPython.html.widgets import DOM Widget\n",
"from IPython.utils.traitlets import Unicode\n",
"\n",
"# Define our DateWidget and its target model and default view.\n",
"class DateWidget(Widget):\n",
" target_name = Unicode('DateWidgetModel')\n",
" default_view_name = Unicode('DatePickerView')\n",
" \n",
" # Define the custom state properties to sync with the front-end\n",
" _keys = ['value', 'description']\n",
" value = Unicode()\n",
" description = Unicode()\n",
"class DateWidget(DOMWidget):\n",
" _view_name = Unicode('DatePickerView', sync=True)\n",
" value = Unicode(sync=True)\n",
" description = Unicode(sync=True)\n",
" \n",
" # This function automatically gets called by the traitlet machinery when\n",
" # value is modified because of this function's name.\n",
@ -877,7 +756,7 @@
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 40
"prompt_number": 35
},
{
"cell_type": "markdown",
@ -896,22 +775,22 @@
"from dateutil import parser\n",
"\n",
"# Import the base Widget class and the traitlets Unicode class.\n",
"from IPython.html.widgets import Widget\n",
"from IPython.html.widgets import DOM Widget, CallbackDispatcher \n",
"from IPython.utils.traitlets import Unicode\n",
"\n",
"# Define our DateWidget and its target model and default view.\n",
"class DateWidget(Widget):\n",
" target_name = Unicode('DateWidgetModel')\n",
" default_view_name = Unicode('DatePickerView')\n",
" \n",
" # Define the custom state properties to sync with the front-end\n",
" _keys = ['value', 'description']\n",
" value = Unicode()\n",
" description = Unicode()\n",
"class DateWidget(DOMWidget):\n",
" _view_name = Unicode('DatePickerView', sync=True)\n",
" value = Unicode(sync=True)\n",
" description = Unicode(sync=True)\n",
" \n",
" def __init__(self, **kwargs):\n",
" super(DateWidget, self).__init__(**kwargs)\n",
" self._validation_callbacks = []\n",
" \n",
" # Specify the number of positional arguments supported. For \n",
" # validation we only are worried about one parameter, the\n",
" # new value that should be validated.\n",
" self.validation = CallbackDispatcher(acceptable_nargs=[1])\n",
" \n",
" # This function automatically gets called by the traitlet machinery when\n",
" # value is modified because of this function's name.\n",
@ -922,40 +801,23 @@
" parsed_date = parser.parse(new_value)\n",
" parsed_date_string = parsed_date.strftime(\"%Y-%m-%d\")\n",
" except:\n",
" parsed_date = None\n",
" parsed_date_string = ''\n",
" \n",
" # Set the parsed date string if the current date string is different.\n",
" if old_value != new_value:\n",
" if self.handle_validate(parsed_date):\n",
" validation = self.validation(parsed_date)\n",
" if validation is None or validation == True:\n",
" self.value = parsed_date_string\n",
" else:\n",
" self.value = old_value\n",
" self.send_state() # The traitlet event won't fire since the value isn't changing.\n",
" # We need to force the back-end to send the front-end the state\n",
" # to make sure that the date control date doesn't change.\n",
" \n",
" \n",
" # Allow the user to register custom validation callbacks.\n",
" # callback(new value as a datetime object)\n",
" def on_validate(self, callback, remove=False):\n",
" if remove and callback in self._validation_callbacks:\n",
" self._validation_callbacks.remove(callback)\n",
" elif (not remove) and (not callback in self._validation_callbacks):\n",
" self._validation_callbacks.append(callback)\n",
" \n",
" # Call user validation callbacks. Return True if valid.\n",
" def handle_validate(self, new_value):\n",
" for callback in self._validation_callbacks:\n",
" if not callback(new_value):\n",
" return False\n",
" return True\n",
" "
" # to make sure that the date control date doesn't change."
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 41
"prompt_number": 45
},
{
"cell_type": "heading",
@ -980,23 +842,14 @@
"input": [
"%%javascript\n",
"\n",
"require([\"notebook/js/widgets/base\"], function(){\n",
" \n",
" // Define the DateModel and register it with the widget manager.\n",
" var DateModel = IPython.WidgetModel.extend({});\n",
" IPython.widget_manager.register_widget_model('DateWidgetModel', DateModel);\n",
"\n",
"require([\"notebook/js/widgets/widget\"], function(WidgetManager){\n",
" \n",
" // Define the DatePickerView\n",
" var DatePickerView = IPython.WidgetView.extend({\n",
" \n",
" var DatePickerView = IPython.DOMWidgetView.extend({\n",
" render: function(){\n",
" \n",
" // Create a div to hold our widget.\n",
" this.$el = $('<div />')\n",
" .addClass('widget-hbox-single'); // Apply this class to the widget container to make\n",
" // it fit with the other built in widgets.\n",
" this.delegateEvents();\n",
" \n",
" this.$el.addClass('widget-hbox-single'); /* Apply this class to the widget container to make\n",
" it fit with the other built in widgets.*/\n",
" // Create a label.\n",
" this.$label = $('<div />')\n",
" .addClass('widget-hlabel')\n",
@ -1020,10 +873,10 @@
" this.$label.hide();\n",
" } else {\n",
" this.$label.show();\n",
" this.$label.html (description);\n",
" this.$label.text (description);\n",
" }\n",
" \n",
" return IPython.WidgetView.prototype.update.call (this);\n",
" return DatePickerView.__super__.update.apply (this);\n",
" },\n",
" \n",
" // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n",
@ -1032,12 +885,12 @@
" // Callback for when the date is changed.\n",
" handle_date_change: function(event) {\n",
" this.model.set('value', this.$date.val());\n",
" this.touch();\n",
" },\n",
" \n",
" });\n",
" \n",
" // Register the DatePickerView with the widget manager.\n",
" IPython.widget_m anager.register_widget_view('DatePickerView', DatePickerView);\n",
" WidgetM anager.register_widget_view('DatePickerView', DatePickerView);\n",
"});"
],
"language": "python",
@ -1046,23 +899,14 @@
{
"javascript": [
"\n",
"require([\"notebook/js/widgets/base\"], function(){\n",
" \n",
" // Define the DateModel and register it with the widget manager.\n",
" var DateModel = IPython.WidgetModel.extend({});\n",
" IPython.widget_manager.register_widget_model('DateWidgetModel', DateModel);\n",
"\n",
"require([\"notebook/js/widgets/widget\"], function(WidgetManager){\n",
" \n",
" // Define the DatePickerView\n",
" var DatePickerView = IPython.WidgetView.extend({\n",
" \n",
" var DatePickerView = IPython.DOMWidgetView.extend({\n",
" render: function(){\n",
" \n",
" // Create a div to hold our widget.\n",
" this.$el = $('<div />')\n",
" .addClass('widget-hbox-single'); // Apply this class to the widget container to make\n",
" // it fit with the other built in widgets.\n",
" this.delegateEvents();\n",
" \n",
" this.$el.addClass('widget-hbox-single'); /* Apply this class to the widget container to make\n",
" it fit with the other built in widgets.*/\n",
" // Create a label.\n",
" this.$label = $('<div />')\n",
" .addClass('widget-hlabel')\n",
@ -1086,10 +930,10 @@
" this.$label.hide();\n",
" } else {\n",
" this.$label.show();\n",
" this.$label.html (description);\n",
" this.$label.text (description);\n",
" }\n",
" \n",
" return IPython.WidgetView.prototype.update.call (this);\n",
" return DatePickerView.__super__.update.apply (this);\n",
" },\n",
" \n",
" // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n",
@ -1098,22 +942,22 @@
" // Callback for when the date is changed.\n",
" handle_date_change: function(event) {\n",
" this.model.set('value', this.$date.val());\n",
" this.touch();\n",
" },\n",
" \n",
" });\n",
" \n",
" // Register the DatePickerView with the widget manager.\n",
" IPython.widget_m anager.register_widget_view('DatePickerView', DatePickerView);\n",
" WidgetM anager.register_widget_view('DatePickerView', DatePickerView);\n",
"});"
],
"metadata": {},
"output_type": "display_data",
"text": [
"<IPython.core.display.Javascript at 0x10a274a 10>"
"<IPython.core.display.Javascript at 0x1efe2 10>"
]
}
],
"prompt_number": 53
"prompt_number": 40
},
{
"cell_type": "heading",
@ -1135,40 +979,23 @@
"collapsed": false,
"input": [
"# Add some additional widgets for aesthetic purpose\n",
"display(widgets.String Widget(description=\"First:\"))\n",
"display(widgets.String Widget(description=\"Last:\"))\n",
"display(widgets.TextBox Widget(description=\"First:\"))\n",
"display(widgets.TextBox Widget(description=\"Last:\"))\n",
"\n",
"my_widget = DateWidget(description=\"DOB:\")\n",
"display(my_widget)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 43
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Since the date widget uses `value` and `description`, we can also display its value using a `TextBoxView`. The allows us to look at the raw date value being passed to and from the back-end and front-end."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"display(my_widget, view_name=\"TextBoxView\")"
"my_widget = DateWidget()\n",
"display(my_widget)\n",
"my_widget.description=\"DOB:\""
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 44
"prompt_number": 46
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we will try to create a widget that only accepts dates in the year 2013 . We render the widget without a description to verify that it can still render without a label."
"Now we will try to create a widget that only accepts dates in the year 2014. We render the widget without a description to verify that it can still render without a label."
]
},
{
@ -1179,25 +1006,25 @@
"display(my_widget)\n",
"\n",
"def validate_date(date):\n",
" return not date is None and date.year == 2013 \n",
"my_widget.on_ validate(validate_date)"
" return not date is None and date.year == 2014 \n",
"my_widget.validation.r egister_callback (validate_date)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 5 7
"prompt_number": 4 7
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# Try setting a valid date\n",
"my_widget.value = \"December 2, 2013 \""
"my_widget.value = \"December 2, 2014 \""
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 46
"prompt_number": 48
},
{
"cell_type": "code",
@ -1209,7 +1036,7 @@
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 48
"prompt_number": 49
},
{
"cell_type": "code",
@ -1223,21 +1050,13 @@
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 58 ,
"prompt_number": 50 ,
"text": [
"u''"
"u'2014-12-02 '"
]
}
],
"prompt_number": 58
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": []
"prompt_number": 50
}
],
"metadata": {}