A Dashboard Widget
that Reads and Saves
its Preferences
Volume Number: 24
Issue Number: 10
Column Tag: Dashboard Widgets
A Dashboard Widget
that Reads and Saves
its Preferences
Create a Dashboard Widget that can save and read data after restarting it.
by Mihalis Tsoukalos
Introduction
In this article I am going to illustrate how to create a Dashboard Widget that saves its preferences. After saving the preferences, you will learn how to read and use the saved information and display the selected data in the front side of the Widget. The name of the Widget is "Save Prefs".
The files that compose the Widget
Figure 1 shows the files of the Widget as well as their sizes (in bytes).
Figure 1: The files that compose the "Save Prefs" Widget.
As you can understand by looking at Figure 1, the "Save Prefs" Widget is relatively simple. You should notice that it has a directory -the AppleClasses directory- that contains three JavaScript files. Apple provides the contents of the AppleClasses directory and the only thing that you should do is to copy the three JavaScript files inside your Widget's directory.
Also, as you will see in the next section, you will have to include them in the main HTML file of your Widget. Source code for this project can be downloaded from ftp.mactech.com/src/mactech/volume24_2008/24.10.sit. The source archive contains the following files:
SavePrefs.html file
SavePrefs.js file
SavePrefs.css
Info.plist
You may think that the SavePrefs.js JavaScript file contains a lot of code but most of the code is typical when creating a Dashboard Widget. The showPrefs() and hidePrefs() functions are used for watching and hiding the back side of the Widget and you usually have to copy and paste their definitions to your new Widgets.
The SavePrefs.css file
The CSS file looks pretty simple. Nevertheless, if you make small mistakes to the CSS code the Widget may misbehave very badly! I am saying this because I had some problems with the #OptionPopup declaration. Due to my wrong declarations the option list was displayed outside of the Widget area and I could not see it at all!
The Info.plist file
The Info.plist file is pretty simple and is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BackwardsCompatibleClassLookup</key>
<true/>
<key>CFBundleDisplayName</key>
<string>Save Prefs</string>
<key>CFBundleIdentifier</key>
<string>com.mtsouk.widget.saveprefs</string>
<key>CFBundleName</key>
<string>Save Prefs</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>CloseBoxInsetX</key>
<integer>14</integer>
<key>CloseBoxInsetY</key>
<integer>16</integer>
<key>MainHTML</key>
<string>SavePrefs.html</string>
</dict>
</plist>
Explaining the Technique
The presented technique uses the following two JavaScript methods:
- widget.preferenceForKey(keyName): This method tries to read the value of a key, if the value is already saved.
- widget.setPreferenceForKey(value, keyName): This method sets the value of a key. The Dashboard Reference suggests that you should pass null in order to delete an existing key.
Apple suggests that you utilize the widget.preferenceForKey(keyName) function using the following practice:
if(window.widget)
{
var optionString = widget.preferenceForKey("optionString");
if (optionString && optionString.length > 0)
{
optionText.innerText = optionString;
}
}
Similarly, Apple suggests that you use the widget.setPreferenceForKey(value, keyName) function as follows:
if(window.widget)
{
widget.setPreferenceForKey("Hello MacTech!","optionString");
}
A word of advice: The described method stores strings without any encryption. It is therefore not a secure way to store your sensitive information.
The following lines of JavaScript code declare two global variables, called glassDoneButton and whiteInfoButton, respectively. Each of the two variables holds one button. The first declaration creates the done button whereas the second declaration creates that little info (i) button that you frequently see in Widgets.
var glassDoneButton;
var whiteInfoButton;
The following JavaScript code implements the two button definitions:
glassDoneButton = new AppleGlassButton(document.getElementById("doneButton"),
"Done", hidePrefs);
whiteInfoButton = new AppleInfoButton(document.getElementById("infoButton"),
document.getElementById("front"), "white", "white", showPrefs);
The following command line output text explains where Dashboard keeps the Widget stored information using the described method:
mtsouk$ ll ~/Library/Preferences/widget-com.mtsouk.widget.saveprefs.plist
-rw
1 mtsouk mtsouk 98 May 18 22:13
/Users/mtsouk/Library/Preferences/widget-com.mtsouk.widget.saveprefs.plist
mtsouk$
The contents of the widget-com.mtsouk.widget.save-prefs.plist file are the following:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>OptionString</key>
<string>Option 4</string>
</dict>
</plist>
Figure 2: The final look of the presented Widget (both sides).
A word of advice: You can now understand why it is extremely important to have a uniquely defined CFBundleIdentifier key for every Widget that you create or use. The above plist file that stores the Widget preferences uses the CFBundleIdentifier value as a part of its filename. It is also important to have a UNIQUE CFBundleName key because if you try to install a Widget with the same CFBundleName key, Dashboard will ask you if you want to replace the existing Widget (the other, different Widget with the same CFBundleName name)!!
Conclusions
This article presents an advanced technique that lets you store and retrieve your Dashboard Widget preferences or any other data you like. The presented Widget uses the back side for selecting the desired preference and its front side for displaying it but you can choose to implement it any way you want.
Bibliography and References
Introduction to Dashboard Programming Topics: http://developer.apple.com/documentation/AppleApplications/Conceptual/Dashboard_ProgTopics/Introduction/Introduction.html
Introduction to Dashboard Tutorial: http://developer.apple.com/documentation/AppleApplications/Conceptual/Dashboard_Tutorial/Introduction/chapter_1_section_1.html
Developing Dashboard Widgets: http://developer.apple.com/macosx/dashboard.html
Apple Dashboard Page: http://developer.apple.com/appleapplications/dashboard/
Debugging Dashboard Widgets: http://developer.apple.com/technotes/tn2005/tn2139.html
Dashboard Sample Code: http://developer.apple.com/samplecode/AppleApplications/idxDashboard-date.html#//apple_ref/doc/uid/TP30000925-TP30000418-TP40001366
Disclaimer: The presented Widget code is a modified version of the "GoodBye" Widget provided by Apple and located on your Tiger machine (but not in Mac OS X 10.5), inside the "/Developer/Examples/Dashboard/GoodbyeWorld/3-SavingPreferences" folder. The "Save Prefs" Widget that is presented in this article has four options and, as you saw, it is a little bit more complicated than the "GoodBye" Apple Widget.
Mihalis Tsoukalos lives in Greece with his wife Eugenia and enjoys digital photography and writing articles. He is the author of the "Programming Dashboard Widgets" eBook. You can reach him at tsoukalos@sch.gr.