{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Embrasing web standards" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "One of the main reasons we developed the current notebook as a web application \n", "is to embrace the available-everywhere web technology. \n", "\n", "Being a pure web application using only HTML, Javascript and CSS, the Notebook can access \n", "all of the web technology improvements for free. Thus, as browsers support for different \n", "media extend, the notebook web app should be compatible without modification. \n", "\n", "This is also true with performance of the User Interface as the speed of the Javascript \n", "VM increases. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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", "Even if this task is not always easy, we strive to keep our code as accessible and reusable as possible.\n", "This should allow - with minimum effort - development of small extensions that customize the behavior of the web interface. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Tampering with the Notebook app" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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", "\n", " - In Chrome and Safari, Developer tools are in the menu [Menu -> More tools -> Developer Tools] \n", " - In Firefox you might need to install [Firebug](http://getfirebug.com/)\n", " - others ?\n", " \n", "Those will be your best friends to debug and try different approaches for your extensions." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Injecting JS" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### using magics" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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", "\n", "You might see here and there people modifying CSS and injecting Javascript into notebook by reading files and publishing them into the notebook.\n", "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", "\n", "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." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "## You can inspect the autosave code to see what it does.\n", "%autosave??" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### custom.js" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To inject Javascript we provide an entry point: `custom.js` that allows the user to execute and load other resources into the notebook.\n", "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", "\n", "`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." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### Because we like you...." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You have been provided with an pre-existing profile folder with this tutorial...\n", "Start the notebook from the root of the tutorial directory with :\n", "\n", "```bash\n", "$ ipython notebook --ProfileDir.location=./profile_euroscipy\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### but back to theory" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "profile_dir = ! ipython locate\n", "profile_dir = profile_dir[0]\n", "profile_dir" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "and custom js is in " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import os.path\n", "custom_js_path = os.path.join(profile_dir,'profile_default','static','custom','custom.js')" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# my custom js\n", "with open(custom_js_path) as f:\n", " for l in f: \n", " print l," ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**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**." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exercise :" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " - Create a `custom.js` in the right location with the following content:\n", "```javascript\n", "alert(\"hello world from custom.js\")\n", "```\n", "\n", " - Restart your server and open any notebook.\n", " - Be greeted by custom.js" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### For the quick ones : " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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. " ] }, { "cell_type": "markdown", "metadata": { "foo": true }, "source": [ "Create a dropdown elemement in the toolbar (DOM `IPython.toolbar.element`). You will need \n", "\n", "- `IPython.notebook.set_autosave_interval(miliseconds)`\n", "- know that 1 min = 60 sec, and 1 sec = 1000 ms" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```javascript\n", "\n", "var label = jQuery('