Frame-Busting Gadgets

In the questions after my @media ajax talk, Simon Willison asked about frame busting. If gadgets sit inside iframes, what’s to stop them from busting the frame, i.e. replacing the container with another website. I notice he made a similar comment when OpenSocial came out. If a gadget can cause iGoogle to go away in place of another website, it could for example launch a phishing attack by presenting a mock iGoogle login page (“iGoogle has timed out. Please re-enter your username and password.”).

At a technical level, there is actually nothing to prevent this. There’s no magic in the container. IFrames are about as good as it gets in modern browser for taming the gadgets, but there are still problems with that model, and one of those is the ability for iframes to bust out. I decided to create a demo of this. The gadget is here. You can drop it into iGoogle and see for yourself. Video below:

[kml_flashembed movie="http://picupper.com/video/framebust.swf" height="700" width="400" /]

(Parenthetically, the video is vertical. Why are videos always horizontal on the internets? It’s a computer, not a TV! It should be just as easy to embed an dodecahedron video if that’s what I fancy at the time.)

At this stage, there’s no technical way around this. One possibility would be for the container to do something in the rarely-used onexit() method, which runs just before the new page is loaded. However, as I learned with WebWait, which is also vulnerable to frame-busting, there’s nothing you can really do at that stage, and you can’t determine if the exit is happening because of a frame-busting event as opposed to the user just typing in a new URL. I suppose onexit() could still be used to log info to the server – if you knew all the times the container exits and which gadgets were present at that time, you might find certain (malicious) gadgets were present more times than you’d expect if they were present randomly. Although, I’m not sure about how reliable it is to make an Ajax call in the onexit(). (In this case, though, it would only need to work some of the time.)

In the future, the technical solution is Caja, if it proves to be production-ready. Caja ensures a safe subset of Javascript, so a container like iGoogle would only ever serve a gadget if it was verified to be safe.

Until then, we have to rely on “social” mechanisms. i.e. user comments in the catalogue and manual checking by container staff. A while ago, iGoogle made it harder to add a gadget directly by URL – you basically have to use the catalogue unless you’re a developer. So the catalogue is effectively acting as a whitelist – once found to be malicious, a gadget could be removed. This isn’t simple though – gadgets are dynamic and the catalogue is effectively just a list of URLs. A malicious author could have their gadget added to the catalogue and then change it, so the gadgets need constant review – a highly ineffective process.

I also mentioned in the presentation that “html” type gadgets are more recommended than “url” gadgets. This is partly because with html gadgets, the container at least has some idea of what’s happening inside the gadget – though not entirely, since the code can still reference external scripts and services. With “url” gadgets, what happens is entirely controlled by an external server.

OpenSocial-Tiddlywiki Integration

Go straight to the demo.

Google Gadget TiddlyWiki plugin - a tiddlywiki macro to embed google/opensocial gadgets

I’m at the Osmosoft hackathon and finally got an opportunity to experiment with OpenSocial-Tiddlywiki integration. Specifically, how to embed OpenSocial gadgets in Tiddlywiki. I paired (trio’d?) up with Stuart Race and Tom D’Roza on it. We managed to get something useful up in an hour or two, which is testimony to the simplicity of both OpenSocial and Tiddlywiki. It’s only proof-of-concept for now and for some reason doesn’t work in IE.

Technically, it’s iGoogle integration, not OpenSocial. The gadgets are iframes pointing to the iGoogle gadget server (gmodules.com). That’s because right now, it’s not clear there are any OpenSocial containers that will serve out gadgets externally in the same way. Of the various live OpenSocial containers, there is really scant information about how to embed the gadgets in an external page. Suffice to say, the code here is virtually identical to what you’d need to embed an OpenSocial gadget – it’s simply a matter of changing the endpoint URL from whence gadgets are served.

