Hawkman
Joined: 12 Jun 2005 Posts: 28 Location: Derby, UK
|
| Posted: Sun Sep 27, 2009 - 5:53 pm Post subject: |
|
|
I'm assuming you probably don't know much (any?) javascript. If you're looking at customising the widgets beyond the simple settings Apple provides, you'll need to know some. But, I'll walk you through a popup feeds widget. I'll be using Dashcode 3.0 (from Snow Leopard), though, so I can't guarantee this will work with the RSS widget from any other version.
First, get yourself a blank RSS widget. Fill out the details required in the checklist. Remember the feed url you enter; that one will be the default, and we'll need to make sure it's the top option in the popup.
Now, go to the widget design area. Select "front" from the source list to (cunningly) show the front:
Now, from the library (Window > Show Library), select a popup menu:
...and drag it to the widget. I suggest at the top, in the blue bar. Resize it with the handlers if you want. With this new popup menu selected, go to the Attributes tab in the Inspector window (Window > Show Inspector, if it isn't showing already):
You need to change the Label and Value for each option (add or delete options as you wish). Make sure the first one uses the url you set at the start, and is selected (dot is blue). Name -- any name you like -- under Label, and feed url under Value.
Next, switch to the Behaviours tab. We want it to do something when the value is changed, so we'll add an event handler for the onchange event:
Type just changeFeed, and hit enter. It will change to changefeed(event) automatically, and probably even take you to the new function it created in the bottom pane of the main window. If not, click the little arrow next to it:
Finally, we'll add the code which changes the feed when we change the popup:
Change the code to this:
| Code: | function changeFeed(event)
{
setFeedSource(this.getValue());
refreshFeed();
} |
You can stop here, but if you want to know how I worked that snippet of code out -- and I suggest that you perhaps should -- then read on.
How did I know what to write? Well, check out the functions in that main.js file. It looks scary, but Apple have set up the "load", "remove", "show" etc events to fire when those things happen to the widget. Clearly, the widget displays a feed when it's first placed, so the code to do that must be inside "load" (which fires first) or "show" (which fires afterwards, as well as every time Dashboard is shown). So, let's look at what those functions have in them:
| Code: | //
// Function: load()
// Called by HTML body element's onload event when the widget is ready to start
//
function load()
{
dashcode.setupParts();
numItemsToShow = +attributes.numItemsToShow;
maxAgeToShow = +attributes.maxAgeToShow;
showDate = attributes.showDate == 1;
slider = document.getElementById("slider");
scaleArticles(slider.value);
setFeedSource(attributes.feedURL);
} |
Hmm, not much about loading the feed here. (anything after // on a line is a non-code comment, by the way). But there's a very useful line "setFeedSource(attributes.feedURL);". It just takes a string, so we'd pass it the Value string from our popup; that's what "setFeedSource(this.getValue());" does in our changeFeed function.
Aside: Don't worry about this.getValue() -- "this" is a tricky bugger in javascript, but in this case it applies to the popup menu object, and "getValue()" is a function provided by the popup object which we dropped in. The popup object is designed by Apple, and to make it pretty it's more complicated than it technically has to be to merely operate... which is why they provide these nice useful functions. You can take my word for it that this is what you need, or you can have a peak at its functions in the PopupButton.js file inside the Parts folder and see for yourself:
Anyway, back to the code. Here's the other likely candidate from main.js, "show":
| Code: | //
// Function: show()
// Called when the widget has been shown
//
function show()
{
// Refresh feed if 15 minutes have passed since the last update
var now = (new Date).getTime();
if ((now - lastUpdated) > 15 * 60 * 1000) {
refreshFeed();
}
} |
Aha! It checks the time, compares it to the variable lastUpdated, and if there's a big enough difference (15 minutes) it does refreshFeed(). Now, there's a whole cascade of functions below refreshFeed that do the actual work. But they're all triggered by this one statement. (Apple do very clean design.) We don't want to check times or anything -- if our new code is running, someone changed the popup, so we want it refreshed right now! All we need is that one line, "refreshFeed();", and it'll fetch, tidy up and display our new feed -- based on the new url we set in the previous line.
There are many ways I could have implemented a multi-feed widget, and I chose this because it'd be easiest. I make no attempt to store items or check feeds in the background or anything fancy; that'd be possible, but involve LOTS more code. This really is just switching out the url, as though you'd set it up differently to begin with, and while it's dealing with one feed then as far as the widget is concerned the other one might as well not exist. I also can't guarantee that there won't be subtle bugs you'll run into by pulling the rug out from under the widget like this. But, it seems to be a fairly robust way of doing it, thanks entirely to the beauty of Apple's existing code.
Hope it's helpful. |
|