Adventures in Opera Unite

Opera recently released Opera Unite claiming to reinvenet the web. I have used Opera Unite the latest week, and been playing around developing for it just as long. Heres what I think about it and have learned so far.

What is Opera Unite

Opera Unite is the latest member in the Opera-family and brings some new ideas to the table. Opera calls it “Reinventing the web” – those kinds of claims will of course provoke a lot of people (especially the know-alls). It does perhaps not reinvent the web, but it does give the users more power and controll of their own data again, as was intended in the – oh so far away – beginning of the web

Opera’s idea is that you should be able to share your own data easily and with whoever you want, and to achieve this Opera has bundled the browser with a web-server. The applications you can share with Opera Unite is closely related to the Opera-widgets, but gives a little more power – i.e. access to the server and file-system through JS. So by using standard web-technologies (SVG, HTML5, CSS, JS…) you can now pretty easily develop server-applications as well.

A popular rant-attack is against the fact that you have to create an opera-account to get this up and running, as Opera uses a proxy (operaunite.com) to organize the traffic and getting through your router. A lot of people complain of this as “Opera monitoring our data” (like this isn’t possible for Google and Facebook already) – so listen: as long as you’re connected to the Internet, your data will pass through quite some servers no matter what. Though luck. Now, if this is a service that will stand the test of time and users, I will expect the possibility for users to either run their own proxy-services or bypass it all together.

Now, what concerns me the most right now, is the security-aspect. A lot of people will by running Opera Unite give any bad people out there (yup, I know you’re out there!) one more frontier to fight on – they can now attack the Opera Unite-server running on your computer, as well as attacking the browser. This means that Opera has to be extremely thorough to eliminate any security-issues that surely will come.

Beside of this, I’m very excited in seeing how this will evolve. They have released some developer-resources already, and I’m sure more will come – so I’m eager to see how developers out there will develop creative tools to run under Unite.

Developer-experiences so far

As this is still in alpha there are a lot of issues I assume will get better when getting closer to release-date. This is meant as tips to other developers more or less new to Unite-development.

Initiating your app

You will need a config.xml, index.html and a javascript-file to get started. Your app can have a setup like this:

See the config.xml-link for details of the setup of this. The index.html can be a very simple HTML5-file, ie like this:

<!DOCTYPE html>
<script src="script.js"></script>

Now we’re getting started, I’ll give an excerpt of a script.js-file, and give an idea of how it can look:

window.onload = function () {
    w = opera.io.webserver
    if (w)
        // the default page, kind of like index.html : )
        w.addEventListener('_index', showMainPage, false);
        // And two common
        w.addEventListener('newEntry', newEntry, false);
        w.addEventListener('editEntry', editEntry, false);
    }
}

function showMainPage(e) {
    var response = e.connection.response;
    var myhtml = "<!DOCTYPE html><head><title>AppTitle</title>/head><body><h1>Welcome!</h1></body></html>";
    response.write(myhtml);
    response.close();
}

– As you probably can see, we are adding event-listeners to the webserver to listen for actions, and every page/action of an application requires it’s own method which takes care of the logics and displays any contents by writing the necessary HTML. This is good explained in Opera’s documentation so I won’t dive further into that here.

What I’d rather like to mention is those things that will “crash” your app:

Every action-method must accept a named argument for the event-object – which in turn will give access to the response and request-objects. If not specifically named, then the app won’t load.

You will also have to write something (response.write(“something”)) _and_ close the response (response.close()) in the current action, otherwise the app won’t load.

Markuper

Opera does also give out a template-helper, which is just a JS-library which will come handy. I haven’t found a place that distributes it in an organized manner, but you may download it as a part of the barebone-example in the previous link, or you may dissect any of the existing apps (download the .us-file, rename to .zip and extract). It seems there are some different versions out there so beware.

The templater doesn’t currently seem to allow variables in attributes

This is cumbersome, as I’d like to do something like this:

<div id="content" data-import="templates/{{page}}.html"></div>

I assume this will be fixed, as it seems – when skimming through the library – that it should have been taken care of in the XPath-expression looking for the variables. I’m working on a patch.

Update:
Ref comment from António Afonso, it seems that it’s only the data-attributes (used for importing, iterating through lists etc), that were affected of this. The “patch” is simple:

  1. Open the template.js
  2. Find the method “this.parse = function( data )” (line 1439)
  3. Switch the order of the this.parseDataAttributes( data ) and this.fillValues( data )-calls
  4. Save and go on!

Imported files through the templater can’t be empty

If you try do something like this:

<div id="content" data-import="templates/content.html"></div>

and the “content.html”-file is empty, then the app won’t load :p.

404 Not found

If you get the “404 Not found – Resource not found” it’s propably a JS-error. Unfortunately you won’t get any better debug-messages by now if you haven’t implemented it yourself (see the “Notifications”-part of this post). Take a close look at your code, and I assume Opera will fix integration with dragonfly in upcoming releases.