One concern about this is whether or not Google will be cool with us pointing directly to the iframe. Technically, you’re supposed to embed gadgets using a script tag, which will document.writeln() the iframe and its source. I vaguely recall a time last year where we were playing around with direct calls to the gadget, and gmodules saying no. This is possible in theory, if the server was attempting to match each iframe request with a previous corresponding script call. However, I am probably dreaming. It seems to be working fine. In any event, Shindig has no constraint like that, so if we extend this to point to other opensocial servers, or something spun up by an individual, it should work fine.

Usage

With the plugin installed, it’s simple to use:

<<gadget http://abowman.googlepages.com/spider.xml >>

or with options:

<<gadget http://www.btinternet.com/~tdroza/gadgets/twitter/index.xml height:400 width:500 border:0 prefs:"up_max_items=5&up_username=downingstreet&up_feed=http://twitter.com/statuses/user_timeline/" >>

If you’re familiar with opensocial you’ll realise that the height, width, and border are options to the gadget server telling it how to render the gadget and its chrome; whereas the prefs string contains preferences which the gadget itself gets. All this is optional.

Plugin Code

We began with the Shout plugin whose code I’ve already documented. It was only a matter of creating an iframe and pointing it – by setting its src property – to “http://www.gmodules.com/ig/ifr?url=”+params[0]. And that worked fine, and we had gadgets inside tiddlywiki.

The hard part was parameters, took a little investigation to work out how to handle key-value pair parameters. The plugin code below serves as a simple example for how it’s done. It’s very similar to the very cool Ruby/Rails idiom which has also been adopted by Javascript libraries like Prototype (obviously, given its Rails association) and JQuery. i.e. mandatory params followed by a hash of optional params. Here, the URL is mandatory, and its proceeded by a set of key-value pairs.

The plugin code:

javascript
< view plain text >
  1. config.macros.gadget = {};
  2. config.macros.gadget .handler = function(place,macroName,params, wikifier, paramString) {
  3. var elem = createTiddlyElement(place,"iframe",null,"greeting","");
  4. var p = paramString.parseParams(null, null, true);
  5.  
  6. elem.src= "http://www.gmodules.com/ig/ifr?url=" + params[0] + "&" + getParam(p,"prefs","");
  7. elem.height = getParam(p,"height","200");
  8. elem.width= getParam(p,"width","300");
  9. elem.style.border= getParam(p,"border","1");
  10.  
  11. place.appendChild(elem);
  12. }

That’s it.

Applications

Why would you want to embed a gadget in a tiddlywiki, aside from proof of concept? Well, tiddlywiki is a platform whose applications are many and varied; OpenSocial integration simply enhances the platform so that developers can select from a rich palette of existing gadgets. For example, if your tiddlywiki involves trip planning, pull in a Google Maps gadget.

It also makes for an extremely easy way to collect up a bunch of related gadgets, and optionally have a conversation around them. For example, you could compile your favourite game and toy gadgets into a game tiddlywiki. Remember tiddlywikis are single files, so this becomes a single file game.html which you can mail around, keep on your hard drive, or post to a server. A related usage would be a single tiddlywiki where all gadgets are the same type, but with different preference strings. For example, 10 weather gadgets with different “location” settings.

OpenSocial: A Beautiful Platform for Server-less Web Development

It’s belatedly dawned on me how OpenSocial makes a great server-less Ajax platform. When you create an OpenSocial gadget, you’re building a lil Ajax app that performs much coolness that would normally require a server, but doesn’t. Effectively, you’re delegating the duties of the gadget’s host environment. All you have to do is write a single XML file and host it somewhere. In fact Google Gadget Editor gives you an editor to write it in and a place to host it.

In fact, this is so good that if I was teaching someone Ajax in 60 minutes or less, I would consider getting them to write a gadget. It’s that simple. Previously, I might have got them to write a static HTML file, with embedded Javascript and CSS, but now they can do the same thing and benefit from server-side features too, features they never had to install. This is like getting the usual benefits of the DOM and the Javascript API, but with much more. You’re getting both a set of APIs, just like when you use JQuery or Prototype, but you’re also getting a server which many of those APIs rely on. So it’s a true platform.

