Appendix A. Tips and Tricks

"These are much deeper waters than I had thought."

—Sherlock Holmes ("The Reigate Puzzle")


IN THIS APPENDIX


Automatic Update and User Tracking

One critical, post-deployment piece of functionality that virtually all gadgets need is the capability to automatically update the gadget. What is required is the capability to make sure that the user is notified and updated when a new or updated version of the gadget is available. This functionality is not available in the Gadget API, so we have to create our own methodology for updating a gadget.

Gadgets don't collect user emails, you can't send a newsletter to notify all a gadget's users, nor do they have a help section that might provide an easier path for users to check for updates. And very often, gadgets don't have a full-fledged website where a user can come back to check for the latest version. To avoid having multiple versions of the gadget floating around, it's important to add this functionality in the gadget itself. The gadget should contain the code necessary for it to check for updates at regular intervals.

Checking for a New Version of the Gadget

There are three considerations with regard to gadget updates:

  • Putting the gadget version information online
  • Adding the code in the gadget to check the current version against any available newer version of the gadget
  • Notify the user if a new version is available

Putting the Gadget Version Information Online

Remember that the gadget.xml file contains the gadget's version information; one way to retrieve the newer version of the gadget is to host this file online. If you have updated your gadget, you would like to update the version field in the gadget's manifest file. The original gadget.xml, which is on the user's machine, might have the gadget version as 1.0 as shown here:

<version>1.0</version>

The newer gadget, instead, contains the version information as 1.1 as well as a new info url, www.innovatewithgadgets.com/newgadget, which is the download URL for the newer gadget. The updated gadget.xml file follows. Please note the version and the info url.

<?xml version="1.0" encoding="utf-8" ?>
<gadget>
  <name>- Innovate -</name>
  <namespace>Innovate.Gadgets</namespace>
  <version>1.1</version>
  <author name="Rajesh Lal">
    <logo src="images/logo.png" />
    <info url="www.innovatewithgadgets.com/newgadget" />
  </author>
  <copyright>Copyright&#169; 2007-2008</copyright>
  <description>Sidebar Gadget description</description>
  <icons>
    <icon width="70" height="80" src="images/icon.png" />
  </icons>
  <hosts>
    <host name="sidebar">
      <base type="HTML" apiVersion="1.0.0" src="gadget.html" />
      <permissions>Full</permissions>
      <platform minPlatformVersion="1.0" />
      <defaultImage src="images/drag.png"/>
    </host>
  </hosts>
</gadget>

You then have to host the updated gadget.xml file online so that it can be compared in the gadget code against the existing version. The path of the newer gadget is stored in the info url field in gadget.xml. This URL, as you will see later, is retrieved to notify the user about the new gadget location.

Inserting Code to Check the Version

The next step is to add the functionality in the gadget to compare the existing gadget version with the newer version available online. A function, checkForUpdate(), to do so is added in the utility.js file included with this book. You can access the functions by adding the following to the gadget.html file:

<script src="code/utility.js" type="text/javascript"></script>

In the utility.js file, you can find four global variables to help with update management:

// for updating the gadget
var updateAvailable =false;
var globalUpdateMessage ="Go to gadget website";
var globalUpdateURL ="http://innovatewithgadgets.com";
var globalUpdateGadgetXML ="http://mywebsite.com/Gadget.xml";
// Change mywebsite.com value in globalUpdateGadgetXML variable to the
// gadget.xml file in your website

The updateAvailable variable is set to a value of true if the version of the gadget online is newer than the version of the existing gadget. The variable, globalUpdateURL, stores the URL where the user can go to download the new gadget. This variable is updated from the newer version of the gadget.xml file from the info url field. Finally, the globalUpdateGadgetXML variable holds the path of the newest version of the gadget.xml file.

Note that the globalUpdateGadgetXML variable is declared in the gadget's utility.js file and is packed with the first version of the gadget, so when you come up with a new version of the gadget, your existing user base already has a gadget with an update url pointing to this fixed location (http://mywebsite.com/gadget.xml in the earlier code). Because the URL is coded into the gadget, you won't be able to change it and you have to make sure to upload the new gadget.xml file in that location only.

Now it's time to implement the checkForUpdate function:

// for updating the gadget
// include Utility.js in gadget.html
function checkForUpdate()
{
    var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
    xmlDoc.async = false;
    xmlDoc.load(globalUpdateGadgetXML);
    var gadget = xmlDoc.selectNodes("gadget");
    var Results = gadget[0].childNodes[2].text;
    var InfoURL = gadget[0].childNodes[3].childNodes[1].getAttribute("url");
    xmlDoc=null;
     if (Results > System.Gadget.version)
     {
       if (InfoURL.indexOf("http://")==-1)
       {
         InfoURL = "http://" + InfoURL;
        // InfoURL must contain http://
        }
        globalUpdateURL=InfoURL;
        globalUpdateMessage = "An update is available,";
        globalUpdateMessage += " visit" + globalUpdateURL;
        updateAvailable=true;
        UpdateBackground();
     }
     else
    {
     globalUpdateMessage = "Go to gadget website";
    }
}

The function checkForUpdate() uses XMLDOM to load the online gadget.xml file. It then parses the version and URL information:

var Results = gadget[0].childNodes[2].text;

Results contains the version and InfoURL is the update URL:

var InfoURL = gadget[0].childNodes[3].childNodes[1].getAttribute("url");


NOTE

Note that this approach assumes that your gadget.xml file is similar to the gadget.xml file that comes with the samples. The parent-child relations shown here gadget[0].childNodes[3].childNodes[1].getAttribute("url"); are relative to the nodes in the gadget.xml file. This implementation can be further improved using advanced XML parsing methods such as XPath and so on.


The result is then compared with System.Gadget.version, and if it is greater, the updateAvailable flag is set to true and the UpdateBackground function is called. The UpdateBackground function, as discussed in the next section, notifies the user about the update.

Notifying the User That a Newer Version Exists

After a newer version is detected, the user needs to be notified that a newer version of the gadget exists and that the gadget can be updated. This can be done in different ways.

A visual clue such as an information icon can be used; a message can be displayed, and so forth. The important part is to convey the information to the user that a new version of the gadget is available.

One unobtrusive way to communicate that information is to change only the background image, as shown in Figure A.1.

FIGURE A.1 The image on the left shows the gadget in its usual state. The image on the right shows the gadget with the background changed to display a download arrow, indicating that an update is available.

image

Here is the code used in this gadget for changing the background:

function UpdateBackground()
{
  if (System.Gadget.Settings.read("mini") ==true)
  {
     if (updateAvailable)
     {
      System.Gadget.background =
      "url(../images/UpdateAvailableSmall.png)";
      document.getElementById("mylogo").title =globalUpdateMessage;
      document.getElementById("infourl").href = globalUpdateURL;
     }
  }
  else
  {
     if (updateAvailable)
     {
     System.Gadget.background = "url(../images/UpdateAvailable.png)";
     document.getElementById("mylogo").title =globalUpdateMessage;
     document.getElementById("infourl").href = globalUpdateURL;
   }
  }
}

This code assumes that the UpdateAvailable.png file exists. Notice that the function also updates the tooltip and the link to the new URL.

Tracking Your Users

The next tip I am going to share with you is how to track users. By tracking I don't mean tracking user's personal information, but statistical data like how many people are using the gadget, or how users are grouped by different patterns such as demographic, usage, and so on. Before writing this book I created two gadgets and was updating them regularly. In one of the updates, I started tracking the users. I was surprised to discover that one of the gadgets had more than 10,000 users and the other one had fewer than 10. It was obvious which gadget I would concentrate on and continue supporting.

Tracking the number of users of the gadget, and other statistics about users, provides a lot of useful information that can be used to further improve the gadget. If you are displaying a web page in the gadget, you can easily track the number of visitors to the web page by using tools and widgets like the ones from sitemeter.com.

You can do two things with gadgets to track users:

  • Add a tracking code in the links
  • Track the XML feed used by the gadget

Using Tracking Codes

The first option is to put a tracking code in all the links to your website that the gadget makes. For example, if the gadget links to the website www.innovatewithgadgets.com, change the link to www.innovatewithgadgets.com?gadget=true. With this URL, web traffic analysis software collects information specific to that URL. You can then use that information to determine the number of visitors coming to your website through the gadget.

For gadgets that use online feeds, the best way to track users is with the use of a feed distribution network such as www.feedburner.com.

Feed Tracking with FeedBurner

FeedBurner provides an easy way to distribute your RSS/Atom feed and provides a multitude of statistics (see Figure A.2). All you need is a free account and the URL of your RSS/Atom feed. FeedBurner "burns" the feed and provides you with a new address for your RSS/Atom feed; for example, http://feeds.feedburner.com/trickofmind.

FIGURE A.2 Statistics for last 30 days of the feed for Trickofmind gadgets.

image

