Click here to Skip to main content
Click here to Skip to main content

Windows 7 Sidebar Gadget - CodeProject Reputation Watcher

, 22 Mar 2011 CPOL
Rate this:
Please Sign up or sign in to vote.
Windows 7 Gadget that scrapes your reputation points and graph, and tracks changes between updates
gadget_main.png

Introduction

Following on from the CodeProject Chrome Extension I had previously written, I wanted to explore what it would take to port this across to a Windows Desktop Gadget. This article will explore how to put together a desktop gadget, and look at some of the issues discovered and how to overcome these. The gadget polls the CodeProject for a member's profile, and utilizes jQuery to scrape out the reputation points and display the member's current reputation points and change since the previous poll. The gadget can also grab the member's reputation graph and display this to the user in a 'flyout'.

Background

The information required in building this extension can be found on the Microsoft MSDN Windows Sidebar Development pages. For information relating to jQuery, see here.

The Sidebar Gadget

Sidebar gadgets were introduced in Windows Vista, and the gadgets are docked within the sidebar area. In Windows 7, the docking within the sidebar was removed, and the gadgets are free to float anywhere the user places them. I have only tested this in Windows 7, as I am not wanting anything to do with Vista anymore, which any sane person will fully understand!

Gadgets can be ActiveX controls embedded within an HTML file, or just plain and simple HTML and associated JavaScript/images, etc. As I was porting this gadget from the previously mentioned Chrome Extension, this article will only focus on the plain and simple HTML/JavaScript implementation.

This gadget is effectively a collection of HTML files with fully embedded JavaScript and CSS, or can link out to other JavaScript, CSS, and image files. The gadget is just a renamed zip file (with a .gadget extension) which contains all the necessary components and elements. We will cover the packaging later in the article. In order for Windows to know what to do with all these files within the package and how to present it to the user, a manifest file in the root of the project defines the various elements. The manifest file must be named gadget.xml.

Let's take a look now at the manifest file crafted for this gadget:

<?xml version="1.0" encoding="utf-8" ?>
- <gadget>
  <name>CodeProject Gadget</name>
  <version>1.2.0.0</version>
- <author name="Dave Auld">
  <info url="http://www.dave-auld.net" />
  <logo src="images\bob.png" />
  </author>
  <copyright>©2011 Dave Auld.</copyright>
  <description>CodeProject Windows Desktop Gadget</description>
- <icons>
  <icon height="48" width="48" src="images\bob48.png" />
  </icons>
- <hosts>
- <host name="sidebar">
  <base type="HTML" apiVersion="1.0.0" src="cpgadget.html" />
  <permissions>Full</permissions>
  <platform minPlatformVersion="1.0" />
  <defaultImage src="images\bob128.png" />
  </host>
  </hosts>
  </gadget>

There are some basic attributes like name, version, and description, which are self explanatory. The icons and defaultimage elements define which images are available for use by the windows; these appear in the Gadget Selection page when it is installed, and when dragging the gadget to the desktop. The base element contains a src parameter which defines the HTML file to open as the main gadget element. Some of the other elements are mandatory values which must be used, and are defined in the MSDN documentation. Some of the elements are also used on the gadget selection screen to provide information to the user, as shown below:

gadget_select.png

Gadget Initialization, Configuration, and Settings

When the gadget starts up, the code configures some of the functionality within the gadget, namely which HTML file is used for the settings dialog, and which file is used for the flyout functionality. The flyout functionality is what we use for the reputation graph display. An event handler is also initialised to handle when the settings dialog closes, to perform an update if the member ID or refresh interval has changed. The first time the gadget runs, the member ID is defaulted to the author's, and the refresh interval set to 300 seconds.

Settings are stored and read using functions within the System.Gadget.Settings namespace. In Version 1.1, some additional checks were made to check if settings for the gadget instance already existed before setting the defaults. This was added because if the computer was rebooted, the default settings were re-applied. The code that performs the initialisation is shown below:

var memberID = "557325";     // Member ID Number (1st load is Authors ID)
var refreshInt = "300";      // 300 Second default

//Check if the instance has settings stored already before
//applying new defaults
if (System.Gadget.Settings.read("MemberID") === "")
{
    //Write the default settings
    System.Gadget.Settings.writeString("MemberID", memberID);
    System.Gadget.Settings.writeString("RefreshInterval", refreshInt);
}
else
{
    //Read the saved settings
    memberID = System.Gadget.Settings.readString("MemberID");
    refreshInt = System.Gadget.Settings.readString("RefreshInterval");
}

System.Gadget.onSettingsClosed = SettingsClosed;

// --------------------------------------------------------------------
// Initialize the gadget. called from the onload event of primary file
// --------------------------------------------------------------------
function init() {
    // Enable Settings dialog for the gadget.
    System.Gadget.settingsUI = "cpsettings.html";

    // Specify the Flyout root.
    System.Gadget.Flyout.file = "cprepgraph.html";
    System.Gadget.Flyout.show = false;

    //Hide the Play image, as will start in Autoupdate
    $("#playImage").hide();

    reload_Page();

    //kickoff the auto update timer
    setTimeout(function () { updateTick(); }, 1000);
}

The settings dialog is used to set the member ID and the refresh interval. It is accessed by clicking the spanner/wrench icon on the gadget, which opens up the settings HTML file and presents the dialog to the user.

gadget_settings.png

Adding and Using jQuery, Why Use it? Scraping Content?

As this gadget is a port of the Chrome Extension, the methods for adding and using jQuery and why we should use it are exactly the same, so rather than duplicate this part, please refer to the Chrome Extension article here. The gadget only makes use of jQuery, and does not make use of jQueryUI, so the only reference required is the one relating to the jQuery library, namely:

<script type="text/javascript" src="jquery/jquery-1.4.2.min.js"></script>

