Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Beginning Mac OS X Tiger Dashboard Widget Development (2006)

.pdf
Скачиваний:
19
Добавлен:
17.08.2013
Размер:
9.7 Mб
Скачать

More Widgets

<option value=”blogs_forums”>Blog & Forums</option> <option value=”business”>Business</option>

<option value=”calculate_convert”>Calculate & Convert</option> <option value=”developer”>Developer</option>

<option value=”email_messaging”>Email & Messaging</option> <option value=”food”>Food</option>

<option value=”games”>Games</option>

<option value=”information”>Information</option> <option value=”international”>International</option> <option value=”movie_tv”>Movies & TV</option> <option value=”music”>Music</option>

<option value=”networking_security”>Networking & Security</option> <option value=”news”>News</option>

<option value=”radio_podcasts”>Radio & Podcasts</option> <option value=”references”>References</option>

<option value=”search”>Search</option> <option value=”shopping”>Shopping</option> <option value=”sports”>Sports</option> <option value=”status”>Status</option>

<option value=”transportation”>Transportation</option> <option value=”travel”>Travel</option>

<option value=”webcams”>Webcams</option> </select>

<div id=’dashSite’ onmousedown=’gotoDashboardSite()’></div> </div>

<div id=”list”>

<div id=”list_left”> </div>

<div id=”list_middle”> </div>

<div id=”list_right”> </div>

</div>

<div id=”bottom”>

<div id=”bottom_left”> </div>

<div id=”bottom_middle”> <div id=”status”></div>

</div>

<div id=”bottom_right”> </div>

</div>

Toward the bottom of the HTML file are the contentParent and contentScrollArea <div>s for the content area where the items in the feeds are displayed. Below the content area <div>s are the details <div>s. Whenever you select a widget in the list, the detailed information about the widget is displayed in the detail pane that these <div>s specify.

<div id=”contentParent”>

<div id=”contentScrollArea”> <div id=”content”></div>

</div>

281

Chapter 19

<div id=”contentScrollbar”></div> </div>

<div id=”detailsParent”> <div id=”details_top”>

<div id=”details_top_left”> </div>

<div id=”details_top_middle”> </div>

<div id=”details_top_right”> </div>

</div>

<div id=”details_inner”>

<div id=”details_inner_left”> </div>

<div id=”details_inner_middle”> </div>

<div id=”details_inner_right”> </div>

</div>

<div id=”details_bottom”>

<div id=”details_bottom_left”> </div>

<div id=”details_bottom_middle”> </div>

<div id=”details_bottom_right”> </div>

</div>

<div id=”detailsInnerParent”> <div id=”detailsScrollArea”>

<div id=”details”></div> </div>

<div id=”detailsScrollbar”></div> </div>

<div id=”buttons”>

<div id=”cancelButton”></div> <div id=”moreInfoButton”></div>

</div>

</div>

<div id=’infoButton’></div>

<img id=’resize’ src=’/System/Library/WidgetResources/resize.png’ onmousedown=’mouseDown(event);’/>

</div>

<div id=”back”>

<div id=”credits”>

RSS Feed provided by <a href=”#” onclick=’widget.openURL(“http://www.apple.com/”)’>Apple</a><br />

Widget created by <a href=”#” onclick=’widget.openURL(“http://www.edotstudios.com/”)’>e dot studios</a><br />

<p class=”copy”>

© 2006 - e dot studios </p>

</div>

282

More Widgets

<div id=”donateButton”></div> <div id=’doneButton’></div>

</div>

</body>

</html>

If you open the Images directory (Figure 19-7), you’ll see the individual graphics corresponding to the

<div>s.

Figure 19-7

In the MW.css file, the comment line “Details” indicates where the selectors are for the details <div>s. Taking the selectors for the top row, you can see that they reference the tiles for the details area on the widget.

/* DETAILS */

#detailsParent { position: absolute; top: 50px;

bottom: 30px; left: 0px;

283

Chapter 19

right: 0px;

display: none; opacity: 0.0;

}

#details_top { position: absolute; top: 0px;

left: 0px; right: 0px;

height: 7px;

}

#details_top_left { position: absolute; top: 0px;

bottom: 0px; left: 0px;

width: 18px;

