Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / XML

A shoutcast Radio sidebar gadget

4.33/5 (6 votes)
31 May 2007CPOL24 min read 1   807  
About writing sidebar gadgets

Screenshot - ScreenShot002.jpg

Introduction

In this article I want to introduce people to the art of sidebar gadget developing. The article is for beginners so I did my best to keep the code simple but a minimum knowledge of Javascript is required. We will use the 3 most basic parts: the gadget, flyout and settings window. This is my first attempt to write an article for codeproject. English is not my native language so I hope you don't mind my language too much.

Why a radio gadget

Like most people who install Windows Vista, the first thing I noticed was the sidebar. Being the owner of a shoutcast radio gave me the idea of designing a special gadget for it. The original gadget became a one station application, but for this article I made one you can use for all your favourite shoutcast servers.

Shoutcast is made by nullsoft so most people use it in combination with winamp. It works fine with Windows media player to, so we will use the ActiveX to play the streamed media from the gadget. But before we start, let us make a short list of what our sidebar gadget has to do. And most of all, mark out the problems we can encounter while creating it.

  1. The gadget must have a possibility to connect to all your favourite shoutcast radio stations. To do this we will use the settings in a way we can add, remove and select stations.
  2. I want to keep it simple for the article, so I just limit the controls to play, stop and volume control.
  3. My favourite part of the shoutcast server is the fact it has a list of recently played songs. The problem here is, it is only available in XML if you have the administrator's password of the server. Lucky normal listeners can read it from the ugly black HTML page the shoutcast server provides. For the gadget I will read that page to get the playlist information.

Preparing the project

Vista Sidebar gadgets are located in the gadget folder of the active user. This won't be a big surprise to you, considering that every user of your computer can install his own gadgets. We will design our gadget directly in this folder, this way we can see our work in the sidebar.
Every gadget in the gadget folder has its own subfolder using the following occurrence name.gadget. For the gadget we are making this will be radio.gadget.
You can browse the gadget folder located at:
%userprofile%\AppData\Local\Microsoft\Windows Sidebar\Gadgets

We can make the folder we need manual. It is even possible to make our gadget completely in Notepad or in a different text editor. Personally I prefer using Visual Web Developer. Like you can see in my profile, I live on a small budget therefore I use the express edition, but I am sure there won't be a big problem using the full version!

So open Web Developer and create a new website based on the "Empty Website" template. For location you use the following, but be sure to replace David with your own username!
:\Users\David\AppData\Local\Microsoft\Windows Sidebar\Gadgets\radio.gadget

This will open the empty project we will use for building our gadget.
The first thing to do is make a few folders. So right click in your Solution explorer and use the folder option to make 3 folders.

  • css: We will use this one to keep our css templates together.
  • images: Here we will keep the images we use for Icons and skin.
  • js: Similar to the css folder, but this is for keeping the JavaScripts.

Move all the images from the zip file to the images folder you just created.
This concludes the preparations we had to do and we are ready to start coding our little application!

Create the gadget's XML file

The gadget manifest is an XML file containing data about the author and the files used by the gadget. This XML is always called gadget.xml so the system can find it, all the other filenames you can make up yourself!

Right click the project in the Solution explorer and create a new item. From the templates you choose XML file and this way the header is already created for you.

XML
<?xml version="1.0" encoding="utf-8" ?>
<gadget>
  <name>Radio Gadget</name>
  <namespace>Gevaerts.Gadgets</namespace>
  <version>1.0.0.0</version> 

The first line was generated for us by web developer. After that we open the gadget XML tags. The first node is <name> and here we can give the name of our work. This name we find back in the gadget gallery, and on top of the settings window.
For <namespace> I filled in Gevaerts.Gadgets, but you can change it to whatever you want.
The <version> tag I put in 1.0.0.0 because this is the first release version of our gadget.

XML
<author name="David Gevaerts">
  <info url="www.gevaerts.org" />
  <logo src="images/radio.gif"/>
</author>

The node author name is optional but very useful! You can give it your own name and it has 2 optional elements. The info URL where you can enter a link to your website. And the logo src where you can enter a graphic associated with yourself.

XML
<copyright>© Gevaerts Organisations 2007</copyright>
<description>Radio gadget of the article</description>

These lines are optional, but are useful so it is a good idea to enter them. I don't believe they really need explanation.

