A Simple Windows 7 Gadget To Preview CodeProject’s Featured Articles

0
76

Editorial Note

This article is one of the articles in series that demonstrate the development of  the CodeProject’s foundation miscellaneous tools and API’s that can use easily and conveniently used for an offline articles editing, showing a member’s articles and reputation statistics, using search to find articles about topics a reader is interested in, etc. The Windows Vista/7 sidebar gadget introduced in this article is the most presently active and up-to-date web application that can be used to preview the featured contents once published at the CodeProject’s web site by its members and contributors. Hope that, the following gadget will be extremely useful for a large audience of readers and CodeProject’s members. Another valuable purpose of this paper and code being uploaded is to demonstrate how to easily create and deploy a Windows Vista/7 sidebar gadget based on the example announced above.

Introduction

“Gadgets are lightweight HTML and script-based applications that provide the abillity to derive and present information or functionality from a variety of sources, such as local applications and controls, or websites and services. Developers with experience authoring webpages will find the process of creating a gadget very familiar…” – Microsoft Developers Network (MSDN): Developing Gadgets For Windows Vista/7 Sidebar

In this article we’ll introduce the implementation of a simple lightweight Windows Vista/Seven desktop gadget that allows to preview the featured articles published and announced at the CodeProject’s web site main page. The following gadget will automatically refresh in the certain interval of time specified by a user to render new featured articles currently exhibited on the CodeProject’s main web page.  The using of this gadget will allow a user to keep up with the latest CodeProject’s featured articles published at the CodeProject the same way as if the user has navigated to https://www.codeproject.com/ with a regular web browser.

Moreover, the following gadget provides a functionality that could be especially useful to the CodeProject’s members contibuting articles to the CodeProject’s web site. In particular, when a featured article that a member once has published is presently annouced in the CodeProject’s main web page, the gadget reminds about the featured articles is being exhibited by either playing a notification sound or delaying on showing up the article’s announcement:

During the discussion, we’ll take a closer look at using various scripting languages such as HTML/CSS and JavaScript as well as some of the Microsoft UI developement tools and libraries such as Windows Gadget API functions namespace that allows to create the most of Windows 7 sidebar gadgets.

Specifically, we’ll make a focus on such fundamental aspects as using HTML/CSS markup language to create the gadget’s core web page rendered at the gadget’s window in the desktop’s sidebar. Particularly, we’ll explain how to use HTML and CSS-styles to author the basic layout of the gadget’s main web page. As well, we’ll delve into such important topics of the web application developement as the implementation of the basic gadget’s functionality by using DHTML/JavaScript language, including the event handling mechanism that orchestrates the dynamic responsive gadget’s behavior, Ajax-requests to download and retrieve the contents of the CodeProject’s main web page as well as  using the JavaScript’s regular expressions and other parsing mechnisms such as  (DOM – Document Object Model) to either extract particular data on the current article from the main web page being loaded from the CodeProject’s web server or update the gadget’s HTML-document programmatically, using timers to provide the gadget’s dynamic response by refreshing the gadget within a specific interval of time, etc.

In particular, we’ll demonstrate how to maintain the gadget’s main web page, that having a specific layout, will render the featured article’s related content in the gadget’s window region of the sidebar. At here, we’ll particularly spotlight on such topics as designing the gadget’s core web page, using CSS-stylesheets to provide the attribute values of certain HTML-elements in the gadget’s main web page HTML-document.

To provide the basic functionality of the gadget being discussed, we’ll find out how to implement the number of functions in JavaScript that will perform such tasks as rendering the gadget’s web page, externally loading the CodeProject’s main web page as well as retrieving and parsing its contents programmatically, based on using regular expressions and DOM, handling events to provide the basic gadget’s dynamic behavior and functionality such as refreshing the gadget’s window to show up the featured article announcement contents in a specific interval of time, using JavaScript’s random number generator to randomly select the CodeProject’s web site category under which the current featured article is exhibited, firing the sound notifications of the featured article once contributed by a specific CodeProject’s member, etc.