By the way, I’m assuming you’re using XML content type, not URL. XML content type is the way forward, especially as we move to a Caja world. XML gadgets will get you the richest functionality. URL gadgets are only suitable for legacy concerns, and in some cases, accessibility.

So you’re using XML content type, which means the entirety of your Ajax app lives in one file. What does an OpenSocial platform provide to your little XML gadget spec?

  • Persistence. The most important thing is you can save application data. You can serialise any state you care to persist, and then store it as a hidden user preference. This is really neat. It means you can write a TODO gadget, for example, and ensure all the TODO tasks will be saved, but without having to store them on your own database and without having to build a persistence layer around it. And of course, the platform will (theoretically) provide the necessary security to ensure users only see their own tasks.
  • Preferences. You can easily let users customise your app via the preference API. For free, you get form fields to let users state their preferences, with drop-downs for enumerated types. And of course, the preferences are persisted without any effort on your part.
  • Content Fetching. It gets even better. On-Demand Javascript is often bigged up as the way to get data from third parties. But thanks to OpenSocial’s remote fetching APIs, it’s just as easy to grab content via the containers Cross-Domain Proxy. This means you can get any internet content and call any API, not just those specifically designed for cross-domain browser calls. There are also value-adds here, e.g. caching, scheduling periodic updates, converting feed data of any format into a consistent JSON structure.
  • Identity and Social Networking. Ah yes, the almighty “social” in OpenSocial. On the right platform, your server-less Ajax app can get info about the page owner and the page viewer, and their friends. Friends and social stuff and knowing whose page it is, that’s cool and all. But what’s really exciting here is much simpler than that – it’s simply IDENTITY. What matters most is: With a single API call, you get an ID for the guy viewing your gadget!!! You didn’t have to handle registration, password reminder links, etc. etc., and go through all the associated security questions around it. All the usual stuff you have to do if you want to know who’s using your application. It’s all *free* to you, gadget developer. (Downside is your company doesn’t “own the user”, so your gadget will never get you pina coladas on the beach at noon and an environmentally-conscious hybrid vehicle to sip frappachino grandès in.) With this user handle, you can also save a hashmap of information about the user, persisted by our friend the server.
  • Many other services. Each platform is free to provide any number of features beyond the required API; this is how platforms compete against each other in the OpenSocial world. “Feature” is actually the term used for a particular set of browser and server services, e.g. “dynamic height” – the ability for a gadget to update its height – is a standard OpenSocial feature. Notifications – the ability for gadgets to add little notes to the top which the user must manually clear – well, that’s a custom feature iGoogle provides but others don’t. So anyway, there are lots of these features and your gadgets get them for free. In most cases, they are just libraries which you could also get for free by using Scriptaculous or whatever…but still, with OpenSocial, it’s really, really, easy! No download or installation. (Although it must be said that with library CDNs like Google’s new effort, you can also use many Ajax libraries without installation too. The difference here is that at least some of these features are tied to server-side services as well.)

So, these days, OpenSocial may well be the easiest way for a newbie to learn Ajax, and for any developer to get an Ajax app up and running. I actually think we need more tools and services to allow standard Ajax apps – not gadgets – to get up and running fast too. After all, the UI in OpenSocial is based on a widget/gadget model, and this is a mini web app running on a bigger page. Nowadays, we have canvas gadgets, which are bigger, but still not so big and run inside another web page. What if you took the same cloudish platform principles and applied it to a big old Ajax app, occupying the entire page and with its own URL (though probably coming from the platform’s domain). You can sort of do that already by looking at the content of the gadget iframe, but it’s not designed for that purpose…and if it was, you could do some interesting stuff.

For instance, I envisage a simple-to-use cloud storage system based around principles of Persevere and CouchDB, and for limited use, it could even allow anonymous access. I’ll perhaps demo all this at some stage.

Tools Europe – Pre-Workshop Preparation