XML
<icons>
  <icon height="48" width="48" src="images/radio.gif"/>
</icons>

The icons node is also optional. Vista uses a standard icon when you don't provide one. But why not make one yourself? You do all the effort of creating an application so take the time to make it good! For our example I made a radio icon radio.gif you can find in the images map.
And now the important part, the code that will make our gadget work.

XML
<hosts>
  <host name="sidebar">
    <base type="HTML" apiVersion="1.0.0" src="gadget.htm" />
    <permissions>Full</permissions>
    <platform minPlatformVersion="1.0" />
  </host>
</hosts>

The data we need is included inside the hosts node. The first element we use is the host. We are making a sidebar gadget, so for host name we use "sidebar". The first child is the base type, the type expected is "HTML" and we use apiVersion "1.0.0". The most important part here is the src where we make the connection to the HTML file of the gadget.
You can use any name you want. But the best strategy is keep it simple! I used gadget.htm so it is easy to find it later.
The next child of host is <permissions>. The Microsoft documentation says Full is expected, but I did not find more information about this.
The platform child is set to the minimum platform needed for the gadget. In our case this is Version="1.0". This is everything we need in our manifest file, the only thing we need to do now is close it with:

XML
</gadget> 

Create the gadget.htm

In our manifest we pointed to our source HTML file gadget.htm. This is the main part of our gadget. It is this file we will use to connect everything together using CSS, HTML and JavaScript. It also contains the body we see in the gadget bar.
First we will create 3 files. In the root of gadget we create the "gadget.htm" file, in our css folder we create "gadget.css". And last but not least in the js folder we make "gadget.js". The JavaScript file we handle later. But the .htm and .css I handle together because they are so closely related. After this part, the gadget will be visible in the gadget gallery.

HTML
<html xmlns="http://www.w3.org/1999/xhtml" >
<head> 
    <title>Radio gadget</title>
    <script type="text/javascript" src="js/gadget.js"></script>
    <link type="text/css" rel="stylesheet" href="css/gadget.css" />
</head> 

Sidebar gadgets are not that different from web applications, they are only smaller. So the htm file will look very familiar to you. The header for this project contains the title and links to the CSS file and the JavaScript.

HTML
<body onLoad="gadgetInit();">
    <object id="player" classid="CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6"
                      width="0" height="0"></object>
    <div id="PlayControle">
        <img  alt="Turn on the radio." src="images/PlayBut.png" 
            onmouseover="this.src='images/PlayButDark.png';" 
            onmouseout="this.src='images/PlayBut.png';" 
            onclick="startRadio();" />
    </div>
    <div id="playlist">
        <img  alt="Show the last played songs" src="images/PLBut.png" 
            onmouseover="this.src='images/PLButDark.png';" 
            onmouseout="this.src='images/PLBut.png';" 
            onclick="playlist();" />
    </div>
    <div id="vulumedown">
        <img  alt="Volume Up" src="images/VolMin.png" 
            onmouseover="this.src='images/VolMinDark.png';" 
            onmouseout="this.src='images/VolMin.png';" 
            onclick="volumeUp();" />
    </div>
    <div id="vulumeup">
        <img  alt="Volume Down" src="images/VolUp.png" 
            onmouseover="this.src='images/VolUpDark.png';" 
            onmouseout="this.src='images/VolUp.png';" 
            onclick="volumeDown();" />
    </div>    
    <div id="radioname">
    </div>    
</body>
</html> 

In the body tag we call the JavaScript function gadgetInit() when we load the gadget in the sidebar. But the body tag is handling a lot more. To show you this, look at the CSS file:

JavaScript
body 
{
    width:120;
    height:96;
    padding-top:0;
    padding-left:0;
    background-image: url(../images/RadioW.png);
} 

Notice we use the width and the height property to set the size our gadget will have in the sidebar. The width is set to the maximum of 120 pixels like Microsoft suggests. You can make it smaller. But when we all use the same width our sidebar will have a nice ordered look.The height you can make bigger if you like. A golden rule is "don't use more space than you really need".
Next we set the padding on 0 so our gadget takes the correct position in the sidebar. Also notice we set our radio graphic in the background image, our graphic is made 120 by 96 pixels so it won't repeat.

