Archive for February, 2009

Making a search command – part 3

Thursday, February 26th, 2009

Another couple of days have passed, so another round of updates is in order. Some of the changes I’ll mention here affect the previous articles: Making a search command – the easy way! and Making a search command – part 2, so if you’ve read them: read this one too!

This is the part that broke your commands

And in more than one way. If you’ve tried some of the commands before the recent updates, you might have noticed that for some reason, certain queries wouldn’t return any previews, while other would work just fine. This is because some search engines return “strange” results in the middle of the normal results – and only do it sometimes – but the only way the parser knew which titles, previews and thumbnails fit together, was by their index in each of their own lists. This was a very fragile system, and while it it still available as fallback, using it isn’t recommended.

The main difference is that the parameter options.parser.container should no longer select the element that contains all the results, but rather it should select a list containing each result. Each results title, preview and thumbnail will then be found (if available) inside the result, and grouping is no longer dependant on indexes. This means that any given result can have a missing preview or thumbnail, and it won’t affect any of the others.

Obviously, changing the meaning of the parameter means you will have to rewrite any search command you have that uses it. I hope the benefit of stability will outweigh this initial annoyance.

JSON as promised

In my last post, I said I was going to be working on JSON support, and as of about 4 hours ago, initial support has landed in hg. I have successfully rewritten our default google and yahoo commands to use this new system, and still use the JSON API provided by the services, but as I don’t have much experience with this sort of interface, it is entirely possible that I have in some way limited the functionality and thus the compatibility with some services. If this is the case, the JSON support will of course be expanded.

A slight note on the usage is perhaps needed here. Let us take google as an example:

CmdUtils.makeSearchCommand({
  name: "Google",
  url: "http://www.google.com/search?q={QUERY}",
  parser: {type: "JSON",
           url: "http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q={QUERY}",
           container: "responseData.results",
           title: "titleNoFormatting",
           preview: "content",
           href: "url"}
});

First you might notice that there are two fields called url, one outside the parser and one inside. In that order, the first one does exactly what it usually did, except it’s only used if the user presses return to go directly to the search page. The second is the one used for the actual searching if you pass type: "JSON" to the parser. If the API requires you to use POST, this works the same way as you’re used to.

Secondly, if you happen to be uncannily familiar with the structure of the JSON google returns, you might notice that the container parameter I talked about earlier in this very post doesn’t seem to be pointing to each result. Instead, it’s pointing to the container of all the results. If you think about it however, in the HTML-case, jQuery makes sure we are returned a list of results, but in JSON, the parent element holding the results is already a list of results – so it sort of makes sense.

The only other new thing is the addition of the options.parser.href parameter, which was automatically calculated in the HTML version. In JSON, the url is usually held in a separate field, so this is needed to make sure we actually link to the results.

What you can do to speed things up

These changes that break backward compatibility will happen less often – or hopefully not at all – if I get fast feedback and suggestions. The more you complain, the more likely I am to do something about it fast :-P

To try these changes out, run Ubiquity from source, or wait for 0.1.7 or 0.2pre15 where they will most likely be included.

Making a search command – part 2

Monday, February 23rd, 2009

A few days have passed since my first post Making a search command – the easy way!, and a few new features have been implemented, most of which were suggested by readers – so keep up filling the suggestion box!

Picture this

Most notably, it is now possible to include a thumbnail in the preview, which will be automatically formatted and inserted to the left of the preview text. This is especially useful for search-sites which display images to help identify the result – such as books, cd, movies, etc…

As an example, here is the Wikipedia command redone with this enhancement:

CmdUtils.makeSearchCommand({
  name: "Amazon",
  url: "http://www.amazon.com/s/ref=nb_ss_gw?url=search-alias%3Dstripbooks&field-keywords={QUERY}",
  parser: {container: "div.listView",
           title: "div.productTitle a",
           preview: "div.productTitle span.ptBrand",
           thumbnail: "div.productImage"}
});

You will also note the lack of an icon and description, but if you try it out (in latest source) you’ll see that it makes no difference. If left out, they are automatically generated from url and name respectively.

Search preview with thumbnails

Search preview with thumbnails

Correcting errors

Some sites (like Amazon) have a tendency to return weird results in the middle of the set, without any real indication that it isn’t an actual result, and this can cause the parser to become confused (say, if the number of titles and the number of preview do not match up, which belongs to which?), and before, it would give you a warning in console and then most likely die before returning any output to the user. Now, it will fall back to just supplying a list of titles, and explain to the user why the previews are missing.

