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

Beginning Mac OS X Tiger Dashboard Widget Development (2006)

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

iPhoto Mini

The leftButton and rightButton <div>s have the onclick functions for prevImage and nextImage to browse through the images in the albums. The reloadButton <div> has the loadAlbums(true) JavaScript function that rebuilds the list of iPhoto albums. Below these functions for the controls on the front of the widget, the preferences on the back side of the widget are included.

JavaScript Functionality

The iPhotoLoader plugin is central to the functionality of the iPhoto Mini widget. It reads the AlbumData.xml file to get the list of albums, can build paths to iPhoto’s library directories by reading the preferences file, and creates the path where one isn’t specified by assuming the default location in the user’s directory. Because it can get all of the album information, it provides the widget with all of the information about the number of photos and the number and names of the photo albums. The JavaScript functions to browse the pictures in the albums don’t directly call the plugin, but they make use of the information it provides. The global variables gCurrentImageIndex and gNumberOfImages in the prevImage and nextImage functions are populated with information from the plugin.

function prevImage() { --gCurrentImageIndex;

if (gCurrentImageIndex < 0) gCurrentImageIndex = gNumberOfImages-1;

changeImage(gCurrentImageIndex);

}

function nextImage() { ++gCurrentImageIndex;

if (gCurrentImageIndex > (gNumberOfImages-1)) gCurrentImageIndex = 0;

changeImage(gCurrentImageIndex);

}

Because the iPhotoLoader plugin reads the AlbumData.xml file, it is able to read the list of albums and get the number of photos in each album. The loadAlbums(reset) function is responsible for building or rebuilding the album information.

function loadAlbums(reset) { if (iPhotoLoader) {

if (reset) {

var result = iPhotoLoader.buildAlbums();

if (!result) { changeImage(-1);

}else {

var menuDiv = document.getElementById(“popupMenu”); var totalAlbums = iPhotoLoader.numberOfAlbums();

menuDiv.options.length = 0;

for (var i = 0; i < totalAlbums; i++) {

261

Chapter 17

var albumName = iPhotoLoader.nameOfAlbumAtIndex(i);

var imagesCount = iPhotoLoader.numberOfPhotosInAlbum(albumName);

menuDiv.options[i] = new Option(albumName+” (“+imagesCount+”)”, albumName);

}

menuDiv.options[0].selected = true;

popupChanged(document.getElementById(“popupMenu”));

}

}else {

if (widget.preferenceForKey(“randomPic”) && iPhotoLoader) { gCurrentImageIndex =

Math.random()*iPhotoLoader.numberOfPhotosInAlbum(gCurrentAlbum);

changeImage(gCurrentImageIndex);

}

}

}

}

The iPhotoLoader plugin also helps load the current photo in the application selected from the Action menu. The openInApp(appName) function gets the path to the photo inside of the iPhoto directories and launches the application with the path to the photo.