Back in the htm file we make an object to the media player the ID. We use this in the JavaScript later.
Now we create a few div tags we use for handling the control buttons. Note for the beginners, look how I use the onmouseover and onmouseout events to change the image. The onclick events are pointing to functions in the JavaScript file.
The CSS for these div's are almost the same, so I show only 1. Look in the source for the others.

JavaScript
div#PlayControle 
{
    position:absolute;
    width:28px;
    height:28px;
    top:68;
    left:34;
    z-index:1;
} 

This is what you find in the CSS for PlayControle. The position is absolute so we can position our buttons exact where we want it. Our buttons are 28 by 28 and we use the top and left to set the top left position of this control.
We are done with the HTML and CSS files, save them and open the gadget gallery. Bingo, our work shows up! You can install it in your sidebar if you want. In the next section, we will make it work!

The gadget JavaScript

We now have a sidebar, but there is just one problem! It is not doing anything. What we want to do now is make a connection to our favorite radio stations. Open up the gadget.js file created in the last chapter and enter the function below:

JavaScript
// The basic Javascript for the gadget
var player;
var state=1;
var radio = "http://radio.wartimememories.net:8004"

function gadgetInit()
{
    // To Do : Here you can enter your code to start the gadget
    player = document.getElementById('player');
    player.settings.volume = 80;

    // We need to do some gadget specials like creating the flyouts
    System.Gadget.Flyout.file = "Flyout.htm";
    System.Gadget.settingsUI = "Settings.htm";
    System.Gadget.onSettingsClosed = settingsClosed;
    radioname.innerHTML = System.Gadget.Settings.read("radioname");
} 

I use 3 global variables. One to hold the player, one to hold the state, the last keeps the radio station you want to connect to. I initialize the global variable radio with the main radio server. For the example I used my own server, but feel free to change it.
The gadgetInit function is called from the gadget.htm when we start up the gadget in the sidebar. It only handles a few initial tasks. Normally we will do a lot more work here, but for the tutorial I better keep it short.
I load the media player in the player variable using the getElementById and the ID we gave it in the HTML code. And we give it an initial volume of 80.

We will use a flyout for the last played list. And we will use the settings for adding and selecting radio servers. The Gadget API provides us with properties for this. Now create 2 extra htm files in the root of the project Flyout.htm and Settings.htm. These are the files will use for the settings- and the flyout window of the gadget.
The gadget needs to know what to do when the settings window is closed. This is important because it is possible we selected a different radio station! We do this by making the event System.Gadget.onSettingsClosed point to the function settingsClosed. I will explain this function later.
To finish we move the name of the selected radio to the radio name Window of the gadget. If no server was selected this Window stays empty.

JavaScript
function startRadio()
{
    if(state == 1)
    {
        player.URL = radio;
        state=0;
        PlayControle.innerHTML = "<img alt=\"Turn off Wartime Memories radio\"
        src=\"images/StopBut.png\" 
        onmouseover=\"this.src='images/StopButDark.png';\" 
        onmouseout=\"this.src='images/StopBut.png';\" 
        onclick=\"startRadio();\" />";
    }
    else
    {
        player.URL = "";
        state=1;
        PlayControle.innerHTML = "<img alt=\"Turn on Wartime Memories radio\" 
        src=\"images/PlayBut.png\" 
        onmouseover=\"this.src='images/PlayButDark.png';\" 
        onmouseout=\"this.src='images/PlayBut.png';\" 
        onclick=\"startRadio();\" />";
    }
} 

This function is the central part of the application. It starts and stops the selected radio according the status. If state is set to 1, the gadget is not playing and we will start it. We start a stream by loading the radio address in the URL property of the player. After this, we set the state to 0 and use the innerHTML of PlayControle to change the button into the stop button.
When the state was 0 we use the else. We stop the stream by loading an empty string into the URL property of the player. Like I told, for this article I want to keep it simple! We set the state back to 1 and change the button back to the play button. Easy like that, no fancy routines here but it will do the job.

JavaScript
function volumeUp()
{
    if(player.settings.volume < 100)
    {
        player.settings.volume = player.settings.volume + 10;
    }
} 

The function we call when a user clicks one of the volume buttons is very basic like you can see. Here you see the volumeUp routine. The volume down function is the opposite of this and I am sure you can figure it out for yourself. When a user clicks the volume up button we check if the player.settings.volume property is smaller then 100. If this is the case we add 10 to its value. The volume property is an integer between 0 and 100. I change it in steps of 10 but you can change it according your own needs.