After it is set up, you can use FeedBurner's feed address in the Sidebar gadget and monitor your site statistics with FeedBurner's analysis tools.

One thing you need to consider while using FeedBurner's feed is using Microsoft XML DOM instead of AJAX (XMLHTTPRequest object) for retrieving the feed. FeedBurner uses a number of secure and nonsecure servers, which sometimes cause issues when using AJAX calls. The following section gives you more details on the two methodologies.

Reading XML, XHTML, RSS/Atom, HTML, Text, and JSON Data

Sidebar gadgets often need to get data from online resources. The data is often in multiple formats, such as XML, XHTML, RSS/Atom, HTML, or even just plain text. Over the course of this book I have discussed using AJAX along with the XMLHTTPRequest object to retrieve data. The XMLHTTPRequest object fits the bill most of time, but there are cases where you need additional robustness or flexibility.

Using Microsoft XML DOM is much more robust than an AJAX call. If you have hosted your feed in a content distribution network like FeedBurner, using the AJAX method can be inconsistent. For additional flexibility for manipulating feeds, consider using the Windows RSS platform. Here are the options for reading data from an online resource:

  • XMLHTTPRequest object (AJAX method) for reading data in XML, XHTML, RSS/Atom, text, HTML and JSON (JavaScript Object Notation) formats
  • Microsoft XMLDOM object for XML, XHTML and RSS/Atom data formats
  • Windows RSS platform and Microsoft Feed Manager, specifically for RSS/Atom data

I compare each of these methods in the following sections.

The XMLHTTPRequest Object

The XMLHttpRequest (XHR) object is an API that the scripting language can use to retrieve XML and other text data from a web server. This communication can be made asynchronous and can be used for retrieving almost all kinds of data, namely XML, HTML, text, JSON, and so forth.

Here is an example of data retrieval using the XMLHTTPRequest object, which you will find in the gadget template Innovate.gadget:

/////////////////////////////////////////////////////////////////////////////
// XML Functions TO GET  feed
/////////////////////////////////////////////////////////////////////////////
function GetFeed() {
try
{
   error.style.visibility = "hidden";
      loading.style.visibility = "visible";
      content.style.visibility = "hidden";
    loading.style.visibility = "visible";
    loading.title  = "Connecting...";
    var rssObj  = new ActiveXObject("Microsoft.XMLHTTP");
    rssObj.open("GET", System.Gadget.Settings.read("FeedURL") + "?"
            + Math.random()*1 ,true);
    rssObj.onreadystatechange = function() {
        if (rssObj.readyState === 4) {
            if (rssObj.status === 200) {
                loading.innerText = "";
                rssXML = rssObj.responseXML;
                page = 0;
                ParseFeed();
                content.style.visibility = "visible";
                loading.style.visibility = "hidden";
                if (chkConn) { clearInterval(chkConn); }
            } else {
              var chkConn;
              content.style.visibility = "hidden";
              loading.style.visibility = "hidden";
              error.innerText = " Service not available ";
              error.style.visibility = "visible";
              chkConn = setInterval(GetFeed, 30 * 60000);
            }
        } else {
               loading.style.visibility = "visible";
               loading.title = "Connecting...";
        }
    }
    rssObj.send(null);
    }
    catch(e)
    {
                content.style.visibility = "hidden";
                loading.style.visibility = "hidden";
                error.innerText = " Service not available" ;
                error.style.visibility = "visible";
    }
}

This is also the best approach when you are trying to read text, HTML, or JSON data from an online resource asynchronously.

For more information on XMLHTTPRequest object, see http://msdn2.microsoft.com/en-us/library/ms535874(VS.85).aspx.

Microsoft XML DOM

The XML DOM (Document Object Model) is a standard object model for manipulating XML via an API. It is useful for accessing and manipulating XML documents, its elements, attributes, and text.

Here is an example of using XML DOM to retrieve data:

/////////////////////////////////////////////////////////////////////////////
// Using Microsoft.XMLDOM Functions TO GET  feed
/////////////////////////////////////////////////////////////////////////////
function getFeedXMLDOM() {
try
{
      error.style.visibility = "hidden";
    loading.style.visibility = "visible";
    content.style.visibility = "hidden";
    loading.style.visibility = "visible";
    loading.title  = "Connecting...";

    var xmlDocument = new ActiveXObject('Microsoft.XMLDOM'),
    xmlDocument.onreadystatechange = function () {
      if (xmlDocument.readyState == 4) {
        loading.innerText = "";
            rssXML = xmlDocument;
            page = 0;
            ParseFeed();
            content.style.visibility = "visible";
            loading.style.visibility = "hidden";
          }
         else
         {
            loading.style.visibility = "visible";
            loading.title = "Connecting...";
         }
        };
    xmlDocument.load(System.Gadget.Settings.read("FeedURL"));
    }
    catch(e)
    {
        content.style.visibility = "hidden";
        loading.style.visibility = "hidden";
        error.innerText = " Service not available" ;
        error.style.visibility = "visible";
    }
}