Content was scraped in exactly the same way as the Chrome Extension, with the code only modified slightly to cater for the gadget layout.

Note: Windows Sidebar makes use of the Internet Explorer engine for hosting the gadget, and as a result of this, I found that the Internet Explorer Cache started interfering with the updates of the reputation points, and these did not refresh correctly. In order to stop the Internet Explorer cache from getting in the way, it is possible to configure jQuery not to use the cache. This was achieved by adding the following code to the start of the JavaScript file, disabling the cache for all calls made by jQuery:

// Disable caching of AJAX responses - Stop IE reusing
//         cache data for the same URL requests
    $.ajaxSetup({
        cache: false
    });

Implementing Auto-Refresh

One of the major differences between the Chrome Extension and the Windows Gadget is the refreshing of data. Every time the extension is activated from the Chrome toolbar, it would load new data. The gadget however is open all the time, so a method of refreshing the data was required. This was achieved by implementing a self regenerating timer tick event and a counter. When the gadget first loads, it starts a timer with a callback function which is the 'tick'; the tick maintains a counter of the number of times it has ticked, and if this exceeds the refresh period, it performs a refresh of the data. At the end of each tick, it starts another timeout and does a callback to itself. The gadget can also stop and restart the auto-refresh by using a Play/Pause boolean flag. Once I worked out what I was trying to do, it turned out to be a relatively simple and effective mechanism. The code for the timer routines is shown below:

// 300 Second default, this is a string as it comes from the Settings Dialog
var refreshInt = "300";
var tickCount = 0;       // How many ticks have elapsed
var autoupdate = true;   // Is autoupdate on/off

    //This code is actually held within the gadget start up routine
    //kickoff the auto update timer
    setTimeout(function () { updateTick(); }, 1000);

// --------------------------------------------------------------------
// Auto-Refresh codes
// --------------------------------------------------------------------
function updateTick() {

    tickCount++;

    if (autoupdate) {
        if (tickCount >= parseInt(refreshInt)) {
            //refresh
            tickCount = 0;

            reload_Page();
        }

        setTimeout(function () { updateTick(); }, 1000);
    }
}

function playpauseUpdates() {

    autoupdate = !autoupdate;

    if (autoupdate) {
        $("#playImage").hide();
        $("#pauseImage").show();
    }
    else {
        $("#playImage").show();
        $("#pauseImage").hide();
    }

    //clear the tickCounter
    tickCount = 0;

    if (autoupdate) {
        updateTick();
    }
}

Gadget Interface Elements Overview

gadget_parts.png

  1. Show / Hide the reputation graph
  2. Manually refresh the data
  3. Navigate to CodeProject
  4. Animated image shown when data refreshing
  5. Play / Pause auto refresh control
  6. Mouse over for basic author info and version number
  7. Close the gadget
  8. Display the settings dialog
  9. Grab control for moving the gadget
  10. Mouse over each category cell to see member level tooltip, each category cell will change colour accordingly
  11. Area where points change between refreshes, e.g., +5
  12. Category reputation points
  13. Date/time of last refresh

Testing Code

Testing the gadget did become a bit of a pain. Normally, for JavaScript testing, it is easy just to throw in a few alert statements here and there to see what is going on; however, alert() has been disabled in gadgets. It turns out however, that window.prompt() is still active and can be used. You can attach the debugger to the Sidebar process, but for a simple quick check, this is way too much overkill.

The simplest way in the end was to just make the change, and then package and install the gadget and use it. Repeat as necessary, adding and removing window.prompt() as you go along. Oh, hail GadgetPacker....more on that in a minute!

Packaging and Deployment/Hosting

As stated at the start of the article, a gadget is just a renamed zip file with all the necessary files, all contained within. You can simply use Explorer 'Send-to compressed (zipped) folder' to grab all the files and then just manually rename the output file to whatever you want the name of the gadget to be.

You could imagine that this would become very tedious, having to repeat the process over and over again; in the end, I wrote a little tool (called GadgetPacker) to perform this process as well as initiating the install process. You can read more about and grab a copy of GadgetPacker here.

Gadgets can be distributed by email, served by a web server, or moved around the network, and when the user wants to install it, simply double click the file and the installation process will kick off.

So How Can I Use This Extension?

Download the gadget file, and double click to install. When you first install the gadget, it will default the member ID to that of the author, and the refresh period to 5 minutes. Enter the settings and enter your member ID which can be found from your profile page on CodeProject.

Extension Removal

The gadget can be removed by uninstalling from the Sidebar control panel.

Known Issues

As the gadgets are hosted within the Internet Explorer process, if you use the navigate to CodeProject button, Internet Explorer is opened, even if it is not your default browser, as window.open() is used.

References

History

(Version numbers relate to code changes, not article revisions.)

  • V1.2 - 21 March 2011: Persist settings on computer reboot
  • V1.1 - 19 January 2011: Persist settings on computer reboot
  • V1.0 - 11 December 2010: First version of the article and code release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

DaveAuld
Engineer
Scotland Scotland
I have been working in the Oil & Gas Industry for over 25 years now.
 
Core Discipline is Instrumentation and Control Systems.
 
Completed Bsc Honours Degree (B29 in Computing) with the Open University in 2012.
 
Currently, Offshore Installation Manager for the Beryl Bravo platform, which is located ~180 miles NE of Aberdeen, Scotland in the Northern North Sea.
Formely on the Forties Charlie platform, which is located ~110Miles NE of Aberdeen.
Follow on   Twitter   Google+   LinkedIn

Comments and Discussions

 
GeneralMy vote of 5 PinmemberYvan Rodrigues28-Nov-11 12:38 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.141216.1 | Last Updated 22 Mar 2011
Article Copyright 2010 by DaveAuld
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid