My favorites | English | Sign in

Google Desktop APIs (Labs)

Details Views and YouTube Videos in Desktop Gadgets

This article was written and submitted by an external developer. The Google Desktop Team thanks Yannick Stucki for his time and expertise.


Yannick Stucki, Gadget Developer
November 2007

"My gadget has so little space to display all this information! -- Use details views to get more."
"Wow, playing the latest YouTube video in my gadget would be so cool!"

Introduction

Figure 1: An opened details view

Gadgets are typically designed to be small-sized applications on a user's desktop, sidebar or even their iGoogle homepage. The sidebar especially limits the size of gadgets, yet sometimes a gadget developer would like to display more content. This can be easily achieved by using details views. The details view has been in Google Desktop since version 2. Over time, the functionality has improved, and we can display content in newer, better ways.

There are two different kinds of details view: the HTML details view and XML details view. In this article, I am going to introduce you to both of them.

XML details view

An XML details view (Figure 1) displays content the same way it would in the main gadget view. A details view is defined in a details.xml, which is similar to the main.xml. Both files use the same XML markup as shown in the following example of an empty details.xml:

<view height="348" width="427" onopen="detailsView_onOpen()" >
    <script src="details.js" />
</view>

With the script tag, you can add as many script files to the details view as you want, but it is recommended to have a separate file for details view specific code as we've done here (details.js). detailsView_onOpen() is triggered when the details view opens.

Nobody wants an empty details view, so fill this XML file with all the tags you would normally use in a gadget. The easiest way to get started is to load the gadget in the Designer and visually edit details.xml.

Opening the details view

Now that you've filled the details view with buttons, lists, and images, you're probably wondering how to open and display this details view at runtime. First, we need to create a details view object:

var detailsView = new DetailsView();

detailsView.SetContent(
    "", // Item's displayed website/news source. -> not used for an XML details view
    undefined, // Time created
    "details.xml", // The XML file
    false, // Whether time is shown as absolute time
    0); // Content layout flags

After setting up the details view object, you can show it like this:

plugin.showDetailsView(detailsView, "", gddDetailsViewFlagNone, onDetailsViewFeedback);

function onDetailsViewFeedback(detailsViewFlags) {
  //This function is called when there is feedback from the details view
}

The following flags could be passed for the third parameter in the showDetailsView function:

gddDetailsViewFlagNone
No flags are passed.
gddDetailsViewFlagToolbarOpen
Make the details view title clickable like a button.
gddDetailsViewFlagNegativeFeedback
Add a negative feedback button in the details view (e.g. 'Don't show me items like this').
gddDetailsViewFlagRemoveButton
Add a 'Remove' button to the details view.
gddDetailsViewFlagShareWithButton
Add a button in the details view which displays the friends list when clicked. The user can share the content item with them.

To close an opened details view, call this:

plugin.CloseDetailsView();

NOTE: there can only be one details view shown at a time (HTML or XML). Once you open a new one, the old one gets automatically closed. There is no need to close the old one beforehand.

Communicating with the details view

You now know how to set up, open, and close an XML details view. The next step is to add dynamic content to the details view. You might want to fill a label with specific text or show different pictures.

Fortunately, there is an easy way to send data to and from the details view. Let's assume I had fetched data about a movie:

var showtimes;
var rating;
var duration;
var title;

This might be a lot of information to display in a gadget (especially if there are several movies), so I might want to display them in a details view whenever someone clicks on a movie from a list.

To send this information to a details view, run the following lines before opening it:

detailsView.detailsViewData.putValue("showtimes", showtimes);
detailsView.detailsViewData.putValue("rating", rating);
detailsView.detailsViewData.putValue("duration", duration);
detailsView.detailsViewData.putValue("title", title);

To extract the data, put the following lines into the details.js file:

function detailsView_onOpen(){
    showtimes=detailsViewData.getValue("showtimes");

    rating=detailsViewData.getValue("rating");
    duration=detailsViewData.getValue("duration");
    title=detailsViewData.getValue("title");
}

Now you can access those variables from inside the details view. Cleaner code might make use of Object Oriented Programming (See "Object-oriented Programming Principles in Gadgets" for more information). So instead of sending those four variables individually, you could do this:

var movie;
movie.showtimes=showtimes;
movie.rating=rating;
movie.duration=duration;
movie.title=title;

detailsView.detailsViewData.putValue("movie", movie);
function detailsView_onOpen(){

    movie=detailsViewData.getValue("movie");

    //use it, e.g:
    label1.innerText=movie.duration;
}

Getting feedback from the details view

Now that you've learned how to send data to the details view, you might be interested in knowing how to send data from the details view to the main gadget. We earlier set up a function onDetailsViewFeedback that is called by the details view when it has something to report. One example of this feedback, is notification that the the details view is closed. Clicking the titlebar or remove buttons also trigger feedback events.

So let's assume you had opened a details view with the flag gddDetailsViewFlagRemoveButton instead of gddDetailsViewFlagNone. The following code listens for two events: the closing and the removal of the details view.

function onDetailsViewFeedback(detailsViewFlags) {
  if (detailsViewFlags == gddDetailsViewFlagNone) {
    // The user closed the details view. Do something here if you have to.
  } else if (detailsViewFlags == gddDetailsViewFlagRemoveButton) {
    // The user clicked on the remove button. Remove this element from the list. he doesn't want it.
  }
}

Putting it all together

We seen a lot of code snippets so far. Let's regroup and show all the snippets as they would appear in an actual gadget:

main.js

function callDetailsView(){
    var detailsView = new DetailsView();
    detailsView.SetContent("",undefined,"details.xml",false,0);
    detailsView.detailsViewData.putValue("anyKeyWord", anyVariableOrObject);
    plugin.showDetailsView(detailsView, "", gddDetailsViewFlagRemoveButton, onDetailsViewFeedback);
}

function onDetailsViewFeedback(detailsViewFlags) {

  if (detailsViewFlags == gddDetailsViewFlagNone) {
    // The user closed the details view. Do something here if you have to.
  } else if (detailsViewFlags == gddDetailsViewFlagRemoveButton) {
    // The user clicked on the remove button. Remove this element from the list. he doesn't want it.
  }
}

details.js

function detailsView_onOpen(){

    var something=detailsViewData.getValue("andKeyWord");
}

The HTML details view - or playing a YouTube video

Instead of having an XML details view, you can also have a details view that is filled with HTML content. The HtmlDetailsView sample in the Google Desktop SDK is a good example to learn from, especially if you compare it to the XmlDetailsView sample (also in the SDK).

HTML may be an appealing option for those who are familiar with it, but in my opinion using XML is easier because you can use the Designer for its development. However, the HTML details view also has its advantages. One example is playing a YouTube video. The code example below is lengthy, but try to focus on the bold lines. You need to call showYoutube whenever you want to play a video. Furthermore, the the other bold lines highlight differences between an XML implementation.

var htmlDetailsView=null;
showYoutube("http://www.youtube.com/v/yavHaoKAJaI", "The Kingdom Trailer");

function showYoutube(url,title) {
var snippet = "<object id=\"movie\" width=\"100%\" height=\"100%\"><param name=\"movie\" "
        + "value=\"" +url + "&autoplay=1\"></param><embed "
        + "src=\"" + url + "&autoplay=1\" name=\"movie\" type=\"application/x-shockwave-flash\" width=\"100%\" "
        + "height=\"100%\" bgcolor=\"#000000\"></embed></object>";

  var detailsHTML =
"<html><head><script>window.external.window = window;</script><style type=\"text/css\"> body{font-family:arial,sans-serif; font-size: 10px; margin-left: 3px; margin-top: 3px; margin-right: 3px; margin-bottom: 3px;}</style></head><body bgcolor=\"#000000\" text=\"#FFFFFF\" link=\#FFFF00\ vlink=\#FFCC99\ alink=\#FFFF00\ scroll=\"no\">";
  detailsHTML += snippet;

  detailsHTML += "<br /><br /></body></html>";

    plugin.closeDetailsView();

  htmlDetailsView = new DetailsView();
  htmlDetailsView.html_content = true;
  htmlDetailsView.setContent("", undefined, detailsHTML, false, 0);

  htmlDetailsView.external = {};

  // Show the details view
  plugin.showDetailsView(htmlDetailsView, title,
    gddDetailsViewFlagNone, onHtmlDetailsViewFeedback);
}

function onHtmlDetailsViewFeedback(detailsViewFlags) {
  // Remove the movie from DOM to make it stop playing
  var window = htmlDetailsView.external.window;
  var movie = window.document.getElementById("movie");
  if (movie != null)

    movie.parentNode.removeChild(movie);

  if (detailsViewFlags == gddDetailsViewFlagNone) {
    // User closed the details view
  } else if (detailsViewFlags == gddDetailsViewFlagToolbarOpen) {
    // User clicked on the title of the details view
    var winShell = new ActiveXObject("Shell.Application");
    winShell.ShellExecute(linkArray[index]);
    winShell = null;
  }


  htmlDetailsView=null;
  CollectGarbage();
}

One cool thing about that player is that you can resize the window (drag it at the edges) and the video screen will adjust to fill the window.

Figure 2: YouTube movie in a details view.

How to get the right YouTube URL

If you want to play YouTube videos, you obviously need a URL to the video. For video searches, Google Video provides better results. That's why we employ a trick here and search YouTube videos via Google Video:

fetchYoutube("The Kingdom trailer")

function fetchYoutube(name){
    var youtubeHttp;
    youtubeHttp= new XMLHttpRequest();
    youtubeHttp.onreadystatechange = function(){OnReceivedYouTube(name,youtubeHttp);};
    youtubeHttp.open("GET", "http://video.google.com/videofeed?type=search&q=site%3Awww.youtube.com+"+name+"&so=0&num=20&output=rss", true);

    youtubeHttp.send();
}

function OnReceivedYouTube(name,youtubeHttp){
  if (youtubeHttp.readyState == 4) {
    var doc = new DOMDocument();
          doc.loadXML(youtubeHttp.responseText);
    Tags = doc.getElementsByTagName("item");
    if (Tags == null || Tags.length <= 0)
      return;
    var swf;
    for (var node = Tags[0].firstChild; node != null; node = node.nextSibling) {
        if (node.nodeName == "link"){

          swf = node.text;

          swf=swf.substring(swf.indexOf("www.youtube.com%2Fwatch%3Fv%3D")+30,swf.length);
          swf=swf.substring(0,swf.indexOf("&"));
          swf="http://www.youtube.com/v/"+swf;
          break;
        }
    }
    //swf now is the url we want
    showYoutube(swf,name);

    youtubeHttp=null;
  }
}

How to set an HTML details view's size

Unfortunately, there is no direct way to define an HTML details view's size. However, the size of an HTML details view is equal to the size of the last details view opened, including XML details views. If you have a gadget that uses HTML details view, quickly open and close an invisible (opacity=0) XML details view set to a particular size beforehand.

One last word of advice

Before you incorporate all this code into your own gadget, please be aware of this: a user may be annoyed if gadgets behave unexpectedly. For example, if you have a list of items, and clicking on an item opens a details view, the user expects that re-clicking the item closes the details view. To implement this, you could have a variable currentlyOpen that always stores the name of the item that is open at the moment or is empty if no details view is open. If a user clicks an item, check to see if it's the same as what's in currentlyOpen and then close the current details view instead of opening a new one. If you want more information about this subject, I recommend that you read Meeting User Expectations, where this technique is mentioned with many other ones that should improve your gadget.

Resources

I hope this article showed you how to deliver useful content to your users or entertain them with cool videos. Unfortunately, details views aren't yet fully documented in the API reference, but here are some resources that might be helpful:

  • Have a look at the SDK. There are good XmlDetailsView and HtmlDetailsView examples.
  • The Movies Gadget uses both XML details views to display information and HTML details view to play YouTube videos.
  • Any other gadget you come across that uses details views -- there are many of them.

Of course you can also do more than just display YouTube videos with an HTML details view. Tinker around with it, and if you need help you can always ask your question in the developer group.

Author's Bio

Yannick Stucki

I am currently a student and started programming a few years ago. It's always tough to produce complete programs yourself (that are actually used by others) because as a hobbyist programmer, you just don't have the time and resources of a fully-staffed team. That's why I love gadgets programming: gadgets range from very simple to fairly complex, but most importantly, you can get them out there and have people actually using them.

Besides programming, I love playing Rugby. And in winter, I go snowboarding in the Swiss Alps.

You can read more about my gadgets on my homepage. There you'll also find contact information if you need more help or have suggestions.

Creative Commons License This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.