Additionally, we’ll spend a moment to discuss about creating the gadget’s settings dialog box that allow to personalize the using of the following gadget by setting the duration of the refresh interval in seconds, the name of member identity of the CodeProject’s member used for notification. In addition, we will discuss about such aspects of the Windows 7 sidebar gadgets deployment as creating the gadget’s installable packages, using various development tools to perform the gadget’s main scripts debugging, etc. 

Background

At this point, let’s thoroughly discuss about the fundamental steps of the development process, which, in the most cases, is based on using Microsoft UI desktop development tools, and is similar while creating the most of existing and new Windows Vista/7 sidebar gadgets.

Creating Project

The first important aspect that we’re about to discuss at the very beginning in this article is creating the new gadget’s project for a “scratch” containing all necessary files required to provide the gadget’s basic appearence and functionality under the Windows Vista/7 sidebar desktop application.

Specifically, at the very beginning we should create a simple directory, at the whatever location, locally at your PC, and name it, for example, CodeProject_FeaturedNotifier. Inside this directory we’re simply intended to create the following set of sub-directories and files:

The list of sub-directories to be created inside project’s directory:

./css – the sub-directory that will contain CSS-stylesheet files for the gadget’s HTML-documents such as either main.html and settings.html;

./js – the sub-directory that will contain the specific scripts that provide the gadget’s basic functionality;

./images – the sub-directory containing the images rendered within the gadget’s main HTML-document;

./sounds – the sub-directory containing the various sounds played when the gadget is used;

The list of the gadget’s project files:

./main.html – the core gadget’s main web page

./settings.html – the main gadget’s settings web page displayed within the settings dialog window;

./gadget.xml – the gadget’s main configuration file accessed and parsed by the sidebar application;

./css/gadget.css – the main CSS-stylesheet file loaded by the gadget’s main web page main.html;

./css/settings.css – the CSS-stylesheet file used in the settings.html layout;

./css/Main.min.css – the local copy of the main CodeProject’s web page CSS-stylesheet loaded by the gadget;

./js/main.js – the JavaScript file containing functions that implement the basic gadget’s functionality;

./js/settings.js – the JavaScript file containing functions written in JavaScript used to manage settings;

./images/logo468x60.png – the image containing the CodeProject’s logo rendered at the top of the gadget’s main web page;

./images/logo64x64.png – the image containing the gadget’s icon;

./sounds/notify.wav – the notification sound wav-file played when a member’s featured article is announced;

The Gadget’s Main Web Page Layout Using HTML/CSS

As we’ve already discussed in the introduction, the main component of each gadget is the main web page (e.g. main.html) that basically performs the rendering of the content exhibited on the Windows desktop within the gadget’s window region of the sidebar. To be more specific about the developement of the gadget being discussed, just to make it simple, we’ll not, in fact, implement our own custom layout for that purpose. Instead, we’ll use an already existing layout ported from the original CP’s main web page, the one, which is normally loaded in a web browser. This is typically done by retrieving the fragment of the original CP’s main web page HTML-document.

Also, for that purpose we’ll need to download and use the appropriate CSS-stylesheet externally located at the https://codeproject.global.ssl.fastly.net/App_Themes/CodeProject/Css/Main.min.css?dt=2.8.170713.1 file.  In this case, rather than downloading this CSS-stylesheet from the file everytime the gadget’s main web page is loaded, we’re just aiming to manually download this file and modify its contents by adjusting specific attribute values of several elements within the layout to make sure that the needed contents are properly rendered within the gadget’s window being discussed.

The following HTML-source illustrates the gadget’s main web page layout:

main.html:

<html xmlns="<a href="http://www.w3.org/1999/xhtml">http://www.w3.org/1999/xhtml</a>">
 <head>
 <title>CodeProject's Featured Article Gadget</title>
 <link type="text/css" rel="stylesheet" href="./css/gadget.css">
 <link type="text/css" rel="stylesheet" href="./css/Main.min.css">
 <script src="./js/main.js"></script>
 <meta http-equiv="Content-Type" content="text/html; charset=Unicode" />
 </head>
 <body class="cpfa_gadget" onload="getFeaturedArticle(1);">
 <table cellpadding="0" cellspacing="0">
 <tr>
 <td style="width: 100%; height: 40px">
 <a href="<a href="https://www.codeproject.com/">https://www.codeproject.com/</a>" target="_blank">
 <img src="./images/logo468x60.png" style="width: 100%; height: 100%;"></a>
 </td>
 </tr>
 <tr>
 <td><div id="featured-article" style="display: block; width: auto; height: auto;"></div></td>
 </tr>
 <tr><td align="center">
 <span id="navigate"><a><p style="color:#6600ff;">
 <b>BROWSE THIS ARTICLE!<b></p></a></span></div>
 </td></tr>
 </table>
 </body>
</html>

./css/gadget.css:

.cpfa_gadget{ margin: 0; width: 338px; height: 175px; font-family: verdana; font-weight: bold; font-size: 20px; }

./css/Main.min.css: https://codeproject.global.ssl.fastly.net/App_Themes/CodeProject/Css/Main.min.css?dt=2.8.170713.1

The main difference between the downloadable and local version of the Main.min.css file is that the values of an attribute for the certain page elements such as font size and dimensions were modified to provide the proper document contents rendering within the gadget’s window.

As you’ve might noticed from the code listed above, the gadget’s main web page main.html is really quite similar to any regular web page loaded by a web browser. It normally contains meta-tags specifying such meta-data as the content-type and character set, one or more external links to the local CSS and script-files, the body section of the document, in which we’ve used a table created by  adding specific <table></table> HTML-tags to provide the layout (or just a “skeleton”) of this page The following table contains three rows and a single cell in each. The single cell of the first row is used to render the image of the CodeProject’s logo added by using <img>-tag as well as providing the basic functionality of directly accessing the CodeProject’s main web page in the external browser. This is done by using <a>-tag with the value of parameter href statically specified to the CodeProject’s main page URL.

Another row correspondingly contains a cell created by using <td></td> tags, in which we normally render a dynamically loaded fragment the CodeProject’s main page exhibiting the featured article announcements. Typically the following fragment is defined by the <div class=”feature-article></div> tags and all other HTML-tags inside the following divs. Further we’ll discuss about how we normally use plain JavaScript code to either dynamically load or perform a small modification of the following fragment of the CodeProject’s main page HTML-document.

The cell of the final row is used to render an anchor <a href=”article_currently_announced_url”></a> HTML-element used to easily navigate to the currently announced article web page in the CodeProject’s web site.

Moreover, the <body> start tag also contains the event handling attribute onload=”getFeaturedArticle(1);”  that invokes the specific routine getFeaturedArticle(1); written in JavaScript that actually launches the main gadget’s contents rendering within the gadget’s window.

Besides, the gadget’s main page, at this point, we’ll also discuss about another HTML-document used as the settings dialog window layout. This document is located at the same directory as the gadget’s main web page and according to the pattern for creating sidebar gadgets has a standard reserved name such as settings.html:

settings.html:

<html xmlns="<a href="http://www.w3.org/1999/xhtml">http://www.w3.org/1999/xhtml</a>">
<head>
 <link href="./css/settings.css" rel="stylesheet" type="text/css" />
 <script src="./js/settings.js" type="text/javascript" language="javascript"></script>
 <title>CodeProject's Settings</title>
</head>
<body>
 <b>Interval:</b>
 <select name="interval">
 <option value="5">5</option>
 <option value="15">15</option>
 <option value="30">30</option>
 <option value="60">60</option>
 </select> secs
 <br/><b>Member's Name (e.g. "John Smith"):</b>
 <br/><input name="member" class="member" type="text" maxlength="75" />
 <br/><b>Autoreview:</b><input name="autoreview" type="checkbox" maxlength="75" />
</body>
</html>

./css/settings.css:

.member{ margin: 0; width: 260px; }
body { margin: 0; width:260px; height:120px; }

The settings.html document normally contains the either layout or the basic controls added by using specific HTML-tags such as <select><select> or <input type=”…”/> to provide the values of the main gadget’s parameters and options, including the combobox to choose the gadget’s refresh interval, checkbox for specifying whether we want to autoreview our own featured article, the nickname of a CodeProject’s member who once contributed one or many articles being annouced as the featured articles.

Along with the specific HTML-documents that constituent the gadget being discussed, we also use multiple CSS-stylesheets located at the sub-directory css of the gadget’s main project root directory. These files basically include:

  • ./css/gadget.css – containing a single style of the gadget’s main web page;
  • ./css/settings.css – containg styles for the settings HTML-document rendered within settings dialog window;
  • ./css/Main.min.css – containing style for the main page fragment externally loaded from the CodeProject’s web site. This file is normally manually download and ported to the gadget’s project;

The particular styles are listed above together with the listing of the specific gadget’s HTML-documents previously discussed.

Using JavaScript/AJAX To Implement The Gadget’s Basic Functionality

Besides the web page development guidelines, at this time, we’re about to discuss the details on how to implement the basic gadget’s functionality by creating specific scripts written in JavaScript that orchestrate the basic functions that implement the dynamic behaviour and response of the following gadget.

Before we begin, let’s again take a short glance at the HTML-document contained in the main.html file listed above. As we already know, the <body> tag of the entire gadget’s main web page has the onload=”getFeaturedArticle(1);” event handler being specified as an attribute. The onload event is normally fired and handled whenever the gadget’s main web page is loaded and the ready state is changed to “complete”. In this case, when the gadget is added to the sidebar by a user, its main web page is loaded and rendered within the gadget’s window. This normally causes the following event to be fired and handled by executing a specific function being invoked. (e.g. getFeaturedArticle(1)).

To be more specific, in this case, we’re initially invoke the getFeaturedArticle(cat_id) function implemented in the ./js/main.js script file, which performs the main job to dynamically load and render the gadget’s main web page contents:

var connection_id = 0;

function getFeaturedArticle(cat_id) {
 var xhttp = new XMLHttpRequest();
 var timeout_interval = parseInt(System.Gadget.Settings.read("interval"));
 xhttp.onreadystatechange = function() {
 if (this.readyState == 4 && this.status == 200) {
 var cpfa_contents = this.responseText.match(
 new RegExp('<div class="feature-article">' + '(.*)' + '</div>', "gm")).join();
 
 document.getElementById("featured-article").innerHTML = cpfa_contents;

 var cpfa_div = getElementByClassName("div", "thumbnail");
 var cpfa_title = getElementByClassName("div", "title");

 var cpfa_url = 'https://www.codeproject.com' + cpfa_div.childNodes.item(0).href.
 substring(cpfa_div.childNodes.item(0).href.indexOf("/Articles"));

 document.getElementById("navigate").childNodes.item(0).href = cpfa_url;
 
 cpfa_div.childNodes.item(0).removeAttribute("href");
 cpfa_title.childNodes.item(0).removeAttribute("href"); 
 
 var author_name = System.Gadget.Settings.read("author_name");
 if (author_name != "" && cpfa_contents.indexOf(author_name) > -1)
 {
 clearTimeout(connection_id);
 System.Sound.playSound("./sounds/notify.wav");

 if (System.Gadget.Settings.read("autoreview") == true)
 window.location.href = cpfa_url;

 connection_id = window.setTimeout(function() { getFeaturedArticle(1); },
 timeout_interval * 1000 * ((timeout_interval > 5) ? 2 : 5));
 }
 }
 }

 xhttp.open("GET", 'https://www.codeproject.com/?cat='+cat_id, true);
 xhttp.send();

 var cpfa_cats = new Array(1,2,9,10,18,22,23,24,25,26,27,28);
 connection_id = window.setTimeout(function() { getFeaturedArticle(cpfa_cats[Math.
 floor(Math.random() * cpfa_cats.length) + 1]); }, timeout_interval * 1000);
}

When the following function is executed, it’s normally performing an Ajax-request to the CodeProject’s web site to loading its main page. This is typically done, by using XMLHttpRequest or MSXML2.XMLHTTP.3.0 object being declared. Particularly to load the CodeProject’s main web page contents we’re invoking two methods of the either XMLHttpRequest.open(method, url, async) or XMLHttpRequest.send() to create an HTTP-request and dispatch it to the web server respectively. The  XMLHttpRequest.open(method, url, async) method normally accepts the three main parameters as its arguments including the HTTP-method “GET” or “POST” added to the HTTP-header being sent, the exact address URI-string of the web page loaded and, also, the parameter which value indicates whether we want to send an asynchronous requests to server.

