# Bespin Tutorials

## Adding to the GUI

# Introduction

Since Bespin is a webapp, any Bespin command could conceivably pop up some bit of user interface to interact with the user. It's just a matter of creating some DOM nodes and placing them on the screen.

But, if you want something a bit more persistent and integrated, you'll need to learn a bit about how Bespin's GUI is put together. That's what this tutorial is about.

At the same time, we're going to talk about how Bespin plugins can themselves be pluggable.

In this tutorial, we assume that you're already familiar with using dryice and the basics of making plugins. We're also going to assume a directory structure like the one from the commands tutorial.

By the end of this tutorial, we'll have something that looks toolbar-like. We're not trying to create a fully-functional toolbar here, because the focus is on hooking in to Bespin's GUI.

This tutorial should work with Bespin 0.9a1 or later. However, there is a bug in Firefox 3.6.x that will cause the toolbar to not display properly. Bespin 0.9a2 has a workaround for this, and the bug itself is fixed in Firefox versions after 3.6.x.

## Creating Our Plugin

As with the commands tutorial, we're assuming that you're working within a directory called `bespintutorial` that has Bespin itself in a subdirectory called `bespin`.

In plugins that have user interface elements, you will almost always need to create a "multi file plugin". That just means we'll be creating a directory rather than a single .js file.

We'll create a directory called `tutorialtoolbar`. To turn it into a plugin, we need to create a file called `package.json` in the `tutorialtoolbar` directory.

We also need a dryice manifest so that we can see our plugin in action. Create a file called `toolbar.json` in the `bespintutorial` directory. Here's what we'll put in it to start with:

    {
        "output_dir": "../build",
        "plugins": ["embedded", "tutorialtoolbar"],
        "search_path": [".."]
    }

Switch to the `bespin` directory and run:

    python dryice.py -s 8080 ../toolbar.json

You shouldn't get any errors from dryice. That means that it was able to find our tutorialtoolbar plugin. If you open your browser to http://localhost:8080/, you'll see a normal looking Bespin. Now we just need to put something in our plugin.

## Creating A Simple View

For a first step, we'll just toss a string up on the screen. In the `tutorialtoolbar` directory, create a new file called `index.js`. Here's how our toolbar component will start out:

    exports.ToolbarView = function() {
        var elem = document.createElement("div");
        elem.innerHTML = "<b>Toolbar!</b>";
        this.element = elem;
    };

We're creating a `Toolbar` class. When a new `Toolbar` is created, it gets a new element which just has our string in it. We set that to `element` on the instance. This is the key to GUI components that are integrated into Bespin's UI: they just offer up an `element` that Bespin will put in place.

The next step is telling the Bespin system about our new component. We do that in the `package.json` file, which will now look like this:

    {
        "provides": [
            {
                "ep": "factory",
                "name": "tutorialtoolbar",
                "action": "new",
                "pointer": "#ToolbarView"
            }
        ]
    }

The factory extension point is used for extensions that provide components for Bespin to automatically instantiate. That may sound kind of vague, but you'll see in a moment that it's actually easy to use. The `action` tells Bespin that it's going to be creating a new instance and the `pointer` is telling Bespin to look in the tutorialtoolbar plugin's `index` module for something called `ToolbarView`.

We've written code that will generate our initial toolbar and we've told Bespin that this is available. The next step is to tell Bespin to put one into the UI. This can be done either in the dryice manifest file or even at runtime when `useBespin` is called. We'll do it in the manifest file (`toolbar.json`). Here's the new manifest:

    {
        "output_dir": "../build",
        "plugins": ["embedded", "tutorialtoolbar"],
        "search_path": [".."],
        "config": {
            "objects": {
                "toolbar": {
                    "factory": "tutorialtoolbar"
                }
            },
            "gui": {
                "north": {
                    "component": "toolbar"
                }
            }
        }
    }