function openInApp(appName) { if (iPhotoLoader) {

var normalPath = unescape(gImage.src); var path = normalPath.split(“://”)[1];

iPhotoLoader.openImageAtPathWithApp(path, appName);

}

}

The actionPopupChanged() function gets the name of the custom application from the preferences and then calls the openInApp() function to give the custom application the path to the photo.

function actionPopupChanged(el) {

var value = el.options[el.selectedIndex].value;

if (value != undefined && value != “”) { if (value == “custom”)

value = widget.preferenceForKey(“customApp”);

openInApp(value);

}

el.options[0].selected = true;

}

Toward the end of the JavaScript file is the section that handles resizing the widget. It contains the mouseDown and mouseUp event handlers that make live resizing possible. The mouseDown handler is called whenever the resize control is clicked; it registers the handlers for the drag and the mouseUp at the end of the drag, and it records the size of the window.

262

iPhoto Mini

/* RESIZING */

var growboxInset;

function mouseDown(event) { document.addEventListener(“mousemove”, mouseMove, true); document.addEventListener(“mouseup”, mouseUp, true);

growboxInset = {x:(window.innerWidth - event.x), y:(window.innerHeight - event.y)};

event.stopPropagation();

event.preventDefault();

}

function mouseMove(event) {

var x = event.x + growboxInset.x; var y = event.y + growboxInset.y;

document.getElementById(“resize”).style.bottom = 17;

if (y <= 215) y = 215;

if (x <= 216) x = 216;

window.resizeTo(x,y);

var frontDiv = document.getElementById(“front”); front.style.height = window.outerHeight; front.style.width = window.outerWidth;

var photoDiv = document.getElementById(“photo”); var newHeight = y-38-30;

var newWidth = x;

var ratio = newWidth/newHeight;

photoDiv.style.height = newHeight; photoDiv.style.width = newWidth;

gImageMaxHeight = newHeight; gImageMaxWidth = newHeight*ratio;

imageLoaded();

event.stopPropagation();

event.preventDefault();

}

function mouseUp(event) { document.removeEventListener(“mousemove”, mouseMove, true); document.removeEventListener(“mouseup”, mouseUp, true);

263

Chapter 17

event.stopPropagation();

event.preventDefault();

}

The mouseMove function is called as the window is resized. It tracks the size of the drag and resizes the window accordingly. The function also calculates the ratio between the original size of the window and the resized window and adjusts the picture to fit in the resized window.

The mouseUp hander at the end of the section removes itself and the mouseMove function so they will not continue to be called with any additional clicks or drags.

Summar y

Like the Amazon Album Art widget, iPhoto Mini makes use of iPhoto’s libraries and adds missing features. By allowing you to open the photos directly in Mail, Safari, Preview, and another application, iPhoto Mini saves you the effort of either saving the picture to another directory or searching through the iPhoto directories to find the file. The ability to show a random picture from your albums is one

of those great touches that adds polish and sets iPhoto Mini apart from other widgets.

264

18

iTunes Connection

Monitor

One of the features of iTunes is that you can share your music with other users on your network. This is much easier than sharing CDs, but the feature has its drawbacks. If you quit iTunes while someone is listening to your music, it will tell you that users are connected (Figure 18-1), but it doesn’t tell you which users. Even though iTunes is up to version 6.0, identifying the connected audiophiles has never been added to iTunes.

iTunes Connection Monitor

As he has with an increasing number of applications, Jason Yee provides missing functionality, and then some, in a widget: iTunes Connection Monitor. The widget provides two views of the connections to your shared music. It provides a list of users who are listening to music in your shared music library and shows you which songs they are listening to.

While not as elaborate as some widgets, iTunes Connection Monitor does follow the Apple notion of a widget that does one thing very well.

Chapter 18

Figure 18-1

The Interface

The iTunes Connection Monitor may have the simplest interface of all the widgets you have looked at. It has two sides as most widgets do. The front side has a listing of users connected to your shared music library (Figure 18-2). The widget checks for connections each time you invoke Dashboard, but the reload button at the lower right of the widget will check again.

Figure 18-2

266

iTunes Connection Monitor

The back side of the widget doesn’t contain the widget’s preferences, but is another view of connections to your shared music library (see Figure 18-3). This view shows you the songs that the connected users are listening to.

Figure 18-3

iTunes Connection Monitor Internals

When you show the contents of the iTunes Connection Monitor, you may think this is the simplest widget you have ever seen (Figure 18-4). What you’ll immediately notice is that iTunes Connection Monitor does not have plugins, multiple JavaScripts, multiple images, or localized files. The Images directory contains only the flipper graphic and the front and back PNG files for the widget.

Part of the reason for this simplicity may be that while iTunes is scriptable using AppleScript, none of the commands allows you to see the connected users or the songs they are listening to.

Because the AppleScript dictionary in iTunes doesn’t support these functions (small surprise, given that they aren’t available in the application itself), Jason has to use a Unixy approach to get the information.

Figure 18-4

267

Chapter 18

Info.plist

In the Info.plist file, notice that only the AllowSystems access key is set. When you look at the JavaScript, you’ll see that the widget needs the AllowSystems access key enabled because it uses a command-line utility called lsof, which provides a list of all of the open files on your Macintosh.

<plist version=”1.0”> <dict>

<key>AllowMultipleInstances</key>

<false/>

<key>AllowSystem</key>

<true/>

<key>CFBundleIdentifier</key>

<string>com.argon18.widget.itcm</string>

<key>CFBundleName</key>

<string>iTCM</string>

<key>CFBundleDisplayName</key>

<string>iTCM</string>

<key>CFBundleShortVersionString</key>

<string>1.6</string>

<key>CFBundleVersion</key>

<string>1.6</string>

<key>DefaultImage</key>

<string>Default</string>

<key>Height</key>

<integer>203</integer>

<key>MainHTML</key>

<string>itcm.html</string>

<key>Width</key>

<integer>164</integer>

</dict>

</plist>

HTML/CSS

The CSS and JavaScript files are imported at the top of the HTML file. The front and back sides of the widget are very similar. The span on the front of the widget contains the text “Searching,” which is replaced with the list of the IP addresses of computers when the JavaScript has run the command to gather the connected users. If you have a hosts file configured, the IP addresses are replaced with the machine host names. The span on the back of the widget also contains the text “Searching.” This is replaced with the list of songs playing when the JavaScript has run the command to gather them.

<html>

<head>

<style type=”text/css”>@import “itcm.css”;</style>

<script type=”text/javascript” src=”itcm.js” charset=”utf-8”></script> </head>

<body>

<div id=”front”>

<img span=”backgroundImage” src=”Images/Default.png”> <span id=”connections”>Connected Users: Searching...</span>

<img id=”flipper” src=”Images/flipper.png” onclick=’flip(“front”)’> </div>

268

iTunes Connection Monitor

<div id=”back”>

<img span=”backgroundImage” src=”Images/Default2.png”> <span id=”songs”>Songs Playing: Searching...</span>

<img id=”flipper” src=”Images/flipper.png” onclick=’flip(“back”)’> </div>

</body>

</html>

For both the front and the back, the current visible <div> is passed as a parameter as a notification to flip to the other.

The connections selector in the itcm.css file sets the style for the list of IP addresses or machine names. The font line in the CSS file has multiple sizes and fonts to give Dashboard more than one option for rendering the widget if one or two of the fonts aren’t available. Notice that in addition to the three listed sans-serif faces — Verdana, Arial, and Helvetica — Jason has included the generic font face sans-serif.

body { margin: 0;

}

#connections {

font: 10px/12px Verdana,Arial,Helvetica,sans-serif; color: #FFFFFF;

position: absolute; top: 35px;

left: 20px; right: 20px;

}

#songs {

font: 10px/12px Verdana,Arial,Helvetica,sans-serif; color: #FFFFFF;

position: absolute; top: 35px;

left: 20px; right: 20px;

}

.backgroundImage { position: absolute; top: 0px;

left: 0px;

}

#flipper {

position: absolute; bottom: 5px; right: 5px;

}

#back { display: none;

}

269

Chapter 18

The flipper selector toward the bottom of the CSS file determines where the flipper button appears on the widget. It is set for five pixels from the right and five pixels from the bottom of the widget.

JavaScript Functionality

Even though it lacks user configurable preferences, the iTunes Connection Monitor does store a preference. If you open the widget-com.argon18.widget.itcm.plist file (Figure 18-5), you’ll see the solitary whichside preference.

Figure 18-5

This preference is the side of the widget — either front or back — that was open the last time Dashboard was open. The flip(side) function determines whether the front or the back side was open and writes the name of the side to the whichside parameter.

if(window.widget) { widget.onshow = onshow; widget.onremove = onremove;

}

function onshow() {

// called whenever widget is shown after first run searching();

load_info();

}

function onremove() {

270