I have the honour of delivering a keynote at the Tools Europe conference in Zurich next week, as well as at the “Mining Web 2.0 Patterns” workshop, which, as you can tell from its title, I’m looking forward to participating in. The workshop chairs are Dragos Manolescu and Joe Yoder.

The keynote is on OpenSocial, Gadgets, and Design Patterns; and I’ll have more to say about it later. I believe it will be recorded too. For now, I’m using my blog to post my response for the pre-workshop preparation.

Sites and materials relevant to my presentation

Questions:

  • Which features make the gadgets easy or hard to use, and how might the gadgets be improved?
  • At UI level, which best practice patterns are apparent?
  • What changes to the platform would improve user experience?

Sites and materials relevant to other workshop tracks

Site Navigation:

Services:

What is OpenSocial?

I just realised there’s no good executive summary for OpenSocial. Every resource fluffs about the “social” aspect and forgets about the UI aspect. The UI aspect, essentially a gadget specification, is just as important as the social aspect, notwithstanding its absence from the “OpenSocial” brand name. I’m not a fan of the name “OpenSocial” for this reason, though I acknowledge it does have more attention-grabbing bling than “open social widget framework 1.0″. In any event, it’s regrettable that most commentators gobble it up hook, line, and sinker; as evidenced by their almost exclusive focus on the social angle.

With no further ado, here’s my attempt at a one-paragraph summary of OpenSocial …

OpenSocial Executive Summary

OpenSocial is a standard for “mini” web apps, called “gadgets”, which are designed to be embedded other websites. The standard informs developers who wish to write portable gadgets, i.e. those which work in any OpenSocial environment; and likewise, it informs developers who are creating such environments. It defines an XML format for applications, typically containing the user interface (HTML/CSS/Javascript) as well as metadata, e.g. author, gadget size, and preferences. In addition, OpenSocial defines a number of APIs, so that gadgets can invoke services such as changing the gadget height and fetching remote content. One particularly important class of APIs are those of a social nature. These enable a gadget to access data and run services related to the user who is viewing the gadget, or the user whose web page the gadget is embedded in. For example, the gadget can – subject to security settings – find a person’s name and location, traverse their social network, and invite them to install an application. Access to social data is not limited to gadgets, however, as OpenSocial also provides a RESTful variant of the social API, suitable for any kind of net-enabled client. OpenSocial was launched by Google in November, 2007, and is to be managed by the non-profit OpenSocial Foundation.

Relative Paths and On-Demand Calls in Gadgets

A problem with the current opensocial gadget spec is that there’s no relative path support. This means you end up hard-coding any references to Javascripts, CSS stylesheets, images, and services which are distributed along with your gadget.

This is not good. For example, you may have a “prod” setup and a “dev” setup. While developing, you will have to hard-code <script> tags and so on to hit the “dev” location, but then for production, you will want them pointing at your scripts in the production location. Likewise, you might want to ship the bundle to someone else for them to host on their own network.

You can deal with it using a pre-compiler tool – you know, using sed-like token substitution to piff in the right location. But a pre-compilation step is a messy compromise – I just want to distribute the code and be done with it. Another solution would be to output the gadget spec from a script, which would let you solve the problem in one of two ways: (a) inline common Javascripts and stylesheets so that you don’t even need to link to them; (b) piff in the right location on the fly. Again, this is not ideal. It introduces a new server-side language and demands the spec server supports it. My aim here is simple distribution of gadgets – as long as you can host a tree of static files, you can serve my gadgets.

The optimal solution right now is far from ideal, but is the best way I know to do it. You use On-Demand Javascript (and on-demand CSS and on-demand <insert resource type here>). First, you work out the gadget spec location, then you manipulate the URL to find the required Javascript, and then you pull it down using DOM manipulation.

I’m using a compressed version of something like this:

javascript
< view plain text >
  1. var gadgetURL = _args()["url"];
  2.     function loadScript(scriptURL, onLoaded) {
  3.       var baseURL=gadgetURL.replace(/[a-zA-Z0-9_]+.xml(?.*)?/,"")
  4.       if (scriptURL.indexOf("http")!=0) scriptURL = baseURL + scriptURL;
  5.       if (debugMode) scriptURL+="?" + (new Date()).getTime();
  6.       var script = document.createElement("script");
  7.       script.src = scriptURL;
  8.       if (onLoaded) script.onload = onLoaded;
  9.       document.body.appendChild(script);
  10.     }

It’s partly based on a mailing list comment from Arne Roomann-Kurrik. Massaging further, I end up with the following boilerplate block which must be cut-and-paste into each gadget to bootstrap reuse:

javascript
< view plain text >
  1. _IG_RegisterOnloadHandler(function() { var script = document.createElement("script"); script.src = _args()["url"].replace(/[a-zA-Z0-9_]+.xml(?.*)?/,"") + "../core.js"; script.onload = initialise; document.body.appendChild(script); });

After dropping this at the bottom of my gadget, I know that (a) ../core.js will be pulled down and executed – it is relative path from wherever the gadget came; (b) initialise() will be called once core.js has been loaded. Each of my gadget’s has an initialise() function which does gadget-specific initialisation. core.js is a common library and also happens to include loadScript() in case I want to pull down further Javascripts, and also loadStylesheet() so I can grab a stylesheet with relative path.

All this is not at all ideal, for several reasons:

  1. For all the benefit of neatly using a separate Javascript file, you have to cut-and-paste boilerplate code into every page! But at least the boilerplate won’t have to be changed often.
  2. Performance will suffer as the script is loaded later than it should be.
  3. It relies on the “url” being passed into the gadget; to my knowledge, this is not something you can definitely assume will happen, i.e. it’s not mandated by the opensocial standard that the gadget receives a parameter called “url” identifying where the gadget came from.

I have requested on the opensocial spec mailing list to provide direct relative path support and the response has been positive, hopefully we’ll see it soon, thus rendering large parts of this post obsolete. The solution looks to be rather neat – injecting a <base> tag to establish a base URL which all relative paths work against.

Testing OpenSocial Apps – Current Challenges

At present, the OpenSocial containers are new and the whole process is still quite difficult from a developer’s perspective. These are unfortunate barriers to adoption which the containers could overcome with some redesign.

The challenges at present are:

  • Manual signup and approval process required. Even to get onto the sandbox area, you have to go through a manual signup and approval process, which usually takes a day or two. A human is in the loop verifying your details. At that time, the developer may have lost interest, or the mail may never get to them.
  • Lack of test accounts. The sandbox accounts usually can’t interact with non-sandbox accounts – that’s what makes them “sandboxes” and this is a wise policy. However, what do you do, as a developer, when you want to test with a large group of friends? You could friend other developers, but testing is going to get a little tired if you have to keep asking them what happened. The problem is the manual signup process – you have to add new users with fake details for approval by the container – weird! On Orkut at least, you can also invite friends from your test account, so it’s possible. And, oh yeah, I hope you get a kick out of CAPTCHA. You’ll be filling in a *lot* of CAPTCHA forms as you build up your social network of imaginary friends! One to create the account, one to verify email, one for good luck here, one more just because why not. And that’s for each user on each container! If I was running these containers, I would make it even simpler and just create an initial block of 10 fake friends (some friends with each other…pick your favourite soap opera) and let the user seamlessly add new ones too.
  • Older versions and Missing Features. Ning and Plaxo are hosting OpenSocial 0.5, whereas 0.7 has been out for a while and 0.8 is about to come out. I can’t blame them for not upgrading all the time, but it still makes development more difficult. As for missing features, I noticed this with Hi5. It’s a good implementation, but still missing a critical feature – UserPrefs. This is just the multi-container nature of OpenSocial.
  • Slow code-test cycle. When testing with a container, you have to change the gadget on the server and the container will then reload it and render it. This reloading process will always take some time, but the container can do as much as possible to eliminate any other delays. Unfortunately, they don’t make it easy at present. I refer specifically to caching. You obviously don’t want your gadget to be cached during code-test cycles. Caching is usually enabled by default, even in the sandbox. That’s kind of dubious – you would think a sandbox should load the gadget each time. But okay, I can accept that decision as it’s useful when you’re testing the gadget 100 times not to be re-downloading it all the time. However, it’s usually not clear or documented how to suppress caching when you want to. Again, the containers should be making it dead simple if they want to encourage development…how about a caching on/off checkbox somewhere in the gadget chrome or settings menu?

