There are a lot of painful implications to how requestNavigateTo works
within OpenSocial that should be addressed asap. Failure to fix these
issues will hinder developers and business models on the platform.
Here is my suggestion.
Currently applications emit at the server or rewrite on the client
simple links into complicated javascript calls. For us in iLike,
instead of generating:
<a href="/ilike/artist/Led+Zeppelin">Led Zeppelin</a>
we find ourselves generating
<a href="/ilike/artist/Led+Zeppelin"
onClick="gadgets.views.requestNavigateTo(new
gadgets.views.View('canvas'), {path: 'artist/Led+Zeppelin'});return
false">Led Zeppelin</a>
Going through container javascript to navigate isn't the worst thing
in the world, but the fact that there is no real URL in the browser
has several perhaps non-obvious implications to the user experience,
business model, and technical layering which are worth thinking about
and fixing:
1) when links are real HREF's in the browser, users can see where
they are going when they hover over things, and they can copy/paste
links and send them to friends. They can DIGG them, they can post them
to facebook, they can copy them into google bookmarks. They can save
them in their browser favorites. They can open links in new tabs. They
can do none of these things in opensocial containers right now.
2) Links to canvas pages from activity stream items and any kind of
container notifications are also not going to work trivially -- gadget
javascript is not involved, we need to embed specific links into
activity streams, notifications, and messages. we can't do that right
now.
3) From a development perspective, the links are not only more
readable for us and lead us to the code backing them more quickly, but
we can also paste such links into our ticketing system and find and
resolve issues more quickly rather than needed to create tickets that
describe the steps to get to a sub-page. We can also concatenate
suffixes from production links onto our private workspace or staging
links to test out fixes. Partners can send us links that are broken or
that they have a question about. Customers can point us at particular
pages that have a problem, or our help buttons can automaticaly send
us the page the user was on. We can use simple site performance and
uptime monitoring tools to see how our opensocial application is
performing if we have URLs. When we don't have real URLs in some
fashion, all of this stops and our development process slows down and
our customers and partners do not bother taking the time to send us
feedback, or they are frustrated by the process, and we can't easily
monitor the uptime or performance of our application from an end-user
perspective. We get reports like "on the NNN artist page on Orkut
there is a link to a concert on July 3rd at the Gorge amphitheatre..."
we can ping our web cluster for basic uptime/performance, but we can't
ping specific user or canvas pages to see whether something is broken.
This makes developing for and supporting OpenSocial painful.
4) Also from a development perspective, when we use real URLs a whole
class of URL-signing and parameter-passing bugs that have plagued each
container and which continue plaguing us daily here would have been
eliminated or minimally easier to track down. Encoding & signing " "
and "+" was broken. UTF8 characters like Mötley Crüe weren't working.
All this because containers don't know exactly what to encode or how
and are doing it within JSON blobs. It's unclear why this wheel of URL-
encoding is being reinvented.
5) if there are javascript errors anywhere on the page and javascript
stops running, navigation simply breaks, which is a horrendous user
experience. They can refresh, but they can't go anywhere within our
content -- not good and makes our applications and opensocial feel
flaky. This happens regularly.
6) Finally from a business model perspective, real URLs give us the
ability to create ads and external references that refer to our canvas
pages. It allows us to cross-promote our applications and our canvas
pages between different opensocial containers and facebook and our own
sites. It allows applications to cross-link with one another within a
containers, for promotional or other reasons. It allows us to email
users and give them a link to visit Hi5, Orkut, or MySpace versions of
iLike and add our application, and it allows us to do conversion-
tracking for installs from ads or email pointers and to optimize our
conversion to installation. We have none of this without URLs. The
most trivial example of this kind of utility which opensocial recently
lost traffic from is that we launched a new REM album for free
streaming on 3/24 exclusively with iLike. We were able to point users,
the press, record labels, and bands (including the band itself, REM)
to http://apps.facebook.com/ilike/rem and to http://www.ilike.com/rem.
We have no URL to point press/analysts or the band to on Orkut, Hi5,
MySpace. On REM's "artist dashboard" on ilike we can point them to
their iLike-generated artist pages in non-OpenSocial containers so
they can preview how the songs and videos they are posting will appear
to their fans. We can't point them to their OpenSocial canvas pages.
You may think that this level of url cross-referencing is only useful
to complex/deep apps with many canvas pages like ours. This is not the
case -- even the smallest applications benefit from the business model
and development implications of URLs that can fall back on pure
navigation.
So, in a nutshell, here's the ideal API from my perspective: users can
copy-paste the URLs and we can construct urls offline or server-side
(given a known root, which ideally would be http://apps.<container>.com/ilike,
but fine with us if it's anything fixed like http://<container>/app_100)
and end up back in our application, but we actually use
requestNavigateTo under the covers which does all the good things
containers apparently need in all the different contexts and we can
support zany things like desktop/offline containers.
<a href="http://apps.<container>.com/ilike/artist/Led+Zeppelin?
a=1&b=1" onClick="gadgets.views.requestNavigateTo({view : 'canvas',
url : 'artist/Led+Zeppelin?a=1&b=1'}); return fa">Led Zeppelin</a>
OR
<a href="ilike/artist/Led+Zeppelin?a=1&b=1"
onClick="gadgets.views.requestNavigateTo({view : 'canvas', url :
'artist/Led+Zeppelin?a=1&b=1'}); return fa">Led Zeppelin</a>
(the latter if the iframe host puts our docroot into place as they
host our manifest, or we could do that ourselves given a fixed base
URL)
Note that I would prefer this was shortened to take an URL instead of
making us do all the path, options crud to indicate a GET -- this is
just code that each application duplicates over and over again and we
should optimize the most common case. If you couldn't do that we could
stick with the longer convoluted arguments -- I don't really mind,
though I think it creates an irritating barrier to entry for
programmers to figure out for this API -- we would probably be
rewriting this content on the client by looking for rel="nofollow" or
some such on <a tags, like:
<a rel="nofollow" href="ilike/artist/Led+Zeppelin?a=1&b=1">Led
Zeppelin</a>
Which we would convert/rewrite at the client to have the onClick=
within them.
Thx, n@