Search with broken preview

Search with broken preview

What’s next?

The next thing I’ll be looking into, is allowing makeSearchCommand to use services that return JSON encoded data. This will enable us to use APIs made public by many search engines instead of scraping the HTML, and is a feature that has not only been requested by early adopters, but will also make it possible (and/or easier) to switch over to this new parser system for all of our default search commands.

As usual, I encourage you all to try out the new features, and see if anything breaks or behaves unexpectedly. And of course, if they do: let me know! :-)

Making a search command – the easy way!

Friday, February 20th, 2009

Ubiquity prides itself on not only making it easy for the average user to understand how ubiquity works, but also for making it easy for command authors to enhance it – and for good reason. Anyone should be able to write a simple command, to make their day just a little less tedious, just a little more efficient.

How it used to be

Now, making a search command has been very easy for a while, thanks to the excellent work of a handful of the core devels. To show how simple it has been, I’ll develop a command to search our own trac, and use this process to illustrate the recently added features.

First thing we do, is head over to Trac and do a search to see where it takes us. This url is quite human readable:
https://ubiquity.mozilla.com/trac/search?q=example
We can then create the search command with this simple code:

CmdUtils.makeSearchCommand({
  name: "Trac",
  url: "https://ubiquity.mozilla.com/trac/search?q={QUERY}",
  icon: "https://ubiquity.mozilla.com/trac/chrome/common/trac.ico",
  description: "Searches Trac for your words."
});

and that would work just fine. Go ahead, try it – just paste it into your command editor (note: wordpress is refusing to let me link this, so here you go instead: chrome://ubiquity/content/editor.html .) Now just bring up ubiquity and type “Trac example” and hit enter – you should end up at the same place as the link above.

Here is a screenshot of how it looks:

Screenshot of simple Trac search

Screenshot of simple Trac search

“But what about a decent preview of the results?”, I hear you cry, “like the one the google search has, or wikipedia – you can even navigate it by using your keyboard!”. Well here’s the thing – those aren’t that simple to do. The more technically inclined can take a look at how it’s done here (note: you have to view source.)

As if this hurdle wasn’t enough – we should also be thinking about standardizing the way search commands look and feel. This is key in user experience: consistency.

Easy does it

Instead of having the user write a lot of semi-redundant javascript each time he or she wants to make a search command, or indeed at all, it is now possible to pass a simple parser argument to makeSearchCommand which makes Ubiquity do all the hard work for you – now doesn’t that sound nice?

The argument is called parser, and is an array of options: (note: this feature has only recently landed in hg, so you’ll have to run either ubiquity from source, or wait till version 0.1.7 or 0.2pre14, which will almost certainly include this feature)

container
a jQuery selector that can help you narrowing in your search for the actual results on the page
title
a jQuery selector that will match each of the titles in the results
preview
same as above, except it will match the preview data returned by the search engine (if left out, only titles will be previewed)
baseurl
a string prepended to the link in the title (should only be passed if the search engine returns relative paths)

Finding the right jQuery selectors to pass is still a bit more technical than what might be expected of the average user, and we hope to alleviate that problem sometime in the future, perhaps with a neat UI that helps you pick out the titles and previews with a simple mouseclick. For now though, let’s settle for this and move on with the demonstration.

For Trac, where the HTML is fairly clean, finding the right values was a breeze, and for the avid reader wanting to try this out for themselves, I recommend using Firebug along with its “inspect” feature.

As soon as we pass the parser option to makeSearchCommand like so:

CmdUtils.makeSearchCommand({
  name: "Trac",
  url: "https://ubiquity.mozilla.com/trac/search?q={QUERY}",
  icon: "https://ubiquity.mozilla.com/trac/chrome/common/trac.ico",
  parser: {container: "dl#results",
           title: "dt",
           preview: "dd.searchable",
           baseurl: "https://ubiquity.mozilla.com"},
  description: "Searches Trac for your words."
});

Will do a pretty good job of emulating all that hard work that would otherwise have gone into creating the preview. Again just paste the above into your command editor, or simply insert the parser argument by hand.
This is a screenshot of the new behaviour:

Trac search with preview

Trac search with preview

Of course in the future, this might very well be improved upon, better looking template, better error-handling, there are lots of potential improvements out there. And that is where I leave you – with the freedom to play around with this cool new feature, and the opportunity to help evolve this beyond its current state, and hopefully towards something better for everyone. The easiest way to do this is to try it out on your favourite sites, and report back here any bugs or shortcomings you may find.