Computer users learn all kinds of arbitrary conventions: blue underlined text is a hyperlink, an I-beam cursor means you can select text, clicking 'OK' for all the dialogs during software installation—whoops! That's not such a good one, but you get my point.
This is no different with gadgets. Most users first encounter Google Desktop gadgets by using the news gadget or some other item-based gadget. They learn the default way of interacting with gadgets from these first encounters. As I post more articles on code.google.com and the Google Desktop APIs blog, one of my themes will focus on how we, as gadget creators, should design our interfaces given a user's habits. In this article, I'll examine how users typically interact with a gadget and show how to get the expected behavior out of the gadget.
In the news gadget, the user sees lots of news stories, each of which is a content item. Here are the interactions users come to expect from the news gadget:
Many gadgets in our gallery, unfortunately, violate these expectations. This may seem minor, but users value consistency. Not only is it pleasing, it makes the experience much easier, and lets users focus on the unique features of the gadget, not its odd behavior.
When I tell developers about these common behaviors, a common reply is 'OK, so how do I get my gadget to do that?' Here's a brief description that focuses on items that are enclosed in a div
tag.
First, you want to have an array of such items:
var items_ = [];
Suppose you want to create 5 items. Each item has some main text and a date. The entire item should be clickable and should change colors when it's highlighted. Here's some code to achieve that:
for (var j = 0; j < 5; ++j) { // (1) Generate the per-item code that will be called depending on how the user interacts with the item var commonCode = ' onmouseover="hilightItem(' + j + ');" onmouseout="unhilightItem(' + j + ');" enabled="true" ' + 'onclick="onItemClick(' + j + ');" ondblclick="onItemDblClick(' + j + ');"'; // (2) construct the item, and include the common interaction code var newDiv = '<div x="0" y="' + 45 * j + '" width="248" height="40" background="#ebebeb" ' + commonCode + '>' + '<label name="itemName" x="0" y="0" align="left" width="246" size="14" ' + 'font="Georgia" ' + commonCode + '>' + itemName[j] + '</label>' + '<label name="itemDate" x="0" y="19" align="left" width="246" size="12" height="20" ' + 'font="Georgia" ' + commonCode + '>' + itemDate[j] + '</label>' + '</div>'; // (3) store the item in our global items_ array items_[j] = content.appendElement(newDiv); }
Notice that in (1) we handle all the common behaviors when interacting with an item.
The onmouseover
and onmouseout
handlers deal with highlights, the onclick
handler controls the details view, and the ondblclick
handler will deal with opening the item.
Referring to (2), since all the elements of the div
must be clickable (the container, the text, and the date), we add the common code to all parts of the div
.
Finally, we keep a reference to the div
in our items array (3).
The highlighting handlers are as follows:
function hilightItem(itemIndex) { // we use an image for the background. This image is stored in the gg file of the gadget items_[itemIndex].background = "selected.png"; } function unhilightItem(itemIndex) { // we return to our default background color when the user moves the mouse away from the item items_[itemIndex].background = "#EBEBEB"; }
Displaying a details view, and properly closing it when the user clicks the item again, is also quite easy:
var currentItemDetailsView_ = -1; function onItemClick(itemIndex) { // close the details view if already displaying if (itemIndex == currentItemDetailsView_) { plugin.CloseDetailsView(); currentItemDetailsView_ = -1; return; } // otherwise construct details view.. // DO WORK HERE // show details plugin.ShowDetailsView(htmlDetailsView, title, gddDetailsViewFlagToolbarOpen, onDetailsViewFeedback); currentItemDetailsView_ = itemIndex ; } function onDetailsViewFeedback(detailsViewFlags) { // the user/system closed the details view if (detailsViewFlags == gddDetailsViewFlagNone) currentItemDetailsView_ = -1; }
Finally, opening an item on double-click is handled by this code:
function onItemDblClick(itemIndex) { var shell = new ActiveXObject("Shell.Application"); shell.Open(itemUrls[itemIndex]); }
This small amount of work is worth doing to make users feel more comfortable with your gadget. Please post comments to our developer forum if you do something different in your gadgets, or have thoughts on what I've described here.