In this case, we’re constructing the complete string containg the URL of the page being loaded, by using Javascript’s string manipulation operators. We’re normally using the value of the cat_id variable, passed as an argument to the getFeaturedArticle(cat_id) function. Also, we’re using HTTP-method “GET” and performing the asynchronous requests to the web server. After the appropriate HTTP-request is dispatched by calling the send method, we have to retrieve the HTML-contents of the main page being loaded from the CodeProject’s web site. To do this, we actually need to implement an anonimous callback function that will handle the onreadystatechange event when the HTTP-request is completed.

By implementing the following callback function, we’re actually creating the mechanism that performs the following tasks.

When the onreadystate event is fired and the callback is invoked, we’re actually performing a check if the ready state of the document loaded is “completed” and the HTTP-status code is equal to the success (code: 200). If so, we’re retrieving the contents being loaded from xhttp.responseText property of the XMLHttpRequest object.

Let’s remind beforehand, that, in this case, we normally could have used another slightly different property xhttp.responseXML to slipstream the process of parsing the loaded contents by using DOM objects. However, we cannot do this due to CORS cross-origin HTTP request policy violation set up and used in the CodeProject’s web server which normally prohibits and blocks parsing HTML-documents as XML in the resources other than the CodeProject’s web site.

That’s actually why, to parse and extract data from the loaded HTML-contents, we’re alternatively using Javascripts regular expressions, specifically RegExp object and match method that allows to process a regular expression such as <div class=”feature-article”>’ + ‘(.*)’ + ‘</div> to locate and extract the fragment of the CodeProject’s main web page announcing featured articles, when is being applied to the value of the responseText property. According to the CodeProject’s main web page document structure the entire fragment that renders the presently shown featured article which is located inside the <div class=”feature-article”>…</div> scope, located and extracted by using the mentioned above match method and RegExp object being created. As the result of the match method execution we’re obtaing the return value which actually is an array of the occurrences located by using the regular expression. Finally we’re using the array method join() to concate the all items of the following array into a string. The return value of the join() method is finally assigned to the cpfa_contents variable which value is the string containing the HTML-fragment being extracted from CodeProject’s main web page loaded:

var cpfa_contents = this.responseText.match(
 new RegExp('<div class="feature-article">' + '(.*)' + '</div>', "gm")).join();

Since we’ve retrieved the contents of the CodeProject’s main web page representing the featured articles by performing Ajax-request, we’re aiming to render the following contents in the core gadget’s web page. To do this, we’re obviously accessing the document object and invoke getElementById method to get an object of the <div class=”featured-article”></div> tag in the gadget’s web page inside of which we’re about to render the featured article contents previous retrieved. Particularly we’ll use innerHTML property of this object to dynamically add the following contents inside the following <div> tag. Finally, we’ll simply assign the value of the cpfa_contents variable to the following property:

document.getElementById("featured-article").innerHTML = cpfa_contents;

While processing the HTML-contents rendering a featured article loaded from the CodeProject’s main web page, we actually need to extract values located at the specific <div> and <span> tags to obtain the URL of the currently announced featured article. Unfortunately, the elements of the ready HTML-document fragment being loaded does not contain the id attiribute that makes the process of using DOM-objects is more complicated, since we need to get the objects of certain elements by their class-name.

From the other respect, another problem is that the sidebar desktop application, unlike the conventional IE web browser uses one of the existing minimalist beta-versions of WebBrowser ActiveX object to render core gadget’s web page, that actually might not support many features of the Javascript used in the regular browser. For example, unlike the fully-functional browsers, the getElementsByClassName(…) method is not supported by the sidebar desktop application.

To get object of a specific element by its class-name we have to implement our own custom getElementByClassName function, which allows to get such objects based on using another getElementsByTagName JavaScript DOM-function, which is currently supported:

function getElementByClassName(tag_name, class_name) {
 var object = document.getElementsByTagName(tag_name);
 for (var index = 0; index < object.length; index++)
 if (object[index].className == class_name)
 return object[index];
}

In this case, we’re obtaining the array of objects of each tag which name is specified as the first parameter of this function and performing a simple linear search by iterating through the following array of objects and find the specific tag objects with the class-name value assigned to the second function’s parameter. Since, such an object has been located the function is returning its value immidiately.

In the Javascript code being discussed, we normally invoke the following getElementByClassName(…) function twice to either get an object of the div-tags having the class name equal to the value “thumbnail” and “title” respectively:

            var cpfa_div = getElementByClassName("div", "thumbnail");
            var cpfa_title = getElementByClassName("div", "title");

After we’ve obtained those objects and assigned them to the cpfa_div and cpfa_title variables we’re extracting the values of the href-attribute of the two anchor-tags located inside those div-tags. The values of href-attribute contains the URL of the currently announced featured article.

Later on, by using those values we’re constructing the complete URL of the following article by using concate string manipulation functions including indexOf(…) function that is used to locate the index of the fragment of the URL-string being parsed that starts with “/Article” sub-string, as well as the substring(…) function by using which we’re extracting the URL string starting at the position returned by the indexOf(…) function.

As we already know, the original value of the href-attribute is assigned to the string containing the wrong URL-address that begins with, for example, “file://….”. This causes an article being rendered cannot be browsed in the external browser. o workaround this issue, we must actually “patch” the URL-strings being extracted by actually “hijacking” the correct URL-string:

var cpfa_url = 'https://www.codeproject.com' + cpfa_div.childNodes.item(0).href.
 substring(cpfa_div.childNodes.item(0).href.indexOf("/Articles"));

In this case, we’re using cpfa_div object previously obtained and accessing the childNodes property to invoke the item(0) method that allows to get an object of the first and only one child anchor tag inside the specific div-tag section. After that, we’re normally using the value of href property containing the URL-string assigned to the specific href-attribute of the anochor tag. Then, we’re locating and extracting the substring we need and append it to the string containing the URL-address of the CodeProject’s main web page. Finally, by doing this, we’re obtaining the usable valid URL-string for the current featured article and assign it to the cpfa_url variable.

Later, we’re assigning the value of cpfa_url variable to the href-attribute of the anchor tag with id=”navigate” used to display the link with text “BROWSE THIS ARTICLE” at the bottom of the gadget’s main web page:

document.getElementById("navigate").childNodes.item(0).href = cpfa_url;

Also, to remove the unusable links we’re removing the href-attribute from the specific anchor-tags within the HTML-fragment by executing the following code:

cpfa_div.childNodes.item(0).removeAttribute("href");
cpfa_title.childNodes.item(0).removeAttribute("href");

As we’ve already discussed, the following gadget normally shows up a different featured article in a specific  interval of time. To do this, we actually need to recursively invoke the same getFeaturedArticle function by using it as a callback of the window.setTimout Javascript function. This generic function normally executes getFeaturedArticle after a specific interval has ellapsed. The recursive invocation to the getFeaturedArticle provides the real-time content updates. To make sure, that we’re rendering a new featured article after each gadget’s refresh, we will implement and use the random selection of the CodeProject articles category. To do this we actually need to declare and use a separate array containing items that correspond to the existing category-id’s. Actually, we’ll use the Javascript Math.floor() and Math.random() functions to generate a value of index of item in the array of category-id’s. This way, we’re selecting a distinct value of category-id and pass it as a parameter of the getFeaturedArticle function. This value is then appended to the URL-string used as a parameter of XMLHttpRequest.open method as it has already been discussed.

Another parameter value that is used along with the window.setInterval function is the value of timeout that is normally read from the gadget’s settings by calling the following Windows Gadgets API function:

var timeout_interval = parseInt(System.Gadget.Settings.read("interval"));

The another essential aspect that I would like to make a focus on is the notification features of the gadget being created. This typically can be implemented by using the same string manipulation functions such as indexOf(…) to locate and extract the data on the author’s name of the current featured article. Also we need to use the same Windows Gadget API function shown above to retrieve the value of the author_name settings property value.