JavaScript
function playlist()
{
    if(System.Gadget.Flyout.show)
    {
        System.Gadget.Flyout.show = false;
    }
    else
    {
        System.Gadget.Flyout.show = true;
    }
} 

When a user of the application clicks the playlist button, we want to present the list of last played songs. This list we will present to the user in the flyout Window. In the gadgetInit function we made the Flyout point to the Flyout.htm file, so all we need to do in this function, is check if the flyout show state is true or not. If it is true we make it false. This way the flyout becomes inactive. Else we make it true so the flyout becomes visible.

JavaScript
function settingsClosed(event)
{
    if(event.closeAction == event.Action.commit)
    {
        readSettings();
    }
} 

Here we see the function I was talking about before! It is this function we pointed the System.Gadget.onSettingsClosed event to. All we do here is check if the close action equals Acrion.commit and if this is the case we call our function readSettings. The readSettings function you see here is only responsible to read the settings we need in the main gadget. The radio name we directly move to the Window using innerHTML. And the URL address of the selected server is loaded to the radio variable. The global variable we need to connect to the server.

JavaScript
function readSettings()
{
    radio = System.Gadget.Settings.read("active");
    radioname.innerHTML = System.Gadget.Settings.read("radioname");
} 

Now it is a good time to check on your work. Install your gadget and see. When you click the play button the radio starts playing, you can stop it by clicking the stop button and you can pump up the volume.

This concludes the routines in the gadget.js files for the tutorial. Feel free to experiment with it and make your own version more advanced.

Screenshot - ScreenShot003.jpg

Making the flyout window

Now it is time to make our flyout and the play list. The HTML and the CSS for this part are really reduced to the minimum.

HTML
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
    <title>Recently played</title>
    <link href="css/flyout.css" rel="stylesheet" type="text/css" />
    <script type="text/javascript" src="js/flyout.js"></script>
</head>
<body onload="flyoutinit();">
    <div id="canvas">
    </div>
</body>
</html> 

The header contains the name of the flyout and set the links to the CSS and the JavaScript. It is exactly the same like we did in gadget.htm. The body uses the onload event to start the flyoutinit() function. We can find this in the flyout.js file. We only need one part in the body of the HTML code a div layer "canvas". This canvas div is used to make the playlist visible. Most of the flyout will be generated in the JavaScript. I don't think it is necessary to explain the CSS part here. It is really simple and more or less the same as gadget.css.

JavaScript
function flyoutinit()
{
    radio = System.Gadget.Settings.read("active");
    splitServer();
    getpage();
} 

When we open the flyout, the function flyoutinit() is called by the onload event in the HTML body tag. To present the last played list we need the address of our radio server. We can read this directly from our settings, the same way we did this in the main gadget JavaScript. The function makes 2 calls. One to splitServer, a function we use to split our radio URL to an address and a port number. The getpage function will then handle the rest like parsing the information, and present it on the canvas layer.

JavaScript
function splitServer()
{
    var re = new RegExp("^http://");
    work = radio.replace(re,"");
    work = work.split(":");
    adress = work[0];
    port = work[1];
} 

Here we use two simple regular expressions to break the radio URL in the address and the port we need for making the playlist. First we remove the http:// from the URL using the replace method. Now we have a work string we can split in the server address and the port. After the split method, work will be an array where work[0] contains the address and [1] the port. We have everything we need to make our playlist and present it to our user now. Here is the place we run into a few problems!

We want the information we need in XML format, so we can use AJAX to process it. The problem with the shoutcast server is, it only gives this information to authenticated administrators. If you build a website for your own server, this is not a problem. But in our case it is! We don't have the administrator password. Even if we make a one radio version, for a radio we own, we don't want to include it in the gadget. We don't want to give our listeners administrative access to the radio server. Moreover, it is not interesting to do it like this, in case we want to change the password.

Not everything is lost! Shoutcast provides us with that ugly black page with the song history. Maybe we can use this? Yes we can, but this brings us to a different problem! We can use AJAX to read HTML pages. But here we have a little problem with Explorer. Lots of forums are filled with information about the Internet Explorer cashing problem. A good trick to surround this is including the time string in the URL. This works perfectly on normal HTTP servers. The problem is, shoutcast is not a normal HTTP server! And it won't accept URL's with unknown GET arguments.

