8 posts tagged “javascript”
When I posted about lib-flickr-minimal, I noted that the newly-launched flickr.places.placesForUser method made a more interesting demo of data you could fetch when authenticated than, say, showing a user's most recent private photos. Evidently the developers at Flickr agreed it was an interesting concept, because over the last couple of months that area of the API has been extended considerably, As a result, I've expanded the demo into an AppJet application of its own.
Where? What? When? is the result. It shows you, on a map, the locations with the most photos according to a given criterion: by default, that's a tag, but it can also show your photos, or those from your friends and family, or your contacts. You can then inspect a place and see the most recent relevant photos, or the most popular tags, for that location.
How did that evolve from the initial demo app? Instead of simply printing a table based on Flickr's response into the document, I directly plotted the results on the map. I added a small form to enable the choice of criteria, and when Flickr added the placesForTags method, I added that as a choice. Belatedly, I realised that would also work for users without authentication, so I removed the requirement to authenticate, and made tags the logged-out default. (The image above shows a slight change to the initial results: it's the same tag, London, but at the neighbourhood, not locality, level. All of the locations are within the greater city's area, which probably won't be a surprise, but that's not true for Paris. Evidently, what happens in Vegas doesn't always stay there.)
The design of the application isn't quite settled, but I knew I wanted to replace the standard Google Maps pushpins with partially-transparent circles. Initially, I went with red, but when I showed it to colleagues, they said it reminded them of maps of bomb blast radii, so I spent a while looking around for the right colour, before settling on a yellow. The circles themselves are scaled according to the natural log of the number of photos for that location; I played with square roots as well, but I feel that logarithms give the right sense of scale.
The last piece of work I did was adding tag display for locations, using the tagsForPlace method. These tags can be surfed: clicking on one will load a new search for the given tag. It's noticable that the first few tags for most places are almost always place names, while common tags seem to share a familiar pattern of scattered, similarly-sized circles across the US, Europe, south-east Asia and coastal Australia.
There's still a few things I could add; tag persistence in URLs (to make it easier to share pages), better loading indicators (especially initially), options on which photos are shown, and links to view the search on Flickr itself, for example. There's also a missing question: while the API methods support maximum and minimum times, I haven't yet added options to allow you to show When? However, for now I think I've done enough (and I'll note that the site has a link to view the source of the application, if you fancy hacking on it yourself.) Enjoy.
groupr (my little JavaScript application that gives users an overview of their Flickr group membership) needs to be able to communicate with Flickr. That's really not hard; getting the most recent public photos posted by a user can be done trivially, either using feeds or the API proper.
However, most of the calls that you need to write really interesting applications require authentication, so that they can see private data. Rather than use the password antipattern, Flickr uses a well-thought-out multi-step system. Unfortunately, this can be a bit tricky to wrap your head around, and harder still to debug. It was certainly something I spent a while grappling with for groupr. That's the main reason I've split out the parts of groupr that talk to Flickr into a library on AppJet called lib-flickr-minimal.
As the name suggests, the library doesn't actually do that much. There are methods to handle the steps of authentication, and there's a generic function to call any Flickr method. However, it's more than enough for me to write both groupr, and a little demo application that guides other users through the process of handling authentication.
(A little on that demo application. I spent a few minutes trying to think of a method that required read privileges that would not be too obvious and dull ("you have 500 private photos", for example). Thankfully I remembered the recently-launched flickr.places.placesForUser method, and so I decided to use that as my example call. A bit more work meant I could plot the places returned onto a Google map, so now you can see where you've taken (or at least, geotagged) the most photos.

Ideally I'd rewrite this to produce something prettier, like Dopplr's lovely raumzeitgeist images, but for now, it's a nice little one-page example.)
Philosphically, I prefer this style of library. There seem to be two schools of thought when it comes to building such things. You can tell from the source of the library that I'm in the "least possible work" camp: provide helpers for the functions that are tricky, but for most calls, let the user consult Flickr's documentation to figure out what to call, and use JSON as a return format to make everything that you get back an object (or at least, a rich data structure).
The other camp, which I think of as being influenced by Java and other less dynamic languages, wants to provide a method for everything. As a result their implementations tend to have lots of boilerplate code for handling every single Flickr method (there are about a hundred now), and more for parsing the returned XML (rarely, if never, JSON) and add to it convenience methods for such things as constructing URLs.
While the latter style is probably superficially appealing (you get documents in one place, and the library can error-check locally) it also has significant drawbacks. When Flickr add a method, or extend the returned data, the library has to be patched and re-released. Many libraries only implement the methods of interest to the author, leaving chunks of the API unimplemented. (These are particularly annoying for me; they tend to implement flickr.photos.search, which seems to be the cornerstone of the Flickr API, but ignore the interesting methods around the edges, which I seem to be drawn to.)
There is a nice middle way, which is to use metaprogramming and the API's own reflection methods to construct a list of allowed calls and arguments, giving error-checking but also updating automatically when Flickr add methods. The libraries I prefer for both Python and Ruby do this, and very nice they are too.
To be honest, this is probably where I want lib-flickr-minimal to end up, but for now, I'll happily take a library that stays out of my way rather than one that aims to do everything but only implements a few things. Hopefuly others on AppJet, or those looking to implement Flickr authentication, will find it useful too.
Long-time readers here may remember groupr. (If you don't, it was a small web application that loaded the photos in your Flickr groups, something that, oddly, you can't do on Flickr itself.) I wrote it at the beginning of 2007 for Fotango's Zimki platform. Of course, when that died at the end of last year, groupr vanished, but not before I took a backup of the code and templates underlying it, in the hope that one day I might be able to revive it.
For a few different reasons, I've been considering bringing groupr back recently. I could use Google's App Engine, as I've done for snaptrip, but that was from scratch, and for this project, I didn't fancy porting both the code and templates. I had a quick look at Helma and Trimpath, but I didn't get on with either of them. There's also the fact that they they're not hosted solutions, and part of the joy of server-side JavaScript (SSJS) is not having to worry about finding a server. I also tried Reasonably Smart, but you have to be pretty clever to get git working, and I couldn't, so that was out.
Eventually I found AppJet, and after a quick look I was convinced that this was probably a good place to end up, and after about eight hours to port what I had, and another five or so to fix up some things I never quite polished off on the old version, you can now use groupr.appjet.net.
So, how does it compare to Zimki, and how hard was it to port the code? (After all, big names are now talking about portability in the cloud). Well, AppJet may be closed source, but they offer a downloadable JAR which ran without any effort for me on Mac OS X, meaning both that I could develop locally (even offline, with cached data), and that if AppJet vanishes (which, after all, happened to Zimki) I can take groupr and run it on a server of my own. In this case, practicality trumps theoretical openness.
AppJet's IDE feels a lot nicer than Zimki's did (although I barely use (or used) either, preferring BBEdit with AppJet's JAR, or Trawler for Zimki). I also approve of the way that libraries are handled (they're just apps whose name includes the 'lib-' prefix) is pretty nice. You can see what is using a library and there's provision for inline documentation too. The community feels bigger than Zimki's ever did (although that might just be because the idea of SSJS is taking off), and I was able to find a few useful libararies (such as a TrimPath template port) pretty easily. Speaking of libaries, AppJet's 'storage' is oddly non-core, but it's a pretty nice row-style store with nice querying facilities. It lacks Zimki's handy "expires:+2h" syntax, but that wasn't too hard to fit in myself.
One definite annoyance I have with AppJet is that they don't keep all their libraries out of the global namespace. Zimki's functionality was all hidden in a zimki object, but AppJet has a few top-level standard libraries, and 'page' and 'response' both clashed with names I was using in groupr's previous version. Another is that there's no way of handling non-JavaScript files, so both static files and templates are tricky. I've ended up with the former being hosted on my main server, and the latter as a hash of triple-quoted strings (a Python-ism that AppJet has imported into their JS runtime). Proper file support, like Zimki had, would be a boon there. However, both of these were pretty easy to overcome, and it turned out Zimki did very little that AppJet couldn't replicate. (Replacing the (Mojo, I believe) API calls was four lines of jQuery; replacing the server-side API cleverness, for my needs, was a few lines of JSON.)
Overall, then, I think I'm pretty happy with my experience so far. I've managed to revive the project without too much hair-pulling, and, as I said, even extended it from the state it was in on Zimki. Maybe server-side JavaScript has a future after all?
A week or so ago, the lovely people at Flickr launched their new iPhone-specific mobile site. It's very nicely done, and there's one thing in particular I noticed that I've always wished for on their main site.
Having had a (years-old) desire for this feature on the website rekindled, I decided to spend a few hours with Greasemonkey seeing if I could make it happen, and I managed to do so, thanks largely to people who've led the way. Here's show_flickr_contact_context.user.js.

However, before you go charging in to install it, I should probably warn you that it's very much still at the "proof of concept" stage. Flickr's context boxes are surprisingly complicated little blocks of HTML, and (perhaps ironically) I haven't made any of the JavaScript in them work. Moreover, it seems that I've broken the functionality in existing context blocks. Moreover, the script only works when you've come directly from the Photos from your Contacts page, or if it detects an argument that it sets in the URL from the context paging block.** This is because the API call the script needs to make seems to be quite a complicated one, so I'm trying very hard to be polite with the usage of it.
Anyway, I thought it'd be nice to document even though it's really only getting going, so feel free to have a play with it. If I do tidy up any of its rough edges, I'll be sure to mention it here.
* A couple of minor notes on the implementation. On the plus side, it obeys the setting on the Photos from your Contacts page that sets whether or not you see five or one image from each. However, there's no way to modify this on the phone itself. Unfortunately, it's also hard to change contexts; in other words, to swap from paging by contacts to paging within a user's photostream. Both compromises are down to the lack of space for UI on the iPhone, though, so I'm hardly going to really complain (hence the hiding this in a footnote).
** Ideally I'd do this using Flickr's own convention: /photos/name/id/in/contacts/. Unfortunately, if Flickr finds a /in/ argument it doesn't understand, you get redirected and lose the context, so I'm using /photos/name/id/?contact=in instead. Ah well.
This post has been brewing for a while, but I've been prompted to actually write it by seeing John Gruber's offhand remark on his most recent linked list entry, about CSS gradients in WebKit:
No, it's not just him. WebKit, and Opera's layout engine Presto, raced towards Acid3 compliance in March, with both effectively reaching a photo finish on the 26th. Meanwhile, Microsoft hasn't even shipped a non-beta Acid2 passing browser¹; no surprise there. But where's Gecko, the Mozilla layout engine, the one that powers Firefox?Just me, or is WebKit racing way ahead of Gecko in terms of support for cool new stuff?
Well, to be blunt, it doesn't look as if they care much. We have one developer saying that Acid3 is basically worthless, and another (more diplomatically) stating that it's a missed opportunity and an exercise in making browsers jump hoops, rather than improve "real" functionality. As others (almost certainly more qualified than I am) have noted, this sounds a lot like the noises from Microsoft around the time of Acid2's release.
The thing is, I'm not here to kick Gecko, but to understand its problems, if it has them. Does the team's response to Acid3 mean it does? Possibly not on its own, but coupled with events like the move of Epiphany to WebKit², and the aforementioned speed of development on WebKit (and to a lesser extent Opera's Presto³) I have to wonder. Why is development there so slow?
One stated reason is that the Mozilla Foundation is on a rush to release Firefox 3, and it's certainly true that it is coming up for release. On the other hand, Apple certainly seem to be able to keep the open-source WebKit tree distinct from the version used in releases - Safari 3.1 shipped with an Acid3 score of 75 when nightlies were scoring 90-odd - so I should hope that's not the real reason. Maybe they're pulling people off the layout engine to work on the browser? That's not as stupid as it sounds for most apps, given the way the Firefox UI is set out using XUL, a markup language. Even so, it feels like a bad use of engineering. Maybe Gecko's reached that point where extending it's no fun. The language the team themselves uses, with talk of Gecko 2, makes me wonder if that's true.
I don't have answers, anyway, but I'd love to hear from people who do why Gecko is giving the appearance of stagnation, while WebKit seems full of life.
¹ Bafflingly, it seems that Microsoft develops not one, but four layout engines: Trident, for IE/Win, Tasman, originally for IE/Mac and now part of Office:Mac, and two unnamed engines, one in Word and Outlook 2007, and another in Expression Web Designer.
² Admittedly that's got contributing factors beyond merely Gecko; it sounds like the wrapper they were using to embed it (GTKMozEmbed) had some seriously nasty issues of its own.
³ I mentioned to Tom Insam that I was surprised I'd never heard of the name of this engine, but he sagely noted that, as it's not open source or embeddable, there's no reason I would have.
or, why I won't be migrating to Google Mashup Editor
Last winter I wrote a small web application called groupr which let you look at photos from your Flickr groups in one place. I did that partly because I thought it would be useful (it is, a bit) but also because I wanted to play with the platform the company I'd once worked for had released. That platform was called Zimki, and it was, in hindsight, a pretty ambitious thing for a small company to attempt.
Zimki is a hosted server-side Javascript application framework, complete with a data storage model and a templating engine (actually two). It makes it easy to quickly knock up a small web application, or at least it does once you wrap your head around it and get hold of tools to save you using the (frankly awful) web pages provided for editing your app. It's the closest I've seen to what Marc Andreessen has called level 3 platforms:
A Level 3 platform's apps run inside the platform itself -- the platform provides the "runtime environment" within which the app's code runs.
Indeed, this is exactly how Zimki works. Unfortunately, it's also closing by Christmas.
There's a big company out there who also have something that looks a bit like a level 3 platform. Google Mashup Editor also lets you run code in a hosted environment, build multi-page sites, and read and store data from the web. Unfortunately, there's no way I can port groupr to it.
Firstly, there's a very limited set of server-side computations allowed. If there's not a module or control for something, you can't do it. This is the first thing I ran across. groupr has a local config file with my Flickr API key and secret, and it uses MD5 to calculate the required parameter for the authentication step. It turns out that's impossible with GME.
Secondly, there seems to be no way to pass data in to the application other than by user interaction or feeds. Notably, you can't inspect HTTP query strings, the mainstay of web programming since 1994. Since Flickr's frob is returned in an HTTP parameter, this means it's impossible to ever use GME for a Flickr application that requires authentication. Well, actually, you could do everything on the client side, but then why use a hosted environment at all? I doubt I'd get enough use out of its templating language to justify the effort.
As with my complaints about Skitch, this is almost certainly a case of me wanting a product to be what it's not, but I can't help feeling that if Google aren't prepared to build a real Level 3 platform, nobody is. In the meantime, I suppose revert to writing my own apps with web frameworks that use SQL and which need work to scale, just like everyone else does.
There have been a couple of posts since Apple's press event on Tuesday, which saw the launch of the new .Mac Galleries - an online, read-only version of iPhoto, kind of - that state that "Apple doesn't get the web". Jeremy Keith says
in the fast-moving, messy world of online services I don’t think the genius-led design of Apple can compete with the truckloads of nimble young upstarts making snazzily addictive products on the Web
and Chris Heathcote writes
Whenever Apple strays towards software and the web recently, there’s a lot of flashy interfaces, and little substance.
I think there's a slight qualification to be made here. I think Apple are great at web publishing. Their site is one of the best product sites I've seen (despite the fact I dislike the new bigger-than-800-pixel width). I've been going on about the elegance of URLs - it's possible to guess that there's something at apple.com/keyboard, for example - since 2001 or something, and even when they drop in AJAX their pages still have usable permanent links.
When designing for consumers, Apple takes the same approach. They produce tools for publishing, using a one-to-many, one-direction mode of thinking. As James Duncan Davidson notes as he writes about the .Mac galleries, "It’s not Flickr, and comparing it to Flickr is probably pointless." Well, no. Flickr is the archetypal Web 2.0 application, being almost as much about community as about photographs themselves. The .Mac gallery, on the other hand, is all about putting your work online. There's no comments, no notes, no tags, but the people who it's aimed at don't want that. They're about publishing, not interaction, and while they pages are undoubtedly heavy, and probably scale badly, they're also slick enough that a lot of people will like them.
Similarly, iWeb-generated blogs have no comments, but well-designed templates (from which it's hard to stray.)* Again, it's designed for publishing. The problem for Apple is that it's not 1999 any more. People expect more from their sites now, and thankfully more and more of the sites I use are applications, not brochureware. So perhaps the statement needs to be refined, because despite the JavaScript libraries and slick visuals, Apple doesn't get Web 2.0.
* One point where iWeb fails is that it doesn't preserve Apple's nice URLs; the ones it generates are distinctly ugly. At least, they were in the first version.
One of the nice things about working on groupr in the first few weeks was getting involved in the object model and the underlying code, but there were a couple of hooks I left deliberately so that I could add some whizzy client-side effects later. One was the fact that the call to get the photos in a group pool had a couple of optional parameters; the number of images to fetch and the page number.
With the latest revision of groupr, which is now live, that's actually been made accessible to users. If there's more than nine images per group, you'll be able to page back and forwards through them. If you're not a member of many groups this probably makes the app vaguely interesting to you. If not, maybe you'll like the fade effect, for which I have to thank Gareth, for suggesting it, and jQuery, for making it easy.
Annoyingly, though, I've just realised that I can't use Flickr's group IDs as CSS IDs. @ is not a permitted character. (This is probably because it's used in the selector syntax; something I should have realised when jQuery was failing to select items based on ID. I ended up using an XPath selector instead, but that's not really such a useful discovery now.) Oh well, nothing like a big HTML refactor to get stuck into, is there?
