-
Notifications
You must be signed in to change notification settings - Fork 15
Developer Tutorial
This tutorial will guide you through building what is perhaps the simplest space that you can make: HelloWorld. The HelloWorld space, when completed, will allow you to add the words 'Hello World!' as a shift to any page on the web. Potentially, anyone else who has ShiftSpace installed will be able to see your message if they happen to discover it on a page, if they are following your activity, or are part of group that you published the shift to. They can also see without the plugin if they view it in the ShiftSpace proxy. Yet another way they might see it is if a blog has installed it as a blog plugin.
But before we begin, make sure you're running Firefox, that you've installed the ShiftSpace development environment, as well as GreaseMonkey. You also need to install a cutting edge release of the Firebug extension for Firefox. FireBug is a critical tool for designing your space, it allows you to easily examine and manipulate HTML and CSS "on the fly." It will also prove invaluable for debugging.
Finally, point your browser at the ShiftSpace Developer Sandbox. This will probably be something like http://localhost:8080/sandbox/. You should see a pretty picture of a big desert. This is where most of your development will happen. If you have installed GreaseMonkey and ShiftSpace you should make sure that ShiftSpace never launches on your development URLs, otherwise you'll get some weird results. Right click on the GreaseMonkey icon in the lower right corner of your browser window and select Manage User Scripts.... Select ShiftSpace and click the button Add button next to Excluded Pages. The default value to exclude is correct, just add it. You can now close the GreaseMonkey window and continue hacking.
In your ShiftSpace root directory there is a python script called shifty.py. This is helper tool for running common tasks. In order to use it you have to use the terminal. On OS X this means Terminal.app. If you're on Windows you should have installed mysysgit. mysysgit comes packaged with with a bash shell, and we'll refer to this as the terminal. On Linux - well you definitely know what the terminal is ;)
Open up a terminal and run the following:
$ cd into/your/shiftspace/ $ python shifty.py new HelloWorld
This creates all of the files needed for space development in a folder called HelloWorld in the spaces directory where all spaces live. You could have done this by hand, but it's easy to forget exactly what goes in what file. Using shifty.py makes this a whole lot easier. Open the new HelloWorld directory now and examine the contents of the file in your favorite text editor.
Believe it or not this is a fully functioning space. Let's see it in action.
If you've read over the installation instruction you know that to hack on ShiftSpace you need to start up CouchDB. If you are unsure how to do this refer to last section in the install instructions for your platform.
You also need to start the built in webserver using Shifty.
$ cd into/your/shiftspace/ $ python shifty.py runserver
This starts up the server on port 8080. If you want to start up the server on a different port, just give the runserver command a port number that you want to use.
Now point your browser to the sandbox. Open the console with the shift+space key combination. If you haven't created an account do so now (remember this is saving to your local CouchDB). If you have, just login using your username and password.
Install your space by selecting the Settings tab of the ShiftSpace Console. From there click on the Installed subtab. You should see a list including the pre-installed spaces. Scroll down to the input field. Type in 'HelloWorld' and click the Install button. Careful, space names are case sensitive (we'll fix this in a future version). You should see your space icon appear along with the name underneath the default installed Spaces.
Click on the Space Menu (first button on the lower left). Select the HelloWorld space. You should see a new orange shift appear on the page. Try dragging it around. Note that when you let go it gets saved and appears in the console.
Cool. Now let's dig in and see how this works.
It's time to see how this stuff works. In the following section we'll dive into what a space looks like as well as how to build one from scratch.
Open HelloWorld.js in the newly created HelloWorld directory. Erase its contents and let's start from scratch.
At its most basic level, building a new Space involves defining two things:
- The Space class itself (manage the overall UI/behavior for the Space)
- A specific Shift class (manage the UI/behavior of individual shifts)
To begin, we need extend the ShiftSpace.Space class. This is a very simple operation with MooTools, which offers useful object oriented conventions. By creating subclasses from the ShiftSpace.Space and ShiftSpace.Shift abstract base classes, you gain access to restricted ShiftSpace methods and benefit from our prewritten code. We try to do most of the heavy lifting for you. If you developed a Space prior to 1.0 please note that the subclassing syntax has changed because we are now only supporting MooTools 1.2.
var HelloWorldSpace = new Class({ Extends: ShiftSpace.Space // In a more complicated space you might have stuff here! });
This is using the MooTools subclassing syntax. While nice, we realized this is some serious boilerplate code. You have to write this every time. We got sick of writing it everytime. So here's a shortcut.
var HelloWorldSpace = Space();
This code is functionally equivalent to previous one but it's a lot less typing. Please not that you cannot use this shortcut generally with MooTools classes, this is a ShiftSpace-specific optimization.
Now we need to make a HelloWorld Shift class. To do this we need to extend the ShiftSpace.Shift class. Again you could write it like the following:
var HelloWorldShift = new Class({ Extends: ShiftSpace.Shift // Your code will go here });
But's simpler and easier to remember to write this:
var HelloWorldShift = Shift({ // Your code will go here });
The first thing you want to implement is the setup method. You should initialize your shift instances based on the properties of the passed in JSON object.
var HelloWorldShift = Shift({ setup: function(json) { this.setPosition(json); this.makeDraggable(); this.save(); } });
We're back to where we were before except that HelloWorld shifts now save themselves as soon as you create them. We haven't done anything new yet, but it's good to drive home how to build a space from scratch.
You're probably asking yourself how your shift appears on the screen, there doesn't seem to be any code that does that. To begin to get a idea of how this works we need to look at the attributes file for the HelloWorld space.
Open the *attrs.json* file in your HelloWorld space directory and make it look the following:
{ name: 'HelloWorld', authors: ['type your name'], icon: 'HelloWorld.png', css: 'HelloWorld.css', description: 'My first space for ShiftSpace 1.0!', tooltip: 'The most awesome space evar! or something like that', version: 0.1, shift: { html: 'HelloWorld.html' } }
This should be pretty self explanatory. ShiftSpace loads this file before it loads your space. That's why you see the space icon, tooltip, description, etc. One thing to note is the *shift.html* property that we've defined. In the past space developers had to define their interface by writing code. This ended up being a fairly time consuming and tedious affair. Since that time we developed a very useful system called *Sandalphon* which allows us to design our interfaces using only HTML and CSS. Recently we've made it possible for you to access this functionality without having to be bogged down in the details about how it works.
NOTE FOR PRE-1.0 DEVELOPERS: Prior to 1.0, developers would put their space attributes in the class definition. This is no longer supported and in fact your space will not properly load if you attempt to do this. In order for ShiftSpace to load you must provide a separate attr.json file in your space directory. Why? We want to support a wider variety of Spaces than prior releases did. For example you might want to create a space that always automatically loads on the New York Times. Because the ShiftSpace runtime always loads Spaces lazily (that is, spaces are not loaded until a user actually tries to view, create, or edit a shift) this presents a problem. The only way for ShiftSpace to know about the capabilities of your space before loading it is for you to provide the attrs.json file.
Note that in *HelloWorld.js* the space class is named *HelloWorldSpace* and the shift class is named *HelloWorldShift*. This is actually somewhat important. This is a convention. Notice that we did not write it as "HelloWorld_Space". Of course you don't have to follow conventions, but the ShiftSpace runtime cannot read your mind. If you have a different naming convention you would like to use you will need to specify this. If you want to use a different name for your space class specify a *className* property. For a different shift class name use *shift.className*.
Hopefully you have a better idea now how the different parts of a space fit together. In this final section we'll look at modifying the CSS as well as adding a couple of new behaviors to your space.
The ShiftSpace teams believe that building extensions for a browser should be "webby." To us this means sticking with HTML+CSS+JavaScript. In the past we leaned a little heavily on JavaScript. Space development now supports designing the look and feel of your interface almost entirely with HTML and CSS. For anything but the most trivial of spaces, this saves hundreds of lines of boilerplate code.
Basically you provide an html file and we'll add this as property to each shift when it get's created. This might not make much sense right now so let's see how it works.
Open the file *HelloWorld.html* and make it look like the following:
<div class="HelloWorldShift">
Drag me!
</div>
Now for our CSS file. Open *HelloWorld.css* and make the font-size a little bit bigger:
.HelloWorldShift { font: 32px verdana sans-serif; position: absolute; padding: 5px 10px 5px 10px; color: #FFF; background-color: #F63B02; left:200px; top:200px; }
Refresh the sandbox, and create a new HelloWorld shift. You should see that your changes have taken.
You've probably been wondering how HelloWorld can auto-magically save itself to the database. This is because all shifts have an *encode* method. By default shifts encode their position. Instead of using the default *encode* method, let's provide our own. *encode* lists every property that you want to persist. Here we want to store a summary (useful because summaries are displayed in the console) and the position of a shift.
var HelloWorldShift = Shift({ setup: function(json) { this.setPosition(json.position); this.makeDraggable(); this.save(); }, encode: function() { return { summary : this.element.get('text'), position : this.getPosition() }; } }
When you call save in your code, ShiftSpace calls your shifts encode method to figure which properties to store in the database.
encode like setup are not methods you call yourself. ShiftSpace will call these methods for you at the proper time. While this approach may seem odd at first, it really frees you up to concern yourself only with the actions and behaviors you would like your space to provide.
Notice that when saving the summary property, we write this.element. ShiftSpace automatically attaches your interface to your shift instances in the property element. Here were simply using standard MooTools functions to grab the text out of the shift's div.
Test your space to make sure everything is ok.
Before moving on let's make it so that you can change the text of the shift by double clicking on it.
var HelloWorldShift = Shift({ setup: function(json) { if(json.summary) this.element.set("text", json.summary); this.setPosition(json.position); this.makeDraggable(); this.element.addEvent("dblick", this.changeMessage.bind(this)); this.save(); }, changeMessage: function() { var text = prompt("Please enter a new message:", this.summary); this.element.set("text", text); this.save(); }, encode: function() { return { summary : this.element.get("text"), position : this.getPosition() }; } });
Wow, that made code quite a bit longer. Let's break it apart:
if(json.summary) this.element.set("text", json.summary);
This means only set the value of our element to the value of json.summary if json.summary has value. For new shifts, summary is null, for HelloWorld shifts that have been saved, this has a definite value.
this.element.addEvent("dblick", this.changeMessage.bind(this));
This add a double click event handler to our shift. When the event occurs we want to have our *changeMessage* method called. Because of the peculiarities of JavaScript we have to bind this function to our shift. Event binding while not particularly complex is a conversation outside the scope of this tutorial. We recommend that you read on existing literature on the web on this topic.
The changeMessage function should be quite clear. It prompts the user for some text, updates the UI, and then saves the shift.
Finally the *encode* method set the value of summary to the current value of the text inside the shift's div element.
var HelloWorldSpace = Space(); var HelloWorldShift = Shift({ setup: function(json) { if(json.summary) this.element.set("text", json.summary); this.setPosition(json.position); this.makeDraggable(); this.element.addEvent("dblick", this.changeMessage.bind(this)); this.save(); }, changeMessage: function() { var text = prompt("Please enter a new message:", this.summary); this.element.set("text", text); this.save(); }, encode: function() { return { summary : this.element.get("text"), position : this.getPosition() }; } });