JavaScript Walkthrough #2: Setting
For this Gadget, the Settings panel needed to read and parse a current XML list of subjects and categories, allow the user to navigate through them, and save selected options to be used for filtering headlines. Much like the Gadget itself, the settings code starts off by instantiating an XMLHTTP object (notice that I don't need to code for other browsers since I know this can only be used in a Sidebar).
function buildSettings() {
System.Gadget.Flyout.show = false;
System.Gadget.onSettingsClosing = settingsClosing;
try {
cats = new ActiveXObject('Msxml2.XMLHTTP');
url = 'http://services.devx.com/gadget/dnet_gadget_categories.xml';
cats.open('GET', url, true);
cats.onreadystatechange = catchCats;
cats.send(null);
} catch (err) {
System.Gadget.Settings.write('subject','Not Available');
System.Gadget.Settings.write('category','Not Available');
cats = null;
}
}
After catching the handoff, the next function aligns individual category and subject counters to the current Gadget settings. By starting at the last element and rolling backwards, the categories naturally default to the first element, 0, if for some reason the XML category lists are edited and the user's current element is deleted.
categories = xmlCats.getElementsByTagName('category_item');
subjects = xmlCats.getElementsByTagName('subject_item');
for (thisCat=categories.length; thisCat>0; thisCat--)
{
if (categories[thisCat-1].text == System.Gadget.Settings.read('category'))
{
thisCat--; // Counter should represent index, not count
break;
}
}
for (thisSub=subjects.length; thisSub>0; thisSub--)
{
if (subjects[thisSub-1].text == System.Gadget.Settings.read('subject'))
{
thisSub--;
break;
}
}
category_text.innerHTML = System.Gadget.Settings.read('category');
subject_text.innerHTML = System.Gadget.Settings.read('subject');
Admittedly, the category and subject navigation on the Settings panel lacks a little something. Blessed with an abundance of neither time nor imagination, I opted for a simple forward-only loop triggered by the <div> tags' onclick events. At least they reset to the start when they reach the end. That's fancy.
function changeSubject() {
thisSub++;
if (thisSub == subjects.length)
{
thisSub=0;
}
subject_text.innerHTML = subjects[thisSub].text;
}
function changeCategory() {
thisCat++;
if (thisCat == categories.length)
{
thisCat=0;
}
category_text.innerHTML = categories[thisCat].text;
}
Going from main to flyout involved only the transfer of data, which I could perform using the Settings object, because I could expect the flyout's onload event to fire every time it was used. Also, the communication between the two is one-way, i.e. I didn't need to capture any data coming from flyout back to main.
However, the relationship between settings and main is a little more complicated because use of the Settings panel not only involves transfer of data back to main but also a Commit or Cancel action that determines if that data is used. Further, main is already loaded and won't reload as long as the Gadget is in the Sidebar, so I couldn't take advantage of the onload event like I could with the flyout. Though there may be other events I could play with more or less reliably, the gadget API includes events that fire during use of the Settings panel, which makes the job much easier.
I decided to separate settings code from the rest for more discreet functionality. I also used the combination of onSettingsClosing and onSettingsClosed to pass control from the Settings panel back to the Gadget itself, while saving and reading data in a manner similar to the flyout. In the last section, you saw where the Gadget code takes up the action after the Settings panel is closed. Here's where the settings code makes the first step, though.
function settingsClosing(event)
{
if(event.closeAction == event.Action.commit)
{
saveSettings();
}
else if (event.closeAction == event.Action.cancel)
{
}
}
Obviously, a lot more can be done here than I'm doing. Take a look at the Gadgets that come with Windows Vista and you'll see much more robust use of these events. But for the purposes of this project, it accomplishes everything we need: either it saves the user's choices or it doesn't.
function saveSettings() {
System.Gadget.Settings.write('category',categories[thisCat].text);
System.Gadget.Settings.write('subject',subjects[thisSub].text);
}