##// END OF EJS Templates
Work on widget tutorials
Brian E. Granger -
Show More
@@ -1,349 +1,335 b''
1 {
1 {
2 "metadata": {
2 "metadata": {
3 "cell_tags": [
3 "cell_tags": [
4 [
4 [
5 "<None>",
5 "<None>",
6 null
6 null
7 ]
7 ]
8 ],
8 ],
9 "name": "",
9 "name": "",
10 "signature": "sha256:25599ae01786ec88374ddc5bd814583b1c0cd9fbe69f59fefaeba5c3b1507735"
10 "signature": "sha256:19f2a57c9ac75d472a9e403515009613fac3fbc733219f7fd4f39a0616ca619f"
11 },
11 },
12 "nbformat": 3,
12 "nbformat": 3,
13 "nbformat_minor": 0,
13 "nbformat_minor": 0,
14 "worksheets": [
14 "worksheets": [
15 {
15 {
16 "cells": [
16 "cells": [
17 {
17 {
18 "cell_type": "markdown",
19 "metadata": {},
20 "source": [
21 "[< Back to Part 4](Part 4 - Styles.ipynb) or [Index](index.ipynb)"
22 ]
23 },
24 {
25 "cell_type": "code",
18 "cell_type": "code",
26 "collapsed": false,
19 "collapsed": false,
27 "input": [
20 "input": [
28 "from IPython.html import widgets # Widget definitions\n",
21 "from IPython.html import widgets # Widget definitions\n",
29 "from IPython.display import display # Used to display widgets in the notebook"
22 "from IPython.display import display # Used to display widgets in the notebook"
30 ],
23 ],
31 "language": "python",
24 "language": "python",
32 "metadata": {},
25 "metadata": {},
33 "outputs": [],
26 "outputs": [],
34 "prompt_number": 1
27 "prompt_number": 1
35 },
28 },
36 {
29 {
37 "cell_type": "heading",
30 "cell_type": "heading",
38 "level": 1,
31 "level": 1,
39 "metadata": {},
32 "metadata": {},
40 "source": [
33 "source": [
41 "Alignment"
34 "Alignment"
42 ]
35 ]
43 },
36 },
44 {
37 {
45 "cell_type": "markdown",
38 "cell_type": "markdown",
46 "metadata": {},
39 "metadata": {},
47 "source": [
40 "source": [
48 "Most widgets have a `description` attribute, which allows a label for the widget to be defined.\n",
41 "Most widgets have a `description` attribute, which allows a label for the widget to be defined.\n",
49 "The label of the widget has a fixed minimum width.\n",
42 "The label of the widget has a fixed minimum width.\n",
50 "The text of the label is always right aligned and the widget is left aligned:"
43 "The text of the label is always right aligned and the widget is left aligned:"
51 ]
44 ]
52 },
45 },
53 {
46 {
54 "cell_type": "code",
47 "cell_type": "code",
55 "collapsed": false,
48 "collapsed": false,
56 "input": [
49 "input": [
57 "display(widgets.TextWidget(description=\"a:\"))\n",
50 "display(widgets.TextWidget(description=\"a:\"))\n",
58 "display(widgets.TextWidget(description=\"aa:\"))\n",
51 "display(widgets.TextWidget(description=\"aa:\"))\n",
59 "display(widgets.TextWidget(description=\"aaa:\"))"
52 "display(widgets.TextWidget(description=\"aaa:\"))"
60 ],
53 ],
61 "language": "python",
54 "language": "python",
62 "metadata": {},
55 "metadata": {},
63 "outputs": [],
56 "outputs": [],
64 "prompt_number": 2
57 "prompt_number": 2
65 },
58 },
66 {
59 {
67 "cell_type": "markdown",
60 "cell_type": "markdown",
68 "metadata": {},
61 "metadata": {},
69 "source": [
62 "source": [
70 "If a label is longer than the minimum width, the widget is shifted to the right:"
63 "If a label is longer than the minimum width, the widget is shifted to the right:"
71 ]
64 ]
72 },
65 },
73 {
66 {
74 "cell_type": "code",
67 "cell_type": "code",
75 "collapsed": false,
68 "collapsed": false,
76 "input": [
69 "input": [
77 "display(widgets.TextWidget(description=\"a:\"))\n",
70 "display(widgets.TextWidget(description=\"a:\"))\n",
78 "display(widgets.TextWidget(description=\"aa:\"))\n",
71 "display(widgets.TextWidget(description=\"aa:\"))\n",
79 "display(widgets.TextWidget(description=\"aaa:\"))\n",
72 "display(widgets.TextWidget(description=\"aaa:\"))\n",
80 "display(widgets.TextWidget(description=\"aaaaaaaaaaaaaaaaaa:\"))"
73 "display(widgets.TextWidget(description=\"aaaaaaaaaaaaaaaaaa:\"))"
81 ],
74 ],
82 "language": "python",
75 "language": "python",
83 "metadata": {},
76 "metadata": {},
84 "outputs": [],
77 "outputs": [],
85 "prompt_number": 3
78 "prompt_number": 3
86 },
79 },
87 {
80 {
88 "cell_type": "markdown",
81 "cell_type": "markdown",
89 "metadata": {},
82 "metadata": {},
90 "source": [
83 "source": [
91 "If a `description` is not set for the widget, the label is not displayed:"
84 "If a `description` is not set for the widget, the label is not displayed:"
92 ]
85 ]
93 },
86 },
94 {
87 {
95 "cell_type": "code",
88 "cell_type": "code",
96 "collapsed": false,
89 "collapsed": false,
97 "input": [
90 "input": [
98 "display(widgets.TextWidget(description=\"a:\"))\n",
91 "display(widgets.TextWidget(description=\"a:\"))\n",
99 "display(widgets.TextWidget(description=\"aa:\"))\n",
92 "display(widgets.TextWidget(description=\"aa:\"))\n",
100 "display(widgets.TextWidget(description=\"aaa:\"))\n",
93 "display(widgets.TextWidget(description=\"aaa:\"))\n",
101 "display(widgets.TextWidget())"
94 "display(widgets.TextWidget())"
102 ],
95 ],
103 "language": "python",
96 "language": "python",
104 "metadata": {},
97 "metadata": {},
105 "outputs": [],
98 "outputs": [],
106 "prompt_number": 4
99 "prompt_number": 4
107 },
100 },
108 {
101 {
109 "cell_type": "heading",
102 "cell_type": "heading",
110 "level": 1,
103 "level": 1,
111 "metadata": {},
104 "metadata": {},
112 "source": [
105 "source": [
113 "Custom Alignment"
106 "Custom Alignment"
114 ]
107 ]
115 },
108 },
116 {
109 {
117 "cell_type": "markdown",
110 "cell_type": "markdown",
118 "metadata": {},
111 "metadata": {},
119 "source": [
112 "source": [
120 "`ContainerWidget`s allow for custom alignment of widgets.\n",
113 "`ContainerWidget`s allow for custom alignment of widgets.\n",
121 "The `hbox` and `vbox` CSS classes cause the `ContainerWidget` to horizontally or vertically align its children."
114 "The `hbox` and `vbox` CSS classes cause the `ContainerWidget` to horizontally or vertically align its children."
122 ]
115 ]
123 },
116 },
124 {
117 {
125 "cell_type": "code",
118 "cell_type": "code",
126 "collapsed": false,
119 "collapsed": false,
127 "input": [
120 "input": [
128 "child_style = {\n",
121 "child_style = {\n",
129 " 'background': '#77CC77',\n",
122 " 'background': '#77CC77',\n",
130 " 'padding': '25px',\n",
123 " 'padding': '25px',\n",
131 " 'margin': '5px',\n",
124 " 'margin': '5px',\n",
132 " 'font-size': 'xx-large',\n",
125 " 'font-size': 'xx-large',\n",
133 " 'color': 'white',\n",
126 " 'color': 'white',\n",
134 "}\n",
127 "}\n",
135 "\n",
128 "\n",
136 "def make_container(title):\n",
129 "def make_container(title):\n",
137 " header = widgets.LatexWidget(value=title) \n",
130 " header = widgets.LatexWidget(value=title) \n",
138 " display(header)\n",
131 " display(header)\n",
139 " header.set_css({\n",
132 " header.set_css({\n",
140 " 'font-size': '30pt',\n",
133 " 'font-size': '30pt',\n",
141 " 'margin-top': '40pt',\n",
134 " 'margin-top': '40pt',\n",
142 " 'margin-bottom': '20pt',\n",
135 " 'margin-bottom': '20pt',\n",
143 " })\n",
136 " })\n",
144 " \n",
137 " \n",
145 " container = widgets.ContainerWidget()\n",
138 " container = widgets.ContainerWidget()\n",
146 " container.set_css({\n",
139 " container.set_css({\n",
147 " 'background': '#999999',\n",
140 " 'background': '#999999',\n",
148 " 'width': '100%',\n",
141 " 'width': '100%',\n",
149 " })\n",
142 " })\n",
150 " display(container)\n",
143 " display(container)\n",
151 " return container\n",
144 " return container\n",
152 "\n",
145 "\n",
153 "def fill_container(container):\n",
146 "def fill_container(container):\n",
154 " components = []\n",
147 " components = []\n",
155 " for i in range(3):\n",
148 " for i in range(3):\n",
156 " components.append(widgets.LatexWidget(value=\"ABC\"[i]))\n",
149 " components.append(widgets.LatexWidget(value=\"ABC\"[i]))\n",
157 " components[i].set_css(child_style)\n",
150 " components[i].set_css(child_style)\n",
158 " container.children = components\n",
151 " container.children = components\n",
159 " \n",
152 " \n",
160 "container = make_container('VBox')\n",
153 "container = make_container('VBox')\n",
161 "container.add_class('vbox')\n",
154 "container.add_class('vbox')\n",
162 "fill_container(container)\n",
155 "fill_container(container)\n",
163 "\n",
156 "\n",
164 "container = make_container('HBox')\n",
157 "container = make_container('HBox')\n",
165 "container.remove_class('vbox')\n",
158 "container.remove_class('vbox')\n",
166 "container.add_class('hbox')\n",
159 "container.add_class('hbox')\n",
167 "fill_container(container)\n"
160 "fill_container(container)\n"
168 ],
161 ],
169 "language": "python",
162 "language": "python",
170 "metadata": {},
163 "metadata": {},
171 "outputs": [],
164 "outputs": [],
172 "prompt_number": 5
165 "prompt_number": 5
173 },
166 },
174 {
167 {
175 "cell_type": "markdown",
168 "cell_type": "markdown",
176 "metadata": {},
169 "metadata": {},
177 "source": [
170 "source": [
178 "The `start`, `center`, and `end` classes adjust the alignment of the widgets on the axis where they are being rendered.\n",
171 "The `start`, `center`, and `end` classes adjust the alignment of the widgets on the axis where they are being rendered.\n",
179 "Below is an example of the different alignments."
172 "Below is an example of the different alignments."
180 ]
173 ]
181 },
174 },
182 {
175 {
183 "cell_type": "code",
176 "cell_type": "code",
184 "collapsed": false,
177 "collapsed": false,
185 "input": [
178 "input": [
186 "container = make_container('HBox Pack Start')\n",
179 "container = make_container('HBox Pack Start')\n",
187 "container.remove_class('vbox')\n",
180 "container.remove_class('vbox')\n",
188 "container.add_class('hbox')\n",
181 "container.add_class('hbox')\n",
189 "container.add_class('start')\n",
182 "container.add_class('start')\n",
190 "fill_container(container)\n",
183 "fill_container(container)\n",
191 " \n",
184 " \n",
192 "container = make_container('HBox Pack Center')\n",
185 "container = make_container('HBox Pack Center')\n",
193 "container.remove_class('vbox')\n",
186 "container.remove_class('vbox')\n",
194 "container.add_class('hbox')\n",
187 "container.add_class('hbox')\n",
195 "container.add_class('center')\n",
188 "container.add_class('center')\n",
196 "fill_container(container)\n",
189 "fill_container(container)\n",
197 " \n",
190 " \n",
198 "container = make_container('HBox Pack End')\n",
191 "container = make_container('HBox Pack End')\n",
199 "container.remove_class('vbox')\n",
192 "container.remove_class('vbox')\n",
200 "container.add_class('hbox')\n",
193 "container.add_class('hbox')\n",
201 "container.add_class('end')\n",
194 "container.add_class('end')\n",
202 "fill_container(container)"
195 "fill_container(container)"
203 ],
196 ],
204 "language": "python",
197 "language": "python",
205 "metadata": {},
198 "metadata": {},
206 "outputs": [],
199 "outputs": [],
207 "prompt_number": 6
200 "prompt_number": 6
208 },
201 },
209 {
202 {
210 "cell_type": "markdown",
203 "cell_type": "markdown",
211 "metadata": {},
204 "metadata": {},
212 "source": [
205 "source": [
213 "The `box-flex0`, `box-flex1`, and `box-flex2` DOM classes modify the container's flexibility. Changing a container flexibility affects how and if the container will occupy the remaining space. Applying `box-flex0` has the same result as not applying flex. Below is an example of different flex configurations. The number on the boxes correspond to the applied flex."
206 "The `box-flex0`, `box-flex1`, and `box-flex2` DOM classes modify the container's flexibility. Changing a container flexibility affects how and if the container will occupy the remaining space. Applying `box-flex0` has the same result as not applying flex. Below is an example of different flex configurations. The number on the boxes correspond to the applied flex."
214 ]
207 ]
215 },
208 },
216 {
209 {
217 "cell_type": "code",
210 "cell_type": "code",
218 "collapsed": false,
211 "collapsed": false,
219 "input": [
212 "input": [
220 "def fill_container(container, flexes):\n",
213 "def fill_container(container, flexes):\n",
221 " components = []\n",
214 " components = []\n",
222 " for i in range(len(flexes)):\n",
215 " for i in range(len(flexes)):\n",
223 " components.append(widgets.ContainerWidget())\n",
216 " components.append(widgets.ContainerWidget())\n",
224 " components[i].set_css(child_style)\n",
217 " components[i].set_css(child_style)\n",
225 " \n",
218 " \n",
226 " label = widgets.LatexWidget(value=str(flexes[i]))\n",
219 " label = widgets.LatexWidget(value=str(flexes[i]))\n",
227 " components[i].children = [label]\n",
220 " components[i].children = [label]\n",
228 " container.children = components\n",
221 " container.children = components\n",
229 " \n",
222 " \n",
230 " for i in range(len(flexes)):\n",
223 " for i in range(len(flexes)):\n",
231 " if flexes[i] == 0:\n",
224 " if flexes[i] == 0:\n",
232 " components[i].add_class('box-flex0')\n",
225 " components[i].add_class('box-flex0')\n",
233 " elif flexes[i] == 1:\n",
226 " elif flexes[i] == 1:\n",
234 " components[i].add_class('box-flex1')\n",
227 " components[i].add_class('box-flex1')\n",
235 " elif flexes[i] == 2:\n",
228 " elif flexes[i] == 2:\n",
236 " components[i].add_class('box-flex2')\n",
229 " components[i].add_class('box-flex2')\n",
237 " \n",
230 " \n",
238 "container = make_container('Different Flex Configurations')\n",
231 "container = make_container('Different Flex Configurations')\n",
239 "container.remove_class('vbox')\n",
232 "container.remove_class('vbox')\n",
240 "container.add_class('hbox')\n",
233 "container.add_class('hbox')\n",
241 "fill_container(container, [0, 0, 0])\n",
234 "fill_container(container, [0, 0, 0])\n",
242 " \n",
235 " \n",
243 "container = make_container('')\n",
236 "container = make_container('')\n",
244 "container.remove_class('vbox')\n",
237 "container.remove_class('vbox')\n",
245 "container.add_class('hbox')\n",
238 "container.add_class('hbox')\n",
246 "fill_container(container, [0, 0, 1])\n",
239 "fill_container(container, [0, 0, 1])\n",
247 " \n",
240 " \n",
248 "container = make_container('')\n",
241 "container = make_container('')\n",
249 "container.remove_class('vbox')\n",
242 "container.remove_class('vbox')\n",
250 "container.add_class('hbox')\n",
243 "container.add_class('hbox')\n",
251 "fill_container(container, [0, 1, 1])\n",
244 "fill_container(container, [0, 1, 1])\n",
252 " \n",
245 " \n",
253 "container = make_container('')\n",
246 "container = make_container('')\n",
254 "container.remove_class('vbox')\n",
247 "container.remove_class('vbox')\n",
255 "container.add_class('hbox')\n",
248 "container.add_class('hbox')\n",
256 "fill_container(container, [0, 2, 2])\n",
249 "fill_container(container, [0, 2, 2])\n",
257 " \n",
250 " \n",
258 "container = make_container('')\n",
251 "container = make_container('')\n",
259 "container.remove_class('vbox')\n",
252 "container.remove_class('vbox')\n",
260 "container.add_class('hbox')\n",
253 "container.add_class('hbox')\n",
261 "fill_container(container, [0, 1, 2])\n",
254 "fill_container(container, [0, 1, 2])\n",
262 " \n",
255 " \n",
263 "container = make_container('')\n",
256 "container = make_container('')\n",
264 "container.remove_class('vbox')\n",
257 "container.remove_class('vbox')\n",
265 "container.add_class('hbox')\n",
258 "container.add_class('hbox')\n",
266 "fill_container(container, [1, 1, 2])"
259 "fill_container(container, [1, 1, 2])"
267 ],
260 ],
268 "language": "python",
261 "language": "python",
269 "metadata": {},
262 "metadata": {},
270 "outputs": [],
263 "outputs": [],
271 "prompt_number": 7
264 "prompt_number": 7
272 },
265 },
273 {
266 {
274 "cell_type": "markdown",
267 "cell_type": "markdown",
275 "metadata": {},
268 "metadata": {},
276 "source": [
269 "source": [
277 "The `align_start`, `align_center`, and `align_end` DOM classes adjust the alignment of the widgets on the axis perpindicular to the one that they are being rendered on. Below is an example of the different alignments."
270 "The `align_start`, `align_center`, and `align_end` DOM classes adjust the alignment of the widgets on the axis perpindicular to the one that they are being rendered on. Below is an example of the different alignments."
278 ]
271 ]
279 },
272 },
280 {
273 {
281 "cell_type": "code",
274 "cell_type": "code",
282 "collapsed": false,
275 "collapsed": false,
283 "input": [
276 "input": [
284 "def fill_container(container):\n",
277 "def fill_container(container):\n",
285 " components = []\n",
278 " components = []\n",
286 " for i in range(3):\n",
279 " for i in range(3):\n",
287 " components.append(widgets.LatexWidget(parent=container, value=\"ABC\"[i]))\n",
280 " components.append(widgets.LatexWidget(parent=container, value=\"ABC\"[i]))\n",
288 " components[i].set_css(child_style)\n",
281 " components[i].set_css(child_style)\n",
289 " components[i].set_css('height', str((i+1) * 50) + 'px')\n",
282 " components[i].set_css('height', str((i+1) * 50) + 'px')\n",
290 " container.children = components\n",
283 " container.children = components\n",
291 "\n",
284 "\n",
292 "container = make_container('HBox Align Start')\n",
285 "container = make_container('HBox Align Start')\n",
293 "container.remove_class('vbox')\n",
286 "container.remove_class('vbox')\n",
294 "container.add_class(\"hbox\")\n",
287 "container.add_class(\"hbox\")\n",
295 "container.add_class(\"align-start\")\n",
288 "container.add_class(\"align-start\")\n",
296 "fill_container(container)\n",
289 "fill_container(container)\n",
297 " \n",
290 " \n",
298 "container = make_container('HBox Align Center')\n",
291 "container = make_container('HBox Align Center')\n",
299 "container.remove_class('vbox')\n",
292 "container.remove_class('vbox')\n",
300 "container.add_class(\"hbox\")\n",
293 "container.add_class(\"hbox\")\n",
301 "container.add_class(\"align-center\")\n",
294 "container.add_class(\"align-center\")\n",
302 "fill_container(container)\n",
295 "fill_container(container)\n",
303 " \n",
296 " \n",
304 "container = make_container('HBox Align End')\n",
297 "container = make_container('HBox Align End')\n",
305 "container.remove_class('vbox')\n",
298 "container.remove_class('vbox')\n",
306 "container.add_class(\"hbox\")\n",
299 "container.add_class(\"hbox\")\n",
307 "container.add_class(\"align-end\")\n",
300 "container.add_class(\"align-end\")\n",
308 "fill_container(container)"
301 "fill_container(container)"
309 ],
302 ],
310 "language": "python",
303 "language": "python",
311 "metadata": {},
304 "metadata": {},
312 "outputs": [],
305 "outputs": [],
313 "prompt_number": 8
306 "prompt_number": 8
314 },
307 },
315 {
308 {
316 "cell_type": "markdown",
309 "cell_type": "markdown",
317 "metadata": {},
310 "metadata": {},
318 "source": [
311 "source": [
319 "By default the widget area is a `vbox`; however, there are many uses for a `hbox`. The example below uses a `hbox` to display a set of vertical sliders, like an equalizer."
312 "By default the widget area is a `vbox`; however, there are many uses for a `hbox`. The example below uses a `hbox` to display a set of vertical sliders, like an equalizer."
320 ]
313 ]
321 },
314 },
322 {
315 {
323 "cell_type": "code",
316 "cell_type": "code",
324 "collapsed": false,
317 "collapsed": false,
325 "input": [
318 "input": [
326 "container = widgets.ContainerWidget()\n",
319 "container = widgets.ContainerWidget()\n",
327 "container.children=[widgets.FloatSliderWidget(orientation='vertical', description=str(i+1), value=50.0) \n",
320 "container.children=[widgets.FloatSliderWidget(orientation='vertical', description=str(i+1), value=50.0) \n",
328 " for i in range(15)]\n",
321 " for i in range(15)]\n",
329 "display(container)\n",
322 "display(container)\n",
330 "container.remove_class('vbox')\n",
323 "container.remove_class('vbox')\n",
331 "container.add_class('hbox')"
324 "container.add_class('hbox')"
332 ],
325 ],
333 "language": "python",
326 "language": "python",
334 "metadata": {},
327 "metadata": {},
335 "outputs": [],
328 "outputs": [],
336 "prompt_number": 9
329 "prompt_number": 9
337 },
338 {
339 "cell_type": "markdown",
340 "metadata": {},
341 "source": [
342 "In [Part 6](Part 6 - Custom Widget.ipynb) of this [series](index.ipynb), you will learn how to create your own custom widget."
343 ]
344 }
330 }
345 ],
331 ],
346 "metadata": {}
332 "metadata": {}
347 }
333 }
348 ]
334 ]
349 } No newline at end of file
335 }
@@ -1,314 +1,306 b''
1 {
1 {
2 "metadata": {
2 "metadata": {
3 "cell_tags": [
3 "cell_tags": [
4 [
4 [
5 "<None>",
5 "<None>",
6 null
6 null
7 ]
7 ]
8 ],
8 ],
9 "name": ""
9 "name": "",
10 "signature": "sha256:9a70b52f0b16861d1cd6a8342b233247958977a52bde8d3efd69d21131ce1926"
10 },
11 },
11 "nbformat": 3,
12 "nbformat": 3,
12 "nbformat_minor": 0,
13 "nbformat_minor": 0,
13 "worksheets": [
14 "worksheets": [
14 {
15 {
15 "cells": [
16 "cells": [
16 {
17 {
17 "cell_type": "markdown",
18 "cell_type": "markdown",
18 "metadata": {},
19 "metadata": {},
19 "source": [
20 "source": [
20 "[Index](index.ipynb)\n",
21 "\n",
22 "To use IPython widgets in the notebook, the widget namespace needs to be imported."
21 "To use IPython widgets in the notebook, the widget namespace needs to be imported."
23 ]
22 ]
24 },
23 },
25 {
24 {
26 "cell_type": "code",
25 "cell_type": "code",
27 "collapsed": false,
26 "collapsed": false,
28 "input": [
27 "input": [
29 "from IPython.html import widgets # Widget definitions\n",
28 "from IPython.html import widgets # Widget definitions\n",
30 "from IPython.display import display # Used to display widgets in the notebook"
29 "from IPython.display import display # Used to display widgets in the notebook"
31 ],
30 ],
32 "language": "python",
31 "language": "python",
33 "metadata": {},
32 "metadata": {},
34 "outputs": [],
33 "outputs": [],
35 "prompt_number": 1
34 "prompt_number": 1
36 },
35 },
37 {
36 {
38 "cell_type": "heading",
37 "cell_type": "heading",
39 "level": 1,
38 "level": 1,
40 "metadata": {},
39 "metadata": {},
41 "source": [
40 "source": [
42 "Basic Widgets"
41 "Basic Widgets"
43 ]
42 ]
44 },
43 },
45 {
44 {
46 "cell_type": "markdown",
45 "cell_type": "markdown",
47 "metadata": {},
46 "metadata": {},
48 "source": [
47 "source": [
49 "IPython comes with basic widgets that represent common interactive controls. These widgets are\n",
48 "IPython comes with basic widgets that represent common interactive controls. These widgets are\n",
50 "\n",
49 "\n",
51 "- CheckboxWidget\n",
50 "- CheckboxWidget\n",
52 "- ToggleButtonWidget\n",
51 "- ToggleButtonWidget\n",
53 "- FloatSliderWidget\n",
52 "- FloatSliderWidget\n",
54 "- BoundedFloatTextWidget\n",
53 "- BoundedFloatTextWidget\n",
55 "- FloatProgressWidget\n",
54 "- FloatProgressWidget\n",
56 "- FloatTextWidget\n",
55 "- FloatTextWidget\n",
57 "- ImageWidget\n",
56 "- ImageWidget\n",
58 "- IntSliderWidget\n",
57 "- IntSliderWidget\n",
59 "- BoundedIntTextWidget\n",
58 "- BoundedIntTextWidget\n",
60 "- IntProgressWidget\n",
59 "- IntProgressWidget\n",
61 "- IntTextWidget\n",
60 "- IntTextWidget\n",
62 "- ToggleButtonsWidget\n",
61 "- ToggleButtonsWidget\n",
63 "- RadioButtonsWidget\n",
62 "- RadioButtonsWidget\n",
64 "- DropdownWidget\n",
63 "- DropdownWidget\n",
65 "- SelectWidget\n",
64 "- SelectWidget\n",
66 "- HTMLWidget\n",
65 "- HTMLWidget\n",
67 "- LatexWidget\n",
66 "- LatexWidget\n",
68 "- TextareaWidget\n",
67 "- TextareaWidget\n",
69 "- TextWidget\n",
68 "- TextWidget\n",
70 "- ButtonWidget\n",
69 "- ButtonWidget\n",
71 "\n",
70 "\n",
72 "A few special widgets are also included, that can be used to capture events and change how other widgets are displayed. These widgets are\n",
71 "A few special widgets are also included, that can be used to capture events and change how other widgets are displayed. These widgets are\n",
73 "\n",
72 "\n",
74 "- ContainerWidget\n",
73 "- ContainerWidget\n",
75 "- PopupWidget\n",
74 "- PopupWidget\n",
76 "- AccordionWidget\n",
75 "- AccordionWidget\n",
77 "- TabWidget\n",
76 "- TabWidget\n",
78 "\n",
77 "\n",
79 "To see the complete list of widgets, one can execute the following"
78 "To see the complete list of widgets, one can execute the following"
80 ]
79 ]
81 },
80 },
82 {
81 {
83 "cell_type": "code",
82 "cell_type": "code",
84 "collapsed": false,
83 "collapsed": false,
85 "input": [
84 "input": [
86 "[widget for widget in dir(widgets) if widget.endswith('Widget')]"
85 "[widget for widget in dir(widgets) if widget.endswith('Widget')]"
87 ],
86 ],
88 "language": "python",
87 "language": "python",
89 "metadata": {},
88 "metadata": {},
90 "outputs": [
89 "outputs": [
91 {
90 {
92 "metadata": {},
91 "metadata": {},
93 "output_type": "pyout",
92 "output_type": "pyout",
94 "prompt_number": 2,
93 "prompt_number": 2,
95 "text": [
94 "text": [
96 "['AccordionWidget',\n",
95 "['AccordionWidget',\n",
97 " 'BoundedFloatTextWidget',\n",
96 " 'BoundedFloatTextWidget',\n",
98 " 'BoundedIntTextWidget',\n",
97 " 'BoundedIntTextWidget',\n",
99 " 'ButtonWidget',\n",
98 " 'ButtonWidget',\n",
100 " 'CheckboxWidget',\n",
99 " 'CheckboxWidget',\n",
101 " 'ContainerWidget',\n",
100 " 'ContainerWidget',\n",
102 " 'DOMWidget',\n",
101 " 'DOMWidget',\n",
103 " 'DropdownWidget',\n",
102 " 'DropdownWidget',\n",
104 " 'FloatProgressWidget',\n",
103 " 'FloatProgressWidget',\n",
105 " 'FloatSliderWidget',\n",
104 " 'FloatSliderWidget',\n",
106 " 'FloatTextWidget',\n",
105 " 'FloatTextWidget',\n",
107 " 'HTMLWidget',\n",
106 " 'HTMLWidget',\n",
108 " 'ImageWidget',\n",
107 " 'ImageWidget',\n",
109 " 'IntProgressWidget',\n",
108 " 'IntProgressWidget',\n",
110 " 'IntSliderWidget',\n",
109 " 'IntSliderWidget',\n",
111 " 'IntTextWidget',\n",
110 " 'IntTextWidget',\n",
112 " 'LatexWidget',\n",
111 " 'LatexWidget',\n",
113 " 'PopupWidget',\n",
112 " 'PopupWidget',\n",
114 " 'RadioButtonsWidget',\n",
113 " 'RadioButtonsWidget',\n",
115 " 'SelectWidget',\n",
114 " 'SelectWidget',\n",
116 " 'TabWidget',\n",
115 " 'TabWidget',\n",
117 " 'TextWidget',\n",
116 " 'TextWidget',\n",
118 " 'TextareaWidget',\n",
117 " 'TextareaWidget',\n",
119 " 'ToggleButtonWidget',\n",
118 " 'ToggleButtonWidget',\n",
120 " 'ToggleButtonsWidget',\n",
119 " 'ToggleButtonsWidget',\n",
121 " 'Widget']"
120 " 'Widget']"
122 ]
121 ]
123 }
122 }
124 ],
123 ],
125 "prompt_number": 2
124 "prompt_number": 2
126 },
125 },
127 {
126 {
128 "cell_type": "markdown",
127 "cell_type": "markdown",
129 "metadata": {},
128 "metadata": {},
130 "source": [
129 "source": [
131 "The basic widgets all have sensible default values. Create a *FloatSliderWidget* without displaying it:"
130 "The basic widgets all have sensible default values. Create a *FloatSliderWidget* without displaying it:"
132 ]
131 ]
133 },
132 },
134 {
133 {
135 "cell_type": "code",
134 "cell_type": "code",
136 "collapsed": false,
135 "collapsed": false,
137 "input": [
136 "input": [
138 "mywidget = widgets.FloatSliderWidget()"
137 "mywidget = widgets.FloatSliderWidget()"
139 ],
138 ],
140 "language": "python",
139 "language": "python",
141 "metadata": {},
140 "metadata": {},
142 "outputs": [],
141 "outputs": [],
143 "prompt_number": 3
142 "prompt_number": 3
144 },
143 },
145 {
144 {
146 "cell_type": "markdown",
145 "cell_type": "markdown",
147 "metadata": {},
146 "metadata": {},
148 "source": [
147 "source": [
149 "Constructing a widget does not display it on the page. To display a widget, the widget must be passed to the IPython `display(object)` method or must be returned as the last item in the cell. `mywidget` is displayed by"
148 "Constructing a widget does not display it on the page. To display a widget, the widget must be passed to the IPython `display(object)` method or must be returned as the last item in the cell. `mywidget` is displayed by"
150 ]
149 ]
151 },
150 },
152 {
151 {
153 "cell_type": "code",
152 "cell_type": "code",
154 "collapsed": false,
153 "collapsed": false,
155 "input": [
154 "input": [
156 "display(mywidget)"
155 "display(mywidget)"
157 ],
156 ],
158 "language": "python",
157 "language": "python",
159 "metadata": {},
158 "metadata": {},
160 "outputs": [],
159 "outputs": [],
161 "prompt_number": 4
160 "prompt_number": 4
162 },
161 },
163 {
162 {
164 "cell_type": "markdown",
163 "cell_type": "markdown",
165 "metadata": {},
164 "metadata": {},
166 "source": [
165 "source": [
167 "or"
166 "or"
168 ]
167 ]
169 },
168 },
170 {
169 {
171 "cell_type": "code",
170 "cell_type": "code",
172 "collapsed": false,
171 "collapsed": false,
173 "input": [
172 "input": [
174 "mywidget"
173 "mywidget"
175 ],
174 ],
176 "language": "python",
175 "language": "python",
177 "metadata": {},
176 "metadata": {},
178 "outputs": [],
177 "outputs": [],
179 "prompt_number": 5
178 "prompt_number": 5
180 },
179 },
181 {
180 {
182 "cell_type": "markdown",
181 "cell_type": "markdown",
183 "metadata": {},
182 "metadata": {},
184 "source": [
183 "source": [
185 "It's important to realize that widgets are not the same as output, even though they are displayed with `display`. Widgets are drawn in a special widget area. That area is marked with a close button which allows you to collapse the widgets. Widgets cannot be interleaved with output. Doing so would break the ability to make simple animations using `clear_output`.\n",
184 "It's important to realize that widgets are not the same as output, even though they are displayed with `display`. Widgets are drawn in a special widget area. That area is marked with a close button which allows you to collapse the widgets. Widgets cannot be interleaved with output. Doing so would break the ability to make simple animations using `clear_output`.\n",
186 "\n",
185 "\n",
187 "Widgets are manipulated via special instance attributes (traitlets). The names of these traitlets are listed in the widget's `keys` attribute (as seen below). A few of these attributes are common to most widgets. The basic attributes are `value`, `description`, `visible`, and `disabled`. `_css` and `_view_name` are private attributes that exist in all widgets and should not be modified."
186 "Widgets are manipulated via special instance attributes (traitlets). The names of these traitlets are listed in the widget's `keys` attribute (as seen below). A few of these attributes are common to most widgets. The basic attributes are `value`, `description`, `visible`, and `disabled`. `_css` and `_view_name` are private attributes that exist in all widgets and should not be modified."
188 ]
187 ]
189 },
188 },
190 {
189 {
191 "cell_type": "code",
190 "cell_type": "code",
192 "collapsed": false,
191 "collapsed": false,
193 "input": [
192 "input": [
194 "mywidget.keys"
193 "mywidget.keys"
195 ],
194 ],
196 "language": "python",
195 "language": "python",
197 "metadata": {},
196 "metadata": {},
198 "outputs": [
197 "outputs": [
199 {
198 {
200 "metadata": {},
199 "metadata": {},
201 "output_type": "pyout",
200 "output_type": "pyout",
202 "prompt_number": 6,
201 "prompt_number": 6,
203 "text": [
202 "text": [
204 "['_view_name',\n",
203 "['_view_name',\n",
205 " 'orientation',\n",
204 " 'orientation',\n",
206 " 'min',\n",
205 " 'min',\n",
207 " 'max',\n",
206 " 'max',\n",
208 " '_css',\n",
207 " '_css',\n",
209 " 'value',\n",
208 " 'value',\n",
210 " 'disabled',\n",
209 " 'disabled',\n",
211 " 'visible',\n",
210 " 'visible',\n",
212 " 'step',\n",
211 " 'step',\n",
213 " 'description']"
212 " 'description']"
214 ]
213 ]
215 }
214 }
216 ],
215 ],
217 "prompt_number": 6
216 "prompt_number": 6
218 },
217 },
219 {
218 {
220 "cell_type": "markdown",
219 "cell_type": "markdown",
221 "metadata": {},
220 "metadata": {},
222 "source": [
221 "source": [
223 "Changing a widget's attribute will automatically update that widget everywhere it is displayed in the notebook. Here, the `value` attribute of `mywidget` is set. The slider shown above updates automatically with the new value. Syncing also works in the other direction - changing the value of the displayed widget will update the property's value."
222 "Changing a widget's attribute will automatically update that widget everywhere it is displayed in the notebook. Here, the `value` attribute of `mywidget` is set. The slider shown above updates automatically with the new value. Syncing also works in the other direction - changing the value of the displayed widget will update the property's value."
224 ]
223 ]
225 },
224 },
226 {
225 {
227 "cell_type": "code",
226 "cell_type": "code",
228 "collapsed": false,
227 "collapsed": false,
229 "input": [
228 "input": [
230 "mywidget.value = 25.0"
229 "mywidget.value = 25.0"
231 ],
230 ],
232 "language": "python",
231 "language": "python",
233 "metadata": {},
232 "metadata": {},
234 "outputs": [],
233 "outputs": [],
235 "prompt_number": 7
234 "prompt_number": 7
236 },
235 },
237 {
236 {
238 "cell_type": "markdown",
237 "cell_type": "markdown",
239 "metadata": {},
238 "metadata": {},
240 "source": [
239 "source": [
241 "After changing the widget's value in the notebook by hand to 0.0 (sliding the bar to the far left)."
240 "After changing the widget's value in the notebook by hand to 0.0 (sliding the bar to the far left)."
242 ]
241 ]
243 },
242 },
244 {
243 {
245 "cell_type": "code",
244 "cell_type": "code",
246 "collapsed": false,
245 "collapsed": false,
247 "input": [
246 "input": [
248 "mywidget.value"
247 "mywidget.value"
249 ],
248 ],
250 "language": "python",
249 "language": "python",
251 "metadata": {},
250 "metadata": {},
252 "outputs": [
251 "outputs": [
253 {
252 {
254 "metadata": {},
253 "metadata": {},
255 "output_type": "pyout",
254 "output_type": "pyout",
256 "prompt_number": 8,
255 "prompt_number": 8,
257 "text": [
256 "text": [
258 "25.0"
257 "25.0"
259 ]
258 ]
260 }
259 }
261 ],
260 ],
262 "prompt_number": 8
261 "prompt_number": 8
263 },
262 },
264 {
263 {
265 "cell_type": "markdown",
264 "cell_type": "markdown",
266 "metadata": {},
265 "metadata": {},
267 "source": [
266 "source": [
268 "Widget values can also be set with kwargs during the construction of the widget (as seen below)."
267 "Widget values can also be set with kwargs during the construction of the widget (as seen below)."
269 ]
268 ]
270 },
269 },
271 {
270 {
272 "cell_type": "code",
271 "cell_type": "code",
273 "collapsed": false,
272 "collapsed": false,
274 "input": [
273 "input": [
275 "mysecondwidget = widgets.RadioButtonsWidget(values=[\"Item A\", \"Item B\", \"Item C\"], value=\"Item A\")\n",
274 "mysecondwidget = widgets.RadioButtonsWidget(values=[\"Item A\", \"Item B\", \"Item C\"], value=\"Item A\")\n",
276 "display(mysecondwidget)"
275 "display(mysecondwidget)"
277 ],
276 ],
278 "language": "python",
277 "language": "python",
279 "metadata": {},
278 "metadata": {},
280 "outputs": [],
279 "outputs": [],
281 "prompt_number": 9
280 "prompt_number": 9
282 },
281 },
283 {
282 {
284 "cell_type": "code",
283 "cell_type": "code",
285 "collapsed": false,
284 "collapsed": false,
286 "input": [
285 "input": [
287 "mysecondwidget.value"
286 "mysecondwidget.value"
288 ],
287 ],
289 "language": "python",
288 "language": "python",
290 "metadata": {},
289 "metadata": {},
291 "outputs": [
290 "outputs": [
292 {
291 {
293 "metadata": {},
292 "metadata": {},
294 "output_type": "pyout",
293 "output_type": "pyout",
295 "prompt_number": 10,
294 "prompt_number": 10,
296 "text": [
295 "text": [
297 "'Item A'"
296 "'Item A'"
298 ]
297 ]
299 }
298 }
300 ],
299 ],
301 "prompt_number": 10
300 "prompt_number": 10
302 },
303 {
304 "cell_type": "markdown",
305 "metadata": {},
306 "source": [
307 "In [Part 2](Part 2 - Events.ipynb) of this [series](index.ipynb), you will learn about widget events."
308 ]
309 }
301 }
310 ],
302 ],
311 "metadata": {}
303 "metadata": {}
312 }
304 }
313 ]
305 ]
314 } No newline at end of file
306 }
@@ -1,1058 +1,1049 b''
1 {
1 {
2 "metadata": {
2 "metadata": {
3 "cell_tags": [
3 "cell_tags": [
4 [
4 [
5 "<None>",
5 "<None>",
6 null
6 null
7 ]
7 ]
8 ],
8 ],
9 "name": ""
9 "name": ""
10 },
10 },
11 "nbformat": 3,
11 "nbformat": 3,
12 "nbformat_minor": 0,
12 "nbformat_minor": 0,
13 "worksheets": [
13 "worksheets": [
14 {
14 {
15 "cells": [
15 "cells": [
16 {
16 {
17 "cell_type": "markdown",
17 "cell_type": "markdown",
18 "metadata": {},
18 "metadata": {},
19 "source": [
19 "source": [
20 "[< Back to Part 5](Part 5 - Alignment.ipynb) or [Index](index.ipynb)\n",
21 "\n",
22 "Before reading, make sure to review\n",
20 "Before reading, make sure to review\n",
23 "\n",
21 "\n",
24 "- [MVC prgramming](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller)\n",
22 "- [MVC prgramming](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller)\n",
25 "- [Backbone.js](https://www.codeschool.com/courses/anatomy-of-backbonejs)\n",
23 "- [Backbone.js](https://www.codeschool.com/courses/anatomy-of-backbonejs)\n",
26 "- [The widget IPEP](https://github.com/ipython/ipython/wiki/IPEP-23%3A-Backbone.js-Widgets)\n",
24 "- [The widget IPEP](https://github.com/ipython/ipython/wiki/IPEP-23%3A-Backbone.js-Widgets)\n",
27 "- [The original widget PR discussion](https://github.com/ipython/ipython/pull/4374)"
25 "- [The original widget PR discussion](https://github.com/ipython/ipython/pull/4374)"
28 ]
26 ]
29 },
27 },
30 {
28 {
31 "cell_type": "code",
29 "cell_type": "code",
32 "collapsed": false,
30 "collapsed": false,
33 "input": [
31 "input": [
34 "from __future__ import print_function # For py 2.7 compat\n",
32 "from __future__ import print_function # For py 2.7 compat\n",
35 "\n",
33 "\n",
36 "from IPython.html import widgets # Widget definitions\n",
34 "from IPython.html import widgets # Widget definitions\n",
37 "from IPython.display import display # Used to display widgets in the notebook\n",
35 "from IPython.display import display # Used to display widgets in the notebook\n",
38 "from IPython.utils.traitlets import Unicode # Used to declare attributes of our widget"
36 "from IPython.utils.traitlets import Unicode # Used to declare attributes of our widget"
39 ],
37 ],
40 "language": "python",
38 "language": "python",
41 "metadata": {},
39 "metadata": {},
42 "outputs": [],
40 "outputs": [],
43 "prompt_number": 1
41 "prompt_number": 1
44 },
42 },
45 {
43 {
46 "cell_type": "heading",
44 "cell_type": "heading",
47 "level": 1,
45 "level": 1,
48 "metadata": {},
46 "metadata": {},
49 "source": [
47 "source": [
50 "Abstract"
48 "Abstract"
51 ]
49 ]
52 },
50 },
53 {
51 {
54 "cell_type": "markdown",
52 "cell_type": "markdown",
55 "metadata": {},
53 "metadata": {},
56 "source": [
54 "source": [
57 "This notebook implements a custom date picker widget,\n",
55 "This notebook implements a custom date picker widget,\n",
58 "in order to demonstrate the widget creation process.\n",
56 "in order to demonstrate the widget creation process.\n",
59 "\n",
57 "\n",
60 "To create a custom widget, both Python and JavaScript code is required."
58 "To create a custom widget, both Python and JavaScript code is required."
61 ]
59 ]
62 },
60 },
63 {
61 {
64 "cell_type": "heading",
62 "cell_type": "heading",
65 "level": 1,
63 "level": 1,
66 "metadata": {},
64 "metadata": {},
67 "source": [
65 "source": [
68 "Section 1 - Basics"
66 "Section 1 - Basics"
69 ]
67 ]
70 },
68 },
71 {
69 {
72 "cell_type": "heading",
70 "cell_type": "heading",
73 "level": 2,
71 "level": 2,
74 "metadata": {},
72 "metadata": {},
75 "source": [
73 "source": [
76 "Python"
74 "Python"
77 ]
75 ]
78 },
76 },
79 {
77 {
80 "cell_type": "markdown",
78 "cell_type": "markdown",
81 "metadata": {},
79 "metadata": {},
82 "source": [
80 "source": [
83 "When starting a project like this, it is often easiest to make a simple base implementation,\n",
81 "When starting a project like this, it is often easiest to make a simple base implementation,\n",
84 "to verify that the underlying framework is working as expected.\n",
82 "to verify that the underlying framework is working as expected.\n",
85 "To start, we will create an empty widget and make sure that it can be rendered.\n",
83 "To start, we will create an empty widget and make sure that it can be rendered.\n",
86 "The first step is to define the widget in Python."
84 "The first step is to define the widget in Python."
87 ]
85 ]
88 },
86 },
89 {
87 {
90 "cell_type": "code",
88 "cell_type": "code",
91 "collapsed": false,
89 "collapsed": false,
92 "input": [
90 "input": [
93 "class DateWidget(widgets.DOMWidget):\n",
91 "class DateWidget(widgets.DOMWidget):\n",
94 " _view_name = Unicode('DatePickerView', sync=True)"
92 " _view_name = Unicode('DatePickerView', sync=True)"
95 ],
93 ],
96 "language": "python",
94 "language": "python",
97 "metadata": {},
95 "metadata": {},
98 "outputs": [],
96 "outputs": [],
99 "prompt_number": 2
97 "prompt_number": 2
100 },
98 },
101 {
99 {
102 "cell_type": "markdown",
100 "cell_type": "markdown",
103 "metadata": {},
101 "metadata": {},
104 "source": [
102 "source": [
105 "Our widget inherits from `widgets.DOMWidget` since it is intended that it will be displayed in the notebook directly.\n",
103 "Our widget inherits from `widgets.DOMWidget` since it is intended that it will be displayed in the notebook directly.\n",
106 "The `_view_name` trait is special; the widget framework will read the `_view_name` trait to determine what Backbone view the widget is associated with.\n",
104 "The `_view_name` trait is special; the widget framework will read the `_view_name` trait to determine what Backbone view the widget is associated with.\n",
107 "**Using `sync=True` is very important** because it tells the widget framework that that specific traitlet should be synced between the front- and back-ends."
105 "**Using `sync=True` is very important** because it tells the widget framework that that specific traitlet should be synced between the front- and back-ends."
108 ]
106 ]
109 },
107 },
110 {
108 {
111 "cell_type": "heading",
109 "cell_type": "heading",
112 "level": 2,
110 "level": 2,
113 "metadata": {},
111 "metadata": {},
114 "source": [
112 "source": [
115 "JavaScript"
113 "JavaScript"
116 ]
114 ]
117 },
115 },
118 {
116 {
119 "cell_type": "markdown",
117 "cell_type": "markdown",
120 "metadata": {},
118 "metadata": {},
121 "source": [
119 "source": [
122 "In the IPython notebook [require.js](http://requirejs.org/) is used to load JavaScript dependencies.\n",
120 "In the IPython notebook [require.js](http://requirejs.org/) is used to load JavaScript dependencies.\n",
123 "All IPython widget code depends on `widgets/js/widget.js`,\n",
121 "All IPython widget code depends on `widgets/js/widget.js`,\n",
124 "where the base widget model and base view are defined.\n",
122 "where the base widget model and base view are defined.\n",
125 "We use require.js to load this file:"
123 "We use require.js to load this file:"
126 ]
124 ]
127 },
125 },
128 {
126 {
129 "cell_type": "code",
127 "cell_type": "code",
130 "collapsed": false,
128 "collapsed": false,
131 "input": [
129 "input": [
132 "%%javascript\n",
130 "%%javascript\n",
133 "\n",
131 "\n",
134 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
132 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
135 "\n",
133 "\n",
136 "});"
134 "});"
137 ],
135 ],
138 "language": "python",
136 "language": "python",
139 "metadata": {},
137 "metadata": {},
140 "outputs": [
138 "outputs": [
141 {
139 {
142 "javascript": [
140 "javascript": [
143 "\n",
141 "\n",
144 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
142 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
145 "\n",
143 "\n",
146 "});"
144 "});"
147 ],
145 ],
148 "metadata": {},
146 "metadata": {},
149 "output_type": "display_data",
147 "output_type": "display_data",
150 "text": [
148 "text": [
151 "<IPython.core.display.Javascript at 0x109491690>"
149 "<IPython.core.display.Javascript at 0x109491690>"
152 ]
150 ]
153 }
151 }
154 ],
152 ],
155 "prompt_number": 3
153 "prompt_number": 3
156 },
154 },
157 {
155 {
158 "cell_type": "markdown",
156 "cell_type": "markdown",
159 "metadata": {},
157 "metadata": {},
160 "source": [
158 "source": [
161 "Now we need to define a view that can be used to represent the model.\n",
159 "Now we need to define a view that can be used to represent the model.\n",
162 "To do this, the `IPython.DOMWidgetView` is extended.\n",
160 "To do this, the `IPython.DOMWidgetView` is extended.\n",
163 "**A render function must be defined**.\n",
161 "**A render function must be defined**.\n",
164 "The render function is used to render a widget view instance to the DOM.\n",
162 "The render function is used to render a widget view instance to the DOM.\n",
165 "For now, the render function renders a div that contains the text *Hello World!*\n",
163 "For now, the render function renders a div that contains the text *Hello World!*\n",
166 "Lastly, the view needs to be registered with the widget manager.\n",
164 "Lastly, the view needs to be registered with the widget manager.\n",
167 "\n",
165 "\n",
168 "**Final JavaScript code below:**"
166 "**Final JavaScript code below:**"
169 ]
167 ]
170 },
168 },
171 {
169 {
172 "cell_type": "code",
170 "cell_type": "code",
173 "collapsed": false,
171 "collapsed": false,
174 "input": [
172 "input": [
175 "%%javascript\n",
173 "%%javascript\n",
176 "\n",
174 "\n",
177 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
175 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
178 " \n",
176 " \n",
179 " // Define the DatePickerView\n",
177 " // Define the DatePickerView\n",
180 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
178 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
181 " render: function(){ this.$el.text('Hello World!'); },\n",
179 " render: function(){ this.$el.text('Hello World!'); },\n",
182 " });\n",
180 " });\n",
183 " \n",
181 " \n",
184 " // Register the DatePickerView with the widget manager.\n",
182 " // Register the DatePickerView with the widget manager.\n",
185 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
183 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
186 "});"
184 "});"
187 ],
185 ],
188 "language": "python",
186 "language": "python",
189 "metadata": {},
187 "metadata": {},
190 "outputs": [
188 "outputs": [
191 {
189 {
192 "javascript": [
190 "javascript": [
193 "\n",
191 "\n",
194 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
192 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
195 " \n",
193 " \n",
196 " // Define the DatePickerView\n",
194 " // Define the DatePickerView\n",
197 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
195 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
198 " render: function(){ this.$el.text('Hello World!'); },\n",
196 " render: function(){ this.$el.text('Hello World!'); },\n",
199 " });\n",
197 " });\n",
200 " \n",
198 " \n",
201 " // Register the DatePickerView with the widget manager.\n",
199 " // Register the DatePickerView with the widget manager.\n",
202 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
200 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
203 "});"
201 "});"
204 ],
202 ],
205 "metadata": {},
203 "metadata": {},
206 "output_type": "display_data",
204 "output_type": "display_data",
207 "text": [
205 "text": [
208 "<IPython.core.display.Javascript at 0x1094917d0>"
206 "<IPython.core.display.Javascript at 0x1094917d0>"
209 ]
207 ]
210 }
208 }
211 ],
209 ],
212 "prompt_number": 4
210 "prompt_number": 4
213 },
211 },
214 {
212 {
215 "cell_type": "heading",
213 "cell_type": "heading",
216 "level": 2,
214 "level": 2,
217 "metadata": {},
215 "metadata": {},
218 "source": [
216 "source": [
219 "Test"
217 "Test"
220 ]
218 ]
221 },
219 },
222 {
220 {
223 "cell_type": "markdown",
221 "cell_type": "markdown",
224 "metadata": {},
222 "metadata": {},
225 "source": [
223 "source": [
226 "To test what we have so far, create the widget, just like you would the builtin widgets:"
224 "To test what we have so far, create the widget, just like you would the builtin widgets:"
227 ]
225 ]
228 },
226 },
229 {
227 {
230 "cell_type": "code",
228 "cell_type": "code",
231 "collapsed": false,
229 "collapsed": false,
232 "input": [
230 "input": [
233 "DateWidget()"
231 "DateWidget()"
234 ],
232 ],
235 "language": "python",
233 "language": "python",
236 "metadata": {},
234 "metadata": {},
237 "outputs": [],
235 "outputs": [],
238 "prompt_number": 5
236 "prompt_number": 5
239 },
237 },
240 {
238 {
241 "cell_type": "heading",
239 "cell_type": "heading",
242 "level": 1,
240 "level": 1,
243 "metadata": {},
241 "metadata": {},
244 "source": [
242 "source": [
245 "Section 2 - Something useful"
243 "Section 2 - Something useful"
246 ]
244 ]
247 },
245 },
248 {
246 {
249 "cell_type": "heading",
247 "cell_type": "heading",
250 "level": 2,
248 "level": 2,
251 "metadata": {},
249 "metadata": {},
252 "source": [
250 "source": [
253 "Python"
251 "Python"
254 ]
252 ]
255 },
253 },
256 {
254 {
257 "cell_type": "markdown",
255 "cell_type": "markdown",
258 "metadata": {},
256 "metadata": {},
259 "source": [
257 "source": [
260 "In the last section we created a simple widget that displayed *Hello World!*\n",
258 "In the last section we created a simple widget that displayed *Hello World!*\n",
261 "To make an actual date widget, we need to add a property that will be synced between the Python model and the JavaScript model.\n",
259 "To make an actual date widget, we need to add a property that will be synced between the Python model and the JavaScript model.\n",
262 "The new attribute must be a traitlet, so the widget machinery can handle it.\n",
260 "The new attribute must be a traitlet, so the widget machinery can handle it.\n",
263 "The traitlet must be constructed with a `sync=True` keyword argument, to tell the widget machinery knows to synchronize it with the front-end.\n",
261 "The traitlet must be constructed with a `sync=True` keyword argument, to tell the widget machinery knows to synchronize it with the front-end.\n",
264 "Adding this to the code from the last section:"
262 "Adding this to the code from the last section:"
265 ]
263 ]
266 },
264 },
267 {
265 {
268 "cell_type": "code",
266 "cell_type": "code",
269 "collapsed": false,
267 "collapsed": false,
270 "input": [
268 "input": [
271 "class DateWidget(widgets.DOMWidget):\n",
269 "class DateWidget(widgets.DOMWidget):\n",
272 " _view_name = Unicode('DatePickerView', sync=True)\n",
270 " _view_name = Unicode('DatePickerView', sync=True)\n",
273 " value = Unicode(sync=True)"
271 " value = Unicode(sync=True)"
274 ],
272 ],
275 "language": "python",
273 "language": "python",
276 "metadata": {},
274 "metadata": {},
277 "outputs": [],
275 "outputs": [],
278 "prompt_number": 6
276 "prompt_number": 6
279 },
277 },
280 {
278 {
281 "cell_type": "heading",
279 "cell_type": "heading",
282 "level": 2,
280 "level": 2,
283 "metadata": {},
281 "metadata": {},
284 "source": [
282 "source": [
285 "JavaScript"
283 "JavaScript"
286 ]
284 ]
287 },
285 },
288 {
286 {
289 "cell_type": "markdown",
287 "cell_type": "markdown",
290 "metadata": {},
288 "metadata": {},
291 "source": [
289 "source": [
292 "In the JavaScript, there is no need to define counterparts to the traitlets.\n",
290 "In the JavaScript, there is no need to define counterparts to the traitlets.\n",
293 "When the JavaScript model is created for the first time,\n",
291 "When the JavaScript model is created for the first time,\n",
294 "it copies all of the traitlet `sync=True` attributes from the Python model.\n",
292 "it copies all of the traitlet `sync=True` attributes from the Python model.\n",
295 "We need to replace *Hello World!* with an actual HTML date picker widget."
293 "We need to replace *Hello World!* with an actual HTML date picker widget."
296 ]
294 ]
297 },
295 },
298 {
296 {
299 "cell_type": "code",
297 "cell_type": "code",
300 "collapsed": false,
298 "collapsed": false,
301 "input": [
299 "input": [
302 "%%javascript\n",
300 "%%javascript\n",
303 "\n",
301 "\n",
304 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
302 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
305 " \n",
303 " \n",
306 " // Define the DatePickerView\n",
304 " // Define the DatePickerView\n",
307 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
305 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
308 " render: function(){\n",
306 " render: function(){\n",
309 " \n",
307 " \n",
310 " // Create the date picker control.\n",
308 " // Create the date picker control.\n",
311 " this.$date = $('<input />')\n",
309 " this.$date = $('<input />')\n",
312 " .attr('type', 'date')\n",
310 " .attr('type', 'date')\n",
313 " .appendTo(this.$el);\n",
311 " .appendTo(this.$el);\n",
314 " },\n",
312 " },\n",
315 " });\n",
313 " });\n",
316 " \n",
314 " \n",
317 " // Register the DatePickerView with the widget manager.\n",
315 " // Register the DatePickerView with the widget manager.\n",
318 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
316 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
319 "});"
317 "});"
320 ],
318 ],
321 "language": "python",
319 "language": "python",
322 "metadata": {},
320 "metadata": {},
323 "outputs": [
321 "outputs": [
324 {
322 {
325 "javascript": [
323 "javascript": [
326 "\n",
324 "\n",
327 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
325 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
328 " \n",
326 " \n",
329 " // Define the DatePickerView\n",
327 " // Define the DatePickerView\n",
330 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
328 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
331 " render: function(){\n",
329 " render: function(){\n",
332 " \n",
330 " \n",
333 " // Create the date picker control.\n",
331 " // Create the date picker control.\n",
334 " this.$date = $('<input />')\n",
332 " this.$date = $('<input />')\n",
335 " .attr('type', 'date')\n",
333 " .attr('type', 'date')\n",
336 " .appendTo(this.$el);\n",
334 " .appendTo(this.$el);\n",
337 " },\n",
335 " },\n",
338 " });\n",
336 " });\n",
339 " \n",
337 " \n",
340 " // Register the DatePickerView with the widget manager.\n",
338 " // Register the DatePickerView with the widget manager.\n",
341 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
339 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
342 "});"
340 "});"
343 ],
341 ],
344 "metadata": {},
342 "metadata": {},
345 "output_type": "display_data",
343 "output_type": "display_data",
346 "text": [
344 "text": [
347 "<IPython.core.display.Javascript at 0x109491750>"
345 "<IPython.core.display.Javascript at 0x109491750>"
348 ]
346 ]
349 }
347 }
350 ],
348 ],
351 "prompt_number": 7
349 "prompt_number": 7
352 },
350 },
353 {
351 {
354 "cell_type": "markdown",
352 "cell_type": "markdown",
355 "metadata": {},
353 "metadata": {},
356 "source": [
354 "source": [
357 "In order to get the HTML date picker to update itself with the value set in the back-end, we need to implement an `update()` method."
355 "In order to get the HTML date picker to update itself with the value set in the back-end, we need to implement an `update()` method."
358 ]
356 ]
359 },
357 },
360 {
358 {
361 "cell_type": "code",
359 "cell_type": "code",
362 "collapsed": false,
360 "collapsed": false,
363 "input": [
361 "input": [
364 "%%javascript\n",
362 "%%javascript\n",
365 "\n",
363 "\n",
366 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
364 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
367 " \n",
365 " \n",
368 " // Define the DatePickerView\n",
366 " // Define the DatePickerView\n",
369 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
367 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
370 " render: function(){\n",
368 " render: function(){\n",
371 " \n",
369 " \n",
372 " // Create the date picker control.\n",
370 " // Create the date picker control.\n",
373 " this.$date = $('<input />')\n",
371 " this.$date = $('<input />')\n",
374 " .attr('type', 'date')\n",
372 " .attr('type', 'date')\n",
375 " .appendTo(this.$el);\n",
373 " .appendTo(this.$el);\n",
376 " },\n",
374 " },\n",
377 " \n",
375 " \n",
378 " update: function() {\n",
376 " update: function() {\n",
379 " \n",
377 " \n",
380 " // Set the value of the date control and then call base.\n",
378 " // Set the value of the date control and then call base.\n",
381 " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
379 " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
382 " return DatePickerView.__super__.update.apply(this);\n",
380 " return DatePickerView.__super__.update.apply(this);\n",
383 " },\n",
381 " },\n",
384 " });\n",
382 " });\n",
385 " \n",
383 " \n",
386 " // Register the DatePickerView with the widget manager.\n",
384 " // Register the DatePickerView with the widget manager.\n",
387 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
385 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
388 "});"
386 "});"
389 ],
387 ],
390 "language": "python",
388 "language": "python",
391 "metadata": {},
389 "metadata": {},
392 "outputs": [
390 "outputs": [
393 {
391 {
394 "javascript": [
392 "javascript": [
395 "\n",
393 "\n",
396 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
394 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
397 " \n",
395 " \n",
398 " // Define the DatePickerView\n",
396 " // Define the DatePickerView\n",
399 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
397 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
400 " render: function(){\n",
398 " render: function(){\n",
401 " \n",
399 " \n",
402 " // Create the date picker control.\n",
400 " // Create the date picker control.\n",
403 " this.$date = $('<input />')\n",
401 " this.$date = $('<input />')\n",
404 " .attr('type', 'date')\n",
402 " .attr('type', 'date')\n",
405 " .appendTo(this.$el);\n",
403 " .appendTo(this.$el);\n",
406 " },\n",
404 " },\n",
407 " \n",
405 " \n",
408 " update: function() {\n",
406 " update: function() {\n",
409 " \n",
407 " \n",
410 " // Set the value of the date control and then call base.\n",
408 " // Set the value of the date control and then call base.\n",
411 " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
409 " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
412 " return DatePickerView.__super__.update.apply(this);\n",
410 " return DatePickerView.__super__.update.apply(this);\n",
413 " },\n",
411 " },\n",
414 " });\n",
412 " });\n",
415 " \n",
413 " \n",
416 " // Register the DatePickerView with the widget manager.\n",
414 " // Register the DatePickerView with the widget manager.\n",
417 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
415 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
418 "});"
416 "});"
419 ],
417 ],
420 "metadata": {},
418 "metadata": {},
421 "output_type": "display_data",
419 "output_type": "display_data",
422 "text": [
420 "text": [
423 "<IPython.core.display.Javascript at 0x109491750>"
421 "<IPython.core.display.Javascript at 0x109491750>"
424 ]
422 ]
425 }
423 }
426 ],
424 ],
427 "prompt_number": 8
425 "prompt_number": 8
428 },
426 },
429 {
427 {
430 "cell_type": "markdown",
428 "cell_type": "markdown",
431 "metadata": {},
429 "metadata": {},
432 "source": [
430 "source": [
433 "To get the changed value from the frontend to publish itself to the backend,\n",
431 "To get the changed value from the frontend to publish itself to the backend,\n",
434 "we need to listen to the change event triggered by the HTM date control and set the value in the model.\n",
432 "we need to listen to the change event triggered by the HTM date control and set the value in the model.\n",
435 "After the date change event fires and the new value is set in the model,\n",
433 "After the date change event fires and the new value is set in the model,\n",
436 "it is very important that we call `this.touch()` to let the widget machinery know which view changed the model.\n",
434 "it is very important that we call `this.touch()` to let the widget machinery know which view changed the model.\n",
437 "This is important because the widget machinery needs to know which cell to route the message callbacks to.\n",
435 "This is important because the widget machinery needs to know which cell to route the message callbacks to.\n",
438 "\n",
436 "\n",
439 "**Final JavaScript code below:**"
437 "**Final JavaScript code below:**"
440 ]
438 ]
441 },
439 },
442 {
440 {
443 "cell_type": "code",
441 "cell_type": "code",
444 "collapsed": false,
442 "collapsed": false,
445 "input": [
443 "input": [
446 "%%javascript\n",
444 "%%javascript\n",
447 "\n",
445 "\n",
448 "\n",
446 "\n",
449 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
447 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
450 " \n",
448 " \n",
451 " // Define the DatePickerView\n",
449 " // Define the DatePickerView\n",
452 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
450 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
453 " render: function(){\n",
451 " render: function(){\n",
454 " \n",
452 " \n",
455 " // Create the date picker control.\n",
453 " // Create the date picker control.\n",
456 " this.$date = $('<input />')\n",
454 " this.$date = $('<input />')\n",
457 " .attr('type', 'date')\n",
455 " .attr('type', 'date')\n",
458 " .appendTo(this.$el);\n",
456 " .appendTo(this.$el);\n",
459 " },\n",
457 " },\n",
460 " \n",
458 " \n",
461 " update: function() {\n",
459 " update: function() {\n",
462 " \n",
460 " \n",
463 " // Set the value of the date control and then call base.\n",
461 " // Set the value of the date control and then call base.\n",
464 " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
462 " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
465 " return DatePickerView.__super__.update.apply(this);\n",
463 " return DatePickerView.__super__.update.apply(this);\n",
466 " },\n",
464 " },\n",
467 " \n",
465 " \n",
468 " // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n",
466 " // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n",
469 " events: {\"change\": \"handle_date_change\"},\n",
467 " events: {\"change\": \"handle_date_change\"},\n",
470 " \n",
468 " \n",
471 " // Callback for when the date is changed.\n",
469 " // Callback for when the date is changed.\n",
472 " handle_date_change: function(event) {\n",
470 " handle_date_change: function(event) {\n",
473 " this.model.set('value', this.$date.val());\n",
471 " this.model.set('value', this.$date.val());\n",
474 " this.touch();\n",
472 " this.touch();\n",
475 " },\n",
473 " },\n",
476 " });\n",
474 " });\n",
477 " \n",
475 " \n",
478 " // Register the DatePickerView with the widget manager.\n",
476 " // Register the DatePickerView with the widget manager.\n",
479 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
477 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
480 "});"
478 "});"
481 ],
479 ],
482 "language": "python",
480 "language": "python",
483 "metadata": {},
481 "metadata": {},
484 "outputs": [
482 "outputs": [
485 {
483 {
486 "javascript": [
484 "javascript": [
487 "\n",
485 "\n",
488 "\n",
486 "\n",
489 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
487 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
490 " \n",
488 " \n",
491 " // Define the DatePickerView\n",
489 " // Define the DatePickerView\n",
492 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
490 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
493 " render: function(){\n",
491 " render: function(){\n",
494 " \n",
492 " \n",
495 " // Create the date picker control.\n",
493 " // Create the date picker control.\n",
496 " this.$date = $('<input />')\n",
494 " this.$date = $('<input />')\n",
497 " .attr('type', 'date')\n",
495 " .attr('type', 'date')\n",
498 " .appendTo(this.$el);\n",
496 " .appendTo(this.$el);\n",
499 " },\n",
497 " },\n",
500 " \n",
498 " \n",
501 " update: function() {\n",
499 " update: function() {\n",
502 " \n",
500 " \n",
503 " // Set the value of the date control and then call base.\n",
501 " // Set the value of the date control and then call base.\n",
504 " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
502 " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
505 " return DatePickerView.__super__.update.apply(this);\n",
503 " return DatePickerView.__super__.update.apply(this);\n",
506 " },\n",
504 " },\n",
507 " \n",
505 " \n",
508 " // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n",
506 " // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n",
509 " events: {\"change\": \"handle_date_change\"},\n",
507 " events: {\"change\": \"handle_date_change\"},\n",
510 " \n",
508 " \n",
511 " // Callback for when the date is changed.\n",
509 " // Callback for when the date is changed.\n",
512 " handle_date_change: function(event) {\n",
510 " handle_date_change: function(event) {\n",
513 " this.model.set('value', this.$date.val());\n",
511 " this.model.set('value', this.$date.val());\n",
514 " this.touch();\n",
512 " this.touch();\n",
515 " },\n",
513 " },\n",
516 " });\n",
514 " });\n",
517 " \n",
515 " \n",
518 " // Register the DatePickerView with the widget manager.\n",
516 " // Register the DatePickerView with the widget manager.\n",
519 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
517 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
520 "});"
518 "});"
521 ],
519 ],
522 "metadata": {},
520 "metadata": {},
523 "output_type": "display_data",
521 "output_type": "display_data",
524 "text": [
522 "text": [
525 "<IPython.core.display.Javascript at 0x109491b10>"
523 "<IPython.core.display.Javascript at 0x109491b10>"
526 ]
524 ]
527 }
525 }
528 ],
526 ],
529 "prompt_number": 9
527 "prompt_number": 9
530 },
528 },
531 {
529 {
532 "cell_type": "heading",
530 "cell_type": "heading",
533 "level": 2,
531 "level": 2,
534 "metadata": {},
532 "metadata": {},
535 "source": [
533 "source": [
536 "Test"
534 "Test"
537 ]
535 ]
538 },
536 },
539 {
537 {
540 "cell_type": "markdown",
538 "cell_type": "markdown",
541 "metadata": {},
539 "metadata": {},
542 "source": [
540 "source": [
543 "To test, create the widget the same way that the other widgets are created."
541 "To test, create the widget the same way that the other widgets are created."
544 ]
542 ]
545 },
543 },
546 {
544 {
547 "cell_type": "code",
545 "cell_type": "code",
548 "collapsed": false,
546 "collapsed": false,
549 "input": [
547 "input": [
550 "my_widget = DateWidget()\n",
548 "my_widget = DateWidget()\n",
551 "display(my_widget)"
549 "display(my_widget)"
552 ],
550 ],
553 "language": "python",
551 "language": "python",
554 "metadata": {},
552 "metadata": {},
555 "outputs": [],
553 "outputs": [],
556 "prompt_number": 10
554 "prompt_number": 10
557 },
555 },
558 {
556 {
559 "cell_type": "markdown",
557 "cell_type": "markdown",
560 "metadata": {},
558 "metadata": {},
561 "source": [
559 "source": [
562 "Display the widget again to make sure that both views remain in sync."
560 "Display the widget again to make sure that both views remain in sync."
563 ]
561 ]
564 },
562 },
565 {
563 {
566 "cell_type": "code",
564 "cell_type": "code",
567 "collapsed": false,
565 "collapsed": false,
568 "input": [
566 "input": [
569 "my_widget"
567 "my_widget"
570 ],
568 ],
571 "language": "python",
569 "language": "python",
572 "metadata": {},
570 "metadata": {},
573 "outputs": [],
571 "outputs": [],
574 "prompt_number": 11
572 "prompt_number": 11
575 },
573 },
576 {
574 {
577 "cell_type": "markdown",
575 "cell_type": "markdown",
578 "metadata": {},
576 "metadata": {},
579 "source": [
577 "source": [
580 "Read the date from Python"
578 "Read the date from Python"
581 ]
579 ]
582 },
580 },
583 {
581 {
584 "cell_type": "code",
582 "cell_type": "code",
585 "collapsed": false,
583 "collapsed": false,
586 "input": [
584 "input": [
587 "my_widget.value"
585 "my_widget.value"
588 ],
586 ],
589 "language": "python",
587 "language": "python",
590 "metadata": {},
588 "metadata": {},
591 "outputs": [
589 "outputs": [
592 {
590 {
593 "metadata": {},
591 "metadata": {},
594 "output_type": "pyout",
592 "output_type": "pyout",
595 "prompt_number": 12,
593 "prompt_number": 12,
596 "text": [
594 "text": [
597 "u''"
595 "u''"
598 ]
596 ]
599 }
597 }
600 ],
598 ],
601 "prompt_number": 12
599 "prompt_number": 12
602 },
600 },
603 {
601 {
604 "cell_type": "markdown",
602 "cell_type": "markdown",
605 "metadata": {},
603 "metadata": {},
606 "source": [
604 "source": [
607 "Set the date from Python"
605 "Set the date from Python"
608 ]
606 ]
609 },
607 },
610 {
608 {
611 "cell_type": "code",
609 "cell_type": "code",
612 "collapsed": false,
610 "collapsed": false,
613 "input": [
611 "input": [
614 "my_widget.value = \"1998-12-01\" # December 1st, 1998"
612 "my_widget.value = \"1998-12-01\" # December 1st, 1998"
615 ],
613 ],
616 "language": "python",
614 "language": "python",
617 "metadata": {},
615 "metadata": {},
618 "outputs": [],
616 "outputs": [],
619 "prompt_number": 13
617 "prompt_number": 13
620 },
618 },
621 {
619 {
622 "cell_type": "heading",
620 "cell_type": "heading",
623 "level": 1,
621 "level": 1,
624 "metadata": {},
622 "metadata": {},
625 "source": [
623 "source": [
626 "Section 3 - Extra credit"
624 "Section 3 - Extra credit"
627 ]
625 ]
628 },
626 },
629 {
627 {
630 "cell_type": "markdown",
628 "cell_type": "markdown",
631 "metadata": {},
629 "metadata": {},
632 "source": [
630 "source": [
633 "The 3rd party `dateutil` library is required to continue. https://pypi.python.org/pypi/python-dateutil"
631 "The 3rd party `dateutil` library is required to continue. https://pypi.python.org/pypi/python-dateutil"
634 ]
632 ]
635 },
633 },
636 {
634 {
637 "cell_type": "code",
635 "cell_type": "code",
638 "collapsed": false,
636 "collapsed": false,
639 "input": [
637 "input": [
640 "# Import the dateutil library to parse date strings.\n",
638 "# Import the dateutil library to parse date strings.\n",
641 "from dateutil import parser"
639 "from dateutil import parser"
642 ],
640 ],
643 "language": "python",
641 "language": "python",
644 "metadata": {},
642 "metadata": {},
645 "outputs": [],
643 "outputs": [],
646 "prompt_number": 14
644 "prompt_number": 14
647 },
645 },
648 {
646 {
649 "cell_type": "markdown",
647 "cell_type": "markdown",
650 "metadata": {},
648 "metadata": {},
651 "source": [
649 "source": [
652 "In the last section we created a fully working date picker widget.\n",
650 "In the last section we created a fully working date picker widget.\n",
653 "Now we will add custom validation and support for labels.\n",
651 "Now we will add custom validation and support for labels.\n",
654 "So far, only the ISO date format \"YYYY-MM-DD\" is supported.\n",
652 "So far, only the ISO date format \"YYYY-MM-DD\" is supported.\n",
655 "Now, we will add support for all of the date formats recognized by the Python dateutil library."
653 "Now, we will add support for all of the date formats recognized by the Python dateutil library."
656 ]
654 ]
657 },
655 },
658 {
656 {
659 "cell_type": "heading",
657 "cell_type": "heading",
660 "level": 2,
658 "level": 2,
661 "metadata": {},
659 "metadata": {},
662 "source": [
660 "source": [
663 "Python"
661 "Python"
664 ]
662 ]
665 },
663 },
666 {
664 {
667 "cell_type": "markdown",
665 "cell_type": "markdown",
668 "metadata": {},
666 "metadata": {},
669 "source": [
667 "source": [
670 "The standard property name used for widget labels is `description`.\n",
668 "The standard property name used for widget labels is `description`.\n",
671 "In the code block below, `description` has been added to the Python widget."
669 "In the code block below, `description` has been added to the Python widget."
672 ]
670 ]
673 },
671 },
674 {
672 {
675 "cell_type": "code",
673 "cell_type": "code",
676 "collapsed": false,
674 "collapsed": false,
677 "input": [
675 "input": [
678 "class DateWidget(widgets.DOMWidget):\n",
676 "class DateWidget(widgets.DOMWidget):\n",
679 " _view_name = Unicode('DatePickerView', sync=True)\n",
677 " _view_name = Unicode('DatePickerView', sync=True)\n",
680 " value = Unicode(sync=True)\n",
678 " value = Unicode(sync=True)\n",
681 " description = Unicode(sync=True)"
679 " description = Unicode(sync=True)"
682 ],
680 ],
683 "language": "python",
681 "language": "python",
684 "metadata": {},
682 "metadata": {},
685 "outputs": [],
683 "outputs": [],
686 "prompt_number": 15
684 "prompt_number": 15
687 },
685 },
688 {
686 {
689 "cell_type": "markdown",
687 "cell_type": "markdown",
690 "metadata": {},
688 "metadata": {},
691 "source": [
689 "source": [
692 "The traitlet machinery searches the class that the trait is defined in for methods with \"`_changed`\" suffixed onto their names. Any method with the format \"`_X_changed`\" will be called when \"`X`\" is modified.\n",
690 "The traitlet machinery searches the class that the trait is defined in for methods with \"`_changed`\" suffixed onto their names. Any method with the format \"`_X_changed`\" will be called when \"`X`\" is modified.\n",
693 "We can take advantage of this to perform validation and parsing of different date string formats.\n",
691 "We can take advantage of this to perform validation and parsing of different date string formats.\n",
694 "Below, a method that listens to value has been added to the DateWidget."
692 "Below, a method that listens to value has been added to the DateWidget."
695 ]
693 ]
696 },
694 },
697 {
695 {
698 "cell_type": "code",
696 "cell_type": "code",
699 "collapsed": false,
697 "collapsed": false,
700 "input": [
698 "input": [
701 "class DateWidget(widgets.DOMWidget):\n",
699 "class DateWidget(widgets.DOMWidget):\n",
702 " _view_name = Unicode('DatePickerView', sync=True)\n",
700 " _view_name = Unicode('DatePickerView', sync=True)\n",
703 " value = Unicode(sync=True)\n",
701 " value = Unicode(sync=True)\n",
704 " description = Unicode(sync=True)\n",
702 " description = Unicode(sync=True)\n",
705 "\n",
703 "\n",
706 " # This function automatically gets called by the traitlet machinery when\n",
704 " # This function automatically gets called by the traitlet machinery when\n",
707 " # value is modified because of this function's name.\n",
705 " # value is modified because of this function's name.\n",
708 " def _value_changed(self, name, old_value, new_value):\n",
706 " def _value_changed(self, name, old_value, new_value):\n",
709 " pass"
707 " pass"
710 ],
708 ],
711 "language": "python",
709 "language": "python",
712 "metadata": {},
710 "metadata": {},
713 "outputs": [],
711 "outputs": [],
714 "prompt_number": 16
712 "prompt_number": 16
715 },
713 },
716 {
714 {
717 "cell_type": "markdown",
715 "cell_type": "markdown",
718 "metadata": {},
716 "metadata": {},
719 "source": [
717 "source": [
720 "Now the function parses the date string,\n",
718 "Now the function parses the date string,\n",
721 "and only sets the value in the correct format."
719 "and only sets the value in the correct format."
722 ]
720 ]
723 },
721 },
724 {
722 {
725 "cell_type": "code",
723 "cell_type": "code",
726 "collapsed": false,
724 "collapsed": false,
727 "input": [
725 "input": [
728 "class DateWidget(widgets.DOMWidget):\n",
726 "class DateWidget(widgets.DOMWidget):\n",
729 " _view_name = Unicode('DatePickerView', sync=True)\n",
727 " _view_name = Unicode('DatePickerView', sync=True)\n",
730 " value = Unicode(sync=True)\n",
728 " value = Unicode(sync=True)\n",
731 " description = Unicode(sync=True)\n",
729 " description = Unicode(sync=True)\n",
732 " \n",
730 " \n",
733 " # This function automatically gets called by the traitlet machinery when\n",
731 " # This function automatically gets called by the traitlet machinery when\n",
734 " # value is modified because of this function's name.\n",
732 " # value is modified because of this function's name.\n",
735 " def _value_changed(self, name, old_value, new_value):\n",
733 " def _value_changed(self, name, old_value, new_value):\n",
736 " \n",
734 " \n",
737 " # Parse the date time value.\n",
735 " # Parse the date time value.\n",
738 " try:\n",
736 " try:\n",
739 " parsed_date = parser.parse(new_value)\n",
737 " parsed_date = parser.parse(new_value)\n",
740 " parsed_date_string = parsed_date.strftime(\"%Y-%m-%d\")\n",
738 " parsed_date_string = parsed_date.strftime(\"%Y-%m-%d\")\n",
741 " except:\n",
739 " except:\n",
742 " parsed_date_string = ''\n",
740 " parsed_date_string = ''\n",
743 " \n",
741 " \n",
744 " # Set the parsed date string if the current date string is different.\n",
742 " # Set the parsed date string if the current date string is different.\n",
745 " if self.value != parsed_date_string:\n",
743 " if self.value != parsed_date_string:\n",
746 " self.value = parsed_date_string"
744 " self.value = parsed_date_string"
747 ],
745 ],
748 "language": "python",
746 "language": "python",
749 "metadata": {},
747 "metadata": {},
750 "outputs": [],
748 "outputs": [],
751 "prompt_number": 17
749 "prompt_number": 17
752 },
750 },
753 {
751 {
754 "cell_type": "markdown",
752 "cell_type": "markdown",
755 "metadata": {},
753 "metadata": {},
756 "source": [
754 "source": [
757 "Finally, a `CallbackDispatcher` is added so the user can perform custom validation.\n",
755 "Finally, a `CallbackDispatcher` is added so the user can perform custom validation.\n",
758 "If any one of the callbacks registered with the dispatcher returns False,\n",
756 "If any one of the callbacks registered with the dispatcher returns False,\n",
759 "the new date is not set.\n",
757 "the new date is not set.\n",
760 "\n",
758 "\n",
761 "**Final Python code below:**"
759 "**Final Python code below:**"
762 ]
760 ]
763 },
761 },
764 {
762 {
765 "cell_type": "code",
763 "cell_type": "code",
766 "collapsed": false,
764 "collapsed": false,
767 "input": [
765 "input": [
768 "class DateWidget(widgets.DOMWidget):\n",
766 "class DateWidget(widgets.DOMWidget):\n",
769 " _view_name = Unicode('DatePickerView', sync=True)\n",
767 " _view_name = Unicode('DatePickerView', sync=True)\n",
770 " value = Unicode(sync=True)\n",
768 " value = Unicode(sync=True)\n",
771 " description = Unicode(sync=True)\n",
769 " description = Unicode(sync=True)\n",
772 " \n",
770 " \n",
773 " def __init__(self, **kwargs):\n",
771 " def __init__(self, **kwargs):\n",
774 " super(DateWidget, self).__init__(**kwargs)\n",
772 " super(DateWidget, self).__init__(**kwargs)\n",
775 " \n",
773 " \n",
776 " self.validate = widgets.CallbackDispatcher()\n",
774 " self.validate = widgets.CallbackDispatcher()\n",
777 " \n",
775 " \n",
778 " # This function automatically gets called by the traitlet machinery when\n",
776 " # This function automatically gets called by the traitlet machinery when\n",
779 " # value is modified because of this function's name.\n",
777 " # value is modified because of this function's name.\n",
780 " def _value_changed(self, name, old_value, new_value):\n",
778 " def _value_changed(self, name, old_value, new_value):\n",
781 " \n",
779 " \n",
782 " # Parse the date time value.\n",
780 " # Parse the date time value.\n",
783 " try:\n",
781 " try:\n",
784 " parsed_date = parser.parse(new_value)\n",
782 " parsed_date = parser.parse(new_value)\n",
785 " parsed_date_string = parsed_date.strftime(\"%Y-%m-%d\")\n",
783 " parsed_date_string = parsed_date.strftime(\"%Y-%m-%d\")\n",
786 " except:\n",
784 " except:\n",
787 " parsed_date_string = ''\n",
785 " parsed_date_string = ''\n",
788 " \n",
786 " \n",
789 " # Set the parsed date string if the current date string is different.\n",
787 " # Set the parsed date string if the current date string is different.\n",
790 " if old_value != new_value:\n",
788 " if old_value != new_value:\n",
791 " valid = self.validate(parsed_date)\n",
789 " valid = self.validate(parsed_date)\n",
792 " if valid in (None, True):\n",
790 " if valid in (None, True):\n",
793 " self.value = parsed_date_string\n",
791 " self.value = parsed_date_string\n",
794 " else:\n",
792 " else:\n",
795 " self.value = old_value\n",
793 " self.value = old_value\n",
796 " self.send_state() # The traitlet event won't fire since the value isn't changing.\n",
794 " self.send_state() # The traitlet event won't fire since the value isn't changing.\n",
797 " # We need to force the back-end to send the front-end the state\n",
795 " # We need to force the back-end to send the front-end the state\n",
798 " # to make sure that the date control date doesn't change."
796 " # to make sure that the date control date doesn't change."
799 ],
797 ],
800 "language": "python",
798 "language": "python",
801 "metadata": {},
799 "metadata": {},
802 "outputs": [],
800 "outputs": [],
803 "prompt_number": 18
801 "prompt_number": 18
804 },
802 },
805 {
803 {
806 "cell_type": "heading",
804 "cell_type": "heading",
807 "level": 2,
805 "level": 2,
808 "metadata": {},
806 "metadata": {},
809 "source": [
807 "source": [
810 "JavaScript"
808 "JavaScript"
811 ]
809 ]
812 },
810 },
813 {
811 {
814 "cell_type": "markdown",
812 "cell_type": "markdown",
815 "metadata": {},
813 "metadata": {},
816 "source": [
814 "source": [
817 "Using the Javascript code from the last section,\n",
815 "Using the Javascript code from the last section,\n",
818 "we add a label to the date time object.\n",
816 "we add a label to the date time object.\n",
819 "The label is a div with the `widget-hlabel` class applied to it.\n",
817 "The label is a div with the `widget-hlabel` class applied to it.\n",
820 "`widget-hlabel` is a class provided by the widget framework that applies special styling to a div to make it look like the rest of the horizontal labels used with the built-in widgets.\n",
818 "`widget-hlabel` is a class provided by the widget framework that applies special styling to a div to make it look like the rest of the horizontal labels used with the built-in widgets.\n",
821 "Similar to the `widget-hlabel` class is the `widget-hbox-single` class.\n",
819 "Similar to the `widget-hlabel` class is the `widget-hbox-single` class.\n",
822 "The `widget-hbox-single` class applies special styling to widget containers that store a single line horizontal widget.\n",
820 "The `widget-hbox-single` class applies special styling to widget containers that store a single line horizontal widget.\n",
823 "\n",
821 "\n",
824 "We hide the label if the description value is blank."
822 "We hide the label if the description value is blank."
825 ]
823 ]
826 },
824 },
827 {
825 {
828 "cell_type": "code",
826 "cell_type": "code",
829 "collapsed": false,
827 "collapsed": false,
830 "input": [
828 "input": [
831 "%%javascript\n",
829 "%%javascript\n",
832 "\n",
830 "\n",
833 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
831 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
834 " \n",
832 " \n",
835 " // Define the DatePickerView\n",
833 " // Define the DatePickerView\n",
836 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
834 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
837 " render: function(){\n",
835 " render: function(){\n",
838 " this.$el.addClass('widget-hbox-single'); /* Apply this class to the widget container to make\n",
836 " this.$el.addClass('widget-hbox-single'); /* Apply this class to the widget container to make\n",
839 " it fit with the other built in widgets.*/\n",
837 " it fit with the other built in widgets.*/\n",
840 " // Create a label.\n",
838 " // Create a label.\n",
841 " this.$label = $('<div />')\n",
839 " this.$label = $('<div />')\n",
842 " .addClass('widget-hlabel')\n",
840 " .addClass('widget-hlabel')\n",
843 " .appendTo(this.$el)\n",
841 " .appendTo(this.$el)\n",
844 " .hide(); // Hide the label by default.\n",
842 " .hide(); // Hide the label by default.\n",
845 " \n",
843 " \n",
846 " // Create the date picker control.\n",
844 " // Create the date picker control.\n",
847 " this.$date = $('<input />')\n",
845 " this.$date = $('<input />')\n",
848 " .attr('type', 'date')\n",
846 " .attr('type', 'date')\n",
849 " .appendTo(this.$el);\n",
847 " .appendTo(this.$el);\n",
850 " },\n",
848 " },\n",
851 " \n",
849 " \n",
852 " update: function() {\n",
850 " update: function() {\n",
853 " \n",
851 " \n",
854 " // Set the value of the date control and then call base.\n",
852 " // Set the value of the date control and then call base.\n",
855 " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
853 " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
856 " \n",
854 " \n",
857 " // Hide or show the label depending on the existance of a description.\n",
855 " // Hide or show the label depending on the existance of a description.\n",
858 " var description = this.model.get('description');\n",
856 " var description = this.model.get('description');\n",
859 " if (description == undefined || description == '') {\n",
857 " if (description == undefined || description == '') {\n",
860 " this.$label.hide();\n",
858 " this.$label.hide();\n",
861 " } else {\n",
859 " } else {\n",
862 " this.$label.show();\n",
860 " this.$label.show();\n",
863 " this.$label.text(description);\n",
861 " this.$label.text(description);\n",
864 " }\n",
862 " }\n",
865 " \n",
863 " \n",
866 " return DatePickerView.__super__.update.apply(this);\n",
864 " return DatePickerView.__super__.update.apply(this);\n",
867 " },\n",
865 " },\n",
868 " \n",
866 " \n",
869 " // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n",
867 " // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n",
870 " events: {\"change\": \"handle_date_change\"},\n",
868 " events: {\"change\": \"handle_date_change\"},\n",
871 " \n",
869 " \n",
872 " // Callback for when the date is changed.\n",
870 " // Callback for when the date is changed.\n",
873 " handle_date_change: function(event) {\n",
871 " handle_date_change: function(event) {\n",
874 " this.model.set('value', this.$date.val());\n",
872 " this.model.set('value', this.$date.val());\n",
875 " this.touch();\n",
873 " this.touch();\n",
876 " },\n",
874 " },\n",
877 " });\n",
875 " });\n",
878 " \n",
876 " \n",
879 " // Register the DatePickerView with the widget manager.\n",
877 " // Register the DatePickerView with the widget manager.\n",
880 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
878 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
881 "});"
879 "});"
882 ],
880 ],
883 "language": "python",
881 "language": "python",
884 "metadata": {},
882 "metadata": {},
885 "outputs": [
883 "outputs": [
886 {
884 {
887 "javascript": [
885 "javascript": [
888 "\n",
886 "\n",
889 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
887 "require([\"widgets/js/widget\"], function(WidgetManager){\n",
890 " \n",
888 " \n",
891 " // Define the DatePickerView\n",
889 " // Define the DatePickerView\n",
892 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
890 " var DatePickerView = IPython.DOMWidgetView.extend({\n",
893 " render: function(){\n",
891 " render: function(){\n",
894 " this.$el.addClass('widget-hbox-single'); /* Apply this class to the widget container to make\n",
892 " this.$el.addClass('widget-hbox-single'); /* Apply this class to the widget container to make\n",
895 " it fit with the other built in widgets.*/\n",
893 " it fit with the other built in widgets.*/\n",
896 " // Create a label.\n",
894 " // Create a label.\n",
897 " this.$label = $('<div />')\n",
895 " this.$label = $('<div />')\n",
898 " .addClass('widget-hlabel')\n",
896 " .addClass('widget-hlabel')\n",
899 " .appendTo(this.$el)\n",
897 " .appendTo(this.$el)\n",
900 " .hide(); // Hide the label by default.\n",
898 " .hide(); // Hide the label by default.\n",
901 " \n",
899 " \n",
902 " // Create the date picker control.\n",
900 " // Create the date picker control.\n",
903 " this.$date = $('<input />')\n",
901 " this.$date = $('<input />')\n",
904 " .attr('type', 'date')\n",
902 " .attr('type', 'date')\n",
905 " .appendTo(this.$el);\n",
903 " .appendTo(this.$el);\n",
906 " },\n",
904 " },\n",
907 " \n",
905 " \n",
908 " update: function() {\n",
906 " update: function() {\n",
909 " \n",
907 " \n",
910 " // Set the value of the date control and then call base.\n",
908 " // Set the value of the date control and then call base.\n",
911 " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
909 " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
912 " \n",
910 " \n",
913 " // Hide or show the label depending on the existance of a description.\n",
911 " // Hide or show the label depending on the existance of a description.\n",
914 " var description = this.model.get('description');\n",
912 " var description = this.model.get('description');\n",
915 " if (description == undefined || description == '') {\n",
913 " if (description == undefined || description == '') {\n",
916 " this.$label.hide();\n",
914 " this.$label.hide();\n",
917 " } else {\n",
915 " } else {\n",
918 " this.$label.show();\n",
916 " this.$label.show();\n",
919 " this.$label.text(description);\n",
917 " this.$label.text(description);\n",
920 " }\n",
918 " }\n",
921 " \n",
919 " \n",
922 " return DatePickerView.__super__.update.apply(this);\n",
920 " return DatePickerView.__super__.update.apply(this);\n",
923 " },\n",
921 " },\n",
924 " \n",
922 " \n",
925 " // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n",
923 " // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n",
926 " events: {\"change\": \"handle_date_change\"},\n",
924 " events: {\"change\": \"handle_date_change\"},\n",
927 " \n",
925 " \n",
928 " // Callback for when the date is changed.\n",
926 " // Callback for when the date is changed.\n",
929 " handle_date_change: function(event) {\n",
927 " handle_date_change: function(event) {\n",
930 " this.model.set('value', this.$date.val());\n",
928 " this.model.set('value', this.$date.val());\n",
931 " this.touch();\n",
929 " this.touch();\n",
932 " },\n",
930 " },\n",
933 " });\n",
931 " });\n",
934 " \n",
932 " \n",
935 " // Register the DatePickerView with the widget manager.\n",
933 " // Register the DatePickerView with the widget manager.\n",
936 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
934 " WidgetManager.register_widget_view('DatePickerView', DatePickerView);\n",
937 "});"
935 "});"
938 ],
936 ],
939 "metadata": {},
937 "metadata": {},
940 "output_type": "display_data",
938 "output_type": "display_data",
941 "text": [
939 "text": [
942 "<IPython.core.display.Javascript at 0x1094eef90>"
940 "<IPython.core.display.Javascript at 0x1094eef90>"
943 ]
941 ]
944 }
942 }
945 ],
943 ],
946 "prompt_number": 19
944 "prompt_number": 19
947 },
945 },
948 {
946 {
949 "cell_type": "heading",
947 "cell_type": "heading",
950 "level": 2,
948 "level": 2,
951 "metadata": {},
949 "metadata": {},
952 "source": [
950 "source": [
953 "Test"
951 "Test"
954 ]
952 ]
955 },
953 },
956 {
954 {
957 "cell_type": "markdown",
955 "cell_type": "markdown",
958 "metadata": {},
956 "metadata": {},
959 "source": [
957 "source": [
960 "To test the drawing of the label we create the widget like normal but supply the additional description property a value."
958 "To test the drawing of the label we create the widget like normal but supply the additional description property a value."
961 ]
959 ]
962 },
960 },
963 {
961 {
964 "cell_type": "code",
962 "cell_type": "code",
965 "collapsed": false,
963 "collapsed": false,
966 "input": [
964 "input": [
967 "# Add some additional widgets for aesthetic purpose\n",
965 "# Add some additional widgets for aesthetic purpose\n",
968 "display(widgets.TextWidget(description=\"First:\"))\n",
966 "display(widgets.TextWidget(description=\"First:\"))\n",
969 "display(widgets.TextWidget(description=\"Last:\"))\n",
967 "display(widgets.TextWidget(description=\"Last:\"))\n",
970 "\n",
968 "\n",
971 "my_widget = DateWidget()\n",
969 "my_widget = DateWidget()\n",
972 "display(my_widget)\n",
970 "display(my_widget)\n",
973 "my_widget.description=\"DOB:\""
971 "my_widget.description=\"DOB:\""
974 ],
972 ],
975 "language": "python",
973 "language": "python",
976 "metadata": {},
974 "metadata": {},
977 "outputs": [],
975 "outputs": [],
978 "prompt_number": 20
976 "prompt_number": 20
979 },
977 },
980 {
978 {
981 "cell_type": "markdown",
979 "cell_type": "markdown",
982 "metadata": {},
980 "metadata": {},
983 "source": [
981 "source": [
984 "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."
982 "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."
985 ]
983 ]
986 },
984 },
987 {
985 {
988 "cell_type": "code",
986 "cell_type": "code",
989 "collapsed": false,
987 "collapsed": false,
990 "input": [
988 "input": [
991 "my_widget = DateWidget()\n",
989 "my_widget = DateWidget()\n",
992 "display(my_widget)\n",
990 "display(my_widget)\n",
993 "\n",
991 "\n",
994 "def require_2014(date):\n",
992 "def require_2014(date):\n",
995 " return not date is None and date.year == 2014\n",
993 " return not date is None and date.year == 2014\n",
996 "my_widget.validate.register_callback(require_2014)"
994 "my_widget.validate.register_callback(require_2014)"
997 ],
995 ],
998 "language": "python",
996 "language": "python",
999 "metadata": {},
997 "metadata": {},
1000 "outputs": [],
998 "outputs": [],
1001 "prompt_number": 21
999 "prompt_number": 21
1002 },
1000 },
1003 {
1001 {
1004 "cell_type": "code",
1002 "cell_type": "code",
1005 "collapsed": false,
1003 "collapsed": false,
1006 "input": [
1004 "input": [
1007 "# Try setting a valid date\n",
1005 "# Try setting a valid date\n",
1008 "my_widget.value = \"December 2, 2014\""
1006 "my_widget.value = \"December 2, 2014\""
1009 ],
1007 ],
1010 "language": "python",
1008 "language": "python",
1011 "metadata": {},
1009 "metadata": {},
1012 "outputs": [],
1010 "outputs": [],
1013 "prompt_number": 22
1011 "prompt_number": 22
1014 },
1012 },
1015 {
1013 {
1016 "cell_type": "code",
1014 "cell_type": "code",
1017 "collapsed": false,
1015 "collapsed": false,
1018 "input": [
1016 "input": [
1019 "# Try setting an invalid date\n",
1017 "# Try setting an invalid date\n",
1020 "my_widget.value = \"June 12, 1999\""
1018 "my_widget.value = \"June 12, 1999\""
1021 ],
1019 ],
1022 "language": "python",
1020 "language": "python",
1023 "metadata": {},
1021 "metadata": {},
1024 "outputs": [],
1022 "outputs": [],
1025 "prompt_number": 23
1023 "prompt_number": 23
1026 },
1024 },
1027 {
1025 {
1028 "cell_type": "code",
1026 "cell_type": "code",
1029 "collapsed": false,
1027 "collapsed": false,
1030 "input": [
1028 "input": [
1031 "my_widget.value"
1029 "my_widget.value"
1032 ],
1030 ],
1033 "language": "python",
1031 "language": "python",
1034 "metadata": {},
1032 "metadata": {},
1035 "outputs": [
1033 "outputs": [
1036 {
1034 {
1037 "metadata": {},
1035 "metadata": {},
1038 "output_type": "pyout",
1036 "output_type": "pyout",
1039 "prompt_number": 24,
1037 "prompt_number": 24,
1040 "text": [
1038 "text": [
1041 "u'2014-12-02'"
1039 "u'2014-12-02'"
1042 ]
1040 ]
1043 }
1041 }
1044 ],
1042 ],
1045 "prompt_number": 24
1043 "prompt_number": 24
1046 },
1047 {
1048 "cell_type": "markdown",
1049 "metadata": {},
1050 "source": [
1051 "This concludes Part 6 of the [series](index.ipynb)."
1052 ]
1053 }
1044 }
1054 ],
1045 ],
1055 "metadata": {}
1046 "metadata": {}
1056 }
1047 }
1057 ]
1048 ]
1058 }
1049 } No newline at end of file
@@ -1,261 +1,248 b''
1 {
1 {
2 "metadata": {
2 "metadata": {
3 "cell_tags": [
3 "cell_tags": [
4 [
4 [
5 "<None>",
5 "<None>",
6 null
6 null
7 ]
7 ]
8 ],
8 ],
9 "name": ""
9 "name": "",
10 "signature": "sha256:8cade57fabc6819dc950bc28502028554861fb1440d5d832922b95fd2b8bf25c"
10 },
11 },
11 "nbformat": 3,
12 "nbformat": 3,
12 "nbformat_minor": 0,
13 "nbformat_minor": 0,
13 "worksheets": [
14 "worksheets": [
14 {
15 {
15 "cells": [
16 "cells": [
16 {
17 {
17 "cell_type": "markdown",
18 "metadata": {},
19 "source": [
20 "[< Back to Part 1](Part 1 - Basics.ipynb) or [Index](index.ipynb)"
21 ]
22 },
23 {
24 "cell_type": "code",
18 "cell_type": "code",
25 "collapsed": false,
19 "collapsed": false,
26 "input": [
20 "input": [
27 "from __future__ import print_function # 2.7 compatability\n",
21 "from __future__ import print_function # 2.7 compatability\n",
28 "\n",
22 "\n",
29 "from IPython.html import widgets # Widget definitions\n",
23 "from IPython.html import widgets # Widget definitions\n",
30 "from IPython.display import display # Used to display widgets in the notebook"
24 "from IPython.display import display # Used to display widgets in the notebook"
31 ],
25 ],
32 "language": "python",
26 "language": "python",
33 "metadata": {},
27 "metadata": {},
34 "outputs": [],
28 "outputs": [],
35 "prompt_number": 1
29 "prompt_number": 1
36 },
30 },
37 {
31 {
38 "cell_type": "heading",
32 "cell_type": "heading",
39 "level": 1,
33 "level": 1,
40 "metadata": {},
34 "metadata": {},
41 "source": [
35 "source": [
42 "Traitlet Events"
36 "Traitlet Events"
43 ]
37 ]
44 },
38 },
45 {
39 {
46 "cell_type": "markdown",
40 "cell_type": "markdown",
47 "metadata": {},
41 "metadata": {},
48 "source": [
42 "source": [
49 "As mentioned in Part 1, the widget attributes are IPython traitlets. Traitlets are eventful. To handle changes, the `on_trait_change` method of the widget can be used to register a callback. The docstring for `on_trait_change` can be seen below. Both the `name` and `remove` properties are optional."
43 "As mentioned in Part 1, the widget attributes are IPython traitlets. Traitlets are eventful. To handle changes, the `on_trait_change` method of the widget can be used to register a callback. The docstring for `on_trait_change` can be seen below. Both the `name` and `remove` properties are optional."
50 ]
44 ]
51 },
45 },
52 {
46 {
53 "cell_type": "code",
47 "cell_type": "code",
54 "collapsed": false,
48 "collapsed": false,
55 "input": [
49 "input": [
56 "print(widgets.Widget.on_trait_change.__doc__)"
50 "print(widgets.Widget.on_trait_change.__doc__)"
57 ],
51 ],
58 "language": "python",
52 "language": "python",
59 "metadata": {},
53 "metadata": {},
60 "outputs": [
54 "outputs": [
61 {
55 {
62 "output_type": "stream",
56 "output_type": "stream",
63 "stream": "stdout",
57 "stream": "stdout",
64 "text": [
58 "text": [
65 "Setup a handler to be called when a trait changes.\n",
59 "Setup a handler to be called when a trait changes.\n",
66 "\n",
60 "\n",
67 " This is used to setup dynamic notifications of trait changes.\n",
61 " This is used to setup dynamic notifications of trait changes.\n",
68 "\n",
62 "\n",
69 " Static handlers can be created by creating methods on a HasTraits\n",
63 " Static handlers can be created by creating methods on a HasTraits\n",
70 " subclass with the naming convention '_[traitname]_changed'. Thus,\n",
64 " subclass with the naming convention '_[traitname]_changed'. Thus,\n",
71 " to create static handler for the trait 'a', create the method\n",
65 " to create static handler for the trait 'a', create the method\n",
72 " _a_changed(self, name, old, new) (fewer arguments can be used, see\n",
66 " _a_changed(self, name, old, new) (fewer arguments can be used, see\n",
73 " below).\n",
67 " below).\n",
74 "\n",
68 "\n",
75 " Parameters\n",
69 " Parameters\n",
76 " ----------\n",
70 " ----------\n",
77 " handler : callable\n",
71 " handler : callable\n",
78 " A callable that is called when a trait changes. Its\n",
72 " A callable that is called when a trait changes. Its\n",
79 " signature can be handler(), handler(name), handler(name, new)\n",
73 " signature can be handler(), handler(name), handler(name, new)\n",
80 " or handler(name, old, new).\n",
74 " or handler(name, old, new).\n",
81 " name : list, str, None\n",
75 " name : list, str, None\n",
82 " If None, the handler will apply to all traits. If a list\n",
76 " If None, the handler will apply to all traits. If a list\n",
83 " of str, handler will apply to all names in the list. If a\n",
77 " of str, handler will apply to all names in the list. If a\n",
84 " str, the handler will apply just to that name.\n",
78 " str, the handler will apply just to that name.\n",
85 " remove : bool\n",
79 " remove : bool\n",
86 " If False (the default), then install the handler. If True\n",
80 " If False (the default), then install the handler. If True\n",
87 " then unintall it.\n",
81 " then unintall it.\n",
88 " \n"
82 " \n"
89 ]
83 ]
90 }
84 }
91 ],
85 ],
92 "prompt_number": 2
86 "prompt_number": 2
93 },
87 },
94 {
88 {
95 "cell_type": "markdown",
89 "cell_type": "markdown",
96 "metadata": {},
90 "metadata": {},
97 "source": [
91 "source": [
98 "Mentioned in the doc string, the callback registered can have 4 possible signatures:\n",
92 "Mentioned in the doc string, the callback registered can have 4 possible signatures:\n",
99 "\n",
93 "\n",
100 "- callback()\n",
94 "- callback()\n",
101 "- callback(trait_name)\n",
95 "- callback(trait_name)\n",
102 "- callback(trait_name, new_value)\n",
96 "- callback(trait_name, new_value)\n",
103 "- callback(trait_name, old_value, new_value)\n",
97 "- callback(trait_name, old_value, new_value)\n",
104 "\n",
98 "\n",
105 "Using this method, an example of how to output an IntSliderWiget's value as it is changed can be seen below."
99 "Using this method, an example of how to output an IntSliderWiget's value as it is changed can be seen below."
106 ]
100 ]
107 },
101 },
108 {
102 {
109 "cell_type": "code",
103 "cell_type": "code",
110 "collapsed": false,
104 "collapsed": false,
111 "input": [
105 "input": [
112 "int_range = widgets.IntSliderWidget()\n",
106 "int_range = widgets.IntSliderWidget()\n",
113 "display(int_range)\n",
107 "display(int_range)\n",
114 "\n",
108 "\n",
115 "def on_value_change(name, value):\n",
109 "def on_value_change(name, value):\n",
116 " print(value)\n",
110 " print(value)\n",
117 "\n",
111 "\n",
118 "int_range.on_trait_change(on_value_change, 'value')"
112 "int_range.on_trait_change(on_value_change, 'value')"
119 ],
113 ],
120 "language": "python",
114 "language": "python",
121 "metadata": {},
115 "metadata": {},
122 "outputs": [],
116 "outputs": [],
123 "prompt_number": 3
117 "prompt_number": 3
124 },
118 },
125 {
119 {
126 "cell_type": "heading",
120 "cell_type": "heading",
127 "level": 1,
121 "level": 1,
128 "metadata": {},
122 "metadata": {},
129 "source": [
123 "source": [
130 "Specialized Events"
124 "Specialized Events"
131 ]
125 ]
132 },
126 },
133 {
127 {
134 "cell_type": "heading",
128 "cell_type": "heading",
135 "level": 2,
129 "level": 2,
136 "metadata": {},
130 "metadata": {},
137 "source": [
131 "source": [
138 "Button Click Event"
132 "Button Click Event"
139 ]
133 ]
140 },
134 },
141 {
135 {
142 "cell_type": "markdown",
136 "cell_type": "markdown",
143 "metadata": {},
137 "metadata": {},
144 "source": [
138 "source": [
145 "The `ButtonWidget` is a special widget, like the `ContainerWidget` and `TabWidget`, that isn't used to represent a data type. Instead the button widget is used to handle mouse clicks. The `on_click` method of the `ButtonWidget` can be used to register function to be called when the button is clicked. The docstring of the `on_click` can be seen below."
139 "The `ButtonWidget` is a special widget, like the `ContainerWidget` and `TabWidget`, that isn't used to represent a data type. Instead the button widget is used to handle mouse clicks. The `on_click` method of the `ButtonWidget` can be used to register function to be called when the button is clicked. The docstring of the `on_click` can be seen below."
146 ]
140 ]
147 },
141 },
148 {
142 {
149 "cell_type": "code",
143 "cell_type": "code",
150 "collapsed": false,
144 "collapsed": false,
151 "input": [
145 "input": [
152 "print(widgets.ButtonWidget.on_click.__doc__)"
146 "print(widgets.ButtonWidget.on_click.__doc__)"
153 ],
147 ],
154 "language": "python",
148 "language": "python",
155 "metadata": {},
149 "metadata": {},
156 "outputs": [
150 "outputs": [
157 {
151 {
158 "output_type": "stream",
152 "output_type": "stream",
159 "stream": "stdout",
153 "stream": "stdout",
160 "text": [
154 "text": [
161 "Register a callback to execute when the button is clicked.\n",
155 "Register a callback to execute when the button is clicked.\n",
162 "\n",
156 "\n",
163 " The callback will be called with one argument,\n",
157 " The callback will be called with one argument,\n",
164 " the clicked button widget instance.\n",
158 " the clicked button widget instance.\n",
165 "\n",
159 "\n",
166 " Parameters\n",
160 " Parameters\n",
167 " ----------\n",
161 " ----------\n",
168 " remove : bool (optional)\n",
162 " remove : bool (optional)\n",
169 " Set to true to remove the callback from the list of callbacks.\n"
163 " Set to true to remove the callback from the list of callbacks.\n"
170 ]
164 ]
171 }
165 }
172 ],
166 ],
173 "prompt_number": 4
167 "prompt_number": 4
174 },
168 },
175 {
169 {
176 "cell_type": "markdown",
170 "cell_type": "markdown",
177 "metadata": {},
171 "metadata": {},
178 "source": [
172 "source": [
179 "Button clicks 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."
173 "Button clicks 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."
180 ]
174 ]
181 },
175 },
182 {
176 {
183 "cell_type": "code",
177 "cell_type": "code",
184 "collapsed": false,
178 "collapsed": false,
185 "input": [
179 "input": [
186 "button = widgets.ButtonWidget(description=\"Click Me!\")\n",
180 "button = widgets.ButtonWidget(description=\"Click Me!\")\n",
187 "display(button)\n",
181 "display(button)\n",
188 "\n",
182 "\n",
189 "def on_button_clicked(b):\n",
183 "def on_button_clicked(b):\n",
190 " print(\"Button clicked.\")\n",
184 " print(\"Button clicked.\")\n",
191 "\n",
185 "\n",
192 "button.on_click(on_button_clicked)"
186 "button.on_click(on_button_clicked)"
193 ],
187 ],
194 "language": "python",
188 "language": "python",
195 "metadata": {},
189 "metadata": {},
196 "outputs": [
190 "outputs": [
197 {
191 {
198 "output_type": "stream",
192 "output_type": "stream",
199 "stream": "stdout",
193 "stream": "stdout",
200 "text": [
194 "text": [
201 "Button clicked.\n"
195 "Button clicked.\n"
202 ]
196 ]
203 },
197 },
204 {
198 {
205 "output_type": "stream",
199 "output_type": "stream",
206 "stream": "stdout",
200 "stream": "stdout",
207 "text": [
201 "text": [
208 "Button clicked.\n"
202 "Button clicked.\n"
209 ]
203 ]
210 },
204 },
211 {
205 {
212 "output_type": "stream",
206 "output_type": "stream",
213 "stream": "stdout",
207 "stream": "stdout",
214 "text": [
208 "text": [
215 "Button clicked.\n"
209 "Button clicked.\n"
216 ]
210 ]
217 }
211 }
218 ],
212 ],
219 "prompt_number": 5
213 "prompt_number": 5
220 },
214 },
221 {
215 {
222 "cell_type": "markdown",
216 "cell_type": "markdown",
223 "metadata": {},
217 "metadata": {},
224 "source": [
218 "source": [
225 "Event handlers can also be used to create widgets. In the example below, clicking a button spawns another button with a description equal to how many times the parent button had been clicked at the time."
219 "Event handlers can also be used to create widgets. In the example below, clicking a button spawns another button with a description equal to how many times the parent button had been clicked at the time."
226 ]
220 ]
227 },
221 },
228 {
222 {
229 "cell_type": "code",
223 "cell_type": "code",
230 "collapsed": false,
224 "collapsed": false,
231 "input": [
225 "input": [
232 "def new_button(clicked):\n",
226 "def new_button(clicked):\n",
233 " button = widgets.ButtonWidget()\n",
227 " button = widgets.ButtonWidget()\n",
234 " button.clicks = 0\n",
228 " button.clicks = 0\n",
235 " clicked.clicks += 1\n",
229 " clicked.clicks += 1\n",
236 " button.description = \"%d\" % clicked.clicks\n",
230 " button.description = \"%d\" % clicked.clicks\n",
237 " display(button)\n",
231 " display(button)\n",
238 " button.on_click(new_button)\n",
232 " button.on_click(new_button)\n",
239 "button = widgets.ButtonWidget(description = \"Start\")\n",
233 "button = widgets.ButtonWidget(description = \"Start\")\n",
240 "button.clicks = 0\n",
234 "button.clicks = 0\n",
241 "display(button)\n",
235 "display(button)\n",
242 "button.on_click(new_button)\n",
236 "button.on_click(new_button)\n",
243 " "
237 " "
244 ],
238 ],
245 "language": "python",
239 "language": "python",
246 "metadata": {},
240 "metadata": {},
247 "outputs": [],
241 "outputs": [],
248 "prompt_number": 6
242 "prompt_number": 6
249 },
250 {
251 "cell_type": "markdown",
252 "metadata": {},
253 "source": [
254 "In [Part 3](Part 3 - Placement.ipynb) of this [series](index.ipynb), you will learn about widget placement."
255 ]
256 }
243 }
257 ],
244 ],
258 "metadata": {}
245 "metadata": {}
259 }
246 }
260 ]
247 ]
261 } No newline at end of file
248 }
@@ -1,73 +1,65 b''
1 {
1 {
2 "metadata": {
2 "metadata": {
3 "name": "",
3 "name": "",
4 "signature": "sha256:554c73fb7038db942bd25f77ad2217699e1f3fda6535fad67103256dc1beda0b"
4 "signature": "sha256:a2f4e040950648308ac7ec5f95d83948b4499ffc68e6bfd8f6fe8784955f52fb"
5 },
5 },
6 "nbformat": 3,
6 "nbformat": 3,
7 "nbformat_minor": 0,
7 "nbformat_minor": 0,
8 "worksheets": [
8 "worksheets": [
9 {
9 {
10 "cells": [
10 "cells": [
11 {
11 {
12 "cell_type": "heading",
12 "cell_type": "heading",
13 "level": 1,
13 "level": 1,
14 "metadata": {},
14 "metadata": {},
15 "source": [
15 "source": [
16 "Widget Tutorials"
16 "Widget Tutorials"
17 ]
17 ]
18 },
18 },
19 {
19 {
20 "cell_type": "markdown",
20 "cell_type": "markdown",
21 "metadata": {},
21 "metadata": {},
22 "source": [
22 "source": [
23 "This directory includes a tutorials related to the IPython notebook widget framework."
23 "This directory includes a tutorials related to the IPython notebook widget framework."
24 ]
24 ]
25 },
25 },
26 {
26 {
27 "cell_type": "heading",
27 "cell_type": "heading",
28 "level": 2,
28 "level": 2,
29 "metadata": {},
29 "metadata": {},
30 "source": [
30 "source": [
31 "Interact"
31 "Interact"
32 ]
32 ]
33 },
33 },
34 {
34 {
35 "cell_type": "markdown",
35 "cell_type": "markdown",
36 "metadata": {},
36 "metadata": {},
37 "source": [
37 "source": [
38 "* [Using Interact](Using Interact.ipynb)"
38 "* [Using Interact](Using Interact.ipynb)"
39 ]
39 ]
40 },
40 },
41 {
41 {
42 "cell_type": "heading",
42 "cell_type": "heading",
43 "level": 2,
43 "level": 2,
44 "metadata": {},
44 "metadata": {},
45 "source": [
45 "source": [
46 "Widgets"
46 "Widgets"
47 ]
47 ]
48 },
48 },
49 {
49 {
50 "cell_type": "markdown",
50 "cell_type": "markdown",
51 "metadata": {},
51 "metadata": {},
52 "source": [
52 "source": [
53 "- [Basics](Basics.ipynb) \n",
53 "- [Basics](Basics.ipynb) \n",
54 "- [Events](Events.ipynb) \n",
54 "- [Events](Events.ipynb) \n",
55 "- [Placement](Placement.ipynb) \n",
55 "- [Placement](Placement.ipynb) \n",
56 "- [Styles](Styles.ipynb) \n",
56 "- [Styles](Styles.ipynb) \n",
57 "- [Alignment](Alignment.ipynb) \n",
57 "- [Alignment](Alignment.ipynb) \n",
58 "- [Custom Widgets](Custom Widgets.ipynb) "
58 "- [Custom Widgets](Custom Widgets.ipynb) "
59 ]
59 ]
60 },
61 {
62 "cell_type": "code",
63 "collapsed": false,
64 "input": [],
65 "language": "python",
66 "metadata": {},
67 "outputs": []
68 }
60 }
69 ],
61 ],
70 "metadata": {}
62 "metadata": {}
71 }
63 }
72 ]
64 ]
73 } No newline at end of file
65 }
@@ -1,187 +1,174 b''
1 {
1 {
2 "metadata": {
2 "metadata": {
3 "cell_tags": [
3 "cell_tags": [
4 [
4 [
5 "<None>",
5 "<None>",
6 null
6 null
7 ]
7 ]
8 ],
8 ],
9 "name": ""
9 "name": "",
10 "signature": "sha256:60ff1a42e4dbc911ae15b409033e993257425c982809950746a567a4419b9484"
10 },
11 },
11 "nbformat": 3,
12 "nbformat": 3,
12 "nbformat_minor": 0,
13 "nbformat_minor": 0,
13 "worksheets": [
14 "worksheets": [
14 {
15 {
15 "cells": [
16 "cells": [
16 {
17 {
17 "cell_type": "markdown",
18 "metadata": {},
19 "source": [
20 "[< Back to Part 2](Part 2 - Events.ipynb) or [Index](index.ipynb)"
21 ]
22 },
23 {
24 "cell_type": "code",
18 "cell_type": "code",
25 "collapsed": false,
19 "collapsed": false,
26 "input": [
20 "input": [
27 "from IPython.html import widgets # Widget definitions\n",
21 "from IPython.html import widgets # Widget definitions\n",
28 "from IPython.display import display # Used to display widgets in the notebook"
22 "from IPython.display import display # Used to display widgets in the notebook"
29 ],
23 ],
30 "language": "python",
24 "language": "python",
31 "metadata": {},
25 "metadata": {},
32 "outputs": [],
26 "outputs": [],
33 "prompt_number": 1
27 "prompt_number": 1
34 },
28 },
35 {
29 {
36 "cell_type": "heading",
30 "cell_type": "heading",
37 "level": 1,
31 "level": 1,
38 "metadata": {},
32 "metadata": {},
39 "source": [
33 "source": [
40 "Parent/Child Relationships"
34 "Parent/Child Relationships"
41 ]
35 ]
42 },
36 },
43 {
37 {
44 "cell_type": "markdown",
38 "cell_type": "markdown",
45 "metadata": {},
39 "metadata": {},
46 "source": [
40 "source": [
47 "To display widget A inside widget B, widget A must be a child of widget B. Only one instance of any particular widget can be child of another. In other words, *widget A* cannot have *widget B* listed twice in it's list of children.\n",
41 "To display widget A inside widget B, widget A must be a child of widget B. Only one instance of any particular widget can be child of another. In other words, *widget A* cannot have *widget B* listed twice in it's list of children.\n",
48 "\n",
42 "\n",
49 "Widgets that can contain other widgets have a `children` attribute. This attribute can be set via a kwarg in the widget's constructor or after construction. Calling display on an object with children automatically displays those children, too."
43 "Widgets that can contain other widgets have a `children` attribute. This attribute can be set via a kwarg in the widget's constructor or after construction. Calling display on an object with children automatically displays those children, too."
50 ]
44 ]
51 },
45 },
52 {
46 {
53 "cell_type": "code",
47 "cell_type": "code",
54 "collapsed": false,
48 "collapsed": false,
55 "input": [
49 "input": [
56 "float_range = widgets.FloatSliderWidget()\n",
50 "float_range = widgets.FloatSliderWidget()\n",
57 "string = widgets.TextWidget(value='hi')\n",
51 "string = widgets.TextWidget(value='hi')\n",
58 "container = widgets.ContainerWidget(children=[float_range, string])\n",
52 "container = widgets.ContainerWidget(children=[float_range, string])\n",
59 "\n",
53 "\n",
60 "display(container) # Displays the `container` and all of it's children."
54 "display(container) # Displays the `container` and all of it's children."
61 ],
55 ],
62 "language": "python",
56 "language": "python",
63 "metadata": {},
57 "metadata": {},
64 "outputs": [],
58 "outputs": [],
65 "prompt_number": 2
59 "prompt_number": 2
66 },
60 },
67 {
61 {
68 "cell_type": "markdown",
62 "cell_type": "markdown",
69 "metadata": {},
63 "metadata": {},
70 "source": [
64 "source": [
71 "Children can also be added to parents after the parent has been displayed. The parent is responsible for rendering its children."
65 "Children can also be added to parents after the parent has been displayed. The parent is responsible for rendering its children."
72 ]
66 ]
73 },
67 },
74 {
68 {
75 "cell_type": "code",
69 "cell_type": "code",
76 "collapsed": false,
70 "collapsed": false,
77 "input": [
71 "input": [
78 "container = widgets.ContainerWidget()\n",
72 "container = widgets.ContainerWidget()\n",
79 "display(container)\n",
73 "display(container)\n",
80 "\n",
74 "\n",
81 "int_range = widgets.IntSliderWidget()\n",
75 "int_range = widgets.IntSliderWidget()\n",
82 "container.children=[int_range]\n"
76 "container.children=[int_range]\n"
83 ],
77 ],
84 "language": "python",
78 "language": "python",
85 "metadata": {},
79 "metadata": {},
86 "outputs": [],
80 "outputs": [],
87 "prompt_number": 3
81 "prompt_number": 3
88 },
82 },
89 {
83 {
90 "cell_type": "heading",
84 "cell_type": "heading",
91 "level": 1,
85 "level": 1,
92 "metadata": {},
86 "metadata": {},
93 "source": [
87 "source": [
94 "Visibility"
88 "Visibility"
95 ]
89 ]
96 },
90 },
97 {
91 {
98 "cell_type": "markdown",
92 "cell_type": "markdown",
99 "metadata": {},
93 "metadata": {},
100 "source": [
94 "source": [
101 "Sometimes it is necessary to hide or show widgets in place, without having to redisplay the widget.\n",
95 "Sometimes it is necessary to hide or show widgets in place, without having to redisplay the widget.\n",
102 "The `visibility` property of widgets can be used to hide or show widgets that have already been displayed (as seen below)."
96 "The `visibility` property of widgets can be used to hide or show widgets that have already been displayed (as seen below)."
103 ]
97 ]
104 },
98 },
105 {
99 {
106 "cell_type": "code",
100 "cell_type": "code",
107 "collapsed": false,
101 "collapsed": false,
108 "input": [
102 "input": [
109 "string = widgets.LatexWidget(value=\"Hello World!\")\n",
103 "string = widgets.LatexWidget(value=\"Hello World!\")\n",
110 "display(string) "
104 "display(string) "
111 ],
105 ],
112 "language": "python",
106 "language": "python",
113 "metadata": {},
107 "metadata": {},
114 "outputs": [],
108 "outputs": [],
115 "prompt_number": 4
109 "prompt_number": 4
116 },
110 },
117 {
111 {
118 "cell_type": "code",
112 "cell_type": "code",
119 "collapsed": false,
113 "collapsed": false,
120 "input": [
114 "input": [
121 "string.visible=False"
115 "string.visible=False"
122 ],
116 ],
123 "language": "python",
117 "language": "python",
124 "metadata": {},
118 "metadata": {},
125 "outputs": [],
119 "outputs": [],
126 "prompt_number": 5
120 "prompt_number": 5
127 },
121 },
128 {
122 {
129 "cell_type": "code",
123 "cell_type": "code",
130 "collapsed": false,
124 "collapsed": false,
131 "input": [
125 "input": [
132 "string.visible=True"
126 "string.visible=True"
133 ],
127 ],
134 "language": "python",
128 "language": "python",
135 "metadata": {},
129 "metadata": {},
136 "outputs": [],
130 "outputs": [],
137 "prompt_number": 6
131 "prompt_number": 6
138 },
132 },
139 {
133 {
140 "cell_type": "markdown",
134 "cell_type": "markdown",
141 "metadata": {},
135 "metadata": {},
142 "source": [
136 "source": [
143 "In the example below, a form is rendered, which conditionally displays widgets depending on the state of other widgets. Try toggling the student checkbox."
137 "In the example below, a form is rendered, which conditionally displays widgets depending on the state of other widgets. Try toggling the student checkbox."
144 ]
138 ]
145 },
139 },
146 {
140 {
147 "cell_type": "code",
141 "cell_type": "code",
148 "collapsed": false,
142 "collapsed": false,
149 "input": [
143 "input": [
150 "form = widgets.ContainerWidget()\n",
144 "form = widgets.ContainerWidget()\n",
151 "first = widgets.TextWidget(description=\"First Name:\")\n",
145 "first = widgets.TextWidget(description=\"First Name:\")\n",
152 "last = widgets.TextWidget(description=\"Last Name:\")\n",
146 "last = widgets.TextWidget(description=\"Last Name:\")\n",
153 "\n",
147 "\n",
154 "student = widgets.CheckboxWidget(description=\"Student:\", value=False)\n",
148 "student = widgets.CheckboxWidget(description=\"Student:\", value=False)\n",
155 "school_info = widgets.ContainerWidget(visible=False, children=[\n",
149 "school_info = widgets.ContainerWidget(visible=False, children=[\n",
156 " widgets.TextWidget(description=\"School:\"),\n",
150 " widgets.TextWidget(description=\"School:\"),\n",
157 " widgets.IntTextWidget(description=\"Grade:\", min=0, max=12)\n",
151 " widgets.IntTextWidget(description=\"Grade:\", min=0, max=12)\n",
158 " ])\n",
152 " ])\n",
159 "\n",
153 "\n",
160 "pet = widgets.TextWidget(description=\"Pet's Name:\")\n",
154 "pet = widgets.TextWidget(description=\"Pet's Name:\")\n",
161 "form.children = [first, last, student, school_info, pet]\n",
155 "form.children = [first, last, student, school_info, pet]\n",
162 "display(form)\n",
156 "display(form)\n",
163 "\n",
157 "\n",
164 "def on_student_toggle(name, value):\n",
158 "def on_student_toggle(name, value):\n",
165 " if value:\n",
159 " if value:\n",
166 " school_info.visible = True\n",
160 " school_info.visible = True\n",
167 " else:\n",
161 " else:\n",
168 " school_info.visible = False\n",
162 " school_info.visible = False\n",
169 "student.on_trait_change(on_student_toggle, 'value')\n"
163 "student.on_trait_change(on_student_toggle, 'value')\n"
170 ],
164 ],
171 "language": "python",
165 "language": "python",
172 "metadata": {},
166 "metadata": {},
173 "outputs": [],
167 "outputs": [],
174 "prompt_number": 7
168 "prompt_number": 7
175 },
176 {
177 "cell_type": "markdown",
178 "metadata": {},
179 "source": [
180 "In [Part 4](Part 4 - Styles.ipynb) of this [series](index.ipynb), you will learn about widget styling."
181 ]
182 }
169 }
183 ],
170 ],
184 "metadata": {}
171 "metadata": {}
185 }
172 }
186 ]
173 ]
187 } No newline at end of file
174 }
@@ -1,368 +1,355 b''
1 {
1 {
2 "metadata": {
2 "metadata": {
3 "cell_tags": [
3 "cell_tags": [
4 [
4 [
5 "<None>",
5 "<None>",
6 null
6 null
7 ]
7 ]
8 ],
8 ],
9 "name": ""
9 "name": "",
10 "signature": "sha256:cd7d3d42126bdbf20c087014460779dfbdb0a63dcb8f489ba7ebfc230a685edd"
10 },
11 },
11 "nbformat": 3,
12 "nbformat": 3,
12 "nbformat_minor": 0,
13 "nbformat_minor": 0,
13 "worksheets": [
14 "worksheets": [
14 {
15 {
15 "cells": [
16 "cells": [
16 {
17 {
17 "cell_type": "markdown",
18 "metadata": {},
19 "source": [
20 "[< Back to Part 3](Part 3 - Placement.ipynb) or [Index](index.ipynb)"
21 ]
22 },
23 {
24 "cell_type": "code",
18 "cell_type": "code",
25 "collapsed": false,
19 "collapsed": false,
26 "input": [
20 "input": [
27 "from IPython.html import widgets # Widget definitions\n",
21 "from IPython.html import widgets # Widget definitions\n",
28 "from IPython.display import display # Used to display widgets in the notebook"
22 "from IPython.display import display # Used to display widgets in the notebook"
29 ],
23 ],
30 "language": "python",
24 "language": "python",
31 "metadata": {},
25 "metadata": {},
32 "outputs": [],
26 "outputs": [],
33 "prompt_number": 1
27 "prompt_number": 1
34 },
28 },
35 {
29 {
36 "cell_type": "heading",
30 "cell_type": "heading",
37 "level": 1,
31 "level": 1,
38 "metadata": {},
32 "metadata": {},
39 "source": [
33 "source": [
40 "CSS"
34 "CSS"
41 ]
35 ]
42 },
36 },
43 {
37 {
44 "cell_type": "markdown",
38 "cell_type": "markdown",
45 "metadata": {},
39 "metadata": {},
46 "source": [
40 "source": [
47 "When trying to design an attractive widget GUI, styling becomes important.\n",
41 "When trying to design an attractive widget GUI, styling becomes important.\n",
48 "Most widget views are DOM (document object model) elements that can be controlled with CSS.\n",
42 "Most widget views are DOM (document object model) elements that can be controlled with CSS.\n",
49 "There are two helper methods that allow the manipulation of the widget's CSS.\n",
43 "There are two helper methods that allow the manipulation of the widget's CSS.\n",
50 "The first is the `Widget.set_css` method.\n",
44 "The first is the `Widget.set_css` method.\n",
51 "This method allows one or more CSS attributes to be set at once. "
45 "This method allows one or more CSS attributes to be set at once. "
52 ]
46 ]
53 },
47 },
54 {
48 {
55 "cell_type": "code",
49 "cell_type": "code",
56 "collapsed": false,
50 "collapsed": false,
57 "input": [
51 "input": [
58 "print(widgets.DOMWidget.set_css.__doc__)"
52 "print(widgets.DOMWidget.set_css.__doc__)"
59 ],
53 ],
60 "language": "python",
54 "language": "python",
61 "metadata": {},
55 "metadata": {},
62 "outputs": [
56 "outputs": [
63 {
57 {
64 "output_type": "stream",
58 "output_type": "stream",
65 "stream": "stdout",
59 "stream": "stdout",
66 "text": [
60 "text": [
67 "Set one or more CSS properties of the widget.\n",
61 "Set one or more CSS properties of the widget.\n",
68 "\n",
62 "\n",
69 " This function has two signatures:\n",
63 " This function has two signatures:\n",
70 " - set_css(css_dict, selector='')\n",
64 " - set_css(css_dict, selector='')\n",
71 " - set_css(key, value, selector='')\n",
65 " - set_css(key, value, selector='')\n",
72 "\n",
66 "\n",
73 " Parameters\n",
67 " Parameters\n",
74 " ----------\n",
68 " ----------\n",
75 " css_dict : dict\n",
69 " css_dict : dict\n",
76 " CSS key/value pairs to apply\n",
70 " CSS key/value pairs to apply\n",
77 " key: unicode\n",
71 " key: unicode\n",
78 " CSS key\n",
72 " CSS key\n",
79 " value:\n",
73 " value:\n",
80 " CSS value\n",
74 " CSS value\n",
81 " selector: unicode (optional, kwarg only)\n",
75 " selector: unicode (optional, kwarg only)\n",
82 " JQuery selector to use to apply the CSS key/value. If no selector \n",
76 " JQuery selector to use to apply the CSS key/value. If no selector \n",
83 " is provided, an empty selector is used. An empty selector makes the \n",
77 " is provided, an empty selector is used. An empty selector makes the \n",
84 " front-end try to apply the css to a default element. The default\n",
78 " front-end try to apply the css to a default element. The default\n",
85 " element is an attribute unique to each view, which is a DOM element\n",
79 " element is an attribute unique to each view, which is a DOM element\n",
86 " of the view that should be styled with common CSS (see \n",
80 " of the view that should be styled with common CSS (see \n",
87 " `$el_to_style` in the Javascript code).\n",
81 " `$el_to_style` in the Javascript code).\n",
88 " \n"
82 " \n"
89 ]
83 ]
90 }
84 }
91 ],
85 ],
92 "prompt_number": 2
86 "prompt_number": 2
93 },
87 },
94 {
88 {
95 "cell_type": "markdown",
89 "cell_type": "markdown",
96 "metadata": {},
90 "metadata": {},
97 "source": [
91 "source": [
98 "The second is `get_css` which allows CSS attributesto be read.\n",
92 "The second is `get_css` which allows CSS attributesto be read.\n",
99 "Note that this method will only read CSS attributes that have been set using the `set_css` method."
93 "Note that this method will only read CSS attributes that have been set using the `set_css` method."
100 ]
94 ]
101 },
95 },
102 {
96 {
103 "cell_type": "code",
97 "cell_type": "code",
104 "collapsed": false,
98 "collapsed": false,
105 "input": [
99 "input": [
106 "print(widgets.DOMWidget.get_css.__doc__)"
100 "print(widgets.DOMWidget.get_css.__doc__)"
107 ],
101 ],
108 "language": "python",
102 "language": "python",
109 "metadata": {},
103 "metadata": {},
110 "outputs": [
104 "outputs": [
111 {
105 {
112 "output_type": "stream",
106 "output_type": "stream",
113 "stream": "stdout",
107 "stream": "stdout",
114 "text": [
108 "text": [
115 "Get a CSS property of the widget.\n",
109 "Get a CSS property of the widget.\n",
116 "\n",
110 "\n",
117 " Note: This function does not actually request the CSS from the \n",
111 " Note: This function does not actually request the CSS from the \n",
118 " front-end; Only properties that have been set with set_css can be read.\n",
112 " front-end; Only properties that have been set with set_css can be read.\n",
119 "\n",
113 "\n",
120 " Parameters\n",
114 " Parameters\n",
121 " ----------\n",
115 " ----------\n",
122 " key: unicode\n",
116 " key: unicode\n",
123 " CSS key\n",
117 " CSS key\n",
124 " selector: unicode (optional)\n",
118 " selector: unicode (optional)\n",
125 " JQuery selector used when the CSS key/value was set.\n",
119 " JQuery selector used when the CSS key/value was set.\n",
126 " \n"
120 " \n"
127 ]
121 ]
128 }
122 }
129 ],
123 ],
130 "prompt_number": 3
124 "prompt_number": 3
131 },
125 },
132 {
126 {
133 "cell_type": "markdown",
127 "cell_type": "markdown",
134 "metadata": {},
128 "metadata": {},
135 "source": [
129 "source": [
136 "Below is an example that applies CSS attributes to a container to emphasize text."
130 "Below is an example that applies CSS attributes to a container to emphasize text."
137 ]
131 ]
138 },
132 },
139 {
133 {
140 "cell_type": "code",
134 "cell_type": "code",
141 "collapsed": false,
135 "collapsed": false,
142 "input": [
136 "input": [
143 "label = widgets.LatexWidget()\n",
137 "label = widgets.LatexWidget()\n",
144 "label.value = \"$\\\\textbf{ALERT:} Hello World!$\"\n",
138 "label.value = \"$\\\\textbf{ALERT:} Hello World!$\"\n",
145 "container = widgets.ContainerWidget(children=[label])\n",
139 "container = widgets.ContainerWidget(children=[label])\n",
146 "\n",
140 "\n",
147 "# set_css used to set a single CSS attribute.\n",
141 "# set_css used to set a single CSS attribute.\n",
148 "container.set_css('border', '3px solid black') # Border the container\n",
142 "container.set_css('border', '3px solid black') # Border the container\n",
149 "\n",
143 "\n",
150 "# set_css used to set multiple CSS attributes.\n",
144 "# set_css used to set multiple CSS attributes.\n",
151 "container.set_css({'padding': '6px', # Add padding to the container\n",
145 "container.set_css({'padding': '6px', # Add padding to the container\n",
152 " 'background': 'yellow'}) # Fill the container yellow\n",
146 " 'background': 'yellow'}) # Fill the container yellow\n",
153 "\n",
147 "\n",
154 "display(container)"
148 "display(container)"
155 ],
149 ],
156 "language": "python",
150 "language": "python",
157 "metadata": {},
151 "metadata": {},
158 "outputs": [],
152 "outputs": [],
159 "prompt_number": 4
153 "prompt_number": 4
160 },
154 },
161 {
155 {
162 "cell_type": "heading",
156 "cell_type": "heading",
163 "level": 1,
157 "level": 1,
164 "metadata": {},
158 "metadata": {},
165 "source": [
159 "source": [
166 "CSS Classes"
160 "CSS Classes"
167 ]
161 ]
168 },
162 },
169 {
163 {
170 "cell_type": "markdown",
164 "cell_type": "markdown",
171 "metadata": {},
165 "metadata": {},
172 "source": [
166 "source": [
173 "In some cases, it is necessary to apply CSS classes to your widgets.\n",
167 "In some cases, it is necessary to apply CSS classes to your widgets.\n",
174 "CSS classes allow DOM elements to be indentified in Javascript and CSS.\n",
168 "CSS classes allow DOM elements to be indentified in Javascript and CSS.\n",
175 "The notebook defines its own set of classes to stylize its elements.\n",
169 "The notebook defines its own set of classes to stylize its elements.\n",
176 "The `add_class` widget method allows you to add CSS classes to your widget."
170 "The `add_class` widget method allows you to add CSS classes to your widget."
177 ]
171 ]
178 },
172 },
179 {
173 {
180 "cell_type": "code",
174 "cell_type": "code",
181 "collapsed": false,
175 "collapsed": false,
182 "input": [
176 "input": [
183 "print(widgets.DOMWidget.add_class.__doc__)"
177 "print(widgets.DOMWidget.add_class.__doc__)"
184 ],
178 ],
185 "language": "python",
179 "language": "python",
186 "metadata": {},
180 "metadata": {},
187 "outputs": [
181 "outputs": [
188 {
182 {
189 "output_type": "stream",
183 "output_type": "stream",
190 "stream": "stdout",
184 "stream": "stdout",
191 "text": [
185 "text": [
192 "Add class[es] to a DOM element.\n",
186 "Add class[es] to a DOM element.\n",
193 "\n",
187 "\n",
194 " Parameters\n",
188 " Parameters\n",
195 " ----------\n",
189 " ----------\n",
196 " class_names: unicode or list\n",
190 " class_names: unicode or list\n",
197 " Class name(s) to add to the DOM element(s).\n",
191 " Class name(s) to add to the DOM element(s).\n",
198 " selector: unicode (optional)\n",
192 " selector: unicode (optional)\n",
199 " JQuery selector to select the DOM element(s) that the class(es) will\n",
193 " JQuery selector to select the DOM element(s) that the class(es) will\n",
200 " be added to.\n",
194 " be added to.\n",
201 " \n"
195 " \n"
202 ]
196 ]
203 }
197 }
204 ],
198 ],
205 "prompt_number": 5
199 "prompt_number": 5
206 },
200 },
207 {
201 {
208 "cell_type": "markdown",
202 "cell_type": "markdown",
209 "metadata": {},
203 "metadata": {},
210 "source": [
204 "source": [
211 "Since `add_class` is a DOM operation, **it will only affect widgets that have already been displayed**.\n",
205 "Since `add_class` is a DOM operation, **it will only affect widgets that have already been displayed**.\n",
212 "`add_class` must be called after the widget has been displayed.\n",
206 "`add_class` must be called after the widget has been displayed.\n",
213 "Extending the example above, the corners of the container can be rounded by adding the `corner-all` CSS class to the container."
207 "Extending the example above, the corners of the container can be rounded by adding the `corner-all` CSS class to the container."
214 ]
208 ]
215 },
209 },
216 {
210 {
217 "cell_type": "code",
211 "cell_type": "code",
218 "collapsed": false,
212 "collapsed": false,
219 "input": [
213 "input": [
220 "container = widgets.ContainerWidget()\n",
214 "container = widgets.ContainerWidget()\n",
221 "container.set_css({'border': '3px solid black',\n",
215 "container.set_css({'border': '3px solid black',\n",
222 " 'padding': '6px', \n",
216 " 'padding': '6px', \n",
223 " 'background': 'yellow'}) \n",
217 " 'background': 'yellow'}) \n",
224 "\n",
218 "\n",
225 "label = widgets.LatexWidget()\n",
219 "label = widgets.LatexWidget()\n",
226 "label.value = \"$\\\\textbf{ALERT:} Hello World!$\"\n",
220 "label.value = \"$\\\\textbf{ALERT:} Hello World!$\"\n",
227 "container.children = [label]\n",
221 "container.children = [label]\n",
228 "display(container)\n",
222 "display(container)\n",
229 "container.add_class('corner-all') # Must be called AFTER display"
223 "container.add_class('corner-all') # Must be called AFTER display"
230 ],
224 ],
231 "language": "python",
225 "language": "python",
232 "metadata": {},
226 "metadata": {},
233 "outputs": [],
227 "outputs": [],
234 "prompt_number": 6
228 "prompt_number": 6
235 },
229 },
236 {
230 {
237 "cell_type": "markdown",
231 "cell_type": "markdown",
238 "metadata": {},
232 "metadata": {},
239 "source": [
233 "source": [
240 "The IPython notebook uses [bootstrap](http://getbootstrap.com/\u200e) for styling.\n",
234 "The IPython notebook uses [bootstrap](http://getbootstrap.com/\u200e) for styling.\n",
241 "The example above can be simplified by using a bootstrap class:"
235 "The example above can be simplified by using a bootstrap class:"
242 ]
236 ]
243 },
237 },
244 {
238 {
245 "cell_type": "code",
239 "cell_type": "code",
246 "collapsed": false,
240 "collapsed": false,
247 "input": [
241 "input": [
248 "label = widgets.LatexWidget(value = \"$\\\\textbf{ALERT:} Hello World!$\")\n",
242 "label = widgets.LatexWidget(value = \"$\\\\textbf{ALERT:} Hello World!$\")\n",
249 "display(label)\n",
243 "display(label)\n",
250 "\n",
244 "\n",
251 "# Apply twitter bootstrap alert class to the label.\n",
245 "# Apply twitter bootstrap alert class to the label.\n",
252 "label.add_class(\"alert\")"
246 "label.add_class(\"alert\")"
253 ],
247 ],
254 "language": "python",
248 "language": "python",
255 "metadata": {},
249 "metadata": {},
256 "outputs": [],
250 "outputs": [],
257 "prompt_number": 7
251 "prompt_number": 7
258 },
252 },
259 {
253 {
260 "cell_type": "markdown",
254 "cell_type": "markdown",
261 "metadata": {},
255 "metadata": {},
262 "source": [
256 "source": [
263 "The example below shows how bootstrap classes can be used to change button apearance."
257 "The example below shows how bootstrap classes can be used to change button apearance."
264 ]
258 ]
265 },
259 },
266 {
260 {
267 "cell_type": "code",
261 "cell_type": "code",
268 "collapsed": false,
262 "collapsed": false,
269 "input": [
263 "input": [
270 "# List of the bootstrap button styles\n",
264 "# List of the bootstrap button styles\n",
271 "button_classes = ['Default', 'btn-primary', 'btn-info', 'btn-success', \n",
265 "button_classes = ['Default', 'btn-primary', 'btn-info', 'btn-success', \n",
272 " 'btn-warning', 'btn-danger', 'btn-inverse', 'btn-link']\n",
266 " 'btn-warning', 'btn-danger', 'btn-inverse', 'btn-link']\n",
273 "\n",
267 "\n",
274 "# Create each button and apply the style. Also add margin to the buttons so they space\n",
268 "# Create each button and apply the style. Also add margin to the buttons so they space\n",
275 "# themselves nicely.\n",
269 "# themselves nicely.\n",
276 "for i in range(8):\n",
270 "for i in range(8):\n",
277 " button = widgets.ButtonWidget(description=button_classes[i])\n",
271 " button = widgets.ButtonWidget(description=button_classes[i])\n",
278 " button.set_css(\"margin\", \"5px\")\n",
272 " button.set_css(\"margin\", \"5px\")\n",
279 " display(button)\n",
273 " display(button)\n",
280 " if i > 0: # Don't add a class the first button.\n",
274 " if i > 0: # Don't add a class the first button.\n",
281 " button.add_class(button_classes[i])\n",
275 " button.add_class(button_classes[i])\n",
282 " "
276 " "
283 ],
277 ],
284 "language": "python",
278 "language": "python",
285 "metadata": {},
279 "metadata": {},
286 "outputs": [],
280 "outputs": [],
287 "prompt_number": 8
281 "prompt_number": 8
288 },
282 },
289 {
283 {
290 "cell_type": "markdown",
284 "cell_type": "markdown",
291 "metadata": {},
285 "metadata": {},
292 "source": [
286 "source": [
293 "It is also useful to be able to remove CSS classes from widgets.\n",
287 "It is also useful to be able to remove CSS classes from widgets.\n",
294 "The `remove_class` method allows you to remove classes from widgets that have been displayed.\n",
288 "The `remove_class` method allows you to remove classes from widgets that have been displayed.\n",
295 "Like `add_class`, it must be called after the widget has been displayed."
289 "Like `add_class`, it must be called after the widget has been displayed."
296 ]
290 ]
297 },
291 },
298 {
292 {
299 "cell_type": "code",
293 "cell_type": "code",
300 "collapsed": false,
294 "collapsed": false,
301 "input": [
295 "input": [
302 "print(widgets.DOMWidget.remove_class.__doc__)"
296 "print(widgets.DOMWidget.remove_class.__doc__)"
303 ],
297 ],
304 "language": "python",
298 "language": "python",
305 "metadata": {},
299 "metadata": {},
306 "outputs": [
300 "outputs": [
307 {
301 {
308 "output_type": "stream",
302 "output_type": "stream",
309 "stream": "stdout",
303 "stream": "stdout",
310 "text": [
304 "text": [
311 "Remove class[es] from a DOM element.\n",
305 "Remove class[es] from a DOM element.\n",
312 "\n",
306 "\n",
313 " Parameters\n",
307 " Parameters\n",
314 " ----------\n",
308 " ----------\n",
315 " class_names: unicode or list\n",
309 " class_names: unicode or list\n",
316 " Class name(s) to remove from the DOM element(s).\n",
310 " Class name(s) to remove from the DOM element(s).\n",
317 " selector: unicode (optional)\n",
311 " selector: unicode (optional)\n",
318 " JQuery selector to select the DOM element(s) that the class(es) will\n",
312 " JQuery selector to select the DOM element(s) that the class(es) will\n",
319 " be removed from.\n",
313 " be removed from.\n",
320 " \n"
314 " \n"
321 ]
315 ]
322 }
316 }
323 ],
317 ],
324 "prompt_number": 9
318 "prompt_number": 9
325 },
319 },
326 {
320 {
327 "cell_type": "markdown",
321 "cell_type": "markdown",
328 "metadata": {},
322 "metadata": {},
329 "source": [
323 "source": [
330 "The example below animates an alert using different bootstrap styles."
324 "The example below animates an alert using different bootstrap styles."
331 ]
325 ]
332 },
326 },
333 {
327 {
334 "cell_type": "code",
328 "cell_type": "code",
335 "collapsed": false,
329 "collapsed": false,
336 "input": [
330 "input": [
337 "import time\n",
331 "import time\n",
338 "label = widgets.LatexWidget(value = \"$\\\\textbf{ALERT:} Hello World!$\")\n",
332 "label = widgets.LatexWidget(value = \"$\\\\textbf{ALERT:} Hello World!$\")\n",
339 "display(label)\n",
333 "display(label)\n",
340 "\n",
334 "\n",
341 "# Apply twitter bootstrap alert class to the label.\n",
335 "# Apply twitter bootstrap alert class to the label.\n",
342 "label.add_class(\"alert\")\n",
336 "label.add_class(\"alert\")\n",
343 "\n",
337 "\n",
344 "# Animate through additional bootstrap label styles 3 times\n",
338 "# Animate through additional bootstrap label styles 3 times\n",
345 "additional_alert_styles = ['alert-error', 'alert-info', 'alert-success']\n",
339 "additional_alert_styles = ['alert-error', 'alert-info', 'alert-success']\n",
346 "for i in range(3 * len(additional_alert_styles)):\n",
340 "for i in range(3 * len(additional_alert_styles)):\n",
347 " label.add_class(additional_alert_styles[i % 3])\n",
341 " label.add_class(additional_alert_styles[i % 3])\n",
348 " label.remove_class(additional_alert_styles[(i-1) % 3])\n",
342 " label.remove_class(additional_alert_styles[(i-1) % 3])\n",
349 " time.sleep(1)\n",
343 " time.sleep(1)\n",
350 " "
344 " "
351 ],
345 ],
352 "language": "python",
346 "language": "python",
353 "metadata": {},
347 "metadata": {},
354 "outputs": [],
348 "outputs": [],
355 "prompt_number": 10
349 "prompt_number": 10
356 },
357 {
358 "cell_type": "markdown",
359 "metadata": {},
360 "source": [
361 "In [Part 5](Part 5 - Alignment.ipynb) of this [series](index.ipynb), you will learn about widget alignment."
362 ]
363 }
350 }
364 ],
351 ],
365 "metadata": {}
352 "metadata": {}
366 }
353 }
367 ]
354 ]
368 } No newline at end of file
355 }
General Comments 0
You need to be logged in to leave comments. Login now