I had the same problem before when I was making a website with lists for a few servers. That time I created a PHP script for reading the shoutcast playlist and presented it in XML data. This script you can use like this and you are welcome to use it free of charge!

If you want to host this script yourself, feel free to write to me!
Now let us write our getpage() function.

JavaScript
function getpage()
{
    xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
    
    if(xmlHttp==null)
    {
        System.Gadget.Flyout.document.parentWindow.canvas.innerHTML = 
                "We found a problem with AJAX functionality!";
        return;
    }
    var d = new Date();
    url="http://wartimememories.net/shoutreader.php?adres="+adress+"
                        &port="+port+"&t="+d.getTime();
    xmlHttp.open("GET",url,true);
    xmlHttp.onreadystatechange = function()
    {
        if(xmlHttp.readyState == 4)
        {
            str = "<table width='100%'><tr><td bgcolor='Gray' 
                style='font-size: xx-small'>";
            str = str + xmlHttp.responseXML.getElementsByTagName
                ('played')[0].childNodes[0].nodeValue + " : ";
            str = str + xmlHttp.responseXML.getElementsByTagName
                ('title')[0].childNodes[0].nodeValue;
            str = str + "</td></tr>"
            for(i=1; i<xmlHttp.responseXML.getElementsByTagName
                ('played').length; i++)
            {
                str = str + "<tr><td bgcolor='Silver' style='font-size: 
                xx-small'>";
                str = str + xmlHttp.responseXML.getElementsByTagName
                ('played')[i].childNodes[0].nodeValue + " : ";
                str = str + xmlHttp.responseXML.getElementsByTagName
                ('title')[i].childNodes[0].nodeValue;
                str = str + "</td></tr>";
            }           
            str = str + "</table>";
            System.Gadget.Flyout.document.parentWindow.canvas.innerHTML =  str;
        }
    }
    xmlHttp.send();
} 

This is the longest function in the entire source code. It is not that difficult to understand. The biggest part of it is creating the HTML code for the list. The first thing we do here is loading the "Msxml2.XMLHTTP" ActiveX in xmlHttp and we check it was loaded correctly. If it was not loaded, we write an error message to the flyout and return. It is no use to continue without the ActiveX in place.

Next we generate a Date() object in d, we need this to generate our URL to surround the caching problem I mentioned before.
Now we have everything in place to create the URL. Note how we include the time. This is important or else we keep reading the same file from the cache over and over. Now we need to open the URL.

We don't really know when the server will report back. Therefore we make the onreadystatechange event point to a function. This function is called if the state of xmlHttp changes. If this is the case we check if this state equals 4 (this means our document is fully loaded).

We start a string that we use to add our HTML code too. With the getElementsByTagName method, we find the time and the title played. The first element [0] is the song currently playing we make this line darker in our first generated table row. We start the for loop after this handles the rest of the songs in the list. After we handled all the songs we write the resulting string to the canvas.

The last instruction of the getpage function will send the request to the web server.

All we need to do now is make the settings Window.

Screenshot - ScreenShot004.jpg

The Settings HTML and CSS

Our settings will handle a lot of what we want to do. It is easy to make a gadget with just 1 or more preassigned shoutcast servers. But this is not what we want! What we want is a gadget we can add our favourite servers to and select them. All this we will handle by the settings flyout. Different from the other parts, we will make this Window entirely using HTML and JavaScript.

HTML
<body onload="loadsettings();">
    <table>
        <tr>
            <td>
                <select id="RadioList" name="RadioList" size="10" 
            class="rsel" unselectable=on onclick="SelectRecord();">
                </select>
            </td>
            <td valign=top>
                <input id="Add" type="button" value="Add" class="but" 
                onclick="AddRecord();"  />
                <input id="Edit" type="button" value="Edit" class="but" 
                onclick="edit();" disabled />
                <input id="Del" type="button" value="Delete" class="but" 
                onclick="dele();" disabled />
            </td>
        </tr>
    </table>    

Like with the other HTML files we have seen in this article, the onload event will call the initial function in settings.js. Here we make a table with 2 columns. The first column will have our select list with the onclick event pointing to the function SelectRecord(). The other column will handle the Add, Edit and Delete button. The CSS for these parts is straightforward so I won't explain those here, but have a look at them in the source code.

