![]() |
Desktop Development »
Desktop Gadgets »
General
Intermediate
Soapbox Video GadgetBy Quartz.The power of MSN videos in your Windows Vista sidebar with Soapbox. Create and share your favorite video list |
Javascript, XML, CSSVista, Ajax, VS2005, Dev
|
|
Advanced Search Add to IE Search |
|
|
||||||||||||||||||
When I first started sidebar gadget development1, I found gadgets cool and innovative. But the more I learned about them, the more I realized their usefulness. Gadget development provides a whole new platform, becoming more productive in ways unimagined. On one hand, it's a mini web application which can host a web page, call a web service, and use AJAX to read an RSS feed. On the other, it can interact with the Windows API using the power of .NET languages. Wow! That's the best of both the worlds, wouldn't you agree?
The most important factor is the unique way in which a gadget provides the interaction between the web, Windows and users. In this example I try to utilize this, to give user the "Power of Videos" in the sidebar. Check the architecture below.
To hold your interest, here is how it looks in the sidebar.

Before I start, I must warn you: this gadget is quite addictive. Indulge yourself only during your spare time.
There are a number of RSS Feeds available from the Soapbox on MSN Video Beta page which give you the contents of the videos uploaded by the users. Some of the more interesting ones are: "Most Popular Videos", "Most Rated videos", and "Most Recent Videos". There is even a feed for "Videos By Tag" available, which we will use for searching videos. The idea behind this is to use those regularly updated feeds to show the user the video of his choice on the sidebar. If you want to know the basic barebones required to create a gadget, please refer to my first article Daily Dilbert . This article is actually an extension of that first article; I try to explain only those extra features which can be used to refine a gadget further:
The architecture overview

Let's Begin
A standard XML file with the name Gadget.xml is required as shown below:

More information about this is available here
The name of the gadget is "Soapbox @ MSN" (as seen above). The namespace is basically to group more than one gadget (reserved for future use), which you can write in "mynamespace". MinPlatformVersion. Required. The expected value is "1.0."
"Permission" controls the amount of permission in the gadget. "Full" permission is required if you want to access a webpage through the gadget. With these two files you can deploy and test your gadget in the sidebar. The <permission> tags and <type> tags will be more flexible in future versions of gadget development.
| Gadget.xml | An XML file defining the gadget properties, including name, icon and description |
| main.html | the Main HTML page |
| main.js | The core code/script for the gadget |
| Settings.html | Exposes gadget settings for the user to change |
| Settings.js | Script for the Settings file |
| soapboxFlyout.html | The html file which will be used in Flyout window |
| Icon, images etc | For use in the gadget selection box |
You can get more details on these here
The Main.html file will have five elements ("DIV") to get the feed data: cell0, cell1 etc. We can show the videos as a list of five videos (below) or single video.


We have the URL which we call using the MSXML2.XMLHTTP object. This is the core of the AJAX until the feed gets loaded. Here is the magical JavaScript for this:
function getRSS()
{
document.getElementById("mylogo").Title =
System.Gadget.Settings.
read("feedText");
try
{
error.style.visibility = "hidden";
loading.style.visibility = "visible";
rssObj = new ActiveXObject("Msxml2.XMLHTTP");
rssObj.open("GET",
System.Gadget.Settings.read("videoFeed") , true);
rssObj.onreadystatechange = function() {
if (rssObj.readyState = == 4)
{ if (rssObj.status == 200)
{ loading.innerText = "";
error.innerText = "";
error.style.visibility= "hidden";
loading.style.visibility = "hidden";
rssXML = rssObj.responseXML;
page = 0;
parseRSS();
if
(chkConn) { setInterval(getRSS, 60 * 60000);
loading.style.visibility = "hidden";
}
}
else
{
var chkConn;
loading.style.visibility = "visible";
chkConn = setInterval(getRSS, 30 * 60000);
}
} else {
loading.style.visibility = "visible";
}
}
rssObj.send(null);
}
catch(err)
{
loading.style.visibility = "hidden";
error.innerText = " Service not available";
error.style.visibility = "visible";
}
}
As you can see, if there is an error while connecting the feed or an error in the internet connection, we want to show the "Service not available" screen.

Here is the portion of the RSS Feed for a single item in the XML file and the corresponding "partial" ParseXML file to give you an idea of what we are doing with the feed.