POST and GET

GET: e.connection.request.queryItems[‘id’][0]

POST: e.connection.request.bodyItems[‘title’][0]

Custom fonts

@font-face {
    font-family: MyFancyFont;
    src: url('fonts/MyFancyFont.ttf');
}
/* Use like this: */
body {
    font-family: MyFancyFont;
}

This is pretty obvious of course, as the new Opera-engine, Presto, has support for a lot of snacks when coming to HTML, CSS and SVG – and hopefully soon more JS-snacks will come as well.

Notifications

You will more than once want to give some kind of notifications, either to yourself as developer or to the end-users. Notifications can ie be debug-messages, or event-messages like incoming message in an IM-app.

opera.postError() will let you post a message which only will appear in the error-console.

widget.showNotification() will pop up a message in the lower right corner of the screen. It’s possible to attach a callback-function which will be called when/if the user clicks on the message.

void opera.postError( <String> message)
void widget.showNotification( <String> message, <Function> callback )

Quick tips

If you want to test any changes made to the javascript-files, you will have to restart the app. If you’ve just changed any HTML-files ie for the Markuper, you can just reload the page as you’d normally do. If none of them seem to work, you might have to remove the app and install it again. Remember to empty the trash as well before installing!

Packaging the app

The app-packages are simply zipped folders, renamed to the prefix “.us” (Unite Service), and to install it it’s only to drag-drop the file onto an Opera Unite-able browser, or if you want to share it online, give it a link like this:

<a type="application/x-opera-uniteservice" href="url/to/myapp.us">Install myapp</a>

Possibly related reading

Be Sociable, Share!

8 Comments

  1. Arve says:

    Just a quick correction: You don’t neccessarily have to register an event listener for every URL you want to be addressable in your app. If you have shared a folder for making available, and the path matches, the static file will be served, if no handler picks it up.

    Additionally, there is a catch-all request handler you can listen to, ‘_request’, which is dispatched after the more specific request.

  2. António Afonso says:

    Hi there,

    “The templater doesn’t currently seem to allow variables in attributes”:
    The “patch” you’re looking for is switching this.fillValues(data) with this.parseDataAttributes(data) on the this.parse(data) function, which will make the variables being parsed before all those data attributes.

    “Imported files through the templater can’t be empty”
    This, however, is a bug.

  3. michaelo says:

    Hey António,

    Thanks for your comment. Ah, I see – I hadn’t tested using variables in standard attributes which, turned out, worked great as it was.
    Thanks for the tip which worked perfectly.

    Is there any reasons to keep the order as it was originally – read: will there be any side-effects as you know by switching?

  4. michaelo says:

    Hey Arve,

    That’s a good tip indeed – I didn’t think of that kind of use for it (just CSS and JS etc). As far as I can see this apply to the public_html-folder. Anywhere else? I did a quick test with the fileio but I assume it’s only through the app-specific JS you can work with that – right?

    Thanks!

  5. António Afonso says:

    michaelo:

    “will there be any side-effects as you know by switching?”
    Depends on your code actually… this way if you have a data-list each {{}} inside it will be intact and only parsed by the parseDataAttributes function (but I would say that in normal conditions you won’t get any problem).
    I will change this in the future so you don’t have to worry about that (right now the fillValues is getting -all- {{}} elements, doesn’t stop at a data-list for instance)

    Regarding arve’s comment about the _request event handler, keep in mind that after listening to this event static files -won’t- be served automatically anymore, you’ll have to explicitly response.closeAndRedispatch() for that to happen.

    PS: already fixed the “Imported files through the templater can’t be empty” in our internal version, you can patch this by adding “if( !nodes ) { return; }” before the “if ( nodes.length )” on the importTemplate function.

  6. michaelo says:

    @António

    Ok, I see – that does of course make perfect sense. Looking forward to your next release! Do you have, or are you going to have, a sentraliced place for all Opera-libraries? (I can’t seem to find any as of now)

    Regarding the _request event handler:
    That’s something to keep in mind.

    Let’s now say I want to dispatch to the static content as long as there exists a matching file, and otherwise call “_request”-event – I had to create a function which used fileio and try to open the file, catch any errors, and then call closeAndRedispatch() only if successfully open. I’ve read through the documentation but can’t seem to find any sleeker way – what do you think?

    Regarding the import-bug:
    Great! I really appreciate the quick feedback and follow-up.

  7. António Afonso says:

    We’re still discussing how to deliver libraries 🙂

    Yes, you are right about the static file delivery. What you can also do, is to put all your static files inside a specifc directory, for instance static/, then you just need to check if the request is for some file under that directory and closeAndRedispatch.

  8. […] at the bottom of this post (template.js) if you want to allow variables in the expressions. See my previous Unite-post for […]

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>