background-image: url(“Images/details_top_left.png”); background-repeat: no-repeat;

}

#details_top_middle { position: absolute; top: 0px;

bottom: 0px; left: 18px; right: 19px;

background-image: url(“Images/details_top_middle.png”); background-repeat: repeat-x;

}

#details_top_right { position: absolute; top: 0px;

bottom: 0px; right: 0px;

width: 19px;

background-image: url(“Images/details_top_right.png”); background-repeat: no-repeat;

}

The details content selectors are for the space where the details about each widget will be displayed. They specify the font and font size to use for the content, the amount of padding to set the margins, and the alignment of the paragraphs.

284

More Widgets

/* Details content */

#detailsInnerParent { position: absolute; top: 0px;

bottom: 0px; left: 10px; right: 10px;

font-family: “Lucida Grande”; font-size: 0.6em; text-align: center;

color: #fff;

}

#details {

position: absolute; top: 0px;

bottom: 25px; left: 0px; right: 19px;

padding-top: 5px; padding-left: 5px;

overflow: hidden;

}

#details p.text { text-align: left;

}

#buttons {

position: absolute; left: 15px;

right: 27px; bottom: 1px;

}

#cancelButton {

}

#moreInfoButton { position: absolute; right: 5px; bottom: 0px;

}

JavaScript Functionality

The MW.js file is neatly divided into sections for variables and initialization, functions, XML parsing, building the list, and resizing the widget.

285

Chapter 19

The changeCategory(index) function gets the appropriate listing for the category that you select from the Category pop-up menu. The first five lines are variables for tacking items associated with changing the category. The first variable holds the category that has been selected from the pop-up menu. The listDiv variable holds the listing of widgets. The statusDiv contains the status of the widget. It displays either the name of the currently selected category or, as you can see later in this function, a “Loading...” message while it fetches the content. The value and name variables contain the value that you selected from the category pop-up and the display name associated with that value.

function changeCategory(index) {

var selectionDiv = document.getElementById(“categoryPopup”); var listDiv = document.getElementById(“content”);

var statusDiv = document.getElementById(“status”);

var value = selectionDiv.options[index].value; var name = selectionDiv.options[index].text;

widget.setPreferenceForKey(index, “selectedIndex”);

if (value && value != “”) { //listDiv.innerText = “”; statusDiv.innerText = “Loading...”;

gCategoryName = name;

loadXMLDocument(gAppleDashFeedURL+value+”/recent.rss”);

}

}

The widget.setPreferenceForKey(index, “selectedIndex”) takes the selected category and writes it to the preferences file. By doing this, the next time you open Dashboard, More Widgets remembers your selection and gets the latest feed for it. The if statement at the end of the function sets the status to “Loading...” and gets the Recent widgets feed from the Dashboard site using the loadXMLDocument function.

The loadXMLDocument function is in the XML Parsing set of functions in MW.js. The functions in this section of the JavaScript take the contents of the RSS feed from the Apple Dashboard site and produce the listings for the More Widget’s content area. The loadXMLDocument(url) begins retrieving the Dashboard RSS feed using the XMLHttpRequest object which is from the WebKit, with the line xmlRequest = new XMLHttpRequest(). The following lines in the function begin processing the request by setting the header that will be sent, setting the mime type to XML, and making an open request. The processXMLRequest() function checks that the DOM tree was read successfully — the number 4 signals the completion of the transaction. If the DOM tree was read successfully, the function calls the parseXMLDocument(xmlRequest.responseXML) function with the response from the RSS feed.

/* XML Parsing */

var xmlRequest;

function loadXMLDocument(url) {

url += “?uselessParam” + (new Date()).getTime();

if (xmlRequest) {

286

More Widgets

xmlRequest.abort(); xmlRequest = null;

}

xmlRequest = new XMLHttpRequest();

xmlRequest.onreadystatechange = processXMLRequest; xmlRequest.setRequestHeader(“Cache-Control”, “no-cache”); xmlRequest.overrideMimeType(“text/xml”); xmlRequest.open(“GET”, url, true); xmlRequest.send(null);

}

function processXMLRequest() {

if (xmlRequest.readyState == 4) { parseXMLDocument(xmlRequest.responseXML);

}

}