function parseRSS(page)
{
rssItems = rssXML.getElementsByTagName("item");
rssTitle = null; rssAuthors = null; rssDescription = null;
rssLink = null;
rssTitle = escape(rssItems[i].firstChild.text);
rssLink =rssItems[i].getElementsByTagName("guid")[0]
.firstChild.nodeValue;
rssViews = rssItems[i].getElementsByTagName("vidAt:playCount")[0]
.firstChild.nodeValue;
rssDateUpdate = rssItems[i].getElementsByTagName("vidAt:pubDate")[0]
.firstChild.nodeValue;
rssRatingValue = rssItems[i].getElementsByTagName("vidAt:rating")[0]
.firstChild.nodeValue;
rssDuration = rssItems[i].getElementsByTagName("vidAt:duration")[0]
.firstChild.nodeValue;
rssVDescription= escape(rssItems[i].getElementsByTagName
("vidAt:description")[0].firstChild.nodeValue);
rssDescription=rssItems[i].getElementsByTagName("description")[0]
.firstChild
.nodeValue;
myTitle = unescape(rssTitle)
myTitle1 = myTitle.substr(0,16);
myRatingTip = "Rating: " + rssRatingValueFormated2 + ",
View: "
+ rssViews + ", Duration: " + rssDurationFormated ;
document.getElementById("cell" + (cell)).innerHTML =
"onclick="
showFlyout(\'' + rssTitle + '\',\'' + rssVDescription + '\',
\'' + rssLink + '\',\'' + rssImage + '\',\'' + rssRImage + '\',\''
+ rssViews + '\',
\'' + rssDateUpdate + '\',\'' + rssDurationFormated + '\',
\'' + rssRatingValueFormated2 + '\');" >
}
Since we have the feed required, we can create a flyout from the video. This is the showFlyout function, which is created dynamically and is used to pass all the parameters from the item to the flyout page.
function showFlyout(sTitle,sDescription,sGuid, sImage, sRImage,sView,
sDateUpdate,sDuration,sRatingFormated)
{
if (System.Gadget.Settings.read("sTitle")==sTitle)
{
System.Gadget.Settings.write("sTitle", "myTitle");
hideFlyout();
}
else
{
System.Gadget.Settings.write("sTitle", sTitle);
System.Gadget.Settings.write("sView", sView);
System.Gadget.Settings.write("sDateUpdate", sDateUpdate);
System.Gadget.Settings.write("sGuid", sGuid);
System.Gadget.Settings.write("sDescription", sDescription);
System.Gadget.Settings.write("sImage", sImage);
System.Gadget.Settings.write("sRImage", sRImage);
System.Gadget.Settings.write("sRatingFormated",
sRatingFormated);
System.Gadget.Settings.write("sDuration", sDuration);
System.Gadget.Flyout.file = "soapboxFlyout.html";
System.Gadget.Flyout.show = true;
}
}
Apart from the settings which are set on the showFlyout function, there are other settings which can be managed by the user. The user can search under "Video" or select from one of the Video feeds.
Once we have all the settings, we Build the video object in the flyout window.
function BuildVideoObject()
{
try
{
if (System.Gadget.Settings.read("videoSize")
=="large")
{
Video_HtmlString = '�OBJECT id="VIDEO"
width="640" height="480" ';
}
else
{
Video_HtmlString = '�OBJECT id="Body1"
width="320" height="240" ';
}
Video_HtmlString += 'style="position:absolute; left:0;top:0;"';
Video_HtmlString += 'CLASSID="CLSID:6BF52A52-394A-11d3-B153-"';
Video_HtmlString += 'type="application/x-oleobject"
VIEWASTEXT�';
Video_HtmlString += '�PARAM NAME="URL" VALUE="';
Video_HtmlString +=
"http:/soapbox.msn.com/StreamingUrl.aspx?vid="
+ System.Gadget.Settings.read("sGuid");
Video_HtmlString += '"��param NAME="stretchToFit"
VALUE="1"�';
Video_HtmlString += '�param name="AutoSize"
value="1"�
�PARAM NAME="SendPlayStateChangeEvents"
VALUE="True"�';
Video_HtmlString += '�PARAM NAME="AutoStart"
VALUE="True"�';
Video_HtmlString += '�PARAM name="uiMode"
value="none"�';
Video_HtmlString += '�PARAM name="PlayCount"
value="9999"�';
Video_HtmlString += '�/OBJECT�';
document.write(Video_HtmlString);
}
catch (err)
{
document.write("Problem with the machine's Windows Media
Player");
}
}
More information on the flyout is available here
Since XML files can have hundreds of items, we need to be able to page it. So we add a DIV item in the main.html file with the following:
![]()
�div id="tbar" title=""�
�table width="100%" height="100%" border="0" cellpadding="2" cellspacing="0"
ID="Table2"�
�tr align="center" valign="middle"�
�td width="12" class="arrow" onclick="chPage(-999);" align="right"�
��/td�
�td width="12" class="arrow" onclick="chPage(-1);" align="right"�
�b���/b��/td�
�td class="sub" id="pageNum"�1/1�/td�
�td width="12" class="arrow" onclick="chPage(+1);" align="left"�
�b���/b��/td�
�td width="12" class="arrow" onclick="chPage(+999);" align="left"�
��/td�
�/tr�
�/table�
�/div�
A Change page function will Parse the content of items to that page.
function chPage(off)
{
try
{
if (System.Gadget.Settings.read("listview"))
{
if (rssItems.length < 100)
{
myval = Math.ceil (rssItems.length/5);
}
else
{myval = 20;}
}
else
{
if (rssItems.length < 100)
{
myval = rssItems.length;
}
else
{myval = 100;}
}
if (off === -999)
{
off = myval-page;
}
if (off === 999)
{
off = myval-page-1;
}
try
{
if (((page + off) > -1) && ((page + off) < myval))
{
page = page + off;
parseRSS(page);
} else if ((page + off) === myval)
{
page = 0;
parseRSS(page);
} else if ((page + off) === 0)
{
page = myval;
parseRSS(page);
}
}
catch (err)
{
}
}
catch (err)
{
}
}

Now with each video you will see a plus icon in the bottom, so you can add the video to your favorites list.
function addtoFavorites(sGuid)
{
var variableName = "userprofile";
var mytext ="Testing";
try
{
var variableName = "userprofile";
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async="false";
xmlDoc.load(System.Environment.getEnvironmentVariable
(variableName) + "\\Videos\\SoapBoxFavorites.xml");
xmlObj=xmlDoc.documentElement;
rssAddItems = xmlObj.getElementsByTagName("channel");
rssAddedItems= xmlObj.getElementsByTagName("item");
var varAlreadythere = false;
if (rssItems[i].getElementsByTagName("guid")[0]
.firstChild.nodeValue == sGuid)
{
if (!varAlreadythere)
{
rssAddItems[0].appendChild(rssItems[i]);
}
break;
}
xmlDoc.save(System.Environment.getEnvironmentVariable
(variableName) + "\\Videos\\SoapBoxFavorites.xml");

When you click on the "Add to Favorite" icon it will add the XML feed information for that video from the online feed to a local XML file.
%userprofile%/Video/soapboxfavorites.xml
Here are the new settings to view your favorite videos. Select "My Favorite Videos" to see the bookmarked videos.

If any "My Favorites" are selected, the gadget will read from the local XML file.
if (System.Gadget.Settings.read("feedText").indexOf("My favorite") >=0)
{
try
{
var variableName = "userprofile";
var xmlDoc = new ActiveXObject("Msxml2.DOMDocument");
xmlDoc.load(System.Environment.getEnvironmentVariable(variableName)
+ "\\Videos\\SoapBoxFavorites.xml");
rssXML=xmlDoc;
parseRSS();
}
By default, the "My Favorite Video" list will show nine videos from the "Current Featured Feed".
Create the XML file for the first time from "Current Featured Feed".
var variableName = "userprofile"
var SoapboxFavoritesPath = System.Environment.getEnvironmentVariable
(variableName) + "\\Videos\\SoapBoxFavorites.xml";
rssObj = new ActiveXObject("Msxml2.XMLHTTP");
rssObj.open("GET",System.Gadget.Settings.read("videoFeed"),true);
rssObj.onreadystatechange = function()
{
if (rssObj.readyState === 4)
{
if (rssObj.status === 200)
{
try
{
System.Shell.itemFromPath(SoapboxFavoritesPath);
return;
}
catch (notFound)
{
var stream = new ActiveXObject("ADODB.Stream");
stream.Type = 1;
stream.Open();
stream.Write(rssObj.responseBody);
stream.SaveToFile(SoapboxFavoritesPath, 2);
stream.Close;
stream = null;
}
You can also remove the video from the Video list. Select My Favorite video, and then you can see the "Remove icon" after each video in the gadget.

function removefromFavorites(sGuid)
{
var variableName = "userprofile";
var mytext ="Testing";
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async="false";
xmlDoc.load(System.Environment.getEnvironmentVariable
(variableName) + "\\Videos\\SoapBoxFavorites.xml");
xmlObj=xmlDoc.documentElement;
rssRemoveItems = xmlObj.getElementsByTagName("item");
if (rssRemoveItems[i].getElementsByTagName("guid")
[0].firstChild.nodeValue==sGuid)
{
var lastNode=rssRemoveItems[i];
var delNode=xmlObj.firstChild.removeChild(lastNode);
xmlDoc.save(System.Environment.getEnvironmentVariable
(variableName) + "\\Videos\\SoapBoxFavorites.xml");
mytext = "Deleted and Saved";
break;
}
}
And we are done.
�param name="AutoSize" value="1"�try catch statement to avoid surprisestry catch Soapbox Gadget in Action : Size: 400 X 360 in flash player

General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 16 Apr 2007 Editor: Sean Ewington |
Copyright 2007 by Quartz. Everything else Copyright © CodeProject, 1999-2009 Web21 | Advertise on the Code Project |