##// END OF EJS Templates
Grammar and spelling improvements
Ben Rousch -
Show More
@@ -1,612 +1,613 b''
1 {
1 {
2 "cells": [
2 "cells": [
3 {
3 {
4 "cell_type": "markdown",
4 "cell_type": "markdown",
5 "metadata": {},
5 "metadata": {},
6 "source": [
6 "source": [
7 "# Embrasing web standards"
7 "# Embrasing web standards"
8 ]
8 ]
9 },
9 },
10 {
10 {
11 "cell_type": "markdown",
11 "cell_type": "markdown",
12 "metadata": {},
12 "metadata": {},
13 "source": [
13 "source": [
14 "One of the main reason that allowed us to developp the current notebook web application \n",
14 "One of the main reasons we developed the current notebook as a web application \n",
15 "was to embrase the web technology. \n",
15 "is to embrace the available-everywhere web technology. \n",
16 "\n",
16 "\n",
17 "By beeing a pure web application using HTML, Javascript and CSS, the Notebook can get \n",
17 "Being a pure web application using only HTML, Javascript and CSS, the Notebook can access \n",
18 "all the web technology improvement for free. Thus, as browsers support for different \n",
18 "all of the web technology improvements for free. Thus, as browsers support for different \n",
19 "media extend, The notebook web app should be able to be compatible without modification. \n",
19 "media extend, the notebook web app should be compatible without modification. \n",
20 "\n",
20 "\n",
21 "This is also true with performance of the User Interface as the speed of javascript VM increase. "
21 "This is also true with performance of the User Interface as the speed of the Javascript \n",
22 "VM increases. "
22 ]
23 ]
23 },
24 },
24 {
25 {
25 "cell_type": "markdown",
26 "cell_type": "markdown",
26 "metadata": {},
27 "metadata": {},
27 "source": [
28 "source": [
28 "The other advantage of using only web technology is that the code of the interface is fully accessible to the end user, and modifiable live.\n",
29 "The other advantage of using only web technology is that the code of the interface is fully accessible to the end user, and modifiable live.\n",
29 "Even if this task is not always easy, we strive to keep our code as accessible and reusable as possible.\n",
30 "Even if this task is not always easy, we strive to keep our code as accessible and reusable as possible.\n",
30 "This should allow with minimum effort to develop small extensions that customize the behavior of the web interface. "
31 "This should allow - with minimum effort - development of small extensions that customize the behavior of the web interface. "
31 ]
32 ]
32 },
33 },
33 {
34 {
34 "cell_type": "markdown",
35 "cell_type": "markdown",
35 "metadata": {},
36 "metadata": {},
36 "source": [
37 "source": [
37 "## Tempering with Notebook app"
38 "## Tampering with the Notebook app"
38 ]
39 ]
39 },
40 },
40 {
41 {
41 "cell_type": "markdown",
42 "cell_type": "markdown",
42 "metadata": {},
43 "metadata": {},
43 "source": [
44 "source": [
44 "The first tool that is availlable to you and that you shoudl be aware of are browser \"developpers tool\". The exact naming can change across browser, and might require the installation of extensions. But basically they can allow you to inspect/modify the DOM, and interact with the javascript code that run the frontend.\n",
45 "The first tool that is available to you and that you should be aware of are browser \"developer tools\". The exact name of these tools is different in each browser, and might require the installation of extensions. But basically they can allow you to inspect/modify the DOM, and interact with the Javascript code that runs the frontend.\n",
45 "\n",
46 "\n",
46 " - In Chrome and safari Developper tools are in the menu [Put mmenu name in english here] \n",
47 " - In Chrome and Safari, Developer tools are in the menu [Menu -> More tools -> Developer Tools] \n",
47 " - In firefox you might need to install [Firebug](http://getfirebug.com/)\n",
48 " - In Firefox you might need to install [Firebug](http://getfirebug.com/)\n",
48 " - others ?\n",
49 " - others ?\n",
49 " \n",
50 " \n",
50 "Those will be your best friends to debug and try different approach for your extensions."
51 "Those will be your best friends to debug and try different approaches for your extensions."
51 ]
52 ]
52 },
53 },
53 {
54 {
54 "cell_type": "markdown",
55 "cell_type": "markdown",
55 "metadata": {},
56 "metadata": {},
56 "source": [
57 "source": [
57 "### Injecting JS"
58 "### Injecting JS"
58 ]
59 ]
59 },
60 },
60 {
61 {
61 "cell_type": "markdown",
62 "cell_type": "markdown",
62 "metadata": {},
63 "metadata": {},
63 "source": [
64 "source": [
64 "#### using magics"
65 "#### using magics"
65 ]
66 ]
66 },
67 },
67 {
68 {
68 "cell_type": "markdown",
69 "cell_type": "markdown",
69 "metadata": {},
70 "metadata": {},
70 "source": [
71 "source": [
71 "Above tools can be tedious to edit long javascipt files. Hopefully we provide the `%%javascript` magic. This allows you to quickly inject javascript into the notebook. Still the javascript injected this way will not survive reloading. Hence it is a good tool for testing an refinig a script.\n",
72 "The above tools can be tedious for editing long Javascipt files. Helpfully, we provide the `%%javascript` magic. This allows you to quickly inject Javascript into the notebook. Still, the Javascript injected this way will not survive reloading. Hence, it is a good tool for testing and refining a script.\n",
72 "\n",
73 "\n",
73 "You might see here and there people modifying css and injecting js into notebook by reading file and publishing them into the notebook.\n",
74 "You might see here and there people modifying CSS and injecting Javascript into notebook by reading files and publishing them into the notebook.\n",
74 "Not only this often break the flow of the notebook and make the re-execution of the notebook broken, but it also mean that you need to execute those cells on all the notebook every time you need to update the code.\n",
75 "Not only does this often break the flow of the notebook and break the re-execution of the notebook, but it also means that you need to execute those cells every time you need to update the code.\n",
75 "\n",
76 "\n",
76 "This can still be usefull in some cases, like the `%autosave` magic that allows to control the time between each save. But this can be replaced by a Javascript dropdown menu to select save interval."
77 "This can still be useful in some cases, like the `%autosave` magic that allows you to control the time between each save. But this can be replaced by a Javascript dropdown menu to select a save interval."
77 ]
78 ]
78 },
79 },
79 {
80 {
80 "cell_type": "code",
81 "cell_type": "code",
81 "execution_count": null,
82 "execution_count": null,
82 "metadata": {
83 "metadata": {
83 "collapsed": false
84 "collapsed": false
84 },
85 },
85 "outputs": [],
86 "outputs": [],
86 "source": [
87 "source": [
87 "## you can inspect the autosave code to see what it does.\n",
88 "## You can inspect the autosave code to see what it does.\n",
88 "%autosave??"
89 "%autosave??"
89 ]
90 ]
90 },
91 },
91 {
92 {
92 "cell_type": "markdown",
93 "cell_type": "markdown",
93 "metadata": {},
94 "metadata": {},
94 "source": [
95 "source": [
95 "#### custom.js"
96 "#### custom.js"
96 ]
97 ]
97 },
98 },
98 {
99 {
99 "cell_type": "markdown",
100 "cell_type": "markdown",
100 "metadata": {},
101 "metadata": {},
101 "source": [
102 "source": [
102 "To inject Javascript we provide an entry point: `custom.js` that allow teh user to execute and load other resources into the notebook.\n",
103 "To inject Javascript we provide an entry point: `custom.js` that allows the user to execute and load other resources into the notebook.\n",
103 "Javascript code in `custom.js` will be executed when the notebook app start and can then be used to customise almost anything in the UI and in the behavior of the notebook.\n",
104 "Javascript code in `custom.js` will be executed when the notebook app starts and can then be used to customize almost anything in the UI and in the behavior of the notebook.\n",
104 "\n",
105 "\n",
105 "`custom.js` can be found in IPython profile dir, and so you can have different UI modification on a per profile basis, as well as share your modfication with others."
106 "`custom.js` can be found in the IPython profile dir, and so you can have different UI modifications on a per-profile basis, as well as share your modfications with others."
106 ]
107 ]
107 },
108 },
108 {
109 {
109 "cell_type": "markdown",
110 "cell_type": "markdown",
110 "metadata": {},
111 "metadata": {},
111 "source": [
112 "source": [
112 "##### Because we like you...."
113 "##### Because we like you...."
113 ]
114 ]
114 },
115 },
115 {
116 {
116 "cell_type": "markdown",
117 "cell_type": "markdown",
117 "metadata": {},
118 "metadata": {},
118 "source": [
119 "source": [
119 "You have been provided with an already existing profile folder with this tutorial...\n",
120 "You have been provided with an pre-existing profile folder with this tutorial...\n",
120 "start the notebook from the root of the tutorial directory with :\n",
121 "Start the notebook from the root of the tutorial directory with :\n",
121 "\n",
122 "\n",
122 "```bash\n",
123 "```bash\n",
123 "$ ipython notebook --ProfileDir.location=./profile_euroscipy\n",
124 "$ ipython notebook --ProfileDir.location=./profile_euroscipy\n",
124 "```"
125 "```"
125 ]
126 ]
126 },
127 },
127 {
128 {
128 "cell_type": "markdown",
129 "cell_type": "markdown",
129 "metadata": {},
130 "metadata": {},
130 "source": [
131 "source": [
131 "##### but back to theory"
132 "##### but back to theory"
132 ]
133 ]
133 },
134 },
134 {
135 {
135 "cell_type": "code",
136 "cell_type": "code",
136 "execution_count": null,
137 "execution_count": null,
137 "metadata": {
138 "metadata": {
138 "collapsed": false
139 "collapsed": false
139 },
140 },
140 "outputs": [],
141 "outputs": [],
141 "source": [
142 "source": [
142 "profile_dir = ! ipython locate\n",
143 "profile_dir = ! ipython locate\n",
143 "profile_dir = profile_dir[0]\n",
144 "profile_dir = profile_dir[0]\n",
144 "profile_dir"
145 "profile_dir"
145 ]
146 ]
146 },
147 },
147 {
148 {
148 "cell_type": "markdown",
149 "cell_type": "markdown",
149 "metadata": {},
150 "metadata": {},
150 "source": [
151 "source": [
151 "and custom js is in "
152 "and custom js is in "
152 ]
153 ]
153 },
154 },
154 {
155 {
155 "cell_type": "code",
156 "cell_type": "code",
156 "execution_count": null,
157 "execution_count": null,
157 "metadata": {
158 "metadata": {
158 "collapsed": false
159 "collapsed": false
159 },
160 },
160 "outputs": [],
161 "outputs": [],
161 "source": [
162 "source": [
162 "import os.path\n",
163 "import os.path\n",
163 "custom_js_path = os.path.join(profile_dir,'profile_default','static','custom','custom.js')"
164 "custom_js_path = os.path.join(profile_dir,'profile_default','static','custom','custom.js')"
164 ]
165 ]
165 },
166 },
166 {
167 {
167 "cell_type": "code",
168 "cell_type": "code",
168 "execution_count": null,
169 "execution_count": null,
169 "metadata": {
170 "metadata": {
170 "collapsed": false
171 "collapsed": false
171 },
172 },
172 "outputs": [],
173 "outputs": [],
173 "source": [
174 "source": [
174 "# my custom js\n",
175 "# my custom js\n",
175 "with open(custom_js_path) as f:\n",
176 "with open(custom_js_path) as f:\n",
176 " for l in f: \n",
177 " for l in f: \n",
177 " print l,"
178 " print l,"
178 ]
179 ]
179 },
180 },
180 {
181 {
181 "cell_type": "markdown",
182 "cell_type": "markdown",
182 "metadata": {},
183 "metadata": {},
183 "source": [
184 "source": [
184 "Note that `custom.js` is ment to be modified by user, when writing a script, you can define it in a separate file and add a line of configuration into `custom.js` that will fetch and execute the file."
185 "Note that `custom.js` is meant to be modified by the user. When writing a script, you can define it in a separate file and add a line of configuration into `custom.js` that will fetch and execute the file."
185 ]
186 ]
186 },
187 },
187 {
188 {
188 "cell_type": "markdown",
189 "cell_type": "markdown",
189 "metadata": {},
190 "metadata": {},
190 "source": [
191 "source": [
191 "**Warning** : even if modification of `custom.js` take effect immediately after browser refresh (except if browser cache is aggressive), *creating* a file in `static/` directory need a **server restart**."
192 "**Warning** : even if modification of `custom.js` takes effect immediately after a browser refresh (except if browser cache is aggressive), *creating* a file in `static/` directory needs a **server restart**."
192 ]
193 ]
193 },
194 },
194 {
195 {
195 "cell_type": "markdown",
196 "cell_type": "markdown",
196 "metadata": {},
197 "metadata": {},
197 "source": [
198 "source": [
198 "## Exercise :"
199 "## Exercise :"
199 ]
200 ]
200 },
201 },
201 {
202 {
202 "cell_type": "markdown",
203 "cell_type": "markdown",
203 "metadata": {},
204 "metadata": {},
204 "source": [
205 "source": [
205 " - Create a `custom.js` in the right location with the following content:\n",
206 " - Create a `custom.js` in the right location with the following content:\n",
206 "```javascript\n",
207 "```javascript\n",
207 "alert(\"hello world from custom.js\")\n",
208 "alert(\"hello world from custom.js\")\n",
208 "```\n",
209 "```\n",
209 "\n",
210 "\n",
210 " - Restart your server and open any notebook.\n",
211 " - Restart your server and open any notebook.\n",
211 " - Be greeted by custom.js"
212 " - Be greeted by custom.js"
212 ]
213 ]
213 },
214 },
214 {
215 {
215 "cell_type": "markdown",
216 "cell_type": "markdown",
216 "metadata": {},
217 "metadata": {},
217 "source": [
218 "source": [
218 "Have a look at [default custom.js](https://github.com/ipython/ipython/blob/1.x/IPython/html/static/custom/custom.js), to see it's content and some more explanation."
219 "Have a look at [default custom.js](https://github.com/ipython/ipython/blob/1.x/IPython/html/static/custom/custom.js), to see it's contents and for more explanation."
219 ]
220 ]
220 },
221 },
221 {
222 {
222 "cell_type": "markdown",
223 "cell_type": "markdown",
223 "metadata": {},
224 "metadata": {},
224 "source": [
225 "source": [
225 "#### For the quick ones : "
226 "#### For the quick ones : "
226 ]
227 ]
227 },
228 },
228 {
229 {
229 "cell_type": "markdown",
230 "cell_type": "markdown",
230 "metadata": {},
231 "metadata": {},
231 "source": [
232 "source": [
232 "We've seen above that you can change the autosave rate by using a magic. This is typically something I don't want to type everytime, and that I don't like to embed into my workwlow and documents. (reader don't care what my autosave time is), let's build an extension that allow to do it. "
233 "We've seen above that you can change the autosave rate by using a magic. This is typically something I don't want to type everytime, and that I don't like to embed into my workflow and documents. (The reader doesn't care what my autosave time is), so let's build an extension that allow to do it. "
233 ]
234 ]
234 },
235 },
235 {
236 {
236 "cell_type": "markdown",
237 "cell_type": "markdown",
237 "metadata": {
238 "metadata": {
238 "foo": true
239 "foo": true
239 },
240 },
240 "source": [
241 "source": [
241 "Create a dropdow elemement in the toolbar (DOM `IPython.toolbar.element`), you will need \n",
242 "Create a dropdown elemement in the toolbar (DOM `IPython.toolbar.element`). You will need \n",
242 "\n",
243 "\n",
243 "- `IPython.notebook.set_autosave_interval(miliseconds)`\n",
244 "- `IPython.notebook.set_autosave_interval(miliseconds)`\n",
244 "- know that 1min = 60 sec, and 1 sec = 1000 ms"
245 "- know that 1 min = 60 sec, and 1 sec = 1000 ms"
245 ]
246 ]
246 },
247 },
247 {
248 {
248 "cell_type": "markdown",
249 "cell_type": "markdown",
249 "metadata": {},
250 "metadata": {},
250 "source": [
251 "source": [
251 "```javascript\n",
252 "```javascript\n",
252 "\n",
253 "\n",
253 "var label = jQuery('<label/>').text('AutoScroll Limit:');\n",
254 "var label = jQuery('<label/>').text('AutoScroll Limit:');\n",
254 "var select = jQuery('<select/>')\n",
255 "var select = jQuery('<select/>')\n",
255 " //.append(jQuery('<option/>').attr('value', '2').text('2min (default)'))\n",
256 " //.append(jQuery('<option/>').attr('value', '2').text('2min (default)'))\n",
256 " .append(jQuery('<option/>').attr('value', undefined).text('disabled'))\n",
257 " .append(jQuery('<option/>').attr('value', undefined).text('disabled'))\n",
257 "\n",
258 "\n",
258 " // TODO:\n",
259 " // TODO:\n",
259 " //the_toolbar_element.append(label)\n",
260 " //the_toolbar_element.append(label)\n",
260 " //the_toolbar_element.append(select);\n",
261 " //the_toolbar_element.append(select);\n",
261 " \n",
262 " \n",
262 "select.change(function() {\n",
263 "select.change(function() {\n",
263 " var val = jQuery(this).val() // val will be the value in [2]\n",
264 " var val = jQuery(this).val() // val will be the value in [2]\n",
264 " // TODO\n",
265 " // TODO\n",
265 " // this will be called when dropdown changes\n",
266 " // this will be called when dropdown changes\n",
266 "\n",
267 "\n",
267 "});\n",
268 "});\n",
268 "\n",
269 "\n",
269 "var time_m = [1,5,10,15,30];\n",
270 "var time_m = [1,5,10,15,30];\n",
270 "for (var i=0; i < time_m.length; i++) {\n",
271 "for (var i=0; i < time_m.length; i++) {\n",
271 " var ts = time_m[i];\n",
272 " var ts = time_m[i];\n",
272 " //[2] ____ this will be `val` on [1] \n",
273 " //[2] ____ this will be `val` on [1] \n",
273 " // | \n",
274 " // | \n",
274 " // v \n",
275 " // v \n",
275 " select.append($('<option/>').attr('value', ts).text(thr+'min'));\n",
276 " select.append($('<option/>').attr('value', ts).text(thr+'min'));\n",
276 " // this will fill up the dropdown `select` with\n",
277 " // this will fill up the dropdown `select` with\n",
277 " // 1 min\n",
278 " // 1 min\n",
278 " // 5 min\n",
279 " // 5 min\n",
279 " // 10 min\n",
280 " // 10 min\n",
280 " // 10 min\n",
281 " // 10 min\n",
281 " // ...\n",
282 " // ...\n",
282 "}\n",
283 "}\n",
283 "```"
284 "```"
284 ]
285 ]
285 },
286 },
286 {
287 {
287 "cell_type": "markdown",
288 "cell_type": "markdown",
288 "metadata": {},
289 "metadata": {},
289 "source": [
290 "source": [
290 "#### A non interactive example first"
291 "#### A non-interactive example first"
291 ]
292 ]
292 },
293 },
293 {
294 {
294 "cell_type": "markdown",
295 "cell_type": "markdown",
295 "metadata": {},
296 "metadata": {},
296 "source": [
297 "source": [
297 "I like my cython to be nicely highlighted\n",
298 "I like my cython to be nicely highlighted\n",
298 "\n",
299 "\n",
299 "```javascript\n",
300 "```javascript\n",
300 "traitlets.config.cell_magic_highlight['magic_text/x-cython'] = {}\n",
301 "traitlets.config.cell_magic_highlight['magic_text/x-cython'] = {}\n",
301 "traitlets.config.cell_magic_highlight['magic_text/x-cython'].reg = [/^%%cython/]\n",
302 "traitlets.config.cell_magic_highlight['magic_text/x-cython'].reg = [/^%%cython/]\n",
302 "```\n",
303 "```\n",
303 "\n",
304 "\n",
304 "`text/x-cython` is the name of CodeMirror mode name, `magic_` prefix will just patch the mode so that the first line that contains a magic does not screw up the highlighting. `reg`is a list or regular expression that will trigger the change of mode."
305 "`text/x-cython` is the name of a CodeMirror mode name, the `magic_` prefix will just patch the mode so that the first line that contains a magic does not screw up the highlighting. `reg`is a list or regular expression that will trigger the change of mode."
305 ]
306 ]
306 },
307 },
307 {
308 {
308 "cell_type": "markdown",
309 "cell_type": "markdown",
309 "metadata": {},
310 "metadata": {},
310 "source": [
311 "source": [
311 "#### Get more docs"
312 "#### Get more docs"
312 ]
313 ]
313 },
314 },
314 {
315 {
315 "cell_type": "markdown",
316 "cell_type": "markdown",
316 "metadata": {},
317 "metadata": {},
317 "source": [
318 "source": [
318 "Sadly you will have to read the js source file (but there are lots of comments) an/or build the javascript documentation using yuidoc.\n",
319 "Sadly, you will have to read the Javascript source file (but there are lots of comments) and/or build the Javascript documentation using YUIDoc.\n",
319 "If you have `node` and `yui-doc` installed:"
320 "If you have `node` and `yui-doc` installed:"
320 ]
321 ]
321 },
322 },
322 {
323 {
323 "cell_type": "markdown",
324 "cell_type": "markdown",
324 "metadata": {},
325 "metadata": {},
325 "source": [
326 "source": [
326 "```bash\n",
327 "```bash\n",
327 "$ cd ~/ipython/IPython/html/static/notebook/js/\n",
328 "$ cd ~/ipython/IPython/html/static/notebook/js/\n",
328 "$ yuidoc . --server\n",
329 "$ yuidoc . --server\n",
329 "warn: (yuidoc): Failed to extract port, setting to the default :3000\n",
330 "warn: (yuidoc): Failed to extract port, setting to the default :3000\n",
330 "info: (yuidoc): Starting YUIDoc@0.3.45 using YUI@3.9.1 with NodeJS@0.10.15\n",
331 "info: (yuidoc): Starting YUIDoc@0.3.45 using YUI@3.9.1 with NodeJS@0.10.15\n",
331 "info: (yuidoc): Scanning for yuidoc.json file.\n",
332 "info: (yuidoc): Scanning for yuidoc.json file.\n",
332 "info: (yuidoc): Starting YUIDoc with the following options:\n",
333 "info: (yuidoc): Starting YUIDoc with the following options:\n",
333 "info: (yuidoc):\n",
334 "info: (yuidoc):\n",
334 "{ port: 3000,\n",
335 "{ port: 3000,\n",
335 " nocode: false,\n",
336 " nocode: false,\n",
336 " paths: [ '.' ],\n",
337 " paths: [ '.' ],\n",
337 " server: true,\n",
338 " server: true,\n",
338 " outdir: './out' }\n",
339 " outdir: './out' }\n",
339 "info: (yuidoc): Scanning for yuidoc.json file.\n",
340 "info: (yuidoc): Scanning for yuidoc.json file.\n",
340 "info: (server): Starting server: http://127.0.0.1:3000\n",
341 "info: (server): Starting server: http://127.0.0.1:3000\n",
341 "```\n",
342 "```\n",
342 "\n",
343 "\n",
343 "and browse http://127.0.0.1:3000 to get docs"
344 "and browse to http://127.0.0.1:3000 to get the docs"
344 ]
345 ]
345 },
346 },
346 {
347 {
347 "cell_type": "markdown",
348 "cell_type": "markdown",
348 "metadata": {
349 "metadata": {
349 "foo": true
350 "foo": true
350 },
351 },
351 "source": [
352 "source": [
352 "#### Some convenience methods"
353 "#### Some convenience methods"
353 ]
354 ]
354 },
355 },
355 {
356 {
356 "cell_type": "markdown",
357 "cell_type": "markdown",
357 "metadata": {},
358 "metadata": {},
358 "source": [
359 "source": [
359 "By browsing the doc you will see that we have soem convenience methods that avoid to re-invent the UI everytime :\n",
360 "By browsing the docs you will see that we have some convenience methods that avoid re-inventing the UI everytime :\n",
360 "```javascript\n",
361 "```javascript\n",
361 "IPython.toolbar.add_buttons_group([\n",
362 "IPython.toolbar.add_buttons_group([\n",
362 " {\n",
363 " {\n",
363 " 'label' : 'run qtconsole',\n",
364 " 'label' : 'run qtconsole',\n",
364 " 'icon' : 'icon-terminal', // select your icon from \n",
365 " 'icon' : 'icon-terminal', // select your icon from \n",
365 " // http://fortawesome.github.io/Font-Awesome/icons/\n",
366 " // http://fortawesome.github.io/Font-Awesome/icons/\n",
366 " 'callback': function(){IPython.notebook.kernel.execute('%qtconsole')}\n",
367 " 'callback': function(){IPython.notebook.kernel.execute('%qtconsole')}\n",
367 " }\n",
368 " }\n",
368 " // add more button here if needed.\n",
369 " // add more button here if needed.\n",
369 " ]);\n",
370 " ]);\n",
370 "```\n",
371 "```\n",
371 "with a [lot of icons] you can select from. \n",
372 "with a [lot of icons] you can select from. \n",
372 "\n",
373 "\n",
373 "[lot of icons]: http://fortawesome.github.io/Font-Awesome/icons/"
374 "[lot of icons]: http://fortawesome.github.io/Font-Awesome/icons/"
374 ]
375 ]
375 },
376 },
376 {
377 {
377 "cell_type": "markdown",
378 "cell_type": "markdown",
378 "metadata": {
379 "metadata": {
379 "foo": true
380 "foo": true
380 },
381 },
381 "source": [
382 "source": [
382 "## Cell Metadata"
383 "## Cell Metadata"
383 ]
384 ]
384 },
385 },
385 {
386 {
386 "cell_type": "markdown",
387 "cell_type": "markdown",
387 "metadata": {
388 "metadata": {
388 "foo": true
389 "foo": true
389 },
390 },
390 "source": [
391 "source": [
391 "The most requested feature is generaly to be able to distinguish individual cell in th enotebook, or run specific action with them.\n",
392 "The most requested feature is generally to be able to distinguish individual cells in the notebook, or run specific actions with them.\n",
392 "To do so, you can either use `IPython.notebook.get_selected_cell()`, or rely on `CellToolbar`. This allow you to register aset of action and graphical element that will be attached on individual cells."
393 "To do so, you can either use `IPython.notebook.get_selected_cell()`, or rely on `CellToolbar`. This allows you to register a set of actions and graphical elements that will be attached to individual cells."
393 ]
394 ]
394 },
395 },
395 {
396 {
396 "cell_type": "markdown",
397 "cell_type": "markdown",
397 "metadata": {},
398 "metadata": {},
398 "source": [
399 "source": [
399 "### Cell Toolbar"
400 "### Cell Toolbar"
400 ]
401 ]
401 },
402 },
402 {
403 {
403 "cell_type": "markdown",
404 "cell_type": "markdown",
404 "metadata": {},
405 "metadata": {},
405 "source": [
406 "source": [
406 "You can see some example of what can be done by toggling the `Cell Toolbar` selector in the toolbar on top of the notebook. It provide two default `presets` that are `Default` and `slideshow`. Default allow edit the metadata attached to each cell manually."
407 "You can see some examples of what can be done by toggling the `Cell Toolbar` selector in the toolbar on top of the notebook. It provides two default `presets` that are `Default` and `slideshow`. Defaults allow editing the metadata attached to each cell manually."
407 ]
408 ]
408 },
409 },
409 {
410 {
410 "cell_type": "markdown",
411 "cell_type": "markdown",
411 "metadata": {},
412 "metadata": {},
412 "source": [
413 "source": [
413 "First we define a function that takes at first parameter an element on the DOM in which to inject UI element. Second element will be the cell this element will be registerd with. Then we will need to register that function ad give it a name.\n"
414 "First we define a function that takes as the first parameter an element on the DOM into which to inject UI element. The second element will be the cell with which this element will be registerd. Then we will need to register that function and give it a name.\n"
414 ]
415 ]
415 },
416 },
416 {
417 {
417 "cell_type": "markdown",
418 "cell_type": "markdown",
418 "metadata": {},
419 "metadata": {},
419 "source": [
420 "source": [
420 "#### Register a callback"
421 "#### Register a callback"
421 ]
422 ]
422 },
423 },
423 {
424 {
424 "cell_type": "code",
425 "cell_type": "code",
425 "execution_count": null,
426 "execution_count": null,
426 "metadata": {
427 "metadata": {
427 "collapsed": false
428 "collapsed": false
428 },
429 },
429 "outputs": [],
430 "outputs": [],
430 "source": [
431 "source": [
431 "%%javascript\n",
432 "%%javascript\n",
432 "var CellToolbar = IPython.CellToolbar\n",
433 "var CellToolbar = IPython.CellToolbar\n",
433 "var toggle = function(div, cell) {\n",
434 "var toggle = function(div, cell) {\n",
434 " var button_container = $(div)\n",
435 " var button_container = $(div)\n",
435 "\n",
436 "\n",
436 " // let's create a button that show the current value of the metadata\n",
437 " // Let's create a button that shows the current value of the metadata\n",
437 " var button = $('<button/>').addClass('btn btn-mini').text(String(cell.metadata.foo));\n",
438 " var button = $('<button/>').addClass('btn btn-mini').text(String(cell.metadata.foo));\n",
438 "\n",
439 "\n",
439 " // On click, change the metadata value and update the button label\n",
440 " // On click, change the metadata value and update the button label\n",
440 " button.click(function(){\n",
441 " button.click(function(){\n",
441 " var v = cell.metadata.foo;\n",
442 " var v = cell.metadata.foo;\n",
442 " cell.metadata.foo = !v;\n",
443 " cell.metadata.foo = !v;\n",
443 " button.text(String(!v));\n",
444 " button.text(String(!v));\n",
444 " })\n",
445 " })\n",
445 "\n",
446 "\n",
446 " // add the button to the DOM div.\n",
447 " // add the button to the DOM div.\n",
447 " button_container.append(button);\n",
448 " button_container.append(button);\n",
448 "}\n",
449 "}\n",
449 "\n",
450 "\n",
450 " // now we register the callback under the name foo to give the\n",
451 " // now we register the callback under the name foo to give the\n",
451 " // user the ability to use it later\n",
452 " // user the ability to use it later\n",
452 " CellToolbar.register_callback('tuto.foo', toggle);"
453 " CellToolbar.register_callback('tuto.foo', toggle);"
453 ]
454 ]
454 },
455 },
455 {
456 {
456 "cell_type": "markdown",
457 "cell_type": "markdown",
457 "metadata": {},
458 "metadata": {},
458 "source": [
459 "source": [
459 "#### Registering a preset"
460 "#### Registering a preset"
460 ]
461 ]
461 },
462 },
462 {
463 {
463 "cell_type": "markdown",
464 "cell_type": "markdown",
464 "metadata": {},
465 "metadata": {},
465 "source": [
466 "source": [
466 "This function can now be part of many `preset` of the CellToolBar."
467 "This function can now be part of any `preset` of the CellToolBar."
467 ]
468 ]
468 },
469 },
469 {
470 {
470 "cell_type": "code",
471 "cell_type": "code",
471 "execution_count": null,
472 "execution_count": null,
472 "metadata": {
473 "metadata": {
473 "collapsed": false,
474 "collapsed": false,
474 "foo": true,
475 "foo": true,
475 "slideshow": {
476 "slideshow": {
476 "slide_type": "subslide"
477 "slide_type": "subslide"
477 }
478 }
478 },
479 },
479 "outputs": [],
480 "outputs": [],
480 "source": [
481 "source": [
481 "%%javascript\n",
482 "%%javascript\n",
482 "IPython.CellToolbar.register_preset('Tutorial 1',['tuto.foo','default.rawedit'])\n",
483 "IPython.CellToolbar.register_preset('Tutorial 1',['tuto.foo','default.rawedit'])\n",
483 "IPython.CellToolbar.register_preset('Tutorial 2',['slideshow.select','tuto.foo'])"
484 "IPython.CellToolbar.register_preset('Tutorial 2',['slideshow.select','tuto.foo'])"
484 ]
485 ]
485 },
486 },
486 {
487 {
487 "cell_type": "markdown",
488 "cell_type": "markdown",
488 "metadata": {},
489 "metadata": {},
489 "source": [
490 "source": [
490 "You should now have access to two presets :\n",
491 "You should now have access to two presets :\n",
491 "\n",
492 "\n",
492 " - Tutorial 1\n",
493 " - Tutorial 1\n",
493 " - Tutorial 2\n",
494 " - Tutorial 2\n",
494 " \n",
495 " \n",
495 "And check that the buttons you defin share state when you toggle preset. \n",
496 "And check that the buttons you defined share state when you toggle preset. \n",
496 "Check moreover that the metadata of the cell is modified when you clisk the button, and that when saved on reloaded the metadata is still availlable."
497 "Also check that the metadata of the cell is modified when you click the button, and that the saved metadata is still available on reload."
497 ]
498 ]
498 },
499 },
499 {
500 {
500 "cell_type": "markdown",
501 "cell_type": "markdown",
501 "metadata": {},
502 "metadata": {},
502 "source": [
503 "source": [
503 "#### Exercise:"
504 "#### Exercise:"
504 ]
505 ]
505 },
506 },
506 {
507 {
507 "cell_type": "markdown",
508 "cell_type": "markdown",
508 "metadata": {},
509 "metadata": {},
509 "source": [
510 "source": [
510 "Try to wrap the all code in a file, put this file in `{profile}/static/custom/<a-name>.js`, and add \n",
511 "Try to wrap the all code in a file, put this file in `{profile}/static/custom/<a-name>.js`, and add \n",
511 "\n",
512 "\n",
512 "```\n",
513 "```\n",
513 "require(['custom/<a-name>']);\n",
514 "require(['custom/<a-name>']);\n",
514 "```\n",
515 "```\n",
515 "\n",
516 "\n",
516 "in `custom.js` to have this script automatically loaded in all your notebooks.\n",
517 "in `custom.js` to have this script automatically loaded in all your notebooks.\n",
517 "\n"
518 "\n"
518 ]
519 ]
519 },
520 },
520 {
521 {
521 "cell_type": "markdown",
522 "cell_type": "markdown",
522 "metadata": {},
523 "metadata": {},
523 "source": [
524 "source": [
524 "`require` is provided by a [javascript library](http://requirejs.org/) that allow to express dependency. For simple extension like the previous one we directly mute the global namespace, but for more complexe extension you could pass acallback to `require([...], <callback>)` call, to allow the user to pass configuration information to your plugin.\n",
525 "`require` is provided by a [javascript library](http://requirejs.org/) that allows you to express dependency. For simple extensions like the previous one, we directly mute the global namespace, but for more complex extensions you could pass a callback to the `require([...], <callback>)` call, to allow the user to pass configuration information to your plugin.\n",
525 "\n",
526 "\n",
526 "In Python lang, \n",
527 "In Python lang, \n",
527 "\n",
528 "\n",
528 "```javascript\n",
529 "```javascript\n",
529 "require(['a/b', 'c/d'], function( e, f){\n",
530 "require(['a/b', 'c/d'], function( e, f){\n",
530 " e.something()\n",
531 " e.something()\n",
531 " f.something()\n",
532 " f.something()\n",
532 "})\n",
533 "})\n",
533 "```\n",
534 "```\n",
534 "\n",
535 "\n",
535 "could be read as\n",
536 "could be read as\n",
536 "```python\n",
537 "```python\n",
537 "import a.b as e\n",
538 "import a.b as e\n",
538 "import c.d as f\n",
539 "import c.d as f\n",
539 "e.something()\n",
540 "e.something()\n",
540 "f.something()\n",
541 "f.something()\n",
541 "```\n",
542 "```\n",
542 "\n",
543 "\n",
543 "\n",
544 "\n",
544 "See for example @damianavila [\"ZenMode\" plugin](https://github.com/ipython-contrib/IPython-notebook-extensions/blob/master/custom.example.js#L34) :\n",
545 "See for example @damianavila [\"ZenMode\" plugin](https://github.com/ipython-contrib/IPython-notebook-extensions/blob/master/custom.example.js#L34) :\n",
545 "\n",
546 "\n",
546 "```javascript\n",
547 "```javascript\n",
547 "\n",
548 "\n",
548 "// read that as\n",
549 "// read that as\n",
549 "// import custom.zenmode.main as zenmode\n",
550 "// import custom.zenmode.main as zenmode\n",
550 "require(['custom/zenmode/main'],function(zenmode){\n",
551 "require(['custom/zenmode/main'],function(zenmode){\n",
551 " zenmode.background('images/back12.jpg');\n",
552 " zenmode.background('images/back12.jpg');\n",
552 "})\n",
553 "})\n",
553 "```\n"
554 "```\n"
554 ]
555 ]
555 },
556 },
556 {
557 {
557 "cell_type": "markdown",
558 "cell_type": "markdown",
558 "metadata": {},
559 "metadata": {},
559 "source": [
560 "source": [
560 "#### For the quickest"
561 "#### For the quickest"
561 ]
562 ]
562 },
563 },
563 {
564 {
564 "cell_type": "markdown",
565 "cell_type": "markdown",
565 "metadata": {},
566 "metadata": {},
566 "source": [
567 "source": [
567 "Try to use [the following](https://github.com/ipython/ipython/blob/1.x/IPython/html/static/notebook/js/celltoolbar.js#L367) to bind a dropdown list to `cell.metadata.difficulty.select`. \n",
568 "Try to use [the following](https://github.com/ipython/ipython/blob/1.x/IPython/html/static/notebook/js/celltoolbar.js#L367) to bind a dropdown list to `cell.metadata.difficulty.select`. \n",
568 "\n",
569 "\n",
569 "It should be able to take the 4 following values :\n",
570 "It should be able to take the four following values :\n",
570 "\n",
571 "\n",
571 " - `<None>`\n",
572 " - `<None>`\n",
572 " - `Easy`\n",
573 " - `Easy`\n",
573 " - `Medium`\n",
574 " - `Medium`\n",
574 " - `Hard`\n",
575 " - `Hard`\n",
575 " \n",
576 " \n",
576 "We will use it to customise the output of the converted notebook depending of the tag on each cell"
577 "We will use it to customize the output of the converted notebook depending on the tag on each cell"
577 ]
578 ]
578 },
579 },
579 {
580 {
580 "cell_type": "code",
581 "cell_type": "code",
581 "execution_count": null,
582 "execution_count": null,
582 "metadata": {
583 "metadata": {
583 "collapsed": false
584 "collapsed": false
584 },
585 },
585 "outputs": [],
586 "outputs": [],
586 "source": [
587 "source": [
587 "%load soln/celldiff.js"
588 "%load soln/celldiff.js"
588 ]
589 ]
589 }
590 }
590 ],
591 ],
591 "metadata": {
592 "metadata": {
592 "kernelspec": {
593 "kernelspec": {
593 "display_name": "Python 3",
594 "display_name": "Python 3",
594 "language": "python",
595 "language": "python",
595 "name": "python3"
596 "name": "python3"
596 },
597 },
597 "language_info": {
598 "language_info": {
598 "codemirror_mode": {
599 "codemirror_mode": {
599 "name": "ipython",
600 "name": "ipython",
600 "version": 3
601 "version": 3
601 },
602 },
602 "file_extension": ".py",
603 "file_extension": ".py",
603 "mimetype": "text/x-python",
604 "mimetype": "text/x-python",
604 "name": "python",
605 "name": "python",
605 "nbconvert_exporter": "python",
606 "nbconvert_exporter": "python",
606 "pygments_lexer": "ipython3",
607 "pygments_lexer": "ipython3",
607 "version": "3.4.3"
608 "version": "3.4.3"
608 }
609 }
609 },
610 },
610 "nbformat": 4,
611 "nbformat": 4,
611 "nbformat_minor": 0
612 "nbformat_minor": 0
612 }
613 }
General Comments 0
You need to be logged in to leave comments. Login now