The parseXMLDocument() function begins by calling the findChild function from the WebKit, which walks the DOM tree of the XML response. For each node that it finds on the tree, this parse function gets the description, link, content, and publication date of the widget and adds it to the array. When it is through walking the tree, it calls the build() function.

function parseXMLDocument(xmlData) {

var rssElement = findChild(xmlData, ‘rss’); if (!rssElement) {

//alert(“no rss tag found!”); return;

}

if (gItemsList) { delete gItemsList; gItemsList = null;

}

gItemsList = new Array();

var channelElement = findChild(rssElement, ‘channel’); if (!channelElement) {

//alert(“no channel tag found!”); return;

}

for (var element = channelElement.firstChild; element != null; element = element.nextSibling) {

if (element.nodeName = ‘item’) {

var title = findChild(element, ‘title’);

if (title != null) {

var desc = findChild(element, ‘description’); var link = findChild(element, ‘link’);

var html = findChild(element, ‘content:encoded’); var pubDate = findChild(element, ‘pubDate’);

287

Chapter 19

gItemsList.push(new Array(title.firstChild.nodeValue, desc.firstChild.nodeValue, link.firstChild.nodeValue, html.firstChild.nodeValue, ((pubDate == null) ? “” : pubDate.firstChild.nodeValue)));

}

}

}

build();

var statusDiv = document.getElementById(“status”); statusDiv.innerText = “Category: “+gCategoryName;

gContentScrollArea.refresh();

}

function findChild (element, nodeName) { var child;

for (child = element.firstChild; child != null; child = child.nextSibling) { if (child.nodeName == nodeName)

return child;

}

return null;

}

The build() function creates the HTML listing of widgets. It creates an unordered list and places each of the widgets as an item in that list. It also incorporates a mouseUp event to show the details of the widget whenever you click a widget in the list.

function build() {

var div = document.getElementById(“content”); var html = new String();

if (gItemsList.length > 0) { html += “<ul>”;

for (var i = 0; i < gItemsList.length; i++) { var type = (i % 2) ? “even” : “odd”;

html += “<li id=’item”+i+”’ class=’”+type+”’ onmouseup=\”showDetails(“+i+”)\” >”;

html += “<div id=’listTitle’>”+gItemsList[i][gFeedItemTitle]+”</div>”; html += “<div

id=’listDate’>”+parseDateItem(gItemsList[i][gFeedItemDate])+”</div>”; html += “</li>”;

}

html += “</ul>”; } else {

html += “No items!”;

}

div.innerHTML = html;

}

288

More Widgets

The showDetails(itemNr) function displays the details of the widget whenever you click the widget name in the scrolling list. This function gets the selected item and sets the background color to show that it has been selected. It gets the details of the selected widget, creates the HTML that is used to display the details information, and sets the details area to the HTML. The details window that covers the widget window is created using the details selectors in the MW.css file. The details graphics are stored in the Images directory.

function showDetails(itemNr) {

var itemDiv = document.getElementById(“item”+itemNr);

if (gSelectedItem != null) {

if (gSelectedItem != itemDiv) { gSelectedItem.style.background = “none”;

gSelectedItem.style.backgroundColor = gSelectedItem.bgColor; gSelectedItem.url = “”;

}

}

gSelectedItem = itemDiv;

gSelectedItem.bgColor = itemDiv.style.backgroundColor; gSelectedItem.url = gItemsList[itemNr][gFeedItemLink];

itemDiv.style.background = “url(Images/selection.png)”;

var detailsDiv = document.getElementById(“details”); var html = new String();

html += getWidgetImageURL(gItemsList[itemNr][gFeedItemContent])+”<br />”; html += “<p

class=\”text\”>”+getWidgetFullDescription(gItemsList[itemNr][gFeedItemContent])+”</

p>”;

detailsDiv.innerHTML = html;

gAnimator = new AppleAnimator(500, 25, 0, 1, detailsFader); gAnimator.start();

}

Summar y

Like other RSS feed widgets, More Widgets allows you monitor an RSS feed without using your browser. More Widgets takes XML data from Apple’s website and parses it to produce the scrolling list of widgets that are available at Dashboard Downloads. It does this using the XMLHttpRequest object and parsing the XML information that is returned. You are also able to get basic information about the widgets listed at Dashboard Downloads without launching a browser.

289