There is a lot the containers can learn from Facebook, and they will need to for OpenSocial to really take off and compete against it. For comparison, here is how Facebook deals with the issues above:

  • Manual signup and approval process required. Facebook makes this completely automated. You create a normal Facebook account and simply visit a special URL to make it a developer account.
  • Lack of test accounts. It’s easy to create test accounts in Facebook – you just keep creating normal accounts and flipping them to become developer accounts by visiting that special URL.
  • Older versions and Missing features. With Facebook, there is only one implementation, so only one definitive version of the API. There’s nothing OpenSocial can do about this directly. It’s simply a consequence of the “Write Once, Run Many” aspiration and the only way for the community to deal with it is to be better in other ways, and to at least be very explicit about what each container does and does not support.
  • Slow code-test cycle. This doesn’t arise in the same way because the model is either based on an iframe directly to your site, or FBML you enter into a form. The OpenSocial gadget model – an XML sitting on a server somewhere – is neater as there’s no form involved; everything’s encapsulated in the XML file. However, it does introduce the whole question of caching and the containers should be doing all they can to simplify the development process to that end.

I’m a great believer in the OpenSocial vision; hence, I hope the containers will be working to minimise these obstacles. Right now, it’s okay for professionals, but there are enough hurdles there to hold back an army of potential hobbyist developers from uneashing their creativity on this platform.

Widget/Gadget Containers: What are they good for?

Ajax, AjaxPatterns, Gadgets, OpenSocial, Shindig, Web, Web 2.0, Widgets

Background

Widgets are small “mini websites”, typically self-contained blocks of content, on a larger web page (with Ajax Design Patterns, I referred to them by the nom du jour Portlets). They are used in a couple of ways:

  • Embedded in a normal web page. For example, my blog currently contains a BBC weather widget and a “Twitter Badge” showing my latest tweets. Widgets embedded in this way are combined by the publisher, often with some manual HTML coding (script tags), and are usually a sideshow affair.
  • Combined within a widget container (aka “widget portal”, “Ajax homepage”). Websites such as iGoogle and NetVibes are primarily designed as widget aggregators, allowing an end-user to construct a personalised page for themselves. They are the Ajax/Web 2.0 successors of the “My <whatever>” hype (My Yahoo!, My Excite!, etc.) of the mid-to-late ’90s. To some extent, a social networks like Facebook fits into this category too, with the proliferation of applications available to users to embed on their homepages. And as Facebook in particular illustrates, widget containers are not always private “productivity tools”, but may also be available to a user’s friends or the general public. Indeed, the more conventional widget containers have recently started allowing users to make their public portals, which starts to move them in the territories of CMS and social networking.

Well, this is an article is about widget containers. Specifically, I’m currently compiling a list of typical features you’d expect to see in widget containers, so if this post sounds stream-of-consciousness, well, it sort of is.

Anatomy of a Widget (well, Gadget and OpenSocial) Container

A good place to start is the breakdown of functionality for Shindig, the new Google-supported Apache project to build a reference implementation for the OpenSocial standard. OpenSocial is heavily intertwined with the whole idea of widgets and widget containers, since it’s basically Google Gadgets + standardised social networking APIs. Hence, Shindig is essentially the high-profile open-source project involving a widget container. Shindig has been broken into four parts:

  • Gadget Container JavaScript — core JavaScript foundation for general gadget functionality (read more about gadget functionality). This JavaScript manages security, communication, UI layout, and feature extensions, such as the OpenSocial API.
  • Gadget Server — an open source version of gmodules.com, which is used to render the gadget xml into JavaScript and HTML for the container to expose via the container JavaScript.
  • OpenSocial Container JavaScript — JavaScript environment that sits on top of the Gadget Container JS and provides OpenSocial specific functionality (profiles, friends, activities).
  • OpenSocial Gateway Server — an open source implementation of the server interface to container-specific information, including the OpenSocial REST APIs, with clear extension points so others can connect it to their own backends.