HTML
    <div id="record">
        <table width="100%" height="100%" border="0">
            <tr height="15" valign="top">
                <td bgcolor=gray class="tdesc">
                    Name
                </td>
                <td bgcolor=silver>
                    <input id="rname" type="text" class="textf" />
                </td>
            </tr>
            <tr height="15" valign="top">
                <td bgcolor=gray class="tdesc">
                    URL
                </td>
                <td bgcolor=silver>
                    <input id="url" type="text" class="textf" />
                </td>
            </tr>
            <tr valign="top">
                <td bgcolor=gray class="tdesc">
                    Description
                </td>
                <td bgcolor=silver>
                    <textarea id="desc" class="descf"></textarea>
                </td>
             </tr>
       </table>
    </div>
</body>
</html>   

The record div, handles the visualisation of the selected radio record. It is also used for editing and adding records. We will use the JavaScript to handle this.

The Settings JavaScript

The settings.js is the biggest script of the project and it needs a lot of explanation. More then the rest of the application this part will do most of the work. The strange part is, when you need a 1 server gadget, you don't need it! If that is the case, just change the initial string in gadget.js to the radio server you want. But if you want a gadget where you can select and add different servers, this part of the code will make it possible.

JavaScript
var radioCount;
var oldSel=-1;
var radioRecords = new Array();
var recName;
var recAdress;
var recDesc;
var ed = false; 

First we create the global variables we need in this script. We need a variable to keep the amount of radio servers to choose from. One global variable to keep the old selection, the array we will use for the radio records, and the variables we will use for the selected record.

JavaScript
function loadsettings()
{
    radioCount = System.Gadget.Settings.read("radioCount");
    
    if(!radioCount) radioCount = 0;
    for(i=0; i<radioCount; i++)
    {
        radioRecords[i] = System.Gadget.Settings.read("radioRecord"+i);
        splitRec(radioRecords[i]);
        RadioList.options[i] = new Option(recName);
    }
    RadioList.selectedIndex = System.Gadget.Settings.read("selected");
    SelectRecord();
} 

When the settings Window is not open, all our information is saved in the individual gadget environment. When we open this Window the first thing we need to do is load them into our working environment, this is what we do in this function.

First we load the radioCount global with the radioCount from our gadget environment using the System.Gadget.Settings.read method. In case we don't have a previous radioCount saved we make our global 0.

The for loop will read the radio servers we saved before. It reads the radio records in our array. Then we split this record with the splitRec function. Now we use the recName to create a new option for the RadioList used to select our radio servers.

After the loop we read the selected radio in the RadioList.selectedIndex property, this way the selected radio will get highlighted in the listbox. With all the information in place we call the selectRecord() function to make the selected radio server visible in the Window.

We know how to read our information back but how do we write it? Let us look at the next function to explain this part.

JavaScript
System.Gadget.onSettingsClosing = function(event)
{
    if(event.closeAction == event.Action.commit)
    {
        if(ed) 
        {
            radioRecords[RadioList.options.selectedIndex] = 
            rname.value + "|" + url.value + "|" + desc.value;
            ed = false;
        }
        System.Gadget.Settings.write("active",url.value);
        System.Gadget.Settings.write("radioCount",radioCount);
        System.Gadget.Settings.write("selected",oldSel);
        System.Gadget.Settings.write("radioname",rname.value);        
        for(i=0; i<radioCount; i++)
        {
            System.Gadget.Settings.write("radioRecord"+i,radioRecords[i]);
        }
    }
    event.cancel = false;
} 

This is the function called when the settings Window is closing. The first thing we do is check if the event.closeAction equals the Action commit, in other words we check if we get here by clicking the OK button. If this is the case we check if ed is true. A true value for ed is set by the edit() routine and lets us know the user changed the record. In this case we need to create the record string in the radioRecords array so the changes will be saved. The structure of those records is easy to understand, we use the value of the input fields in the HTML and separate them with the | character in the string. We will use this character for separating them in the splitRec function described later. The last task we do in case of edited records, is set the ed global variable back to false.
Now it is time to save active, radioCount, selected and radioname. Using a for loop we now save our radioRecords. The last task we need to do in this function, is set the event.cancel to false.