The new section is the `config` section. This provides the application configuration (about which you can read more in the Embedder's Guide).

The `objects` part of the config is telling Bespin to create a "global" (global within Bespin) object called `toolbar`. Bespin will look for a factory called `tutorialtoolbar`, which happens to be what we defined in the `package.json` file.

The `gui` part of the config is telling Bespin to toss the component (object) that we created with the name `toolbar` into the "north" part of the interface. Bespin uses a simple "border layout" with north, south, east, west and center locations. So, our toolbar should appear at the top of the page.

Refresh your browser, and you should see our Toolbar! appear at the top. If it appears at the bottom, you've witnessed the bug mentioned in the introduction.

## CSS3 Flexible Box Model (an aside)

CSS3 includes a module called the Flexible Box Model (sometimes called flexbox), which Paul Rouget did a great job of introducing in this Mozilla Hacks article.

Traditionally, HTML+CSS have been quite nice for laying out documents but not so great for laying out user interfaces. Flexbox makes laying out UI a far easier process.

Bespin uses flexbox to create the border layout. When you declare that a GUI component belongs in the "north", all Bespin has to do is add the "north" class to the element, and it pops into the right place.

Flexbox would also be a great way to create a toolbar, but we're not going to go that far in this tutorial.

By using flexbox, we let the browser do all of the layout which is generally faster and smoother than JavaScript-based layouts.

## Making Our Toolbar Pluggable

One of Bespin's main features is that it is customizable and extendable. While it's certainly possible to make a static toolbar with a certain collection of functions, it's a lot more interesting to create a toolbar that is itself pluggable. Plus, that's part of the point of our tutorial.

We'll start by defining an extension point of our own in `package.json`. Add this as another item in the `provides` list in `package.json`:

    {
        "ep": "extensionpoint",
        "name": "tutorialtoolbaritem",
        "description": "Toolbar item views",
        "params": [
            {
                "name": "name",
                "description": "name of this toolbar item",
                "type": "string"
            },
            {
                "name": "pointer",
                "description": "pointer to a component that can be instantiated with new and has an element defined on it."
            }
        ]
    }

Extension points themselves are defined via the `extensionpoint` extension point. Seems a bit circular, but it works. We're creating an extension point called `tutorialtoolbaritem`. Bespin is designed to be introspectable, so we provide some documentation about the extension point via the `description` and `params` properties.

We're going to make `tutorialtoolbaritem`s look a lot like Bespin's GUI components (an object with an `element` property).

Now, we need to make our toolbar go out and find the registered `tutorialtoolbaritem`s. We'll change `index.js` to look like this:

    var catalog = require("bespin:plugins").catalog;

    exports.ToolbarView = function() {
        var elem = document.createElement("menu");
        elem.setAttribute('class', "tutorial-toolbar");
        elem.setAttribute('type', "toolbar");
        this.element = elem;

        this._items = [];

        var extensions = catalog.getExtensions('tutorialtoolbaritem');
        var self = this;
        extensions.forEach(function(ext) {
            ext.load().then(function(item) {
                item = new item();
                self._items.push(item);
                elem.appendChild(item.element);
            });
        });
    };

The first thing we're going to do is change the element we're creating into an HTML5 menu element. By giving it a type of `toolbar`, we're letting the browser know that we're creating a toolbar. Right now, the browsers don't render the toolbar in any special way, but we can use CSS to render the toolbar however we wish.

Next, we'll make a list to keep track of the items we find. Speaking of finding the items, we need to talk to the plugin catalog about that. In the first line of the file, we imported the catalog. Now, we call getExtensions which will return all of the `tutorialtoolbaritem`s.

We use `var self = this` because we've got some nested callbacks and that's a bit nicer to look at than binding each function individually. Then, we loop through the list of extensions and call `load` on each one.

The `load` function returns a Promise. Promises provide a convenient way to manage callbacks for asynchronous behavior. For our purposes here, the only difference between a Promise and a normal callback function is that we don't pass the callback directly to `load`. Instead, we call `then` on the promise and pass the callback to that.

Back in our metadata for the `tutorialtoolbaritem` extension point, we defined the `pointer` property as a pointer to a component that can be instantiated with new and has an element defined on it. So, when we `load` the extension, that's what we're going to get back. With the tutorialtoolbar item in hand, we can call `new` on it, add that new instance to our items list and then add the instance's element to our toolbar.

And, with that, we have created a dynamically extendable toolbar.

## Adding Some Items

Of course, if we reload our Bespin, the toolbar will be rather boring. We haven't added any toolbar items!

With the infrastructure that we put in place in the last section, we can create `tutorialtoolbaritem`s in any plugin. For convenience, we'll just add a couple of items in the tutorialtoolbar plugin.

We'll make a new module (file) for them in the `tutorialtoolbar` directory called `items.js`. At this stage, we're not going to make our toolbar items do anything, but we just want to have something to display. Here is our `items.js` file:

    exports.Logo = function() {
        var li = document.createElement('li');
        li.innerHTML = "Logo here";
        this.element = li;
    };

    exports.OpenFileIndicator = function() {
        var li = document.createElement('li');
        li.innerHTML = "SampleProject &mdash; readme.txt";
        this.element = li;
    };

    exports.Save = function() {
        var li = document.createElement('li');
        li.innerHTML = "Save";
        this.element = li;
    };

    exports.PositionIndicator = function() {
        var li = document.createElement('li');
        li.innerHTML = "Row 0, Column 0";
        this.element = li;
    };

As you can see, each one of these functions does nothing but create an `li` element (as per the HTML5 spec for menus) and add that element to the instance on the `element` property.

One more thing to do before we can see our toolbar. We need to register the extensions for our `tutorialtoolbar` extension point. Back in `package.json`, we're going to add these four more items to our `provides` property:

    {
        "ep": "tutorialtoolbaritem",
        "name": "logo",
        "pointer": "items#Logo"
    },
    {
        "ep": "tutorialtoolbaritem",
        "name": "openfileindicator",
        "pointer": "items#OpenFileIndicator"
    },
    {
        "ep": "tutorialtoolbaritem",
        "name": "save",
        "pointer": "items#Save"
    },
    {
        "ep": "tutorialtoolbaritem",
        "name": "positionindicator",
        "pointer": "items#PositionIndicator"
    }

You can see that each one of these refers to the `items` module in the pointer, since that's where we put these items.

For reference, here's the complete `package.json` file at this stage:

    {
        "provides": [
            {
                "ep": "factory",
                "name": "tutorialtoolbar",
                "action": "new",
                "pointer": "#ToolbarView"
            },
            {
                "ep": "extensionpoint",
                "name": "toolbaritem",
                "description": "Toolbar item views",
                "params": [
                    {
                        "name": "name",
                        "description": "name of this toolbar item",
                        "type": "string"
                    },
                    {
                        "name": "pointer",
                        "description": "pointer to a component that can be instantiated with new and has an element defined on it."
                    }
                ]
            },
            {
                "ep": "tutorialtoolbaritem",
                "name": "logo",
                "pointer": "items#Logo"
            },
            {
                "ep": "tutorialtoolbaritem",
                "name": "openfileindicator",
                "pointer": "items#OpenFileIndicator"
            },
            {
                "ep": "tutorialtoolbaritem",
                "name": "save",
                "pointer": "items#Save"
            },
            {
                "ep": "tutorialtoolbaritem",
                "name": "positionindicator",
                "pointer": "items#PositionIndicator"
            }
        ]
    }

With that, we've done everything we need to do to see our toolbar. Let's reload the page. You should see something that looks like this:

It worked! It has our items in it! Doesn't look much like a toolbar, though, does it?

## Styling Your Plugins

To make our toolbar look like a toolbar, we need to add some styles. In order to support themes properly, Bespin uses LESS, which is an extended CSS syntax.

In the `tutorialtoolbar` directory, create a `resources` directory. In there, create a file called `toolbar.less`. We need to tell Bespin's theme manager about this file, so we need to add one more thing to the `provides` property in `package.json`:

    {
        "ep": "themestyles",
        "url": [ "toolbar.less" ]
    }

`themestyles` extensions provide URLs (relative to the plugin's resources directory) to the LESS files that this plugin needs to have loaded. The theme manager will automatically load these files as needed.

And what's in this mysterious `toolbar.less` file?

    .bespin {
        .tutorial-toolbar {
            display: block;
            background-color: #000;
            border-bottom: solid #424038 1px;
            -moz-box-shadow: 0px 0px 3px 3px #000;
            -webkit-box-shadow: 0px 0px 3px 3px #000;
            color: #ffffff;
            font-family: Helvetica, Arial;
            width: 100%;
            margin: 0px;
            padding: 0px;
        }

        .tutorial-toolbar li {
            display: inline;
            padding: 0px 24px 0px 0px;
        }
    }

This looks like fairly normal CSS, right? Except what's that `.bespin` doing surrounding those other rules? When LESS expands this out to standard CSS, the result would be something like this:

    .bespin .tutorial-toolbar {
    }

    .bespin .tutorial-toolbar li {
    }

So, the surrounding `.bespin` is a nice little shorthand, and it prevents CSS from leaking out onto the page. When you consider the use of Bespin Embedded on other sites, it's a good idea to ensure that all of our styles are scoped for use only within Bespin.

With these styles in place, let's reload the page. Much nicer, eh?

## Wrapping Up

On the one hand, this tutorial didn't give us a functioning toolbar. It's all static text. On the other hand, look at everything we did cover:

- multi-file plugin structure
- creating a component that Bespin can display
- the awesomeness that is CSS3's Flexible Box Model
- configuring our component for display in Bespin
- defining and using our own extension points