The major difference is in the ActiveX object used. In the AJAX method it was Microsoft.XMLHTTP, and in the preceding method it's Microsoft.XMLDOM. Once you retrieve the XML data, you can then parse it the same way in both the methods.


NOTE

Microsoft.XMLDOM is only meant for XML data and cannot be used for text or HTML data.


Here is an example from my personal experience. For one of my gadgets I was using the XMLHTTPRequest object with XML data distributed by FeedBurner. FeedBurner has multiple servers to manage the bandwidth. Both secure and nonsecure servers are used and the feed is distributed over the network. This caused inconsistency in the AJAX method. When the user count for the gadget increased to more than 10,000, I started getting complaints from users. On numerous occasions, users were getting unspecified errors. I changed the XMLHTTPRequest object to XMLDOM and since then, I've never had any problems. Right now the same gadget has more than 25,000 users.

For more information and a beginner's guide on XML DOM visit http://msdn2.microsoft.com/en-us/library/aa468547.aspx

Windows RSS Platform & Microsoft Feed Manager

One of the great additions in Windows Vista and IE 7 is the improvement in the Windows RSS platform. The Windows RSS platform enables applications to access and manipulate RSS feeds. It exposes several ActiveX objects and APIs that can be used in a gadget. Here is the list of objects that can be used to retrieve online feeds:

  • The Feed object manipulates a single RSS feed.
  • The FeedFolder object exposes methods to manipulate the Common Feed List folder hierarchy and properties of a feed folder.
  • The FeedItem object has methods and properties for a single item in an RSS feed.
  • The FeedManager object provides methods to access the Common Feed List, which is a hierarchy of RSS feeds to which the user is subscribed.

These objects can be used together for advanced feed manipulations; for example, to subscribe to new feeds, enumerate existing subscriptions, access feed properties, manage feeds into folders, normalize the XML source of a feed, and so forth. It works for all kinds of feeds and channels. The ActiveX object can be instantiated with

FeedManager = new ActiveXObject(Microsoft.FeedsManager);

If you are going to create a gadget specific for feed management, I would suggest looking through the script files of the existing RSSFeeds.Gadget sample that comes with Windows Vista.

For more information on feed objects visit http://msdn2.microsoft.com/en-us/library/ms684749(VS.85).aspx

Globalization and Localization

Globalization enables an application to work in different countries. There are two aspects of globalization:

  • Internationalization— Enabling the application to be used without language or culture barriers; that is, language and culture information comes from a resource rather than having been hard-coded in the application.
  • Localization— Translating and enabling the product for a specific locale by using the resource file to provide translations of the application text into a specific language and culture.

Let's see how gadgets support localization.

First take a look at the universal directory structure. If the file structure is in the common root as shown in Figure A.3, it can serve multiple locales without any change.

FIGURE A.3 The gadget works for all the locales but displays the same information, data, and images in each. The gadget is not tailored to specific locales.

image

The gadget in this figure shows only the language and culture used when the gadget was created. If you want to support the gadget for different locales, you need multiple folders inside the gadget package—one for each locale, each of them containing localized HTML, JavaScript, and image files. You can also have common files that work regardless of locale. This works because the Sidebar automatically retrieves the HTML files in the appropriate directory that is associated with the current locale setting.

Let's look at how the Sidebar checks for files inside the gadget folder.

If the current locale is fr-FR for French-France, the Sidebar looks for files and images in folders in this order until a match is found:

1. GlobalDemo.gadget/fr-FR

2. GlobalDemo.gadget/fr

3. GlobalDemo.gadget

So, nonlocale files and images can be put in the GlobalDemo.gadget folder and can be used across the gadget. Figure A.4 shows a gadget with three locales: en-US for American English, es-ES for Spanish in Spain, and fe-FR for French in France.

FIGURE A.4 Note the folder structure on the right side shows common images and the style folder in a non–culture-specific, root folder.

image