Since then, we’re performing another check if the author_name property value is set and occurs in the text of the featured article announcement, we’re clearing the current timeout value used by the window.setTimeout function using the value of the connection_id variable returned whenever this function is called. Also we’re using the appropriate Javascript built-in multimedia function to play a notification sound file ./sounds/notify.wav. After that we’re performing a check if the autopreview option is set by performing the similar steps described above. If so we’re setting the value of the window.location.href to the URL-string of the currently exhibited featured article assigned to the same cpfa_url variable. Finally, we’re modifying the value of the timeout interval parameter to make a delay on the member’s featured article rendering, and invoke window.setTimeout function over again, which typically causes the continious recursive call to the getFeaturedArticle function. In this case, we’re using an initial value of this function single parameter equal to 1. It means that the featured articles retrieval and rendering will start over from the category having id equal to 1, as follows:

var author_name = System.Gadget.Settings.read("author_name");
if (author_name != "" && cpfa_contents.indexOf(author_name) > -1)
{ clearTimeout(connection_id); System.Sound.playSound("./sounds/notify.wav"); if (System.Gadget.Settings.read("autoreview") == true) window.location.href = cpfa_url; connection_id = window.setTimeout(function() { getFeaturedArticle(1); }, timeout_interval * 1000 * ((timeout_interval > 5) ? 2 : 5));
}

At last, the final gadget’s developement topic which we’re about to discuss, is creating the appropriate script and the couple of functions used to either get or set the value of the settings parameters that personalize the general behavior of the following gadget being used.

For that purpose, we must create the settings.js file loaded and used in the settings.html document. In the following file, we’re implementing the two functions including the function that similarly handles the onreadystatechange event as well as another anonimous callback function which is assigned to the System.Gadget.onSettingsClosing property. The first function is used to read the values of each user-defined settings property and assign it to specific controls in the settings.html document to be displayed when settings dialog window is open. The second function is used to handle the settings dialog window close or commit event and save the values of those parameters being set by invoking System.Gadget.Settings.write API-function:

document.onreadystatechange = function()
{ 
 if (document.readyState=="complete")
 {
 member.value = System.Gadget.Settings.read("author_name");
 interval.selectedIndex = System.Gadget.Settings.read("timeout");
 autoreview.checked = System.Gadget.Settings.read("autoreview");
 } 
}

System.Gadget.onSettingsClosing = function(event)
{
 if (event.closeAction == event.Action.commit)
 {
 System.Gadget.Settings.write("author_name", member.value); 
 System.Gadget.Settings.write("timeout", interval.selectedIndex);
 System.Gadget.Settings.write("autoreview", autoreview.checked);
 System.Gadget.Settings.write("interval", interval.options[interval.selectedIndex].value);

 event.cancel = false;
 }
}

One more topic which is also worth to discuss in this article is creating gadget flyouts, but the following discussion actually goes beyond the main point of this article, since the gadget being introduced and developed is not intended to contain any flyout windows that could be used to render various extra info’s on the featured article being announced.

Creating The Gadget’s Configuration XML Script

The final essential step for developing the gadget being discussed, that makes the following gadgets installable and usable, is the step at which we’re creating the gadget’s main configuration file gadget.xml which contents are listed below:

="1.0"="utf-8"
<gadget>
  <name>CodeProject's Featured Articles</name>
  <namespace>CodeProject.API</namespace>
  <version>1.0.0.0</version>
  <author name="Arthur V. Ratz">
    <info url="<a href="https://www.codeproject.com/script/Membership/View.aspx?mid=11760135">https://www.codeproject.com/script/Membership/View.aspx?mid=11760135</a>" />
    <logo src="./images/logo64x64.png" />
  </author>
  <copyright>CPOL © Arthur V. Ratz</copyright>
  <description>"Preview CodeProject's Featured Articles"</description>
  <icons>
   <icon height="64" width="64" src="./images/logo64x64.png" /></icons>
  <hosts>
    <host name="sidebar">
      <base type="HTML" apiVersion="1.0.0" src="./main.html" />
      <permissions>Full</permissions>
      <platform minPlatformVersion="1.0" />
    </host>
  </hosts>