That’s a very useful overview, though I’m looking more at specific features which generally cut across at least some of these parts. For example, gadget preferences. These are part of the container Javascript because there is a UI to change the preferences, they are part of the gadget server because it must initialise the gadget according to preferences, and they are part of the server because they must be persisted.

Feature List

First cut at a feature list (# indicates not directly available in iGoogle)

Gadget Preferences

  • Preference defaults
  • User can set preferences
  • Publisher can set preferences when embedding widget on a page
  • Preference variable types: string, enumerable (set by dropdown, set by combobox), boolean, list, location, etc
  • Preference persistence: by database against session vs. in cookie
  • Preferences persisted for anonymous user (Lazy Registration)
  • Gadgets can access preferences via API, consistent access regardless of content type and embedding model
  • # Gadget can be notified of preference changes, so that it’s not necessary to reload the entire gadget/page after each change

Gadget Appearance

  • Gadget appearance customisable by publisher
  • Gadget appearance customisable by user
  • # Round corners, shadows, background images (e.g. Schmedley has all of these)

Gadget Content Type

See Widget Content Type article * HTML – from container provider’s domain * URL – from gadget provider’s own domain * # Inlined – embedded on container. This implies a security model, e.g. Caja

Container Appearance

  • User can change gadget skin, header, footer, background, widget preferences via constrained mechanism (ie can’t change everything; e.g. config file or UI)
  • Publisher can change look and feel via HTML/CSS
  • Gadget themes available, with gallery, for pre-defined configurations
  • Animation used for features such as preference setting and expand/collapse of widgets
  • Drag-and-drop shows preview of page appearance after drop

Container Layout

  • Multi-column (usually 3) vs. freestyle
  • Gadgets can be dragged around the page, displacing other gadgets
  • Tabs allow for multiple layouts
    • Tabs can be renamed
    • Gadgets can be dragged into tabs

Gadget Manipulation

  • Gadgets can be added
    • by URL (with security warnings etc)
    • from Gallery (see Gallery below)
    • by cloning a gadget on user’s page or someone else’s public page or external page
  • Gadgets can be removed
  • Can limit singleton gadgets to one instance per container

Gadget Gallery

  • Gadgets displayed and rendered with metadata embedded in gadget spec, e.g. thumbnail image, author, etc.
  • Gadgets can be browsed by category, date added, etc.
  • # Users can tag gadgets and gadgets can be browsed by tags; tag cloud; etc
  • Users can rate gadgets
  • # Users can recommend gadgets to their friends
  • Users can comment on gadgets

Gadget-To-Gadget Communication

  • Gadgets can communicate with each other (Google PubSub)

Gadget Size

  • # Gadget content can be expanded and collapsed (BBC Beta Homepage)
  • Gadgets can be dynamically resized

Content Sharing

  • Container can be made public (what happens to personalised widgets?)
  • Container can be shared with “friends” (how are friends decided)
  • Users can invite/permit/disallow friends to use their container

Gadget Services

  • Proxying service
  • Caching service (extends proxying service)
  • OpenSocial (or generic social networking) service
  • # Advertising service – Gadgets can serve as ads with revenue model
  • # Financial service – Gadgets can charge for services (subscription, one-off, etc.)

Admin Functions

  • Admin function to tweak gadget/theme rankings, scrutinise/moderate/eliminate gadget/theme submissions, etc
  • Admin function to view metrics, e.g. number of page views, popularity of gadgets, back-end service usage (e.g. proxying and OpenSocial calls)
  • Admin function to manage users (provide support, ban, etc.)