You can pack your gadget with all the locale folders, or, if you know your user's locale, you can have multiple .gadget packages, one for each locale. For example, on your website you may ask users what their locale is and provide them a link to the appropriate package to download.

Localized Gadget Example

Among the downloads for this book you will find a GlobalDemo.gadget with a structure similar to that found in Figure A.4. Using a local.js file is a standard way of storing locale-specific text. Here is how the local.js file looks for the sample gadget inside the en-US/code folder:

local.js for en-US locale:

// en-US Locale specific "sample" text
var globalTitle ="Globalization Sample";
var globalWelcomeMessage = "Welcome";
var globalDecription ="I hope you like it !";

Similarly, local.js for other locales is as follows:

es-ES local.js file:

// es-ES Locale specific "sample" text
var globalTitle ="Muestra del Globalization";
var globalWelcomeMessage = "Recepción";
var globalDecription ="¡Espero que tengas gusto de él!";

fr-FR local.js file:

// fr-FR-ES Locale specific "sample" text
var globalTitle ="échantillon de globalisation";
var globalWelcomeMessage = "Bienvenue";
var globalSettingsDecription ="J'espère que vous l'aimez !";

This is just to show you a standard way of doing this; of course a real gadget will have a lot more data then these three global variables. The idea behind this is that wherever these variables are used, include the local.js file and the gadget then automatically displays locale-specific text. You can find the code to include the .js file in gadget.html:

<script src="code/local.js" type="text/javascript"></script>

Here is the gadget in action for the en-US locale:

FIGURE A.5 The GlobalDemo.gadget with a background image specific to the current locale: en-US.

image

And here is the function SetGlobalText that sets the text dynamically and is called during setup:

function Setup()
{
   SystemSetup();
   Resize();
   SetGlobalText();
}
function SetGlobalText()
{
gadgetTitle.innerText=globalTitle;
helloglobal.innerText = globalWelcomeMessage;
globaldescription.innerText = globalDecription;
}

The sample gadget GlobalDemo.gadget uses common style information while at the same time specifying different images for each locale. You can use this gadget as a starting point for your own locale-specific gadget. The next section gives a list of locale and country codes that are required for the purpose.

Locales with Country Codes

To see a list of country codes for all the locales that can be used inside a gadget, visit the "Language Codes" section of MSDN at http://msdn2.microsoft.com/en-us/library/ms533052(VS.85).aspx.

Graphic Design

We discussed in Chapter 3, "An Approach to Design," how to make the gadget look elegant and match the Windows Vista theme. You saw how a gadget background image with alpha transparency and shadow enhances the presentation. In this section, we will go a bit further and look at how to achieve those effects for an image used in a gadget. There are two ways of doing this:

  • Use gadget protocols on standard PNG images for advanced photo effects such as applying transparency, shadow, thumbnail generation, icon extraction, and so on.
  • Create a PNG image with alpha transparency and shadow effect using a photo-editing tool such as Adobe Photoshop or Paint.NET.

This section looks at both these techniques. Microsoft provides a set of protocols to work efficiently on images. These protocols are simple HTML tags that can be applied to elements. These protocols can add effects to images without the use of any photo-editing software.

Gadget Protocols for Image and Text

There are four gadget-specific protocols that add effects to the user interface. All these protocols start with the letter g and have special properties and methods that modify the gadget's appearance. They are applied in the gadget along with other HTML elements. Here is the list:

  • g:background
  • g:text
  • g:image
  • gimage

As you will see later, gimage and g:image are two separate protocols and are used for different purposes. The gimage protocol was developed later to address advanced functionalities not available in g:image.

g:background

The g:background protocol is used to define the background of the gadget. It can also contain multiple g:text and g:image elements. The methods of this protocol are listed in Table A.1.

TABLE A.1 Methods of the g:background Protocol

image

The sample gadget (GraphicDemo.gadget) which comes with the chapter uses these methods. Here is a typical implementation of g:background in an HTML page:

<g:background id="imgBackground" src="imagesackground.png" />

g:text and g:image

g:text and g:image are the two gadget-specific elements used to modify text and images. They also expose methods and properties that modify the gadget's appearance and are used similar to the g:background protocol in an HTML page. The methods of the g:text and g:image elements are listed in Table A.2.

TABLE A.2 Methods of g:text and g:image

image

<g:text id="txtDemo">Demo Text</g:text>
<g:image src="..gDemo.png" id="imgDemo" />

gimage