JavaScript
function AddRecord()
{
    if(rname.value != "" && url.value != "")
    {
        radioRecords[RadioList.options.length] = rname.value + "|" + url.value + "|" + desc.value;
        radioCount = RadioList.options.length+1;
        RadioList.options[RadioList.options.length] = new Option(rname.value);
    }
} 

When we start our gadget for the first time it has no radio server information at all. Even when you install a new occurrence of the gadget it will be empty because every gadget has his settings. So the function we need the most at this time is to add our favourite radio stations.
In our record the name and the server URL are mandatory so we test if both values are entered. If this is not the case it is no use to add our record. The user can add a description if he wants but that is up to him.
We use the RadioList.options.length here. This gives us the amount of options in the RadioList. Because of the fact our array starts from 0 the amount of records is also the next empty index so we can use this to create our next radiorecord. The radioRecord is created exactly the same way I described in the previous function so I don't need to explain this again. The radioCount is set to length + 1 and we add a new option to the RadioList with the name of the server for value.
Our next function will select or deselect the servers from the listbox and creates the buttons and the record active when they are needed.

JavaScript
function SelectRecord()
{
    if(RadioList.selectedIndex == oldSel)
    {
        RadioList.selectedIndex = -1;
        rname.value = ""; rname.disabled = false;
        url.value = ""; url.disabled = false;
        desc.value = ""; desc.disabled = false;
        Add.disabled = false;
        Edit.disabled = true;
        Del.disabled = true;
    }
    else
    {       
        splitRec(radioRecords[RadioList.options.selectedIndex]);
        rname.value = recName; rname.disabled = true;
        url.value = recAdress; url.disabled = true;
        desc.value = recDesc; desc.disabled = true;
        Add.disabled = true;
        Edit.disabled = false;
        Del.disabled = false;
    }
    oldSel = RadioList.selectedIndex;
} 

I check if the selected option is equal to oldSel. If this is the case, we need to deselect the option. This is something I already answered in countless JavaScript beginner forums. For the ones new to JavaScript a selectedIndex of -1 means no option is selected.
We now create the fields in the record empty and make the disabled property false. This way we can type in the fields. We do the same with the disabled property of Add button. When no radio is selected we are able to add a new record. The opposite is also true, when no radio is selected we can't edit or delete one so we set the disabled properties of these buttons to true.
If the selectedIndex was not equal to oldSel it means we selected a new option from the list. In this case we need to fill the fields of our record with the values of the selected server and make the fields disabled so the user can't type in it.
We use the splitRec function to get the values in our selected array element. Then we move the record into the value from the input fields and in this case set the disabled properties to true. The buttons here are exactly the opposite from what we did before so make the property of the Add button true, and the Edit and Delete button f<code>alse. All we need to do now is set the oldSel global variable to the selectedIndex for later use.

JavaScript
function edit()
{
    rname.disabled = false;
    url.disabled = false;
    desc.disabled = false;
    ed = true;
} 

The edit function is very simple like you can see. The only thing we need to do here is set the disabled properties of our fields to false so we can edit them. Then set the global variable ed to d. This way our System.Gadget.onSettingsClosing event will save the changes when the user click the OK button.

JavaScript
function dele()
{
    radioRecords.splice(RadioList.options.selectedIndex,1);
    RadioList.options[RadioList.options.selectedIndex] = null;
    radioCount--;
} 

The dele() function uses the splice method to remove the selected record from our radioRecord array. To remove an option from the radioList we have to set it to null. If we now decrease the radiocounter the selected radio server is deleted.

JavaScript
function splitRec(work)
{
    work = work.split("|");
    recName = work[0];
    recAdress = work[1];
    recDesc = work[2];
} 

The last function we need to create is the one I mentioned a few times before. It is here we fill the global record variables. We use the split method using the "|" character. After the split we end up with an array in the work variable.

And now we are done! The radio gadget is created. All we need to do now is make a ZIP file named radio.zip and we move all the files and maps we have in our gadget directory to this ZIP file. When this is done we rename the ZIP file to radio.gadget and this will be the installable version of the gadget. Upload it to your website or share it with others!

Like I mentioned before, I have kept this gadget very limited and basic. Now it is time for you to get active, change it to suit your own needs. Make a volume bar for example or a text scroll showing the current song in the gadget graphic.

License

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