</gadget>

As you’ve might noticed from the XML code above, the following configuration script has the following tags, each one corresponding to a specific entity and parameters. In particular, in this script, we’re using such descriptive tags as <name> which allows to specify the name of the gadget, namespace, version, author name, copyright details, the external author’s URL link, etc. Also, in this script we’re creating such other entities as the <icon> which is basically provides the path to the gadget’s logo file and its sizes. The special case among those gadget’s configuration entites is the <base>, <permissions> and <platform> tags by adding which we actually specify the path and filename of the core gadget’s main web page HTML-document, the severity of the sidebar security policy and the sidebar platform minimal version. Notice, that the gadget won’t run unless you create all these mentioned above entities in the gadget.xml file.

Using the code

How To Deploy, Install, Use This Project

Deploying The Complete Gadget’s Package

Finally, after we’ve created all project files as the result of the gadget’s development process, we’ll further need to create a gadget’s package. This can be typically done by using, for example, one of the existing file compressors that allow to create zip-archievies. As the result of compressing all those files in the project’s parent directory, we’ll get CodeProject_FeaturedNotifier.zip file. Now, to be able to install and use the gadget, we’ll actually need to simply rename the following archieve file to CodeProject_FeaturedNotifier.gadget. Since then, to install the newly created gadget, we’ll have to double click on the following gadget-file and confirm install it when prompted by a specific dialog box. Finally, the installed gadget will appear in the desktop’s sidebar:

To explore and delve into the code as a part of the gadget’s project, just navigate to the other directories such as root directory, css, js, images and sounds.

Installing The Gadget Ready

To use the gadget being discussed, just download the CodeProject_FeaturedNotifier.zip  archieve file and navigate to the CodeProject_FeaturedNotifier\installer directory and just run the gadget’s package (e.g. CodeProject_FeaturedNotifier.gadget). This will install the following gadget in the Windows sidebar and make it visible. Please note that the Windows Vista/7 sidebar gadgets when being installed are located at  

%USERPROFILE%\AppData\Local\Microsoft\Windows Sidebar\Gadgets\CodeProject_FeaturedNotifier.gadget

Debugging Guidelines

Also you can try to debug the code being executed during the gadget is added to the sidebar and visible by using Microsoft Visual Studio debugger. For that purpose, under the IE web browser settings Internet Explorer 11\Tools\Internet Options untick two checkboxes: disable script debugging (Internet Explorer) and disable script debugging (other):

After that launch Microsoft Visual Studio and navigate to the Microsoft Visual Studio\debug menu and toggle Attach To Process option. Finally, the dialog window in which we’ll need to locate and specify the sidebar process, will appear:

After selecting the sidebar process, the scripts debugging will just begin. To perform the actual debugging, we’ll need to navigate the Visual Studio solution explorer’s left pane to locate our gadget for debugging. By doing this, the gadget’s scripts contents will appear in the Visual Studio’s editor which allows to either set debug breakpoints or inspect the value of the particular variables with the autos or watch pane:

Optionally, we can use the IE or other browser’s built-in native development tools for the similar purpose. To do this just navigate to Tools\F12 Developer Tools option to either preview HTML-documents DOM or launch the scripts debugging process.

Points of Interest

I have created the Windows Vista/7 sidebar gadget just for fun and for my own needs, but it also can be useful to the other CodeProject.Com members who contribute various articles, as well as for the audience of readers and also enterpreneur and experienced IT-professionals who passionate reading articles published at the CodeProject web site.

Feedback

I encourage everyone who has read or reviewed this article to send me any feedback including the gadget’s bugs reports, your especial thanks, wishes to use a better gadget or code, various comments, votes, etc. The readers can contact me by submitting their posts to the article’s discussion forum below, or by directly sending messages to my e-mail address at artvratz@gmail.com

That’s all folks.

Best Regards, Arthur V. Ratz.

History

  • July 28, 2017 – The first revision of the article has been published (the basic gadget’s functionality has been discussed).

LEAVE A REPLY