The gimage protocol is also used to display images from a user's computer. The advantage of using gimage is you can provide a path to any file (not just images) and the gimage protocol extracts the icon of the file and displays it. This protocol is also very useful for enhanced thumbnail handling and image sizing. You can specify the image height and width as a querystring appended to the source path as shown in the sample code. Note that the implementation of this protocol is slightly different from other protocols, which can be used as HTML elements.

Here's an example that shows the source of the gimage as a JavaScript file.

<img id="myGImage"
src="gimage:///C:UsersuserAppDataLocalMicrosoftWindows Sidebar
ImageGadgetsGraphicDemo.gadgetcodeGadget.js" />

The following example shows the dynamic thumbnail generation for the image. Note that it passes the height width as querystrings :

var requiredHeightWidth= "?width=15&height=15";
var gImage = document.createElement("img");
gImage.src = "gimage:///" + System.Gadget.path +
             "\images\gdemo.png" + requiredHeightWidth;

Sample Gadget g:Demo

The download file set for this chapter contains the gadget GraphicDemo.gadget (see Figure A.6). I suggest that you play around with it to see examples of the protocols discussed in the previous sections.

FIGURE A.6 The Gadget Protocol Demo uses g:background and the addShadow() method for a shadow effect in the gadget background.

image

The following is the HTML code for this gadget:

<body onload="Setup()">
   <g:background id="imgBackground" src="imagesackground.png">
   <div>
   <div id="blogtitletable">
   <table width="100%" height="20"  border="0">
        <tr align="center" valign="middle">
          <tdalign="left"></td>
          <td class="subtitle" id="gadgetTitle" valign ="middle" >
          Gadget Protocol</td>
          <tdalign="left"></td>
         </tr>
      </table>
    </div>
    <fieldset id="GDemoImage">
    </fieldset>
        <div id="protocolbar" title="">
<table width="100%" height="20"  border="0">
<tr valign="middle">
<td><a onclick="addImage()">Add</a></td>
<td><a onclick="removeElements()">Remove</a></td></tr>
<tr valign="middle">
<td><a onclick="setBackgroundShadow()">Shadow</a></td></tr></table>
    </div>
    </div>
    </g:background>
</body>
</html>

Note that the g:background protocol is used to specify the gadget's background image.

Here's the JavaScript code:

function Setup()
{
setBackgroundShadow();
}
function setBackgroundShadow()
{
if(backGroundShadow=="black")
{
    imgBackground.opacity = 100;
    imgBackground.addShadow("black", 50, 50, 0, 0);
    backGroundShadow="color"
  }
  else
  {
    imgBackground.opacity = 100;
    imgBackground.addShadow("Color(255, 255, 0, 0)", 50, 25, 0, 0);
    backGroundShadow="black"
  }
}

The setBackgroundShadow method uses the opacity and the addShadow method of the protocol to add the shadow effect:

function addImage()
{
    var file= System.Gadget.path + "\images\gdemo.png";
    var oDemoRect = GDemoImage.getBoundingClientRect();
    var img = new Image();
    img.src = file;

    var imgDemo= imgBackground.addImageObject
    (file, oDemoRect.right - img.width - 10, oBoundingRect.top);

    imgDemo.opacity = 50;
    imgDemo.addGlow("Color(255, 255, 0, 0)",50,25);
}

The addImage() method uses the addImageObject() method of the g:background protocol to add an image dynamically:

// Remove all image and text elements added to the background since load.
function removeElements()
{
    imgBackground.removeObjects();
}

The removeElements method uses the removeObjects method of the g:background protocol.

More in information on these graphic protocols can be found at http://msdn2.microsoft.com/en-us/library/bb508512(VS.85).aspx


CAUTION

When you are using Visual Studio to create HTML pages, by default Visual Studio adds the DOCTYPE and xmlns attributes in the <HTML> element. Make sure to remove those before testing for gadget protocols. Your HTML code should look like the following:

<html><head> <title>My Gadget </title></head>...

Contrast this with the default HTML page as generated by Visual Studio:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head> <title> My Gadget </title></head>...


The next section shows you how to create a transparent PNG file in Adobe Photoshop.

Creating a Transparent PNG File in Photoshop

Because all the images used in a gadget are typically transparent PNG images, let's create one in Adobe Photoshop, specifically an icon.png for the gadget which is used in Chapter 5.

1. Open Photoshop and click on File, New, and configure it according to the specifications shown in Figure A.7.

FIGURE A.7 The settings shown here create a 64x64–pixel transparent image.

image

2. Zoom the image to 400% and then select the Rounded Rectangle tool shown in Figure A.8.

FIGURE A.8 The Rounded Rectangle tool, which created the oval rectangle, is selected in the toolbar. The chiseled sky pattern gives a sky color; play around with other combinations and shades.

image

3. Your background of the icon is ready; now open the image that you want as a foreground of the icon in a separate window. Make sure that the image's width and height are each less than 64 pixels.

4. Make a copy of the image layer by pressing Ctrl+A to select the entire image. Now go to File, New Image, and click on Ctrl+C to copy there. Now you should see the image in two layers. The background layer is blank and the foreground layer is the image.

5. In the foreground image, use the Polygonal Lasso tool to select the capture edges of the image.

6. Right-click on the selection and click on Select Inverse (see Figure A.9).

FIGURE A.9 After cropping the image using the Lasso tool, make the background invisible.

image

7. Press the Delete key and make sure that the background layer is invisible by clicking the eye icon in the Layers tab beside the background layer.

8. Drag the layer to the window containing the original shape and save it as a Vista icon, using the .png format (see Figure A.10).

FIGURE A.10 Here you have a transparent icon to use for a gadget.

image

Now that you've seen one way of creating a transparent icon or a PNG image with Adobe Photoshop, the next thing to learn is how to create the shadow/outer edge for the gadget background image.

Creating Outer Edges/Shadow Effects in Photoshop

The gadget background image supports translucent edges or what is called a shadow effect. This gives the gadget a rich and sophisticated look. This can be achieved with the gadget protocol (refer to the section "Sample Gadget g:Demo," where you added shadow effects using the addShadow method with the g:background protocol), but for those who want to get their hands dirty, here is one way of doing it in Photoshop.

You can achieve this effect in Photoshop by using the Layer style, as shown in the following steps. Note that the maximum width of the docked image needs to be 130 pixels, so you need to account for the shadow, which should be 2 pixels wide on the left and 3 pixels wide on the right. Let's begin.

1. Take an image with width equal to 130 pixels minus 5 pixels—that is, 125 pixels. Open it in Photoshop. This example uses the default image, without shadow, for the Currency gadget (see Figure A.11).

FIGURE A.11 Here is how a docked gadget looks with shadow (left) and without shadow (right).

image

2. Go to the Image menu and select Canvas Size. Increase the canvas size width and height by 5 pixels, as shown in Figure A.12.

3. Go to the Layer menu and select Layer Style. Click on Drop Shadow. The configuration, shown in Figure A.13, creates a shadow of 3 pixels along the right side of the image and a similar shadow effect at the bottom.

FIGURE A.12 Increasing the canvas size by five pixels accommodates the shadow.

image

FIGURE A.13 This creates a 3-pixel shadow on the right and bottom side of the gadget background image.

image

4. Select Outer Glow for 2 pixels of shadow on the left and top, as shown in Figure A.14.

FIGURE A.14 To create a shadow on the left and top, use the Outer Glow effect, with the size set to 2 pixels.

image

5. Save the file as a PNG format and you are finished. You can see the results in Figure A.15.

FIGURE A.15 The background PNG image has now both a 3-pixel shadow in the right and 2-pixel shadow in the left.

image

Note that the gadget design specification needs a limit to the width of its shadow to the right and left. However, to give a proper shadow effect to the gadget background, top and bottom also uses two and three pixels shadows, respectively.

This is one way of creating shadows; if you don't have Photoshop; try downloading Paint.NET, which gives similar options to create a shadow. Visit http://www.getpaint.net/ for a free download.

Security and Other Resources

Gadget security is a big concern in the community because many gadgets can easily be written to introduce vulnerabilities to the user's computer. A gadget can contain a script that executes locally and that can access local files and folders. Gadgets run in Explorer's Local Machine Zone. This zone does not appear in Internet Explorer's security tab but does exist as a fifth security zone. Administrators can edit the settings of this zone by modifying the Registry.

Security settings for all users on the machine are in the Registry at the following location:

HKEY_LOCAL_MACHINESoftwareMicrosoftWindowsCurrentVersionInternet Settingsones

By default, scripts in the Local Machine Zone can create instances of local ActiveX controls and download data across domains. Gadgets can do this also but with one limitation: Gadgets cannot download and install new ActiveX controls. The User Account Control (UAC) in Windows Vista prevents gadgets from running with administrative privileges.

For more information on Vista Security, visit Windows Vista Sidebar Security at http://msdn2.microsoft.com/en-us/library/aa965881.aspx.

To avoid these security concerns keep the following in mind:

Avoid using ActiveX controls in your gadget. The end user may not be comfortable if your gadget uses or installs an ActiveX control. If your gadget needs to access the local machine's resources, use the Windows Management and Instrumentation (WMI) API to query and access information. WMI is very powerful and can return detailed information about hardware devices and software processes. This was discussed in Chapter 2, "The Architecture." As well as used extensively in Chapter 10, "Most Recently Used .NET Projects—An Application Gadget."

Keep in mind, however, that with Vista's User Account Control, a gadget lacks administrative access and might not be able to use the full capability of the WMI API. See "User Account Control and WMI" at http://msdn2.microsoft.com/en-gb/library/aa826699.aspx and "Inspect Your Gadget" at http://msdn2.microsoft.com/en-us/library/bb498012.aspx for a list of guidelines.

Use signed certificates to ensure that the gadget is coming from the right source. You saw in Chapter 8, in the section "CAB File Approach," how a certificate can be used to digitally sign a gadget. Remember, though, that this assures 100% authenticity only if the certificate is from a trusted authority such as Thawte or VeriSign.

Use Windows Live Gallery for gadget deployment. After the gadget is ready for distribution, consider hosting it with Windows Live Gallery at http://gallery.live.com. Windows Live Gallery regularly monitors gadgets hosted by the website and checks for security issues. This has two benefits: First, the gadget is exposed to millions of users; second, the user relies on the website and has greater confidence in the Live Gallery website than in an independent gadget provider.

Protecting Your Code

Gadgets are HTML, CSS, and JavaScript files, along with some images, all zipped together. So, the source of the gadget goes with the gadget. You may therefore be concerned about the intellectual property of the code in the gadget.

The best way to secure your intellectual property is to protect the code—that is, the JavaScript file.

Here are two of the methods you can use for that:

JavaScript Compressors— These are algorithms that typically reduce the JavaScript file size by half by removing all the whitespace and comments. Some algorithms can obfuscate the function names to reduce the size of the file and the readability of the script. The algorithm is not meant for true obfuscation, but the process makes the code look messy and, in a way, makes it difficult for an outsider to understand.

One such compressor, made by Douglas Crockford, is JsMin, which you can find at http://fmarcia.info/jsmin/test.html. There is another that comes with the DOJO toolkit. This one can be found at http://www.dev411.com/dojo/javascript_compressor/.

JavaScript Obfuscators— These are algorithms that convert scripts into a highly mangled and obfuscated form. This makes them extremely difficult to study, analyze, reuse, and rework while retaining the functionality of the original code. They also hide the structure (control flow, division into subroutines and classes) of the script completely.

The disadvantage of a JavaScript obfuscator algorithm is that it might not be completely accurate, so test the obfuscated code or use a commercial obfuscator. Personally, I find the JavaScript compressor JSMin good enough for the purpose.

Gadgets in an Enterprise (Accessing SQL Server)

Gadgets can also be effectively used as supplements to enterprise-level applications. You saw in Chapter 9, "Site Statistics Gadget with AJAX—An Information Gadget," how gadgets can be used to access web services. Let's see how a gadget can access a local or remote SQL Server database.

Note that the database connection object adodb.connection is an ActiveX control that needs to be already installed in the client machine. Here is sample code for accessing a table in a local or remote database:

Function AccessSQLServer(databaseSource, databaseName, username, passWord)
{
var gadgetSqlConnection = new ActiveXObject("adodb.connection");
gadgetSqlConnection.open("Provider=sqloledb;Data Source="
       + databaseSource+ ";Initial Catalog="+databaseName+";User
       Id="+userName+";Password="+passWord+"");
var gQuery ="select * from TableName";
var gadgetRecordSet = gadgetSqlConnection SqlConnection.Execute(gQuery);var result
Image= "";
while (gadgetRecordSet.eof == false)
   {
      result = result + gadgetRecordSet (1) + "<br>";
      gadgetRecordSet.moveNext();
   }
gadgetContent.innerHTML = result;
}

The function takes databaseSource, databaseName, and the username and password as parameters, creates an instance of the database connection, and opens it with the parameters provided. The gadgetgRecordset object then queries the database with the query provided in the gadgetgQuery variable.

Here is another example of a gadget that access Microsoft Dynamics, http://www.codeproject.com/KB/gadgets/DynamicsCRMGadget.aspx.

Resources and References

For more resources and information, you can visit http://www.innovatewithgadgets.com/Extra/Gadget-Links-Used.htm. There you will find all the links and references used in this book.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.120.206